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}