1use std::collections::hash_map::DefaultHasher;
8use std::hash::{Hash, Hasher};
9use std::path::{Path, PathBuf};
10
11use crate::config::Config;
12
13pub fn resolve_root(arg: Option<&str>) -> PathBuf {
15 let raw = arg.unwrap_or(".");
16 std::fs::canonicalize(raw).unwrap_or_else(|_| PathBuf::from(raw))
17}
18
19pub fn state_dir(root: &Path) -> PathBuf {
24 let mut h = DefaultHasher::new();
25 root.hash(&mut h);
26 let hash = format!("{:016x}", h.finish());
27 let xdg = non_empty(std::env::var_os("XDG_CACHE_HOME").or_else(win_var("LOCALAPPDATA")));
30 let home = non_empty(std::env::var_os("HOME").or_else(win_var("USERPROFILE")));
31 let rgx_cache = non_empty(std::env::var_os("RGX_CACHE_DIR"));
32 let cfg = Config::get().cache_dir.clone();
33 let base = cache_base(rgx_cache, cfg, xdg, home);
34 base.join(hash)
35}
36
37#[cfg(windows)]
38pub(crate) fn win_var(name: &'static str) -> impl FnOnce() -> Option<std::ffi::OsString> {
39 move || std::env::var_os(name)
40}
41
42#[cfg(not(windows))]
43pub(crate) fn win_var(_name: &'static str) -> impl FnOnce() -> Option<std::ffi::OsString> {
44 || None
45}
46
47pub(crate) fn non_empty(v: Option<std::ffi::OsString>) -> Option<std::ffi::OsString> {
49 v.filter(|s| !s.is_empty())
50}
51
52fn cache_base(
53 rgx_cache_dir: Option<std::ffi::OsString>,
54 config_cache_dir: Option<PathBuf>,
55 xdg_cache_home: Option<std::ffi::OsString>,
56 home: Option<std::ffi::OsString>,
57) -> PathBuf {
58 if let Some(dir) = rgx_cache_dir {
59 return PathBuf::from(dir);
60 }
61 if let Some(dir) = config_cache_dir {
62 return dir;
63 }
64 xdg_cache_home
65 .map(PathBuf::from)
66 .or_else(|| home.map(|h| PathBuf::from(h).join(".cache")))
67 .unwrap_or_else(std::env::temp_dir)
68 .join("rgx")
69}
70
71pub fn snapshot_path(root: &Path) -> PathBuf {
72 state_dir(root).join("index.bin")
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use std::ffi::OsString;
79
80 fn os(s: &str) -> Option<OsString> {
81 Some(OsString::from(s))
82 }
83
84 #[test]
85 fn cache_base_precedence() {
86 let cfg = || Some(PathBuf::from("/cfg/cache"));
87 assert_eq!(
88 cache_base(os("/custom/rgx"), cfg(), os("/xdg"), os("/home/u")),
89 PathBuf::from("/custom/rgx")
90 );
91 assert_eq!(
92 cache_base(None, cfg(), os("/xdg"), os("/home/u")),
93 PathBuf::from("/cfg/cache")
94 );
95 assert_eq!(
96 cache_base(None, None, os("/xdg"), os("/home/u")),
97 PathBuf::from("/xdg/rgx")
98 );
99 assert_eq!(
100 cache_base(None, None, None, os("/home/u")),
101 PathBuf::from("/home/u/.cache/rgx")
102 );
103 }
104}