1 use std
::collections
::HashMap
;
5 use crate::core
::compiler
::unit_dependencies
;
6 use crate::core
::compiler
::UnitInterner
;
7 use crate::core
::compiler
::{BuildConfig, BuildContext, CompileMode, Context, Kind}
;
8 use crate::core
::profiles
::UnitFor
;
9 use crate::core
::Workspace
;
11 use crate::util
::errors
::{CargoResult, CargoResultExt}
;
12 use crate::util
::paths
;
13 use crate::util
::Config
;
15 pub struct CleanOptions
<'a
> {
16 pub config
: &'a Config
,
17 /// A list of packages to clean. If empty, everything is cleaned.
18 pub spec
: Vec
<String
>,
19 /// The target arch triple to clean, or None for the host arch
20 pub target
: Option
<String
>,
21 /// Whether to clean the release directory
23 /// Whether to just clean the doc directory
27 /// Cleans the package's build artifacts.
28 pub fn clean(ws
: &Workspace
<'_
>, opts
: &CleanOptions
<'_
>) -> CargoResult
<()> {
29 let mut target_dir
= ws
.target_dir();
30 let config
= ws
.config();
32 // If the doc option is set, we just want to delete the doc directory.
34 target_dir
= target_dir
.join("doc");
35 return rm_rf(&target_dir
.into_path_unlocked(), config
);
38 // If the release option is set, we set target to release directory
40 target_dir
= target_dir
.join("release");
43 // If we have a spec, then we need to delete some packages, otherwise, just
44 // remove the whole target directory and be done with it!
46 // Note that we don't bother grabbing a lock here as we're just going to
47 // blow it all away anyway.
48 if opts
.spec
.is_empty() {
49 return rm_rf(&target_dir
.into_path_unlocked(), config
);
52 let (packages
, resolve
) = ops
::resolve_ws(ws
)?
;
54 let profiles
= ws
.profiles();
55 let interner
= UnitInterner
::new();
56 let mut build_config
= BuildConfig
::new(config
, Some(1), &opts
.target
, CompileMode
::Build
)?
;
57 build_config
.release
= opts
.release
;
58 let bcx
= BuildContext
::new(
67 let mut units
= Vec
::new();
69 let mut kinds
= vec
![Kind
::Host
];
70 if let Some(target
) = build_config
.requested_target
{
71 kinds
.push(Kind
::Target(target
));
74 for spec
in opts
.spec
.iter() {
75 // Translate the spec to a Package
76 let pkgid
= resolve
.query(spec
)?
;
77 let pkg
= packages
.get_one(pkgid
)?
;
79 // Generate all relevant `Unit` targets for this package
80 for target
in pkg
.targets() {
81 for kind
in kinds
.iter() {
82 for mode
in CompileMode
::all_modes() {
83 for unit_for
in UnitFor
::all_values() {
84 let profile
= if mode
.is_run_custom_build() {
85 profiles
.get_profile_run_custom_build(&profiles
.get_profile(
101 let features
= resolve
.features_sorted(pkg
.package_id());
102 units
.push(bcx
.units
.intern(
103 pkg
, target
, profile
, *kind
, *mode
, features
, /*is_std*/ false,
111 let unit_dependencies
=
112 unit_dependencies
::build_unit_dependencies(&bcx
, &resolve
, None
, &units
, &[])?
;
113 let default_kind
= kinds
.last().cloned().unwrap();
114 let mut cx
= Context
::new(config
, &bcx
, unit_dependencies
, default_kind
)?
;
115 cx
.prepare_units(None
, &units
)?
;
117 for unit
in units
.iter() {
118 if unit
.mode
.is_doc() || unit
.mode
.is_doc_test() {
119 // Cleaning individual rustdoc crates is currently not supported.
120 // For example, the search index would need to be rebuilt to fully
121 // remove it (otherwise you're left with lots of broken links).
122 // Doc tests produce no output.
125 rm_rf(&cx
.files().fingerprint_dir(unit
), config
)?
;
126 if unit
.target
.is_custom_build() {
127 if unit
.mode
.is_run_custom_build() {
128 rm_rf(&cx
.files().build_script_out_dir(unit
), config
)?
;
130 rm_rf(&cx
.files().build_script_dir(unit
), config
)?
;
135 for output
in cx
.outputs(unit
)?
.iter() {
136 rm_rf(&output
.path
, config
)?
;
137 if let Some(ref dst
) = output
.hardlink
{
146 fn rm_rf(path
: &Path
, config
: &Config
) -> CargoResult
<()> {
147 let m
= fs
::metadata(path
);
148 if m
.as_ref().map(|s
| s
.is_dir()).unwrap_or(false) {
151 .verbose(|shell
| shell
.status("Removing", path
.display()))?
;
152 paths
::remove_dir_all(path
)
153 .chain_err(|| failure
::format_err
!("could not remove build directory"))?
;
154 } else if m
.is_ok() {
157 .verbose(|shell
| shell
.status("Removing", path
.display()))?
;
158 paths
::remove_file(path
)
159 .chain_err(|| failure
::format_err
!("failed to remove build artifact"))?
;