Skip to content

Add cargo lintcheck --recursive to check dependencies of crates #9510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lintcheck/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ publish = false
[dependencies]
cargo_metadata = "0.14"
clap = "3.2"
crossbeam-channel = "0.5.6"
flate2 = "1.0"
rayon = "1.5.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.85"
tar = "0.4"
toml = "0.5"
ureq = "2.2"
Expand Down
20 changes: 19 additions & 1 deletion lintcheck/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,27 @@ is checked.
is explicitly specified in the options.

### Fix mode
You can run `./lintcheck/target/debug/lintcheck --fix` which will run Clippy with `--fix` and
You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).
This lets us spot bad suggestions or false positives automatically in some cases.

Please note that the target dir should be cleaned afterwards since clippy will modify
the downloaded sources which can lead to unexpected results when running lintcheck again afterwards.

### Recursive mode
You can run `cargo lintcheck --recursive` to also run Clippy on the dependencies
of the crates listed in the crates source `.toml`. e.g. adding `rand 0.8.5`
would also lint `rand_core`, `rand_chacha`, etc.

Particularly slow crates in the dependency graph can be ignored using
`recursive.ignore`:

```toml
[crates]
cargo = {name = "cargo", versions = ['0.64.0']}

[recursive]
ignore = [
"unicode-normalization",
]
```
8 changes: 8 additions & 0 deletions lintcheck/lintcheck_crates.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ cfg-expr = {name = "cfg-expr", versions = ['0.7.1']}
puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"}
rpmalloc = {name = "rpmalloc", versions = ['0.2.0']}
tame-oidc = {name = "tame-oidc", versions = ['0.1.0']}

[recursive]
ignore = [
# Takes ~30s to lint
"combine",
# Has 1.2 million `clippy::match_same_arms`s
"unicode-normalization",
]
10 changes: 9 additions & 1 deletion lintcheck/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@ fn get_clap_config() -> ArgMatches {
Arg::new("markdown")
.long("markdown")
.help("Change the reports table to use markdown links"),
Arg::new("recursive")
.long("--recursive")
.help("Run clippy on the dependencies of crates specified in crates-toml")
.conflicts_with("threads")
.conflicts_with("fix"),
])
.get_matches()
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub(crate) struct LintcheckConfig {
/// max number of jobs to spawn (default 1)
pub max_jobs: usize,
Expand All @@ -54,6 +59,8 @@ pub(crate) struct LintcheckConfig {
pub lint_filter: Vec<String>,
/// Indicate if the output should support markdown syntax
pub markdown: bool,
/// Run clippy on the dependencies of crates
pub recursive: bool,
}

impl LintcheckConfig {
Expand Down Expand Up @@ -119,6 +126,7 @@ impl LintcheckConfig {
fix: clap_config.contains_id("fix"),
lint_filter,
markdown,
recursive: clap_config.contains_id("recursive"),
}
}
}
67 changes: 67 additions & 0 deletions lintcheck/src/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::recursive::{deserialize_line, serialize_line, DriverInfo};

use std::io::{self, BufReader, Write};
use std::net::TcpStream;
use std::process::{self, Command, Stdio};
use std::{env, mem};

/// 1. Sends [DriverInfo] to the [crate::recursive::LintcheckServer] running on `addr`
/// 2. Receives [bool] from the server, if `false` returns `None`
/// 3. Otherwise sends the stderr of running `clippy-driver` to the server
fn run_clippy(addr: &str) -> Option<i32> {
let driver_info = DriverInfo {
package_name: env::var("CARGO_PKG_NAME").ok()?,
crate_name: env::var("CARGO_CRATE_NAME").ok()?,
version: env::var("CARGO_PKG_VERSION").ok()?,
};

let mut stream = BufReader::new(TcpStream::connect(addr).unwrap());

serialize_line(&driver_info, stream.get_mut());

let should_run = deserialize_line::<bool, _>(&mut stream);
if !should_run {
return None;
}

// Remove --cap-lints allow so that clippy runs and lints are emitted
let mut include_next = true;
let args = env::args().skip(1).filter(|arg| match arg.as_str() {
"--cap-lints=allow" => false,
"--cap-lints" => {
include_next = false;
false
},
_ => mem::replace(&mut include_next, true),
});

let output = Command::new(env::var("CLIPPY_DRIVER").expect("missing env CLIPPY_DRIVER"))
.args(args)
.stdout(Stdio::inherit())
.output()
.expect("failed to run clippy-driver");

stream
.get_mut()
.write_all(&output.stderr)
.unwrap_or_else(|e| panic!("{e:?} in {driver_info:?}"));

match output.status.code() {
Some(0) => Some(0),
code => {
io::stderr().write_all(&output.stderr).unwrap();
Some(code.expect("killed by signal"))
},
}
}

pub fn drive(addr: &str) {
process::exit(run_clippy(addr).unwrap_or_else(|| {
Command::new("rustc")
.args(env::args_os().skip(2))
.status()
.unwrap()
.code()
.unwrap()
}))
}
Loading