Skip to content

Commit 016fe19

Browse files
committed
Auto merge of #12629 - Eh2406:WhyStringlyTyped, r=epage
Read/write the encoded `cargo update --precise` in the same place ### What does this PR try to resolve? There's a stringly typed interface between https://github.com/rust-lang/cargo/blob/de7537e63296ee13cb78611a988bcc9a6ac26134/src/cargo/ops/cargo_generate_lockfile.rs#L105 and https://github.com/rust-lang/cargo/blob/de7537e63296ee13cb78611a988bcc9a6ac26134/src/cargo/sources/registry/index.rs#L587, the only reason I found it with by finding the original commit #5205 As far as I can tell, anyone could just create this internally meaningful ~structure~ string by passing it on the command line. This should get cleaned up, for now by moving the encoding and decoding in to the same file. ### How should we test and review this PR? Internal refactor and test still pass. ### Additional information I am hoping that in the redesign of `cargo update` we can come up with a better design for smuggling this data from the API all the way to querying the registry. It seems like locking the dependency to the selected version would be conceptually simpler, or using the patch system, or something.
2 parents 84544d4 + 4d63fbc commit 016fe19

File tree

3 files changed

+61
-34
lines changed

3 files changed

+61
-34
lines changed

src/cargo/core/source/source_id.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::core::PackageId;
22
use crate::sources::registry::CRATES_IO_HTTP_INDEX;
33
use crate::sources::{DirectorySource, CRATES_IO_DOMAIN, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
44
use crate::sources::{GitSource, PathSource, RegistrySource};
5-
use crate::util::{config, CanonicalUrl, CargoResult, Config, IntoUrl};
5+
use crate::util::{config, CanonicalUrl, CargoResult, Config, IntoUrl, ToSemver};
6+
use anyhow::Context;
67
use serde::de;
78
use serde::ser;
89
use std::cmp::{self, Ordering};
@@ -430,11 +431,6 @@ impl SourceId {
430431
}
431432
}
432433

433-
/// Gets the value of the precise field.
434-
pub fn precise(self) -> Option<&'static str> {
435-
self.inner.precise.as_deref()
436-
}
437-
438434
/// Gets the Git reference if this is a git source, otherwise `None`.
439435
pub fn git_reference(self) -> Option<&'static GitReference> {
440436
match self.inner.kind {
@@ -443,6 +439,33 @@ impl SourceId {
443439
}
444440
}
445441

442+
/// Gets the value of the precise field.
443+
pub fn precise(self) -> Option<&'static str> {
444+
self.inner.precise.as_deref()
445+
}
446+
447+
/// Check if the precise data field stores information for this `name`
448+
/// from a call to [SourceId::with_precise_registry_version].
449+
///
450+
/// If so return the version currently in the lock file and the version to be updated to.
451+
/// If specified, our own source will have a precise version listed of the form
452+
// `<pkg>=<p_req>-><f_req>` where `<pkg>` is the name of a crate on
453+
// this source, `<p_req>` is the version installed and `<f_req>` is the
454+
// version requested (argument to `--precise`).
455+
pub fn precise_registry_version(
456+
self,
457+
name: &str,
458+
) -> Option<(semver::Version, semver::Version)> {
459+
self.inner
460+
.precise
461+
.as_deref()
462+
.and_then(|p| p.strip_prefix(name)?.strip_prefix('='))
463+
.map(|p| {
464+
let (current, requested) = p.split_once("->").unwrap();
465+
(current.to_semver().unwrap(), requested.to_semver().unwrap())
466+
})
467+
}
468+
446469
/// Creates a new `SourceId` from this source with the given `precise`.
447470
pub fn with_precise(self, v: Option<String>) -> SourceId {
448471
SourceId::wrap(SourceIdInner {
@@ -451,6 +474,23 @@ impl SourceId {
451474
})
452475
}
453476

477+
/// When updating a lock file on a version using `cargo update --precise`
478+
/// the requested version is stored in the precise field.
479+
/// On a registry dependency we also need to keep track of the package that
480+
/// should be updated and even which of the versions should be updated.
481+
/// All of this gets encoded in the precise field using this method.
482+
/// The data can be read with [SourceId::precise_registry_version]
483+
pub fn with_precise_registry_version(
484+
self,
485+
name: impl fmt::Display,
486+
version: &semver::Version,
487+
precise: &str,
488+
) -> CargoResult<SourceId> {
489+
semver::Version::parse(precise)
490+
.with_context(|| format!("invalid version format for precise version `{precise}`"))?;
491+
Ok(self.with_precise(Some(format!("{}={}->{}", name, version, precise))))
492+
}
493+
454494
/// Returns `true` if the remote registry is the standard <https://crates.io>.
455495
pub fn is_crates_io(self) -> bool {
456496
match self.inner.kind {

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::core::{Resolve, SourceId, Workspace};
55
use crate::ops;
66
use crate::util::config::Config;
77
use crate::util::CargoResult;
8-
use anyhow::Context;
98
use std::collections::{BTreeMap, HashSet};
109
use termcolor::Color::{self, Cyan, Green, Red, Yellow};
1110
use tracing::debug;
@@ -88,27 +87,27 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
8887
} else {
8988
let mut sources = Vec::new();
9089
for name in opts.to_update.iter() {
91-
let dep = previous_resolve.query(name)?;
90+
let pid = previous_resolve.query(name)?;
9291
if opts.recursive {
93-
fill_with_deps(&previous_resolve, dep, &mut to_avoid, &mut HashSet::new());
92+
fill_with_deps(&previous_resolve, pid, &mut to_avoid, &mut HashSet::new());
9493
} else {
95-
to_avoid.insert(dep);
94+
to_avoid.insert(pid);
9695
sources.push(match opts.precise {
9796
Some(precise) => {
9897
// TODO: see comment in `resolve.rs` as well, but this
9998
// seems like a pretty hokey reason to single out
10099
// the registry as well.
101-
let precise = if dep.source_id().is_registry() {
102-
semver::Version::parse(precise).with_context(|| {
103-
format!("invalid version format for precise version `{}`", precise)
104-
})?;
105-
format!("{}={}->{}", dep.name(), dep.version(), precise)
100+
if pid.source_id().is_registry() {
101+
pid.source_id().with_precise_registry_version(
102+
pid.name(),
103+
pid.version(),
104+
precise,
105+
)?
106106
} else {
107-
precise.to_string()
108-
};
109-
dep.source_id().with_precise(Some(precise))
107+
pid.source_id().with_precise(Some(precise.to_string()))
108+
}
110109
}
111-
None => dep.source_id().with_precise(None),
110+
None => pid.source_id().with_precise(None),
112111
});
113112
}
114113
if let Ok(unused_id) =

src/cargo/sources/registry/index.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,7 @@ use crate::core::{PackageId, SourceId, Summary};
9191
use crate::sources::registry::{LoadResponse, RegistryData};
9292
use crate::util::interning::InternedString;
9393
use crate::util::IntoUrl;
94-
use crate::util::{
95-
internal, CargoResult, Config, Filesystem, OptVersionReq, PartialVersion, ToSemver,
96-
};
94+
use crate::util::{internal, CargoResult, Config, Filesystem, OptVersionReq, PartialVersion};
9795
use anyhow::bail;
9896
use cargo_util::{paths, registry::make_dep_path};
9997
use semver::Version;
@@ -582,18 +580,8 @@ impl<'cfg> RegistryIndex<'cfg> {
582580
.filter(|s| !s.yanked || yanked_whitelist.contains(&s.summary.package_id()))
583581
.map(|s| s.summary.clone());
584582

585-
// Handle `cargo update --precise` here. If specified, our own source
586-
// will have a precise version listed of the form
587-
// `<pkg>=<p_req>o-><f_req>` where `<pkg>` is the name of a crate on
588-
// this source, `<p_req>` is the version installed and `<f_req> is the
589-
// version requested (argument to `--precise`).
590-
let precise = source_id
591-
.precise()
592-
.filter(|p| p.starts_with(name) && p[name.len()..].starts_with('='))
593-
.map(|p| {
594-
let (current, requested) = p[name.len() + 1..].split_once("->").unwrap();
595-
(current.to_semver().unwrap(), requested.to_semver().unwrap())
596-
});
583+
// Handle `cargo update --precise` here.
584+
let precise = source_id.precise_registry_version(name);
597585
let summaries = summaries.filter(|s| match &precise {
598586
Some((current, requested)) => {
599587
if req.matches(current) {

0 commit comments

Comments
 (0)