ricecoder_storage/config/
modes.rs1use super::Config;
9use crate::types::StorageMode;
10use std::path::Path;
11
12pub struct StorageModeHandler;
14
15impl StorageModeHandler {
16 pub fn load_for_mode(
22 mode: StorageMode,
23 global_path: Option<&Path>,
24 project_path: Option<&Path>,
25 ) -> crate::error::StorageResult<Config> {
26 match mode {
27 StorageMode::GlobalOnly => Self::load_global_only(global_path),
28 StorageMode::ProjectOnly => Self::load_project_only(project_path),
29 StorageMode::Merged => Self::load_merged(global_path, project_path),
30 }
31 }
32
33 fn load_global_only(global_path: Option<&Path>) -> crate::error::StorageResult<Config> {
35 if let Some(path) = global_path {
36 let config_file = path.join("config.yaml");
37 if config_file.exists() {
38 return super::loader::ConfigLoader::load_from_file(&config_file);
39 }
40 }
41 Ok(Config::default())
42 }
43
44 fn load_project_only(project_path: Option<&Path>) -> crate::error::StorageResult<Config> {
46 if let Some(path) = project_path {
47 let config_file = path.join("config.yaml");
48 if config_file.exists() {
49 return super::loader::ConfigLoader::load_from_file(&config_file);
50 }
51 }
52 Ok(Config::default())
53 }
54
55 fn load_merged(
57 global_path: Option<&Path>,
58 project_path: Option<&Path>,
59 ) -> crate::error::StorageResult<Config> {
60 let global_config = if let Some(path) = global_path {
61 let config_file = path.join("config.yaml");
62 if config_file.exists() {
63 super::loader::ConfigLoader::load_from_file(&config_file).ok()
64 } else {
65 None
66 }
67 } else {
68 None
69 };
70
71 let project_config = if let Some(path) = project_path {
72 let config_file = path.join("config.yaml");
73 if config_file.exists() {
74 super::loader::ConfigLoader::load_from_file(&config_file).ok()
75 } else {
76 None
77 }
78 } else {
79 None
80 };
81
82 let (merged, _) = super::merge::ConfigMerger::merge(
83 Config::default(),
84 global_config,
85 project_config,
86 None,
87 );
88
89 Ok(merged)
90 }
91
92 pub fn verify_isolation(
97 mode: StorageMode,
98 global_path: Option<&Path>,
99 project_path: Option<&Path>,
100 ) -> crate::error::StorageResult<bool> {
101 match mode {
102 StorageMode::GlobalOnly => {
103 if let Some(path) = project_path {
105 let config_file = path.join("config.yaml");
106 Ok(!config_file.exists())
107 } else {
108 Ok(true)
109 }
110 }
111 StorageMode::ProjectOnly => {
112 if let Some(path) = global_path {
114 let config_file = path.join("config.yaml");
115 Ok(!config_file.exists())
116 } else {
117 Ok(true)
118 }
119 }
120 StorageMode::Merged => {
121 Ok(true)
123 }
124 }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use std::fs;
132 use tempfile::TempDir;
133
134 #[test]
135 fn test_global_only_mode_loads_global() {
136 let temp_dir = TempDir::new().expect("Failed to create temp dir");
137 let global_path = temp_dir.path();
138
139 let config_file = global_path.join("config.yaml");
141 let config_content = r#"
142providers:
143 default_provider: openai
144defaults:
145 model: gpt-4
146steering: []
147"#;
148 fs::write(&config_file, config_content).expect("Failed to write config");
149
150 let config =
151 StorageModeHandler::load_for_mode(StorageMode::GlobalOnly, Some(global_path), None)
152 .expect("Failed to load config");
153
154 assert_eq!(
155 config.providers.default_provider,
156 Some("openai".to_string())
157 );
158 assert_eq!(config.defaults.model, Some("gpt-4".to_string()));
159 }
160
161 #[test]
162 fn test_project_only_mode_loads_project() {
163 let temp_dir = TempDir::new().expect("Failed to create temp dir");
164 let project_path = temp_dir.path();
165
166 let config_file = project_path.join("config.yaml");
168 let config_content = r#"
169providers:
170 default_provider: anthropic
171defaults:
172 model: claude-3
173steering: []
174"#;
175 fs::write(&config_file, config_content).expect("Failed to write config");
176
177 let config =
178 StorageModeHandler::load_for_mode(StorageMode::ProjectOnly, None, Some(project_path))
179 .expect("Failed to load config");
180
181 assert_eq!(
182 config.providers.default_provider,
183 Some("anthropic".to_string())
184 );
185 assert_eq!(config.defaults.model, Some("claude-3".to_string()));
186 }
187
188 #[test]
189 fn test_merged_mode_project_overrides_global() {
190 let global_dir = TempDir::new().expect("Failed to create temp dir");
191 let project_dir = TempDir::new().expect("Failed to create temp dir");
192
193 let global_config_file = global_dir.path().join("config.yaml");
195 let global_content = r#"
196providers:
197 default_provider: openai
198defaults:
199 model: gpt-4
200steering: []
201"#;
202 fs::write(&global_config_file, global_content).expect("Failed to write global config");
203
204 let project_config_file = project_dir.path().join("config.yaml");
206 let project_content = r#"
207providers:
208 default_provider: anthropic
209defaults:
210 model: claude-3
211steering: []
212"#;
213 fs::write(&project_config_file, project_content).expect("Failed to write project config");
214
215 let config = StorageModeHandler::load_for_mode(
216 StorageMode::Merged,
217 Some(global_dir.path()),
218 Some(project_dir.path()),
219 )
220 .expect("Failed to load config");
221
222 assert_eq!(
224 config.providers.default_provider,
225 Some("anthropic".to_string())
226 );
227 assert_eq!(config.defaults.model, Some("claude-3".to_string()));
228 }
229
230 #[test]
231 fn test_global_only_isolation() {
232 let global_dir = TempDir::new().expect("Failed to create temp dir");
233 let project_dir = TempDir::new().expect("Failed to create temp dir");
234
235 let global_config_file = global_dir.path().join("config.yaml");
237 fs::write(
238 &global_config_file,
239 "providers:\n default_provider: openai\ndefaults: {}\nsteering: []",
240 )
241 .expect("Failed to write global config");
242
243 let project_config_file = project_dir.path().join("config.yaml");
244 fs::write(
245 &project_config_file,
246 "providers:\n default_provider: anthropic\ndefaults: {}\nsteering: []",
247 )
248 .expect("Failed to write project config");
249
250 let config = StorageModeHandler::load_for_mode(
252 StorageMode::GlobalOnly,
253 Some(global_dir.path()),
254 Some(project_dir.path()),
255 )
256 .expect("Failed to load config");
257
258 assert_eq!(
260 config.providers.default_provider,
261 Some("openai".to_string())
262 );
263 }
264
265 #[test]
266 fn test_project_only_isolation() {
267 let global_dir = TempDir::new().expect("Failed to create temp dir");
268 let project_dir = TempDir::new().expect("Failed to create temp dir");
269
270 let global_config_file = global_dir.path().join("config.yaml");
272 fs::write(
273 &global_config_file,
274 "providers:\n default_provider: openai\ndefaults: {}\nsteering: []",
275 )
276 .expect("Failed to write global config");
277
278 let project_config_file = project_dir.path().join("config.yaml");
279 fs::write(
280 &project_config_file,
281 "providers:\n default_provider: anthropic\ndefaults: {}\nsteering: []",
282 )
283 .expect("Failed to write project config");
284
285 let config = StorageModeHandler::load_for_mode(
287 StorageMode::ProjectOnly,
288 Some(global_dir.path()),
289 Some(project_dir.path()),
290 )
291 .expect("Failed to load config");
292
293 assert_eq!(
295 config.providers.default_provider,
296 Some("anthropic".to_string())
297 );
298 }
299}