gitignore_template_generator/parser/
api.rs

1use std::ffi::OsString;
2
3use clap::ValueEnum;
4
5use crate::core::ProgramExit;
6pub use crate::parser::impls::ClapArgsParser;
7
8#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Default)]
9pub enum TimeoutUnit {
10    MILLISECOND,
11    #[default]
12    SECOND,
13}
14
15pub enum Action {
16    List,
17    RobustGenerate,
18    Generate,
19}
20
21/// Struct to gather cli args parsing result.
22///
23/// Used by [`crate::parser::ArgsParser`] implementations to store
24/// parsing result.
25#[derive(Debug, PartialEq, Default)]
26pub struct Args {
27    /// A non-empty list of gitignore template names.
28    ///
29    /// * Represented by the provided positional arguments, and required
30    ///   unless any of `author`, `version` or `help` options are given.
31    /// * This field does not allow commas in any of its field.
32    pub template_names: Vec<String>,
33
34    /// The gitignore template generator service url.
35    ///
36    /// * Optional value represented by the cli option
37    ///   [`crate::constant::cli_options::SERVER_URL`] that takes a string
38    ///   value, and falling back to
39    ///   [`crate::constant::template_manager::BASE_URL`] if not provided
40    ///   in cli args.
41    pub server_url: String,
42
43    /// The gitignore template generator service endpoint uri.
44    ///
45    /// * Optional value represented by the cli option
46    ///   [`crate::constant::cli_options::GENERATOR_URI`] that takes a string
47    ///   value, and falling back to
48    ///   [`crate::constant::template_manager::GENERATOR_URI`] if not provided in cli
49    ///   args.
50    pub generator_uri: String,
51
52    /// The gitignore template lister service endpoint uri.
53    ///
54    /// * Optional value represented by the cli option
55    ///   [`crate::constant::cli_options::LISTER_URI`] that takes a string
56    ///   value, and falling back to
57    ///   [`crate::constant::template_manager::LISTER_URI`] if not provided in cli
58    ///   args.
59    pub lister_uri: String,
60
61    /// The boolean indicator of whether to display help infos or not.
62    ///
63    /// * Optional value represented by the cli option
64    ///   [`crate::constant::cli_options::HELP`], and falling back to `false`
65    ///   if not provided in cli args.
66    /// * Has precedence over version and author options if multiple are given
67    pub show_help: bool,
68
69    /// The boolean indicator of whether to display version infos or not.
70    ///
71    /// * Optional value represented by the cli option
72    ///   [`crate::constant::cli_options::VERSION`], and falling back to
73    ///   `false` if not provided in cli args.
74    /// * Has precedence over author option if multiple are given
75    pub show_version: bool,
76
77    /// The boolean indicator of whether to display author infos or not.
78    ///
79    /// * Optional value represented by the cli option
80    ///   [`crate::constant::cli_options::AUTHOR`], and falling back to
81    ///   `false` if not provided in cli args.
82    pub show_author: bool,
83
84    /// The boolean indicator of whether to display list of available templates
85    /// or not.
86    ///
87    /// * Optional value represented by the cli option
88    ///   [`crate::constant::cli_options::LIST`], and falling back to
89    ///   `false` if not provided in cli args.
90    pub show_list: bool,
91
92    /// The boolean indicator of whether to enable robust template check or not.
93    ///
94    /// Robust template check allow the script to handle template existence
95    /// check without reaching the generator endpoint.
96    ///
97    /// * Optional value represented by the cli option
98    ///   [`crate::constant::cli_options::CHECK`], and falling back to
99    ///   `false` if not provided in cli args.
100    pub check_template_names: bool,
101
102    /// The service call timeout.
103    ///
104    /// * Optional value represented by the cli option
105    ///   [`crate::constant::cli_options::TIMEOUT`], and falling back to
106    ///   [`crate::constant::template_manager::TIMEOUT`] if not provided in
107    ///   cli args.
108    pub timeout: u64,
109
110    /// The timeout unit.
111    ///
112    /// * Optional value represented by the cli option
113    ///   [`crate::constant::cli_options::TIMEOUT_UNIT`], and falling back to
114    ///   [`crate::constant::template_manager::TIMEOUT_UNIT`] if not provided in
115    ///   cli args.
116    pub timeout_unit: TimeoutUnit,
117}
118
119impl Args {
120    pub fn new() -> Self {
121        Self {
122            template_names: Vec::new(),
123            server_url: crate::constant::template_manager::BASE_URL.to_string(),
124            generator_uri: crate::constant::template_manager::GENERATOR_URI.to_string(),
125            lister_uri: crate::constant::template_manager::LISTER_URI.to_string(),
126            show_help: false,
127            show_version: false,
128            show_author: false,
129            show_list: false,
130            check_template_names: false,
131            timeout: crate::constant::template_manager::TIMEOUT_INT,
132            timeout_unit: crate::constant::template_manager::TIMEOUT_UNIT_ENUM,
133        }
134    }
135
136    pub fn to_action(&self) -> Action {
137        if self.show_list {
138            Action::List
139        } else if self.check_template_names {
140            Action::RobustGenerate
141        } else {
142            Action::Generate
143        }
144    }
145
146    /// Sets new value for `template_names` field.
147    ///
148    /// It needs to be called on struct instance and effectively mutates it.
149    ///
150    /// # Arguments
151    ///
152    /// * `template_names` - The new value to be assigned to `template_names`
153    ///   field.
154    ///
155    /// # Returns
156    ///
157    /// The mutated borrowed instance.
158    pub fn with_template_names(mut self, template_names: Vec<String>) -> Self {
159        self.template_names = template_names;
160        self
161    }
162
163    /// Sets new value for `server_url` field.
164    ///
165    /// It needs to be called on struct instance and effectively mutates it.
166    ///
167    /// # Arguments
168    ///
169    /// * `server_url` - The new value to be assigned to `server_url`
170    ///   field.
171    ///
172    /// # Returns
173    ///
174    /// The mutated borrowed instance.
175    pub fn with_server_url(mut self, server_url: &str) -> Self {
176        self.server_url = server_url.to_string();
177        self
178    }
179
180    /// Sets new value for `generator_uri` field.
181    ///
182    /// It needs to be called on struct instance and effectively mutates it.
183    ///
184    /// # Arguments
185    ///
186    /// * `generator_uri` - The new value to be assigned to
187    ///   `generator_uri` field.
188    ///
189    /// # Returns
190    ///
191    /// The mutated borrowed instance.
192    pub fn with_generator_uri(mut self, generator_uri: &str) -> Self {
193        self.generator_uri = generator_uri.to_string();
194        self
195    }
196
197    /// Sets new value for `lister_uri` field.
198    ///
199    /// It needs to be called on struct instance and effectively mutates it.
200    ///
201    /// # Arguments
202    ///
203    /// * `lister_uri` - The new value to be assigned to `lister_uri` field.
204    ///
205    /// # Returns
206    ///
207    /// The mutated borrowed instance.
208    pub fn with_lister_uri(mut self, lister_uri: &str) -> Self {
209        self.lister_uri = lister_uri.to_string();
210        self
211    }
212
213    /// Sets new value for `show_list` field.
214    ///
215    /// It needs to be called on struct instance and effectively mutates it.
216    ///
217    /// # Arguments
218    ///
219    /// * `show_list` - The new value to be assigned to `show_list`
220    ///   field.
221    ///
222    /// # Returns
223    ///
224    /// The mutated borrowed instance.
225    pub fn with_show_list(mut self, show_list: bool) -> Self {
226        self.show_list = show_list;
227        self
228    }
229
230    /// Sets new value for `check_template_names` field.
231    ///
232    /// It needs to be called on struct instance and effectively mutates it.
233    ///
234    /// # Arguments
235    ///
236    /// * `check_template_names` - The new value to be assigned to
237    ///   `check_template_names` field.
238    ///
239    /// # Returns
240    ///
241    /// The mutated borrowed instance.
242    pub fn with_check_template_names(mut self, check_template_names: bool) -> Self {
243        self.check_template_names = check_template_names;
244        self
245    }
246
247    /// Sets new value for `timeout` field.
248    ///
249    /// It needs to be called on struct instance and effectively mutates it.
250    ///
251    /// # Arguments
252    ///
253    /// * `timeout` - The new value to be assigned to `timeout` field.
254    ///
255    /// # Returns
256    ///
257    /// The mutated borrowed instance.
258    pub fn with_timeout(mut self, timeout: u64) -> Self {
259        self.timeout = timeout;
260        self
261    }
262
263    /// Sets new value for `timeout_unit` field.
264    ///
265    /// It needs to be called on struct instance and effectively mutates it.
266    ///
267    /// # Arguments
268    ///
269    /// * `timeout_unit` - The new value to be assigned to `timeout_unit` field.
270    ///
271    /// # Returns
272    ///
273    /// The mutated borrowed instance.
274    pub fn with_timeout_unit(mut self, timeout_unit: TimeoutUnit) -> Self {
275        self.timeout_unit = timeout_unit;
276        self
277    }
278}
279
280/// Cli args parser trait to parse CLI args and return them in an [`Args`].
281///
282/// The produced Args instance needs to comply with constraints of each
283/// one of its fields (see fields doc in [`Args`] for more infos).
284pub trait ArgsParser {
285    /// Parses given cli args and return them as an [`Args`] instance.
286    ///
287    /// * First CLI args should be the binary name
288    /// * Rely on [`ArgsParser::try_parse`] method but additionally wrap
289    ///   error handling logic
290    ///
291    /// # Arguments
292    ///
293    /// * `args` - The CLI args to be parsed. Typically retrieved from
294    ///   [`std::env::args_os`].
295    ///
296    /// # Returns
297    ///
298    /// An owned instance of [`Args`] containing parsing result of given args.
299    fn parse(&self, args: impl IntoIterator<Item = OsString>) -> Args;
300
301    /// Parses given cli args and return them as an [`Args`] instance if no
302    /// error or early exit occurred.
303    ///
304    /// * First CLI args should be the binary name
305    /// * Version, author and help options are considered as early program
306    ///   exit
307    /// * Returned Args complies with expected constraints (see fields doc
308    ///   in [`Args`] for more infos)
309    ///
310    /// # Arguments
311    ///
312    /// * `args` - The CLI args to be parsed. Typically retrieved from
313    ///   [`std::env::args_os`].
314    ///
315    /// # Returns
316    ///
317    /// A result containing an owned instance of [`Args`] if successful parsing,
318    /// or a [`ProgramExit`] if any error or early exit occurred (e.g. version/
319    /// author/help infos printing, invalid cli args...)
320    fn try_parse(&self, args: impl IntoIterator<Item = OsString>) -> Result<Args, ProgramExit>;
321}