use std::collections::BTreeSet;
use std::path::Path;
use crate::cache;
use crate::error::Result;
use crate::manifest::Manifest;
pub fn prune(cwd: &Path) -> Result<String> {
let located = Manifest::locate(cwd)?;
let manifest = &located.manifest;
let cache_dir = located.root.join(&manifest.cache_dir);
let live: BTreeSet<String> = manifest
.commands
.iter()
.map(|rule| rule.name.clone())
.collect();
let pruned = cache::prune(&cache_dir, &live)?;
Ok(render(&pruned))
}
fn render(pruned: &[String]) -> String {
if pruned.is_empty() {
return "no orphan records to prune\n".to_owned();
}
let mut out = format!("pruned {} orphan record(s):\n", pruned.len());
for name in pruned {
out.push_str(&format!(" {name}\n"));
}
out
}
#[cfg(test)]
mod tests {
use super::prune;
use crate::cache;
fn manifest(root: &std::path::Path, body: &str) {
let dir = root.join(".mmz");
std::fs::create_dir_all(&dir).expect("mkdir .mmz");
std::fs::write(dir.join("config.yaml"), body).expect("write manifest");
}
#[test]
fn prunes_records_for_rules_not_in_the_manifest() {
let dir = tempfile::tempdir().expect("tempdir");
let base = dir.path();
manifest(base, "cache_dir: .cache\ncommands:\n - name: cargo test\n");
let cache_dir = base.join(".cache");
cache::write(&cache_dir, "cargo test", "d", true);
cache::write(&cache_dir, "cargo bench", "d", true);
let first = prune(base).expect("prune");
assert!(first.contains("cargo bench"), "orphan reported: {first}");
assert!(first.contains("pruned 1"), "count reported: {first}");
assert!(
cache::read(&cache_dir, "cargo test").is_some(),
"live record kept"
);
assert!(
cache::read(&cache_dir, "cargo bench").is_none(),
"orphan removed"
);
let again = prune(base).expect("prune");
assert!(
again.contains("no orphan"),
"nothing left to prune: {again}"
);
}
#[test]
fn missing_manifest_is_an_error() {
let dir = tempfile::tempdir().expect("tempdir");
assert!(prune(dir.path()).is_err(), "no manifest is fatal");
}
}