about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/run-make-support/src/fs.rs70
1 files changed, 44 insertions, 26 deletions
diff --git a/src/tools/run-make-support/src/fs.rs b/src/tools/run-make-support/src/fs.rs
index 2ca55ad3b3a..6e95897c646 100644
--- a/src/tools/run-make-support/src/fs.rs
+++ b/src/tools/run-make-support/src/fs.rs
@@ -1,7 +1,49 @@
 use std::io;
 use std::path::{Path, PathBuf};
 
-/// Copy a directory into another.
+/// Given a symlink at `src`, read its target, then create a new symlink at `dst` also pointing to
+/// target.
+pub fn copy_symlink(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
+    let src = src.as_ref();
+    let dst = dst.as_ref();
+    if let Err(e) = copy_symlink_raw(src, dst) {
+        panic!("failed to copy symlink from `{}` to `{}`: {e}", src.display(), dst.display(),);
+    }
+}
+
+fn copy_symlink_raw(ty: FileType, src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
+    // Traverse symlink once to find path of target entity.
+    let target_path = std::fs::read_link(src)?;
+
+    let new_symlink_path = dst.as_ref();
+    #[cfg(windows)]
+    {
+        use std::os::windows::fs::FileTypeExt;
+        if ty.is_symlink_dir() {
+            std::os::windows::fs::symlink_dir(&target_path, new_symlink_path)?;
+        } else {
+            // Target may be a file or another symlink, in any case we can use
+            // `symlink_file` here.
+            std::os::windows::fs::symlink_file(&target_path, new_symlink_path)?;
+        }
+    }
+    #[cfg(unix)]
+    {
+        let _ = ty;
+        std::os::unix::fs::symlink(target_path, new_symlink_path)?;
+    }
+    #[cfg(not(any(windows, unix)))]
+    {
+        let _ = ty;
+        // Technically there's also wasi, but I have no clue about wasi symlink
+        // semantics and which wasi targets / environment support symlinks.
+        unimplemented!("unsupported target");
+    }
+    Ok(())
+}
+
+/// Copy a directory into another. This will not traverse symlinks; instead, it will create new
+/// symlinks pointing at target paths that symlinks in the original directory points to.
 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();
@@ -14,31 +56,7 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
             if ty.is_dir() {
                 copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
             } else if ty.is_symlink() {
-                // Traverse symlink once to find path of target entity.
-                let target_path = std::fs::read_link(entry.path())?;
-
-                let new_symlink_path = dst.join(entry.file_name());
-                #[cfg(windows)]
-                {
-                    use std::os::windows::fs::FileTypeExt;
-                    if ty.is_symlink_dir() {
-                        std::os::windows::fs::symlink_dir(&target_path, new_symlink_path)?;
-                    } else {
-                        // Target may be a file or another symlink, in any case we can use
-                        // `symlink_file` here.
-                        std::os::windows::fs::symlink_file(&target_path, new_symlink_path)?;
-                    }
-                }
-                #[cfg(unix)]
-                {
-                    std::os::unix::fs::symlink(target_path, new_symlink_path)?;
-                }
-                #[cfg(not(any(windows, unix)))]
-                {
-                    // Technically there's also wasi, but I have no clue about wasi symlink
-                    // semantics and which wasi targets / environment support symlinks.
-                    unimplemented!("unsupported target");
-                }
+                copy_symlink_raw(entry.path(), dst.join(entry.file_name()))?;
             } else {
                 std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
             }