ferrisup/core/
config.rs

1// Configuration management for FerrisUp
2use serde::{Deserialize, Serialize};
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use super::error::{Error, Result};
7
8/// Configuration for FerrisUp
9#[derive(Debug, Serialize, Deserialize)]
10pub struct Config {
11    /// Path to templates directory
12    pub templates_dir: PathBuf,
13    /// User preferences
14    pub preferences: Preferences,
15}
16
17/// User preferences for FerrisUp
18#[derive(Debug, Serialize, Deserialize)]
19pub struct Preferences {
20    /// Whether to initialize git repositories for new projects
21    #[serde(default = "default_git")]
22    pub git: bool,
23    /// Whether to build projects after creation
24    #[serde(default = "default_build")]
25    pub build: bool,
26    /// Whether to use interactive mode
27    #[serde(default = "default_interactive")]
28    pub interactive: bool,
29}
30
31fn default_git() -> bool {
32    true
33}
34
35fn default_build() -> bool {
36    false
37}
38
39fn default_interactive() -> bool {
40    true
41}
42
43impl Default for Config {
44    fn default() -> Self {
45        let mut templates_dir = dirs::home_dir()
46            .expect("Failed to get home directory")
47            .join(".ferrisup")
48            .join("templates");
49
50        // If running from a development environment, use the local templates directory
51        if Path::new("templates").exists() {
52            templates_dir = PathBuf::from("templates");
53        }
54
55        Self {
56            templates_dir,
57            preferences: Preferences::default(),
58        }
59    }
60}
61
62impl Default for Preferences {
63    fn default() -> Self {
64        Self {
65            git: default_git(),
66            build: default_build(),
67            interactive: default_interactive(),
68        }
69    }
70}
71
72impl Config {
73    /// Load configuration from a file
74    pub fn load(path: &Path) -> Result<Self> {
75        let content = fs::read_to_string(path).map_err(|e| Error::Config(format!("Failed to read config file: {}", e)))?;
76        let config: Config = serde_json::from_str(&content).map_err(|e| Error::Config(format!("Invalid config format: {}", e)))?;
77        Ok(config)
78    }
79
80    /// Save configuration to a file
81    pub fn save(&self, path: &Path) -> Result<()> {
82        let content = serde_json::to_string_pretty(self).map_err(|e| Error::Config(format!("Failed to serialize config: {}", e)))?;
83        fs::write(path, content).map_err(|e| Error::Config(format!("Failed to write config file: {}", e)))?;
84        Ok(())
85    }
86
87    /// Get the default configuration path
88    pub fn default_path() -> PathBuf {
89        dirs::config_dir()
90            .expect("Failed to get config directory")
91            .join("ferrisup")
92            .join("config.json")
93    }
94    
95    /// Get the config path to use for operations
96    pub fn get_config_path() -> PathBuf {
97        // First check if there's a local config file
98        let local_config = Path::new("ferrisup.json");
99        if local_config.exists() {
100            return local_config.to_path_buf();
101        }
102        
103        // Then check the default config path
104        Self::default_path()
105    }
106    
107    /// Get the default configuration
108    pub fn get_default_config() -> Self {
109        Self::default()
110    }
111}