1 use clap::{Arg, ArgAction, ArgMatches, Command};
3 use std::path::PathBuf;
5 fn get_clap_config() -> ArgMatches {
6 Command::new("lintcheck")
7 .about("run clippy on a set of crates and check output")
10 .action(ArgAction::Set)
13 .help("Only process a single crate of the list"),
14 Arg::new("crates-toml")
15 .action(ArgAction::Set)
16 .value_name("CRATES-SOURCES-TOML-PATH")
18 .help("Set the path for a crates.toml where lintcheck should read the sources from"),
20 .action(ArgAction::Set)
22 .value_parser(clap::value_parser!(usize))
25 .help("Number of threads to use, 0 automatic choice"),
28 .help("Runs cargo clippy --fix and checks if all suggestions apply"),
31 .action(ArgAction::Append)
32 .value_name("clippy_lint_name")
33 .help("Apply a filter to only collect specified lints, this also overrides `allow` attributes"),
36 .help("Change the reports table to use markdown links"),
39 .help("Run clippy on the dependencies of crates specified in crates-toml")
40 .conflicts_with("threads")
41 .conflicts_with("fix"),
46 #[derive(Debug, Clone)]
47 pub(crate) struct LintcheckConfig {
48 /// max number of jobs to spawn (default 1)
50 /// we read the sources to check from here
51 pub sources_toml_path: PathBuf,
52 /// we save the clippy lint results here
53 pub lintcheck_results_path: PathBuf,
54 /// Check only a specified package
55 pub only: Option<String>,
56 /// whether to just run --fix and not collect all the warnings
58 /// A list of lints that this lintcheck run should focus on
59 pub lint_filter: Vec<String>,
60 /// Indicate if the output should support markdown syntax
62 /// Run clippy on the dependencies of crates
66 impl LintcheckConfig {
67 pub fn new() -> Self {
68 let clap_config = get_clap_config();
70 // first, check if we got anything passed via the LINTCHECK_TOML env var,
71 // if not, ask clap if we got any value for --crates-toml <foo>
72 // if not, use the default "lintcheck/lintcheck_crates.toml"
73 let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
75 .get_one::<String>("crates-toml")
76 .map_or("lintcheck/lintcheck_crates.toml", |s| &**s)
80 let markdown = clap_config.contains_id("markdown");
81 let sources_toml_path = PathBuf::from(sources_toml);
83 // for the path where we save the lint results, get the filename without extension (so for
84 // wasd.toml, use "wasd"...)
85 let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
86 let lintcheck_results_path = PathBuf::from(format!(
87 "lintcheck-logs/{}_logs.{}",
89 if markdown { "md" } else { "txt" }
92 // look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
93 // use half of that for the physical core count
94 // by default use a single thread
95 let max_jobs = match clap_config.get_one::<usize>("threads") {
98 // Rayon seems to return thread count so half that for core count
99 rayon::current_num_threads() / 2
101 Some(&threads) => threads,
102 // no -j passed, use a single thread
106 let lint_filter: Vec<String> = clap_config
107 .get_many::<String>("filter")
109 iter.map(|lint_name| {
110 let mut filter = lint_name.replace('_', "-");
111 if !filter.starts_with("clippy::") {
112 filter.insert_str(0, "clippy::");
118 .unwrap_or_default();
123 lintcheck_results_path,
124 only: clap_config.get_one::<String>("only").map(String::from),
125 fix: clap_config.contains_id("fix"),
128 recursive: clap_config.contains_id("recursive"),