Skip to main content

Crate cache_manager

Crate cache_manager 

Source
Expand description

§cache-manager

made-with-rust crates.io MIT licensed Apache 2.0 licensed Coverage

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_path only computes a filesystem path — it does not create directories or files.

Behavior:

  • Searches upward from the current working directory for a Cargo.toml and 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_path argument 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_policy methods.

§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:

  1. max_age
  2. max_files
  3. max_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_policy calls (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§

CacheGroup
A group (subdirectory) under a CacheRoot that manages cache entries.
CacheRoot
Represents a discovered or explicit cache root directory.
EvictPolicy
Optional eviction controls applied by CacheGroup::ensure_dir_with_policy and CacheRoot::ensure_group_with_policy.
EvictionReport
Files selected for eviction by policy evaluation.