@@ -3,18 +3,19 @@ use super::{
3
3
constants:: COULD_NOT_UNWRAP_FILENAME ,
4
4
diff_exit_status:: DiffExitStatus ,
5
5
file_data:: { FileData , LineReader } ,
6
- functions:: { check_existence, is_binary , system_time_to_rfc2822} ,
6
+ functions:: { check_existence, system_time_to_rfc2822} ,
7
7
hunks:: Hunks ,
8
8
} ;
9
9
use crate :: diff_util:: constants:: NO_NEW_LINE_AT_END_OF_FILE ;
10
10
use std:: {
11
11
cmp:: Reverse ,
12
12
collections:: HashMap ,
13
13
fmt:: Write ,
14
- fs:: { read_to_string , File } ,
14
+ fs:: { self , File } ,
15
15
io:: { self , BufReader , Read } ,
16
16
os:: unix:: fs:: MetadataExt ,
17
- path:: Path ,
17
+ path:: { Display , Path } ,
18
+ str,
18
19
} ;
19
20
20
21
pub struct FileDiff < ' a > {
@@ -46,72 +47,78 @@ impl<'a> FileDiff<'a> {
46
47
format_options : & FormatOptions ,
47
48
show_if_different : Option < String > ,
48
49
) -> io:: Result < DiffExitStatus > {
49
- if is_binary ( path1) ? || is_binary ( path2) ? {
50
- Self :: binary_file_diff ( path1, path2)
51
- } else {
52
- let content1 = read_to_string ( path1) ?. into_bytes ( ) ;
53
- let linereader1 = LineReader :: new ( & content1) ;
54
- let ends_with_newline1 = linereader1. ends_with_newline ( ) ;
55
- let mut lines1 = Vec :: new ( ) ;
56
- for line in linereader1 {
57
- if !format_options. ignore_trailing_white_spaces {
58
- lines1. push ( line) ;
59
- } else {
60
- lines1. push ( line. trim_end ( ) ) ;
50
+ let path1_vec = fs:: read ( path1) ?;
51
+ let path2_vec = fs:: read ( path2) ?;
52
+
53
+ // Try normal diff first
54
+ if let Ok ( path1_str) = str:: from_utf8 ( path1_vec. as_slice ( ) ) {
55
+ if let Ok ( path2_str) = str:: from_utf8 ( path2_vec. as_slice ( ) ) {
56
+ // Both files consist only of valid UTF-8 data
57
+ let linereader1 = LineReader :: new ( path1_str. as_bytes ( ) ) ;
58
+ let ends_with_newline1 = linereader1. ends_with_newline ( ) ;
59
+ let mut lines1 = Vec :: new ( ) ;
60
+ for line in linereader1 {
61
+ if !format_options. ignore_trailing_white_spaces {
62
+ lines1. push ( line) ;
63
+ } else {
64
+ lines1. push ( line. trim_end ( ) ) ;
65
+ }
61
66
}
62
- }
63
67
64
- let content2 = read_to_string ( path2 ) ? . into_bytes ( ) ;
65
- let linereader2 = LineReader :: new ( & content2 ) ;
66
- let ends_with_newline2 = linereader2 . ends_with_newline ( ) ;
67
- let mut lines2 = Vec :: new ( ) ;
68
- for line in linereader2 {
69
- if !format_options . ignore_trailing_white_spaces {
70
- lines2 . push ( line ) ;
71
- } else {
72
- lines2 . push ( line . trim_end ( ) ) ;
68
+ let linereader2 = LineReader :: new ( path2_str . as_bytes ( ) ) ;
69
+ let ends_with_newline2 = linereader2 . ends_with_newline ( ) ;
70
+ let mut lines2 = Vec :: new ( ) ;
71
+ for line in linereader2 {
72
+ if !format_options . ignore_trailing_white_spaces {
73
+ lines2 . push ( line ) ;
74
+ } else {
75
+ lines2 . push ( line . trim_end ( ) ) ;
76
+ }
73
77
}
74
- }
75
- let mut file1 = FileData :: get_file ( path1, lines1, ends_with_newline1) ?;
76
- let mut file2 = FileData :: get_file ( path2, lines2, ends_with_newline2) ?;
77
-
78
- let mut diff = FileDiff :: new ( & mut file1, & mut file2, format_options) ;
79
-
80
- // histogram diff
81
- let mut lcs_indices = vec ! [ -1_i32 ; diff. file1. lines( ) . len( ) ] ;
82
- let num_lines1 = diff. file1 . lines ( ) . len ( ) ;
83
- let num_lines2 = diff. file2 . lines ( ) . len ( ) ;
84
- FileDiff :: histogram_lcs (
85
- diff. file1 ,
86
- diff. file2 ,
87
- 0 ,
88
- num_lines1,
89
- 0 ,
90
- num_lines2,
91
- & mut lcs_indices,
92
- ) ;
78
+ let mut file1 = FileData :: get_file ( path1, lines1, ends_with_newline1) ?;
79
+ let mut file2 = FileData :: get_file ( path2, lines2, ends_with_newline2) ?;
80
+
81
+ let mut diff = FileDiff :: new ( & mut file1, & mut file2, format_options) ;
82
+
83
+ // histogram diff
84
+ let mut lcs_indices = vec ! [ -1_i32 ; diff. file1. lines( ) . len( ) ] ;
85
+ let num_lines1 = diff. file1 . lines ( ) . len ( ) ;
86
+ let num_lines2 = diff. file2 . lines ( ) . len ( ) ;
87
+ FileDiff :: histogram_lcs (
88
+ diff. file1 ,
89
+ diff. file2 ,
90
+ 0 ,
91
+ num_lines1,
92
+ 0 ,
93
+ num_lines2,
94
+ & mut lcs_indices,
95
+ ) ;
93
96
94
- diff. hunks
95
- . create_hunks_from_lcs ( & lcs_indices, num_lines1, num_lines2) ;
97
+ diff. hunks
98
+ . create_hunks_from_lcs ( & lcs_indices, num_lines1, num_lines2) ;
96
99
97
- if diff. hunks . hunk_count ( ) > 0 {
98
- diff. are_different = true ;
99
- }
100
+ if diff. hunks . hunk_count ( ) > 0 {
101
+ diff. are_different = true ;
102
+ }
100
103
101
- if diff. are_different {
102
- if let Some ( show_if_different) = show_if_different {
103
- println ! ( "{show_if_different}" ) ;
104
+ if diff. are_different {
105
+ if let Some ( show_if_different) = show_if_different {
106
+ println ! ( "{show_if_different}" ) ;
107
+ }
108
+ } else {
109
+ Self :: print_identical_message_if_appropriate (
110
+ format_options,
111
+ path1. display ( ) ,
112
+ path2. display ( ) ,
113
+ ) ;
104
114
}
105
- } else if format_options. report_identical_files {
106
- println ! (
107
- "Files {} and {} are identical" ,
108
- path1. display( ) ,
109
- path2. display( )
110
- ) ;
111
- }
112
115
113
- diff. print ( )
116
+ return diff. print ( ) ;
117
+ }
114
118
}
119
+
120
+ // Fall back to binary diff
121
+ Self :: binary_file_diff ( format_options, path1, path2)
115
122
}
116
123
117
124
pub fn file_dir_diff (
@@ -148,18 +155,33 @@ impl<'a> FileDiff<'a> {
148
155
}
149
156
}
150
157
151
- fn binary_file_diff ( file1_path : & Path , file2_path : & Path ) -> io:: Result < DiffExitStatus > {
152
- let differ_report = format ! (
153
- "Binary files {} and {} differ" ,
154
- file1_path. display( ) ,
155
- file2_path. display( )
156
- ) ;
158
+ fn print_identical_message_if_appropriate (
159
+ format_options : & FormatOptions ,
160
+ path_1_display : Display ,
161
+ path_2_display : Display ,
162
+ ) {
163
+ if format_options. report_identical_files {
164
+ println ! ( "Files {path_1_display} and {path_2_display} are identical" , ) ;
165
+ }
166
+ }
167
+
168
+ fn binary_file_diff (
169
+ format_options : & FormatOptions ,
170
+ file1_path : & Path ,
171
+ file2_path : & Path ,
172
+ ) -> io:: Result < DiffExitStatus > {
173
+ let file1_path_display = file1_path. display ( ) ;
174
+ let file2_path_display = file2_path. display ( ) ;
175
+
176
+ let differ_report =
177
+ format ! ( "Binary files {file1_path_display} and {file2_path_display} differ" , ) ;
157
178
158
179
let file1 = File :: open ( file1_path) ?;
159
180
let file2 = File :: open ( file2_path) ?;
160
181
161
182
if file1. metadata ( ) ?. size ( ) != file2. metadata ( ) ?. size ( ) {
162
- println ! ( "{}" , differ_report) ;
183
+ println ! ( "{differ_report}" ) ;
184
+
163
185
return Ok ( DiffExitStatus :: Different ) ;
164
186
}
165
187
@@ -168,12 +190,20 @@ impl<'a> FileDiff<'a> {
168
190
169
191
for bytes_pair in file1. bytes ( ) . zip ( file2. bytes ( ) ) {
170
192
let ( b1, b2) = ( bytes_pair. 0 ?, bytes_pair. 1 ?) ;
193
+
171
194
if b1 != b2 {
172
- println ! ( "{}" , differ_report) ;
195
+ println ! ( "{differ_report}" ) ;
196
+
173
197
return Ok ( DiffExitStatus :: Different ) ;
174
198
}
175
199
}
176
200
201
+ Self :: print_identical_message_if_appropriate (
202
+ format_options,
203
+ file1_path_display,
204
+ file2_path_display,
205
+ ) ;
206
+
177
207
Ok ( DiffExitStatus :: NotDifferent )
178
208
}
179
209
0 commit comments