diff options
| author | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2024-08-22 15:54:52 +0000 |
|---|---|---|
| committer | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2024-08-22 15:54:52 +0000 |
| commit | e0900a1bb79a6c844fadb4b27fe8e0793d952476 (patch) | |
| tree | 3d59b6e7234f6ac96476a5b3b908b3bd803fd3a9 /src | |
| parent | 0f6e1ae67854c3c44726e8376144c16b465fe7c6 (diff) | |
| download | rust-e0900a1bb79a6c844fadb4b27fe8e0793d952476.tar.gz rust-e0900a1bb79a6c844fadb4b27fe8e0793d952476.zip | |
Revert "bootstrap: fix clean's `remove_dir_all` implementation"
This reverts commit 1687c55168f3837506afcd2240a8a0b6eadcc1eb.
Diffstat (limited to 'src')
| -rw-r--r-- | src/bootstrap/src/core/build_steps/clean.rs | 93 |
1 files changed, 78 insertions, 15 deletions
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index bcbe490c36a..f608e5d715e 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -6,6 +6,7 @@ //! directory unless the `--all` flag is present. use std::fs; +use std::io::{self, ErrorKind}; use std::path::Path; use crate::core::builder::{crate_description, Builder, RunConfig, ShouldRun, Step}; @@ -100,11 +101,11 @@ fn clean(build: &Build, all: bool, stage: Option<u32>) { return; } - remove_dir_recursive("tmp"); + rm_rf("tmp".as_ref()); // Clean the entire build directory if all { - remove_dir_recursive(&build.out); + rm_rf(&build.out); return; } @@ -135,17 +136,17 @@ fn clean_specific_stage(build: &Build, stage: u32) { } let path = t!(entry.path().canonicalize()); - remove_dir_recursive(&path); + rm_rf(&path); } } } fn clean_default(build: &Build) { - remove_dir_recursive(build.out.join("tmp")); - remove_dir_recursive(build.out.join("dist")); - remove_dir_recursive(build.out.join("bootstrap").join(".last-warned-change-id")); - remove_dir_recursive(build.out.join("bootstrap-shims-dump")); - remove_dir_recursive(build.out.join("rustfmt.stamp")); + rm_rf(&build.out.join("tmp")); + rm_rf(&build.out.join("dist")); + rm_rf(&build.out.join("bootstrap").join(".last-warned-change-id")); + rm_rf(&build.out.join("bootstrap-shims-dump")); + rm_rf(&build.out.join("rustfmt.stamp")); let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t)).collect(); // After cross-compilation, artifacts of the host architecture (which may differ from build.host) @@ -165,16 +166,78 @@ fn clean_default(build: &Build) { continue; } let path = t!(entry.path().canonicalize()); - remove_dir_recursive(&path); + rm_rf(&path); } } } -/// Wrapper for [`std::fs::remove_dir_all`] that panics on failure and prints the `path` we failed -/// on. -fn remove_dir_recursive<P: AsRef<Path>>(path: P) { - let path = path.as_ref(); - if let Err(e) = fs::remove_dir_all(path) { - panic!("failed to `remove_dir_all` at `{}`: {e}", path.display()); +fn rm_rf(path: &Path) { + match path.symlink_metadata() { + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return; + } + panic!("failed to get metadata for file {}: {}", path.display(), e); + } + Ok(metadata) => { + if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + do_op(path, "remove file", |p| match fs::remove_file(p) { + #[cfg(windows)] + Err(e) + if e.kind() == std::io::ErrorKind::PermissionDenied + && p.file_name().and_then(std::ffi::OsStr::to_str) + == Some("bootstrap.exe") => + { + eprintln!("WARNING: failed to delete '{}'.", p.display()); + Ok(()) + } + r => r, + }); + + return; + } + + for file in t!(fs::read_dir(path)) { + rm_rf(&t!(file).path()); + } + + do_op(path, "remove dir", |p| match fs::remove_dir(p) { + // Check for dir not empty on Windows + // FIXME: Once `ErrorKind::DirectoryNotEmpty` is stabilized, + // match on `e.kind()` instead. + #[cfg(windows)] + Err(e) if e.raw_os_error() == Some(145) => Ok(()), + r => r, + }); + } + }; +} + +fn do_op<F>(path: &Path, desc: &str, mut f: F) +where + F: FnMut(&Path) -> io::Result<()>, +{ + match f(path) { + Ok(()) => {} + // On windows we can't remove a readonly file, and git will often clone files as readonly. + // As a result, we have some special logic to remove readonly files on windows. + // This is also the reason that we can't use things like fs::remove_dir_all(). + #[cfg(windows)] + Err(ref e) if e.kind() == ErrorKind::PermissionDenied => { + let m = t!(path.symlink_metadata()); + let mut p = m.permissions(); + p.set_readonly(false); + t!(fs::set_permissions(path, p)); + f(path).unwrap_or_else(|e| { + // Delete symlinked directories on Windows + if m.file_type().is_symlink() && path.is_dir() && fs::remove_dir(path).is_ok() { + return; + } + panic!("failed to {} {}: {}", desc, path.display(), e); + }); + } + Err(e) => { + panic!("failed to {} {}: {}", desc, path.display(), e); + } } } |
