Skip to main content

chkpt_core/
config.rs

1use std::path::{Path, PathBuf};
2
3/// Generate a 16-hex-char project ID from workspace path.
4pub fn project_id_from_path(path: &Path) -> String {
5    let canonical = path.to_string_lossy();
6    let hash = xxhash_rust::xxh3::xxh3_128(canonical.as_bytes());
7    format!("{:032x}", hash)[..16].to_string()
8}
9
10/// Store directory layout for a project.
11pub struct StoreLayout {
12    base: PathBuf,
13}
14
15impl StoreLayout {
16    pub fn new(project_id: &str) -> Self {
17        let home_dir = std::env::var_os("CHKPT_HOME")
18            .map(PathBuf::from)
19            .or_else(dirs::home_dir)
20            .unwrap_or_else(|| PathBuf::from("."));
21        Self::from_home_dir(home_dir, project_id)
22    }
23
24    pub fn from_home_dir<P: AsRef<Path>>(home_dir: P, project_id: &str) -> Self {
25        let base = home_dir
26            .as_ref()
27            .join(".chkpt")
28            .join("stores")
29            .join(project_id);
30        Self { base }
31    }
32
33    pub fn base_dir(&self) -> &Path {
34        &self.base
35    }
36
37    pub fn catalog_path(&self) -> PathBuf {
38        self.base.join("catalog.sqlite")
39    }
40
41    pub fn trees_dir(&self) -> PathBuf {
42        self.base.join("trees")
43    }
44
45    pub fn packs_dir(&self) -> PathBuf {
46        self.base.join("packs")
47    }
48
49    pub fn index_path(&self) -> PathBuf {
50        self.base.join("index.bin")
51    }
52
53    pub fn locks_dir(&self) -> PathBuf {
54        self.base.join("locks")
55    }
56
57    /// Create all required directories.
58    pub fn ensure_dirs(&self) -> std::io::Result<()> {
59        for dir in [
60            self.base.clone(),
61            self.trees_dir(),
62            self.packs_dir(),
63            self.locks_dir(),
64        ] {
65            std::fs::create_dir_all(dir)?;
66        }
67
68        // Prevent macOS Spotlight from indexing the store directory.
69        // mdworker_shared processes spike CPU after bulk writes without this.
70        #[cfg(target_os = "macos")]
71        {
72            let marker = self.base.join(".metadata_never_index");
73            if !marker.exists() {
74                std::fs::File::create(marker)?;
75            }
76        }
77
78        Ok(())
79    }
80}