Skip to content

Commit 5f616eb

Browse files
committed
Add warnings for yanked dependencies.
This only applies for `cargo package/publish` with the publish-lockfile feature, or `cargo install --locked`.
1 parent 3d89379 commit 5f616eb

File tree

13 files changed

+225
-8
lines changed

13 files changed

+225
-8
lines changed

src/cargo/core/package.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::cell::{Cell, Ref, RefCell};
1+
use std::cell::{Cell, Ref, RefCell, RefMut};
22
use std::cmp::Ordering;
33
use std::collections::{HashMap, HashSet};
44
use std::fmt;
@@ -454,6 +454,10 @@ impl<'cfg> PackageSet<'cfg> {
454454
pub fn sources(&self) -> Ref<'_, SourceMap<'cfg>> {
455455
self.sources.borrow()
456456
}
457+
458+
pub fn sources_mut(&self) -> RefMut<'_, SourceMap<'cfg>> {
459+
self.sources.borrow_mut()
460+
}
457461
}
458462

459463
// When dynamically linked against libcurl, we want to ignore some failures

src/cargo/core/source/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ pub trait Source {
9696
/// queries, even if they are yanked. Currently only applies to registry
9797
/// sources.
9898
fn add_to_yanked_whitelist(&mut self, pkgs: &[PackageId]);
99+
100+
/// Query if a package is yanked. Only registry sources can mark packages
101+
/// as yanked. This ignores the yanked whitelist.
102+
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool>;
99103
}
100104

101105
pub enum MaybePackage {
@@ -169,6 +173,10 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
169173
fn add_to_yanked_whitelist(&mut self, pkgs: &[PackageId]) {
170174
(**self).add_to_yanked_whitelist(pkgs);
171175
}
176+
177+
fn is_yanked(&mut self, pkg: PackageId) -> CargoResult<bool> {
178+
(**self).is_yanked(pkg)
179+
}
172180
}
173181

174182
impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T {
@@ -227,6 +235,10 @@ impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T {
227235
fn add_to_yanked_whitelist(&mut self, pkgs: &[PackageId]) {
228236
(**self).add_to_yanked_whitelist(pkgs);
229237
}
238+
239+
fn is_yanked(&mut self, pkg: PackageId) -> CargoResult<bool> {
240+
(**self).is_yanked(pkg)
241+
}
230242
}
231243

232244
/// A `HashMap` of `SourceId` -> `Box<Source>`.

src/cargo/core/source/source_id.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,24 @@ impl SourceId {
228228
&self.inner.url
229229
}
230230

231-
pub fn display_registry(self) -> String {
231+
pub fn display_index(self) -> String {
232232
if self.is_default_registry() {
233233
"crates.io index".to_string()
234234
} else {
235235
format!("`{}` index", url_display(self.url()))
236236
}
237237
}
238238

239+
pub fn display_registry_name(self) -> String {
240+
if self.is_default_registry() {
241+
"crates.io".to_string()
242+
} else if let Some(name) = &self.inner.name {
243+
name.clone()
244+
} else {
245+
url_display(self.url())
246+
}
247+
}
248+
239249
/// Returns `true` if this source is from a filesystem path.
240250
pub fn is_path(self) -> bool {
241251
self.inner.kind == Kind::Path

src/cargo/ops/cargo_install.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use tempfile::Builder as TempFileBuilder;
88

99
use crate::core::compiler::Freshness;
1010
use crate::core::compiler::{DefaultExecutor, Executor};
11-
use crate::core::{Edition, PackageId, Source, SourceId, Workspace};
11+
use crate::core::resolver::Method;
12+
use crate::core::{Edition, PackageId, PackageIdSpec, Source, SourceId, Workspace};
1213
use crate::ops;
1314
use crate::ops::common_for_install_and_uninstall::*;
1415
use crate::sources::{GitSource, SourceConfigMap};
@@ -306,6 +307,8 @@ fn install_one(
306307

307308
config.shell().status("Installing", pkg)?;
308309

310+
check_yanked_install(&ws)?;
311+
309312
let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor);
310313
let compile = ops::compile_ws(&ws, Some(source), opts, &exec).chain_err(|| {
311314
if let Some(td) = td_opt.take() {
@@ -481,6 +484,32 @@ fn install_one(
481484
}
482485
}
483486

487+
fn check_yanked_install(ws: &Workspace<'_>) -> CargoResult<()> {
488+
if ws.ignore_lock() || !ws.root().join("Cargo.lock").exists() {
489+
return Ok(());
490+
}
491+
let specs = vec![PackageIdSpec::from_package_id(ws.current()?.package_id())];
492+
// It would be best if `source` could be passed in here to avoid a
493+
// duplicate "Updating", but since `source` is taken by value, then it
494+
// wouldn't be available for `compile_ws`.
495+
let (pkg_set, resolve) = ops::resolve_ws_with_method(ws, None, Method::Everything, &specs)?;
496+
let mut sources = pkg_set.sources_mut();
497+
for pkg_id in resolve.iter() {
498+
if let Some(source) = sources.get_mut(pkg_id.source_id()) {
499+
if source.is_yanked(pkg_id)? {
500+
ws.config().shell().warn(format!(
501+
"package `{}` in Cargo.lock is yanked in registry `{}`, \
502+
consider running without --locked",
503+
pkg_id,
504+
pkg_id.source_id().display_registry_name()
505+
))?;
506+
}
507+
}
508+
}
509+
510+
Ok(())
511+
}
512+
484513
/// Display a list of installed binaries.
485514
pub fn install_list(dst: Option<&str>, config: &Config) -> CargoResult<()> {
486515
let root = resolve_root(dst, config)?;

src/cargo/ops/cargo_package.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use tar::{Builder, EntryType, Header};
1212

1313
use crate::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor};
1414
use crate::core::resolver::Method;
15-
use crate::core::{Package, PackageId, PackageIdSpec, Resolve, Source, SourceId, Workspace};
15+
use crate::core::{
16+
Package, PackageId, PackageIdSpec, PackageSet, Resolve, Source, SourceId, Workspace,
17+
};
1618
use crate::ops;
1719
use crate::sources::PathSource;
1820
use crate::util::errors::{CargoResult, CargoResultExt};
@@ -425,12 +427,14 @@ fn tar(
425427
let new_pkg = src.root_package()?;
426428
let specs = vec![PackageIdSpec::from_package_id(new_pkg.package_id())];
427429
let tmp_ws = Workspace::ephemeral(new_pkg, config, None, true)?;
428-
let new_resolve = ops::resolve_ws_with_method(&tmp_ws, None, Method::Everything, &specs)?.1;
430+
let (pkg_set, new_resolve) =
431+
ops::resolve_ws_with_method(&tmp_ws, None, Method::Everything, &specs)?;
429432
// resolve_ws_with_method won't save for ephemeral, do it manually.
430433
ops::write_pkg_lockfile(&tmp_ws, &new_resolve)?;
431434
if let Some(orig_resolve) = orig_resolve {
432435
compare_resolve(config, tmp_ws.current()?, &orig_resolve, &new_resolve)?;
433436
}
437+
check_yanked(config, &pkg_set, &new_resolve)?;
434438

435439
let toml = paths::read(&new_lock_path)?;
436440
let path = format!(
@@ -536,6 +540,23 @@ fn compare_resolve(
536540
Ok(())
537541
}
538542

543+
fn check_yanked(config: &Config, pkg_set: &PackageSet<'_>, resolve: &Resolve) -> CargoResult<()> {
544+
let mut sources = pkg_set.sources_mut();
545+
for pkg_id in resolve.iter() {
546+
if let Some(source) = sources.get_mut(pkg_id.source_id()) {
547+
if source.is_yanked(pkg_id)? {
548+
config.shell().warn(format!(
549+
"package `{}` in Cargo.lock is yanked in registry `{}`, \
550+
consider updating to a version that is not yanked",
551+
pkg_id,
552+
pkg_id.source_id().display_registry_name()
553+
))?;
554+
}
555+
}
556+
}
557+
Ok(())
558+
}
559+
539560
fn run_verify(ws: &Workspace<'_>, tar: &FileLock, opts: &PackageOpts<'_>) -> CargoResult<()> {
540561
let config = ws.config();
541562
let pkg = ws.current()?;

src/cargo/sources/directory.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,8 @@ impl<'cfg> Source for DirectorySource<'cfg> {
214214
}
215215

216216
fn add_to_yanked_whitelist(&mut self, _pkgs: &[PackageId]) {}
217+
218+
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool> {
219+
Ok(false)
220+
}
217221
}

src/cargo/sources/git/source.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ impl<'cfg> Source for GitSource<'cfg> {
239239
}
240240

241241
fn add_to_yanked_whitelist(&mut self, _pkgs: &[PackageId]) {}
242+
243+
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool> {
244+
Ok(false)
245+
}
242246
}
243247

244248
#[cfg(test)]

src/cargo/sources/path.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,4 +575,8 @@ impl<'cfg> Source for PathSource<'cfg> {
575575
}
576576

577577
fn add_to_yanked_whitelist(&mut self, _pkgs: &[PackageId]) {}
578+
579+
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool> {
580+
Ok(false)
581+
}
578582
}

src/cargo/sources/registry/index.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,13 @@ impl<'cfg> RegistryIndex<'cfg> {
336336
}
337337
Ok(count)
338338
}
339+
340+
pub fn is_yanked(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> CargoResult<bool> {
341+
let summaries = self.summaries(pkg.name().as_str(), load)?;
342+
let found = summaries
343+
.iter()
344+
.filter(|&(summary, _yanked)| summary.version() == pkg.version())
345+
.any(|(_summary, yanked)| *yanked);
346+
Ok(found)
347+
}
339348
}

src/cargo/sources/registry/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ impl<'cfg> RegistrySource<'cfg> {
525525
let path = self.ops.index_path();
526526
self.index =
527527
index::RegistryIndex::new(self.source_id, path, self.config, self.index_locked);
528+
self.updated = true;
528529
Ok(())
529530
}
530531

@@ -645,10 +646,17 @@ impl<'cfg> Source for RegistrySource<'cfg> {
645646
}
646647

647648
fn describe(&self) -> String {
648-
self.source_id.display_registry()
649+
self.source_id.display_index()
649650
}
650651

651652
fn add_to_yanked_whitelist(&mut self, pkgs: &[PackageId]) {
652653
self.yanked_whitelist.extend(pkgs);
653654
}
655+
656+
fn is_yanked(&mut self, pkg: PackageId) -> CargoResult<bool> {
657+
if !self.updated {
658+
self.do_update()?;
659+
}
660+
self.index.is_yanked(pkg, &mut *self.ops)
661+
}
654662
}

0 commit comments

Comments
 (0)