@@ -33,12 +33,16 @@ struct Cli {
3333 /// Pattern to ignore during comparison
3434 #[ arg( long, env = "IGNORE_PATTERN" ) ]
3535 ignore : Option < String > ,
36+
37+ /// Show detailed differences when directories don't match
38+ #[ arg( long, env = "SHOW_DIFF" ) ]
39+ show_diff : bool ,
3640}
3741
3842fn main ( ) {
3943 let cli = Cli :: parse ( ) ;
4044
41- match directories_match ( & cli. dir1 , & cli. dir2 , cli. ignore . as_deref ( ) ) {
45+ match directories_match ( & cli. dir1 , & cli. dir2 , cli. ignore . as_deref ( ) , cli . show_diff ) {
4246 Ok ( true ) => process:: exit ( 0 ) ,
4347 Ok ( false ) => process:: exit ( 1 ) ,
4448 Err ( e) => {
@@ -48,7 +52,7 @@ fn main() {
4852 }
4953}
5054
51- fn directories_match ( dir1 : & str , dir2 : & str , ignore : Option < & str > ) -> Result < bool , Box < dyn Error > > {
55+ fn directories_match ( dir1 : & str , dir2 : & str , ignore : Option < & str > , show_diff : bool ) -> Result < bool , Box < dyn Error > > {
5256 let tree1 = MerkleTree :: builder ( dir1) . build ( ) ?;
5357 let tree2 = MerkleTree :: builder ( dir2) . build ( ) ?;
5458
@@ -62,21 +66,58 @@ fn directories_match(dir1: &str, dir2: &str, ignore: Option<&str>) -> Result<boo
6266 . map ( |i| ( i. path . relative . to_string ( ) , i. hash . to_hex_string ( ) ) )
6367 . collect ( ) ;
6468
65- Ok ( files1 == files2)
69+ let matches = files1 == files2;
70+ if !matches && show_diff {
71+ print_differences ( & files1, & files2, dir1, dir2) ;
72+ }
73+
74+ Ok ( matches)
6675}
6776
77+ // -- Helper functions --
78+
6879fn should_ignore_path ( relative_path : & camino:: Utf8Path , ignore : Option < & str > ) -> bool {
6980 let path_str = relative_path. as_str ( ) ;
70-
7181 // Ignore empty paths
7282 if path_str. is_empty ( ) {
7383 return true ;
7484 }
75-
85+
7686 // Apply ignore pattern if provided
7787 ignore. map_or ( false , |pattern| path_str. contains ( pattern) )
7888}
7989
90+ fn print_differences ( files1 : & HashMap < String , String > , files2 : & HashMap < String , String > , _dir1 : & str , dir2 : & str ) {
91+ let mut diff_count = 0 ;
92+
93+ // Find different and missing files
94+ for ( path, hash1) in files1 {
95+ match files2. get ( path) {
96+ Some ( hash2) if hash1 != hash2 => {
97+ println ! ( "📝 {}: content differs" , path) ;
98+ diff_count += 1 ;
99+ }
100+ None => {
101+ println ! ( "❌ {}: missing in {}" , path, dir2) ;
102+ diff_count += 1 ;
103+ }
104+ _ => { }
105+ }
106+ }
107+
108+ // Find extra files
109+ for path in files2. keys ( ) {
110+ if !files1. contains_key ( path) {
111+ println ! ( "➕ {}: extra in {}" , path, dir2) ;
112+ diff_count += 1 ;
113+ }
114+ }
115+
116+ println ! ( "\n ❌ Found {} differences" , diff_count) ;
117+ }
118+
119+ // -- Tests --
120+
80121#[ cfg( test) ]
81122mod tests {
82123 use super :: * ;
@@ -104,7 +145,7 @@ mod tests {
104145 write_file ( & dir1, "file.txt" , "content" ) ;
105146 write_file ( & dir2, "file.txt" , "content" ) ;
106147
107- assert ! ( directories_match( dir1. to_str( ) . unwrap( ) , dir2. to_str( ) . unwrap( ) , None ) . unwrap( ) ) ;
148+ assert ! ( directories_match( dir1. to_str( ) . unwrap( ) , dir2. to_str( ) . unwrap( ) , None , false ) . unwrap( ) ) ;
108149
109150 fs:: remove_dir_all ( & dir1) . ok ( ) ;
110151 fs:: remove_dir_all ( & dir2) . ok ( ) ;
@@ -122,7 +163,7 @@ mod tests {
122163 write_file ( & dir1, "file.txt" , "content A" ) ;
123164 write_file ( & dir2, "file.txt" , "content B" ) ;
124165
125- assert ! ( !directories_match( dir1. to_str( ) . unwrap( ) , dir2. to_str( ) . unwrap( ) , None ) . unwrap( ) ) ;
166+ assert ! ( !directories_match( dir1. to_str( ) . unwrap( ) , dir2. to_str( ) . unwrap( ) , None , false ) . unwrap( ) ) ;
126167
127168 fs:: remove_dir_all ( & dir1) . ok ( ) ;
128169 fs:: remove_dir_all ( & dir2) . ok ( ) ;
@@ -142,7 +183,7 @@ mod tests {
142183 write_file ( & dir1, "build-info/ignore.txt" , "diff1" ) ;
143184 write_file ( & dir2, "build-info/ignore.txt" , "diff2" ) ;
144185
145- assert ! ( directories_match( dir1. to_str( ) . unwrap( ) , dir2. to_str( ) . unwrap( ) , Some ( "build-info" ) ) . unwrap( ) ) ;
186+ assert ! ( directories_match( dir1. to_str( ) . unwrap( ) , dir2. to_str( ) . unwrap( ) , Some ( "build-info" ) , false ) . unwrap( ) ) ;
146187
147188 fs:: remove_dir_all ( & dir1) . ok ( ) ;
148189 fs:: remove_dir_all ( & dir2) . ok ( ) ;
0 commit comments