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

clean: add --with-downloads option #10070

Closed
wants to merge 5 commits into from
Closed
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
5 changes: 5 additions & 0 deletions src/bin/cargo/commands/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub fn cli() -> App {
subcommand("clean")
.about("Remove artifacts that cargo has generated in the past")
.arg(opt("quiet", "Do not print cargo log messages").short("q"))
.arg(opt(
"with-downloads",
"Whether to also clean Cargo's cache directories holding downloaded crates",
))
.arg_package_spec_simple("Package to clean artifacts for")
.arg_manifest_path()
.arg_target_triple("Target triple to clean output for")
Expand All @@ -31,6 +35,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
requested_profile: args.get_profile_name(config, "dev", ProfileChecking::Custom)?,
profile_specified: args.is_present("profile") || args.is_present("release"),
doc: args.is_present("doc"),
with_downloads: args.is_present("with-downloads"),
};
ops::clean(&ws, &opts)?;
Ok(())
Expand Down
22 changes: 21 additions & 1 deletion src/cargo/core/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt;

use crate::core::package::PackageSet;
use crate::core::{Dependency, Package, PackageId, Summary};
use crate::util::{CargoResult, Config};
use crate::util::{CargoResult, Config, Filesystem};

mod source_id;

Expand Down Expand Up @@ -101,6 +101,10 @@ pub trait Source {
/// Query if a package is yanked. Only registry sources can mark packages
/// as yanked. This ignores the yanked whitelist.
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool>;

fn source_cache(&mut self) -> Option<&mut Filesystem>;

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem>;
}

pub enum MaybePackage {
Expand Down Expand Up @@ -178,6 +182,14 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
fn is_yanked(&mut self, pkg: PackageId) -> CargoResult<bool> {
(**self).is_yanked(pkg)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
(**self).source_cache()
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
(**self).dot_crate_cache()
}
}

impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T {
Expand Down Expand Up @@ -240,6 +252,14 @@ impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T {
fn is_yanked(&mut self, pkg: PackageId) -> CargoResult<bool> {
(**self).is_yanked(pkg)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
(**self).source_cache()
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
(**self).dot_crate_cache()
}
}

/// A `HashMap` of `SourceId` -> `Box<Source>`.
Expand Down
41 changes: 41 additions & 0 deletions src/cargo/ops/cargo_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use crate::core::compiler::{CompileKind, CompileMode, Layout, RustcTargetData};
use crate::core::profiles::Profiles;
use crate::core::{PackageIdSpec, TargetKind, Workspace};
use crate::ops;
use crate::sources::SourceConfigMap;
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::lev_distance;
use crate::util::Config;

use anyhow::Context as _;
use cargo_util::paths;
use std::collections::{hash_map, HashMap};
use std::fs;
use std::path::Path;

Expand All @@ -24,6 +26,8 @@ pub struct CleanOptions<'a> {
pub requested_profile: InternedString,
/// Whether to just clean the doc directory
pub doc: bool,
/// Whether to also clean the package cache
pub with_downloads: bool,
}

/// Cleans the package's build artifacts.
Expand Down Expand Up @@ -53,6 +57,12 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
// Note that we don't bother grabbing a lock here as we're just going to
// blow it all away anyway.
if opts.spec.is_empty() {
if opts.with_downloads {
// We also need to remove src/ and cache/ from CARGO_HOME.
rm_rf(&config.registry_cache_path().into_path_unlocked(), config)?;
rm_rf(&config.registry_source_path().into_path_unlocked(), config)?;
}

return rm_rf(&target_dir.into_path_unlocked(), config);
}

Expand Down Expand Up @@ -133,6 +143,16 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
}
let packages = pkg_set.get_many(pkg_ids)?;

let mut registries = HashMap::new();
let (_pc_lock, sources) = if opts.with_downloads {
(
Some(config.acquire_package_cache_lock()?),
Some(SourceConfigMap::new(config)?),
)
} else {
(None, None)
};

for pkg in packages {
let pkg_dir = format!("{}-*", pkg.name());

Expand All @@ -142,6 +162,27 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
rm_rf_glob(&Path::new(&dir).join(&pkg_dir), config)?;
}

if let Some(sources) = &sources {
let source_id = pkg.package_id().source_id();
let registry = match registries.entry(source_id) {
hash_map::Entry::Occupied(o) => o.into_mut(),
hash_map::Entry::Vacant(v) => {
let reg = sources.load(source_id, &Default::default())?;
v.insert(reg)
}
};

// The as_path_unlocked are okay since we've acquired the package cache lock.
if let Some(src_path) = registry.source_cache() {
let dir = escape_glob_path(src_path.as_path_unlocked())?;
rm_rf_glob(&Path::new(&dir).join(&pkg_dir), config)?;
}
if let Some(cache_path) = registry.dot_crate_cache() {
let dir = escape_glob_path(cache_path.as_path_unlocked())?;
rm_rf_glob(&Path::new(&dir).join(&format!("{}.crate", pkg_dir)), config)?;
}
}

for target in pkg.targets() {
if target.is_custom_build() {
// Get both the build_script_build and the output directory.
Expand Down
10 changes: 9 additions & 1 deletion src/cargo/sources/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::core::source::MaybePackage;
use crate::core::{Dependency, Package, PackageId, Source, SourceId, Summary};
use crate::sources::PathSource;
use crate::util::errors::CargoResult;
use crate::util::Config;
use crate::util::{Config, Filesystem};

use anyhow::Context as _;
use cargo_util::{paths, Sha256};
Expand Down Expand Up @@ -205,4 +205,12 @@ impl<'cfg> Source for DirectorySource<'cfg> {
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool> {
Ok(false)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
None
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
None
}
}
10 changes: 9 additions & 1 deletion src/cargo/sources/git/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::sources::git::utils::GitRemote;
use crate::sources::PathSource;
use crate::util::errors::CargoResult;
use crate::util::hex::short_hash;
use crate::util::Config;
use crate::util::{Config, Filesystem};
use anyhow::Context;
use log::trace;
use std::fmt::{self, Debug, Formatter};
Expand Down Expand Up @@ -212,6 +212,14 @@ impl<'cfg> Source for GitSource<'cfg> {
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool> {
Ok(false)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
None
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
None
}
}

#[cfg(test)]
Expand Down
10 changes: 9 additions & 1 deletion src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
use crate::core::source::MaybePackage;
use crate::core::{Dependency, Package, PackageId, Source, SourceId, Summary};
use crate::ops;
use crate::util::{internal, CargoResult, Config};
use crate::util::{internal, CargoResult, Config, Filesystem};
use anyhow::Context as _;
use cargo_util::paths;
use filetime::FileTime;
Expand Down Expand Up @@ -541,4 +541,12 @@ impl<'cfg> Source for PathSource<'cfg> {
fn is_yanked(&mut self, _pkg: PackageId) -> CargoResult<bool> {
Ok(false)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
None
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
None
}
}
4 changes: 4 additions & 0 deletions src/cargo/sources/registry/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,8 @@ impl<'cfg> RegistryData for LocalRegistry<'cfg> {
) -> CargoResult<File> {
panic!("this source doesn't download")
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
None
}
}
10 changes: 10 additions & 0 deletions src/cargo/sources/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@ pub trait RegistryData {
/// (remote=git, local=files).
fn index_path(&self) -> &Filesystem;

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem>;

/// Loads the JSON for a specific named package from the index.
///
/// * `root` is the root path to the index.
Expand Down Expand Up @@ -790,4 +792,12 @@ impl<'cfg> Source for RegistrySource<'cfg> {
}
self.index.is_yanked(pkg, &mut *self.ops)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
Some(&mut self.src_path)
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
self.ops.dot_crate_cache()
}
}
4 changes: 4 additions & 0 deletions src/cargo/sources/registry/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
}
false
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
Some(&mut self.cache_path)
}
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
Expand Down
9 changes: 9 additions & 0 deletions src/cargo/sources/replaced.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::core::source::MaybePackage;
use crate::core::{Dependency, Package, PackageId, Source, SourceId, Summary};
use crate::util::errors::CargoResult;
use crate::util::Filesystem;

use anyhow::Context as _;

Expand Down Expand Up @@ -127,4 +128,12 @@ impl<'cfg> Source for ReplacedSource<'cfg> {
fn is_yanked(&mut self, pkg: PackageId) -> CargoResult<bool> {
self.inner.is_yanked(pkg)
}

fn source_cache(&mut self) -> Option<&mut Filesystem> {
self.inner.source_cache()
}

fn dot_crate_cache(&mut self) -> Option<&mut Filesystem> {
self.inner.dot_crate_cache()
}
}
87 changes: 86 additions & 1 deletion tests/testsuite/clean.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Tests for the `cargo clean` command.

use cargo::core::SourceId;
use cargo_test_support::install::cargo_home;
use cargo_test_support::paths::is_symlink;
use cargo_test_support::registry::Package;
use cargo_test_support::registry::{registry_url, Package};
use cargo_test_support::{
basic_bin_manifest, basic_manifest, git, main_file, project, project_in, rustc_host,
};
Expand Down Expand Up @@ -337,6 +339,89 @@ fn clean_verbose() {
p.cargo("build").run();
}

#[cargo_test]
fn clean_with_downloads() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[dependencies]
bar = "0.1"
baz = "0.1"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();

Package::new("bar", "0.1.0").publish();
Package::new("baz", "0.1.0").publish();

p.cargo("build").run();

let src_cache = cargo_home().join("registry").join("src");
let dot_crate_cache = cargo_home().join("registry").join("cache");
assert!(src_cache.exists());
assert!(dot_crate_cache.exists());
p.cargo("clean --with-downloads").with_stdout("").run();
assert!(!src_cache.exists());
assert!(!dot_crate_cache.exists());
}
#[cargo_test]
fn clean_package_with_downloads() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[dependencies]
bar = "0.1"
baz = "0.1"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();

Package::new("bar", "0.1.0").publish();
Package::new("baz", "0.1.0").publish();

p.cargo("build").run();

let id = SourceId::for_registry(&registry_url()).unwrap();
let hash = cargo::util::hex::short_hash(&id);
let src_cache = cargo_home()
.join("registry")
.join("src")
.join(format!("-{}", hash));
let bar_src_cache = src_cache.join(format!("bar-0.1.0"));
let baz_src_cache = src_cache.join(format!("baz-0.1.0"));
let dot_crate_cache = cargo_home()
.join("registry")
.join("cache")
.join(format!("-{}", hash));
let bar_dot_crate_cache = dot_crate_cache.join(format!("bar-0.1.0.crate"));
let baz_dot_crate_cache = dot_crate_cache.join(format!("baz-0.1.0.crate"));
assert!(bar_src_cache.exists());
assert!(baz_src_cache.exists());
assert!(bar_dot_crate_cache.exists());
assert!(baz_dot_crate_cache.exists());
p.cargo("clean --with-downloads -p bar")
.with_stdout("")
.run();
assert!(!bar_src_cache.exists());
assert!(baz_src_cache.exists());
assert!(!bar_dot_crate_cache.exists());
assert!(baz_dot_crate_cache.exists());
}

#[cargo_test]
fn clean_remove_rlib_rmeta() {
let p = project()
Expand Down