arm_toolchain/toolchain/
remove.rs

1use std::path::PathBuf;
2
3use tokio_util::sync::CancellationToken;
4
5use crate::toolchain::ToolchainError;
6use crate::{CheckCancellation, fs};
7
8pub enum RemoveProgress {
9    Start { total_bytes: u64 },
10    Progress { bytes_removed: u64 },
11    End,
12}
13
14pub async fn remove_dir_progress(
15    dir: PathBuf,
16    mut progress: impl FnMut(RemoveProgress),
17    cancel_token: &CancellationToken,
18) -> Result<(), ToolchainError> {
19    let mut items = vec![];
20    let total_bytes = enumerate_dir(dir, &mut items, cancel_token).await?;
21    let mut bytes_removed = 0;
22
23    progress(RemoveProgress::Start { total_bytes });
24
25    for item in items {
26        if item.sym {
27            if cfg!(windows) && item.dir {
28                fs::remove_dir(&item.path).await?;
29            } else {
30                fs::remove_file(&item.path).await?;
31            }
32        } else if item.dir {
33            fs::remove_dir(&item.path).await?;
34        } else {
35            fs::remove_file(&item.path).await?;
36            bytes_removed += item.size;
37        }
38
39        progress(RemoveProgress::Progress { bytes_removed });
40    }
41
42    progress(RemoveProgress::End);
43
44    Ok(())
45}
46
47async fn enumerate_dir(
48    path: PathBuf,
49    contents_vec: &mut Vec<Item>,
50    cancel_token: &CancellationToken,
51) -> Result<u64, ToolchainError> {
52    let mut bytes = 0;
53
54    let meta = fs::symlink_metadata(&path).await?;
55
56    if meta.is_symlink() {
57        contents_vec.push(Item {
58            path,
59            dir: meta.is_dir(),
60            sym: true,
61            size: meta.len(),
62        });
63        return Ok(meta.len());
64    }
65
66    if meta.is_file() {
67        contents_vec.push(Item {
68            path,
69            dir: false,
70            sym: false,
71            size: meta.len(),
72        });
73        return Ok(meta.len());
74    }
75
76    let mut read_dir = fs::read_dir(&path).await?;
77    while let Some(entry) = read_dir.next_entry().await? {
78        cancel_token.check_cancellation(ToolchainError::Cancelled)?;
79
80        let path = entry.path();
81        bytes += Box::pin(enumerate_dir(path, contents_vec, cancel_token)).await?;
82    }
83
84    contents_vec.push(Item {
85        path,
86        dir: true,
87        sym: false,
88        size: meta.len(),
89    });
90
91    Ok(bytes + meta.len())
92}
93
94struct Item {
95    path: PathBuf,
96    sym: bool,
97    dir: bool,
98    size: u64,
99}