11use std:: io;
22use std:: path:: { Path , PathBuf } ;
33
4- /// Copy a directory into another.
4+ /// Given a symlink at `src`, read its target, then create a new symlink at `dst` also pointing to
5+ /// target.
6+ pub fn copy_symlink ( src : impl AsRef < Path > , dst : impl AsRef < Path > ) {
7+ let src = src. as_ref ( ) ;
8+ let dst = dst. as_ref ( ) ;
9+ if let Err ( e) = copy_symlink_raw ( src, dst) {
10+ panic ! ( "failed to copy symlink from `{}` to `{}`: {e}" , src. display( ) , dst. display( ) , ) ;
11+ }
12+ }
13+
14+ fn copy_symlink_raw ( ty : FileType , src : impl AsRef < Path > , dst : impl AsRef < Path > ) -> io:: Result < ( ) > {
15+ // Traverse symlink once to find path of target entity.
16+ let target_path = std:: fs:: read_link ( src) ?;
17+
18+ let new_symlink_path = dst. as_ref ( ) ;
19+ #[ cfg( windows) ]
20+ {
21+ use std:: os:: windows:: fs:: FileTypeExt ;
22+ if ty. is_symlink_dir ( ) {
23+ std:: os:: windows:: fs:: symlink_dir ( & target_path, new_symlink_path) ?;
24+ } else {
25+ // Target may be a file or another symlink, in any case we can use
26+ // `symlink_file` here.
27+ std:: os:: windows:: fs:: symlink_file ( & target_path, new_symlink_path) ?;
28+ }
29+ }
30+ #[ cfg( unix) ]
31+ {
32+ let _ = ty;
33+ std:: os:: unix:: fs:: symlink ( target_path, new_symlink_path) ?;
34+ }
35+ #[ cfg( not( any( windows, unix) ) ) ]
36+ {
37+ let _ = ty;
38+ // Technically there's also wasi, but I have no clue about wasi symlink
39+ // semantics and which wasi targets / environment support symlinks.
40+ unimplemented ! ( "unsupported target" ) ;
41+ }
42+ Ok ( ( ) )
43+ }
44+
45+ /// Copy a directory into another. This will not traverse symlinks; instead, it will create new
46+ /// symlinks pointing at target paths that symlinks in the original directory points to.
547pub fn copy_dir_all ( src : impl AsRef < Path > , dst : impl AsRef < Path > ) {
648 fn copy_dir_all_inner ( src : impl AsRef < Path > , dst : impl AsRef < Path > ) -> io:: Result < ( ) > {
749 let dst = dst. as_ref ( ) ;
@@ -14,31 +56,7 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
1456 if ty. is_dir ( ) {
1557 copy_dir_all_inner ( entry. path ( ) , dst. join ( entry. file_name ( ) ) ) ?;
1658 } else if ty. is_symlink ( ) {
17- // Traverse symlink once to find path of target entity.
18- let target_path = std:: fs:: read_link ( entry. path ( ) ) ?;
19-
20- let new_symlink_path = dst. join ( entry. file_name ( ) ) ;
21- #[ cfg( windows) ]
22- {
23- use std:: os:: windows:: fs:: FileTypeExt ;
24- if ty. is_symlink_dir ( ) {
25- std:: os:: windows:: fs:: symlink_dir ( & target_path, new_symlink_path) ?;
26- } else {
27- // Target may be a file or another symlink, in any case we can use
28- // `symlink_file` here.
29- std:: os:: windows:: fs:: symlink_file ( & target_path, new_symlink_path) ?;
30- }
31- }
32- #[ cfg( unix) ]
33- {
34- std:: os:: unix:: fs:: symlink ( target_path, new_symlink_path) ?;
35- }
36- #[ cfg( not( any( windows, unix) ) ) ]
37- {
38- // Technically there's also wasi, but I have no clue about wasi symlink
39- // semantics and which wasi targets / environment support symlinks.
40- unimplemented ! ( "unsupported target" ) ;
41- }
59+ copy_symlink_raw ( entry. path ( ) , dst. join ( entry. file_name ( ) ) ) ?;
4260 } else {
4361 std:: fs:: copy ( entry. path ( ) , dst. join ( entry. file_name ( ) ) ) ?;
4462 }
0 commit comments