jirust_cli/runners/cfg_cmd_runner.rs
1use crate::config::config_file::{AuthData, ConfigFile};
2
3use rpassword::read_password;
4use std::{fs, io::BufRead, path::Path};
5
6/// ConfigCmdRunner is a struct that holds the configuration file path
7/// and provides methods to initialize, set, and show the configuration file.
8pub struct ConfigCmdRunner {
9 cfg_file: String,
10}
11
12/// Implementation of ConfigCmdRunner
13///
14/// # Methods
15///
16/// * `new(cfg_file: String) -> ConfigCmdRunner` - creates a new instance of ConfigCmdRunner
17/// * `init_file() -> Result<(), std::io::Error>` - initializes the configuration file
18/// * `set_cfg_auth(cfg: ConfigFile) -> Result<ConfigFile, std::io::Error>` - sets the authentication data in the configuration file
19/// * `set_cfg_jira(cfg: ConfigFile) -> Result<ConfigFile, std::io::Error>` - sets the Jira URL in the configuration file
20/// * `setup_cfg(cfg: ConfigFile) -> Result<(), std::io::Error>` - sets up the configuration file
21/// * `show_cfg(cfg: ConfigFile)` - shows the configuration file
22impl ConfigCmdRunner {
23 /// Creates a new instance of ConfigCmdRunner
24 ///
25 /// # Arguments
26 ///
27 /// * `cfg_file` - a String that holds the path to the configuration file
28 ///
29 /// # Returns
30 ///
31 /// * `ConfigCmdRunner` - a new instance of ConfigCmdRunner
32 ///
33 /// # Examples
34 ///
35 /// ```
36 /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
37 ///
38 /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
39 /// ```
40 pub fn new(cfg_file: String) -> ConfigCmdRunner {
41 ConfigCmdRunner { cfg_file }
42 }
43
44 /// Ensure the CLI can create or update the configuration file before asking for input.
45 fn ensure_cfg_writable(&self) -> Result<(), std::io::Error> {
46 let path = Path::new(&self.cfg_file);
47 if let Some(parent) = path.parent() {
48 if !parent.as_os_str().is_empty() && !parent.exists() {
49 fs::create_dir_all(parent)?;
50 }
51 }
52
53 fs::OpenOptions::new()
54 .write(true)
55 .create(true)
56 .truncate(false)
57 .open(path)
58 .map(|_| ())
59 }
60
61 /// Initializes the configuration file
62 ///
63 /// # Returns
64 ///
65 /// * `Result<(), std::io::Error>` - a Result that returns an empty tuple or an error
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
71 ///
72 /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
73 /// cfg_runner.init_file();
74 /// ```
75 pub fn init_file(&self) -> Result<(), std::io::Error> {
76 let path = Path::new(&self.cfg_file);
77 fs::create_dir_all(path.parent().unwrap())?;
78 fs::File::create(path)?;
79 Ok(())
80 }
81
82 /// Sets the authentication data in the configuration file
83 ///
84 /// # Arguments
85 ///
86 /// * `cfg` - a ConfigFile that holds the configuration data
87 ///
88 /// # Returns
89 ///
90 /// * `Result<ConfigFile, std::io::Error>` - a Result that returns the updated ConfigFile or an error
91 ///
92 /// # Examples
93 ///
94 /// ```no_run
95 /// use jirust_cli::config::config_file::ConfigFile;
96 /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
97 ///
98 /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
99 /// let cfg = ConfigFile::default();
100 ///
101 /// cfg_runner.set_cfg_auth(cfg);
102 /// ```
103 pub fn set_cfg_auth(&self, cfg: ConfigFile) -> Result<ConfigFile, std::io::Error> {
104 self.ensure_cfg_writable()?;
105 println!("Your username: ");
106 let stdin = std::io::stdin();
107 let mut reader = stdin.lock();
108 self.read_auth_from_sources(cfg, &mut reader, read_password)
109 }
110
111 fn read_auth_from_sources<R, P>(
112 &self,
113 mut cfg: ConfigFile,
114 reader: &mut R,
115 mut password_reader: P,
116 ) -> Result<ConfigFile, std::io::Error>
117 where
118 R: BufRead,
119 P: FnMut() -> Result<String, std::io::Error>,
120 {
121 let mut user = String::new();
122 reader.read_line(&mut user)?;
123 println!("Your apikey: ");
124 let apikey = password_reader()?;
125 let config_data = AuthData::new(user, apikey);
126 cfg.set_auth_key(config_data.to_base64());
127 cfg.write_to_file(self.cfg_file.as_str())?;
128 Ok(cfg)
129 }
130
131 /// Sets the Jira URL in the configuration file
132 ///
133 /// # Arguments
134 ///
135 /// * `cfg` - a ConfigFile that holds the configuration data
136 ///
137 /// # Returns
138 ///
139 /// * `Result<ConfigFile, std::io::Error>` - a Result that returns the updated ConfigFile or an error
140 ///
141 /// # Examples
142 ///
143 /// ```no_run
144 /// use jirust_cli::config::config_file::ConfigFile;
145 /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
146 ///
147 /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
148 /// let cfg = ConfigFile::default();
149 /// cfg_runner.set_cfg_jira(cfg);
150 /// ```
151 pub fn set_cfg_jira(&self, cfg: ConfigFile) -> Result<ConfigFile, std::io::Error> {
152 self.ensure_cfg_writable()?;
153 println!("Your Jira instance URL: ");
154 let stdin = std::io::stdin();
155 let mut reader = stdin.lock();
156 self.read_jira_from_reader(cfg, &mut reader)
157 }
158
159 fn read_jira_from_reader<R>(
160 &self,
161 mut cfg: ConfigFile,
162 reader: &mut R,
163 ) -> Result<ConfigFile, std::io::Error>
164 where
165 R: BufRead,
166 {
167 let mut read_data = String::new();
168 reader.read_line(&mut read_data)?;
169 cfg.set_jira_url(read_data.clone());
170 read_data.clear();
171 println!("Default Jira issue resolution JSON Value: ");
172 reader.read_line(&mut read_data)?;
173 cfg.set_standard_resolution(read_data.clone());
174 read_data.clear();
175 println!("Default Jira issue resolution comment JSON: ");
176 reader.read_line(&mut read_data)?;
177 cfg.set_standard_resolution_comment(read_data);
178 cfg.write_to_file(self.cfg_file.as_str())?;
179 Ok(cfg)
180 }
181
182 /// Sets up the configuration file
183 ///
184 /// # Arguments
185 ///
186 /// * `cfg` - a ConfigFile that holds the configuration data
187 ///
188 /// # Returns
189 ///
190 /// * `Result<(), std::io::Error>` - a Result that returns an empty tuple or an error
191 ///
192 /// # Examples
193 ///
194 /// ```no_run
195 /// use jirust_cli::config::config_file::ConfigFile;
196 /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
197 ///
198 /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
199 /// let cfg = ConfigFile::default();
200 /// cfg_runner.setup_cfg(cfg);
201 /// ```
202 pub fn setup_cfg(&self, mut cfg: ConfigFile) -> Result<(), std::io::Error> {
203 self.init_file()?;
204 cfg = self.set_cfg_jira(cfg)?;
205 self.set_cfg_auth(cfg)?;
206 Ok(())
207 }
208
209 /// Shows the configuration file data
210 ///
211 /// # Arguments
212 ///
213 /// * `cfg` - a ConfigFile that holds the configuration data
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// use jirust_cli::config::config_file::ConfigFile;
219 /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
220 ///
221 /// let cfg = ConfigFile::default();
222 ///
223 /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
224 /// cfg_runner.show_cfg(cfg);
225 /// ```
226 pub fn show_cfg(&self, cfg: ConfigFile) {
227 println!("Auth token: {}", cfg.get_auth_key());
228 println!("Jira URL: {}", cfg.get_jira_url());
229 println!(
230 "Jira default resolution: {:?}",
231 cfg.get_standard_resolution()
232 );
233 println!(
234 "Jira default resolution comment: {:?}",
235 cfg.get_standard_resolution_comment()
236 );
237 }
238
239 #[cfg(test)]
240 pub(crate) fn set_cfg_auth_with_reader<R, P>(
241 &self,
242 cfg: ConfigFile,
243 reader: &mut R,
244 password_reader: P,
245 ) -> Result<ConfigFile, std::io::Error>
246 where
247 R: BufRead,
248 P: FnMut() -> Result<String, std::io::Error>,
249 {
250 self.ensure_cfg_writable()?;
251 self.read_auth_from_sources(cfg, reader, password_reader)
252 }
253
254 #[cfg(test)]
255 pub(crate) fn set_cfg_jira_with_reader<R>(
256 &self,
257 cfg: ConfigFile,
258 reader: &mut R,
259 ) -> Result<ConfigFile, std::io::Error>
260 where
261 R: BufRead,
262 {
263 self.ensure_cfg_writable()?;
264 self.read_jira_from_reader(cfg, reader)
265 }
266}