Skip to content

Commit c52a34e

Browse files
committed
fix: Make path dependencies with the same name stays locked
1 parent a15a507 commit c52a34e

File tree

2 files changed

+65
-17
lines changed

2 files changed

+65
-17
lines changed

src/cargo/core/resolver/encode.rs

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ impl EncodableResolve {
202202
if !all_pkgs.insert(enc_id.clone()) {
203203
anyhow::bail!("package `{}` is specified twice in the lockfile", pkg.name);
204204
}
205-
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
205+
let id = match pkg
206+
.source
207+
.as_deref()
208+
.or_else(|| get_source_id(&path_deps, pkg))
209+
{
206210
// We failed to find a local package in the workspace.
207211
// It must have been removed and should be ignored.
208212
None => {
@@ -364,7 +368,11 @@ impl EncodableResolve {
364368

365369
let mut unused_patches = Vec::new();
366370
for pkg in self.patch.unused {
367-
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
371+
let id = match pkg
372+
.source
373+
.as_deref()
374+
.or_else(|| get_source_id(&path_deps, &pkg))
375+
{
368376
Some(&src) => PackageId::try_new(&pkg.name, &pkg.version, src)?,
369377
None => continue,
370378
};
@@ -395,7 +403,7 @@ impl EncodableResolve {
395403
version = ResolveVersion::V2;
396404
}
397405

398-
Ok(Resolve::new(
406+
return Ok(Resolve::new(
399407
g,
400408
replacements,
401409
HashMap::new(),
@@ -404,11 +412,42 @@ impl EncodableResolve {
404412
unused_patches,
405413
version,
406414
HashMap::new(),
407-
))
415+
));
416+
417+
fn get_source_id<'a>(
418+
path_deps: &'a HashMap<String, HashMap<semver::Version, SourceId>>,
419+
pkg: &'a EncodableDependency,
420+
) -> Option<&'a SourceId> {
421+
{
422+
if let Some(source_id) = path_deps.iter().find_map(|(name, version_source)| {
423+
// First look for cases where the version and name are the same
424+
if name == &pkg.name {
425+
if let Ok(pkg_version) = pkg.version.parse::<semver::Version>() {
426+
if let Some(source_id) = version_source.get(&pkg_version) {
427+
return Some(source_id);
428+
}
429+
}
430+
}
431+
None
432+
}) {
433+
Some(source_id)
434+
} else {
435+
// Next look for cases where the name is the same
436+
path_deps.iter().find_map(|(name, version_source)| {
437+
if name == &pkg.name {
438+
return version_source.values().next();
439+
}
440+
None
441+
})
442+
}
443+
}
444+
}
408445
}
409446
}
410447

411-
fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>> {
448+
fn build_path_deps(
449+
ws: &Workspace<'_>,
450+
) -> CargoResult<HashMap<String, HashMap<semver::Version, SourceId>>> {
412451
// If a crate is **not** a path source, then we're probably in a situation
413452
// such as `cargo install` with a lock file from a remote dependency. In
414453
// that case we don't need to fixup any path dependencies (as they're not
@@ -418,13 +457,15 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
418457
.filter(|p| p.package_id().source_id().is_path())
419458
.collect::<Vec<_>>();
420459

421-
let mut ret = HashMap::new();
460+
let mut ret: HashMap<String, HashMap<semver::Version, SourceId>> = HashMap::new();
422461
let mut visited = HashSet::new();
423462
for member in members.iter() {
424-
ret.insert(
425-
member.package_id().name().to_string(),
426-
member.package_id().source_id(),
427-
);
463+
ret.entry(member.package_id().name().to_string())
464+
.or_insert_with(HashMap::new)
465+
.insert(
466+
member.package_id().version().clone(),
467+
member.package_id().source_id(),
468+
);
428469
visited.insert(member.package_id().source_id());
429470
}
430471
for member in members.iter() {
@@ -444,7 +485,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
444485
fn build_pkg(
445486
pkg: &Package,
446487
ws: &Workspace<'_>,
447-
ret: &mut HashMap<String, SourceId>,
488+
ret: &mut HashMap<String, HashMap<semver::Version, SourceId>>,
448489
visited: &mut HashSet<SourceId>,
449490
) {
450491
for dep in pkg.dependencies() {
@@ -455,7 +496,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
455496
fn build_dep(
456497
dep: &Dependency,
457498
ws: &Workspace<'_>,
458-
ret: &mut HashMap<String, SourceId>,
499+
ret: &mut HashMap<String, HashMap<semver::Version, SourceId>>,
459500
visited: &mut HashSet<SourceId>,
460501
) {
461502
let id = dep.source_id();
@@ -467,7 +508,14 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
467508
Err(_) => return,
468509
};
469510
let Ok(pkg) = ws.load(&path) else { return };
470-
ret.insert(pkg.name().to_string(), pkg.package_id().source_id());
511+
visited.insert(pkg.package_id().source_id());
512+
build_pkg(&pkg, ws, ret, visited);
513+
ret.entry(pkg.package_id().name().to_string())
514+
.or_insert_with(HashMap::new)
515+
.insert(
516+
pkg.package_id().version().clone(),
517+
pkg.package_id().source_id(),
518+
);
471519
visited.insert(pkg.package_id().source_id());
472520
build_pkg(&pkg, ws, ret, visited);
473521
}

tests/testsuite/patch.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,12 +2939,12 @@ foo v0.0.0 ([ROOT]/foo)
29392939
"\
29402940
foo v0.0.0 ([ROOT]/foo)
29412941
├── bar v1.0.999 ([ROOT]/foo/bar-1-as-3)
2942-
│ └── bar v3.0.1
2942+
│ └── bar v3.0.0
29432943
└── bar v2.0.999 ([ROOT]/foo/bar-2-as-3)
2944-
└── bar v3.0.1
2944+
└── bar v3.0.0
29452945
",
29462946
)
29472947
.run();
29482948

2949-
assert_ne!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig"));
2950-
}
2949+
assert_eq!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig"));
2950+
}

0 commit comments

Comments
 (0)