diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index 477e7ce6c773..e901a4d27fb7 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -779,6 +779,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { Poll::Pending } } else { + let mut precise_yanked_in_use = false; ready!(self .index .query_inner(dep.package_name(), &req, &mut *self.ops, &mut |s| { @@ -786,15 +787,38 @@ impl<'cfg> Source for RegistrySource<'cfg> { QueryKind::Exact => dep.matches(s.as_summary()), QueryKind::Fuzzy => true, }; + if !matched { + return; + } // 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` - if matched - && (!s.is_yanked() || self.yanked_whitelist.contains(&s.package_id())) - { + if !s.is_yanked() { + callback(s); + } else if self.yanked_whitelist.contains(&s.package_id()) { callback(s); + } else if req.is_precise() { + precise_yanked_in_use = true; + if self.config.cli_unstable().unstable_options { + callback(s); + } } }))?; + if precise_yanked_in_use { + self.config + .cli_unstable() + .fail_if_stable_opt("--precise ", 4225)?; + let name = dep.package_name(); + let version = req + .precise_version() + .expect("--precise in use"); + let mut shell = self.config.shell(); + shell.warn(format_args!( + "a yanked package `{name}@{version}` is requested by the `--precise` flag", + ))?; + shell.note("it is not recommended to depend on a yanked version")?; + shell.note("if possible, try other SemVer-compatbile versions")?; + } if called { return Poll::Ready(Ok(())); } diff --git a/src/cargo/util/semver_ext.rs b/src/cargo/util/semver_ext.rs index dcf680a509b2..ae32483f3f3d 100644 --- a/src/cargo/util/semver_ext.rs +++ b/src/cargo/util/semver_ext.rs @@ -87,6 +87,18 @@ impl OptVersionReq { }; } + pub fn is_precise(&self) -> bool { + matches!(self, OptVersionReq::Precise(..)) + } + + /// Gets the version to which this req is precise to, if any. + pub fn precise_version(&self) -> Option<&Version> { + match self { + OptVersionReq::Precise(version, _) => Some(version), + _ => None, + } + } + pub fn is_locked(&self) -> bool { matches!(self, OptVersionReq::Locked(..)) } diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index fe2df05b955c..684a85b089ee 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1400,10 +1400,34 @@ fn precise_yanked() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[ERROR] no matching package named `bar` found -location searched: registry `crates-io` -required by package `foo v0.0.0 ([CWD])` +[ERROR] failed to get `bar` as a dependency of package `foo v0.0.0 ([CWD])` + +Caused by: + failed to query replaced source registry `crates-io` + +Caused by: + the `--precise ` flag is unstable[..] + See [..] + See [..] +", + ) + .run(); + + p.cargo("update --precise 0.1.1 bar") + .masquerade_as_nightly_cargo(&["--precise "]) + .arg("-Zunstable-options") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[WARNING] a yanked package `bar@0.1.1` is requested by the `--precise` flag +[NOTE] it is not recommended to depend on a yanked version +[NOTE] if possible, try other SemVer-compatbile versions +[UPDATING] bar v0.1.0 -> v0.1.1 ", ) - .run() + .run(); + + // Use yanked version. + let lockfile = p.read_lockfile(); + assert!(lockfile.contains("\nname = \"bar\"\nversion = \"0.1.1\"")); }