Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/cargo_workspace.rs')
-rw-r--r--crates/project-model/src/cargo_workspace.rs48
1 files changed, 43 insertions, 5 deletions
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index daadcd9d79..25abb19d9d 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/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;