Skip to content

Commit

Permalink
move handling precise up
Browse files Browse the repository at this point in the history
  • Loading branch information
Eh2406 committed Sep 27, 2023
1 parent e6aabe8 commit 4216d62
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 89 deletions.
40 changes: 3 additions & 37 deletions src/cargo/sources/registry/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,7 @@ impl<'cfg> RegistryIndex<'cfg> {
f: &mut dyn FnMut(IndexSummary),
online: bool,
) -> Poll<CargoResult<()>> {
let source_id = self.source_id;

let summaries = ready!(self.summaries(name, req, load))?;

let summaries = summaries
ready!(self.summaries(name, &req, load))?
// First filter summaries for `--offline`. If we're online then
// everything is a candidate, otherwise if we're offline we're only
// going to consider candidates which are actually present on disk.
Expand All @@ -657,38 +653,8 @@ impl<'cfg> RegistryIndex<'cfg> {
// Next filter out all yanked packages. Some yanked packages may
// leak through if they're in a whitelist (aka if they were
// previously in `Cargo.lock`
.filter(|s| !s.is_yanked() || yanked_whitelist.contains(&s.package_id()));

// Handle `cargo update --precise` here.
let precise = source_id.precise_registry_version(name.as_str());
let summaries = summaries.filter(|s| match &precise {
Some((current, requested)) => {
if req.matches(current) {
// Unfortunately crates.io allows versions to differ only
// by build metadata. This shouldn't be allowed, but since
// it is, this will honor it if requested. However, if not
// specified, then ignore it.
let s_vers = s.package_id().version();
match (s_vers.build.is_empty(), requested.build.is_empty()) {
(true, true) => s_vers == requested,
(true, false) => false,
(false, true) => {
// Strip out the metadata.
s_vers.major == requested.major
&& s_vers.minor == requested.minor
&& s_vers.patch == requested.patch
&& s_vers.pre == requested.pre
}
(false, false) => s_vers == requested,
}
} else {
true
}
}
None => true,
});

summaries.for_each(f);
.filter(|s| !s.is_yanked() || yanked_whitelist.contains(&s.package_id()))
.for_each(f);
Poll::Ready(Ok(()))
}

Expand Down
28 changes: 17 additions & 11 deletions src/cargo/sources/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,17 +709,27 @@ impl<'cfg> Source for RegistrySource<'cfg> {
kind: QueryKind,
f: &mut dyn FnMut(Summary),
) -> Poll<CargoResult<()>> {
// If this is a precise dependency, then it came from a lock file and in
let mut req = dep.version_req().clone();

// Handle `cargo update --precise` here.
if let Some((_, requested)) = self
.source_id
.precise_registry_version(dep.package_name().as_str())
.filter(|(c, _)| req.matches(c))
{
req.lock_to(&requested);
}

// If this is a locked dependency, then it came from a lock file and in
// theory the registry is known to contain this version. If, however, we
// come back with no summaries, then our registry may need to be
// updated, so we fall back to performing a lazy update.
if kind == QueryKind::Exact && dep.source_id().precise().is_some() && !self.ops.is_updated()
{
if kind == QueryKind::Exact && req.is_locked() && !self.ops.is_updated() {
debug!("attempting query without update");
let mut called = false;
ready!(self.index.query_inner(
dep.package_name(),
dep.version_req(),
&req,
&mut *self.ops,
&self.yanked_whitelist,
&mut |s| {
Expand All @@ -740,15 +750,11 @@ impl<'cfg> Source for RegistrySource<'cfg> {
let mut called = false;
ready!(self.index.query_inner(
dep.package_name(),
dep.version_req(),
&req,
&mut *self.ops,
&self.yanked_whitelist,
&mut |s| {
let matched = match kind {
QueryKind::Exact => dep.matches(&s),
QueryKind::Fuzzy => true,
};
if matched {
if dep.matches(&s) || kind == QueryKind::Fuzzy {
f(s);
called = true;
}
Expand Down Expand Up @@ -777,7 +783,7 @@ impl<'cfg> Source for RegistrySource<'cfg> {
.index
.query_inner(
name_permutation,
dep.version_req(),
&req,
&mut *self.ops,
&self.yanked_whitelist,
f,
Expand Down
52 changes: 11 additions & 41 deletions src/cargo/util/semver_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,17 @@ impl OptVersionReq {
OptVersionReq::Any => true,
OptVersionReq::Req(req) => req.matches(version),
OptVersionReq::Locked(v, _) => {
v.major == version.major
&& v.minor == version.minor
&& v.patch == version.patch
&& v.pre == version.pre
// We wuld like to use `version == v`.
// Generally we can, lockfiles record an exact version
// which is the only one we should use on repeat builds.
// However, this is also used for the `--precise` field of cargo update
// in that context we treat a requirement that does not have build metadata as allowing any metadata.
version.major == v.major
&& version.minor == v.minor
&& version.patch == v.patch
&& version.pre == v.pre
&& (version.build == v.build
|| (!version.build.is_empty() && v.build.is_empty()))
}
}
}
Expand Down Expand Up @@ -311,40 +318,3 @@ fn is_req(value: &str) -> bool {
};
"<>=^~".contains(first) || value.contains('*') || value.contains(',')
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn locked_has_the_same_with_exact() {
fn test_versions(target_ver: &str, vers: &[&str]) {
let ver = Version::parse(target_ver).unwrap();
let exact = OptVersionReq::exact(&ver);
let mut locked = exact.clone();
locked.lock_to(&ver);
for v in vers {
let v = Version::parse(v).unwrap();
assert_eq!(exact.matches(&v), locked.matches(&v));
}
}

test_versions(
"1.0.0",
&["1.0.0", "1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"],
);
test_versions("0.9.0", &["0.9.0", "0.9.1", "1.9.0", "0.0.9", "0.9.0-pre"]);
test_versions("0.0.2", &["0.0.2", "0.0.1", "0.0.3", "0.0.2-pre"]);
test_versions(
"0.1.0-beta2.a",
&[
"0.1.0-beta2.a",
"0.9.1",
"0.1.0",
"0.1.1-beta2.a",
"0.1.0-beta2",
],
);
test_versions("0.1.0+meta", &["0.1.0", "0.1.0+meta", "0.1.0+any"]);
}
}

0 comments on commit 4216d62

Please sign in to comment.