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