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}