Skip to content

Commit 8fe3bde

Browse files
committed
Allow cargo update --precise with metadata.
1 parent 39ed55e commit 8fe3bde

File tree

3 files changed

+113
-12
lines changed

3 files changed

+113
-12
lines changed

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
use std::collections::{BTreeMap, HashSet};
2-
3-
use log::debug;
4-
use termcolor::Color::{self, Cyan, Green, Red};
5-
61
use crate::core::registry::PackageRegistry;
72
use crate::core::resolver::features::{CliFeatures, HasDevUnits};
83
use crate::core::{PackageId, PackageIdSpec};
94
use crate::core::{Resolve, SourceId, Workspace};
105
use crate::ops;
116
use crate::util::config::Config;
127
use crate::util::CargoResult;
8+
use anyhow::Context;
9+
use log::debug;
10+
use std::collections::{BTreeMap, HashSet};
11+
use termcolor::Color::{self, Cyan, Green, Red};
1312

1413
pub struct UpdateOptions<'a> {
1514
pub config: &'a Config,
@@ -95,6 +94,9 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
9594
// seems like a pretty hokey reason to single out
9695
// the registry as well.
9796
let precise = if dep.source_id().is_registry() {
97+
semver::Version::parse(precise).with_context(|| {
98+
format!("invalid version format for precise version `{}`", precise)
99+
})?;
98100
format!("{}={}->{}", dep.name(), dep.version(), precise)
99101
} else {
100102
precise.to_string()

src/cargo/sources/registry/index.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -460,19 +460,40 @@ impl<'cfg> RegistryIndex<'cfg> {
460460
// this source, `<p_req>` is the version installed and `<f_req> is the
461461
// version requested (argument to `--precise`).
462462
let name = dep.package_name().as_str();
463-
let summaries = summaries.filter(|s| match source_id.precise() {
463+
let precise = match source_id.precise() {
464464
Some(p) if p.starts_with(name) && p[name.len()..].starts_with('=') => {
465465
let mut vers = p[name.len() + 1..].splitn(2, "->");
466-
if dep
467-
.version_req()
468-
.matches(&vers.next().unwrap().to_semver().unwrap())
469-
{
470-
vers.next().unwrap() == s.version().to_string()
466+
let current_vers = vers.next().unwrap().to_semver().unwrap();
467+
let requested_vers = vers.next().unwrap().to_semver().unwrap();
468+
Some((current_vers, requested_vers))
469+
}
470+
_ => None,
471+
};
472+
let summaries = summaries.filter(|s| match &precise {
473+
Some((current, requested)) => {
474+
if dep.version_req().matches(current) {
475+
// Unfortunately crates.io allows versions to differ only
476+
// by build metadata. This shouldn't be allowed, but since
477+
// it is, this will honor it if requested. However, if not
478+
// specified, then ignore it.
479+
let s_vers = s.version();
480+
match (s_vers.build.is_empty(), requested.build.is_empty()) {
481+
(true, true) => s_vers == requested,
482+
(true, false) => false,
483+
(false, true) => {
484+
// Strip out the metadata.
485+
s_vers.major == requested.major
486+
&& s_vers.minor == requested.minor
487+
&& s_vers.patch == requested.patch
488+
&& s_vers.pre == requested.pre
489+
}
490+
(false, false) => s_vers == requested,
491+
}
471492
} else {
472493
true
473494
}
474495
}
475-
_ => true,
496+
None => true,
476497
});
477498

478499
let mut count = 0;

tests/testsuite/update.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,81 @@ fn workspace_only() {
678678
assert!(!lock1.contains("0.0.2"));
679679
assert!(!lock2.contains("0.0.1"));
680680
}
681+
682+
#[cargo_test]
683+
fn precise_with_build_metadata() {
684+
// +foo syntax shouldn't be necessary with --precise
685+
Package::new("bar", "0.1.0+extra-stuff.0").publish();
686+
let p = project()
687+
.file(
688+
"Cargo.toml",
689+
r#"
690+
[package]
691+
name = "foo"
692+
version = "0.1.0"
693+
694+
[dependencies]
695+
bar = "0.1"
696+
"#,
697+
)
698+
.file("src/lib.rs", "")
699+
.build();
700+
p.cargo("generate-lockfile").run();
701+
Package::new("bar", "0.1.1+extra-stuff.1").publish();
702+
Package::new("bar", "0.1.2+extra-stuff.2").publish();
703+
704+
p.cargo("update -p bar --precise 0.1")
705+
.with_status(101)
706+
.with_stderr(
707+
"\
708+
error: invalid version format for precise version `0.1`
709+
710+
Caused by:
711+
unexpected end of input while parsing minor version number
712+
",
713+
)
714+
.run();
715+
716+
p.cargo("update -p bar --precise 0.1.1+does-not-match")
717+
.with_status(101)
718+
.with_stderr(
719+
"\
720+
[UPDATING] [..] index
721+
error: no matching package named `bar` found
722+
location searched: registry `crates-io`
723+
required by package `foo v0.1.0 ([ROOT]/foo)`
724+
",
725+
)
726+
.run();
727+
728+
p.cargo("update -p bar --precise 0.1.1")
729+
.with_stderr(
730+
"\
731+
[UPDATING] [..] index
732+
[UPDATING] bar v0.1.0+extra-stuff.0 -> v0.1.1+extra-stuff.1
733+
",
734+
)
735+
.run();
736+
737+
Package::new("bar", "0.1.3").publish();
738+
p.cargo("update -p bar --precise 0.1.3+foo")
739+
.with_status(101)
740+
.with_stderr(
741+
"\
742+
[UPDATING] [..] index
743+
error: no matching package named `bar` found
744+
location searched: registry `crates-io`
745+
required by package `foo v0.1.0 ([ROOT]/foo)`
746+
",
747+
)
748+
.run();
749+
750+
p.cargo("update -p bar --precise 0.1.3")
751+
.with_stderr(
752+
"\
753+
[UPDATING] [..] index
754+
[UPDATING] bar v0.1.1+extra-stuff.1 -> v0.1.3
755+
",
756+
)
757+
.run();
758+
}

0 commit comments

Comments
 (0)