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}