git_helpe_rs/
git_config.rs

1use std::{collections::HashMap, fs, path::PathBuf};
2
3use crate::{
4    cli::{CommitOperationArguments, SetClipboardCommands, SetFormat, UseTemplate},
5    file_utils::config_file::get_path_to_config,
6};
7use anyhow::{Error, Result};
8use regex::Regex;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Serialize, Deserialize)]
12pub struct GitConfig {
13    pub data: Data,
14    config_path: PathBuf,
15}
16
17type Variants = HashMap<String, String>;
18
19#[derive(Debug, Serialize, Deserialize)]
20pub struct ClipboardCommands {
21    pub copy: String,
22    pub paste: String,
23}
24#[derive(Debug, Serialize, Deserialize)]
25pub struct Data {
26    pub clipboard_commands: ClipboardCommands,
27    pub commit_template_variants: Variants,
28    pub branch_template_variants: Variants,
29    pub branch_prefix_variants: Variants,
30    pub autocomplete_values: Option<Vec<String>>,
31}
32
33pub struct Templates {
34    pub commit_template_variants: Variants,
35    pub branch_template_variants: Variants,
36}
37
38pub enum BranchOrCommitAction {
39    Commit(CommitOperationArguments),
40    BranchFromTemplate(UseTemplate),
41}
42
43impl Data {
44    fn default() -> Self {
45        Data {
46            clipboard_commands: ClipboardCommands {
47                copy: "pbcopy".to_string(),
48                paste: "pbpaste".to_string(),
49            },
50            commit_template_variants: HashMap::new(),
51            branch_template_variants: HashMap::new(),
52            branch_prefix_variants: HashMap::new(),
53            autocomplete_values: None,
54        }
55    }
56}
57
58impl GitConfig {
59    fn default_config() -> Self {
60        return GitConfig {
61            data: Data::default(),
62            config_path: get_path_to_config(None).to_path_buf(),
63        };
64    }
65
66    pub fn new_config(
67        clipboard_commands: ClipboardCommands,
68        branch_prefix_variants: Variants,
69        branch_format_variants: Variants,
70        commit_format_variants: Variants,
71        config_path: Option<PathBuf>,
72    ) -> Self {
73        return GitConfig {
74            data: Data {
75                clipboard_commands,
76                branch_template_variants: branch_format_variants,
77                commit_template_variants: commit_format_variants,
78                branch_prefix_variants,
79                autocomplete_values: None,
80            },
81            config_path: if let Some(config_path) = config_path {
82                config_path
83            } else {
84                get_path_to_config(None).to_path_buf()
85            },
86        };
87    }
88
89    pub fn from_file(path_to_file: PathBuf) -> Self {
90        if fs::metadata(&path_to_file).is_ok() {
91            let contents = fs::read_to_string(&path_to_file);
92            let contents = contents.unwrap_or(
93                "{\
94                    \"clipboard_commands\": {}, \
95                    \"branch_template_variants\": {}, \
96                    \"commit_template_variants\": {}, \
97                    \"branch_prefix_variants\": {}
98                }"
99                .to_string(),
100            );
101
102            let data = serde_json::from_str(&contents);
103            let data: Data = data.unwrap_or(Data::default());
104
105            GitConfig {
106                data: data,
107                config_path: path_to_file,
108            }
109        } else {
110            Self::default_config()
111        }
112    }
113
114    pub fn validate_against_interpolation_regex<'a>(
115        string_to_interpolate: &'a String,
116        name_of_field_to_check: &'static str,
117    ) -> Result<&'a String> {
118        let interpolation_regex = Regex::new(r"\{.*?\}").unwrap();
119        if interpolation_regex.is_match(string_to_interpolate) {
120            return Ok(string_to_interpolate);
121        };
122        return Err(Error::msg(format!(
123            "There was no interpolation signature: {{}} introduced in {name_of_field_to_check}"
124        )));
125    }
126
127    pub fn set_branch_template_variant(&mut self, arg: SetFormat) -> Result<()> {
128        let result = Self::validate_against_interpolation_regex(&arg.value, "branch_template");
129        match result {
130            Err(e) => panic!("{}", e),
131            Ok(_) => self
132                .data
133                .branch_template_variants
134                .insert(arg.key, arg.value),
135        };
136        self.save_to_file()
137    }
138
139    pub fn set_commit_template_variant(&mut self, arg: SetFormat) -> Result<()> {
140        let result = Self::validate_against_interpolation_regex(&arg.value, "commit_template");
141        match result {
142            Err(e) => panic!("{}", e),
143            Ok(_) => {
144                self.data
145                    .commit_template_variants
146                    .insert(arg.key, arg.value);
147            }
148        };
149        self.save_to_file()
150    }
151
152    pub fn set_branch_prefix_variant(&mut self, key: String, value: String) -> Result<()> {
153        self.data.branch_prefix_variants.insert(key, value);
154        self.save_to_file()
155    }
156
157    pub fn set_clipboard_command(&mut self, args: SetClipboardCommands) -> Result<()> {
158        let new_clipboard_commands = ClipboardCommands {
159            copy: args.copy,
160            paste: args.paste,
161        };
162
163        self.data.clipboard_commands = new_clipboard_commands;
164        self.save_to_file()
165    }
166
167    pub fn delete_branch_prefix_variant(&mut self, key: String) -> Result<()> {
168        let old_val = self.data.branch_prefix_variants.remove(&key);
169        println!(
170            "Removed {} : {} from config ",
171            key,
172            old_val.unwrap_or(String::from("None"))
173        );
174        self.save_to_file()
175    }
176
177    fn save_to_file(&self) -> Result<()> {
178        if let Some(dir) = self.config_path.parent() {
179            if !std::fs::metadata(&dir).is_ok() {
180                std::fs::create_dir_all(dir)?;
181            }
182        };
183
184        let contents = serde_json::to_string(&self.data)?;
185        std::fs::write(&self.config_path, contents)?;
186        return Ok(());
187    }
188
189    pub fn display_config(&self) -> Result<String> {
190        let clipboard_command = &self.data.clipboard_commands;
191        let copy = &clipboard_command.copy;
192        let paste = &clipboard_command.paste;
193        let branch = self.data.branch_template_variants.to_owned();
194        let commit = self.data.commit_template_variants.to_owned();
195        let prefixes = self.data.branch_prefix_variants.to_owned();
196
197        Ok(format!(
198            "
199        clipboard commands: {{
200            \"copy\": {:?}
201            \"paste\": {:?}
202        }}
203        branch formats: {:?} 
204        commit formats: {:?} 
205        branch prefixes: {:?} 
206        ",
207            *copy, *paste, branch, commit, prefixes
208        ))
209    }
210}