1use std::path::PathBuf;
16
17use crate::error::CliError;
18
19pub fn execute_cache_clear(store: Option<&str>) -> Result<(), CliError> {
25 match store {
26 Some(store_name) => clear_store(store_name),
27 None => clear_all(),
28 }
29}
30
31fn clear_store(store: &str) -> Result<(), CliError> {
33 let cache_dir = get_cache_dir(store);
34
35 if !cache_dir.exists() {
36 println!(
37 "Cache store '{}' directory not found: {}",
38 store,
39 cache_dir.display()
40 );
41 return Ok(());
42 }
43
44 let count = remove_dir_contents(&cache_dir)?;
45 println!(
46 "Cache store '{}' cleared: {} file(s) removed from {}",
47 store,
48 count,
49 cache_dir.display()
50 );
51 Ok(())
52}
53
54fn clear_all() -> Result<(), CliError> {
56 let cache_root = get_cache_root();
57
58 if !cache_root.exists() {
59 println!("Cache root directory not found: {}", cache_root.display());
60 println!("Nothing to clear.");
61 return Ok(());
62 }
63
64 let count = remove_dir_contents(&cache_root)?;
65 println!(
66 "All caches cleared: {} file(s)/dir(s) removed from {}",
67 count,
68 cache_root.display()
69 );
70 Ok(())
71}
72
73fn get_cache_root() -> PathBuf {
77 PathBuf::from("runtime/cache")
78}
79
80fn get_cache_dir(store: &str) -> PathBuf {
82 get_cache_root().join(store)
83}
84
85fn remove_dir_contents(path: &PathBuf) -> Result<usize, CliError> {
91 let mut count = 0;
92 let entries = std::fs::read_dir(path)?;
93 for entry in entries {
94 let entry = entry?;
95 let entry_path = entry.path();
96 if entry_path.is_dir() {
97 std::fs::remove_dir_all(&entry_path)?;
98 } else {
99 std::fs::remove_file(&entry_path)?;
100 }
101 count += 1;
102 }
103 Ok(count)
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use std::fs;
110 use std::io::Write;
111
112 #[test]
113 fn test_get_cache_root_default() {
114 let root = get_cache_root();
115 assert_eq!(root, PathBuf::from("runtime/cache"));
116 }
117
118 #[test]
119 fn test_get_cache_dir_with_store() {
120 let dir = get_cache_dir("redis");
121 assert_eq!(dir, PathBuf::from("runtime/cache/redis"));
122 }
123
124 #[test]
125 fn test_clear_all_nonexistent_dir() {
126 let temp = tempfile::tempdir().unwrap();
128 let cache_root = temp.path().join("runtime/cache");
129 assert!(!cache_root.exists());
131 }
132
133 #[test]
134 fn test_clear_all_with_files_via_remove_dir_contents() {
135 let temp = tempfile::tempdir().unwrap();
137 let root = temp.path().to_path_buf();
138
139 let file1 = root.join("cache1.txt");
141 let file2 = root.join("cache2.txt");
142 let mut f1 = fs::File::create(&file1).unwrap();
143 writeln!(f1, "data1").unwrap();
144 let mut f2 = fs::File::create(&file2).unwrap();
145 writeln!(f2, "data2").unwrap();
146
147 let count = remove_dir_contents(&root).unwrap();
148 assert_eq!(count, 2);
149 assert!(!file1.exists());
150 assert!(!file2.exists());
151 }
152
153 #[test]
154 fn test_clear_store_nonexistent() {
155 let temp = tempfile::tempdir().unwrap();
157 let store_dir = temp.path().join("nonexistent_store");
158 assert!(!store_dir.exists());
159 }
160
161 #[test]
162 fn test_clear_store_with_files_via_remove_dir_contents() {
163 let temp = tempfile::tempdir().unwrap();
164 let store_dir = temp.path().join("redis");
165 fs::create_dir_all(&store_dir).unwrap();
166
167 let cache_file = store_dir.join("key1.txt");
168 let mut f = fs::File::create(&cache_file).unwrap();
169 writeln!(f, "redis_data").unwrap();
170
171 let count = remove_dir_contents(&store_dir).unwrap();
172 assert_eq!(count, 1);
173 assert!(!cache_file.exists());
174 }
175
176 #[test]
177 fn test_remove_dir_contents_with_subdirs() {
178 let temp = tempfile::tempdir().unwrap();
179 let root = temp.path().to_path_buf();
180
181 let sub_dir = root.join("subdir");
183 fs::create_dir_all(&sub_dir).unwrap();
184 fs::File::create(root.join("file1.txt")).unwrap();
185 fs::File::create(sub_dir.join("file2.txt")).unwrap();
186
187 let count = remove_dir_contents(&root).unwrap();
188 assert_eq!(count, 2); assert!(root.exists());
192 assert!(root.read_dir().unwrap().next().is_none());
193 }
194
195 #[test]
196 fn test_execute_cache_clear_no_store_nonexistent() {
197 let _lock = super::super::test_support::acquire_global_lock();
201 let temp = tempfile::tempdir().unwrap();
202 let original = std::env::current_dir().unwrap();
203 std::env::set_current_dir(temp.path()).unwrap();
204 let result = execute_cache_clear(None);
205 std::env::set_current_dir(&original).unwrap();
206 assert!(result.is_ok());
207 }
208
209 #[test]
210 fn test_execute_cache_clear_with_store_nonexistent() {
211 let result = execute_cache_clear(Some("nonexistent_store_xyz"));
213 assert!(result.is_ok());
214 }
215
216 #[test]
217 fn test_execute_cache_clear_all_with_existing_cache() {
218 let _lock = super::super::test_support::acquire_global_lock();
220 let temp = tempfile::tempdir().unwrap();
221 let original = std::env::current_dir().unwrap();
222 std::env::set_current_dir(temp.path()).unwrap();
223
224 let cache_root = temp.path().join("runtime/cache");
226 fs::create_dir_all(&cache_root).unwrap();
227 let cache_file = cache_root.join("data.txt");
228 fs::write(&cache_file, "cache data").unwrap();
229 assert!(cache_file.exists());
230
231 let result = execute_cache_clear(None);
232 std::env::set_current_dir(&original).unwrap();
233 assert!(result.is_ok());
234 assert!(!cache_file.exists());
236 }
237
238 #[test]
239 fn test_execute_cache_clear_store_with_existing_cache() {
240 let _lock = super::super::test_support::acquire_global_lock();
242 let temp = tempfile::tempdir().unwrap();
243 let original = std::env::current_dir().unwrap();
244 std::env::set_current_dir(temp.path()).unwrap();
245
246 let store_dir = temp.path().join("runtime/cache/redis");
248 fs::create_dir_all(&store_dir).unwrap();
249 let cache_file = store_dir.join("key1.txt");
250 fs::write(&cache_file, "redis data").unwrap();
251 assert!(cache_file.exists());
252
253 let result = execute_cache_clear(Some("redis"));
254 std::env::set_current_dir(&original).unwrap();
255 assert!(result.is_ok());
256 assert!(!cache_file.exists());
258 assert!(store_dir.exists());
260 }
261}