Skip to content

Commit 487ea0e

Browse files
authored
Support escaped runfile paths (#3910)
Add support for spaces, newlines and backslashes in paths written to the runfiles MANIFEST file.
1 parent a9565ff commit 487ea0e

1 file changed

Lines changed: 56 additions & 2 deletions

File tree

rust/runfiles/runfiles.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,27 @@ impl Runfiles {
232232
let path_mapping = manifest_content
233233
.lines()
234234
.flat_map(|line| {
235-
let pair = line
235+
let raw_pair = line
236+
.strip_prefix(' ')
237+
.unwrap_or(line)
236238
.split_once(' ')
237239
.ok_or(RunfilesError::RunfilesManifestInvalidFormat)?;
238-
Ok::<(PathBuf, PathBuf), RunfilesError>((pair.0.into(), pair.1.into()))
240+
let pair = if line.starts_with(' ') {
241+
// Unescape according to SourceManifestAction.java.
242+
// https://github.com/bazelbuild/bazel/blob/3cb75e7bb181e3fb2b33707c172bf80431dc4712/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java#L77-L84
243+
(
244+
raw_pair
245+
.0
246+
.replace("\\s", " ")
247+
.replace("\\n", "\n")
248+
.replace("\\b", "\\")
249+
.into(),
250+
raw_pair.1.replace("\\n", "\n").replace("\\b", "\\").into(),
251+
)
252+
} else {
253+
(raw_pair.0.into(), raw_pair.1.into())
254+
};
255+
Ok::<(PathBuf, PathBuf), RunfilesError>(pair)
239256
})
240257
.collect::<HashMap<_, _>>();
241258
Ok(Mode::ManifestBased(path_mapping))
@@ -633,6 +650,43 @@ mod test {
633650
);
634651
}
635652

653+
#[test]
654+
fn test_manifest_parsing() {
655+
let temp_dir = PathBuf::from(std::env::var("TEST_TMPDIR").unwrap());
656+
std::fs::create_dir_all(&temp_dir).unwrap();
657+
658+
let manifest_file = temp_dir.join("test_manifest_parsing.manifest");
659+
std::fs::write(
660+
&manifest_file,
661+
[
662+
"a/b c/d\n",
663+
" a\\sb/c\\nd\\be f g/h\\ni\\bj\n",
664+
"empty-file \n",
665+
]
666+
.join("\n"),
667+
)
668+
.unwrap();
669+
670+
with_mock_env(
671+
[
672+
(MANIFEST_FILE_ENV_VAR, Some(manifest_file.to_str().unwrap())),
673+
(RUNFILES_DIR_ENV_VAR, None::<&str>),
674+
(TEST_SRCDIR_ENV_VAR, None::<&str>),
675+
],
676+
|| {
677+
let r = Runfiles::create().unwrap();
678+
assert_eq!(r.rlocation("a/b"), Some(PathBuf::from("c/d")));
679+
// Note that the `\s` is not escaped in the link, so not testing for it.
680+
assert_eq!(
681+
r.rlocation("a b/c\nd\\e"),
682+
Some(PathBuf::from("f g/h\ni\\j"))
683+
);
684+
assert_eq!(r.rlocation("empty-file"), Some(PathBuf::from("")));
685+
assert_eq!(r.rlocation("does/not/exist"), None);
686+
},
687+
);
688+
}
689+
636690
#[test]
637691
fn test_manifest_based_can_read_data_from_runfiles() {
638692
let mut path_mapping = HashMap::new();

0 commit comments

Comments
 (0)