1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
use clap::Args;
use mozart_registry::cache::{Cache, build_cache_config};
#[derive(Args)]
pub struct ClearCacheArgs {
/// Only run garbage collection, not a full cache clear
#[arg(long)]
pub gc: bool,
}
pub async fn execute(
args: &ClearCacheArgs,
cli: &super::Cli,
console: &mozart_core::console::Console,
) -> anyhow::Result<()> {
let config = build_cache_config(cli.no_cache);
// Build the list of (key, path) pairs to process.
// cache-dir is only included in full clear mode, not GC mode.
let mut cache_paths = vec![
("cache-vcs-dir", &config.cache_vcs_dir),
("cache-repo-dir", &config.cache_repo_dir),
("cache-files-dir", &config.cache_files_dir),
];
if !args.gc {
cache_paths.push(("cache-dir", &config.cache_dir));
}
for (key, path) in &cache_paths {
// Non-existent directory: skip with informational message
if !path.exists() {
console.info(&format!(
"Cache directory does not exist ({key}): {}",
path.display()
));
continue;
}
// Read-only guard: skip with informational message
if config.read_only {
console.info(&format!("Cache is not enabled ({key}): {}", path.display()));
continue;
}
if args.gc {
console.info(&format!(
"Garbage-collecting cache ({key}): {}",
path.display()
));
let cache = Cache::new((*path).clone(), !config.no_cache);
let result = match *key {
"cache-files-dir" => cache.gc(config.cache_files_ttl, config.cache_files_maxsize),
"cache-vcs-dir" => cache.gc_vcs(config.cache_ttl),
// cache-repo-dir: 1 GB cap (matches Composer)
_ => cache.gc(config.cache_ttl, 1024 * 1024 * 1024),
};
if let Err(e) = result {
console.error(&format!("Error during GC of {key}: {e}"));
}
} else {
console.info(&format!("Clearing cache ({key}): {}", path.display()));
if *key == "cache-dir" {
// Clear anything at the root that isn't covered by sub-caches
let result = (|| -> anyhow::Result<()> {
for entry in std::fs::read_dir(path)? {
let entry = entry?;
let entry_path = entry.path();
// Skip repo/files/vcs subdirs (cleared by their own iterations)
if entry_path == config.cache_files_dir
|| entry_path == config.cache_repo_dir
|| entry_path == config.cache_vcs_dir
{
continue;
}
if entry_path.is_file() {
std::fs::remove_file(&entry_path)?;
} else if entry_path.is_dir() {
std::fs::remove_dir_all(&entry_path)?;
}
}
Ok(())
})();
if let Err(e) = result {
console.error(&format!("Error clearing {key}: {e}"));
}
} else {
let cache = Cache::new((*path).clone(), !config.no_cache);
if let Err(e) = cache.clear() {
console.error(&format!("Error clearing {key}: {e}"));
}
}
}
}
if args.gc {
console.info("All caches garbage-collected.");
} else {
console.info("All caches cleared.");
}
Ok(())
}
|