pars_core/config/
cli.rs

1use std::error::Error;
2use std::fs;
3use std::path::Path;
4#[allow(dead_code)]
5use std::{env, path};
6
7use serde::{Deserialize, Serialize};
8
9use crate::constants::default_constants::{EDITOR, GIT_EXECUTABLE, PGP_EXECUTABLE};
10
11#[derive(Debug, Serialize, Deserialize, Default, Eq, PartialEq)]
12#[serde(default)]
13pub struct ParsConfig {
14    #[serde(default = "PrintConfig::default")]
15    pub print_config: PrintConfig,
16    #[serde(default = "PathConfig::default")]
17    pub path_config: PathConfig,
18    #[serde(default = "ExecutableConfig::default")]
19    pub executable_config: ExecutableConfig,
20}
21
22#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
23pub struct PrintConfig {
24    pub dir_color: String,
25    pub file_color: String,
26    pub symbol_color: String,
27    pub tree_color: String,
28    pub grep_pass_color: String,
29    pub grep_match_color: String,
30}
31
32#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
33pub struct PathConfig {
34    pub default_repo: String,
35    pub repos: Vec<String>,
36}
37
38#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
39pub struct ExecutableConfig {
40    pub pgp_executable: String,
41    pub editor_executable: String,
42    pub git_executable: String,
43}
44
45impl Default for PrintConfig {
46    fn default() -> Self {
47        Self {
48            dir_color: "cyan".into(),
49            file_color: String::new(),
50            symbol_color: "bright green".into(),
51            tree_color: String::new(),
52            grep_pass_color: "bright green".into(),
53            grep_match_color: "bright red".into(),
54        }
55    }
56}
57
58impl AsRef<PrintConfig> for PrintConfig {
59    fn as_ref(&self) -> &PrintConfig {
60        self
61    }
62}
63
64impl PrintConfig {
65    pub fn none() -> Self {
66        Self {
67            dir_color: String::new(),
68            file_color: String::new(),
69            symbol_color: String::new(),
70            tree_color: String::new(),
71            grep_pass_color: String::new(),
72            grep_match_color: String::new(),
73        }
74    }
75}
76
77impl Default for ExecutableConfig {
78    fn default() -> Self {
79        Self {
80            pgp_executable: PGP_EXECUTABLE.into(),
81            editor_executable: EDITOR.into(),
82            git_executable: GIT_EXECUTABLE.into(),
83        }
84    }
85}
86
87impl Default for PathConfig {
88    fn default() -> Self {
89        let default_path = match dirs::home_dir() {
90            Some(path) => {
91                format!("{}{}.password-store", path.display(), path::MAIN_SEPARATOR)
92            }
93            None => {
94                format!(
95                    "{}{}.password-store",
96                    env::var(
97                        #[cfg(unix)]
98                        {
99                            "HOME"
100                        },
101                        #[cfg(windows)]
102                        {
103                            "USERPROFILE"
104                        }
105                    )
106                    .unwrap_or("~".into()),
107                    path::MAIN_SEPARATOR
108                )
109            }
110        };
111        PathConfig { default_repo: default_path.clone(), repos: vec![default_path] }
112    }
113}
114
115pub fn load_config<P: AsRef<Path>>(path: P) -> Result<ParsConfig, Box<dyn Error>> {
116    let content = fs::read_to_string(path)?;
117    let config: ParsConfig = toml::from_str(&content)?;
118    Ok(config)
119}
120
121pub fn save_config<P: AsRef<Path>>(config: &ParsConfig, path: P) -> Result<(), Box<dyn Error>> {
122    let toml_str = toml::to_string_pretty(config)?;
123    fs::write(path, toml_str)?;
124    Ok(())
125}
126
127#[cfg(test)]
128mod tests {
129    use pretty_assertions::assert_eq;
130
131    use super::*;
132    use crate::util::test_util::gen_unique_temp_dir;
133
134    #[test]
135    fn load_save_test() {
136        let (_temp_dir, root) = gen_unique_temp_dir();
137        let config_path = root.join("config.toml");
138
139        let test_config = ParsConfig::default();
140        save_config(&test_config, &config_path).unwrap();
141        let loaded_config = load_config(&config_path).unwrap();
142        assert_eq!(test_config, loaded_config);
143    }
144
145    #[test]
146    fn generate_default_config_test() {
147        let default_config = ParsConfig::default();
148        let root = env!("CARGO_MANIFEST_DIR");
149        let save_path = Path::new(root).parent().unwrap().join("config").join("cli");
150        if !save_path.exists() {
151            fs::create_dir_all(&save_path).unwrap();
152        }
153        save_config(&default_config, save_path.join("pars_config.toml"))
154            .expect("Failed to save default config");
155    }
156
157    #[test]
158    fn invalid_path_test() {
159        let test_config = ParsConfig::default();
160        let result = if cfg!(unix) {
161            save_config(&test_config, "/home/user/\0file.txt")
162        } else if cfg!(windows) {
163            save_config(&test_config, "C:\\<illegal>\\invalid.toml")
164        } else {
165            Err(Box::from("Unsupported OS"))
166        };
167
168        assert!(result.is_err());
169    }
170}