11use pipe_trait:: Pipe ;
2- use std:: { collections:: HashSet , fs:: canonicalize, io, mem:: take, path:: PathBuf } ;
2+ use std:: {
3+ collections:: HashSet ,
4+ fs:: { canonicalize, symlink_metadata} ,
5+ io,
6+ mem:: take,
7+ path:: PathBuf ,
8+ } ;
39
410/// Mockable APIs to interact with the system.
511pub trait Api {
612 type Argument ;
713 type RealPath : Eq ;
814 type RealPathError ;
915 fn canonicalize ( path : & Self :: Argument ) -> Result < Self :: RealPath , Self :: RealPathError > ;
16+ fn is_real_dir ( path : & Self :: Argument ) -> bool ;
1017 fn starts_with ( a : & Self :: RealPath , b : & Self :: RealPath ) -> bool ;
1118}
1219
@@ -21,6 +28,11 @@ impl Api for RealApi {
2128 canonicalize ( path)
2229 }
2330
31+ fn is_real_dir ( path : & Self :: Argument ) -> bool {
32+ path. pipe ( symlink_metadata)
33+ . is_ok_and ( |metadata| !metadata. is_symlink ( ) && metadata. is_dir ( ) )
34+ }
35+
2436 fn starts_with ( a : & Self :: RealPath , b : & Self :: RealPath ) -> bool {
2537 a. starts_with ( b)
2638 }
@@ -43,13 +55,20 @@ pub fn deduplicate_arguments<Api: self::Api>(arguments: &mut Vec<Api::Argument>)
4355pub fn find_argument_duplications_to_remove < Api : self :: Api > (
4456 arguments : & [ Api :: Argument ] ,
4557) -> HashSet < usize > {
46- let real_paths: Vec < _ > = arguments. iter ( ) . map ( Api :: canonicalize) . collect ( ) ;
58+ let real_paths: Vec < _ > = arguments
59+ . iter ( )
60+ . map ( |path| {
61+ Api :: is_real_dir ( path)
62+ . then ( || Api :: canonicalize ( path) )
63+ . and_then ( Result :: ok)
64+ } )
65+ . collect ( ) ;
4766 assert_eq ! ( arguments. len( ) , real_paths. len( ) ) ;
4867
4968 let mut to_remove = HashSet :: new ( ) ;
5069 for left_index in 0 ..arguments. len ( ) {
5170 for right_index in ( left_index + 1 ) ..arguments. len ( ) {
52- if let ( Ok ( left) , Ok ( right) ) = ( & real_paths[ left_index] , & real_paths[ right_index] ) {
71+ if let ( Some ( left) , Some ( right) ) = ( & real_paths[ left_index] , & real_paths[ right_index] ) {
5372 // both paths are the same, remove the second one
5473 if left == right {
5574 to_remove. insert ( right_index) ;
@@ -148,6 +167,13 @@ mod tests {
148167 . pipe ( Ok )
149168 }
150169
170+ fn is_real_dir ( path : & Self :: Argument ) -> bool {
171+ let path = PathBuf :: from ( path) . normalize ( ) ;
172+ MOCKED_SYMLINKS
173+ . iter ( )
174+ . all ( |( link, _) | PathBuf :: from ( link) . normalize ( ) != path)
175+ }
176+
151177 fn starts_with ( a : & Self :: RealPath , b : & Self :: RealPath ) -> bool {
152178 a. starts_with ( b)
153179 }
0 commit comments