Skip to content

Commit 5847787

Browse files
committed
Auto merge of #8274 - Eh2406:8249-repro, r=alexcrichton
reset lockfile information between resolutions #8249 pointed out that some kind of lockfile data was leaking between calls to the resolver. @ehuss made a reproducing test case. This PR resets the `LockedMap` data structure when calling `register_previous_locks`. lets see if CI likes it. fix #8249
2 parents 1afe225 + 8ce0d02 commit 5847787

File tree

5 files changed

+93
-20
lines changed

5 files changed

+93
-20
lines changed

crates/cargo-test-support/src/registry.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub struct Package {
145145
alternative: bool,
146146
invalid_json: bool,
147147
proc_macro: bool,
148+
links: Option<String>,
148149
}
149150

150151
#[derive(Clone)]
@@ -245,6 +246,7 @@ impl Package {
245246
alternative: false,
246247
invalid_json: false,
247248
proc_macro: false,
249+
links: None,
248250
}
249251
}
250252

@@ -368,6 +370,11 @@ impl Package {
368370
self
369371
}
370372

373+
pub fn links(&mut self, links: &str) -> &mut Package {
374+
self.links = Some(links.to_string());
375+
self
376+
}
377+
371378
/// Creates the package and place it in the registry.
372379
///
373380
/// This does not actually use Cargo's publishing system, but instead
@@ -420,6 +427,7 @@ impl Package {
420427
"cksum": cksum,
421428
"features": self.features,
422429
"yanked": self.yanked,
430+
"links": self.links,
423431
})
424432
.to_string();
425433

crates/resolver-tests/tests/resolve.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,31 @@ fn conflict_store_more_then_one_match() {
14581458
let _ = resolve_and_validated(vec![dep("nA")], &reg, None);
14591459
}
14601460

1461+
#[test]
1462+
fn bad_lockfile_from_8249() {
1463+
let input = vec![
1464+
pkg!(("a-sys", "0.2.0")),
1465+
pkg!(("a-sys", "0.1.0")),
1466+
pkg!(("b", "0.1.0") => [
1467+
dep_req("a-sys", "0.1"), // should be optional: true, but not deeded for now
1468+
]),
1469+
pkg!(("c", "1.0.0") => [
1470+
dep_req("b", "=0.1.0"),
1471+
]),
1472+
pkg!("foo" => [
1473+
dep_req("a-sys", "=0.2.0"),
1474+
{
1475+
let mut b = dep_req("b", "=0.1.0");
1476+
b.set_features(vec!["a-sys"]);
1477+
b
1478+
},
1479+
dep_req("c", "=1.0.0"),
1480+
]),
1481+
];
1482+
let reg = registry(input);
1483+
let _ = resolve_and_validated(vec![dep("foo")], &reg, None);
1484+
}
1485+
14611486
#[test]
14621487
fn cyclic_good_error_message() {
14631488
let input = vec![

src/cargo/core/registry.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use log::{debug, trace};
55
use semver::VersionReq;
66
use url::Url;
77

8-
use crate::core::PackageSet;
98
use crate::core::{Dependency, PackageId, Source, SourceId, SourceMap, Summary};
9+
use crate::core::{InternedString, PackageSet};
1010
use crate::sources::config::SourceConfigMap;
1111
use crate::util::errors::{CargoResult, CargoResultExt};
1212
use crate::util::{profile, CanonicalUrl, Config};
@@ -91,16 +91,13 @@ pub struct PackageRegistry<'cfg> {
9191
type LockedMap = HashMap<
9292
// The first level of key-ing done in this hash map is the source that
9393
// dependencies come from, identified by a `SourceId`.
94-
SourceId,
95-
HashMap<
96-
// This next level is keyed by the name of the package...
97-
String,
98-
// ... and the value here is a list of tuples. The first element of each
99-
// tuple is a package which has the source/name used to get to this
100-
// point. The second element of each tuple is the list of locked
101-
// dependencies that the first element has.
102-
Vec<(PackageId, Vec<PackageId>)>,
103-
>,
94+
// The next level is keyed by the name of the package...
95+
(SourceId, InternedString),
96+
// ... and the value here is a list of tuples. The first element of each
97+
// tuple is a package which has the source/name used to get to this
98+
// point. The second element of each tuple is the list of locked
99+
// dependencies that the first element has.
100+
Vec<(PackageId, Vec<PackageId>)>,
104101
>;
105102

106103
#[derive(PartialEq, Eq, Clone, Copy)]
@@ -198,17 +195,20 @@ impl<'cfg> PackageRegistry<'cfg> {
198195
self.yanked_whitelist.extend(pkgs);
199196
}
200197

198+
/// remove all residual state from previous lock files.
199+
pub fn clear_lock(&mut self) {
200+
trace!("clear_lock");
201+
self.locked = HashMap::new();
202+
}
203+
201204
pub fn register_lock(&mut self, id: PackageId, deps: Vec<PackageId>) {
202205
trace!("register_lock: {}", id);
203206
for dep in deps.iter() {
204207
trace!("\t-> {}", dep);
205208
}
206-
let sub_map = self
209+
let sub_vec = self
207210
.locked
208-
.entry(id.source_id())
209-
.or_insert_with(HashMap::new);
210-
let sub_vec = sub_map
211-
.entry(id.name().to_string())
211+
.entry((id.source_id(), id.name()))
212212
.or_insert_with(Vec::new);
213213
sub_vec.push((id, deps));
214214
}
@@ -639,8 +639,7 @@ fn lock(
639639
summary: Summary,
640640
) -> Summary {
641641
let pair = locked
642-
.get(&summary.source_id())
643-
.and_then(|map| map.get(&*summary.name()))
642+
.get(&(summary.source_id(), summary.name()))
644643
.and_then(|vec| vec.iter().find(|&&(id, _)| id == summary.package_id()));
645644

646645
trace!("locking summary of {}", summary.package_id());
@@ -729,8 +728,7 @@ fn lock(
729728
// all known locked packages to see if they match this dependency.
730729
// If anything does then we lock it to that and move on.
731730
let v = locked
732-
.get(&dep.source_id())
733-
.and_then(|map| map.get(&*dep.package_name()))
731+
.get(&(dep.source_id(), dep.package_name()))
734732
.and_then(|vec| vec.iter().find(|&&(id, _)| dep.matches_id(id)));
735733
if let Some(&(id, _)) = v {
736734
trace!("\tsecond hit on {}", id);

src/cargo/ops/resolve.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ fn register_previous_locks(
584584
// the registry as a locked dependency.
585585
let keep = |id: &PackageId| keep(id) && !avoid_locking.contains(id);
586586

587+
registry.clear_lock();
587588
for node in resolve.iter().filter(keep) {
588589
let deps = resolve
589590
.deps_not_replaced(node)

tests/testsuite/build.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4939,3 +4939,44 @@ hello stderr!
49394939
stdout
49404940
);
49414941
}
4942+
4943+
use cargo_test_support::registry::Dependency;
4944+
4945+
#[cargo_test]
4946+
fn reduced_reproduction_8249() {
4947+
// https://github.com/rust-lang/cargo/issues/8249
4948+
Package::new("a-src", "0.1.0").links("a").publish();
4949+
Package::new("a-src", "0.2.0").links("a").publish();
4950+
4951+
Package::new("b", "0.1.0")
4952+
.add_dep(Dependency::new("a-src", "0.1").optional(true))
4953+
.publish();
4954+
Package::new("b", "0.2.0")
4955+
.add_dep(Dependency::new("a-src", "0.2").optional(true))
4956+
.publish();
4957+
4958+
Package::new("c", "1.0.0")
4959+
.add_dep(&Dependency::new("b", "0.1.0"))
4960+
.publish();
4961+
4962+
let p = project()
4963+
.file(
4964+
"Cargo.toml",
4965+
r#"
4966+
[package]
4967+
name = "foo"
4968+
version = "0.1.0"
4969+
4970+
[dependencies]
4971+
b = { version = "*", features = ["a-src"] }
4972+
a-src = "*"
4973+
"#,
4974+
)
4975+
.file("src/lib.rs", "")
4976+
.build();
4977+
4978+
p.cargo("generate-lockfile").run();
4979+
cargo::util::paths::append(&p.root().join("Cargo.toml"), b"c = \"*\"").unwrap();
4980+
p.cargo("check").run();
4981+
p.cargo("check").run();
4982+
}

0 commit comments

Comments
 (0)