about summary refs log tree commit diff
path: root/src/bootstrap/format.rs
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2023-02-12 15:59:57 +0800
committer许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2023-02-14 01:47:12 +0800
commitb10d744b87fcaaeea1a2ec2a299dba494c1f3d82 (patch)
tree1317a33741507ba44dd8e986d5e4e0e2f2d38480 /src/bootstrap/format.rs
parentb7089e0dd3e988270f34f182d3749ea5fff5a18f (diff)
downloadrust-b10d744b87fcaaeea1a2ec2a299dba494c1f3d82.tar.gz
rust-b10d744b87fcaaeea1a2ec2a299dba494c1f3d82.zip
Allow shortcuts to directories to be used for `./x.py fmt`
Fixes #107944.

Maximum recursive search depth is 3 and only accepts shortcuts for
directories (single component paths, such as `./x.py fmt std`). If
there are no shortcut candidates but single componenet path(s) are
given, it falls back to the previous behavior to panic with unable to
find directory. If there are multiple shortcut candidates for a given
single component path, the shortcut candidates are considered
ambiguous, are then ignored, and the single component path is accepted
as-is.

After this change, `./x.py fmt std` no longer panics and formats
`library/std` instead.
Diffstat (limited to 'src/bootstrap/format.rs')
-rw-r--r--src/bootstrap/format.rs40
1 files changed, 38 insertions, 2 deletions
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 6c9c26faef6..615794958d0 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -193,10 +193,46 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     let (tx, rx): (SyncSender<PathBuf>, _) = std::sync::mpsc::sync_channel(128);
     let walker = match paths.get(0) {
         Some(first) => {
-            let mut walker = WalkBuilder::new(first);
+            let find_shortcut_candidates = |p: &PathBuf| {
+                let mut candidates = Vec::new();
+                for candidate in WalkBuilder::new(src.clone()).max_depth(Some(3)).build() {
+                    if let Ok(entry) = candidate {
+                        if let Some(dir_name) = p.file_name() {
+                            if entry.path().is_dir() && entry.file_name() == dir_name {
+                                candidates.push(entry.into_path());
+                            }
+                        }
+                    }
+                }
+                candidates
+            };
+
+            // Only try to look for shortcut candidates for single component paths like
+            // `std` and not for e.g. relative paths like `../library/std`.
+            let should_look_for_shortcut_dir = |p: &PathBuf| p.components().count() == 1;
+
+            let mut walker = if should_look_for_shortcut_dir(first) {
+                if let [single_candidate] = &find_shortcut_candidates(first)[..] {
+                    WalkBuilder::new(single_candidate)
+                } else {
+                    WalkBuilder::new(first)
+                }
+            } else {
+                WalkBuilder::new(first)
+            };
+
             for path in &paths[1..] {
-                walker.add(path);
+                if should_look_for_shortcut_dir(path) {
+                    if let [single_candidate] = &find_shortcut_candidates(path)[..] {
+                        walker.add(single_candidate);
+                    } else {
+                        walker.add(path);
+                    }
+                } else {
+                    walker.add(path);
+                }
             }
+
             walker
         }
         None => WalkBuilder::new(src.clone()),