1use anyhow::{anyhow, Context, Result};
4use std::path::PathBuf;
5
6const ENV_OVERRIDE: &str = "BROWSER_CONTROL_DATA_DIR";
7const CONFIG_ENV_OVERRIDE: &str = "BROWSER_CONTROL_CONFIG_DIR";
8
9pub fn data_dir() -> Result<PathBuf> {
17 if let Some(v) = std::env::var_os(ENV_OVERRIDE) {
18 let p = PathBuf::from(v);
19 if p.as_os_str().is_empty() {
20 return Err(anyhow!("{} is set but empty", ENV_OVERRIDE));
21 }
22 return Ok(p);
23 }
24
25 let pd = directories::ProjectDirs::from("", "", "browser-control")
26 .ok_or_else(|| anyhow!("could not determine user data directory (no home dir found)"))?;
27 Ok(pd.data_dir().to_path_buf())
28}
29
30pub fn registry_db_path() -> Result<PathBuf> {
32 let dir = data_dir()?;
33 std::fs::create_dir_all(&dir)
34 .with_context(|| format!("creating data dir {}", dir.display()))?;
35 Ok(dir.join("registry.db"))
36}
37
38pub fn config_dir() -> Result<PathBuf> {
46 if let Some(v) = std::env::var_os(CONFIG_ENV_OVERRIDE) {
47 let p = PathBuf::from(v);
48 if p.as_os_str().is_empty() {
49 return Err(anyhow!("{} is set but empty", CONFIG_ENV_OVERRIDE));
50 }
51 return Ok(p);
52 }
53
54 let pd = directories::ProjectDirs::from("", "", "browser-control")
55 .ok_or_else(|| anyhow!("could not determine user config directory (no home dir found)"))?;
56 Ok(pd.config_dir().to_path_buf())
57}
58
59pub fn config_file_path() -> Result<PathBuf> {
61 let dir = config_dir()?;
62 std::fs::create_dir_all(&dir)
63 .with_context(|| format!("creating config dir {}", dir.display()))?;
64 Ok(dir.join("config.toml"))
65}
66
67pub fn profiles_dir() -> Result<PathBuf> {
69 let dir = data_dir()?.join("profiles");
70 std::fs::create_dir_all(&dir)
71 .with_context(|| format!("creating profiles dir {}", dir.display()))?;
72 Ok(dir)
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn paths_work() {
81 let _g = crate::test_support::ENV_LOCK
82 .lock()
83 .unwrap_or_else(|e| e.into_inner());
84 let tmp = tempfile::TempDir::new().unwrap();
86 let tmp_path = tmp.path().to_path_buf();
87 std::env::set_var(ENV_OVERRIDE, &tmp_path);
90
91 assert_eq!(data_dir().unwrap(), tmp_path);
92
93 let db = registry_db_path().unwrap();
94 assert_eq!(db, tmp_path.join("registry.db"));
95 assert!(db.parent().unwrap().exists());
96 assert_eq!(db.file_name().unwrap(), "registry.db");
97
98 let pdir = profiles_dir().unwrap();
99 assert_eq!(pdir, tmp_path.join("profiles"));
100 assert!(pdir.is_dir());
101 assert_eq!(pdir.file_name().unwrap(), "profiles");
102
103 std::env::remove_var(ENV_OVERRIDE);
105 let d = data_dir().unwrap();
106 assert!(
107 d.ends_with("browser-control"),
108 "expected default data_dir to end with 'browser-control', got {}",
109 d.display()
110 );
111 }
112
113 #[test]
114 fn config_paths_work() {
115 let _g = crate::test_support::ENV_LOCK
116 .lock()
117 .unwrap_or_else(|e| e.into_inner());
118 let tmp = tempfile::TempDir::new().unwrap();
119 let tmp_path = tmp.path().to_path_buf();
120 std::env::set_var(CONFIG_ENV_OVERRIDE, &tmp_path);
121
122 assert_eq!(config_dir().unwrap(), tmp_path);
123
124 let cfg = config_file_path().unwrap();
125 assert_eq!(cfg, tmp_path.join("config.toml"));
126 assert!(cfg.parent().unwrap().exists());
127 assert_eq!(cfg.file_name().unwrap(), "config.toml");
128
129 std::env::remove_var(CONFIG_ENV_OVERRIDE);
130 let d = config_dir().unwrap();
131 assert!(
132 d.ends_with("browser-control"),
133 "expected default config_dir to end with 'browser-control', got {}",
134 d.display()
135 );
136 }
137}