@@ -552,6 +552,7 @@ impl CargoWorkspace {
552
552
553
553
pub ( crate ) struct FetchMetadata {
554
554
command : cargo_metadata:: MetadataCommand ,
555
+ manifest_path : ManifestPath ,
555
556
lockfile_path : Option < Utf8PathBuf > ,
556
557
kind : & ' static str ,
557
558
no_deps : bool ,
@@ -655,7 +656,15 @@ impl FetchMetadata {
655
656
}
656
657
. with_context ( || format ! ( "Failed to run `{cargo_command:?}`" ) ) ;
657
658
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
+ }
659
668
}
660
669
661
670
pub ( crate ) fn no_deps_metadata ( & self ) -> Option < & cargo_metadata:: Metadata > {
@@ -672,18 +681,47 @@ impl FetchMetadata {
672
681
locked : bool ,
673
682
progress : & dyn Fn ( String ) ,
674
683
) -> 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 ;
677
693
678
694
if no_deps {
679
695
return no_deps_result. map ( |m| ( m, None ) ) ;
680
696
}
681
697
682
698
let mut using_lockfile_copy = false ;
699
+ let mut _temp_dir_guard = None ;
683
700
// The manifest is a rust file, so this means its a script manifest
684
701
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
+ } ) ;
687
725
match std:: fs:: copy ( & lockfile, & target_lockfile) {
688
726
Ok ( _) => {
689
727
using_lockfile_copy = true ;
0 commit comments