6
6
//! directory unless the `--all` flag is present.
7
7
8
8
use std:: fs;
9
- use std:: io:: { self , ErrorKind } ;
10
9
use std:: path:: Path ;
11
10
12
11
use crate :: core:: builder:: { crate_description, Builder , RunConfig , ShouldRun , Step } ;
13
12
use crate :: utils:: helpers:: t;
14
13
use crate :: { Build , Compiler , Kind , Mode , Subcommand } ;
15
14
15
+ #[ cfg( test) ]
16
+ mod tests;
17
+
16
18
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
17
19
pub struct CleanAll { }
18
20
@@ -101,11 +103,11 @@ fn clean(build: &Build, all: bool, stage: Option<u32>) {
101
103
return ;
102
104
}
103
105
104
- rm_rf ( "tmp" . as_ref ( ) ) ;
106
+ remove_dir_all_wrapper ( "tmp" ) ;
105
107
106
108
// Clean the entire build directory
107
109
if all {
108
- rm_rf ( & build. out ) ;
110
+ remove_dir_all_wrapper ( & build. out ) ;
109
111
return ;
110
112
}
111
113
@@ -136,17 +138,17 @@ fn clean_specific_stage(build: &Build, stage: u32) {
136
138
}
137
139
138
140
let path = t ! ( entry. path( ) . canonicalize( ) ) ;
139
- rm_rf ( & path) ;
141
+ remove_dir_all_wrapper ( & path) ;
140
142
}
141
143
}
142
144
}
143
145
144
146
fn clean_default ( build : & Build ) {
145
- rm_rf ( & build. out . join ( "tmp" ) ) ;
146
- rm_rf ( & build. out . join ( "dist" ) ) ;
147
- rm_rf ( & build. out . join ( "bootstrap" ) . join ( ".last-warned-change-id" ) ) ;
148
- rm_rf ( & build. out . join ( "bootstrap-shims-dump" ) ) ;
149
- rm_rf ( & build. out . join ( "rustfmt.stamp" ) ) ;
147
+ remove_dir_all_wrapper ( & build. out . join ( "tmp" ) ) ;
148
+ remove_dir_all_wrapper ( & build. out . join ( "dist" ) ) ;
149
+ remove_dir_all_wrapper ( & build. out . join ( "bootstrap" ) . join ( ".last-warned-change-id" ) ) ;
150
+ remove_dir_all_wrapper ( & build. out . join ( "bootstrap-shims-dump" ) ) ;
151
+ remove_dir_all_wrapper ( & build. out . join ( "rustfmt.stamp" ) ) ;
150
152
151
153
let mut hosts: Vec < _ > = build. hosts . iter ( ) . map ( |t| build. out . join ( t) ) . collect ( ) ;
152
154
// After cross-compilation, artifacts of the host architecture (which may differ from build.host)
@@ -166,78 +168,16 @@ fn clean_default(build: &Build) {
166
168
continue ;
167
169
}
168
170
let path = t ! ( entry. path( ) . canonicalize( ) ) ;
169
- rm_rf ( & path) ;
171
+ remove_dir_all_wrapper ( & path) ;
170
172
}
171
173
}
172
174
}
173
175
174
- fn rm_rf ( path : & Path ) {
175
- match path. symlink_metadata ( ) {
176
- Err ( e) => {
177
- if e. kind ( ) == ErrorKind :: NotFound {
178
- return ;
179
- }
180
- panic ! ( "failed to get metadata for file {}: {}" , path. display( ) , e) ;
181
- }
182
- Ok ( metadata) => {
183
- if metadata. file_type ( ) . is_file ( ) || metadata. file_type ( ) . is_symlink ( ) {
184
- do_op ( path, "remove file" , |p| match fs:: remove_file ( p) {
185
- #[ cfg( windows) ]
186
- Err ( e)
187
- if e. kind ( ) == std:: io:: ErrorKind :: PermissionDenied
188
- && p. file_name ( ) . and_then ( std:: ffi:: OsStr :: to_str)
189
- == Some ( "bootstrap.exe" ) =>
190
- {
191
- eprintln ! ( "WARNING: failed to delete '{}'." , p. display( ) ) ;
192
- Ok ( ( ) )
193
- }
194
- r => r,
195
- } ) ;
196
-
197
- return ;
198
- }
199
-
200
- for file in t ! ( fs:: read_dir( path) ) {
201
- rm_rf ( & t ! ( file) . path ( ) ) ;
202
- }
203
-
204
- do_op ( path, "remove dir" , |p| match fs:: remove_dir ( p) {
205
- // Check for dir not empty on Windows
206
- // FIXME: Once `ErrorKind::DirectoryNotEmpty` is stabilized,
207
- // match on `e.kind()` instead.
208
- #[ cfg( windows) ]
209
- Err ( e) if e. raw_os_error ( ) == Some ( 145 ) => Ok ( ( ) ) ,
210
- r => r,
211
- } ) ;
212
- }
213
- } ;
214
- }
215
-
216
- fn do_op < F > ( path : & Path , desc : & str , mut f : F )
217
- where
218
- F : FnMut ( & Path ) -> io:: Result < ( ) > ,
219
- {
220
- match f ( path) {
221
- Ok ( ( ) ) => { }
222
- // On windows we can't remove a readonly file, and git will often clone files as readonly.
223
- // As a result, we have some special logic to remove readonly files on windows.
224
- // This is also the reason that we can't use things like fs::remove_dir_all().
225
- #[ cfg( windows) ]
226
- Err ( ref e) if e. kind ( ) == ErrorKind :: PermissionDenied => {
227
- let m = t ! ( path. symlink_metadata( ) ) ;
228
- let mut p = m. permissions ( ) ;
229
- p. set_readonly ( false ) ;
230
- t ! ( fs:: set_permissions( path, p) ) ;
231
- f ( path) . unwrap_or_else ( |e| {
232
- // Delete symlinked directories on Windows
233
- if m. file_type ( ) . is_symlink ( ) && path. is_dir ( ) && fs:: remove_dir ( path) . is_ok ( ) {
234
- return ;
235
- }
236
- panic ! ( "failed to {} {}: {}" , desc, path. display( ) , e) ;
237
- } ) ;
238
- }
239
- Err ( e) => {
240
- panic ! ( "failed to {} {}: {}" , desc, path. display( ) , e) ;
241
- }
176
+ /// Wrapper for [`std::fs::remove_dir_all`] that panics on failure and prints the `path` we failed
177
+ /// on.
178
+ fn remove_dir_all_wrapper < P : AsRef < Path > > ( path : P ) {
179
+ let path = path. as_ref ( ) ;
180
+ if let Err ( e) = fs:: remove_dir_all ( & path) {
181
+ panic ! ( "failed to `remove_dir_all` at `{}`: {e}" , path. display( ) ) ;
242
182
}
243
183
}
0 commit comments