about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2024-05-25 13:03:23 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2024-05-27 14:41:19 +0200
commit90fec5a0873c82674890a9f67b73a4f0a35e9d0b (patch)
tree77fe03f65d47a4d580acff9765e4b8cfee628266
parent21e6de7eb64c09102de3f100420a09edc1a2a8d7 (diff)
downloadrust-90fec5a0873c82674890a9f67b73a4f0a35e9d0b.tar.gz
rust-90fec5a0873c82674890a9f67b73a4f0a35e9d0b.zip
Add `copy_dir_all` and `recursive_diff` functions to `run-make-support`
-rw-r--r--src/tools/run-make-support/src/lib.rs67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 9854d91e19e..d96c8b89127 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -12,6 +12,8 @@ pub mod rustc;
 pub mod rustdoc;
 
 use std::env;
+use std::fs;
+use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Output};
 
@@ -201,6 +203,71 @@ pub fn set_host_rpath(cmd: &mut Command) {
     });
 }
 
+/// Copy a directory into another.
+pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
+    fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
+        let dst = dst.as_ref();
+        if !dst.is_dir() {
+            fs::create_dir_all(&dst)?;
+        }
+        for entry in fs::read_dir(src)? {
+            let entry = entry?;
+            let ty = entry.file_type()?;
+            if ty.is_dir() {
+                copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
+            } else {
+                fs::copy(entry.path(), dst.join(entry.file_name()))?;
+            }
+        }
+        Ok(())
+    }
+
+    if let Err(e) = copy_dir_all_inner(&src, &dst) {
+        // Trying to give more context about what exactly caused the failure
+        panic!(
+            "failed to copy `{}` to `{}`: {:?}",
+            src.as_ref().display(),
+            dst.as_ref().display(),
+            e
+        );
+    }
+}
+
+/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise.
+pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
+    fn read_file(path: &Path) -> Vec<u8> {
+        match fs::read(path) {
+            Ok(c) => c,
+            Err(e) => panic!("Failed to read `{}`: {:?}", path.display(), e),
+        }
+    }
+
+    let dir2 = dir2.as_ref();
+    for entry in fs::read_dir(dir1).unwrap() {
+        let entry = entry.unwrap();
+        let entry_name = entry.file_name();
+        let path = entry.path();
+
+        if path.is_dir() {
+            recursive_diff(&path, &dir2.join(entry_name));
+        } else {
+            let path2 = dir2.join(entry_name);
+            let file1 = read_file(&path);
+            let file2 = read_file(&path2);
+
+            // We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
+            // Why not using String? Because there might be minified files or even potentially
+            // binary ones, so that would display useless output.
+            assert!(
+                file1 == file2,
+                "`{}` and `{}` have different content",
+                path.display(),
+                path2.display(),
+            );
+        }
+    }
+}
+
 /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
 /// containing a `cmd: Command` field and a `output` function. The provided helpers are:
 ///