folder_declutter/
process_dir.rs1use std::fs;
2use std::path::Path;
3use std::time::SystemTime;
4
5pub fn process_dir(dir: &Path, cutoff: SystemTime) {
7 let mut removed_files = 0;
8 if let Ok(entries) = fs::read_dir(dir) {
9 for entry in entries.flatten() {
10 let path = entry.path();
11 if path.is_dir() {
12 process_dir(&path, cutoff);
13 if let Ok(mut entries) = fs::read_dir(&path) {
15 if entries.next().is_none() {
16 match fs::remove_dir(&path) {
17 Ok(_) => println!("\nđď¸ Empty folder deleted: {:?}", path),
18 Err(e) => eprintln!("Error deleting folder {:?}: {}", path, e),
19 }
20 }
21 }
22 } else if let Ok(metadata) = fs::metadata(&path) {
23 if let Ok(modified) = metadata.modified() {
24 if modified < cutoff {
25 match fs::remove_file(&path) {
26 Ok(_) => {
27 removed_files += 1;
28 println!("\nđď¸ File deleted: {:?}", path)
29 }
30 Err(e) => eprintln!("Error deleting {:?}: {}", path, e),
31 }
32 }
33 }
34 }
35 }
36 }
37 if removed_files == 0 {
38 println!("\nâ
Done! No files to delete.");
39 return;
40 }
41 println!("\nâ
Done! {} files removed.", removed_files);
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use std::fs::{self, File};
48 use std::io::Write;
49 use std::path::PathBuf;
50 use std::time::{Duration, SystemTime};
51 use tempfile::tempdir;
52
53 #[test]
54 fn test_removes_old_files() {
55 let temp_dir = tempdir().unwrap();
57 let file_path: PathBuf = temp_dir.path().join("old_file.txt");
58 let mut file = File::create(&file_path).unwrap();
59 writeln!(file, "Some test content").unwrap();
60
61 let cutoff = SystemTime::now() + Duration::from_secs(3600);
63
64 process_dir(temp_dir.path(), cutoff);
66
67 assert!(!file_path.exists(), "File should have been deleted");
69 }
70
71 #[test]
72 fn test_preserves_new_files() {
73 let temp_dir = tempdir().unwrap();
75 let file_path: PathBuf = temp_dir.path().join("new_file.txt");
76 let mut file = File::create(&file_path).unwrap();
77 writeln!(file, "Fresh content").unwrap();
78
79 let cutoff = SystemTime::now() - Duration::from_secs(3600);
81
82 process_dir(temp_dir.path(), cutoff);
84
85 assert!(file_path.exists(), "File should not have been deleted");
87 }
88
89 #[test]
90 fn test_recursive_processing() {
91 let temp_dir = tempdir().unwrap();
93 let sub_dir = temp_dir.path().join("subdir");
94 fs::create_dir(&sub_dir).unwrap();
95
96 let old_file: PathBuf = sub_dir.join("old_file.txt");
98 let new_file: PathBuf = sub_dir.join("new_file.txt");
99 {
100 let mut file = File::create(&old_file).unwrap();
101 writeln!(file, "Old content").unwrap();
102 }
103 {
104 let mut file = File::create(&new_file).unwrap();
105 writeln!(file, "New content").unwrap();
106 }
107
108 let cutoff = SystemTime::now() + Duration::from_secs(3600);
110 process_dir(temp_dir.path(), cutoff);
111
112 assert!(!old_file.exists(), "old_file should have been deleted recursively");
114 assert!(!new_file.exists(), "new_file should have been deleted recursively");
115
116 let sub_dir2 = temp_dir.path().join("subdir2");
119 fs::create_dir(&sub_dir2).unwrap();
120 let preserved_file: PathBuf = sub_dir2.join("preserved.txt");
121 {
122 let mut file = File::create(&preserved_file).unwrap();
123 writeln!(file, "I am still new").unwrap();
124 }
125
126 let cutoff_old = SystemTime::now() - Duration::from_secs(3600);
128 process_dir(temp_dir.path(), cutoff_old);
129
130 assert!(preserved_file.exists(), "File should not have been deleted recursively");
132 }
133
134 #[test]
135 fn test_empty_folder_deletion() {
136 let temp_dir = tempdir().unwrap();
138 let empty_subdir = temp_dir.path().join("empty_folder");
139 fs::create_dir(&empty_subdir).unwrap();
140
141 let cutoff = SystemTime::now() + Duration::from_secs(3600);
143 process_dir(temp_dir.path(), cutoff);
144
145 assert!(!empty_subdir.exists(), "Empty folder should have been deleted");
147 }
148}