|
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