1use clap::CommandFactory;
2use clap_complete::{generator::generate, shells};
3use std::path::PathBuf;
4
5#[cfg(any(
6 feature = "audit",
7 feature = "clippy",
8 feature = "deny",
9 feature = "outdated",
10 feature = "typos",
11 feature = "udeps"
12))]
13#[derive(Debug, Clone, Copy, PartialEq, clap::ValueEnum, strum::EnumString)]
14#[non_exhaustive]
15pub enum Issue {
16 #[cfg(feature = "audit")]
17 #[strum(serialize = "audit")]
18 Audit,
19 #[cfg(feature = "clippy")]
20 #[strum(serialize = "clippy")]
21 Clippy,
22 #[cfg(feature = "deny")]
23 #[strum(serialize = "deny")]
24 Deny,
25 #[cfg(feature = "outdated")]
26 #[strum(serialize = "outdated")]
27 Outdated,
28 #[cfg(feature = "typos")]
29 #[strum(serialize = "typos")]
30 Typos,
31 #[cfg(feature = "udeps")]
32 #[strum(serialize = "udeps")]
33 Udeps,
34}
35
36#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, clap::ValueEnum)]
37#[non_exhaustive]
38#[allow(clippy::doc_markdown)]
40pub enum Shell {
41 Bash,
43 Elvish,
45 Fish,
47 Nushell,
49 #[allow(clippy::enum_variant_names)]
52 PowerShell,
53 Zsh,
55}
56
57#[derive(Debug, Clone)]
58pub enum InputPath {
59 Stdin,
60 File(PathBuf),
61}
62
63impl clap::builder::ValueParserFactory for InputPath {
64 type Parser = InputPathValueParser;
65
66 fn value_parser() -> Self::Parser {
67 InputPathValueParser
68 }
69}
70
71#[derive(Debug, Clone)]
72pub struct InputPathValueParser;
73impl clap::builder::TypedValueParser for InputPathValueParser {
74 type Value = InputPath;
75
76 fn parse_ref(
77 &self,
78 _cmd: &clap::Command,
79 _arg: Option<&clap::Arg>,
80 value: &std::ffi::OsStr,
81 ) -> Result<Self::Value, clap::Error> {
82 if value.eq_ignore_ascii_case("-") {
83 Ok(InputPath::Stdin)
84 } else {
85 let os_string = value.to_owned();
86 let path_buf = PathBuf::from(os_string);
87 Ok(InputPath::File(path_buf))
88 }
89 }
90}
91
92#[allow(clippy::struct_excessive_bools)]
95#[derive(Debug, clap::Parser)]
96#[command(version, author)]
97pub struct Command {
98 #[cfg(feature = "audit")]
100 #[arg(long)]
101 pub audit: bool,
102 #[cfg(feature = "audit")]
104 #[arg(long, default_value = "audit.json")]
105 pub audit_path: InputPath,
106 #[cfg(feature = "clippy")]
108 #[arg(long)]
109 pub clippy: bool,
110 #[cfg(feature = "clippy")]
112 #[arg(long, default_value = "clippy.json")]
113 pub clippy_path: InputPath,
114 #[cfg(feature = "deny")]
116 #[arg(long)]
117 pub deny: bool,
118 #[cfg(feature = "deny")]
120 #[arg(long, default_value = "deny.json")]
121 pub deny_path: InputPath,
122 #[cfg(feature = "outdated")]
124 #[arg(long)]
125 pub outdated: bool,
126 #[cfg(feature = "outdated")]
128 #[arg(long, default_value = "outdated.json")]
129 pub outdated_path: InputPath,
130 #[cfg(feature = "typos")]
132 #[arg(long)]
133 pub typos: bool,
134 #[cfg(feature = "typos")]
136 #[arg(long, default_value = "typos.json")]
137 pub typos_path: InputPath,
138 #[cfg(feature = "udeps")]
140 #[arg(long)]
141 pub udeps: bool,
142 #[cfg(feature = "udeps")]
144 #[arg(long, default_value = "udeps.json")]
145 pub udeps_path: InputPath,
146 #[arg(long, default_value = "sonar-issues.json")]
148 pub sonar_path: PathBuf,
149 #[arg(long, default_value = "codeclimate.json")]
151 pub codeclimate_path: PathBuf,
152 #[arg(long, value_enum)]
154 pub completion: Option<Shell>,
155}
156
157impl Command {
158 #[inline]
159 pub fn generate_completion(&self) {
160 if let Some(ref shell) = self.completion {
161 let mut app = Self::command();
162 let mut fd = std::io::stdout();
163 match *shell {
164 Shell::Bash => generate(shells::Bash, &mut app, "cargo-sonar", &mut fd),
165 Shell::Elvish => generate(shells::Elvish, &mut app, "cargo-sonar", &mut fd),
166 Shell::Fish => generate(shells::Fish, &mut app, "cargo-sonar", &mut fd),
167 Shell::Nushell => generate(
168 clap_complete_nushell::Nushell,
169 &mut app,
170 "cargo-sonar",
171 &mut fd,
172 ),
173 Shell::PowerShell => generate(shells::PowerShell, &mut app, "cargo-sonar", &mut fd),
174 Shell::Zsh => generate(shells::Zsh, &mut app, "cargo-sonar", &mut fd),
175 }
176 std::process::exit(0);
177 }
178 }
179}