diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 3facbab3882..6234b814b3a 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -200,6 +200,54 @@ fn clean_specs( let pkg_dir = format!("{}-*", pkg.name()); clean_ctx.progress.on_cleaning_package(&pkg.name())?; + if clean_ctx.gctx.cli_unstable().build_dir_new_layout { + for (_compile_kind, layout) in &layouts_with_host { + let dir = layout.build_dir().build_unit(&pkg.name()); + clean_ctx.rm_rf(&dir)?; + } + + for target in pkg.targets() { + if target.is_custom_build() { + continue; + } + for &mode in &[ + CompileMode::Build, + CompileMode::Test, + CompileMode::Check { test: false }, + ] { + for (compile_kind, layout) in &layouts { + let triple = target_data.short_name(compile_kind); + let (file_types, _unsupported) = target_data + .info(*compile_kind) + .rustc_outputs(mode, target.kind(), triple, clean_ctx.gctx)?; + let artifact_dir = layout + .artifact_dir() + .expect("artifact-dir was not locked during clean"); + let uplift_dir = match target.kind() { + TargetKind::ExampleBin | TargetKind::ExampleLib(..) => { + Some(artifact_dir.examples()) + } + // Tests/benchmarks are never uplifted. + TargetKind::Test | TargetKind::Bench => None, + _ => Some(artifact_dir.dest()), + }; + // Remove the uplifted copy. + if let Some(uplift_dir) = uplift_dir { + for file_type in file_types { + let uplifted_path = + uplift_dir.join(file_type.uplift_filename(target)); + clean_ctx.rm_rf(&uplifted_path)?; + // Dep-info generated by Cargo itself. + let dep_info = uplifted_path.with_extension("d"); + clean_ctx.rm_rf(&dep_info)?; + } + } + } + } + } + continue; + } + // Clean fingerprints. for (_, layout) in &layouts_with_host { let dir = escape_glob_path(layout.build_dir().legacy_fingerprint())?; @@ -228,12 +276,6 @@ fn clean_specs( CompileMode::Check { test: false }, ] { for (compile_kind, layout) in &layouts { - if clean_ctx.gctx.cli_unstable().build_dir_new_layout { - let dir = layout.build_dir().build_unit(&pkg.name()); - clean_ctx.rm_rf_glob(&dir)?; - continue; - } - let triple = target_data.short_name(compile_kind); let (file_types, _unsupported) = target_data .info(*compile_kind) diff --git a/tests/testsuite/clean_new_layout.rs b/tests/testsuite/clean_new_layout.rs new file mode 100644 index 00000000000..33d618fabec --- /dev/null +++ b/tests/testsuite/clean_new_layout.rs @@ -0,0 +1,1037 @@ +//! Tests for the `cargo clean` command. + +use crate::prelude::*; +use cargo_test_support::compare::assert_e2e; +use cargo_test_support::registry::Package; +use cargo_test_support::str; +use cargo_test_support::{ + basic_bin_manifest, basic_manifest, git, main_file, project, project_in, rustc_host, +}; +use glob::GlobError; +use std::env; +use std::path::{Path, PathBuf}; + +#[cargo_test] +fn cargo_clean_simple() { + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(p.build_dir().is_dir()); + + p.cargo("clean") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(!p.build_dir().is_dir()); +} + +#[cargo_test] +fn different_dir() { + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .file("src/bar/a.rs", "") + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(p.build_dir().is_dir()); + + p.cargo("clean") + .cwd("src") + .with_stderr_data(str![[r#" +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(!p.build_dir().is_dir()); +} + +#[cargo_test] +fn clean_multiple_packages() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies.d1] + path = "d1" + [dependencies.d2] + path = "d2" + + [[bin]] + name = "foo" + "#, + ) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .file("d1/Cargo.toml", &basic_bin_manifest("d1")) + .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }") + .file("d2/Cargo.toml", &basic_bin_manifest("d2")) + .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }") + .build(); + + p.cargo("build -p d1 -p d2 -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + let d1_path = &p + .build_dir() + .join("debug") + .join(format!("d1{}", env::consts::EXE_SUFFIX)); + let d2_path = &p + .build_dir() + .join("debug") + .join(format!("d2{}", env::consts::EXE_SUFFIX)); + + assert!(p.bin("foo").is_file()); + assert!(d1_path.is_file()); + assert!(d2_path.is_file()); + + p.cargo("clean -p d1 -p d2") + .cwd("src") + .with_stderr_data(str![[r#" +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(p.bin("foo").is_file()); + assert!(!d1_path.is_file()); + assert!(!d2_path.is_file()); +} + +#[cargo_test] +fn clean_multiple_packages_in_glob_char_path() { + let p = project_in("[d1]") + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .build(); + let foo_path = &p.build_dir().join("debug").join("build"); + + #[cfg(not(target_env = "msvc"))] + let file_glob = "foo/*/deps/foo-*"; + + #[cfg(target_env = "msvc")] + let file_glob = "foo/*/deps/foo.pdb"; + + // Assert that build artifacts are produced + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert_ne!(get_build_artifacts(foo_path, file_glob).len(), 0); + + // Assert that build artifacts are destroyed + p.cargo("clean -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert_eq!(get_build_artifacts(foo_path, file_glob).len(), 0); +} + +fn get_build_artifacts(path: &PathBuf, file_glob: &str) -> Vec> { + let pattern = path.to_str().expect("expected utf-8 path"); + let pattern = glob::Pattern::escape(pattern); + + let path = PathBuf::from(pattern).join(file_glob); + let path = path.to_str().expect("expected utf-8 path"); + glob::glob(path) + .expect("expected glob to run") + .into_iter() + .collect::>>() +} + +#[cargo_test] +fn clean_p_only_cleans_specified_package() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = [ + "foo", + "foo_core", + "foo-base", + ] + "#, + ) + .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("foo/src/lib.rs", "//! foo") + .file("foo_core/Cargo.toml", &basic_manifest("foo_core", "0.1.0")) + .file("foo_core/src/lib.rs", "//! foo_core") + .file("foo-base/Cargo.toml", &basic_manifest("foo-base", "0.1.0")) + .file("foo-base/src/lib.rs", "//! foo-base") + .build(); + + let units_path = &p.build_dir().join("debug").join("build"); + + p.cargo("build -p foo -p foo_core -p foo-base") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + let mut fingerprint_names = get_fingerprints_without_hashes(units_path); + + // Artifacts present for all after building + assert!(fingerprint_names.iter().any(|e| e == "foo")); + let num_foo_core_artifacts = fingerprint_names + .iter() + .filter(|&e| e == "foo_core") + .count(); + assert_ne!(num_foo_core_artifacts, 0); + let num_foo_base_artifacts = fingerprint_names + .iter() + .filter(|&e| e == "foo-base") + .count(); + assert_ne!(num_foo_base_artifacts, 0); + + p.cargo("clean -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + fingerprint_names = get_fingerprints_without_hashes(units_path); + + // Cleaning `foo` leaves artifacts for the others + assert!(!fingerprint_names.iter().any(|e| e == "foo")); + assert_eq!( + fingerprint_names + .iter() + .filter(|&e| e == "foo_core") + .count(), + num_foo_core_artifacts, + ); + assert_eq!( + fingerprint_names + .iter() + .filter(|&e| e == "foo-base") + .count(), + num_foo_core_artifacts, + ); +} + +fn get_fingerprints_without_hashes(fingerprint_path: &Path) -> Vec { + std::fs::read_dir(fingerprint_path) + .expect("Build dir should be readable") + .filter_map(|entry| entry.ok()) + .map(|entry| { + let name = entry.file_name(); + name.into_string() + .expect("fingerprint name should be UTF-8") + }) + .collect() +} + +#[cargo_test] +fn clean_release() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + a = { path = "a" } + "#, + ) + .file("src/main.rs", "fn main() {}") + .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) + .file("a/src/lib.rs", "") + .build(); + + p.cargo("build --release") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("clean -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("build --release") + .with_stderr_data(str![[r#" +[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("clean -p foo --release") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("build --release") + .with_stderr_data(str![[r#" +[COMPILING] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("clean") + .arg("--release") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(p.build_dir().is_dir()); + assert!(p.build_dir().join("debug").is_dir()); + assert!(!p.build_dir().join("release").is_dir()); +} + +#[cargo_test] +fn clean_doc() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + a = { path = "a" } + "#, + ) + .file("src/main.rs", "fn main() {}") + .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) + .file("a/src/lib.rs", "") + .build(); + + p.cargo("doc") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + let doc_path = &p.build_dir().join("doc"); + + assert!(doc_path.is_dir()); + + p.cargo("clean --doc") + .with_stderr_data(str![[r#" +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + assert!(!doc_path.is_dir()); + assert!(p.build_dir().is_dir()); +} + +#[cargo_test] +fn build_script() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + build = "build.rs" + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "build.rs", + r#" + use std::path::PathBuf; + use std::env; + + fn main() { + let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + if env::var("FIRST").is_ok() { + std::fs::File::create(out.join("out")).unwrap(); + } else { + assert!(!out.join("out").exists()); + } + } + "#, + ) + .file("a/src/lib.rs", "") + .build(); + + p.cargo("build") + .env("FIRST", "1") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("build -v") + .with_stderr_data(str![[r#" +[COMPILING] foo v0.0.1 ([ROOT]/foo) +[RUNNING] `rustc [..] build.rs [..]` +[RUNNING] `[ROOT]/foo/target/debug/build/foo/[HASH]/build-script/build-script-build` +[RUNNING] `rustc [..] src/main.rs [..]` +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn clean_git() { + let git = git::new("dep", |project| { + project + .file("Cargo.toml", &basic_manifest("dep", "0.5.0")) + .file("src/lib.rs", "") + }); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + dep = {{ git = '{}' }} + "#, + git.url() + ), + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p dep") + .with_stderr_data(str![[r#" +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn registry() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + bar = "0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + Package::new("bar", "0.1.0").publish(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p bar") + .with_stderr_data(str![[r#" +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn clean_verbose() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + + [dependencies] + bar = "0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + Package::new("bar", "0.1.0").publish(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p bar --verbose") + .with_stderr_data(str![[r#" +[REMOVING] [ROOT]/foo/target/debug/build/bar +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn clean_remove_rlib_rmeta() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(p.target_debug_dir().join("libfoo.rlib").exists()); + let rmeta = p + .glob("target/debug/build/*/*/deps/*.rmeta") + .next() + .unwrap() + .unwrap(); + assert!(rmeta.exists()); + p.cargo("clean -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(!p.target_debug_dir().join("libfoo.rlib").exists()); + assert!(!rmeta.exists()); +} + +#[cargo_test] +fn package_cleans_all_the_things() { + // -p cleans everything + // Use dashes everywhere to make sure dash/underscore stuff is handled. + for crate_type in &["rlib", "dylib", "cdylib", "staticlib", "proc-macro"] { + // Try each crate type individually since the behavior changes when + // they are combined. + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo-bar" + version = "0.1.0" + edition = "2015" + + [lib] + crate-type = ["{}"] + "#, + crate_type + ), + ) + .file("src/lib.rs", "") + .build(); + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p foo-bar") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + //assert_all_clean(&p.build_dir()); // FIXME + } + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo-bar" + version = "0.1.0" + edition = "2018" + + [lib] + crate-type = ["rlib", "dylib", "staticlib"] + + [[example]] + name = "foo-ex-rlib" + crate-type = ["rlib"] + test = true + + [[example]] + name = "foo-ex-cdylib" + crate-type = ["cdylib"] + test = true + + [[example]] + name = "foo-ex-bin" + test = true + "#, + ) + .file("src/lib.rs", "") + .file("src/lib/some-main.rs", "fn main() {}") + .file("src/bin/other-main.rs", "fn main() {}") + .file("examples/foo-ex-rlib.rs", "") + .file("examples/foo-ex-cdylib.rs", "") + .file("examples/foo-ex-bin.rs", "fn main() {}") + .file("tests/foo-test.rs", "") + .file("benches/foo-bench.rs", "") + .file("build.rs", "fn main() {}") + .build(); + + p.cargo("build --all-targets") + .env("CARGO_INCREMENTAL", "1") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("test --all-targets") + .env("CARGO_INCREMENTAL", "1") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("check --all-targets") + .env("CARGO_INCREMENTAL", "1") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p foo-bar") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + //assert_all_clean(&p.build_dir()); // FIXME + + // Try some targets. + p.cargo("build --all-targets --target") + .arg(rustc_host()) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean -p foo-bar --target") + .arg(rustc_host()) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + //assert_all_clean(&p.build_dir()); // FIXME +} + +#[cargo_test] +fn clean_spec_version() { + // clean -p foo where foo matches multiple versions + Package::new("bar", "0.1.0").publish(); + Package::new("bar", "0.2.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + bar1 = {version="0.1", package="bar"} + bar2 = {version="0.2", package="bar"} + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + // Check suggestion for bad pkgid. + p.cargo("clean -p baz") + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] package ID specification `baz` did not match any packages + +[HELP] a package with a similar name exists: `bar` + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("clean -p bar:0.1.0") + .with_stderr_data(str![[r#" +[WARNING] version qualifier in `-p bar:0.1.0` is ignored, cleaning all versions of `bar` found +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + let mut walker = walkdir::WalkDir::new(p.build_dir()) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + let n = e.file_name().to_str().unwrap(); + n.starts_with("bar") || n.starts_with("libbar") + }); + if let Some(e) = walker.next() { + panic!("{:?} was not cleaned", e.path()); + } +} + +#[cargo_test] +fn clean_spec_partial_version() { + // clean -p foo where foo matches multiple versions + Package::new("bar", "0.1.0").publish(); + Package::new("bar", "0.2.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + bar1 = {version="0.1", package="bar"} + bar2 = {version="0.2", package="bar"} + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + // Check suggestion for bad pkgid. + p.cargo("clean -p baz") + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] package ID specification `baz` did not match any packages + +[HELP] a package with a similar name exists: `bar` + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("clean -p bar:0.1") + .with_stderr_data(str![[r#" +[WARNING] version qualifier in `-p bar:0.1` is ignored, cleaning all versions of `bar` found +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + let mut walker = walkdir::WalkDir::new(p.build_dir()) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + let n = e.file_name().to_str().unwrap(); + n.starts_with("bar") || n.starts_with("libbar") + }); + if let Some(e) = walker.next() { + panic!("{:?} was not cleaned", e.path()); + } +} + +#[cargo_test] +fn clean_spec_partial_version_ambiguous() { + // clean -p foo where foo matches multiple versions + Package::new("bar", "0.1.0").publish(); + Package::new("bar", "0.2.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + bar1 = {version="0.1", package="bar"} + bar2 = {version="0.2", package="bar"} + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + // Check suggestion for bad pkgid. + p.cargo("clean -p baz") + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] package ID specification `baz` did not match any packages + +[HELP] a package with a similar name exists: `bar` + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + + p.cargo("clean -p bar:0") + .with_stderr_data(str![[r#" +[WARNING] version qualifier in `-p bar:0` is ignored, cleaning all versions of `bar` found +[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + let mut walker = walkdir::WalkDir::new(p.build_dir()) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + let n = e.file_name().to_str().unwrap(); + n.starts_with("bar") || n.starts_with("libbar") + }); + if let Some(e) = walker.next() { + panic!("{:?} was not cleaned", e.path()); + } +} + +#[cargo_test] +fn clean_spec_reserved() { + // Clean when a target (like a test) has a reserved name. In this case, + // make sure `clean -p` doesn't delete the reserved directory `build` when + // there is a test named `build`. + Package::new("bar", "1.0.0") + .file("src/lib.rs", "") + .file("build.rs", "fn main() {}") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .file("tests/build.rs", "") + .build(); + + p.cargo("build --all-targets") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + assert!(p.target_debug_dir().join("build").is_dir()); + let build_test = p + .glob("target/debug/build/*/*/deps/build-*") + .next() + .unwrap() + .unwrap(); + assert!(build_test.exists()); + // Tests are never "uplifted". + assert!(p.glob("target/debug/build-*").next().is_none()); + + p.cargo("clean -p foo") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + // Should not delete this. + assert!(p.target_debug_dir().join("build").is_dir()); + + // This should not rebuild bar. + p.cargo("build -v --all-targets") + .with_stderr_data(str![[r#" +[FRESH] bar v1.0.0 +[COMPILING] foo v0.1.0 ([ROOT]/foo) +[RUNNING] `rustc [..]` +[RUNNING] `rustc [..]` +[RUNNING] `rustc [..]` +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn clean_dry_run() { + // Basic `clean --dry-run` test. + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + // Start with no files. + p.cargo("clean --dry-run") + .with_stdout_data("") + .with_stderr_data(str![[r#" +[SUMMARY] 0 files +[WARNING] no files deleted due to --dry-run + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("check") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + let before = p.build_dir().ls_r(); + p.cargo("clean --dry-run") + .with_stderr_data(str![[r#" +[SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total +[WARNING] no files deleted due to --dry-run + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + // Verify it didn't delete anything. + let after = p.build_dir().ls_r(); + assert_eq!(before, after); + let mut expected = itertools::join(before.iter().map(|p| p.to_str().unwrap()), "\n"); + expected.push_str("\n"); + let expected = snapbox::filter::normalize_paths(&expected); + let expected = assert_e2e().redactions().redact(&expected); + eprintln!("{expected}"); + // Verify the verbose output. + p.cargo("clean --dry-run -v") + .with_stdout_data(expected.unordered()) + .with_stderr_data(str![[r#" +[SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total +[WARNING] no files deleted due to --dry-run + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn doc_with_package_selection() { + // --doc with -p + let p = project().file("src/lib.rs", "").build(); + p.cargo("clean --doc -p foo") + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] --doc cannot be used with -p + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} + +#[cargo_test] +fn quiet_does_not_show_summary() { + // Checks that --quiet works with `cargo clean`, since there was a + // subtle issue with how the flag is defined as a global flag. + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + p.cargo("clean --quiet --dry-run") + .with_stdout_data("") + .with_stderr_data("") + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); + // Verify exact same command without -q would actually display something. + p.cargo("clean --dry-run") + .with_stdout_data("") + .with_stderr_data(str![[r#" +[SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total +[WARNING] no files deleted due to --dry-run + +"#]]) + .arg("-Zbuild-dir-new-layout") + .masquerade_as_nightly_cargo(&["new build-dir layout"]) + .run(); +} diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs index 8137ebce40e..f8f03b5fedb 100644 --- a/tests/testsuite/main.rs +++ b/tests/testsuite/main.rs @@ -69,6 +69,7 @@ mod cfg; mod check; mod check_cfg; mod clean; +mod clean_new_layout; mod collisions; mod compile_time_deps; mod concurrent;