1
- use libc:: c_uint;
1
+ use libc:: { c_uint, c_ushort} ;
2
+ use std:: ffi:: CString ;
2
3
use std:: marker;
3
4
use std:: mem;
5
+ use std:: ptr;
4
6
use std:: str;
5
7
6
8
use crate :: call:: Convert ;
7
9
use crate :: util:: Binding ;
8
10
use crate :: { raw, Commit , FileFavor , Oid } ;
11
+ use crate :: IntoCString ;
9
12
10
13
/// A structure to represent an annotated commit, the input to merge and rebase.
11
14
///
@@ -22,6 +25,20 @@ pub struct MergeOptions {
22
25
raw : raw:: git_merge_options ,
23
26
}
24
27
28
+ /// Options for merging a file.
29
+ pub struct MergeFileOptions {
30
+ ancestor_label : Option < CString > ,
31
+ our_label : Option < CString > ,
32
+ their_label : Option < CString > ,
33
+ raw : raw:: git_merge_file_options ,
34
+ }
35
+
36
+ /// Information about file-level merging.
37
+ pub struct MergeFileResult < ' repo > {
38
+ raw : raw:: git_merge_file_result ,
39
+ _marker : marker:: PhantomData < & ' repo str > ,
40
+ }
41
+
25
42
impl < ' repo > AnnotatedCommit < ' repo > {
26
43
/// Gets the commit ID that the given git_annotated_commit refers to
27
44
pub fn id ( & self ) -> Oid {
@@ -192,3 +209,208 @@ impl<'repo> Drop for AnnotatedCommit<'repo> {
192
209
unsafe { raw:: git_annotated_commit_free ( self . raw ) }
193
210
}
194
211
}
212
+
213
+ impl Default for MergeFileOptions {
214
+ fn default ( ) -> Self {
215
+ Self :: new ( )
216
+ }
217
+ }
218
+
219
+ impl MergeFileOptions {
220
+ /// Creates a default set of merge file options.
221
+ pub fn new ( ) -> MergeFileOptions {
222
+ let mut opts = MergeFileOptions {
223
+ ancestor_label : None ,
224
+ our_label : None ,
225
+ their_label : None ,
226
+ raw : unsafe { mem:: zeroed ( ) } ,
227
+ } ;
228
+ assert_eq ! ( unsafe { raw:: git_merge_file_options_init( & mut opts. raw, 1 ) } , 0 ) ;
229
+ opts
230
+ }
231
+
232
+ /// Label for the ancestor file side of the conflict which will be prepended
233
+ /// to labels in diff3-format merge files.
234
+ pub fn ancestor_label < T : IntoCString > ( & mut self , t : T ) -> & mut MergeFileOptions {
235
+ self . ancestor_label = Some ( t. into_c_string ( ) . unwrap ( ) ) ;
236
+
237
+ self . raw . ancestor_label = self
238
+ . ancestor_label
239
+ . as_ref ( )
240
+ . map ( |s| s. as_ptr ( ) )
241
+ . unwrap_or ( ptr:: null ( ) ) ;
242
+
243
+ self
244
+ }
245
+
246
+ /// Label for our file side of the conflict which will be prepended to labels
247
+ /// in merge files.
248
+ pub fn our_label < T : IntoCString > ( & mut self , t : T ) -> & mut MergeFileOptions {
249
+ self . our_label = Some ( t. into_c_string ( ) . unwrap ( ) ) ;
250
+
251
+ self . raw . our_label = self
252
+ . our_label
253
+ . as_ref ( )
254
+ . map ( |s| s. as_ptr ( ) )
255
+ . unwrap_or ( ptr:: null ( ) ) ;
256
+
257
+ self
258
+ }
259
+
260
+ /// Label for their file side of the conflict which will be prepended to labels
261
+ /// in merge files.
262
+ pub fn their_label < T : IntoCString > ( & mut self , t : T ) -> & mut MergeFileOptions {
263
+ self . their_label = Some ( t. into_c_string ( ) . unwrap ( ) ) ;
264
+
265
+ self . raw . their_label = self
266
+ . their_label
267
+ . as_ref ( )
268
+ . map ( |s| s. as_ptr ( ) )
269
+ . unwrap_or ( ptr:: null ( ) ) ;
270
+
271
+ self
272
+ }
273
+
274
+ /// Specify a side to favor for resolving conflicts
275
+ pub fn favor ( & mut self , favor : FileFavor ) -> & mut MergeFileOptions {
276
+ self . raw . favor = favor. convert ( ) ;
277
+ self
278
+ }
279
+
280
+ fn flag ( & mut self , opt : u32 , val : bool ) -> & mut MergeFileOptions {
281
+ if val {
282
+ self . raw . flags |= opt;
283
+ } else {
284
+ self . raw . flags &= !opt;
285
+ }
286
+ self
287
+ }
288
+
289
+ /// Create standard conflicted merge files
290
+ pub fn style_standard ( & mut self , standard : bool ) -> & mut MergeFileOptions {
291
+ self . flag ( raw:: GIT_MERGE_FILE_STYLE_MERGE as u32 , standard)
292
+ }
293
+
294
+ /// Create diff3-style file
295
+ pub fn style_diff3 ( & mut self , diff3 : bool ) -> & mut MergeFileOptions {
296
+ self . flag ( raw:: GIT_MERGE_FILE_STYLE_DIFF3 as u32 , diff3)
297
+ }
298
+
299
+ /// Condense non-alphanumeric regions for simplified diff file
300
+ pub fn simplify_alnum ( & mut self , simplify : bool ) -> & mut MergeFileOptions {
301
+ self . flag ( raw:: GIT_MERGE_FILE_SIMPLIFY_ALNUM as u32 , simplify)
302
+ }
303
+
304
+ /// Ignore all whitespace
305
+ pub fn ignore_whitespace ( & mut self , ignore : bool ) -> & mut MergeFileOptions {
306
+ self . flag ( raw:: GIT_MERGE_FILE_IGNORE_WHITESPACE as u32 , ignore)
307
+ }
308
+
309
+ /// Ignore changes in amount of whitespace
310
+ pub fn ignore_whitespace_change ( & mut self , ignore : bool ) -> & mut MergeFileOptions {
311
+ self . flag ( raw:: GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE as u32 , ignore)
312
+ }
313
+
314
+ /// Ignore whitespace at end of line
315
+ pub fn ignore_whitespace_eol ( & mut self , ignore : bool ) -> & mut MergeFileOptions {
316
+ self . flag ( raw:: GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL as u32 , ignore)
317
+ }
318
+
319
+ /// Use the "patience diff" algorithm
320
+ pub fn patience ( & mut self , patience : bool ) -> & mut MergeFileOptions {
321
+ self . flag ( raw:: GIT_MERGE_FILE_DIFF_PATIENCE as u32 , patience)
322
+ }
323
+
324
+ /// Take extra time to find minimal diff
325
+ pub fn minimal ( & mut self , minimal : bool ) -> & mut MergeFileOptions {
326
+ self . flag ( raw:: GIT_MERGE_FILE_DIFF_MINIMAL as u32 , minimal)
327
+ }
328
+
329
+ /// Create zdiff3 ("zealous diff3")-style files
330
+ pub fn style_zdiff3 ( & mut self , zdiff3 : bool ) -> & mut MergeFileOptions {
331
+ self . flag ( raw:: GIT_MERGE_FILE_STYLE_ZDIFF3 as u32 , zdiff3)
332
+ }
333
+
334
+ /// Do not produce file conflicts when common regions have changed
335
+ pub fn accept_conflicts ( & mut self , accept : bool ) -> & mut MergeFileOptions {
336
+ self . flag ( raw:: GIT_MERGE_FILE_ACCEPT_CONFLICTS as u32 , accept)
337
+ }
338
+
339
+ /// The size of conflict markers (eg, "<<<<<<<"). Default is 7.
340
+ pub fn marker_size ( & mut self , size : u16 ) -> & mut MergeFileOptions {
341
+ self . raw . marker_size = size as c_ushort ;
342
+ self
343
+ }
344
+
345
+ /// Acquire a pointer to the underlying raw options.
346
+ pub unsafe fn raw ( & mut self ) -> * const raw:: git_merge_file_options {
347
+ & self . raw as * const _
348
+ }
349
+ }
350
+
351
+ impl < ' repo > MergeFileResult < ' repo > {
352
+ /// True if the output was automerged, false if the output contains
353
+ /// conflict markers.
354
+ pub fn is_automergeable ( & self ) -> bool {
355
+ self . raw . automergeable > 0
356
+ }
357
+
358
+ /// The path that the resultant merge file should use.
359
+ ///
360
+ /// returns `None` if a filename conflict would occur,
361
+ /// or if the path is not valid utf-8
362
+ pub fn path ( & self ) -> Option < & str > {
363
+ self . path_bytes ( ) . and_then ( |bytes| str:: from_utf8 ( bytes) . ok ( ) )
364
+ }
365
+
366
+ /// Gets the path as a byte slice.
367
+ pub fn path_bytes ( & self ) -> Option < & [ u8 ] > {
368
+ unsafe { crate :: opt_bytes ( self , self . raw . path ) }
369
+ }
370
+
371
+ /// The mode that the resultant merge file should use.
372
+ pub fn mode ( & self ) -> u32 {
373
+ self . raw . mode as u32
374
+ }
375
+
376
+ /// The contents of the merge.
377
+ pub fn content ( & self ) -> & ' repo [ u8 ] {
378
+ unsafe {
379
+ std:: slice:: from_raw_parts (
380
+ self . raw . ptr as * const u8 ,
381
+ self . raw . len as usize ,
382
+ )
383
+ }
384
+ }
385
+ }
386
+
387
+ impl < ' repo > Binding for MergeFileResult < ' repo > {
388
+ type Raw = raw:: git_merge_file_result ;
389
+ unsafe fn from_raw ( raw : raw:: git_merge_file_result ) -> MergeFileResult < ' repo > {
390
+ MergeFileResult {
391
+ raw,
392
+ _marker : marker:: PhantomData ,
393
+ }
394
+ }
395
+ fn raw ( & self ) -> raw:: git_merge_file_result {
396
+ self . raw
397
+ }
398
+ }
399
+
400
+ impl < ' repo > Drop for MergeFileResult < ' repo > {
401
+ fn drop ( & mut self ) {
402
+ unsafe { raw:: git_merge_file_result_free ( & mut self . raw ) }
403
+ }
404
+ }
405
+
406
+ impl < ' repo > std:: fmt:: Display for MergeFileResult < ' repo > {
407
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
408
+ let mut ds = f. debug_struct ( "MergeFileResult" ) ;
409
+ if let Some ( path) = & self . path ( ) {
410
+ ds. field ( "path" , path) ;
411
+ }
412
+ ds. field ( "automergeable" , & self . is_automergeable ( ) ) ;
413
+ ds. field ( "mode" , & self . mode ( ) ) ;
414
+ ds. finish ( )
415
+ }
416
+ }
0 commit comments