about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoss Smyth <crs2017@gmail.com>2024-02-26 17:19:30 -0500
committerRoss Smyth <crs2017@gmail.com>2024-03-02 19:45:54 -0500
commit32643dc8536212ef01c8b9c63674cee050c10b8e (patch)
tree28b2521ba01c5a8c7228b93c5fcd8ba4f5a02fb0
parentc414c08da3265390965ccc1f51d8da4f6b3375cb (diff)
downloadrust-32643dc8536212ef01c8b9c63674cee050c10b8e.tar.gz
rust-32643dc8536212ef01c8b9c63674cee050c10b8e.zip
Fix .\miri fmt on Windows
-rw-r--r--src/tools/miri/miri-script/src/commands.rs46
-rw-r--r--src/tools/miri/miri-script/src/util.rs47
2 files changed, 63 insertions, 30 deletions
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 88ee62fc18a..dc6ef58c520 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -526,37 +526,27 @@ impl Command {
     }
 
     fn fmt(flags: Vec<OsString>) -> Result<()> {
+        use itertools::Itertools;
+
         let e = MiriEnv::new()?;
-        let toolchain = &e.toolchain;
         let config_path = path!(e.miri_dir / "rustfmt.toml");
 
-        let mut cmd = cmd!(
-            e.sh,
-            "rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
-        );
-        eprintln!("$ {cmd} ...");
-
-        // Add all the filenames to the command.
-        // FIXME: `rustfmt` will follow the `mod` statements in these files, so we get a bunch of
-        // duplicate diffs.
-        for item in WalkDir::new(&e.miri_dir).into_iter().filter_entry(|entry| {
-            let name = entry.file_name().to_string_lossy();
-            let ty = entry.file_type();
-            if ty.is_file() {
-                name.ends_with(".rs")
-            } else {
-                // dir or symlink. skip `target` and `.git`.
-                &name != "target" && &name != ".git"
-            }
-        }) {
-            let item = item?;
-            if item.file_type().is_file() {
-                cmd = cmd.arg(item.into_path());
-            }
-        }
+        // Collect each rust file in the miri repo.
+        let files = WalkDir::new(&e.miri_dir)
+            .into_iter()
+            .filter_entry(|entry| {
+                let name = entry.file_name().to_string_lossy();
+                let ty = entry.file_type();
+                if ty.is_file() {
+                    name.ends_with(".rs")
+                } else {
+                    // dir or symlink. skip `target` and `.git`.
+                    &name != "target" && &name != ".git"
+                }
+            })
+            .filter_ok(|item| item.file_type().is_file())
+            .map_ok(|item| item.into_path());
 
-        // We want our own error message, repeating the command is too much.
-        cmd.quiet().run().map_err(|_| anyhow!("`rustfmt` failed"))?;
-        Ok(())
+        e.format_files(files, &e.toolchain[..], &config_path, &flags[..])
     }
 }
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index 420ecdab63c..5c020243240 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -1,7 +1,7 @@
 use std::ffi::{OsStr, OsString};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
-use anyhow::{Context, Result};
+use anyhow::{anyhow, Context, Result};
 use dunce::canonicalize;
 use path_macro::path;
 use xshell::{cmd, Shell};
@@ -145,4 +145,47 @@ impl MiriEnv {
         .run()?;
         Ok(())
     }
+
+    /// Receives an iterator of files.
+    /// Will format each file with the miri rustfmt config.
+    /// Does not follow module relationships.
+    pub fn format_files(
+        &self,
+        files: impl Iterator<Item = Result<PathBuf, walkdir::Error>>,
+        toolchain: &str,
+        config_path: &Path,
+        flags: &[OsString],
+    ) -> anyhow::Result<()> {
+        use itertools::Itertools;
+
+        let mut first = true;
+
+        // Format in batches as not all out files fit into Windows' command argument limit.
+        for batch in &files.chunks(256) {
+            // Build base command.
+            let mut cmd = cmd!(
+                self.sh,
+                "rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
+            );
+            if first {
+                eprintln!("$ {cmd} ...");
+                first = false;
+            }
+            // Add files.
+            for file in batch {
+                // Make it a relative path so that on platforms with extremely tight argument
+                // limits (like Windows), we become immune to someone cloning the repo
+                // 50 directories deep.
+                let file = file?;
+                let file = file.strip_prefix(&self.miri_dir)?;
+                cmd = cmd.arg(file);
+            }
+
+            // Run commands.
+            // We want our own error message, repeating the command is too much.
+            cmd.quiet().run().map_err(|_| anyhow!("`rustfmt` failed"))?;
+        }
+
+        Ok(())
+    }
 }