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 extra_checks: Option<Vec<String>>,
19 pub pos_args: Vec<String>,
20}
21
22impl TidyArgParser {
23 fn command() -> Command {
24 Command::new("rust-tidy")
25 .arg(
26 Arg::new("root_path")
27 .help("path of the root directory")
28 .long("root-path")
29 .required(true)
30 .value_parser(value_parser!(PathBuf)),
31 )
32 .arg(
33 Arg::new("cargo")
34 .help("path of cargo")
35 .long("cargo-path")
36 .required(true)
37 .value_parser(value_parser!(PathBuf)),
38 )
39 .arg(
40 Arg::new("output_directory")
41 .help("path of output directory")
42 .long("output-dir")
43 .required(true)
44 .value_parser(value_parser!(PathBuf)),
45 )
46 .arg(
47 Arg::new("concurrency")
48 .help("number of threads working concurrently")
49 .long("concurrency")
50 .required(true)
51 .value_parser(value_parser!(NonZeroUsize)),
52 )
53 .arg(
54 Arg::new("npm")
55 .help("path of npm")
56 .long("npm-path")
57 .required(true)
58 .value_parser(value_parser!(PathBuf)),
59 )
60 .arg(Arg::new("verbose").help("verbose").long("verbose").action(ArgAction::SetTrue))
61 .arg(Arg::new("bless").help("target files are modified").long("bless").action(ArgAction::SetTrue))
62 .arg(
63 Arg::new("extra_checks")
64 .help("extra checks")
65 .long("extra-checks")
66 .value_delimiter(',')
67 .action(ArgAction::Append),
68 )
69 .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))
70 }
71
72 fn build(matches: ArgMatches) -> Self {
73 let mut tidy_flags = Self {
74 root_path: matches.get_one::<PathBuf>("root_path").unwrap().clone(),
75 cargo: matches.get_one::<PathBuf>("cargo").unwrap().clone(),
76 output_directory: matches.get_one::<PathBuf>("output_directory").unwrap().clone(),
77 concurrency: *matches.get_one::<NonZeroUsize>("concurrency").unwrap(),
78 npm: matches.get_one::<PathBuf>("npm").unwrap().clone(),
79 verbose: *matches.get_one::<bool>("verbose").unwrap(),
80 bless: *matches.get_one::<bool>("bless").unwrap(),
81 extra_checks: None,
82 pos_args: vec![],
83 };
84
85 if let Some(extra_checks) = matches.get_many::<String>("extra_checks") {
86 tidy_flags.extra_checks = Some(extra_checks.map(|s| s.to_string()).collect::<Vec<_>>());
87 }
88
89 tidy_flags.pos_args = matches
90 .get_many::<String>("pos_args")
91 .unwrap_or_default()
92 .map(|v| v.to_string())
93 .collect::<Vec<_>>();
94
95 tidy_flags
96 }
97
98 pub fn parse() -> Self {
99 let matches = Self::command().get_matches();
100 Self::build(matches)
101 }
102}