|
1 | 1 | use semver::{Comparator, Op, Version, VersionReq}; |
2 | 2 | use serde_untagged::UntaggedEnumVisitor; |
3 | | -use std::cmp::Ordering; |
4 | 3 | use std::fmt::{self, Display}; |
5 | 4 |
|
6 | 5 | #[derive(PartialEq, Eq, Hash, Clone, Debug)] |
@@ -44,6 +43,13 @@ impl OptVersionReq { |
44 | 43 | OptVersionReq::Req(VersionReq::exact(version)) |
45 | 44 | } |
46 | 45 |
|
| 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 | + |
47 | 53 | pub fn is_exact(&self) -> bool { |
48 | 54 | match self { |
49 | 55 | OptVersionReq::Any => false, |
@@ -84,7 +90,16 @@ impl OptVersionReq { |
84 | 90 | match self { |
85 | 91 | OptVersionReq::Any => true, |
86 | 92 | 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 | + } |
88 | 103 | } |
89 | 104 | } |
90 | 105 | } |
@@ -316,40 +331,3 @@ fn is_req(value: &str) -> bool { |
316 | 331 | }; |
317 | 332 | "<>=^~".contains(first) || value.contains('*') || value.contains(',') |
318 | 333 | } |
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