1 use crate::core
::InternedString
;
2 use std
::collections
::HashMap
;
6 use crate::core
::compiler
::unit_dependencies
;
7 use crate::core
::compiler
::{BuildConfig, BuildContext, CompileKind, CompileMode, Context}
;
8 use crate::core
::compiler
::{RustcTargetData, UnitInterner}
;
9 use crate::core
::profiles
::{Profiles, UnitFor}
;
10 use crate::core
::resolver
::features
::{FeatureResolver, RequestedFeatures}
;
11 use crate::core
::{PackageIdSpec, Workspace}
;
13 use crate::util
::errors
::{CargoResult, CargoResultExt}
;
14 use crate::util
::paths
;
15 use crate::util
::Config
;
17 pub struct CleanOptions
<'a
> {
18 pub config
: &'a Config
,
19 /// A list of packages to clean. If empty, everything is cleaned.
20 pub spec
: Vec
<String
>,
21 /// The target arch triple to clean, or None for the host arch
22 pub target
: Option
<String
>,
23 /// Whether to clean the release directory
24 pub profile_specified
: bool
,
25 /// Whether to clean the directory of a certain build profile
26 pub requested_profile
: InternedString
,
27 /// Whether to just clean the doc directory
31 /// Cleans the package's build artifacts.
32 pub fn clean(ws
: &Workspace
<'_
>, opts
: &CleanOptions
<'_
>) -> CargoResult
<()> {
33 let mut target_dir
= ws
.target_dir();
34 let config
= ws
.config();
36 // If the doc option is set, we just want to delete the doc directory.
38 target_dir
= target_dir
.join("doc");
39 return rm_rf(&target_dir
.into_path_unlocked(), config
);
42 let profiles
= Profiles
::new(ws
.profiles(), config
, opts
.requested_profile
, ws
.features())?
;
44 if opts
.profile_specified
{
45 // After parsing profiles we know the dir-name of the profile, if a profile
46 // was passed from the command line. If so, delete only the directory of
48 let dir_name
= profiles
.get_dir_name();
49 target_dir
= target_dir
.join(dir_name
);
52 // If we have a spec, then we need to delete some packages, otherwise, just
53 // remove the whole target directory and be done with it!
55 // Note that we don't bother grabbing a lock here as we're just going to
56 // blow it all away anyway.
57 if opts
.spec
.is_empty() {
58 return rm_rf(&target_dir
.into_path_unlocked(), config
);
60 let (packages
, resolve
) = ops
::resolve_ws(ws
)?
;
62 let interner
= UnitInterner
::new();
63 let mut build_config
= BuildConfig
::new(config
, Some(1), &opts
.target
, CompileMode
::Build
)?
;
64 build_config
.requested_profile
= opts
.requested_profile
;
65 let target_data
= RustcTargetData
::new(ws
, build_config
.requested_kind
)?
;
66 let bcx
= BuildContext
::new(
76 let requested_features
= RequestedFeatures
::new_all(true);
80 .map(|spec
| PackageIdSpec
::parse(spec
))
81 .collect
::<CargoResult
<Vec
<_
>>>()?
;
82 let features
= FeatureResolver
::resolve(
88 bcx
.build_config
.requested_kind
,
91 let mut units
= Vec
::new();
93 for spec
in opts
.spec
.iter() {
94 // Translate the spec to a Package
95 let pkgid
= resolve
.query(spec
)?
;
96 let pkg
= packages
.get_one(pkgid
)?
;
98 // Generate all relevant `Unit` targets for this package
99 for target
in pkg
.targets() {
100 for kind
in [CompileKind
::Host
, build_config
.requested_kind
].iter() {
101 for mode
in CompileMode
::all_modes() {
102 for unit_for
in UnitFor
::all_values() {
103 let profile
= if mode
.is_run_custom_build() {
105 .get_profile_run_custom_build(&bcx
.profiles
.get_profile(
112 bcx
.profiles
.get_profile(
119 let features
= features
120 .activated_features(pkg
.package_id(), unit_for
.is_for_build_dep());
121 units
.push(bcx
.units
.intern(
122 pkg
, target
, profile
, *kind
, *mode
, features
, /*is_std*/ false,
130 let unit_dependencies
=
131 unit_dependencies
::build_unit_dependencies(&bcx
, &resolve
, &features
, None
, &units
, &[])?
;
132 let mut cx
= Context
::new(config
, &bcx
, unit_dependencies
, build_config
.requested_kind
)?
;
133 cx
.prepare_units(None
, &units
)?
;
135 for unit
in units
.iter() {
136 if unit
.mode
.is_doc() || unit
.mode
.is_doc_test() {
137 // Cleaning individual rustdoc crates is currently not supported.
138 // For example, the search index would need to be rebuilt to fully
139 // remove it (otherwise you're left with lots of broken links).
140 // Doc tests produce no output.
143 rm_rf(&cx
.files().fingerprint_dir(unit
), config
)?
;
144 if unit
.target
.is_custom_build() {
145 if unit
.mode
.is_run_custom_build() {
146 rm_rf(&cx
.files().build_script_out_dir(unit
), config
)?
;
148 rm_rf(&cx
.files().build_script_dir(unit
), config
)?
;
153 for output
in cx
.outputs(unit
)?
.iter() {
154 rm_rf(&output
.path
, config
)?
;
155 if let Some(ref dst
) = output
.hardlink
{
164 fn rm_rf(path
: &Path
, config
: &Config
) -> CargoResult
<()> {
165 let m
= fs
::metadata(path
);
166 if m
.as_ref().map(|s
| s
.is_dir()).unwrap_or(false) {
169 .verbose(|shell
| shell
.status("Removing", path
.display()))?
;
170 paths
::remove_dir_all(path
)
171 .chain_err(|| anyhow
::format_err
!("could not remove build directory"))?
;
172 } else if m
.is_ok() {
175 .verbose(|shell
| shell
.status("Removing", path
.display()))?
;
176 paths
::remove_file(path
)
177 .chain_err(|| anyhow
::format_err
!("failed to remove build artifact"))?
;