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

+1
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

+18-7
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

+6-1
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)