Skip to content

Commit 98766fb

Browse files
committed
If there's a version in the lock file only use that exact version
1 parent 1db86b0 commit 98766fb

File tree

2 files changed

+21
-47
lines changed

2 files changed

+21
-47
lines changed

src/cargo/sources/registry/index.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -439,11 +439,9 @@ impl<'cfg> RegistryIndex<'cfg> {
439439
/// checking the integrity of a downloaded package matching the checksum in
440440
/// the index file, aka [`IndexSummary`].
441441
pub fn hash(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> Poll<CargoResult<&str>> {
442-
let req = OptVersionReq::exact(pkg.version());
442+
let req = OptVersionReq::lock_to_exact(pkg.version());
443443
let summary = self.summaries(pkg.name(), &req, load)?;
444-
let summary = ready!(summary)
445-
.filter(|s| s.package_id().version() == pkg.version())
446-
.next();
444+
let summary = ready!(summary).next();
447445
Poll::Ready(Ok(summary
448446
.ok_or_else(|| internal(format!("no hash listed for {}", pkg)))?
449447
.as_summary()
@@ -697,10 +695,8 @@ impl<'cfg> RegistryIndex<'cfg> {
697695
pkg: PackageId,
698696
load: &mut dyn RegistryData,
699697
) -> Poll<CargoResult<bool>> {
700-
let req = OptVersionReq::exact(pkg.version());
701-
let found = ready!(self.summaries(pkg.name(), &req, load))?
702-
.filter(|s| s.package_id().version() == pkg.version())
703-
.any(|s| s.is_yanked());
698+
let req = OptVersionReq::lock_to_exact(pkg.version());
699+
let found = ready!(self.summaries(pkg.name(), &req, load))?.any(|s| s.is_yanked());
704700
Poll::Ready(Ok(found))
705701
}
706702
}

src/cargo/util/semver_ext.rs

+17-39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use semver::{Comparator, Op, Version, VersionReq};
22
use serde_untagged::UntaggedEnumVisitor;
3-
use std::cmp::Ordering;
43
use std::fmt::{self, Display};
54

65
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
@@ -44,6 +43,13 @@ impl OptVersionReq {
4443
OptVersionReq::Req(VersionReq::exact(version))
4544
}
4645

46+
// Since some registries have allowed crate versions to differ only by build metadata,
47+
// A query using OptVersionReq::exact return nondeterministic results.
48+
// So we `lock_to` the exact version were interested in.
49+
pub fn lock_to_exact(version: &Version) -> Self {
50+
OptVersionReq::Locked(version.clone(), VersionReq::exact(version))
51+
}
52+
4753
pub fn is_exact(&self) -> bool {
4854
match self {
4955
OptVersionReq::Any => false,
@@ -84,7 +90,16 @@ impl OptVersionReq {
8490
match self {
8591
OptVersionReq::Any => true,
8692
OptVersionReq::Req(req) => req.matches(version),
87-
OptVersionReq::Locked(v, _) => v.cmp_precedence(version) == Ordering::Equal,
93+
OptVersionReq::Locked(v, _) => {
94+
// Generally, cargo is of the opinion that semver metadata should be ignored.
95+
// If your registry has two versions that only differing metadata you get the bugs you deserve.
96+
// We also believe that lock files should ensure reproducibility
97+
// and protect against mutations from the registry.
98+
// In this circumstance these two goals are in conflict, and we pick reproducibility.
99+
// If the lock file tells us that there is a version called `1.0.0+bar` then
100+
// we should not silently use `1.0.0+foo` even though they have the same version.
101+
v == version
102+
}
88103
}
89104
}
90105
}
@@ -316,40 +331,3 @@ fn is_req(value: &str) -> bool {
316331
};
317332
"<>=^~".contains(first) || value.contains('*') || value.contains(',')
318333
}
319-
320-
#[cfg(test)]
321-
mod tests {
322-
use super::*;
323-
324-
#[test]
325-
fn locked_has_the_same_with_exact() {
326-
fn test_versions(target_ver: &str, vers: &[&str]) {
327-
let ver = Version::parse(target_ver).unwrap();
328-
let exact = OptVersionReq::exact(&ver);
329-
let mut locked = exact.clone();
330-
locked.lock_to(&ver);
331-
for v in vers {
332-
let v = Version::parse(v).unwrap();
333-
assert_eq!(exact.matches(&v), locked.matches(&v));
334-
}
335-
}
336-
337-
test_versions(
338-
"1.0.0",
339-
&["1.0.0", "1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"],
340-
);
341-
test_versions("0.9.0", &["0.9.0", "0.9.1", "1.9.0", "0.0.9", "0.9.0-pre"]);
342-
test_versions("0.0.2", &["0.0.2", "0.0.1", "0.0.3", "0.0.2-pre"]);
343-
test_versions(
344-
"0.1.0-beta2.a",
345-
&[
346-
"0.1.0-beta2.a",
347-
"0.9.1",
348-
"0.1.0",
349-
"0.1.1-beta2.a",
350-
"0.1.0-beta2",
351-
],
352-
);
353-
test_versions("0.1.0+meta", &["0.1.0", "0.1.0+meta", "0.1.0+any"]);
354-
}
355-
}

0 commit comments

Comments
 (0)