Skip to content

Commit e0900a1

Browse files
committed
Revert "bootstrap: fix clean's remove_dir_all implementation"
This reverts commit 1687c55.
1 parent 0f6e1ae commit e0900a1

File tree

1 file changed

+78
-15
lines changed
  • src/bootstrap/src/core/build_steps

1 file changed

+78
-15
lines changed

src/bootstrap/src/core/build_steps/clean.rs

+78-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! directory unless the `--all` flag is present.
77
88
use std::fs;
9+
use std::io::{self, ErrorKind};
910
use std::path::Path;
1011

1112
use crate::core::builder::{crate_description, Builder, RunConfig, ShouldRun, Step};
@@ -100,11 +101,11 @@ fn clean(build: &Build, all: bool, stage: Option<u32>) {
100101
return;
101102
}
102103

103-
remove_dir_recursive("tmp");
104+
rm_rf("tmp".as_ref());
104105

105106
// Clean the entire build directory
106107
if all {
107-
remove_dir_recursive(&build.out);
108+
rm_rf(&build.out);
108109
return;
109110
}
110111

@@ -135,17 +136,17 @@ fn clean_specific_stage(build: &Build, stage: u32) {
135136
}
136137

137138
let path = t!(entry.path().canonicalize());
138-
remove_dir_recursive(&path);
139+
rm_rf(&path);
139140
}
140141
}
141142
}
142143

143144
fn clean_default(build: &Build) {
144-
remove_dir_recursive(build.out.join("tmp"));
145-
remove_dir_recursive(build.out.join("dist"));
146-
remove_dir_recursive(build.out.join("bootstrap").join(".last-warned-change-id"));
147-
remove_dir_recursive(build.out.join("bootstrap-shims-dump"));
148-
remove_dir_recursive(build.out.join("rustfmt.stamp"));
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"));
149150

150151
let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t)).collect();
151152
// After cross-compilation, artifacts of the host architecture (which may differ from build.host)
@@ -165,16 +166,78 @@ fn clean_default(build: &Build) {
165166
continue;
166167
}
167168
let path = t!(entry.path().canonicalize());
168-
remove_dir_recursive(&path);
169+
rm_rf(&path);
169170
}
170171
}
171172
}
172173

173-
/// Wrapper for [`std::fs::remove_dir_all`] that panics on failure and prints the `path` we failed
174-
/// on.
175-
fn remove_dir_recursive<P: AsRef<Path>>(path: P) {
176-
let path = path.as_ref();
177-
if let Err(e) = fs::remove_dir_all(path) {
178-
panic!("failed to `remove_dir_all` at `{}`: {e}", path.display());
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+
}
179242
}
180243
}

0 commit comments

Comments
 (0)