3
3
use super :: utils;
4
4
use crate :: hash;
5
5
use git2:: {
6
- Delta , Diff , DiffDelta , DiffFormat , DiffHunk , DiffOptions , Patch ,
7
- Repository ,
6
+ Delta , Diff , DiffDelta , DiffFormat , DiffHunk , DiffOptions , Error ,
7
+ Patch , Repository ,
8
8
} ;
9
9
use scopetime:: scope_time;
10
10
use std:: { fs, path:: Path } ;
11
11
12
12
/// type of diff of a single line
13
- #[ derive( Copy , Clone , PartialEq , Hash ) ]
13
+ #[ derive( Copy , Clone , PartialEq , Hash , Debug ) ]
14
14
pub enum DiffLineType {
15
15
/// just surrounding line, no change
16
16
None ,
@@ -29,7 +29,7 @@ impl Default for DiffLineType {
29
29
}
30
30
31
31
///
32
- #[ derive( Default , Clone , Hash ) ]
32
+ #[ derive( Default , Clone , Hash , Debug ) ]
33
33
pub struct DiffLine {
34
34
///
35
35
pub content : String ,
@@ -57,7 +57,7 @@ impl From<DiffHunk<'_>> for HunkHeader {
57
57
}
58
58
59
59
/// single diff hunk
60
- #[ derive( Default , Clone , Hash ) ]
60
+ #[ derive( Default , Clone , Hash , Debug ) ]
61
61
pub struct Hunk {
62
62
/// hash of the hunk header
63
63
pub header_hash : u64 ,
@@ -66,7 +66,7 @@ pub struct Hunk {
66
66
}
67
67
68
68
/// collection of hunks, sum of all diff lines
69
- #[ derive( Default , Clone , Hash ) ]
69
+ #[ derive( Default , Clone , Hash , Debug ) ]
70
70
pub struct FileDiff {
71
71
/// list of hunks
72
72
pub hunks : Vec < Hunk > ,
@@ -79,7 +79,7 @@ pub(crate) fn get_diff_raw<'a>(
79
79
p : & str ,
80
80
stage : bool ,
81
81
reverse : bool ,
82
- ) -> ( Diff < ' a > , DiffOptions ) {
82
+ ) -> Result < Diff < ' a > , Error > {
83
83
let mut opt = DiffOptions :: new ( ) ;
84
84
opt. pathspec ( p) ;
85
85
opt. reverse ( reverse) ;
@@ -88,39 +88,38 @@ pub(crate) fn get_diff_raw<'a>(
88
88
// diff against head
89
89
if let Ok ( ref_head) = repo. head ( ) {
90
90
let parent =
91
- repo. find_commit ( ref_head. target ( ) . unwrap ( ) ) . unwrap ( ) ;
92
- let tree = parent. tree ( ) . unwrap ( ) ;
91
+ repo. find_commit ( ref_head. target ( ) . unwrap ( ) ) ? ;
92
+ let tree = parent. tree ( ) ? ;
93
93
repo. diff_tree_to_index (
94
94
Some ( & tree) ,
95
- Some ( & repo. index ( ) . unwrap ( ) ) ,
95
+ Some ( & repo. index ( ) ? ) ,
96
96
Some ( & mut opt) ,
97
- )
98
- . unwrap ( )
97
+ ) ?
99
98
} else {
100
99
repo. diff_tree_to_index (
101
100
None ,
102
- Some ( & repo. index ( ) . unwrap ( ) ) ,
101
+ Some ( & repo. index ( ) ? ) ,
103
102
Some ( & mut opt) ,
104
- )
105
- . unwrap ( )
103
+ ) ?
106
104
}
107
105
} else {
108
106
opt. include_untracked ( true ) ;
109
107
opt. recurse_untracked_dirs ( true ) ;
110
- repo. diff_index_to_workdir ( None , Some ( & mut opt) ) . unwrap ( )
108
+ repo. diff_index_to_workdir ( None , Some ( & mut opt) ) ?
111
109
} ;
112
110
113
- ( diff, opt )
111
+ Ok ( diff)
114
112
}
115
113
114
+ //TODO: return Option
116
115
///
117
116
pub fn get_diff ( repo_path : & str , p : String , stage : bool ) -> FileDiff {
118
117
scope_time ! ( "get_diff" ) ;
119
118
120
119
let repo = utils:: repo ( repo_path) ;
121
120
let repo_path = repo. path ( ) . parent ( ) . unwrap ( ) ;
122
121
123
- let ( diff, mut opt ) = get_diff_raw ( & repo, & p, stage, false ) ;
122
+ let diff = get_diff_raw ( & repo, & p, stage, false ) . unwrap ( ) ;
124
123
125
124
let mut res: FileDiff = FileDiff :: default ( ) ;
126
125
let mut current_lines = Vec :: new ( ) ;
@@ -172,26 +171,29 @@ pub fn get_diff(repo_path: &str, p: String, stage: bool) -> FileDiff {
172
171
let newfile_path =
173
172
repo_path. join ( delta. new_file ( ) . path ( ) . unwrap ( ) ) ;
174
173
175
- let newfile_content = new_file_content ( & newfile_path)
176
- . unwrap_or_else ( || String :: from ( "file not found" ) ) ;
177
-
178
- let mut patch = Patch :: from_buffers (
179
- & [ ] ,
180
- None ,
181
- newfile_content. as_bytes ( ) ,
182
- Some ( & newfile_path) ,
183
- Some ( & mut opt) ,
184
- )
185
- . unwrap ( ) ;
186
-
187
- patch
188
- . print ( & mut |_delta, hunk : Option < DiffHunk > , line : git2:: DiffLine | {
189
- put ( hunk, line) ;
190
- true
191
- } )
174
+ if let Some ( newfile_content) =
175
+ new_file_content ( & newfile_path)
176
+ {
177
+ let mut patch = Patch :: from_buffers (
178
+ & [ ] ,
179
+ None ,
180
+ newfile_content. as_bytes ( ) ,
181
+ Some ( & newfile_path) ,
182
+ None ,
183
+ )
192
184
. unwrap ( ) ;
193
185
194
- true
186
+ patch
187
+ . print ( & mut |_delta, hunk : Option < DiffHunk > , line : git2:: DiffLine | {
188
+ put ( hunk, line) ;
189
+ true
190
+ } )
191
+ . unwrap ( ) ;
192
+
193
+ true
194
+ } else {
195
+ false
196
+ }
195
197
} else {
196
198
false
197
199
}
@@ -226,8 +228,6 @@ fn new_file_content(path: &Path) -> Option<String> {
226
228
} else if meta. file_type ( ) . is_file ( ) {
227
229
if let Ok ( content) = fs:: read_to_string ( path) {
228
230
return Some ( content) ;
229
- } else {
230
- return Some ( String :: from ( "no text file" ) ) ;
231
231
}
232
232
}
233
233
}
@@ -245,7 +245,7 @@ mod tests {
245
245
} ;
246
246
use std:: {
247
247
fs:: { self , File } ,
248
- io:: Write ,
248
+ io:: { Error , Write } ,
249
249
path:: Path ,
250
250
} ;
251
251
@@ -391,4 +391,26 @@ mod tests {
391
391
392
392
assert_eq ! ( diff. hunks[ 0 ] . lines[ 1 ] . content, "test" ) ;
393
393
}
394
+
395
+ #[ test]
396
+ fn test_diff_new_binary_file_using_invalid_utf8 (
397
+ ) -> Result < ( ) , Error > {
398
+ let file_path = Path :: new ( "bar" ) ;
399
+ let ( _td, repo) = repo_init_empty ( ) ;
400
+ let root = repo. path ( ) . parent ( ) . unwrap ( ) ;
401
+ let repo_path = root. as_os_str ( ) . to_str ( ) . unwrap ( ) ;
402
+
403
+ File :: create ( & root. join ( file_path) ) ?
404
+ . write_all ( b"\xc3 \x28 " ) ?;
405
+
406
+ let diff = get_diff (
407
+ repo_path,
408
+ String :: from ( file_path. to_str ( ) . unwrap ( ) ) ,
409
+ false ,
410
+ ) ;
411
+
412
+ assert_eq ! ( diff. hunks. len( ) , 0 ) ;
413
+
414
+ Ok ( ( ) )
415
+ }
394
416
}
0 commit comments