use std::ffi::OsString;
use std::path::{Path, PathBuf};
pub const CACHE_DIR_VAR: &str = "MITTS_CACHE_DIR";
pub const CAS_DIR: &str = "cas";
pub const ACTION_CACHE_DIR: &str = "ac";
pub const SOURCES_DIR: &str = "sources";
pub const INDEX_DIR: &str = "index";
pub const JOBSERVER_DIR: &str = "jobserver";
pub const FALLBACK_DIR: &str = ".mitts_cache";
pub fn resolve(explicit: Option<&Path>) -> PathBuf {
explicit.map(Path::to_path_buf).unwrap_or_else(default_root)
}
pub fn default_root() -> PathBuf {
default_root_from(|name| std::env::var_os(name))
}
pub fn default_root_from(lookup: impl Fn(&str) -> Option<OsString>) -> PathBuf {
let set = |name: &str| lookup(name).filter(|value| !value.is_empty());
if let Some(dir) = set(CACHE_DIR_VAR) {
return PathBuf::from(dir);
}
if let Some(xdg) = set("XDG_CACHE_HOME") {
return PathBuf::from(xdg).join("mitts");
}
if let Some(home) = set("HOME") {
return PathBuf::from(home).join(".cache").join("mitts");
}
PathBuf::from(FALLBACK_DIR)
}
pub fn from_cas_root(cas_root: &Path) -> PathBuf {
cas_root.parent().unwrap_or(cas_root).to_path_buf()
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
fn lookup<'a>(vars: &'a [(&'a str, &'a str)]) -> impl Fn(&str) -> Option<OsString> + 'a {
let map: HashMap<&'a str, &'a str> = vars.iter().copied().collect();
move |name| map.get(name).map(OsString::from)
}
#[test]
fn explicit_dir_wins_over_environment() {
assert_eq!(resolve(Some(Path::new("/tmp/x"))), PathBuf::from("/tmp/x"));
}
#[test]
fn precedence_is_mitts_then_xdg_then_home_then_fallback() {
let all = [
("MITTS_CACHE_DIR", "/m"),
("XDG_CACHE_HOME", "/x"),
("HOME", "/h"),
];
assert_eq!(default_root_from(lookup(&all)), PathBuf::from("/m"));
assert_eq!(
default_root_from(lookup(&all[1..])),
PathBuf::from("/x/mitts")
);
assert_eq!(
default_root_from(lookup(&all[2..])),
PathBuf::from("/h/.cache/mitts")
);
assert_eq!(default_root_from(lookup(&[])), PathBuf::from(FALLBACK_DIR));
}
#[test]
fn empty_variables_count_as_unset() {
let vars = [
("MITTS_CACHE_DIR", ""),
("XDG_CACHE_HOME", ""),
("HOME", "/h"),
];
assert_eq!(
default_root_from(lookup(&vars)),
PathBuf::from("/h/.cache/mitts")
);
}
#[test]
fn cas_root_maps_back_to_its_cache_root() {
assert_eq!(from_cas_root(Path::new("/r/cas")), PathBuf::from("/r"));
}
}