gitignore_template_generator/parser/
impls.rs1use std::{ffi::OsString, process::exit};
2
3use clap::{ArgMatches, Command};
4
5use super::{Args, ArgsParser, TimeoutUnit, command::build_clap_args};
6use crate::{
7 constant,
8 core::{ExitKind, ProgramExit},
9};
10
11pub struct ClapArgsParser {
14 cli_parser: Command,
15}
16
17#[allow(clippy::new_without_default)]
18impl ClapArgsParser {
19 pub fn new() -> Self {
20 Self {
21 cli_parser: Command::new(env!("CARGO_PKG_NAME"))
22 .version(env!("CARGO_PKG_VERSION"))
23 .author(env!("CARGO_PKG_AUTHORS"))
24 .about(constant::parser_infos::ABOUT)
25 .help_template(include_str!("../../assets/help_template.txt"))
26 .disable_help_flag(true)
27 .disable_version_flag(true)
28 .args(build_clap_args()),
29 }
30 }
31
32 fn parse_global_options(&self, args: &Args) -> Option<ProgramExit> {
33 if args.show_help {
34 let rendered_help = self.cli_parser.clone().render_help();
35 Some(ProgramExit {
36 message: rendered_help.to_string().trim_end().to_string(),
37 exit_status: constant::exit_status::SUCCESS,
38 styled_message: Some(
39 rendered_help.ansi().to_string().trim_end().to_string(),
40 ),
41 kind: ExitKind::HelpInfos,
42 })
43 } else if args.show_version {
44 let message = match self.cli_parser.get_version() {
45 Some(version) => {
46 format!("{} {version}", env!("CARGO_PKG_NAME"))
47 }
48 None => constant::error_messages::VERSION_INFOS_NOT_AVAILABLE
49 .to_string(),
50 };
51
52 Some(ProgramExit {
53 message,
54 exit_status: constant::exit_status::SUCCESS,
55 styled_message: None,
56 kind: ExitKind::VersionInfos,
57 })
58 } else if args.show_author {
59 let message = String::from(match self.cli_parser.get_author() {
60 Some(author) => author,
61 None => constant::error_messages::AUTHOR_INFOS_NOT_AVAILABLE,
62 });
63
64 Some(ProgramExit {
65 message,
66 exit_status: constant::exit_status::SUCCESS,
67 styled_message: None,
68 kind: ExitKind::AuthorInfos,
69 })
70 } else {
71 None
72 }
73 }
74
75 fn map_arg_matches_to_struct(arg_matches: &ArgMatches) -> Args {
76 Args {
77 template_names: arg_matches
78 .get_many::<String>("TEMPLATE_NAMES")
79 .map(|vals| vals.cloned().collect())
80 .unwrap_or_default(),
81 server_url: arg_matches
82 .get_one::<String>("SERVER_URL")
83 .unwrap()
84 .to_string(),
85 generator_uri: arg_matches
86 .get_one::<String>("GENERATOR_URI")
87 .unwrap()
88 .to_string(),
89 lister_uri: arg_matches
90 .get_one::<String>("LISTER_URI")
91 .unwrap()
92 .to_string(),
93 timeout: match arg_matches.get_one::<u64>("TIMEOUT") {
94 Some(timeout) => *timeout,
95 None => constant::template_manager::TIMEOUT_INT,
96 },
97 timeout_unit: arg_matches
98 .get_one::<TimeoutUnit>("TIMEOUT_UNIT")
99 .unwrap()
100 .to_owned(),
101 check_template_names: arg_matches.get_flag("CHECK"),
102 show_help: arg_matches.get_flag("HELP"),
103 show_version: arg_matches.get_flag("VERSION"),
104 show_author: arg_matches.get_flag("AUTHOR"),
105 show_list: arg_matches.get_flag("LIST"),
106 }
107 }
108
109 fn print_error_message(error: &ProgramExit, message: &str) {
110 match error.kind {
111 ExitKind::VersionInfos
112 | ExitKind::HelpInfos
113 | ExitKind::AuthorInfos => println!("{message}"),
114 ExitKind::Error => eprintln!("{message}"),
115 }
116 }
117}
118
119impl ArgsParser for ClapArgsParser {
120 fn parse(&self, args: impl IntoIterator<Item = OsString>) -> Args {
132 match self.try_parse(args) {
133 Ok(parsed_args) => parsed_args,
134 Err(error) => {
135 if let Some(value) = &error.styled_message {
136 Self::print_error_message(&error, value);
137 } else {
138 Self::print_error_message(&error, &error.message);
139 }
140
141 exit(error.exit_status);
142 }
143 }
144 }
145
146 fn try_parse(
147 &self,
148 args: impl IntoIterator<Item = OsString>,
149 ) -> Result<Args, ProgramExit> {
150 match self.cli_parser.clone().try_get_matches_from(args) {
151 Ok(parsing_result) => {
152 let parsed_args =
153 Self::map_arg_matches_to_struct(&parsing_result);
154 match self.parse_global_options(&parsed_args) {
155 Some(error) => Err(error),
156 None => Ok(parsed_args),
157 }
158 }
159 Err(error) => Err(ProgramExit {
160 message: format!(
161 "{}\nFor more information, try '--help'.",
162 error.render()
163 ),
164 exit_status: error.exit_code(),
165 styled_message: Some(format!(
166 "{}\nFor more information, try '\u{1b}[1m--help\u{1b}[0m'.",
167 error.render().ansi()
168 )),
169 kind: ExitKind::Error,
170 }),
171 }
172 }
173}