1use std::path::PathBuf;
19use std::sync::RwLock;
20
21use nils_common::env as common_env;
22
23pub const PLAN_ISSUE_STATE_HOME_ENV: &str = "PLAN_ISSUE_HOME";
25
26static CLI_OVERRIDE: RwLock<Option<PathBuf>> = RwLock::new(None);
27
28pub fn set_state_dir_override(value: Option<PathBuf>) {
34 let mut guard = CLI_OVERRIDE
35 .write()
36 .expect("plan-issue state-dir override write lock");
37 *guard = value;
38}
39
40pub fn state_dir() -> PathBuf {
45 if let Some(path) = CLI_OVERRIDE
46 .read()
47 .expect("plan-issue state-dir override read lock")
48 .clone()
49 {
50 return path;
51 }
52
53 if let Some(value) = common_env::env_non_empty(PLAN_ISSUE_STATE_HOME_ENV) {
54 return PathBuf::from(value);
55 }
56
57 xdg_default()
58}
59
60fn xdg_default() -> PathBuf {
61 if let Some(value) = common_env::env_non_empty("XDG_STATE_HOME") {
62 return PathBuf::from(value).join("plan-issue");
63 }
64
65 let home = std::env::var_os("HOME")
66 .map(PathBuf::from)
67 .unwrap_or_else(|| PathBuf::from("/"));
68 home.join(".local").join("state").join("plan-issue")
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use nils_test_support::{EnvGuard, GlobalStateLock};
75
76 fn reset() {
77 set_state_dir_override(None);
78 }
79
80 #[test]
81 fn cli_override_wins_over_env_and_xdg() {
82 let lock = GlobalStateLock::new();
83 let _env = EnvGuard::set(&lock, "PLAN_ISSUE_HOME", "/tmp/plan-issue-env");
84 let _xdg = EnvGuard::set(&lock, "XDG_STATE_HOME", "/tmp/xdg");
85
86 set_state_dir_override(Some(PathBuf::from("/tmp/cli-override")));
87 let resolved = state_dir();
88 reset();
89
90 assert_eq!(resolved, PathBuf::from("/tmp/cli-override"));
91 }
92
93 #[test]
94 fn env_used_when_override_unset() {
95 let lock = GlobalStateLock::new();
96 reset();
97 let _env = EnvGuard::set(&lock, "PLAN_ISSUE_HOME", "/tmp/plan-issue-env");
98 let _xdg = EnvGuard::set(&lock, "XDG_STATE_HOME", "/tmp/xdg");
99
100 let resolved = state_dir();
101 assert_eq!(resolved, PathBuf::from("/tmp/plan-issue-env"));
102 }
103
104 #[test]
105 fn xdg_default_when_neither_override_nor_env_set() {
106 let lock = GlobalStateLock::new();
107 reset();
108 let _env = EnvGuard::remove(&lock, "PLAN_ISSUE_HOME");
109 let _xdg = EnvGuard::set(&lock, "XDG_STATE_HOME", "/tmp/xdg");
110
111 let resolved = state_dir();
112 assert_eq!(resolved, PathBuf::from("/tmp/xdg/plan-issue"));
113 }
114}