about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates
diff options
context:
space:
mode:
authorLukas Wirth <me@lukaswirth.dev>2025-07-27 11:36:35 +0000
committerGitHub <noreply@github.com>2025-07-27 11:36:35 +0000
commitdfc9bd02ae169689dd643c3e69a4fbd207768b5a (patch)
treecc55906c303cdf7cfe1bb308d18cbb9c8141beec /src/tools/rust-analyzer/crates
parentd941bc7d306e2a6b232342ff453e8196bc27195e (diff)
parentc60cec3411b38c13bb9b1ea92e02bbc8b5db5984 (diff)
downloadrust-dfc9bd02ae169689dd643c3e69a4fbd207768b5a.tar.gz
rust-dfc9bd02ae169689dd643c3e69a4fbd207768b5a.zip
Merge pull request #20290 from ShoyuVanilla/tmp-lockfiles
Use `TempDir` for copied lockfiles
Diffstat (limited to 'src/tools/rust-analyzer/crates')
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs48
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs3
3 files changed, 46 insertions, 6 deletions
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index 27fe9f79bbc..0dbb309a62a 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -20,6 +20,7 @@ semver.workspace = true
 serde_json.workspace = true
 serde.workspace = true
 serde_derive.workspace = true
+temp-dir.workspace = true
 tracing.workspace = true
 triomphe.workspace = true
 la-arena.workspace = true
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index daadcd9d79a..25abb19d9d5 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -552,6 +552,7 @@ impl CargoWorkspace {
 
 pub(crate) struct FetchMetadata {
     command: cargo_metadata::MetadataCommand,
+    manifest_path: ManifestPath,
     lockfile_path: Option<Utf8PathBuf>,
     kind: &'static str,
     no_deps: bool,
@@ -655,7 +656,15 @@ impl FetchMetadata {
         }
         .with_context(|| format!("Failed to run `{cargo_command:?}`"));
 
-        Self { command, lockfile_path, kind: config.kind, no_deps, no_deps_result, other_options }
+        Self {
+            manifest_path: cargo_toml.clone(),
+            command,
+            lockfile_path,
+            kind: config.kind,
+            no_deps,
+            no_deps_result,
+            other_options,
+        }
     }
 
     pub(crate) fn no_deps_metadata(&self) -> Option<&cargo_metadata::Metadata> {
@@ -672,18 +681,47 @@ impl FetchMetadata {
         locked: bool,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
-        let Self { mut command, lockfile_path, kind, no_deps, no_deps_result, mut other_options } =
-            self;
+        let Self {
+            mut command,
+            manifest_path,
+            lockfile_path,
+            kind,
+            no_deps,
+            no_deps_result,
+            mut other_options,
+        } = self;
 
         if no_deps {
             return no_deps_result.map(|m| (m, None));
         }
 
         let mut using_lockfile_copy = false;
+        let mut _temp_dir_guard = None;
         // The manifest is a rust file, so this means its a script manifest
         if let Some(lockfile) = lockfile_path {
-            let target_lockfile =
-                target_dir.join("rust-analyzer").join("metadata").join(kind).join("Cargo.lock");
+            _temp_dir_guard = temp_dir::TempDir::with_prefix("rust-analyzer").ok();
+            let target_lockfile = _temp_dir_guard
+                .and_then(|tmp| tmp.path().join("Cargo.lock").try_into().ok())
+                .unwrap_or_else(|| {
+                    // When multiple workspaces share the same target dir, they might overwrite into a
+                    // single lockfile path.
+                    // See https://github.com/rust-lang/rust-analyzer/issues/20189#issuecomment-3073520255
+                    let manifest_path_hash = std::hash::BuildHasher::hash_one(
+                        &std::hash::BuildHasherDefault::<rustc_hash::FxHasher>::default(),
+                        &manifest_path,
+                    );
+                    let disambiguator = format!(
+                        "{}_{manifest_path_hash}",
+                        manifest_path.components().nth_back(1).map_or("", |c| c.as_str())
+                    );
+
+                    target_dir
+                        .join("rust-analyzer")
+                        .join("metadata")
+                        .join(kind)
+                        .join(disambiguator)
+                        .join("Cargo.lock")
+                });
             match std::fs::copy(&lockfile, &target_lockfile) {
                 Ok(_) => {
                     using_lockfile_copy = true;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 677f29e3c60..655da118bbd 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -1905,7 +1905,8 @@ fn cargo_target_dir(
     meta.manifest_path(manifest);
     // `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve.
     // So we can use it to get `target_directory` before copying lockfiles
-    let mut other_options = vec!["--no-deps".to_owned()];
+    meta.no_deps();
+    let mut other_options = vec![];
     if manifest.is_rust_manifest() {
         meta.env("RUSTC_BOOTSTRAP", "1");
         other_options.push("-Zscript".to_owned());