Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read/write the encoded cargo update --precise in the same place #12629

Merged
merged 1 commit into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions src/cargo/core/source/source_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::core::PackageId;
use crate::sources::registry::CRATES_IO_HTTP_INDEX;
use crate::sources::{DirectorySource, CRATES_IO_DOMAIN, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
use crate::sources::{GitSource, PathSource, RegistrySource};
use crate::util::{config, CanonicalUrl, CargoResult, Config, IntoUrl};
use crate::util::{config, CanonicalUrl, CargoResult, Config, IntoUrl, ToSemver};
use anyhow::Context;
use serde::de;
use serde::ser;
use std::cmp::{self, Ordering};
Expand Down Expand Up @@ -430,11 +431,6 @@ impl SourceId {
}
}

/// Gets the value of the precise field.
pub fn precise(self) -> Option<&'static str> {
self.inner.precise.as_deref()
}

/// Gets the Git reference if this is a git source, otherwise `None`.
pub fn git_reference(self) -> Option<&'static GitReference> {
match self.inner.kind {
Expand All @@ -443,6 +439,33 @@ impl SourceId {
}
}

/// Gets the value of the precise field.
pub fn precise(self) -> Option<&'static str> {
self.inner.precise.as_deref()
}

/// Check if the precise data field stores information for this `name`
/// from a call to [SourceId::with_precise_registry_version].
///
/// If so return the version currently in the lock file and the version to be updated to.
/// If specified, our own source will have a precise version listed of the form
// `<pkg>=<p_req>-><f_req>` where `<pkg>` is the name of a crate on
// this source, `<p_req>` is the version installed and `<f_req>` is the
// version requested (argument to `--precise`).
pub fn precise_registry_version(
self,
name: &str,
) -> Option<(semver::Version, semver::Version)> {
self.inner
.precise
.as_deref()
.and_then(|p| p.strip_prefix(name)?.strip_prefix('='))
.map(|p| {
let (current, requested) = p.split_once("->").unwrap();
(current.to_semver().unwrap(), requested.to_semver().unwrap())
})
}

/// Creates a new `SourceId` from this source with the given `precise`.
pub fn with_precise(self, v: Option<String>) -> SourceId {
SourceId::wrap(SourceIdInner {
Expand All @@ -451,6 +474,23 @@ impl SourceId {
})
}

/// When updating a lock file on a version using `cargo update --precise`
/// the requested version is stored in the precise field.
/// On a registry dependency we also need to keep track of the package that
/// should be updated and even which of the versions should be updated.
/// All of this gets encoded in the precise field using this method.
/// The data can be read with [SourceId::precise_registry_version]
pub fn with_precise_registry_version(
self,
name: impl fmt::Display,
version: &semver::Version,
precise: &str,
) -> CargoResult<SourceId> {
semver::Version::parse(precise)
.with_context(|| format!("invalid version format for precise version `{precise}`"))?;
Ok(self.with_precise(Some(format!("{}={}->{}", name, version, precise))))
}

/// Returns `true` if the remote registry is the standard <https://crates.io>.
pub fn is_crates_io(self) -> bool {
match self.inner.kind {
Expand Down
25 changes: 12 additions & 13 deletions src/cargo/ops/cargo_generate_lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::core::{Resolve, SourceId, Workspace};
use crate::ops;
use crate::util::config::Config;
use crate::util::CargoResult;
use anyhow::Context;
use std::collections::{BTreeMap, HashSet};
use termcolor::Color::{self, Cyan, Green, Red, Yellow};
use tracing::debug;
Expand Down Expand Up @@ -88,27 +87,27 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
} else {
let mut sources = Vec::new();
for name in opts.to_update.iter() {
let dep = previous_resolve.query(name)?;
let pid = previous_resolve.query(name)?;
if opts.recursive {
fill_with_deps(&previous_resolve, dep, &mut to_avoid, &mut HashSet::new());
fill_with_deps(&previous_resolve, pid, &mut to_avoid, &mut HashSet::new());
} else {
to_avoid.insert(dep);
to_avoid.insert(pid);
sources.push(match opts.precise {
Some(precise) => {
// TODO: see comment in `resolve.rs` as well, but this
// seems like a pretty hokey reason to single out
// the registry as well.
let precise = if dep.source_id().is_registry() {
semver::Version::parse(precise).with_context(|| {
format!("invalid version format for precise version `{}`", precise)
})?;
format!("{}={}->{}", dep.name(), dep.version(), precise)
if pid.source_id().is_registry() {
pid.source_id().with_precise_registry_version(
pid.name(),
pid.version(),
precise,
)?
} else {
precise.to_string()
};
dep.source_id().with_precise(Some(precise))
pid.source_id().with_precise(Some(precise.to_string()))
}
}
None => dep.source_id().with_precise(None),
None => pid.source_id().with_precise(None),
});
}
if let Ok(unused_id) =
Expand Down
18 changes: 3 additions & 15 deletions src/cargo/sources/registry/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ use crate::core::{PackageId, SourceId, Summary};
use crate::sources::registry::{LoadResponse, RegistryData};
use crate::util::interning::InternedString;
use crate::util::IntoUrl;
use crate::util::{
internal, CargoResult, Config, Filesystem, OptVersionReq, PartialVersion, ToSemver,
};
use crate::util::{internal, CargoResult, Config, Filesystem, OptVersionReq, PartialVersion};
use anyhow::bail;
use cargo_util::{paths, registry::make_dep_path};
use semver::Version;
Expand Down Expand Up @@ -582,18 +580,8 @@ impl<'cfg> RegistryIndex<'cfg> {
.filter(|s| !s.yanked || yanked_whitelist.contains(&s.summary.package_id()))
.map(|s| s.summary.clone());

// Handle `cargo update --precise` here. If specified, our own source
// will have a precise version listed of the form
// `<pkg>=<p_req>o-><f_req>` where `<pkg>` is the name of a crate on
// this source, `<p_req>` is the version installed and `<f_req> is the
// version requested (argument to `--precise`).
let precise = source_id
.precise()
.filter(|p| p.starts_with(name) && p[name.len()..].starts_with('='))
.map(|p| {
let (current, requested) = p[name.len() + 1..].split_once("->").unwrap();
(current.to_semver().unwrap(), requested.to_semver().unwrap())
});
// Handle `cargo update --precise` here.
let precise = source_id.precise_registry_version(name);
let summaries = summaries.filter(|s| match &precise {
Some((current, requested)) => {
if req.matches(current) {
Expand Down