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