summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/lintcheck/src/config.rs
blob: e0244ddcecb8058341e5e46f42d68d96d755acd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use clap::{Arg, ArgAction, ArgMatches, Command};
use std::env;
use std::path::PathBuf;

fn get_clap_config() -> ArgMatches {
    Command::new("lintcheck")
        .about("run clippy on a set of crates and check output")
        .args([
            Arg::new("only")
                .action(ArgAction::Set)
                .value_name("CRATE")
                .long("only")
                .help("Only process a single crate of the list"),
            Arg::new("crates-toml")
                .action(ArgAction::Set)
                .value_name("CRATES-SOURCES-TOML-PATH")
                .long("crates-toml")
                .help("Set the path for a crates.toml where lintcheck should read the sources from"),
            Arg::new("threads")
                .action(ArgAction::Set)
                .value_name("N")
                .value_parser(clap::value_parser!(usize))
                .short('j')
                .long("jobs")
                .help("Number of threads to use, 0 automatic choice"),
            Arg::new("fix")
                .long("fix")
                .help("Runs cargo clippy --fix and checks if all suggestions apply"),
            Arg::new("filter")
                .long("filter")
                .action(ArgAction::Append)
                .value_name("clippy_lint_name")
                .help("Apply a filter to only collect specified lints, this also overrides `allow` attributes"),
            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, Clone)]
pub(crate) struct LintcheckConfig {
    /// max number of jobs to spawn (default 1)
    pub max_jobs: usize,
    /// we read the sources to check from here
    pub sources_toml_path: PathBuf,
    /// we save the clippy lint results here
    pub lintcheck_results_path: PathBuf,
    /// Check only a specified package
    pub only: Option<String>,
    /// whether to just run --fix and not collect all the warnings
    pub fix: bool,
    /// A list of lints that this lintcheck run should focus on
    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 {
    pub fn new() -> Self {
        let clap_config = get_clap_config();

        // first, check if we got anything passed via the LINTCHECK_TOML env var,
        // if not, ask clap if we got any value for --crates-toml  <foo>
        // if not, use the default "lintcheck/lintcheck_crates.toml"
        let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
            clap_config
                .get_one::<String>("crates-toml")
                .map_or("lintcheck/lintcheck_crates.toml", |s| &**s)
                .into()
        });

        let markdown = clap_config.contains_id("markdown");
        let sources_toml_path = PathBuf::from(sources_toml);

        // for the path where we save the lint results, get the filename without extension (so for
        // wasd.toml, use "wasd"...)
        let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
        let lintcheck_results_path = PathBuf::from(format!(
            "lintcheck-logs/{}_logs.{}",
            filename.display(),
            if markdown { "md" } else { "txt" }
        ));

        // look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
        // use half of that for the physical core count
        // by default use a single thread
        let max_jobs = match clap_config.get_one::<usize>("threads") {
            Some(&0) => {
                // automatic choice
                // Rayon seems to return thread count so half that for core count
                rayon::current_num_threads() / 2
            },
            Some(&threads) => threads,
            // no -j passed, use a single thread
            None => 1,
        };

        let lint_filter: Vec<String> = clap_config
            .get_many::<String>("filter")
            .map(|iter| {
                iter.map(|lint_name| {
                    let mut filter = lint_name.replace('_', "-");
                    if !filter.starts_with("clippy::") {
                        filter.insert_str(0, "clippy::");
                    }
                    filter
                })
                .collect()
            })
            .unwrap_or_default();

        LintcheckConfig {
            max_jobs,
            sources_toml_path,
            lintcheck_results_path,
            only: clap_config.get_one::<String>("only").map(String::from),
            fix: clap_config.contains_id("fix"),
            lint_filter,
            markdown,
            recursive: clap_config.contains_id("recursive"),
        }
    }
}