Skip to content

Commit

Permalink
clean: add --include-cache option
Browse files Browse the repository at this point in the history
This patch adds the `--include-cache` flag to `cargo clean`, which
allows the command to also remove related artifacts from `CARGO_HOME`
such as downloaded `.crate` files in `~/.cargo/cache/` and extracted
source directories in `~/.cargo/src/`.

Note that this feature is not intended to replace the `cargo-cache`
command which does smart cache management. Instead, this command simply
blows away whatever it's asked to delete with no smarts whatsoever.

Fixes #3289.
  • Loading branch information
Jon Gjengset committed Nov 12, 2021
1 parent e11cd81 commit 2f375da
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 5 deletions.
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", "No output printed to stdout").short("q"))
.arg(opt(
"include-cache",
"Whether to clean Cargo's cache directories",
))
.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"),
include_cache: args.is_present("include-cache"),
};
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
44 changes: 44 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 include_cache: 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.include_cache {
// 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.include_cache {
(
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 @@ -141,6 +161,30 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
rm_rf_glob(&layout.fingerprint().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() {
rm_rf_glob(&src_path.as_path_unlocked().join(&pkg_dir), config)?;
}
if let Some(cache_path) = registry.dot_crate_cache() {
rm_rf_glob(
&cache_path
.as_path_unlocked()
.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, rustc_host};
use std::env;
use std::path::Path;
Expand Down Expand Up @@ -299,6 +301,89 @@ fn clean_verbose() {
p.cargo("build").run();
}

#[cargo_test]
fn clean_include_cache() {
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 --include-cache").with_stdout("").run();
assert!(!src_cache.exists());
assert!(!dot_crate_cache.exists());
}
#[cargo_test]
fn clean_package_include_cache() {
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 --include-cache -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

0 comments on commit 2f375da

Please sign in to comment.