swarm_engine_core/config/
paths.rs1use std::path::PathBuf;
14
15pub struct PathResolver;
17
18impl PathResolver {
19 pub fn system_config_dir() -> PathBuf {
25 dirs::home_dir()
26 .map(|h| h.join(".swarm-engine"))
27 .expect("Could not determine home directory")
28 }
29
30 pub fn global_config_file() -> PathBuf {
32 Self::system_config_dir().join("config.toml")
33 }
34
35 pub fn cache_dir() -> PathBuf {
37 Self::system_config_dir().join("cache")
38 }
39
40 pub fn logs_dir() -> PathBuf {
42 Self::system_config_dir().join("logs")
43 }
44
45 pub fn state_dir() -> PathBuf {
47 Self::system_config_dir().join("state")
48 }
49
50 pub fn user_data_dir() -> PathBuf {
58 if let Ok(dir) = std::env::var("SWARM_ENGINE_USER_DATA_DIR") {
59 return PathBuf::from(dir);
60 }
61
62 dirs::home_dir()
63 .map(|h| h.join("swarm-engine"))
64 .expect("Could not determine home directory")
65 }
66
67 pub fn user_scenarios_dir() -> PathBuf {
69 Self::user_data_dir().join("scenarios")
70 }
71
72 pub fn user_eval_scenarios_dir() -> PathBuf {
74 Self::user_scenarios_dir().join("eval")
75 }
76
77 pub fn user_gym_scenarios_dir() -> PathBuf {
79 Self::user_scenarios_dir().join("gym")
80 }
81
82 pub fn reports_dir() -> PathBuf {
84 Self::user_data_dir().join("reports")
85 }
86
87 pub fn exports_dir() -> PathBuf {
89 Self::user_data_dir().join("exports")
90 }
91
92 pub fn templates_dir() -> PathBuf {
94 Self::user_data_dir().join("templates")
95 }
96
97 pub fn project_dir() -> Option<PathBuf> {
105 std::env::current_dir()
106 .ok()
107 .map(|d| d.join("swarm-engine"))
108 .filter(|p| p.exists())
109 }
110
111 pub fn project_config_file() -> Option<PathBuf> {
113 Self::project_dir().map(|d| d.join("config.toml"))
114 }
115
116 pub fn project_scenarios_dir() -> Option<PathBuf> {
118 Self::project_dir().map(|d| d.join("scenarios"))
119 }
120
121 pub fn project_eval_scenarios_dir() -> Option<PathBuf> {
123 Self::project_dir().map(|d| d.join("scenarios").join("eval"))
124 }
125
126 pub fn project_gym_scenarios_dir() -> Option<PathBuf> {
128 Self::project_dir().map(|d| d.join("scenarios").join("gym"))
129 }
130
131 pub fn project_reports_dir() -> Option<PathBuf> {
133 Self::project_dir().map(|d| d.join("reports"))
134 }
135
136 pub fn ensure_dirs() -> std::io::Result<()> {
144 let dirs = [
145 Self::system_config_dir(),
146 Self::cache_dir(),
147 Self::logs_dir(),
148 Self::state_dir(),
149 Self::user_data_dir(),
150 Self::user_eval_scenarios_dir(),
151 Self::user_gym_scenarios_dir(),
152 Self::reports_dir(),
153 ];
154
155 for dir in dirs {
156 if !dir.exists() {
157 std::fs::create_dir_all(&dir)?;
158 tracing::info!("Created directory: {}", dir.display());
159 }
160 }
161
162 Ok(())
163 }
164
165 pub fn eval_scenario_search_paths() -> Vec<PathBuf> {
171 let mut paths = vec![Self::user_eval_scenarios_dir()];
172
173 if let Some(project_dir) = Self::project_eval_scenarios_dir() {
174 if project_dir.exists() {
175 paths.push(project_dir);
176 }
177 }
178
179 paths
180 }
181
182 pub fn gym_scenario_search_paths() -> Vec<PathBuf> {
184 let mut paths = vec![Self::user_gym_scenarios_dir()];
185
186 if let Some(project_dir) = Self::project_gym_scenarios_dir() {
187 if project_dir.exists() {
188 paths.push(project_dir);
189 }
190 }
191
192 paths
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_system_config_dir() {
202 let dir = PathResolver::system_config_dir();
203 assert!(dir.ends_with(".swarm-engine"));
204 }
205
206 #[test]
207 fn test_user_data_dir() {
208 std::env::remove_var("SWARM_ENGINE_USER_DATA_DIR");
210
211 let dir = PathResolver::user_data_dir();
212 assert!(dir.ends_with("swarm-engine"));
213 assert!(!dir.to_string_lossy().contains("/.swarm-engine"));
215 }
216
217 #[test]
218 fn test_user_data_dir_env_override() {
219 let test_dir = "/tmp/test-swarm-engine";
220 std::env::set_var("SWARM_ENGINE_USER_DATA_DIR", test_dir);
221
222 let dir = PathResolver::user_data_dir();
223 assert_eq!(dir, PathBuf::from(test_dir));
224
225 std::env::remove_var("SWARM_ENGINE_USER_DATA_DIR");
226 }
227
228 #[test]
229 fn test_eval_scenario_search_paths() {
230 let paths = PathResolver::eval_scenario_search_paths();
231 assert!(!paths.is_empty());
232 assert!(paths[0].ends_with("scenarios/eval"));
234 }
235}