Fixes BEP path handling for rust analyzer specs (#4130)
The rewrite of the Rust Analyzer auto-discovery pipeline (see #4075)
introduced a bug for users who use
`--experimental_convenience_symlinks=ignore` (i.e. have no bazel-out
symlink in their workspace).
`parse_output_group_paths` documentation suggests that output paths are
always absolute
https://github.com/bazelbuild/rules_rust/blob/dedf05304354aace6a76ae78030a9d69c74e37d4/tools/rust_analyzer/bep.rs#L107-L110
but that is not true for BEP events that trigger the fallback
reconstruction path
https://github.com/bazelbuild/rules_rust/blob/dedf05304354aace6a76ae78030a9d69c74e37d4/tools/rust_analyzer/bep.rs#L241-L243
This PR detects those cases and anchors those paths to the execution
root, making them also absolute.
diff --git a/tools/rust_analyzer/bep.rs b/tools/rust_analyzer/bep.rs
index 5d30727..58eae14 100644
--- a/tools/rust_analyzer/bep.rs
+++ b/tools/rust_analyzer/bep.rs
@@ -110,6 +110,7 @@
pub fn parse_output_group_paths(
bep_path: &Utf8Path,
output_group: &str,
+ execution_root: &Utf8Path,
) -> Result<Vec<Utf8PathBuf>> {
let file = File::open(bep_path).with_context(|| format!("opening BEP file {bep_path}"))?;
let reader = BufReader::new(file);
@@ -162,7 +163,12 @@
};
for file in &set.files {
if let Some(path) = file_to_path(file) {
- paths.push(path);
+ let mut absolute_path = path;
+ if !absolute_path.is_absolute() {
+ absolute_path = execution_root.join(absolute_path);
+ }
+
+ paths.push(absolute_path);
}
}
for child in &set.file_sets {
@@ -177,8 +183,11 @@
/// Convenience wrapper for the `rust_analyzer_crate_spec` output group used
/// during project discovery.
-pub fn parse_spec_paths(bep_path: &Utf8Path) -> Result<Vec<Utf8PathBuf>> {
- parse_output_group_paths(bep_path, SPEC_OUTPUT_GROUP)
+pub fn parse_spec_paths(
+ bep_path: &Utf8Path,
+ execution_root: &Utf8Path,
+) -> Result<Vec<Utf8PathBuf>> {
+ parse_output_group_paths(bep_path, SPEC_OUTPUT_GROUP, execution_root)
}
/// Return the stderr file path captured for every completed Bazel action
@@ -347,7 +356,7 @@
"#,
)
.unwrap();
- let paths = parse_spec_paths(&bep_path).unwrap();
+ let paths = parse_spec_paths(&bep_path, Utf8Path::new("/execroot")).unwrap();
assert_eq!(
paths,
vec![
@@ -358,6 +367,26 @@
}
#[test]
+ fn parse_spec_paths_handles_relative_paths() {
+ let dir = tempdir();
+ let bep_path = dir.join("bep.json");
+ std::fs::write(
+ &bep_path,
+ r#"{"id":{"namedSet":{"id":"0"}},"namedSetOfFiles":{"files":[{"uri":"bytestream://remote/blob","pathPrefix":["bazel-out","k8-fastbuild","bin"],"name":"pkg/lib.rust_analyzer_crate_spec.json"}]}}
+{"id":{"targetCompleted":{"label":"//pkg:lib"}},"completed":{"outputGroup":[{"name":"rust_analyzer_crate_spec","fileSets":[{"id":"0"}]}]}}
+"#,
+ )
+ .unwrap();
+ let paths = parse_spec_paths(&bep_path, Utf8Path::new("/execroot")).unwrap();
+ assert_eq!(
+ paths,
+ vec![Utf8PathBuf::from(
+ "/execroot/bazel-out/k8-fastbuild/bin/pkg/lib.rust_analyzer_crate_spec.json",
+ )]
+ );
+ }
+
+ #[test]
fn parse_output_group_paths_filters_by_group() {
let dir = tempdir();
let bep_path = dir.join("bep.json");
@@ -369,9 +398,16 @@
"#,
)
.unwrap();
- let rustc = parse_output_group_paths(&bep_path, RUSTC_OUTPUT_GROUP).unwrap();
+ let rustc =
+ parse_output_group_paths(&bep_path, RUSTC_OUTPUT_GROUP, Utf8Path::new("/execroot"))
+ .unwrap();
assert_eq!(rustc, vec![Utf8PathBuf::from("/abs/lib.rustc-output")]);
- let specs = parse_output_group_paths(&bep_path, "rust_analyzer_crate_spec").unwrap();
+ let specs = parse_output_group_paths(
+ &bep_path,
+ "rust_analyzer_crate_spec",
+ Utf8Path::new("/execroot"),
+ )
+ .unwrap();
assert_eq!(specs, vec![Utf8PathBuf::from("/abs/lib.spec.json")]);
}
diff --git a/tools/rust_analyzer/lib.rs b/tools/rust_analyzer/lib.rs
index e08e931..71fbdbb 100644
--- a/tools/rust_analyzer/lib.rs
+++ b/tools/rust_analyzer/lib.rs
@@ -87,7 +87,7 @@
&bep_file,
)?;
- let spec_paths = match bep::parse_spec_paths(&bep_file) {
+ let spec_paths = match bep::parse_spec_paths(&bep_file, execution_root) {
Ok(paths) => paths,
// A failed build often means a missing or partial BEP file; surface
// the build error rather than the downstream parse error.