1use toml;
5
6use failure::{format_err, Error};
7use log::info;
8use serde_derive::{Deserialize, Serialize};
9use std::{fs::File, io::prelude::*, path::PathBuf};
10
11#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct Config {
14 pub categories: Vec<String>,
16
17 pub category_delimiters: Vec<String>,
19
20 pub colored_output: bool,
22
23 pub default_template: Option<String>,
26
27 pub enable_debug: bool,
29
30 pub excluded_commit_tags: Vec<String>,
32
33 pub enable_footers: bool,
35
36 pub show_commit_hash: bool,
38
39 pub show_prefix: bool,
41
42 pub sort_by: String,
44
45 pub template_prefix: String,
48}
49
50impl Config {
51 pub fn new() -> Self {
60 Config {
61 categories: Self::get_default_categories(),
62 category_delimiters: vec!["[".to_owned(), "]".to_owned()],
63 colored_output: true,
64 default_template: None,
65 enable_debug: true,
66 excluded_commit_tags: vec![],
67 enable_footers: false,
68 show_commit_hash: false,
69 show_prefix: false,
70 sort_by: "date".to_owned(),
71 template_prefix: "JIRA-1234".to_owned(),
72 }
73 }
74
75 fn get_default_categories() -> Vec<String> {
76 vec![
77 "Added".to_owned(),
78 "Changed".to_owned(),
79 "Fixed".to_owned(),
80 "Improved".to_owned(),
81 "Removed".to_owned(),
82 ]
83 }
84
85 pub fn save_default_config(&self, path: &str) -> Result<String, Error> {
99 let toml_string = toml::to_string(&self).unwrap();
101 info!("{:?}", toml_string);
102
103 let path_buf = self.get_path_with_filename(path);
105 let path_string = path_buf
106 .to_str()
107 .ok_or_else(|| format_err!("Cannot convert path to string"))?;
108
109 let mut file = File::create(&path_buf)?;
111 file.write_all(toml_string.as_bytes())?;
112 Ok(path_string.to_owned())
113 }
114
115 pub fn load(&mut self, path: &str) -> Result<(), Error> {
127 let path_buf = self.get_path_with_filename(path);
128 let mut file = File::open(&path_buf)?;
129 let mut toml_string = String::new();
130 file.read_to_string(&mut toml_string)?;
131
132 *self = toml::from_str(&toml_string)?;
134
135 if self.categories.is_empty() {
139 self.categories = Self::get_default_categories();
140 }
141 Ok(())
142 }
143
144 pub fn is_default_config(&self) -> bool {
153 *self == Config::new()
154 }
155
156 fn get_path_with_filename(&self, path: &str) -> PathBuf {
157 let mut path_buf = PathBuf::from(path);
158 path_buf.push(".gitjournal.toml");
159 path_buf
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn config_save_and_load_ok() {
169 let mut config = Config::new();
170 assert!(config.save_default_config(".").is_ok());
171 assert!(config.load(".").is_ok());
172 assert_eq!(config.is_default_config(), true);
173 }
174
175 #[test]
176 fn config_save_err() {
177 let config = Config::new();
178 let res = config.save_default_config("/dev/null");
179 assert!(res.is_err());
180 if let Err(e) = res {
181 println!("{}", e);
182 }
183 }
184
185 fn load_and_print_failure(path: &str) {
186 let mut config = Config::new();
187 let res = config.load(path);
188 assert!(res.is_err());
189 if let Err(e) = res {
190 println!("{}", e);
191 }
192 }
193
194 #[test]
195 fn config_load_err() {
196 load_and_print_failure("/dev/null");
197 }
198
199 #[test]
200 fn config_load_invalid_1() {
201 load_and_print_failure("tests/invalid_1.toml");
202 }
203
204 #[test]
205 fn config_load_invalid_2() {
206 load_and_print_failure("tests/invalid_2.toml");
207 }
208
209 #[test]
210 fn config_load_invalid_3() {
211 load_and_print_failure("tests/invalid_3.toml");
212 }
213}