delete/lib.rs
1//! Fast, easy deletion of files and folders with async and cross-platform support.
2//! ## Overview
3//!
4//! This crate allows for fast and easy deletion of files and folders. It has `async` and cross-platform support.
5//!
6//! Many of the functions in this crate directly call `std::fs` and `tokio::fs`.
7//!
8//! This crate aims to be:
9//!
10//! - Fast
11//! - Easy To Use
12//! - Powerful
13//!
14//! ## Examples
15//!
16//! ### Non-Async Implementation
17//!
18//! ```rust
19//! use delete::{delete_file};
20//!
21//! fn main() {
22//! // Delete file.txt
23//! delete_file("file.txt").unwrap();
24//! }
25//! ```
26//!
27//! ```rust
28//! use delete::{delete_folder};
29//!
30//! fn main() {
31//! // Delete tests folder
32//! delete_folder("tests").unwrap();
33//! }
34//! ```
35//!
36//! ### Async Implementation
37//!
38//! ```rust
39//! use delete::{delete_file_async};
40//!
41//! #[tokio::main]
42//! async fn main() {
43//! // Delete file.txt asynchronously
44//! delete_file_async("file.txt").await.unwrap();
45//! }
46//! ```
47//!
48//! ```rust
49//! use delete::{delete_folder_async};
50//!
51//! #[tokio::main]
52//! async fn main() {
53//! // Delete tests folder asynchronously
54//! delete_folder_async("tests").await.unwrap();
55//! }
56//! ```
57//!
58//! ## Rapid Implementations
59//!
60//! ```rust
61//! use delete::{rapid_delete_dir_all};
62//!
63//! #[tokio::main]
64//! async fn main() {
65//! // 2-3x faster than std::fs::remove_dir_all
66//! // removes all files and folders in subfolders parallely using tokio workers
67//! rapid_delete_dir_all("node_modules", None, None).await;
68//! }
69//! ```
70//!
71//! ### Credits
72//!
73//! [tokio](https://crates.io/crates/tokio)
74
75use futures::stream::{FuturesUnordered, StreamExt};
76
77fn walkdir(path: &str) -> (Vec<String>, Vec<String>) {
78 let mut files_vec: Vec<String> = vec![];
79 let mut folders_vec: Vec<String> = vec![];
80 for entry in jwalk::WalkDir::new(path) {
81 let entry = entry.unwrap();
82 if entry.path().is_file() {
83 files_vec.push(entry.path().to_str().unwrap().to_string());
84 } else {
85 folders_vec.push(entry.path().to_str().unwrap().to_string());
86 }
87 }
88 (files_vec, folders_vec)
89}
90
91async fn priv_delete_files(files: &[String]) {
92 for f in files {
93 tokio::fs::remove_file(f).await.unwrap();
94 }
95}
96
97async fn priv_delete_folder(folders: &[String]) {
98 for f in folders {
99 let _ = tokio::fs::remove_dir_all(f).await;
100 }
101}
102
103/// Delete a file from the filesystem.
104///
105/// Uses `std::fs` internally.
106/// ## Examples
107/// ```
108/// use delete::{delete_file};
109///
110/// fn main() {
111/// // Delete file.txt
112/// delete_file("file.txt").unwrap();
113/// }
114/// ```
115///
116pub fn delete_file(path: &str) -> std::io::Result<()> {
117 std::fs::remove_file(path)?;
118 Ok(())
119}
120
121/// Delete a file from the filesystem using `async` and `tokio`.
122///
123/// Uses `tokio::fs` internally.
124/// ## Examples
125/// ```
126/// use delete::{delete_file_async};
127///
128/// #[tokio::main]
129/// async fn main() {
130/// // Delete file.txt
131/// delete_file_async("file.txt").await.unwrap();
132/// }
133/// ```
134///
135pub async fn delete_file_async(path: &str) -> std::io::Result<()> {
136 tokio::fs::remove_file(path).await?;
137 Ok(())
138}
139
140/// Delete an empty folder from the filesystem.
141///
142/// Uses `std::fs` internally.
143/// ## Examples
144/// ```
145/// use delete::{delete_folder};
146///
147/// fn main() {
148/// // Delete tests folder
149/// delete_folder("tests").unwrap();
150/// }
151/// ```
152///
153pub fn delete_folder(path: &str) -> std::io::Result<()> {
154 std::fs::remove_dir(path)?;
155 Ok(())
156}
157
158/// Delete an empty folder from the filesystem using `async` and `tokio`.
159///
160/// Uses `tokio::fs` internally.
161/// ## Examples
162/// ```
163/// use delete::{delete_folder_async};
164///
165/// #[tokio::main]
166/// async fn main() {
167/// // Delete tests folder
168/// delete_folder_async("tests").await.unwrap();
169/// }
170/// ```
171///
172pub async fn delete_folder_async(path: &str) -> std::io::Result<()> {
173 tokio::fs::remove_dir(path).await?;
174 Ok(())
175}
176
177/// Delete a folder from the filesystem after recursively deleting all its contents.
178///
179/// Uses `std::fs` internally.
180/// ## Examples
181/// ```
182/// use delete::{delete_folder_all};
183///
184/// fn main() {
185/// // Delete node_modules folder and all its contents.
186/// delete_folder_all("node_modules").unwrap();
187/// }
188/// ```
189///
190pub fn delete_folder_all(path: &str) -> std::io::Result<()> {
191 std::fs::remove_dir_all(path)?;
192 Ok(())
193}
194
195/// Delete a folder from the filesystem after recursively deleting all its contents using `async` and `tokio`.
196///
197/// Uses `tokio::fs` internally.
198/// ## Examples
199/// ```
200/// use delete::{delete_folder_all_async};
201///
202/// #[tokio::main]
203/// async fn main() {
204/// // Delete node_modules folder and all its contents.
205/// delete_folder_all_async("node_modules").await.unwrap();
206/// }
207/// ```
208///
209pub async fn delete_folder_all_async(path: &str) -> std::io::Result<()> {
210 tokio::fs::remove_dir_all(path).await?;
211 Ok(())
212}
213
214/// Rapidly delete a folder from the filesystem after recursively deleting all its contents using `async` and `tokio`.
215///
216/// Benchmarked to be 2-3x faster than `std::fs::remove_dir_all()`
217///
218/// Uses tokio workers to delete files and folders parallely.
219///
220/// ## Parameters
221/// path: `&str` - path to the folder to delete
222///
223/// (Optional) folders_chunk_size: `Option<u64>` - number of folders to be deleted per worker.
224///
225/// if this value is lower, more workers are spawned.
226/// (Optional) files_chunk_size: `Option<u64>` - number of files to be deleted per worker.
227///
228/// if this value is lower, more workers are spawned.
229///
230/// Uses `tokio::fs` internally.
231/// ## Examples
232/// ```
233/// use delete::{rapid_delete_dir_all};
234///
235/// #[tokio::main]
236/// async fn main() {
237/// // Delete node_modules folder and all its contents 2x faster.
238/// rapid_delete_dir_all("node_modules", None, None).await.unwrap();
239/// }
240/// ```
241///
242pub async fn rapid_delete_dir_all(
243 path: &str,
244 folders_chunk_size: Option<u64>,
245 files_chunk_size: Option<u64>,
246) -> std::io::Result<()> {
247 let (files, directories) = walkdir(path);
248
249 let mut workers = FuturesUnordered::new();
250
251 let file_chunk_size;
252
253 if files_chunk_size.is_some() {
254 file_chunk_size = files_chunk_size.unwrap();
255 } else {
256 file_chunk_size = 350;
257 }
258
259 let chunks = files.chunks(file_chunk_size as usize);
260
261 for chunk in chunks {
262 workers.push(async move {
263 priv_delete_files(chunk).await;
264 });
265 }
266
267 while workers.next().await.is_some() {}
268
269 let folder_chunk_size;
270
271 if folders_chunk_size.is_some() {
272 folder_chunk_size = folders_chunk_size.unwrap();
273 } else {
274 folder_chunk_size = 25;
275 }
276
277 let folders = directories.chunks(folder_chunk_size as usize);
278
279 let mut workers = FuturesUnordered::new();
280
281 for folder in folders {
282 workers.push(async move {
283 priv_delete_folder(folder).await;
284 })
285 }
286
287 while workers.next().await.is_some() {}
288
289 let _ = std::fs::remove_dir_all(path);
290
291 Ok(())
292}