whiteout/config/
project.rs

1use anyhow::{Context, Result};
2use std::fs;
3use std::path::{Path, PathBuf};
4
5use super::ConfigData;
6
7#[derive(Debug, Clone)]
8pub struct Config {
9    pub data: ConfigData,
10    pub path: PathBuf,
11}
12
13impl Config {
14    pub fn load_or_default(project_root: impl AsRef<Path>) -> Result<Self> {
15        let config_path = project_root.as_ref().join(".whiteout").join("config.toml");
16        
17        let data = if config_path.exists() {
18            let content = fs::read_to_string(&config_path)
19                .context("Failed to read config file")?;
20            toml::from_str(&content).context("Failed to parse config file")?
21        } else {
22            ConfigData::default()
23        };
24        
25        Ok(Self {
26            data,
27            path: config_path,
28        })
29    }
30
31    pub fn init(project_root: impl AsRef<Path>) -> Result<()> {
32        let whiteout_dir = project_root.as_ref().join(".whiteout");
33        fs::create_dir_all(&whiteout_dir).context("Failed to create .whiteout directory")?;
34        
35        let config_path = whiteout_dir.join("config.toml");
36        if !config_path.exists() {
37            let initial_config = ConfigData::default();
38            let content = toml::to_string_pretty(&initial_config)
39                .context("Failed to serialize initial config")?;
40            fs::write(&config_path, content).context("Failed to write initial config")?;
41        }
42        
43        Self::setup_git_config(project_root.as_ref())?;
44        
45        Ok(())
46    }
47
48    pub fn save(&self) -> Result<()> {
49        let content = toml::to_string_pretty(&self.data)
50            .context("Failed to serialize config")?;
51        
52        fs::create_dir_all(self.path.parent().unwrap())
53            .context("Failed to create config directory")?;
54        
55        fs::write(&self.path, content)
56            .context("Failed to write config file")?;
57        
58        Ok(())
59    }
60
61    pub fn set(&mut self, key: &str, value: &str) -> Result<()> {
62        match key {
63            "encryption.enabled" => {
64                self.data.encryption.enabled = value.parse()
65                    .context("Invalid boolean value")?;
66            }
67            "git.auto_sync" => {
68                self.data.git.auto_sync = value.parse()
69                    .context("Invalid boolean value")?;
70            }
71            "git.pre_commit_check" => {
72                self.data.git.pre_commit_check = value.parse()
73                    .context("Invalid boolean value")?;
74            }
75            _ => anyhow::bail!("Unknown config key: {}", key),
76        }
77        
78        self.save()?;
79        Ok(())
80    }
81
82    pub fn get(&self, key: &str) -> Result<String> {
83        let value = match key {
84            "encryption.enabled" => self.data.encryption.enabled.to_string(),
85            "git.auto_sync" => self.data.git.auto_sync.to_string(),
86            "git.pre_commit_check" => self.data.git.pre_commit_check.to_string(),
87            _ => anyhow::bail!("Unknown config key: {}", key),
88        };
89        
90        Ok(value)
91    }
92
93    fn setup_git_config(project_root: &Path) -> Result<()> {
94        let gitattributes_path = project_root.join(".gitattributes");
95        let mut content = if gitattributes_path.exists() {
96            fs::read_to_string(&gitattributes_path)?
97        } else {
98            String::new()
99        };
100        
101        if !content.contains("filter=whiteout") {
102            if !content.is_empty() && !content.ends_with('\n') {
103                content.push('\n');
104            }
105            content.push_str("* filter=whiteout\n");
106            fs::write(&gitattributes_path, content)?;
107        }
108        
109        Ok(())
110    }
111}
112
113impl Default for Config {
114    fn default() -> Self {
115        Self {
116            data: ConfigData::default(),
117            path: PathBuf::from(".whiteout/config.toml"),
118        }
119    }
120}