Expand description
§cache-manager
Directory-based cache and artifact path management with crate-root discovery, grouped cache paths, and optional eviction on directory initialization.
This crate is intentionally tool-agnostic — it only manages cache/artifact directory layout and paths and does not assume or depend on any specific consumer tooling. Any tool or library that reads or writes files can use cache-manager to compute/manage project-scoped cache paths and apply eviction rules.
It has zero runtime dependencies (standard library only for library consumers).
It is suitable for:
- Artifact storage (build outputs, generated files, intermediate data, etc.).
- Monorepos or multi-crate workspaces that need centralized cache/artifact management via a shared root (for example with
CacheRoot::from_root(...)).
Tested on macOS, Linux, and Windows.
§Usage
Basic terminology and examples showing common operations:
§CacheRoot
The primary root type is CacheRoot, which represents a filesystem root
under which cache groups (CacheGroup) live.
§CacheGroup
A CacheGroup represents a subdirectory under a CacheRoot and manages
cache entries stored in that directory.
§Discovering cache paths
Discover a cache path for the current crate/workspace and resolve an entry path.
Note:
discover_cache_pathonly computes a filesystem path — it does not create directories or files.
Behavior:
- Searches upward from the current working directory for a
Cargo.tomland uses that crate root when found; otherwise it falls back to the current working directory. - The discovered root is canonicalized when possible to avoid surprising differences between logically-equal paths.
- If the
relative_pathargument is absolute, it is returned unchanged.
use cache_manager::CacheRoot;
use std::path::Path;
// Compute a path like <crate-root>/.cache/tool/data.bin without creating it.
let cache_path = CacheRoot::discover_cache_path(".cache", "tool/data.bin");
println!("cache path: {}", cache_path.display());
// Expected relative location under the discovered crate root:
assert!(cache_path.ends_with(Path::new(".cache").join("tool").join("data.bin")));
// The call only computes the path; it does not create files or directories.
assert!(!cache_path.exists());
// If you already have an absolute entry path, it's returned unchanged:
let absolute = std::path::PathBuf::from("/tmp/custom/cache.json");
let kept = CacheRoot::discover_cache_path(".cache", &absolute);
assert_eq!(kept, absolute);Filesystem effects
- Pure (no I/O):
CacheRoot::discover,CacheRoot::discover_cache_path,CacheRoot::cache_path,CacheRoot::group,CacheGroup::entry_path,CacheGroup::subgroup - Create dirs:
CacheRoot::ensure_group,CacheGroup::ensure_dir - Create dirs + optional eviction:
CacheRoot::ensure_group_with_policy,CacheGroup::ensure_dir_with_policy - Create file (creates parents as needed):
CacheGroup::touch
Note: eviction only runs when you pass a policy to the
*_with_policymethods.
§Eviction Policy
Use EvictPolicy with:
CacheGroup::ensure_dir_with_policy(...)CacheRoot::ensure_group_with_policy(...)CacheGroup::eviction_report(...)to preview which files would be evicted.
Policy fields:
max_age: remove files older than or equal to the age threshold.max_files: keep at most N files.max_bytes: keep total file bytes at or below the threshold.
Eviction order is always:
max_agemax_filesmax_bytes
For max_files and max_bytes, files are evicted oldest-first by modified time (ascending), then by path for deterministic tie-breaking.
eviction_report(...) and ensure_*_with_policy(...) use the same selection logic.
§How max_bytes works
- Scans regular files recursively under the managed directory.
- Sums
metadata.len()across those files. - If total exceeds
max_bytes, removes files oldest-first until total is<= max_bytes. - Directories are not counted as bytes.
- Enforcement happens only during policy-aware
ensure_*_with_policycalls (not continuously in the background).
§More examples
Create a CacheRoot from an explicit path and apply an eviction policy to a group:
use cache_manager::{CacheRoot, EvictPolicy};
use std::time::Duration;
let root = CacheRoot::from_root("/tmp/project");
let group = root.group("artifacts");
let policy = EvictPolicy {
max_files: Some(100),
max_age: Some(Duration::from_secs(60 * 60 * 24 * 30)), // 30 days
..Default::default()
};
group.ensure_dir_with_policy(Some(&policy)).expect("ensure and evict");Preview which files would be removed without applying deletions:
use cache_manager::{CacheRoot, EvictPolicy};
let root = CacheRoot::from_root("/tmp/project");
let group = root.group("artifacts");
let policy = EvictPolicy {
max_files: Some(10),
..Default::default()
};
let report = group.eviction_report(&policy).expect("eviction report");
for p in report.marked_for_eviction {
println!("would remove: {}", p.display());
}Create or update a cache entry (ensures parent directories exist):
use cache_manager::CacheRoot;
let root = CacheRoot::from_root("/tmp/project");
let group = root.group("artifacts/json");
let entry = group.touch("v1/index.bin").expect("touch entry");
println!("touched: {}", entry.display());Per-subdirectory policies
Different subdirectories under the same CacheRoot can use independent policies; call ensure_dir_with_policy on each CacheGroup separately to apply per-group rules.
Get the root path
To obtain the underlying filesystem path for a CacheRoot, use path():
use cache_manager::CacheRoot;
let root = CacheRoot::from_root("/tmp/project");
let root_path = root.path();
println!("root path: {}", root_path.display());Also obtain a CacheGroup path and resolve an entry path under that group:
use cache_manager::CacheRoot;
let root = CacheRoot::from_root("/tmp/project");
let group = root.group("artifacts");
let group_path = group.path();
println!("group path: {}", group_path.display());
let entry_path = group.entry_path("v1/index.bin");
println!("entry path: {}", entry_path.display());§License
cache-manager is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0).
See LICENSE-APACHE and LICENSE-MIT for details.
Structs§
- Cache
Group - A group (subdirectory) under a
CacheRootthat manages cache entries. - Cache
Root - Represents a discovered or explicit cache root directory.
- Evict
Policy - Optional eviction controls applied by
CacheGroup::ensure_dir_with_policyandCacheRoot::ensure_group_with_policy. - Eviction
Report - Files selected for eviction by policy evaluation.