tidy/
run_make_tests.rs

1//! Tidy check to ensure that no new Makefiles are added under `tests/run-make/`.
2
3use std::collections::BTreeSet;
4use std::fs::File;
5use std::io::Write;
6use std::path::{Path, PathBuf};
7
8pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) {
9    let mut is_sorted = true;
10
11    let allowed_makefiles = {
12        let mut total_lines = 0;
13        let mut prev_line = "";
14        let allowed_makefiles: BTreeSet<&str> = include_str!("allowed_run_make_makefiles.txt")
15            .lines()
16            .map(|line| {
17                total_lines += 1;
18
19                if prev_line > line {
20                    is_sorted = false;
21                }
22
23                prev_line = line;
24
25                line
26            })
27            .collect();
28
29        if !is_sorted && !bless {
30            tidy_error!(
31                bad,
32                "`src/tools/tidy/src/allowed_run_make_makefiles.txt` is not in order, likely \
33                because you modified it manually, please only update it with command \
34                `x test tidy --bless`"
35            );
36        }
37        if allowed_makefiles.len() != total_lines {
38            tidy_error!(
39                bad,
40                "`src/tools/tidy/src/allowed_run_make_makefiles.txt` contains duplicate entries, \
41                likely because you modified it manually, please only update it with command \
42                `x test tidy --bless`"
43            );
44        }
45
46        allowed_makefiles
47    };
48
49    let mut remaining_makefiles = allowed_makefiles.clone();
50
51    crate::walk::walk_no_read(
52        &[tests_path.join("run-make").as_ref()],
53        |_, _| false,
54        &mut |entry| {
55            if entry.file_type().map_or(true, |t| t.is_dir()) {
56                return;
57            }
58
59            if entry.file_name().to_str().map_or(true, |f| f != "Makefile") {
60                return;
61            }
62
63            let makefile_path = entry.path().strip_prefix(&tests_path).unwrap();
64            let makefile_path = makefile_path.to_str().unwrap().replace('\\', "/");
65
66            if !remaining_makefiles.remove(makefile_path.as_str()) {
67                tidy_error!(
68                    bad,
69                    "found run-make Makefile not permitted in \
70                `src/tools/tidy/src/allowed_run_make_makefiles.txt`, please write new run-make \
71                tests with `rmake.rs` instead: {}",
72                    entry.path().display()
73                );
74            }
75        },
76    );
77
78    // If there are any expected Makefiles remaining, they were moved or deleted.
79    // Our data must remain up to date, so they must be removed from
80    // `src/tools/tidy/src/allowed_run_make_makefiles.txt`.
81    // This can be done automatically on --bless, or else a tidy error will be issued.
82    if bless && (!remaining_makefiles.is_empty() || !is_sorted) {
83        let tidy_src = src_path.join("tools").join("tidy").join("src");
84        let org_file_path = tidy_src.join("allowed_run_make_makefiles.txt");
85        let temp_file_path = tidy_src.join("blessed_allowed_run_make_makefiles.txt");
86        let mut temp_file = t!(File::create_new(&temp_file_path));
87        for file in allowed_makefiles.difference(&remaining_makefiles) {
88            t!(writeln!(temp_file, "{file}"));
89        }
90        t!(std::fs::rename(&temp_file_path, &org_file_path));
91    } else {
92        for file in remaining_makefiles {
93            let mut p = PathBuf::from(tests_path);
94            p.push(file);
95            tidy_error!(
96                bad,
97                "Makefile `{}` no longer exists and should be removed from the exclusions in \
98                `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run `x test tidy --bless` to update \
99                the allow list",
100                p.display()
101            );
102        }
103    }
104}