Allow running `cargo dev lint` on a package directory

This commit is contained in:
Alex Macleod 2022-03-29 18:36:38 +01:00
parent 6206086dd5
commit 9a02386fd8
5 changed files with 81 additions and 31 deletions

View File

@ -11,6 +11,7 @@ itertools = "0.10.1"
opener = "0.5"
regex = "1.5"
shell-escape = "0.1"
tempfile = "3.3"
walkdir = "2.3"
cargo_metadata = "0.14"

View File

@ -1,22 +1,15 @@
//! `bless` updates the reference files in the repo with changed output files
//! from the last test run.
use crate::cargo_clippy_path;
use std::ffi::OsStr;
use std::fs;
use std::lazy::SyncLazy;
use std::path::{Path, PathBuf};
use walkdir::{DirEntry, WalkDir};
#[cfg(not(windows))]
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
#[cfg(windows)]
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
let mut path = std::env::current_exe().unwrap();
path.set_file_name(CARGO_CLIPPY_EXE);
fs::metadata(path).ok()?.modified().ok()
});
static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> =
SyncLazy::new(|| cargo_clippy_path().metadata().ok()?.modified().ok());
/// # Panics
///

View File

@ -13,6 +13,19 @@ pub mod serve;
pub mod setup;
pub mod update_lints;
#[cfg(not(windows))]
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
#[cfg(windows)]
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
/// Returns the path to the `cargo-clippy` binary
#[must_use]
pub fn cargo_clippy_path() -> PathBuf {
let mut path = std::env::current_exe().expect("failed to get current executable name");
path.set_file_name(CARGO_CLIPPY_EXE);
path
}
/// Returns the path to the Clippy project directory
///
/// # Panics

View File

@ -1,19 +1,52 @@
use std::process::{self, Command};
use crate::cargo_clippy_path;
use std::process::{self, Command, ExitStatus};
use std::{fs, io};
pub fn run(filename: &str) {
let code = Command::new("cargo")
.args(["run", "--bin", "clippy-driver", "--"])
.args(["-L", "./target/debug"])
.args(["-Z", "no-codegen"])
.args(["--edition", "2021"])
.arg(filename)
.status()
.expect("failed to run cargo")
.code();
if code.is_none() {
eprintln!("Killed by signal");
fn exit_if_err(status: io::Result<ExitStatus>) {
match status.expect("failed to run command").code() {
Some(0) => {},
Some(n) => process::exit(n),
None => {
eprintln!("Killed by signal");
process::exit(1);
},
}
}
pub fn run(path: &str) {
let is_file = match fs::metadata(path) {
Ok(metadata) => metadata.is_file(),
Err(e) => {
eprintln!("Failed to read {path}: {e:?}");
process::exit(1);
},
};
if is_file {
exit_if_err(
Command::new("cargo")
.args(["run", "--bin", "clippy-driver", "--"])
.args(["-L", "./target/debug"])
.args(["-Z", "no-codegen"])
.args(["--edition", "2021"])
.arg(path)
.status(),
);
} else {
exit_if_err(Command::new("cargo").arg("build").status());
// Run in a tempdir as changes to clippy do not retrigger linting
let target = tempfile::Builder::new()
.prefix("clippy")
.tempdir()
.expect("failed to create tempdir");
let status = Command::new(cargo_clippy_path())
.current_dir(path)
.env("CARGO_TARGET_DIR", target.as_ref())
.status();
target.close().expect("failed to remove tempdir");
exit_if_err(status);
}
process::exit(code.unwrap_or(1));
}

View File

@ -4,6 +4,7 @@
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use clippy_dev::{bless, fmt, lint, new_lint, serve, setup, update_lints};
use indoc::indoc;
fn main() {
let matches = get_clap_config();
@ -56,8 +57,8 @@ fn main() {
serve::run(port, lint);
},
("lint", Some(matches)) => {
let filename = matches.value_of("filename").unwrap();
lint::run(filename);
let path = matches.value_of("path").unwrap();
lint::run(path);
},
_ => {},
}
@ -225,11 +226,20 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
)
.subcommand(
SubCommand::with_name("lint")
.about("Manually run clippy on a file")
.about("Manually run clippy on a file or package")
.after_help(indoc! {"
EXAMPLES
Lint a single file:
cargo dev lint tests/ui/attrs.rs
Lint a package directory:
cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
cargo dev lint ~/my-project
"})
.arg(
Arg::with_name("filename")
Arg::with_name("path")
.required(true)
.help("The path to a file to lint"),
.help("The path to a file or package directory to lint"),
),
)
.get_matches()