Skip to main content

skiff_cli/
paths.rs

1//! Cache and config directory resolution (Python-compatible layout).
2//!
3//! - Cache: `$SKIFF_CACHE_DIR` or `~/.cache/skiff` (tool lists, GraphQL/OpenAPI,
4//!   OAuth, sessions, usage)
5//! - Config: `$SKIFF_CONFIG_DIR` or `~/.config/skiff` (`baked.json`)
6//!
7//! Tests may override via [`set_cache_dir_override`] / [`set_config_dir_override`]
8//! under [`TEST_PATHS_LOCK`].
9
10use std::path::PathBuf;
11use std::sync::{LazyLock, RwLock};
12
13static CACHE_DIR_OVERRIDE: LazyLock<RwLock<Option<PathBuf>>> = LazyLock::new(|| RwLock::new(None));
14static CONFIG_DIR_OVERRIDE: LazyLock<RwLock<Option<PathBuf>>> = LazyLock::new(|| RwLock::new(None));
15
16/// Override cache dir (for tests). `None` clears the override.
17pub fn set_cache_dir_override(path: Option<PathBuf>) {
18    *CACHE_DIR_OVERRIDE.write().expect("cache override lock") = path;
19}
20
21/// Override config dir (for tests). `None` clears the override.
22pub fn set_config_dir_override(path: Option<PathBuf>) {
23    *CONFIG_DIR_OVERRIDE.write().expect("config override lock") = path;
24}
25
26pub fn cache_dir() -> PathBuf {
27    if let Some(p) = CACHE_DIR_OVERRIDE
28        .read()
29        .expect("cache override lock")
30        .clone()
31    {
32        return p;
33    }
34    if let Ok(p) = std::env::var("SKIFF_CACHE_DIR") {
35        return PathBuf::from(p);
36    }
37    home_dir()
38        .map(|h| h.join(".cache").join("skiff"))
39        .unwrap_or_else(|| PathBuf::from(".cache/skiff"))
40}
41
42pub fn config_dir() -> PathBuf {
43    if let Some(p) = CONFIG_DIR_OVERRIDE
44        .read()
45        .expect("config override lock")
46        .clone()
47    {
48        return p;
49    }
50    if let Ok(p) = std::env::var("SKIFF_CONFIG_DIR") {
51        return PathBuf::from(p);
52    }
53    home_dir()
54        .map(|h| h.join(".config").join("skiff"))
55        .unwrap_or_else(|| PathBuf::from(".config/skiff"))
56}
57
58pub fn usage_file() -> PathBuf {
59    cache_dir().join("usage.json")
60}
61
62pub fn baked_file() -> PathBuf {
63    config_dir().join("baked.json")
64}
65
66fn home_dir() -> Option<PathBuf> {
67    std::env::var_os("HOME")
68        .or_else(|| std::env::var_os("USERPROFILE"))
69        .map(PathBuf::from)
70}
71
72pub const DEFAULT_CACHE_TTL: u64 = 3600;
73
74/// Shared lock so tests that override cache/config dirs don't race.
75#[cfg(test)]
76pub static TEST_PATHS_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());