bootstrap/core/builder/
cli_paths.rs1use std::fmt::{self, Debug};
6use std::path::PathBuf;
7
8use crate::core::builder::{Builder, Kind, PathSet, ShouldRun, StepDescription};
9
10pub(crate) const PATH_REMAP: &[(&str, &[&str])] = &[
11 ("rust-analyzer-proc-macro-srv", &["src/tools/rust-analyzer/crates/proc-macro-srv-cli"]),
14 (
16 "tests",
17 &[
18 "tests/assembly-llvm",
20 "tests/codegen-llvm",
21 "tests/codegen-units",
22 "tests/coverage",
23 "tests/coverage-run-rustdoc",
24 "tests/crashes",
25 "tests/debuginfo",
26 "tests/incremental",
27 "tests/mir-opt",
28 "tests/pretty",
29 "tests/run-make",
30 "tests/run-make-cargo",
31 "tests/rustdoc",
32 "tests/rustdoc-gui",
33 "tests/rustdoc-js",
34 "tests/rustdoc-js-std",
35 "tests/rustdoc-json",
36 "tests/rustdoc-ui",
37 "tests/ui",
38 "tests/ui-fulldeps",
39 ],
41 ),
42];
43
44pub(crate) fn remap_paths(paths: &mut Vec<PathBuf>) {
45 let mut remove = vec![];
46 let mut add = vec![];
47 for (i, path) in paths.iter().enumerate().filter_map(|(i, path)| path.to_str().map(|s| (i, s)))
48 {
49 for &(search, replace) in PATH_REMAP {
50 if path.trim_matches(std::path::is_separator) == search {
52 remove.push(i);
53 add.extend(replace.iter().map(PathBuf::from));
54 break;
55 }
56 }
57 }
58 remove.sort();
59 remove.dedup();
60 for idx in remove.into_iter().rev() {
61 paths.remove(idx);
62 }
63 paths.append(&mut add);
64}
65
66#[derive(Clone, PartialEq)]
67pub(crate) struct CLIStepPath {
68 pub(crate) path: PathBuf,
69 pub(crate) will_be_executed: bool,
70}
71
72#[cfg(test)]
73impl CLIStepPath {
74 pub(crate) fn will_be_executed(mut self, will_be_executed: bool) -> Self {
75 self.will_be_executed = will_be_executed;
76 self
77 }
78}
79
80impl Debug for CLIStepPath {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "{}", self.path.display())
83 }
84}
85
86impl From<PathBuf> for CLIStepPath {
87 fn from(path: PathBuf) -> Self {
88 Self { path, will_be_executed: false }
89 }
90}
91
92struct StepExtra<'a> {
94 desc: &'a StepDescription,
95 should_run: ShouldRun<'a>,
96}
97
98struct StepToRun<'a> {
99 sort_index: usize,
100 desc: &'a StepDescription,
101 pathsets: Vec<PathSet>,
102}
103
104pub(crate) fn match_paths_to_steps_and_run(
105 builder: &Builder<'_>,
106 step_descs: &[StepDescription],
107 paths: &[PathBuf],
108) {
109 let steps = step_descs
112 .iter()
113 .map(|desc| StepExtra {
114 desc,
115 should_run: (desc.should_run)(ShouldRun::new(builder, desc.kind)),
116 })
117 .collect::<Vec<_>>();
118
119 if builder.download_rustc() && (builder.kind == Kind::Dist || builder.kind == Kind::Install) {
122 eprintln!(
123 "ERROR: '{}' subcommand is incompatible with `rust.download-rustc`.",
124 builder.kind.as_str()
125 );
126 crate::exit!(1);
127 }
128
129 for StepExtra { desc, should_run } in &steps {
131 assert!(!should_run.paths.is_empty(), "{:?} should have at least one pathset", desc.name);
132 }
133
134 if paths.is_empty() || builder.config.include_default_paths {
135 for StepExtra { desc, should_run } in &steps {
136 if desc.default && should_run.is_really_default() {
137 desc.maybe_run(builder, should_run.paths.iter().cloned().collect());
138 }
139 }
140 }
141
142 let mut paths: Vec<PathBuf> = paths
144 .iter()
145 .map(|original_path| {
146 let mut path = original_path.clone();
147
148 if !path.is_absolute() {
154 path = builder.src.join(path);
155 }
156
157 if !path.exists() {
159 return original_path.clone();
161 }
162
163 match std::path::absolute(&path) {
165 Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(),
166 Err(e) => {
167 eprintln!("ERROR: {e:?}");
168 panic!("Due to the above error, failed to resolve path: {path:?}");
169 }
170 }
171 })
172 .collect();
173
174 remap_paths(&mut paths);
175
176 paths.retain(|path| {
179 for StepExtra { desc, should_run } in &steps {
180 if let Some(suite) = should_run.is_suite_path(path) {
181 desc.maybe_run(builder, vec![suite.clone()]);
182 return false;
183 }
184 }
185 true
186 });
187
188 if paths.is_empty() {
189 return;
190 }
191
192 let mut paths: Vec<CLIStepPath> = paths.into_iter().map(|p| p.into()).collect();
193 let mut path_lookup: Vec<(CLIStepPath, bool)> =
194 paths.clone().into_iter().map(|p| (p, false)).collect();
195
196 let mut steps_to_run = vec![];
199
200 for StepExtra { desc, should_run } in &steps {
201 let pathsets = should_run.pathset_for_paths_removing_matches(&mut paths, desc.kind);
202
203 let mut closest_index = usize::MAX;
209
210 for (index, (path, is_used)) in path_lookup.iter_mut().enumerate() {
212 if !*is_used && !paths.contains(path) {
213 closest_index = index;
214 *is_used = true;
215 break;
216 }
217 }
218
219 steps_to_run.push(StepToRun { sort_index: closest_index, desc, pathsets });
220 }
221
222 steps_to_run.sort_by_key(|step| step.sort_index);
224
225 for StepToRun { sort_index: _, desc, pathsets } in steps_to_run {
227 if !pathsets.is_empty() {
228 desc.maybe_run(builder, pathsets);
229 }
230 }
231
232 paths.retain(|p| !p.will_be_executed);
233
234 if !paths.is_empty() {
235 eprintln!("ERROR: no `{}` rules matched {:?}", builder.kind.as_str(), paths);
236 eprintln!(
237 "HELP: run `x.py {} --help --verbose` to show a list of available paths",
238 builder.kind.as_str()
239 );
240 eprintln!(
241 "NOTE: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`"
242 );
243 crate::exit!(1);
244 }
245}