clippy.rs

 1use std::process::Command;
 2
 3use anyhow::{Context as _, Result, bail};
 4use clap::Parser;
 5
 6#[derive(Parser)]
 7pub struct ClippyArgs {
 8    /// Automatically apply lint suggestions (`clippy --fix`).
 9    #[arg(long)]
10    fix: bool,
11
12    /// The package to run Clippy against (`cargo -p <PACKAGE> clippy`).
13    #[arg(long, short)]
14    package: Option<String>,
15}
16
17pub fn run_clippy(args: ClippyArgs) -> Result<()> {
18    let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
19
20    let mut clippy_command = Command::new(&cargo);
21    clippy_command.arg("clippy");
22
23    if let Some(package) = args.package.as_ref() {
24        clippy_command.args(["--package", package]);
25    } else {
26        clippy_command.arg("--workspace");
27    }
28
29    clippy_command
30        .arg("--release")
31        .arg("--all-targets")
32        .arg("--all-features");
33
34    if args.fix {
35        clippy_command.arg("--fix");
36    }
37
38    clippy_command.arg("--");
39
40    // Deny all warnings.
41    clippy_command.args(["--deny", "warnings"]);
42
43    eprintln!(
44        "running: {cargo} {}",
45        clippy_command
46            .get_args()
47            .map(|arg| arg.to_str().unwrap())
48            .collect::<Vec<_>>()
49            .join(" ")
50    );
51
52    let exit_status = clippy_command
53        .spawn()
54        .context("failed to spawn child process")?
55        .wait()
56        .context("failed to wait for child process")?;
57
58    if !exit_status.success() {
59        bail!("clippy failed: {}", exit_status);
60    }
61
62    Ok(())
63}