Skip to main content

linear_motion/config/
loader.rs

1use super::models::AppConfig;
2use crate::{Error, Result};
3use directories::ProjectDirs;
4use std::path::{Path, PathBuf};
5use tracing::{debug, info};
6
7pub struct ConfigLoader;
8
9impl ConfigLoader {
10    pub fn get_default_config_path() -> Result<PathBuf> {
11        let project_dirs = ProjectDirs::from("com", "linear-motion", "linear-motion")
12            .ok_or_else(|| Error::Other("Could not determine user directories".to_string()))?;
13
14        Ok(project_dirs.config_dir().join("config.json"))
15    }
16
17    pub fn ensure_config_dir() -> Result<PathBuf> {
18        let project_dirs = ProjectDirs::from("com", "linear-motion", "linear-motion")
19            .ok_or_else(|| Error::Other("Could not determine user directories".to_string()))?;
20
21        let config_dir = project_dirs.config_dir();
22        std::fs::create_dir_all(config_dir)?;
23
24        Ok(config_dir.to_path_buf())
25    }
26
27    pub fn get_default_database_path() -> Result<PathBuf> {
28        let project_dirs = ProjectDirs::from("com", "linear-motion", "linear-motion")
29            .ok_or_else(|| Error::Other("Could not determine user directories".to_string()))?;
30
31        Ok(project_dirs.data_dir().join("linear-motion.db"))
32    }
33
34    pub fn ensure_data_dir() -> Result<PathBuf> {
35        let project_dirs = ProjectDirs::from("com", "linear-motion", "linear-motion")
36            .ok_or_else(|| Error::Other("Could not determine user directories".to_string()))?;
37
38        let data_dir = project_dirs.data_dir();
39        std::fs::create_dir_all(data_dir)?;
40
41        Ok(data_dir.to_path_buf())
42    }
43    pub async fn load_from_file<P: AsRef<Path>>(path: P) -> Result<AppConfig> {
44        let path = path.as_ref();
45        debug!("Loading configuration from: {}", path.display());
46
47        if !path.exists() {
48            return Err(Error::Other(format!(
49                "Configuration file {} not found. Run 'linear-motion init' first.",
50                path.display()
51            )));
52        }
53
54        let content = tokio::fs::read_to_string(path).await?;
55        let config: AppConfig = serde_json::from_str(&content)?;
56
57        // Validate the configuration
58        config.validate()?;
59
60        debug!("configuration loaded successfully from {}", path.display());
61        debug!(
62            "config: {} sync sources, database: {:?}",
63            config.sync_sources.len(),
64            config.database_path()
65        );
66
67        Ok(config)
68    }
69
70    pub fn load_from_file_sync<P: AsRef<Path>>(path: P) -> Result<AppConfig> {
71        let path = path.as_ref();
72        debug!("Loading configuration from: {}", path.display());
73
74        if !path.exists() {
75            return Err(Error::Other(format!(
76                "Configuration file {} not found. Run 'linear-motion init' first.",
77                path.display()
78            )));
79        }
80
81        let content = std::fs::read_to_string(path)?;
82        let config: AppConfig = serde_json::from_str(&content)?;
83
84        // Validate the configuration
85        config.validate()?;
86
87        info!("Configuration loaded successfully from {}", path.display());
88        debug!(
89            "Config: {} sync sources, database: {:?}",
90            config.sync_sources.len(),
91            config.database_path()
92        );
93
94        Ok(config)
95    }
96
97    pub fn validate_json_file<P: AsRef<Path>>(path: P) -> Result<()> {
98        let path = path.as_ref();
99
100        if !path.exists() {
101            return Err(Error::Other(format!(
102                "Configuration file {} not found",
103                path.display()
104            )));
105        }
106
107        let content = std::fs::read_to_string(path)?;
108        let config: AppConfig = serde_json::from_str(&content)
109            .map_err(|e| Error::Other(format!("JSON parsing error: {}", e)))?;
110
111        config.validate()?;
112
113        Ok(())
114    }
115}