Skip to main content

cargo_sonar/
cli.rs

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: 'SHell' is incorrectly detected as code that must be wrapped into backticks
39#[allow(clippy::doc_markdown)]
40pub enum Shell {
41    /// Bourne Again SHell (bash)
42    Bash,
43    /// Elvish shell
44    Elvish,
45    /// Friendly Interactive SHell (fish)
46    Fish,
47    /// Nushell
48    Nushell,
49    /// PowerShell
50    // ALLOW: 'PowerShell' is the name that does ends with 'Shell'
51    #[allow(clippy::enum_variant_names)]
52    PowerShell,
53    /// Z SHell (zsh)
54    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: This `struct` is the user external API, and is expected to provide all
93// the different supported format as different boolean options.
94#[allow(clippy::struct_excessive_bools)]
95#[derive(Debug, clap::Parser)]
96#[command(version, author)]
97pub struct Command {
98    /// Enable parsing of the 'cargo audit' report
99    #[cfg(feature = "audit")]
100    #[arg(long)]
101    pub audit: bool,
102    /// Path of the 'cargo audit' report (or `-` for stdin)
103    #[cfg(feature = "audit")]
104    #[arg(long, default_value = "audit.json")]
105    pub audit_path: InputPath,
106    /// Enable parsing of the 'cargo clippy' report
107    #[cfg(feature = "clippy")]
108    #[arg(long)]
109    pub clippy: bool,
110    /// Path of the 'cargo clippy' report (or `-` for stdin)
111    #[cfg(feature = "clippy")]
112    #[arg(long, default_value = "clippy.json")]
113    pub clippy_path: InputPath,
114    /// Enable parsing of the 'cargo deny' report
115    #[cfg(feature = "deny")]
116    #[arg(long)]
117    pub deny: bool,
118    /// Path of the 'cargo deny' report (or `-` for stdin)
119    #[cfg(feature = "deny")]
120    #[arg(long, default_value = "deny.json")]
121    pub deny_path: InputPath,
122    /// Enable parsing of the 'cargo outdated' report
123    #[cfg(feature = "outdated")]
124    #[arg(long)]
125    pub outdated: bool,
126    /// Path of the 'cargo outdated' report (or `-` for stdin)
127    #[cfg(feature = "outdated")]
128    #[arg(long, default_value = "outdated.json")]
129    pub outdated_path: InputPath,
130    /// Enable parsing of the 'typos' report
131    #[cfg(feature = "typos")]
132    #[arg(long)]
133    pub typos: bool,
134    /// Path of the 'typos' report (or `-` for stdin)
135    #[cfg(feature = "typos")]
136    #[arg(long, default_value = "typos.json")]
137    pub typos_path: InputPath,
138    /// Enable parsing of the 'cargo udeps' report
139    #[cfg(feature = "udeps")]
140    #[arg(long)]
141    pub udeps: bool,
142    /// Path of the 'cargo udeps' report (or `-` for stdin)
143    #[cfg(feature = "udeps")]
144    #[arg(long, default_value = "udeps.json")]
145    pub udeps_path: InputPath,
146    /// Path to the generated sonar report
147    #[arg(long, default_value = "sonar-issues.json")]
148    pub sonar_path: PathBuf,
149    /// Path to the generated codeclimate report
150    #[arg(long, default_value = "codeclimate.json")]
151    pub codeclimate_path: PathBuf,
152    /// Generate completion rules for some shells
153    #[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}