1mod layout;
9pub use layout::CacheLayout;
10
11use crate::error::PathError;
12use crate::util::sha256_hex;
13use std::path::{Path, PathBuf};
14
15fn home() -> Result<PathBuf, PathError> {
16 dirs::home_dir().ok_or(PathError::NoHome)
17}
18
19pub fn cache_root() -> Result<PathBuf, PathError> {
23 let base = dirs::cache_dir().ok_or(PathError::NoCacheDir)?;
24 Ok(base.join("dejavu"))
25}
26
27pub fn global_shims_bin() -> Result<PathBuf, PathError> {
31 Ok(cache_root()?.join("shims").join("bin"))
32}
33
34pub fn config_file_path() -> Result<PathBuf, PathError> {
37 let base = match std::env::var_os("XDG_CONFIG_HOME") {
38 Some(v) if !v.is_empty() && Path::new(&v).is_absolute() => PathBuf::from(v),
39 _ => home()?.join(".config"),
40 };
41 Ok(base.join("dejavu").join("config.toml"))
42}
43
44pub fn repo_hash(repo_root: &Path) -> String {
47 let canonical = std::fs::canonicalize(repo_root).unwrap_or_else(|_| repo_root.to_path_buf());
48 let full = sha256_hex(canonical.to_string_lossy().as_bytes());
49 full[..16].to_string()
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn repo_hash_is_stable_and_16_hex() {
58 let a = repo_hash(Path::new("/nonexistent/path/one"));
59 let b = repo_hash(Path::new("/nonexistent/path/one"));
60 let c = repo_hash(Path::new("/nonexistent/path/two"));
61 assert_eq!(a, b);
62 assert_ne!(a, c);
63 assert_eq!(a.len(), 16);
64 assert!(a.chars().all(|ch| ch.is_ascii_hexdigit()));
65 }
66}