1use std::collections::VecDeque;
8use std::num::NonZeroUsize;
9use std::path::PathBuf;
10use std::str::FromStr;
11use std::sync::atomic::{AtomicBool, Ordering};
12use std::thread::{self, ScopedJoinHandle, scope};
13use std::{env, process};
14
15use tidy::*;
16
17fn main() {
18 env::set_var("RUSTC_BOOTSTRAP", "1");
23
24 let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into();
25 let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into();
26 let output_directory: PathBuf =
27 env::args_os().nth(3).expect("need path to output directory").into();
28 let concurrency: NonZeroUsize =
29 FromStr::from_str(&env::args().nth(4).expect("need concurrency"))
30 .expect("concurrency must be a number");
31
32 let src_path = root_path.join("src");
33 let tests_path = root_path.join("tests");
34 let library_path = root_path.join("library");
35 let compiler_path = root_path.join("compiler");
36 let librustdoc_path = src_path.join("librustdoc");
37 let crashes_path = tests_path.join("crashes");
38
39 let args: Vec<String> = env::args().skip(1).collect();
40 let (cfg_args, pos_args) = match args.iter().position(|arg| arg == "--") {
41 Some(pos) => (&args[..pos], &args[pos + 1..]),
42 None => (&args[..], [].as_slice()),
43 };
44 let verbose = cfg_args.iter().any(|s| *s == "--verbose");
45 let bless = cfg_args.iter().any(|s| *s == "--bless");
46 let extra_checks =
47 cfg_args.iter().find(|s| s.starts_with("--extra-checks=")).map(String::as_str);
48
49 let bad = std::sync::Arc::new(AtomicBool::new(false));
50
51 let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
52 for i in (0..handles.len()).rev() {
54 if handles[i].is_finished() {
55 handles.swap_remove_back(i).unwrap().join().unwrap();
56 }
57 }
58
59 while handles.len() >= concurrency.get() {
60 handles.pop_front().unwrap().join().unwrap();
61 }
62 };
63
64 scope(|s| {
65 let mut handles: VecDeque<ScopedJoinHandle<'_, ()>> =
66 VecDeque::with_capacity(concurrency.get());
67
68 macro_rules! check {
69 ($p:ident) => {
70 check!(@ $p, name=format!("{}", stringify!($p)));
71 };
72 ($p:ident, $path:expr $(, $args:expr)* ) => {
73 let shortened = $path.strip_prefix(&root_path).unwrap();
74 let name = if shortened == std::path::Path::new("") {
75 format!("{} (.)", stringify!($p))
76 } else {
77 format!("{} ({})", stringify!($p), shortened.display())
78 };
79 check!(@ $p, name=name, $path $(,$args)*);
80 };
81 (@ $p:ident, name=$name:expr $(, $args:expr)* ) => {
82 drain_handles(&mut handles);
83
84 let handle = thread::Builder::new().name($name).spawn_scoped(s, || {
85 let mut flag = false;
86 $p::check($($args, )* &mut flag);
87 if (flag) {
88 bad.store(true, Ordering::Relaxed);
89 }
90 }).unwrap();
91 handles.push_back(handle);
92 }
93 }
94
95 check!(target_specific_tests, &tests_path);
96
97 check!(deps, &root_path, &cargo, bless);
99 check!(extdeps, &root_path);
100
101 check!(tests_placement, &root_path);
103 check!(tests_revision_unpaired_stdout_stderr, &tests_path);
104 check!(debug_artifacts, &tests_path);
105 check!(ui_tests, &root_path, bless);
106 check!(run_make_tests, &tests_path, &src_path, bless);
108 check!(mir_opt_tests, &tests_path, bless);
109 check!(rustdoc_gui_tests, &tests_path);
110 check!(rustdoc_css_themes, &librustdoc_path);
111 check!(rustdoc_templates, &librustdoc_path);
112 check!(known_bug, &crashes_path);
113 check!(unknown_revision, &tests_path);
114
115 check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
117 check!(fluent_alphabetical, &compiler_path, bless);
118 check!(fluent_period, &compiler_path);
119 check!(target_policy, &root_path);
120
121 check!(pal, &library_path);
123
124 check!(unit_tests, &src_path);
126 check!(unit_tests, &compiler_path);
127 check!(unit_tests, &library_path);
128
129 if bins::check_filesystem_support(&[&root_path], &output_directory) {
130 check!(bins, &root_path);
131 }
132
133 check!(style, &src_path);
134 check!(style, &tests_path);
135 check!(style, &compiler_path);
136 check!(style, &library_path);
137
138 check!(edition, &src_path);
139 check!(edition, &compiler_path);
140 check!(edition, &library_path);
141
142 check!(alphabetical, &src_path);
143 check!(alphabetical, &tests_path);
144 check!(alphabetical, &compiler_path);
145 check!(alphabetical, &library_path);
146
147 check!(x_version, &root_path, &cargo);
148
149 let collected = {
150 drain_handles(&mut handles);
151
152 let mut flag = false;
153 let r = features::check(
154 &src_path,
155 &tests_path,
156 &compiler_path,
157 &library_path,
158 &mut flag,
159 verbose,
160 );
161 if flag {
162 bad.store(true, Ordering::Relaxed);
163 }
164 r
165 };
166 check!(unstable_book, &src_path, collected);
167
168 check!(ext_tool_checks, &root_path, &output_directory, bless, extra_checks, pos_args);
169 });
170
171 if bad.load(Ordering::Relaxed) {
172 eprintln!("some tidy checks failed");
173 process::exit(1);
174 }
175}