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

Fix a number of bugs with cargo clean #2131

Merged
merged 1 commit into from
Nov 15, 2015
Merged
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
3 changes: 3 additions & 0 deletions src/bin/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct Options {
flag_verbose: bool,
flag_quiet: bool,
flag_color: Option<String>,
flag_release: bool,
}

pub const USAGE: &'static str = "
Expand All @@ -25,6 +26,7 @@ Options:
-p SPEC, --package SPEC ... Package to clean artifacts for
--manifest-path PATH Path to the manifest to the package to clean
--target TRIPLE Target triple to clean output for (default all)
--release Whether or not to clean release artifacts
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
Expand All @@ -45,6 +47,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
config: config,
spec: &options.flag_package,
target: options.flag_target.as_ref().map(|s| &s[..]),
release: options.flag_release,
};
ops::clean(&root, &opts).map(|_| None).map_err(|err| {
CliError::from_boxed(err, 101)
Expand Down
60 changes: 37 additions & 23 deletions src/cargo/ops/cargo_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ use std::fs;
use std::io::prelude::*;
use std::path::Path;

use core::{Package, PackageSet, Profiles, Profile};
use core::{Package, PackageSet, Profiles};
use core::source::{Source, SourceMap};
use core::registry::PackageRegistry;
use util::{CargoResult, human, ChainError, Config};
use ops::{self, Layout, Context, BuildConfig, Kind, Unit};

pub struct CleanOptions<'a> {
pub spec: &'a [String],
pub target: Option<&'a str>,
pub config: &'a Config,
pub release: bool,
}

/// Cleans the project from build artifacts.
Expand All @@ -37,39 +39,51 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
// filenames and such
let srcs = SourceMap::new();
let pkgs = PackageSet::new(&[]);
let profiles = Profiles::default();

let dest = if opts.release {"release"} else {"debug"};
let host_layout = Layout::new(opts.config, &root, None, dest);
let target_layout = opts.target.map(|target| {
Layout::new(opts.config, &root, Some(target), dest)
});

let cx = try!(Context::new(&resolve, &srcs, &pkgs, opts.config,
Layout::at(target_dir),
None, BuildConfig::default(),
&profiles));
host_layout, target_layout,
BuildConfig::default(),
root.manifest().profiles()));

let mut registry = PackageRegistry::new(opts.config);

// resolve package specs and remove the corresponding packages
for spec in opts.spec {
let pkgid = try!(resolve.query(spec));

// Translate the PackageId to a Package
let pkg = {
let mut source = pkgid.source_id().load(opts.config);
try!(source.update());
(try!(source.get(&[pkgid.clone()]))).into_iter().next().unwrap()
try!(registry.add_sources(&[pkgid.source_id().clone()]));
(try!(registry.get(&[pkgid.clone()]))).into_iter().next().unwrap()
};

// And finally, clean everything out!
for target in pkg.targets().iter() {
// TODO: `cargo clean --release`
let layout = Layout::new(opts.config, &root, opts.target, "debug");
try!(rm_rf(&layout.fingerprint(&pkg)));
let profiles = [Profile::default_dev(), Profile::default_test()];
for profile in profiles.iter() {
let unit = Unit {
pkg: &pkg,
target: target,
profile: profile,
kind: Kind::Target,
};
for filename in try!(cx.target_filenames(&unit)).iter() {
try!(rm_rf(&layout.dest().join(&filename)));
try!(rm_rf(&layout.deps().join(&filename)));
for target in pkg.targets() {
for kind in [Kind::Host, Kind::Target].iter() {
let layout = cx.layout(&pkg, *kind);
try!(rm_rf(&layout.proxy().fingerprint(&pkg)));
try!(rm_rf(&layout.build(&pkg)));
let Profiles {
ref release, ref dev, ref test, ref bench, ref doc,
ref custom_build,
} = *root.manifest().profiles();
for profile in [release, dev, test, bench, doc, custom_build].iter() {
let unit = Unit {
pkg: &pkg,
target: target,
profile: profile,
kind: *kind,
};
let root = cx.out_dir(&unit);
for filename in try!(cx.target_filenames(&unit)).iter() {
try!(rm_rf(&root.join(&filename)));
}
}
}
}
Expand Down
136 changes: 135 additions & 1 deletion tests/test_cargo_clean.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::env;

use support::{project, execs, main_file, basic_bin_manifest};
use support::{git, project, execs, main_file, basic_bin_manifest};
use support::{COMPILING, RUNNING};
use support::registry::Package;
use hamcrest::{assert_that, existing_dir, existing_file, is_not};

fn setup() {
Expand Down Expand Up @@ -93,3 +95,135 @@ test!(clean_multiple_packages {
assert_that(d1_path, is_not(existing_file()));
assert_that(d2_path, is_not(existing_file()));
});

test!(clean_release {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
a = { path = "a" }
"#)
.file("src/main.rs", "fn main() {}")
.file("a/Cargo.toml", r#"
[package]
name = "a"
version = "0.0.1"
authors = []
"#)
.file("a/src/lib.rs", "");
p.build();

assert_that(p.cargo_process("build").arg("--release"),
execs().with_status(0));

assert_that(p.cargo("clean").arg("-p").arg("foo"),
execs().with_status(0));
assert_that(p.cargo("build").arg("--release"),
execs().with_status(0).with_stdout(""));

assert_that(p.cargo("clean").arg("-p").arg("foo").arg("--release"),
execs().with_status(0));
assert_that(p.cargo("build").arg("--release"),
execs().with_status(0).with_stdout(&format!("\
{compiling} foo v0.0.1 ([..])
", compiling = COMPILING)));
});

test!(build_script {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
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!(!std::fs::metadata(out.join("out")).is_ok());
}
}
"#)
.file("a/src/lib.rs", "");
p.build();

assert_that(p.cargo_process("build").env("FIRST", "1"),
execs().with_status(0));
assert_that(p.cargo("clean").arg("-p").arg("foo"),
execs().with_status(0));
assert_that(p.cargo("build").arg("-v"),
execs().with_status(0).with_stdout(&format!("\
{compiling} foo v0.0.1 ([..])
{running} `rustc build.rs [..]`
{running} `[..]build-script-build[..]`
{running} `rustc src[..]main.rs [..]`
", compiling = COMPILING, running = RUNNING)));
});

test!(clean_git {
let git = git::new("dep", |project| {
project.file("Cargo.toml", r#"
[project]
name = "dep"
version = "0.5.0"
authors = []
"#)
.file("src/lib.rs", "")
}).unwrap();

let p = project("foo")
.file("Cargo.toml", &format!(r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
dep = {{ git = '{}' }}
"#, git.url()))
.file("src/main.rs", "fn main() {}");
p.build();

assert_that(p.cargo_process("build"),
execs().with_status(0));
assert_that(p.cargo("clean").arg("-p").arg("dep"),
execs().with_status(0).with_stdout(""));
assert_that(p.cargo("build"),
execs().with_status(0));
});

test!(registry {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1"
"#)
.file("src/main.rs", "fn main() {}");
p.build();

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

assert_that(p.cargo_process("build"),
execs().with_status(0));
assert_that(p.cargo("clean").arg("-p").arg("bar"),
execs().with_status(0).with_stdout(""));
assert_that(p.cargo("build"),
execs().with_status(0));
});