Skip to main content

bv_core/
cache.rs

1use std::path::PathBuf;
2
3/// On-disk layout for bv's local cache.
4pub struct CacheLayout {
5    root: PathBuf,
6}
7
8impl CacheLayout {
9    /// Resolve the cache root.
10    ///
11    /// Priority:
12    /// 1. `BV_CACHE_DIR` env var (used by tests and CI for isolation)
13    /// 2. `$XDG_CACHE_HOME/bv` if `XDG_CACHE_HOME` is set
14    /// 3. `~/.cache/bv` (consistent across Linux and macOS)
15    pub fn new() -> Self {
16        if let Ok(dir) = std::env::var("BV_CACHE_DIR") {
17            return Self::with_root(PathBuf::from(dir));
18        }
19        let root = xdg_cache_home().join("bv");
20        Self { root }
21    }
22
23    pub fn with_root(root: PathBuf) -> Self {
24        Self { root }
25    }
26
27    pub fn root(&self) -> &PathBuf {
28        &self.root
29    }
30
31    /// `<root>/images/<digest>/` - metadata we track alongside runtime storage.
32    pub fn image_dir(&self, digest: &str) -> PathBuf {
33        self.root.join("images").join(digest)
34    }
35
36    /// `<root>/tools/<tool_id>/<version>/manifest.toml`
37    pub fn manifest_path(&self, tool_id: &str, version: &str) -> PathBuf {
38        self.root
39            .join("tools")
40            .join(tool_id)
41            .join(version)
42            .join("manifest.toml")
43    }
44
45    /// `<root>/index/<index_name>/` - local clones of git registries.
46    pub fn index_dir(&self, index_name: &str) -> PathBuf {
47        self.root.join("index").join(index_name)
48    }
49
50    /// `<root>/data/<dataset_id>/<version>/`
51    pub fn data_dir(&self, dataset_id: &str, version: &str) -> PathBuf {
52        self.root.join("data").join(dataset_id).join(version)
53    }
54
55    /// `<root>/sif/` - Apptainer SIF image cache.
56    pub fn sif_dir(&self) -> PathBuf {
57        self.root.join("sif")
58    }
59
60    /// `<root>/tmp/` - staging area for atomic writes.
61    pub fn tmp_dir(&self) -> PathBuf {
62        self.root.join("tmp")
63    }
64}
65
66impl Default for CacheLayout {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72fn xdg_cache_home() -> PathBuf {
73    if let Ok(dir) = std::env::var("XDG_CACHE_HOME") {
74        return PathBuf::from(dir);
75    }
76    // Fall back to ~/.cache on all platforms.
77    let home = std::env::var_os("HOME")
78        .map(PathBuf::from)
79        .unwrap_or_else(|| PathBuf::from("."));
80    home.join(".cache")
81}