summaryrefslogtreecommitdiffstats
path: root/vendor/gix-tempfile/src/fs/remove_dir.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-tempfile/src/fs/remove_dir.rs')
-rw-r--r--vendor/gix-tempfile/src/fs/remove_dir.rs108
1 files changed, 0 insertions, 108 deletions
diff --git a/vendor/gix-tempfile/src/fs/remove_dir.rs b/vendor/gix-tempfile/src/fs/remove_dir.rs
deleted file mode 100644
index ac7b212fa..000000000
--- a/vendor/gix-tempfile/src/fs/remove_dir.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//!
-use std::path::{Path, PathBuf};
-
-/// A special iterator which communicates its operation through results where…
-///
-/// * `Some(Ok(removed_directory))` is yielded once or more success, followed by `None`
-/// * `Some(Err(std::io::Error))` is yielded exactly once on failure.
-pub struct Iter<'a> {
- cursor: Option<&'a Path>,
- boundary: &'a Path,
-}
-
-/// Construction
-impl<'a> Iter<'a> {
- /// Create a new instance that deletes `target` but will stop at `boundary`, without deleting the latter.
- /// Returns an error if `boundary` doesn't contain `target`
- ///
- /// **Note** that we don't canonicalize the path for performance reasons.
- pub fn new(target: &'a Path, boundary: &'a Path) -> std::io::Result<Self> {
- if !target.starts_with(boundary) {
- return Err(std::io::Error::new(
- std::io::ErrorKind::InvalidInput,
- format!("Removal target {target:?} must be contained in boundary {boundary:?}"),
- ));
- }
- let cursor = if target == boundary {
- None
- } else if target.exists() {
- Some(target)
- } else {
- None
- };
- Ok(Iter { cursor, boundary })
- }
-}
-
-impl<'a> Iterator for Iter<'a> {
- type Item = std::io::Result<&'a Path>;
-
- fn next(&mut self) -> Option<Self::Item> {
- match self.cursor.take() {
- Some(dir) => {
- let next = match std::fs::remove_dir(dir) {
- Ok(()) => Some(Ok(dir)),
- Err(err) => match err.kind() {
- std::io::ErrorKind::NotFound => Some(Ok(dir)),
- _other_error_kind => return Some(Err(err)),
- },
- };
- self.cursor = match dir.parent() {
- Some(parent) => (parent != self.boundary).then_some(parent),
- None => {
- unreachable!("directory {:?} ran out of parents, this really shouldn't happen before hitting the boundary {:?}", dir, self.boundary)
- }
- };
- next
- }
- None => None,
- }
- }
-}
-
-/// Delete all empty directories from `delete_dir` upward and until (not including) the `boundary_dir`.
-///
-/// Note that `boundary_dir` must contain `delete_dir` or an error is returned, otherwise `delete_dir` is returned on success.
-pub fn empty_upward_until_boundary<'a>(delete_dir: &'a Path, boundary_dir: &'a Path) -> std::io::Result<&'a Path> {
- for item in Iter::new(delete_dir, boundary_dir)? {
- match item {
- Ok(_dir) => continue,
- Err(err) => return Err(err),
- }
- }
- Ok(delete_dir)
-}
-
-/// Delete all empty directories reachable from `delete_dir` from empty leaves moving upward to and including `delete_dir`.
-///
-/// If any encountered directory contains a file the entire operation is aborted.
-/// Please note that this is inherently racy and no attempts are made to counter that, which will allow creators to win
-/// as long as they retry.
-pub fn empty_depth_first(delete_dir: impl Into<PathBuf>) -> std::io::Result<()> {
- let delete_dir = delete_dir.into();
- if let Ok(()) = std::fs::remove_dir(&delete_dir) {
- return Ok(());
- }
-
- let mut stack = vec![delete_dir];
- let mut next_to_push = Vec::new();
- while let Some(dir_to_delete) = stack.pop() {
- let mut num_entries = 0;
- for entry in std::fs::read_dir(&dir_to_delete)? {
- num_entries += 1;
- let entry = entry?;
- if entry.file_type()?.is_dir() {
- next_to_push.push(entry.path());
- } else {
- return Err(std::io::Error::new(std::io::ErrorKind::Other, "Directory not empty"));
- }
- }
- if num_entries == 0 {
- std::fs::remove_dir(&dir_to_delete)?;
- } else {
- stack.push(dir_to_delete);
- stack.append(&mut next_to_push);
- }
- }
- Ok(())
-}