ricecoder_refactoring/config/
manager.rs

1//! Configuration manager for refactoring engine
2
3use crate::error::Result;
4use crate::providers::ProviderRegistry;
5use crate::types::RefactoringConfig;
6use std::collections::HashMap;
7use std::sync::Arc;
8use tokio::sync::RwLock;
9use ricecoder_storage::manager::StorageManager;
10
11/// Manages refactoring configurations and providers with storage integration
12pub struct ConfigManager {
13    configs: Arc<RwLock<HashMap<String, RefactoringConfig>>>,
14    provider_registry: Arc<RwLock<Option<ProviderRegistry>>>,
15    storage: Option<Arc<dyn StorageManager>>,
16}
17
18impl ConfigManager {
19    /// Create a new configuration manager
20    pub fn new() -> Self {
21        Self {
22            configs: Arc::new(RwLock::new(HashMap::new())),
23            provider_registry: Arc::new(RwLock::new(None)),
24            storage: None,
25        }
26    }
27
28    /// Create a new configuration manager with storage integration
29    pub fn with_storage(storage: Arc<dyn StorageManager>) -> Self {
30        Self {
31            configs: Arc::new(RwLock::new(HashMap::new())),
32            provider_registry: Arc::new(RwLock::new(None)),
33            storage: Some(storage),
34        }
35    }
36
37    /// Create a new configuration manager with a provider registry
38    pub fn with_provider_registry(provider_registry: ProviderRegistry) -> Self {
39        Self {
40            configs: Arc::new(RwLock::new(HashMap::new())),
41            provider_registry: Arc::new(RwLock::new(Some(provider_registry))),
42            storage: None,
43        }
44    }
45
46    /// Create a new configuration manager with both storage and provider registry
47    pub fn with_storage_and_registry(
48        storage: Arc<dyn StorageManager>,
49        provider_registry: ProviderRegistry,
50    ) -> Self {
51        Self {
52            configs: Arc::new(RwLock::new(HashMap::new())),
53            provider_registry: Arc::new(RwLock::new(Some(provider_registry))),
54            storage: Some(storage),
55        }
56    }
57
58    /// Set the storage manager
59    pub fn set_storage(&mut self, storage: Arc<dyn StorageManager>) {
60        self.storage = Some(storage);
61    }
62
63    /// Get the storage manager
64    pub fn get_storage(&self) -> Option<&Arc<dyn StorageManager>> {
65        self.storage.as_ref()
66    }
67
68    /// Set the provider registry
69    pub async fn set_provider_registry(&self, registry: ProviderRegistry) -> Result<()> {
70        let mut provider_registry = self.provider_registry.write().await;
71        *provider_registry = Some(registry);
72        Ok(())
73    }
74
75    /// Get the provider registry
76    pub async fn get_provider_registry(&self) -> Result<Option<ProviderRegistry>> {
77        let provider_registry = self.provider_registry.read().await;
78        Ok(provider_registry.clone())
79    }
80
81    /// Register a configuration for a language
82    pub async fn register_config(&self, config: RefactoringConfig) -> Result<()> {
83        let mut configs = self.configs.write().await;
84        configs.insert(config.language.clone(), config);
85        Ok(())
86    }
87
88    /// Get configuration for a language
89    ///
90    /// If storage is configured, loads from storage with hierarchy support.
91    /// Otherwise, returns cached configuration.
92    pub async fn get_config(&self, language: &str) -> Result<Option<RefactoringConfig>> {
93        // If storage is available, load from storage with hierarchy
94        if let Some(storage) = &self.storage {
95            use crate::config::storage_loader::StorageConfigLoader;
96            let loader = StorageConfigLoader::new(storage.clone());
97            
98            // Check if configuration exists in storage
99            if loader.has_language_config(language)? {
100                let config = loader.load_language_config(language)?;
101                // Cache the loaded configuration
102                let mut configs = self.configs.write().await;
103                configs.insert(language.to_string(), config.clone());
104                return Ok(Some(config));
105            }
106        }
107
108        // Fall back to cached configuration
109        let configs = self.configs.read().await;
110        Ok(configs.get(language).cloned())
111    }
112
113    /// Load configuration from a file and register it
114    pub async fn load_and_register(&self, path: &std::path::Path) -> Result<()> {
115        use crate::config::loader::ConfigLoader;
116
117        let config = ConfigLoader::load(path)?;
118        ConfigLoader::validate(&config)?;
119        self.register_config(config).await?;
120
121        Ok(())
122    }
123
124    /// Get all registered languages
125    ///
126    /// If storage is configured, returns all available languages from storage.
127    /// Otherwise, returns cached languages.
128    pub async fn get_languages(&self) -> Result<Vec<String>> {
129        // If storage is available, get languages from storage
130        if let Some(storage) = &self.storage {
131            use crate::config::storage_loader::StorageConfigLoader;
132            let loader = StorageConfigLoader::new(storage.clone());
133            return loader.list_available_languages();
134        }
135
136        // Fall back to cached languages
137        let configs = self.configs.read().await;
138        Ok(configs.keys().cloned().collect())
139    }
140
141    /// Check if a language is configured
142    ///
143    /// If storage is configured, checks storage for configuration.
144    /// Otherwise, checks cached configurations.
145    pub async fn has_language(&self, language: &str) -> Result<bool> {
146        // If storage is available, check storage
147        if let Some(storage) = &self.storage {
148            use crate::config::storage_loader::StorageConfigLoader;
149            let loader = StorageConfigLoader::new(storage.clone());
150            return loader.has_language_config(language);
151        }
152
153        // Fall back to cached configurations
154        let configs = self.configs.read().await;
155        Ok(configs.contains_key(language))
156    }
157
158    /// Clear all configurations
159    pub async fn clear(&self) -> Result<()> {
160        let mut configs = self.configs.write().await;
161        configs.clear();
162        Ok(())
163    }
164}
165
166impl Default for ConfigManager {
167    fn default() -> Self {
168        Self::new()
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[tokio::test]
177    async fn test_register_and_get_config() -> Result<()> {
178        let manager = ConfigManager::new();
179        let config = RefactoringConfig {
180            language: "rust".to_string(),
181            extensions: vec![".rs".to_string()],
182            rules: vec![],
183            transformations: vec![],
184            provider: None,
185        };
186
187        manager.register_config(config.clone()).await?;
188        let retrieved = manager.get_config("rust").await?;
189
190        assert!(retrieved.is_some());
191        assert_eq!(retrieved.unwrap().language, "rust");
192
193        Ok(())
194    }
195
196    #[tokio::test]
197    async fn test_get_languages() -> Result<()> {
198        let manager = ConfigManager::new();
199
200        let rust_config = RefactoringConfig {
201            language: "rust".to_string(),
202            extensions: vec![".rs".to_string()],
203            rules: vec![],
204            transformations: vec![],
205            provider: None,
206        };
207
208        let ts_config = RefactoringConfig {
209            language: "typescript".to_string(),
210            extensions: vec![".ts".to_string()],
211            rules: vec![],
212            transformations: vec![],
213            provider: None,
214        };
215
216        manager.register_config(rust_config).await?;
217        manager.register_config(ts_config).await?;
218
219        let languages = manager.get_languages().await?;
220        assert_eq!(languages.len(), 2);
221        assert!(languages.contains(&"rust".to_string()));
222        assert!(languages.contains(&"typescript".to_string()));
223
224        Ok(())
225    }
226
227    #[tokio::test]
228    async fn test_has_language() -> Result<()> {
229        let manager = ConfigManager::new();
230        let config = RefactoringConfig {
231            language: "rust".to_string(),
232            extensions: vec![".rs".to_string()],
233            rules: vec![],
234            transformations: vec![],
235            provider: None,
236        };
237
238        manager.register_config(config).await?;
239
240        assert!(manager.has_language("rust").await?);
241        assert!(!manager.has_language("python").await?);
242
243        Ok(())
244    }
245
246    #[tokio::test]
247    async fn test_clear() -> Result<()> {
248        let manager = ConfigManager::new();
249        let config = RefactoringConfig {
250            language: "rust".to_string(),
251            extensions: vec![".rs".to_string()],
252            rules: vec![],
253            transformations: vec![],
254            provider: None,
255        };
256
257        manager.register_config(config).await?;
258        assert!(manager.has_language("rust").await?);
259
260        manager.clear().await?;
261        assert!(!manager.has_language("rust").await?);
262
263        Ok(())
264    }
265}