{"id":48529987,"url":"https://github.com/jzombie/rust-cache-manager","last_synced_at":"2026-04-07T23:32:34.414Z","repository":{"id":341631070,"uuid":"1170878615","full_name":"jzombie/rust-cache-manager","owner":"jzombie","description":"Simple managed directory system for project-scoped caches with optional eviction policies.","archived":false,"fork":false,"pushed_at":"2026-03-17T01:16:28.000Z","size":41,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-17T07:23:50.287Z","etag":null,"topics":["artifact-cache","cache","caching","development-tools","eviction-policy","filesystem","workspace"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/cache-manager","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jzombie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-02T16:15:43.000Z","updated_at":"2026-03-17T01:16:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jzombie/rust-cache-manager","commit_stats":null,"previous_names":["jzombie/rust-cache-manager"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jzombie/rust-cache-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jzombie%2Frust-cache-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jzombie%2Frust-cache-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jzombie%2Frust-cache-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jzombie%2Frust-cache-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jzombie","download_url":"https://codeload.github.com/jzombie/rust-cache-manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jzombie%2Frust-cache-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31533823,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artifact-cache","cache","caching","development-tools","eviction-policy","filesystem","workspace"],"created_at":"2026-04-07T23:32:34.325Z","updated_at":"2026-04-07T23:32:34.404Z","avatar_url":"https://github.com/jzombie.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cache-manager\n\n[![made-with-rust][rust-logo]][rust-src-page] [![crates.io][crates-badge]][crates-page] [![MIT licensed][mit-license-badge]][mit-license-page] [![Apache 2.0 licensed][apache-2.0-license-badge]][apache-2.0-license-page] [![Coverage][coveralls-badge]][coveralls-page]\n\nDirectory-based cache and artifact path management with discovered `.cache` roots, grouped cache paths, and optional eviction on directory initialization.\n\n\u003e This crate was built to solve a recurring workspace problem we had before adopting it.  \n\u003e Previously, several crates wrote artifacts to different locations with inconsistent eviction policy management.  \n\u003e `cache-manager` provides a single, consistent cache/artifact path layer across the workspace _(and also works outside of `cargo` environments)_.  \n\n- **Core capabilities**\n\t- **Tool-agnostic:** any tool or library that can write to the filesystem can use `cache-manager` as a managed cache/artifact path layout layer.\n\t- **Zero default runtime dependencies:** the standard install uses only the Rust standard library _(optional features do add additional dependencies)_.\n\t- **Built-in eviction policies:** enforce cache limits by file age, file count, and total bytes, with deterministic oldest-first trimming.\n\t- **Predictable discovery + root control:** discover `\u003ccrate-root\u003e/.cache` automatically or pin an explicit root with `CacheRoot::from_root(...)`.\n\t- **Composable cache layout API:** create groups/subgroups and entry paths consistently across tools without custom path-joining logic.\n\t- **Artifact-friendly:** suitable for build outputs, generated files, and intermediate data.\n\t- **Workspace-friendly:** suitable for monorepos or multi-crate workspaces that need centralized cache/artifact management via a shared root (for example with `CacheRoot::from_root(...)`). \n\n- **Optional features**\n\t- **`process-scoped-cache`:** adds [`tempfile`](https://docs.rs/tempfile) and enables process/thread scoped caches.\n\t  - [`CacheRoot::from_tempdir(...)`](#cacheroot-from-tempdir)\n\t  - [`ProcessScopedCacheGroup::new(...)`](#processscopedcachegroup-from-root-and-group-path)\n\t  - [`ProcessScopedCacheGroup::from_group(...)`](#processscopedcachegroup-from-existing-group)\n\t- **`os-cache-dir`:** adds [`directories`](https://docs.rs/directories) and enables OS-native per-user cache roots.\n\t  - [`CacheRoot::from_project_dirs(...)`](#os-native-user-cache-root-optional)\n\n- **Licensing**\n\t- **Open-source + commercial-friendly:** dual-licensed under [MIT][mit-license-page] or [Apache-2.0][apache-2.0-license-page].\n\n\u003e Tested on macOS, Linux, and Windows.\n\n## Usage\n\n### Mental model: root -\u003e groups -\u003e entries\n\n- `CacheRoot`: project/workspace anchor path.\n- `CacheGroup`: subdirectory under a root where a class of cache files lives.\n- Entries: files under a group (for example `v1/index.bin`).\n\n`CacheRoot` and `CacheGroup` are lightweight path objects. Constructing them does not create directories.\n\n### Quick start\n\nUsing `touch` (convenient when you want this crate to create the file):\n\n```rust\nuse cache_manager::{CacheGroup, CacheRoot};\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet group: CacheGroup = root.group(\"artifacts/json\");\n\n// Create the group directory if needed\ngroup.ensure_dir().expect(\"ensure group\");\n\n// `index.bin` is just an example artifact filename that another program might generate\nlet entry: std::path::PathBuf = group.touch(\"v1/index.bin\").expect(\"touch entry\");\n\nlet expected: std::path::PathBuf = root\n\t.path()\n\t.join(\"artifacts\")\n\t.join(\"json\")\n\t.join(\"v1\")\n\t.join(\"index.bin\");\nassert_eq!(entry, expected);\n\n// Example output path\nprintln!(\"{}\", entry.display());\n```\n\nWithout `touch` (compute the path for a separate tool, then write with your own I/O):\n\n```rust\nuse cache_manager::{CacheGroup, CacheRoot};\nuse std::fs;\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet group: CacheGroup = root.group(\"artifacts/json\");\n\ngroup.ensure_dir().expect(\"ensure group\");\n\n// This is the path you can hand to another tool/process\nlet entry_without_touch: std::path::PathBuf = group.entry_path(\"v1/index.bin\");\n\nlet expected: std::path::PathBuf = root\n\t.path()\n\t.join(\"artifacts\")\n\t.join(\"json\")\n\t.join(\"v1\")\n\t.join(\"index.bin\");\nassert_eq!(entry_without_touch, expected);\n\nfs::create_dir_all(entry_without_touch.parent().expect(\"entry parent\"))\n\t.expect(\"create entry parent\");\nfs::write(\u0026entry_without_touch, b\"artifact bytes\").expect(\"write artifact\");\nprintln!(\"{}\", entry_without_touch.display());\n```\n\n### Filesystem effects\n\n- **Core APIs (always available):**\n\t- `CacheRoot::from_root`, `CacheRoot::from_discovery`, `CacheRoot::cache_path`, `CacheRoot::group`\n\t- `CacheGroup::subgroup`, `CacheGroup::entry_path`\n\t- `CacheRoot::ensure_group`, `CacheGroup::ensure_dir`\n\t- `CacheRoot::ensure_group_with_policy`, `CacheGroup::ensure_dir_with_policy`\n\t- `CacheGroup::touch`\n\n- **Feature `os-cache-dir`:**\n\t- `CacheRoot::from_project_dirs`\n\n- **Feature `process-scoped-cache`:**\n\t- `CacheRoot::from_tempdir`\n\t- `ProcessScopedCacheGroup::new`, `ProcessScopedCacheGroup::from_group`\n\t- `ProcessScopedCacheGroup::thread_group`, `ProcessScopedCacheGroup::ensure_thread_group`\n\t- `ProcessScopedCacheGroup::thread_entry_path`, `ProcessScopedCacheGroup::touch_thread_entry`\n\n\u003e Note: eviction only runs when you pass a policy to the `*_with_policy` methods.\n\n### Discovering cache paths\n\nDiscover a cache path for the current crate/workspace and resolve an entry path.\n\n\u003e Note: `CacheRoot::from_discovery()?.cache_path(...)` only computes a filesystem path — it does not create directories or files.\n\nBehavior:\n\n- Searches upward from the current working directory for a `Cargo.toml` and uses `\u003ccrate-root\u003e/.cache` when found; otherwise it falls back to `\u003ccwd\u003e/.cache`.\n- The discovered anchor (`crate root` or `cwd`) is canonicalized when possible to avoid surprising\n  differences between logically-equal paths.\n- If the `relative_path` argument is absolute, it is returned unchanged.\n\n```rust\nuse cache_manager::CacheRoot;\nuse std::path::Path;\n\n// Compute a path like \u003ccrate-root\u003e/.cache/tool/data.bin without creating it\nlet cache_path: std::path::PathBuf = CacheRoot::from_discovery()\n\t.expect(\"discover cache root\")\n\t.cache_path(\"tool\", \"data.bin\");\nprintln!(\"cache path: {}\", cache_path.display());\n\n// Expected relative location under the discovered crate root:\nassert!(cache_path.ends_with(Path::new(\".cache\").join(\"tool\").join(\"data.bin\")));\n\n// The call only computes the path; it does not create files or directories\nassert!(!cache_path.exists());\n\n// If you already have an absolute entry path, it's returned unchanged:\nlet absolute: std::path::PathBuf = std::path::PathBuf::from(\"/tmp/custom/cache.json\");\nlet kept: std::path::PathBuf = CacheRoot::from_discovery()\n\t.expect(\"discover cache root\")\n\t.cache_path(\"tool\", \u0026absolute);\nassert_eq!(kept, absolute);\n```\n\n**Notes on discovery behavior**\n\n`CacheRoot::from_discovery()` deterministically anchors discovered cache\npaths under the configured `CACHE_DIR_NAME` (default: `.cache`). It does\nnot scan for arbitrary directory names — creating a directory named\n`.cache-v2` at the crate root will not cause `from_discovery()` to use it.\nIf you want to use a custom cache root, construct it explicitly with\n`CacheRoot::from_root(...)`.\n\n### OS-native user cache root (optional)\n\nEnable feature flag:\n\n```bash\ncargo add cache-manager --features os-cache-dir\n```\n\nThen construct a `CacheRoot` from platform-native user cache directories:\n\n```rust\nuse cache_manager::CacheRoot;\n\nlet root = CacheRoot::from_project_dirs(\"com\", \"ExampleOrg\", \"ExampleApp\")\n\t.expect(\"discover OS cache dir\");\n\nlet group = root.group(\"artifacts\");\ngroup.ensure_dir().expect(\"ensure group\");\n```\n\n`from_project_dirs` uses `directories::ProjectDirs` and typically resolves to:\n\n- macOS: `~/Library/Caches/\u003capp\u003e`\n- Linux: `$XDG_CACHE_HOME/\u003capp\u003e` or `~/.cache/\u003capp\u003e`\n- Windows: `%LOCALAPPDATA%\\\\\u003corg\u003e\\\\\u003capp\u003e\\\\cache`\n\n`from_project_dirs(qualifier, organization, application)` parameters:\n\n- `qualifier`: a DNS-like namespace component (commonly `\"com\"` or `\"org\"`)\n- `organization`: vendor/team name (for example `\"ExampleOrg\"`)\n- `application`: app/tool identifier (for example `\"ExampleApp\"`)\n\nExample identity tuple:\n\n```rust\nuse cache_manager::CacheRoot;\nuse directories::ProjectDirs;\nuse std::fs;\n\nlet root: CacheRoot = CacheRoot::from_project_dirs(\"com\", \"Acme\", \"WidgetTool\")\n\t.expect(\"discover OS cache dir\");\nlet got: std::path::PathBuf = root.path().to_path_buf();\n\nlet expected: std::path::PathBuf = ProjectDirs::from(\"com\", \"Acme\", \"WidgetTool\")\n\t.expect(\"resolve project dirs\")\n\t.cache_dir()\n\t.to_path_buf();\n\nassert_eq!(got, expected);\n\n// If the example writes anything, keep it scoped and remove it explicitly.\nlet example_group = root.group(\"cache-manager-readme-example\");\nlet probe = example_group.touch(\"probe.txt\").expect(\"write probe\");\nassert!(probe.exists());\nfs::remove_dir_all(example_group.path()).expect(\"cleanup example group\");\n```\n\n\n### Eviction Policy\n\nUse `EvictPolicy` with:\n\n- `CacheGroup::ensure_dir_with_policy(...)`\n- `CacheRoot::ensure_group_with_policy(...)`\n- `CacheGroup::eviction_report(...)` to preview which files would be evicted.\n\nApply policy directly to a `CacheGroup`:\n\n```rust\nuse cache_manager::{CacheRoot, EvictPolicy};\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet group: cache_manager::CacheGroup = root.group(\"artifacts\");\n\nlet policy: EvictPolicy = EvictPolicy {\n\tmax_files: Some(100),\n\t..Default::default()\n};\n\ngroup\n\t.ensure_dir_with_policy(Some(\u0026policy))\n\t.expect(\"ensure and evict\");\n```\n\nApply policy through `CacheRoot` convenience API:\n\n```rust\nuse cache_manager::{CacheRoot, EvictPolicy};\nuse std::time::Duration;\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet policy: EvictPolicy = EvictPolicy {\n\tmax_age: Some(Duration::from_secs(60 * 60 * 24 * 30)), // 30 days\n\t..Default::default()\n};\n\nroot\n\t.ensure_group_with_policy(\"artifacts\", Some(\u0026policy))\n\t.expect(\"ensure group and evict\");\n```\n\nPreview evictions without deleting files:\n\n```rust\nuse cache_manager::{CacheRoot, EvictPolicy, EvictionReport};\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet group: cache_manager::CacheGroup = root.group(\"artifacts\");\nlet policy: EvictPolicy = EvictPolicy {\n\tmax_bytes: Some(10_000_000),\n\t..Default::default()\n};\n\nlet report: EvictionReport = group.eviction_report(\u0026policy).expect(\"eviction report\");\nfor path in report.marked_for_eviction {\n\tprintln!(\"would remove: {}\", path.display());\n}\n```\n\nPolicy fields:\n\n- `max_age`: remove files older than or equal to the age threshold.\n- `max_files`: keep at most N files.\n- `max_bytes`: keep total file bytes at or below the threshold.\n\nPolicies can be combined by setting multiple fields in one `EvictPolicy`.\nWhen combined, all configured limits are enforced in order.\n\n```rust\nuse cache_manager::EvictPolicy;\nuse std::time::Duration;\n\nlet combined: EvictPolicy = EvictPolicy {\n\tmax_age: Some(Duration::from_secs(60 * 60 * 24 * 30)), // 30 days\n\tmax_files: Some(200),\n\tmax_bytes: Some(500 * 1024 * 1024), // 500 MB\n};\n```\n\nEviction order is always:\n\n1. `max_age`\n2. `max_files`\n3. `max_bytes`\n\nFor `max_files` and `max_bytes`, files are evicted oldest-first by modified time (ascending), then by path for deterministic tie-breaking.\n\n`eviction_report(...)` and `ensure_*_with_policy(...)` use the same selection logic.\n\n#### How `max_bytes` works\n\n- Scans regular files recursively under the managed directory.\n- Sums `metadata.len()` across those files.\n- If total exceeds `max_bytes`, removes files oldest-first until total is `\u003c= max_bytes`.\n- Directories are not counted as bytes.\n- Enforcement happens only during policy-aware `ensure_*_with_policy` calls (not continuously in the background).\n\n### Optional process/thread scoped caches\n\nEnable feature flag:\n\n```bash\ncargo add cache-manager --features process-scoped-cache\n```\n\nOr, if editing `Cargo.toml` manually:\n\n```toml\n[dependencies]\ncache-manager = { version = \"\u003clatest\u003e\", features = [\"process-scoped-cache\"] }\n```\n\n#### CacheRoot from tempdir\n\nCreate a temporary cache root backed by a persisted temp directory:\n\n```rust\n#[cfg(feature = \"process-scoped-cache\")]\nfn example_temp_root() {\n\tlet root = cache_manager::CacheRoot::from_tempdir().expect(\"temp cache root\");\n\tlet group = root.group(\"artifacts\");\n\tgroup.ensure_dir().expect(\"ensure group\");\n\n\t// `from_tempdir` intentionally persists the directory; clean up when done.\n\tstd::fs::remove_dir_all(root.path()).expect(\"cleanup temp root\");\n}\n```\n\n#### ProcessScopedCacheGroup from root and group path\n\nUse this constructor when you have a `CacheRoot` plus a relative group path.\nIt creates a process-scoped directory under `root.group(...)`.\n\n```rust\n#[cfg(feature = \"process-scoped-cache\")]\nfn main() {\n\tuse cache_manager::{CacheGroup, CacheRoot, ProcessScopedCacheGroup};\n\tuse std::path::Path;\n\n\t// 1) Build the root and the base group where process directories will live\n\tlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\n\tlet base_group: CacheGroup = root.group(\"artifacts/session\");\n\n\t// 2) Create a process-scoped directory (name starts with `pid-\u003cpid\u003e-...`)\n\tlet scoped: ProcessScopedCacheGroup = ProcessScopedCacheGroup::new(\u0026root, \"artifacts/session\")\n\t\t.expect(\"create process-scoped cache\");\n\n\t// 3) Resolve this thread's subgroup and touch an entry under it\n\tlet thread_group: CacheGroup = scoped.ensure_thread_group().expect(\"ensure thread group\");\n\tlet entry: std::path::PathBuf = thread_group.touch(\"v1/index.bin\").expect(\"touch thread entry\");\n\n\t// 4) Verify the static pieces of the structure\n\tassert!(entry.starts_with(base_group.path()));\n\tassert!(entry.ends_with(Path::new(\"v1/index.bin\")));\n\n\t// 5) Verify the dynamic thread segment (`thread-\u003cn\u003e`)\n\tlet thread_dir: \u0026Path = entry\n\t\t.parent()\n\t\t.and_then(|p| p.parent())\n\t\t.expect(\"thread dir\");\n\n\tassert!(thread_dir\n\t\t.file_name()\n\t\t.and_then(|s| s.to_str())\n\t\t.expect(\"thread dir name\")\n\t\t.starts_with(\"thread-\"));\n\n\t// 6) Verify the dynamic process segment (`pid-\u003ccurrent-pid\u003e-\u003crandom\u003e`)\n\tlet process_dir: \u0026Path = thread_dir.parent().expect(\"process dir\");\n\tlet expected_pid_prefix: String = format!(\"pid-{}-\", std::process::id());\n\n\tassert!(process_dir\n\t\t.file_name()\n\t\t.and_then(|s| s.to_str())\n\t\t.expect(\"process dir name\")\n\t\t.starts_with(\u0026expected_pid_prefix));\n\n\t// Example output path\n\tprintln!(\"{}\", entry.display());\n}\n\n#[cfg(not(feature = \"process-scoped-cache\"))]\nfn main() {}\n```\n\n#### ProcessScopedCacheGroup from existing group\n\nUse this constructor when you already have a `CacheGroup` (for example,\nshared or precomputed by higher-level setup) and want process scoping from\nthat existing group.\n\n```rust\n#[cfg(feature = \"process-scoped-cache\")]\nfn from_group_example() {\n\tuse cache_manager::{CacheGroup, CacheRoot, ProcessScopedCacheGroup};\n\n\tlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\n\tlet base_group: CacheGroup = root.group(\"artifacts/session\");\n\n\tlet scoped: ProcessScopedCacheGroup =\n\t\tProcessScopedCacheGroup::from_group(base_group).expect(\"create process-scoped cache\");\n\tlet thread_entry = scoped\n\t\t.touch_thread_entry(\"v1/index.bin\")\n\t\t.expect(\"touch thread entry\");\n\n\tassert!(thread_entry.starts_with(scoped.path()));\n}\n```\n\nBehavior notes:\n\n- Respects all configured roots/groups because process-scoped paths are always created under your provided `CacheRoot`/`CacheGroup`.\n- The process subdirectory is deleted when the handle is dropped during normal process shutdown.\n- Cleanup is best-effort; abnormal termination (for example `SIGKILL` or crash) can leave stale directories.\n\n### Additional examples\n\nCreate or update a cache entry (ensures parent directories exist):\n\n```rust\nuse cache_manager::{CacheGroup, CacheRoot};\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet group: CacheGroup = root.group(\"artifacts/json\");\n\nlet entry: std::path::PathBuf = group.touch(\"v1/index.bin\").expect(\"touch entry\");\n\nlet expected: std::path::PathBuf = root\n\t.path()\n\t.join(\"artifacts\")\n\t.join(\"json\")\n\t.join(\"v1\")\n\t.join(\"index.bin\");\nassert_eq!(entry, expected);\n\nprintln!(\"touched: {}\", entry.display());\n```\n\n#### Per-subdirectory policies\n\nDifferent subdirectories under the same `CacheRoot` can use independent policies; call `ensure_dir_with_policy` on each `CacheGroup` separately to apply per-group rules.\n\nNote: calling `CacheGroup::ensure_dir()` is equivalent to `CacheGroup::ensure_dir_with_policy(None)`. Likewise, `CacheRoot::ensure_group(...)` behaves the same as `CacheRoot::ensure_group_with_policy(..., None)`.\n\n#### Get the root path\n\nTo obtain the underlying filesystem path for a `CacheRoot`, use `path()`:\n\n```rust\nuse cache_manager::CacheRoot;\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet root_path: \u0026std::path::Path = root.path();\nprintln!(\"root path: {}\", root_path.display());\n```\n\nAlso obtain a `CacheGroup` path and resolve an entry path under that group:\n\n```rust\nuse cache_manager::{CacheGroup, CacheRoot};\n\nlet root: CacheRoot = CacheRoot::from_root(\"/tmp/project\");\nlet group: CacheGroup = root.group(\"artifacts\");\n\nlet group_path: \u0026std::path::Path = group.path();\nprintln!(\"group path: {}\", group_path.display());\n\nlet entry_path: std::path::PathBuf = group.entry_path(\"v1/index.bin\");\nprintln!(\"entry path: {}\", entry_path.display());\n```\n\n## License\n\n`cache-manager` is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0).\n\nSee [LICENSE-APACHE][apache-2.0-license-page] and [LICENSE-MIT][mit-license-page] for details.\n\n[rust-src-page]: https://www.rust-lang.org/\n[rust-logo]: https://img.shields.io/badge/Made%20with-Rust-black\n\n[crates-page]: https://crates.io/crates/cache-manager\n[crates-badge]: https://img.shields.io/crates/v/cache-manager.svg\n\n[mit-license-page]: https://raw.githubusercontent.com/jzombie/rust-cache-manager/refs/heads/main/LICENSE-MIT\n[mit-license-badge]: https://img.shields.io/badge/license-MIT-blue.svg\n\n[apache-2.0-license-page]: https://raw.githubusercontent.com/jzombie/rust-cache-manager/refs/heads/main/LICENSE-APACHE\n[apache-2.0-license-badge]: https://img.shields.io/badge/license-Apache%202.0-blue.svg\n\n[coveralls-page]: https://coveralls.io/github/jzombie/rust-cache-manager?branch=main\n[coveralls-badge]: https://img.shields.io/coveralls/github/jzombie/rust-cache-manager\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjzombie%2Frust-cache-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjzombie%2Frust-cache-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjzombie%2Frust-cache-manager/lists"}