1use std::num::NonZeroUsize;
2use std::path::PathBuf;
3
4use clap::{Arg, ArgAction, ArgMatches, Command, value_parser};
5
6#[cfg(test)]
7mod tests;
8
9#[derive(Debug, Clone)]
10pub struct TidyArgParser {
11 pub root_path: PathBuf,
12 pub cargo: PathBuf,
13 pub output_directory: PathBuf,
14 pub concurrency: NonZeroUsize,
15 pub npm: PathBuf,
16 pub verbose: bool,
17 pub bless: bool,
18 pub ci: Option<bool>,
19 pub extra_checks: Option<Vec<String>>,
20 pub pos_args: Vec<String>,
21}
22
23impl TidyArgParser {
24 fn command() -> Command {
25 Command::new("rust-tidy")
26 .arg(
27 Arg::new("root_path")
28 .help("path of the root directory")
29 .long("root-path")
30 .required(true)
31 .value_parser(value_parser!(PathBuf)),
32 )
33 .arg(
34 Arg::new("cargo")
35 .help("path of cargo")
36 .long("cargo-path")
37 .required(true)
38 .value_parser(value_parser!(PathBuf)),
39 )
40 .arg(
41 Arg::new("output_directory")
42 .help("path of output directory")
43 .long("output-dir")
44 .required(true)
45 .value_parser(value_parser!(PathBuf)),
46 )
47 .arg(
48 Arg::new("concurrency")
49 .help("number of threads working concurrently")
50 .long("concurrency")
51 .required(true)
52 .value_parser(value_parser!(NonZeroUsize)),
53 )
54 .arg(
55 Arg::new("npm")
56 .help("path of npm")
57 .long("npm-path")
58 .required(true)
59 .value_parser(value_parser!(PathBuf)),
60 )
61 .arg(Arg::new("verbose").help("verbose").long("verbose").action(ArgAction::SetTrue))
62 .arg(Arg::new("bless").help("target files are modified").long("bless").action(ArgAction::SetTrue))
63 .arg(Arg::new("ci").help("ci flag").long("ci").default_missing_value("true").num_args(0..=1).value_parser(value_parser!(bool)))
64 .arg(
65 Arg::new("extra_checks")
66 .help("extra checks")
67 .long("extra-checks")
68 .value_delimiter(',')
69 .action(ArgAction::Append),
70 )
71 .arg(Arg::new("pos_args").help("for extra checks. you can specify configs and target files for external check tools").action(ArgAction::Append).last(true))
72 }
73
74 fn build(matches: ArgMatches) -> Self {
75 let mut tidy_flags = Self {
76 root_path: matches.get_one::<PathBuf>("root_path").unwrap().clone(),
77 cargo: matches.get_one::<PathBuf>("cargo").unwrap().clone(),
78 output_directory: matches.get_one::<PathBuf>("output_directory").unwrap().clone(),
79 concurrency: *matches.get_one::<NonZeroUsize>("concurrency").unwrap(),
80 npm: matches.get_one::<PathBuf>("npm").unwrap().clone(),
81 verbose: *matches.get_one::<bool>("verbose").unwrap(),
82 bless: *matches.get_one::<bool>("bless").unwrap(),
83 ci: matches.get_one::<bool>("ci").cloned(),
84 extra_checks: None,
85 pos_args: vec![],
86 };
87
88 if let Some(extra_checks) = matches.get_many::<String>("extra_checks") {
89 tidy_flags.extra_checks = Some(extra_checks.map(|s| s.to_string()).collect::<Vec<_>>());
90 }
91
92 tidy_flags.pos_args = matches
93 .get_many::<String>("pos_args")
94 .unwrap_or_default()
95 .map(|v| v.to_string())
96 .collect::<Vec<_>>();
97
98 tidy_flags
99 }
100
101 pub fn parse() -> Self {
102 let matches = Self::command().get_matches();
103 Self::build(matches)
104 }
105}