fix external crate paths for gen_rust_project (#4200)
This addresses part 1 of #4057
diff --git a/test/rust_analyzer/generated_srcs_test/rust_project_json_test.rs b/test/rust_analyzer/generated_srcs_test/rust_project_json_test.rs
index d6a2c5b..2c6e351 100644
--- a/test/rust_analyzer/generated_srcs_test/rust_project_json_test.rs
+++ b/test/rust_analyzer/generated_srcs_test/rust_project_json_test.rs
@@ -22,23 +22,23 @@
include_dirs: Vec<String>,
}
+ /// `{output_base}/external/.../library` → `{output_base}`
+ fn output_base(p: &Project) -> &str {
+ p.sysroot_src
+ .rsplitn(2, "/external/")
+ .last()
+ .expect("sysroot_src should contain /external/")
+ }
+
#[test]
fn test_generated_srcs() {
let rust_project_path = PathBuf::from(env::var("RUST_PROJECT_JSON").unwrap());
- let content = std::fs::read_to_string(&rust_project_path)
- .unwrap_or_else(|_| panic!("couldn't open {:?}", rust_project_path));
+ let content = std::fs::read_to_string(&rust_project_path).unwrap();
let project: Project =
- serde_json::from_str(&content).expect("Failed to deserialize project JSON");
+ serde_json::from_str(&content).expect("project JSON should deserialize correctly");
- // /tmp/_bazel/12345678/external/tools/rustlib/library => /tmp/_bazel
- let output_base = project
- .sysroot_src
- .rsplitn(2, "/external/")
- .last()
- .unwrap()
- .rsplitn(2, '/')
- .last()
- .unwrap();
+ // /tmp/_bazel/12345678/external/tools/rustlib/library => /tmp/_bazel/12345678
+ let output_base = output_base(&project);
println!("output_base: {output_base}");
let with_gen = project
@@ -58,4 +58,28 @@
// The second entry is the output base, where the generated files are located.
assert!(include_dirs[1].starts_with(output_base));
}
+
+ #[test]
+ fn test_external_root_paths() {
+ let rust_project_path = PathBuf::from(env::var("RUST_PROJECT_JSON").unwrap());
+ let content = std::fs::read_to_string(&rust_project_path).unwrap();
+ let project: Project =
+ serde_json::from_str(&content).expect("project JSON should deserialize correctly");
+ let output_base = output_base(&project);
+ let mut external_roots = project
+ .crates
+ .iter()
+ .map(|c| &c.root_module)
+ .filter(|p| p.contains("/external/"))
+ .peekable();
+
+ assert!(external_roots.peek().is_some());
+
+ let output_base_external = format!("{output_base}/external/");
+
+ for root in external_roots {
+ assert!(root.starts_with(&output_base_external));
+ assert!(!root.contains("execroot"));
+ }
+ }
}
diff --git a/tools/rust_analyzer/lib.rs b/tools/rust_analyzer/lib.rs
index 6733cae..092a2e7 100644
--- a/tools/rust_analyzer/lib.rs
+++ b/tools/rust_analyzer/lib.rs
@@ -496,7 +496,14 @@
.replace("__WORKSPACE__", workspace.as_str())
.replace("${pwd}", execution_root.as_str())
.replace("__EXEC_ROOT__", execution_root.as_str())
- .replace("__OUTPUT_BASE__", output_base.as_str());
+ .replace("__OUTPUT_BASE__", output_base.as_str())
+ // exec_root/external contains symlinks into the output_base/external
+ // but those symlinks are ephemeral. if we do not replace here, goto
+ // definition can fail because those symlinks would no longer be found.
+ .replace(
+ &format!("{execution_root}/external/"),
+ &format!("{output_base}/external/"),
+ );
serde_json::from_str(&content).context("failed to deserialize after template substitution")
}