Skip to content

Commit ae953da

Browse files
authored
feat(runfiles): add support for spaces and newlines in runfiles paths (bazel-contrib#2456)
Bazel 7.4.0 introduced support for all characters in runfile source and target paths: bazelbuild/bazel#23912 This is a backwards-compatible change, based on a similar change in rules_go: bazel-contrib/rules_go#4136
1 parent be704e2 commit ae953da

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ Other changes:
112112
* (providers) Added {obj}`py_runtime_info.site_init_template` and
113113
{obj}`PyRuntimeInfo.site_init_template` for specifying the template to use to
114114
initialize the interpreter via venv startup hooks.
115+
* (runfiles) (Bazel 7.4+) Added support for spaces and newlines in runfiles paths
115116

116117
{#v0-0-0-removed}
117118
### Removed

python/runfiles/runfiles.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,24 @@ def _LoadRunfiles(path: str) -> Dict[str, str]:
5858
result = {}
5959
with open(path, "r") as f:
6060
for line in f:
61-
line = line.strip()
62-
if line:
63-
tokens = line.split(" ", 1)
64-
if len(tokens) == 1:
65-
result[line] = line
66-
else:
67-
result[tokens[0]] = tokens[1]
61+
line = line.rstrip("\n")
62+
if line.startswith(" "):
63+
# In lines that start with a space, spaces, newlines, and backslashes are escaped as \s, \n, and \b in
64+
# link and newlines and backslashes are escaped in target.
65+
escaped_link, escaped_target = line[1:].split(" ", maxsplit=1)
66+
link = (
67+
escaped_link.replace(r"\s", " ")
68+
.replace(r"\n", "\n")
69+
.replace(r"\b", "\\")
70+
)
71+
target = escaped_target.replace(r"\n", "\n").replace(r"\b", "\\")
72+
else:
73+
link, target = line.split(" ", maxsplit=1)
74+
75+
if target:
76+
result[link] = target
77+
else:
78+
result[link] = link
6879
return result
6980

7081
def _GetRunfilesDir(self) -> str:

tests/runfiles/runfiles_test.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,11 @@ def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self) -> None:
185185
def testManifestBasedRlocation(self) -> None:
186186
with _MockFile(
187187
contents=[
188-
"Foo/runfile1",
188+
"Foo/runfile1 ", # A trailing whitespace is always present in single entry lines.
189189
"Foo/runfile2 C:/Actual Path\\runfile2",
190190
"Foo/Bar/runfile3 D:\\the path\\run file 3.txt",
191191
"Foo/Bar/Dir E:\\Actual Path\\Directory",
192+
" Foo\\sBar\\bDir\\nNewline/runfile5 F:\\bActual Path\\bwith\\nnewline/runfile5",
192193
]
193194
) as mf:
194195
r = runfiles.CreateManifestBased(mf.Path())
@@ -205,6 +206,10 @@ def testManifestBasedRlocation(self) -> None:
205206
r.Rlocation("Foo/Bar/Dir/Deeply/Nested/runfile4"),
206207
"E:\\Actual Path\\Directory/Deeply/Nested/runfile4",
207208
)
209+
self.assertEqual(
210+
r.Rlocation("Foo Bar\\Dir\nNewline/runfile5"),
211+
"F:\\Actual Path\\with\nnewline/runfile5",
212+
)
208213
self.assertIsNone(r.Rlocation("unknown"))
209214
if RunfilesTest.IsWindows():
210215
self.assertEqual(r.Rlocation("c:/foo"), "c:/foo")

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy