Skip to content

Commit 5eefbb3

Browse files
committed
Auto merge of rust-lang#10466 - samueltardieu:popular-crates, r=llogiq
Add the `popular-crates` binary This program downloads crates info from <https://crates.io/> and builds a TOML file that can be fed to `lintcheck`. I have been asked, on various pull requests, what the result of `lintcheck` was. However, the default configuration file for lintcheck is limited. This `popular-crates` program allows building a recent list of the recently most downloaded crates from <https://crates.io> and feed it to `lintcheck`. Using it, it was easy to test two new lints against the 500 recently most downloaded crates to ensure that there was no regression. changelog: none
2 parents 216aefb + ce3415e commit 5eefbb3

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed

lintcheck/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ repository = "https://github.com/rust-lang/rust-clippy"
88
categories = ["development-tools"]
99
edition = "2021"
1010
publish = false
11+
default-run = "lintcheck"
1112

1213
[dependencies]
14+
anyhow = "1.0.69"
1315
cargo_metadata = "0.15.3"
1416
clap = { version = "4.1.8", features = ["derive", "env"] }
17+
crates_io_api = "0.8.1"
1518
crossbeam-channel = "0.5.6"
1619
flate2 = "1.0"
20+
indicatif = "0.17.3"
1721
rayon = "1.5.1"
1822
serde = { version = "1.0", features = ["derive"] }
1923
serde_json = "1.0.85"
@@ -24,3 +28,11 @@ walkdir = "2.3"
2428

2529
[features]
2630
deny-warnings = []
31+
32+
[[bin]]
33+
name = "lintcheck"
34+
path = "src/main.rs"
35+
36+
[[bin]]
37+
name = "popular-crates"
38+
path = "src/popular-crates.rs"

lintcheck/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ the repo root.
2525

2626
The results will then be saved to `lintcheck-logs/custom_logs.toml`.
2727

28+
The `custom.toml` file may be built using <https://crates.io> recently most
29+
downloaded crates by using the `popular-crates` binary from the `lintcheck`
30+
directory. For example, to retrieve the 100 recently most downloaded crates:
31+
32+
```
33+
cargo run --release --bin popular-crates -- -n 100 custom.toml
34+
```
35+
36+
2837
### Configuring the Crate Sources
2938

3039
The sources to check are saved in a `toml` file. There are three types of

lintcheck/src/popular-crates.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#![deny(clippy::pedantic)]
2+
3+
use clap::Parser;
4+
use crates_io_api::{CratesQueryBuilder, Sort, SyncClient};
5+
use indicatif::ProgressBar;
6+
use std::collections::HashSet;
7+
use std::fs::File;
8+
use std::io::{BufWriter, Write};
9+
use std::path::PathBuf;
10+
use std::time::Duration;
11+
12+
#[derive(Parser)]
13+
struct Opts {
14+
/// Output TOML file name
15+
output: PathBuf,
16+
/// Number of crate names to download
17+
#[clap(short, long, default_value_t = 100)]
18+
number: usize,
19+
/// Do not output progress
20+
#[clap(short, long)]
21+
quiet: bool,
22+
}
23+
24+
fn main() -> anyhow::Result<()> {
25+
let opts = Opts::parse();
26+
let mut output = BufWriter::new(File::create(opts.output)?);
27+
output.write_all(b"[crates]\n")?;
28+
let client = SyncClient::new(
29+
"clippy/lintcheck (github.com/rust-lang/rust-clippy/)",
30+
Duration::from_secs(1),
31+
)?;
32+
let mut seen_crates = HashSet::new();
33+
let pb = if opts.quiet {
34+
None
35+
} else {
36+
Some(ProgressBar::new(opts.number as u64))
37+
};
38+
let mut query = CratesQueryBuilder::new()
39+
.sort(Sort::RecentDownloads)
40+
.page_size(100)
41+
.build();
42+
while seen_crates.len() < opts.number {
43+
let retrieved = client.crates(query.clone())?.crates;
44+
if retrieved.is_empty() {
45+
eprintln!("No more than {} crates available from API", seen_crates.len());
46+
break;
47+
}
48+
for c in retrieved {
49+
if seen_crates.insert(c.name.clone()) {
50+
output.write_all(
51+
format!(
52+
"{} = {{ name = '{}', versions = ['{}'] }}\n",
53+
c.name, c.name, c.max_version
54+
)
55+
.as_bytes(),
56+
)?;
57+
if let Some(pb) = &pb {
58+
pb.inc(1);
59+
}
60+
}
61+
}
62+
query.set_page(query.page() + 1);
63+
}
64+
Ok(())
65+
}

0 commit comments

Comments
 (0)