mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
fix: Make path dependencies with the same name stays locked
This commit is contained in:
parent
5c1b6313fa
commit
ab927171ce
@ -154,7 +154,7 @@ impl EncodableResolve {
|
|||||||
/// primary uses is to be used with `resolve_with_previous` to guide the
|
/// primary uses is to be used with `resolve_with_previous` to guide the
|
||||||
/// resolver to create a complete Resolve.
|
/// resolver to create a complete Resolve.
|
||||||
pub fn into_resolve(self, original: &str, ws: &Workspace<'_>) -> CargoResult<Resolve> {
|
pub fn into_resolve(self, original: &str, ws: &Workspace<'_>) -> CargoResult<Resolve> {
|
||||||
let path_deps = build_path_deps(ws)?;
|
let path_deps: HashMap<String, HashMap<semver::Version, SourceId>> = build_path_deps(ws)?;
|
||||||
let mut checksums = HashMap::new();
|
let mut checksums = HashMap::new();
|
||||||
|
|
||||||
let mut version = match self.version {
|
let mut version = match self.version {
|
||||||
@ -202,7 +202,11 @@ impl EncodableResolve {
|
|||||||
if !all_pkgs.insert(enc_id.clone()) {
|
if !all_pkgs.insert(enc_id.clone()) {
|
||||||
anyhow::bail!("package `{}` is specified twice in the lockfile", pkg.name);
|
anyhow::bail!("package `{}` is specified twice in the lockfile", pkg.name);
|
||||||
}
|
}
|
||||||
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
|
let id = match pkg
|
||||||
|
.source
|
||||||
|
.as_deref()
|
||||||
|
.or_else(|| get_source_id(&path_deps, pkg))
|
||||||
|
{
|
||||||
// We failed to find a local package in the workspace.
|
// We failed to find a local package in the workspace.
|
||||||
// It must have been removed and should be ignored.
|
// It must have been removed and should be ignored.
|
||||||
None => {
|
None => {
|
||||||
@ -364,7 +368,11 @@ impl EncodableResolve {
|
|||||||
|
|
||||||
let mut unused_patches = Vec::new();
|
let mut unused_patches = Vec::new();
|
||||||
for pkg in self.patch.unused {
|
for pkg in self.patch.unused {
|
||||||
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
|
let id = match pkg
|
||||||
|
.source
|
||||||
|
.as_deref()
|
||||||
|
.or_else(|| get_source_id(&path_deps, &pkg))
|
||||||
|
{
|
||||||
Some(&src) => PackageId::try_new(&pkg.name, &pkg.version, src)?,
|
Some(&src) => PackageId::try_new(&pkg.name, &pkg.version, src)?,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
@ -395,7 +403,7 @@ impl EncodableResolve {
|
|||||||
version = ResolveVersion::V2;
|
version = ResolveVersion::V2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Resolve::new(
|
return Ok(Resolve::new(
|
||||||
g,
|
g,
|
||||||
replacements,
|
replacements,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
@ -404,11 +412,35 @@ impl EncodableResolve {
|
|||||||
unused_patches,
|
unused_patches,
|
||||||
version,
|
version,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
))
|
));
|
||||||
|
|
||||||
|
fn get_source_id<'a>(
|
||||||
|
path_deps: &'a HashMap<String, HashMap<semver::Version, SourceId>>,
|
||||||
|
pkg: &'a EncodableDependency,
|
||||||
|
) -> Option<&'a SourceId> {
|
||||||
|
path_deps.iter().find_map(|(name, version_source)| {
|
||||||
|
if name != &pkg.name || version_source.len() == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if version_source.len() == 1 {
|
||||||
|
return Some(version_source.values().next().unwrap());
|
||||||
|
}
|
||||||
|
// If there are multiple candidates for the same name, it needs to be determined by combining versions (See #13405).
|
||||||
|
if let Ok(pkg_version) = pkg.version.parse::<semver::Version>() {
|
||||||
|
if let Some(source_id) = version_source.get(&pkg_version) {
|
||||||
|
return Some(source_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>> {
|
fn build_path_deps(
|
||||||
|
ws: &Workspace<'_>,
|
||||||
|
) -> CargoResult<HashMap<String, HashMap<semver::Version, SourceId>>> {
|
||||||
// If a crate is **not** a path source, then we're probably in a situation
|
// If a crate is **not** a path source, then we're probably in a situation
|
||||||
// such as `cargo install` with a lock file from a remote dependency. In
|
// such as `cargo install` with a lock file from a remote dependency. In
|
||||||
// that case we don't need to fixup any path dependencies (as they're not
|
// that case we don't need to fixup any path dependencies (as they're not
|
||||||
@ -418,13 +450,15 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||||||
.filter(|p| p.package_id().source_id().is_path())
|
.filter(|p| p.package_id().source_id().is_path())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut ret = HashMap::new();
|
let mut ret: HashMap<String, HashMap<semver::Version, SourceId>> = HashMap::new();
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
for member in members.iter() {
|
for member in members.iter() {
|
||||||
ret.insert(
|
ret.entry(member.package_id().name().to_string())
|
||||||
member.package_id().name().to_string(),
|
.or_insert_with(HashMap::new)
|
||||||
member.package_id().source_id(),
|
.insert(
|
||||||
);
|
member.package_id().version().clone(),
|
||||||
|
member.package_id().source_id(),
|
||||||
|
);
|
||||||
visited.insert(member.package_id().source_id());
|
visited.insert(member.package_id().source_id());
|
||||||
}
|
}
|
||||||
for member in members.iter() {
|
for member in members.iter() {
|
||||||
@ -444,7 +478,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||||||
fn build_pkg(
|
fn build_pkg(
|
||||||
pkg: &Package,
|
pkg: &Package,
|
||||||
ws: &Workspace<'_>,
|
ws: &Workspace<'_>,
|
||||||
ret: &mut HashMap<String, SourceId>,
|
ret: &mut HashMap<String, HashMap<semver::Version, SourceId>>,
|
||||||
visited: &mut HashSet<SourceId>,
|
visited: &mut HashSet<SourceId>,
|
||||||
) {
|
) {
|
||||||
for dep in pkg.dependencies() {
|
for dep in pkg.dependencies() {
|
||||||
@ -455,7 +489,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||||||
fn build_dep(
|
fn build_dep(
|
||||||
dep: &Dependency,
|
dep: &Dependency,
|
||||||
ws: &Workspace<'_>,
|
ws: &Workspace<'_>,
|
||||||
ret: &mut HashMap<String, SourceId>,
|
ret: &mut HashMap<String, HashMap<semver::Version, SourceId>>,
|
||||||
visited: &mut HashSet<SourceId>,
|
visited: &mut HashSet<SourceId>,
|
||||||
) {
|
) {
|
||||||
let id = dep.source_id();
|
let id = dep.source_id();
|
||||||
@ -467,7 +501,12 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
|
|||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
let Ok(pkg) = ws.load(&path) else { return };
|
let Ok(pkg) = ws.load(&path) else { return };
|
||||||
ret.insert(pkg.name().to_string(), pkg.package_id().source_id());
|
ret.entry(pkg.package_id().name().to_string())
|
||||||
|
.or_insert_with(HashMap::new)
|
||||||
|
.insert(
|
||||||
|
pkg.package_id().version().clone(),
|
||||||
|
pkg.package_id().source_id(),
|
||||||
|
);
|
||||||
visited.insert(pkg.package_id().source_id());
|
visited.insert(pkg.package_id().source_id());
|
||||||
build_pkg(&pkg, ws, ret, visited);
|
build_pkg(&pkg, ws, ret, visited);
|
||||||
}
|
}
|
||||||
|
@ -2993,12 +2993,12 @@ foo v0.0.0 ([ROOT]/foo)
|
|||||||
"\
|
"\
|
||||||
foo v0.0.0 ([ROOT]/foo)
|
foo v0.0.0 ([ROOT]/foo)
|
||||||
├── bar v1.0.999 ([ROOT]/foo/bar-1-as-3)
|
├── bar v1.0.999 ([ROOT]/foo/bar-1-as-3)
|
||||||
│ └── bar v3.0.1
|
│ └── bar v3.0.0
|
||||||
└── bar v2.0.999 ([ROOT]/foo/bar-2-as-3)
|
└── bar v2.0.999 ([ROOT]/foo/bar-2-as-3)
|
||||||
└── bar v3.0.1
|
└── bar v3.0.0
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
assert_ne!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig"));
|
assert_eq!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig"));
|
||||||
}
|
}
|
@ -1204,3 +1204,68 @@ fn catch_tricky_cycle() {
|
|||||||
.with_status(101)
|
.with_status(101)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn same_name_version_changed() {
|
||||||
|
// Illustrates having two path packages with the same name, but different versions.
|
||||||
|
// Verifies it works correctly when one of the versions is changed.
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
foo2 = { path = "foo2", package = "foo" }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.file(
|
||||||
|
"foo2/Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "2.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("foo2/src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("tree")
|
||||||
|
.with_stderr("[LOCKING] 2 packages to latest compatible versions")
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v1.0.0 ([ROOT]/foo)
|
||||||
|
└── foo v2.0.0 ([ROOT]/foo/foo2)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.change_file(
|
||||||
|
"foo2/Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "2.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
p.cargo("tree")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[LOCKING] 1 package to latest compatible version
|
||||||
|
[ADDING] foo v2.0.1 ([ROOT]/foo/foo2)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v1.0.0 ([ROOT]/foo)
|
||||||
|
└── foo v2.0.1 ([ROOT]/foo/foo2)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user