Skip to content

Commit d5379d3

Browse files
committed
Use TempDir for copied lockfiles
1 parent fa64d3b commit d5379d3

File tree

5 files changed

+55
-6
lines changed

5 files changed

+55
-6
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ smallvec = { version = "1.15.1", features = [
156156
"const_generics",
157157
] }
158158
smol_str = "0.3.2"
159+
temp-dir = "0.1.16"
159160
text-size = "1.1.1"
160161
tracing = "0.1.41"
161162
tracing-tree = "0.4.0"

crates/project-model/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ semver.workspace = true
2020
serde_json.workspace = true
2121
serde.workspace = true
2222
serde_derive.workspace = true
23+
temp-dir.workspace = true
2324
tracing.workspace = true
2425
triomphe.workspace = true
2526
la-arena.workspace = true

crates/project-model/src/cargo_workspace.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ impl CargoWorkspace {
552552

553553
pub(crate) struct FetchMetadata {
554554
command: cargo_metadata::MetadataCommand,
555+
manifest_path: ManifestPath,
555556
lockfile_path: Option<Utf8PathBuf>,
556557
kind: &'static str,
557558
no_deps: bool,
@@ -655,7 +656,15 @@ impl FetchMetadata {
655656
}
656657
.with_context(|| format!("Failed to run `{cargo_command:?}`"));
657658

658-
Self { command, lockfile_path, kind: config.kind, no_deps, no_deps_result, other_options }
659+
Self {
660+
manifest_path: cargo_toml.clone(),
661+
command,
662+
lockfile_path,
663+
kind: config.kind,
664+
no_deps,
665+
no_deps_result,
666+
other_options,
667+
}
659668
}
660669

661670
pub(crate) fn no_deps_metadata(&self) -> Option<&cargo_metadata::Metadata> {
@@ -672,18 +681,47 @@ impl FetchMetadata {
672681
locked: bool,
673682
progress: &dyn Fn(String),
674683
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
675-
let Self { mut command, lockfile_path, kind, no_deps, no_deps_result, mut other_options } =
676-
self;
684+
let Self {
685+
mut command,
686+
manifest_path,
687+
lockfile_path,
688+
kind,
689+
no_deps,
690+
no_deps_result,
691+
mut other_options,
692+
} = self;
677693

678694
if no_deps {
679695
return no_deps_result.map(|m| (m, None));
680696
}
681697

682698
let mut using_lockfile_copy = false;
699+
let mut _temp_dir_guard = None;
683700
// The manifest is a rust file, so this means its a script manifest
684701
if let Some(lockfile) = lockfile_path {
685-
let target_lockfile =
686-
target_dir.join("rust-analyzer").join("metadata").join(kind).join("Cargo.lock");
702+
_temp_dir_guard = temp_dir::TempDir::with_prefix("rust-analyzer").ok();
703+
let target_lockfile = _temp_dir_guard
704+
.and_then(|tmp| tmp.path().join("Cargo.lock").try_into().ok())
705+
.unwrap_or_else(|| {
706+
// When multiple workspaces share the same target dir, they might overwrite into a
707+
// single lockfile path.
708+
// See https://github.com/rust-lang/rust-analyzer/issues/20189#issuecomment-3073520255
709+
let manifest_path_hash = std::hash::BuildHasher::hash_one(
710+
&std::hash::BuildHasherDefault::<rustc_hash::FxHasher>::default(),
711+
&manifest_path,
712+
);
713+
let disambiguator = format!(
714+
"{}_{manifest_path_hash}",
715+
manifest_path.components().nth_back(1).map_or("", |c| c.as_str())
716+
);
717+
718+
target_dir
719+
.join("rust-analyzer")
720+
.join("metadata")
721+
.join(kind)
722+
.join(disambiguator)
723+
.join("Cargo.lock")
724+
});
687725
match std::fs::copy(&lockfile, &target_lockfile) {
688726
Ok(_) => {
689727
using_lockfile_copy = true;

crates/project-model/src/workspace.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1905,7 +1905,8 @@ fn cargo_target_dir(
19051905
meta.manifest_path(manifest);
19061906
// `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve.
19071907
// So we can use it to get `target_directory` before copying lockfiles
1908-
let mut other_options = vec!["--no-deps".to_owned()];
1908+
meta.no_deps();
1909+
let mut other_options = vec![];
19091910
if manifest.is_rust_manifest() {
19101911
meta.env("RUSTC_BOOTSTRAP", "1");
19111912
other_options.push("-Zscript".to_owned());

0 commit comments

Comments
 (0)