hf_hub/cache/mod.rs
1//! Inspect the local Hugging Face cache.
2//!
3//! [`HFClient::scan_cache`] walks the cache directory and produces an
4//! [`HFCacheInfo`] tree: cached repositories, their revisions, and the
5//! individual files in each revision.
6//!
7//! On disk, downloads are content-addressed — files in
8//! `<cache>/<repo_folder>/snapshots/<commit>/<filename>` are pointers (symlinks
9//! on Unix, copies on Windows) to immutable blobs in
10//! `<cache>/<repo_folder>/blobs/<etag>`. Multiple revisions of the same repo
11//! often share the same blob, which is why repo-level sizes are deduplicated
12//! while revision-level sizes are not — see [`CachedRepoInfo::size_on_disk`]
13//! and [`CachedRevisionInfo::size_on_disk`].
14
15use std::path::PathBuf;
16use std::time::SystemTime;
17
18use bon::bon;
19
20use crate::client::HFClient;
21use crate::error::HFResult;
22
23pub(crate) mod storage;
24
25/// A single file in a cached revision.
26///
27/// `file_path` is the pointer in the `snapshots/` tree (a symlink on Unix);
28/// `blob_path` is the canonical location of the underlying content under
29/// `blobs/`. Both paths refer to the same bytes.
30#[derive(Debug, Clone)]
31pub struct CachedFileInfo {
32 /// Path of the file relative to its revision's snapshot root, including
33 /// any subdirectories (e.g., `subdir/model.bin`).
34 pub file_name: String,
35 /// Absolute path of the pointer file inside the `snapshots/` tree.
36 /// Symlink on Unix, regular file (a copy of the blob) on Windows.
37 pub file_path: PathBuf,
38 /// Absolute path of the actual blob under `blobs/`, after resolving
39 /// `file_path`. Multiple revisions can point at the same blob.
40 pub blob_path: PathBuf,
41 /// Size of the blob in bytes.
42 pub size_on_disk: u64,
43 /// Last access time of the blob, from the filesystem.
44 pub blob_last_accessed: SystemTime,
45 /// Last modification time of the blob, from the filesystem.
46 pub blob_last_modified: SystemTime,
47}
48
49/// A cached revision (commit) of a repository.
50#[derive(Debug, Clone)]
51pub struct CachedRevisionInfo {
52 /// Full 40-character commit SHA.
53 pub commit_hash: String,
54 /// Directory of pointer files for this revision
55 /// (`<cache>/<repo_folder>/snapshots/<commit_hash>/`).
56 pub snapshot_path: PathBuf,
57 /// Files belonging to this revision.
58 pub files: Vec<CachedFileInfo>,
59 /// Sum of [`CachedFileInfo::size_on_disk`] for every file in this
60 /// revision. Blobs shared with other revisions of the same repo are
61 /// counted here but not in [`CachedRepoInfo::size_on_disk`].
62 pub size_on_disk: u64,
63 /// Refs (branches, tags, `refs/pr/<n>`, …) that point at this commit.
64 /// May be empty for revisions only reachable by SHA.
65 pub refs: Vec<String>,
66 /// Latest blob modification time across the files in this revision.
67 pub last_modified: SystemTime,
68}
69
70/// A cached repository, with its revisions aggregated.
71#[derive(Debug, Clone)]
72pub struct CachedRepoInfo {
73 /// Hub repo identifier (e.g., `gpt2`, `google/bert-base-uncased`).
74 pub repo_id: String,
75 /// Lowercase singular name of the repo kind (`"model"`, `"dataset"`, `"space"`, or `"kernel"`)
76 /// — see [`crate::repository::RepoType::singular`].
77 pub repo_type: &'static str,
78 /// Absolute path of the repo's cache subfolder
79 /// (`<cache>/<type>s--<owner>--<name>/`).
80 pub repo_path: PathBuf,
81 /// Cached revisions of this repo.
82 pub revisions: Vec<CachedRevisionInfo>,
83 /// Number of unique blobs stored for this repo. Two revisions sharing the
84 /// same blob count once.
85 pub nb_files: usize,
86 /// Bytes used on disk for unique blobs, with shared blobs counted once.
87 pub size_on_disk: u64,
88 /// Latest blob access time across all revisions.
89 pub last_accessed: SystemTime,
90 /// Latest blob modification time across all revisions.
91 pub last_modified: SystemTime,
92}
93
94/// Snapshot of the local Hugging Face cache directory.
95///
96/// Returned by [`HFClient::scan_cache`]; aggregates every cached repository
97/// found at `cache_dir` along with total disk usage and any warnings emitted
98/// during scanning.
99#[derive(Debug, Clone)]
100pub struct HFCacheInfo {
101 /// Cache directory that was scanned.
102 pub cache_dir: PathBuf,
103 /// Cached repositories discovered under `cache_dir`.
104 pub repos: Vec<CachedRepoInfo>,
105 /// Sum of [`CachedRepoInfo::size_on_disk`] across all repos.
106 pub size_on_disk: u64,
107 /// Human-readable warnings for entries that could not be fully scanned —
108 /// for example, snapshot pointers whose blobs are missing or unreadable.
109 pub warnings: Vec<String>,
110}
111
112#[bon]
113impl HFClient {
114 /// Scan the configured cache directory and return a summary of all cached repositories,
115 /// revisions, and files.
116 ///
117 /// If the cache directory does not exist, returns an [`HFCacheInfo`] with no repos and zero
118 /// size — not an error. Unreadable blobs and dangling snapshot pointers are reported via
119 /// [`HFCacheInfo::warnings`] rather than failing the scan.
120 #[builder(finish_fn = send, derive(Debug, Clone))]
121 pub async fn scan_cache(&self) -> HFResult<HFCacheInfo> {
122 storage::scan_cache_dir(self.cache_dir()).await
123 }
124}
125
126#[cfg(feature = "blocking")]
127#[bon]
128impl crate::blocking::HFClientSync {
129 /// Blocking counterpart of [`HFClient::scan_cache`].
130 #[builder(finish_fn = send, derive(Debug, Clone))]
131 pub fn scan_cache(&self) -> HFResult<HFCacheInfo> {
132 self.runtime.block_on(self.inner.scan_cache().send())
133 }
134}