steer_core/utils/
paths.rs1use std::path::PathBuf;
2
3pub struct AppPaths;
9
10impl AppPaths {
11 pub fn project_dir() -> PathBuf {
13 PathBuf::from(".steer")
14 }
15
16 pub fn project_catalog() -> PathBuf {
18 Self::project_dir().join("catalog.toml")
19 }
20
21 pub fn user_config_dir() -> Option<PathBuf> {
23 directories::ProjectDirs::from("", "", "steer").map(|d| d.config_dir().to_path_buf())
24 }
25
26 pub fn user_data_dir() -> Option<PathBuf> {
28 directories::ProjectDirs::from("", "", "steer").map(|d| d.data_dir().to_path_buf())
29 }
30
31 pub fn local_environment_root() -> PathBuf {
34 if let Ok(root) = std::env::var("STEER_ENV_ROOT") {
35 return PathBuf::from(root);
36 }
37 if let Some(data_dir) = Self::user_data_dir() {
38 return data_dir.join("envs").join("local");
39 }
40 if let Some(home_dir) = dirs::home_dir() {
41 return home_dir.join(".steer").join("envs").join("local");
42 }
43 PathBuf::from(".steer/envs/local")
44 }
45
46 pub fn user_catalog() -> Option<PathBuf> {
48 Self::user_config_dir().map(|d| d.join("catalog.toml"))
49 }
50
51 pub fn discover_catalogs() -> Vec<PathBuf> {
54 let mut paths = Vec::new();
55 paths.push(Self::project_catalog());
56 if let Some(user_cat) = Self::user_catalog() {
57 paths.push(user_cat);
58 }
59 paths
60 }
61
62 pub fn discover_session_configs() -> Vec<PathBuf> {
64 let mut paths = Vec::new();
65 let project = Self::project_dir().join("session.toml");
67 if project.exists() {
68 paths.push(project);
69 }
70 if let Some(user_cfg) = Self::user_config_dir() {
71 let user = user_cfg.join("session.toml");
72 if user.exists() {
73 paths.push(user);
74 }
75 }
76 paths
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn project_paths_are_static() {
86 assert_eq!(AppPaths::project_dir(), PathBuf::from(".steer"));
87 assert_eq!(
88 AppPaths::project_catalog(),
89 PathBuf::from(".steer/catalog.toml")
90 );
91 }
92
93 #[test]
94 fn discover_catalogs_order_is_deterministic() {
95 let catalogs = AppPaths::discover_catalogs();
96 assert!(catalogs.len() == 1 || catalogs.len() == 2);
98 assert_eq!(catalogs[0], PathBuf::from(".steer/catalog.toml"));
99 if catalogs.len() == 2 {
100 let expected_user =
101 AppPaths::user_catalog().expect("user catalog path should exist when returned");
102 assert_eq!(catalogs[1], expected_user);
103 }
104 }
105
106 #[test]
107 fn discover_session_configs_order_is_deterministic() {
108 let configs = AppPaths::discover_session_configs();
109 assert!(configs.len() <= 2);
111 if configs.len() == 2 {
112 assert_eq!(configs[0], PathBuf::from(".steer/session.toml"));
114 let expected_user = AppPaths::user_config_dir().unwrap().join("session.toml");
115 assert_eq!(configs[1], expected_user);
116 } else if configs.len() == 1 {
117 let single = &configs[0];
119 let is_project = *single == PathBuf::from(".steer/session.toml");
120 let is_user =
121 AppPaths::user_config_dir().is_some_and(|d| single == &d.join("session.toml"));
122 assert!(is_project || is_user);
123 }
124 }
125}