Skip to content

Commit 472c3a4

Browse files
jyn514WaffleLapkin
authored andcommitted
Allow multiple Steps to have the same path
In particular, this allows `CargoClippy` and `Clippy` to both use `src/tools/clippy` as the path.
1 parent 48a6cc7 commit 472c3a4

File tree

2 files changed

+30
-21
lines changed

2 files changed

+30
-21
lines changed

src/bootstrap/builder.rs

+27-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::any::{type_name, Any};
22
use std::cell::{Cell, RefCell};
3-
use std::collections::BTreeSet;
3+
use std::collections::{BTreeSet, HashSet};
44
use std::env;
55
use std::ffi::{OsStr, OsString};
66
use std::fmt::{Debug, Write};
@@ -197,28 +197,29 @@ impl PathSet {
197197
}
198198
}
199199

200-
/// Return all `TaskPath`s in `Self` that contain any of the `needles`, removing the
201-
/// matched needles.
200+
/// Return all `TaskPath`s in `Self` that contain any of the `needles`, as well as the matched
201+
/// needles.
202202
///
203203
/// This is used for `StepDescription::krate`, which passes all matching crates at once to
204204
/// `Step::make_run`, rather than calling it many times with a single crate.
205205
/// See `tests.rs` for examples.
206-
fn intersection_removing_matches(
206+
fn intersection_with_matches<'p>(
207207
&self,
208-
needles: &mut Vec<&Path>,
208+
needles: &[&'p Path],
209209
module: Option<Kind>,
210-
) -> PathSet {
210+
) -> (PathSet, Vec<&'p Path>) {
211+
let mut matched_paths = vec![];
211212
let mut check = |p| {
212-
for (i, n) in needles.iter().enumerate() {
213+
for n in needles {
213214
let matched = Self::check(p, n, module);
214215
if matched {
215-
needles.remove(i);
216+
matched_paths.push(*n);
216217
return true;
217218
}
218219
}
219220
false
220221
};
221-
match self {
222+
let pathset = match self {
222223
PathSet::Set(set) => PathSet::Set(set.iter().filter(|&p| check(p)).cloned().collect()),
223224
PathSet::Suite(suite) => {
224225
if check(suite) {
@@ -227,7 +228,8 @@ impl PathSet {
227228
PathSet::empty()
228229
}
229230
}
230-
}
231+
};
232+
(pathset, matched_paths)
231233
}
232234

233235
/// A convenience wrapper for Steps which know they have no aliases and all their sets contain only a single path.
@@ -315,6 +317,7 @@ impl StepDescription {
315317

316318
// Handle all test suite paths.
317319
// (This is separate from the loop below to avoid having to handle multiple paths in `is_suite_path` somehow.)
320+
// Note that unlike below, we don't allow multiple suite paths to share the same path.
318321
paths.retain(|path| {
319322
for (desc, should_run) in v.iter().zip(&should_runs) {
320323
if let Some(suite) = should_run.is_suite_path(&path) {
@@ -330,15 +333,19 @@ impl StepDescription {
330333
}
331334

332335
// Handle all PathSets.
336+
let mut seen_paths = HashSet::new();
333337
for (desc, should_run) in v.iter().zip(&should_runs) {
334-
let pathsets = should_run.pathset_for_paths_removing_matches(&mut paths, desc.kind);
338+
let (pathsets, matched) = should_run.pathset_for_paths_with_matches(&paths, desc.kind);
335339
if !pathsets.is_empty() {
340+
seen_paths.extend(matched);
336341
desc.maybe_run(builder, pathsets);
337342
}
338343
}
339344

340-
if !paths.is_empty() {
341-
eprintln!("error: no `{}` rules matched {:?}", builder.kind.as_str(), paths,);
345+
let cli_paths: HashSet<_> = paths.into_iter().collect();
346+
let missing_paths: Vec<_> = cli_paths.difference(&seen_paths).collect();
347+
if !missing_paths.is_empty() {
348+
eprintln!("error: no `{}` rules matched {:?}", builder.kind.as_str(), missing_paths);
342349
eprintln!(
343350
"help: run `x.py {} --help --verbose` to show a list of available paths",
344351
builder.kind.as_str()
@@ -500,19 +507,21 @@ impl<'a> ShouldRun<'a> {
500507
///
501508
/// The reason we return PathSet instead of PathBuf is to allow for aliases that mean the same thing
502509
/// (for now, just `all_krates` and `paths`, but we may want to add an `aliases` function in the future?)
503-
fn pathset_for_paths_removing_matches(
510+
fn pathset_for_paths_with_matches<'p>(
504511
&self,
505-
paths: &mut Vec<&Path>,
512+
paths: &[&'p Path],
506513
kind: Kind,
507-
) -> Vec<PathSet> {
514+
) -> (Vec<PathSet>, HashSet<&'p Path>) {
515+
let mut all_matched_paths = HashSet::new();
508516
let mut sets = vec![];
509517
for pathset in &self.paths {
510-
let subset = pathset.intersection_removing_matches(paths, Some(kind));
518+
let (subset, matched_paths) = pathset.intersection_with_matches(paths, Some(kind));
511519
if subset != PathSet::empty() {
512520
sets.push(subset);
521+
all_matched_paths.extend(matched_paths);
513522
}
514523
}
515-
sets
524+
(sets, all_matched_paths)
516525
}
517526
}
518527

src/bootstrap/builder/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ fn test_intersection() {
9393
let set = PathSet::Set(
9494
["library/core", "library/alloc", "library/std"].into_iter().map(TaskPath::parse).collect(),
9595
);
96-
let mut command_paths =
96+
let command_paths =
9797
vec![Path::new("library/core"), Path::new("library/alloc"), Path::new("library/stdarch")];
98-
let subset = set.intersection_removing_matches(&mut command_paths, None);
98+
let (subset, matched_paths) = set.intersection_with_matches(&command_paths, None);
9999
assert_eq!(
100100
subset,
101101
PathSet::Set(["library/core", "library/alloc"].into_iter().map(TaskPath::parse).collect())
102102
);
103-
assert_eq!(command_paths, vec![Path::new("library/stdarch")]);
103+
assert_eq!(matched_paths, vec![Path::new("library/alloc"), Path::new("library/core")]);
104104
}
105105

106106
#[test]

0 commit comments

Comments
 (0)