Skip to content

Commit eeff9c2

Browse files
committed
Add wrappers for git_index_conflict_{add,remove,get,cleanup}
1 parent e6aa666 commit eeff9c2

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed

libgit2-sys/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2923,6 +2923,7 @@ extern "C" {
29232923
our_entry: *const git_index_entry,
29242924
their_entry: *const git_index_entry,
29252925
) -> c_int;
2926+
pub fn git_index_conflict_cleanup(index: *mut git_index) -> c_int;
29262927
pub fn git_index_conflict_remove(index: *mut git_index, path: *const c_char) -> c_int;
29272928
pub fn git_index_conflict_get(
29282929
ancestor_out: *mut *const git_index_entry,

src/index.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,182 @@ impl Index {
412412
unsafe { raw::git_index_has_conflicts(self.raw) == 1 }
413413
}
414414

415+
/// Add or update index entries to represent a conflict. Any staged entries
416+
/// that exist at the given paths will be removed.
417+
///
418+
/// The entries are the entries from the tree included in the merge. Any entry
419+
/// may be `None` to indicate that that file was not present in the trees during
420+
/// the merge. For example, ancestor_entry may be `None` to indicate that a file
421+
/// was added in both branches and must be resolved.
422+
pub fn conflict_add(
423+
&self,
424+
ancestor_entry: Option<&IndexEntry>,
425+
our_entry: Option<&IndexEntry>,
426+
their_entry: Option<&IndexEntry>,
427+
) -> Result<(), Error> {
428+
let mut ancestor_raw: Option<raw::git_index_entry> = None;
429+
let mut our_raw: Option<raw::git_index_entry> = None;
430+
let mut their_raw: Option<raw::git_index_entry> = None;
431+
432+
if let Some(ancestor_entry) = ancestor_entry {
433+
let ancestor_path = CString::new(&ancestor_entry.path[..])?;
434+
let mut ancestor_flags = ancestor_entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
435+
436+
if ancestor_entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
437+
ancestor_flags |= ancestor_entry.path.len() as u16;
438+
} else {
439+
ancestor_flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
440+
}
441+
442+
unsafe {
443+
ancestor_raw = Some(raw::git_index_entry {
444+
dev: ancestor_entry.dev,
445+
ino: ancestor_entry.ino,
446+
mode: ancestor_entry.mode,
447+
uid: ancestor_entry.uid,
448+
gid: ancestor_entry.gid,
449+
file_size: ancestor_entry.file_size,
450+
id: *ancestor_entry.id.raw(),
451+
flags: ancestor_flags,
452+
flags_extended: ancestor_entry.flags_extended,
453+
path: ancestor_path.as_ptr(),
454+
mtime: raw::git_index_time {
455+
seconds: ancestor_entry.mtime.seconds(),
456+
nanoseconds: ancestor_entry.mtime.nanoseconds(),
457+
},
458+
ctime: raw::git_index_time {
459+
seconds: ancestor_entry.ctime.seconds(),
460+
nanoseconds: ancestor_entry.ctime.nanoseconds(),
461+
},
462+
});
463+
}
464+
}
465+
466+
if let Some(our_entry) = our_entry {
467+
let our_path = CString::new(&our_entry.path[..])?;
468+
let mut our_flags = our_entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
469+
470+
if our_entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
471+
our_flags |= our_entry.path.len() as u16;
472+
} else {
473+
our_flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
474+
}
475+
476+
unsafe {
477+
our_raw = Some(raw::git_index_entry {
478+
dev: our_entry.dev,
479+
ino: our_entry.ino,
480+
mode: our_entry.mode,
481+
uid: our_entry.uid,
482+
gid: our_entry.gid,
483+
file_size: our_entry.file_size,
484+
id: *our_entry.id.raw(),
485+
flags: our_flags,
486+
flags_extended: our_entry.flags_extended,
487+
path: our_path.as_ptr(),
488+
mtime: raw::git_index_time {
489+
seconds: our_entry.mtime.seconds(),
490+
nanoseconds: our_entry.mtime.nanoseconds(),
491+
},
492+
ctime: raw::git_index_time {
493+
seconds: our_entry.ctime.seconds(),
494+
nanoseconds: our_entry.ctime.nanoseconds(),
495+
},
496+
});
497+
}
498+
}
499+
500+
if let Some(their_entry) = their_entry {
501+
let their_path = CString::new(&their_entry.path[..])?;
502+
let mut their_flags = their_entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
503+
504+
if their_entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
505+
their_flags |= their_entry.path.len() as u16;
506+
} else {
507+
their_flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
508+
}
509+
510+
unsafe {
511+
their_raw = Some(raw::git_index_entry {
512+
dev: their_entry.dev,
513+
ino: their_entry.ino,
514+
mode: their_entry.mode,
515+
uid: their_entry.uid,
516+
gid: their_entry.gid,
517+
file_size: their_entry.file_size,
518+
id: *their_entry.id.raw(),
519+
flags: their_flags,
520+
flags_extended: their_entry.flags_extended,
521+
path: their_path.as_ptr(),
522+
mtime: raw::git_index_time {
523+
seconds: their_entry.mtime.seconds(),
524+
nanoseconds: their_entry.mtime.nanoseconds(),
525+
},
526+
ctime: raw::git_index_time {
527+
seconds: their_entry.ctime.seconds(),
528+
nanoseconds: their_entry.ctime.nanoseconds(),
529+
},
530+
});
531+
}
532+
}
533+
534+
let ancestor_raw_ptr = ancestor_raw.as_ref().map_or_else(std::ptr::null, |ptr| ptr);
535+
let our_raw_ptr = our_raw.as_ref().map_or_else(std::ptr::null, |ptr| ptr);
536+
let their_raw_ptr = their_raw.as_ref().map_or_else(std::ptr::null, |ptr| ptr);
537+
unsafe {
538+
try_call!(raw::git_index_conflict_add(self.raw, ancestor_raw_ptr, our_raw_ptr, their_raw_ptr));
539+
Ok(())
540+
}
541+
}
542+
543+
/// Remove all conflicts in the index (entries with a stage greater than 0).
544+
pub fn conflict_cleanup(&self) -> Result<(), Error> {
545+
unsafe {
546+
try_call!(raw::git_index_conflict_cleanup(self.raw));
547+
Ok(())
548+
}
549+
}
550+
551+
/// Get the index entries that represent a conflict of a single file.
552+
///
553+
/// The entries are not modifiable.
554+
pub fn conflict_get(&self, path: &Path) -> Result<IndexConflict, Error> {
555+
let path = path_to_repo_path(path)?;
556+
let mut ancestor = ptr::null();
557+
let mut our = ptr::null();
558+
let mut their = ptr::null();
559+
560+
unsafe {
561+
try_call!(
562+
raw::git_index_conflict_get(&mut ancestor, &mut our, &mut their, self.raw, path)
563+
);
564+
Ok(IndexConflict {
565+
ancestor: match ancestor.is_null() {
566+
false => Some(IndexEntry::from_raw(*ancestor)),
567+
true => None,
568+
},
569+
our: match our.is_null() {
570+
false => Some(IndexEntry::from_raw(*our)),
571+
true => None,
572+
},
573+
their: match their.is_null() {
574+
false => Some(IndexEntry::from_raw(*their)),
575+
true => None,
576+
},
577+
})
578+
}
579+
}
580+
581+
/// Removes the index entries that represent a conflict of a single file.
582+
pub fn conflict_remove(&self, path: &Path) -> Result<(), Error> {
583+
let path = path_to_repo_path(path)?;
584+
585+
unsafe {
586+
try_call!(raw::git_index_conflict_remove(self.raw, path));
587+
Ok(())
588+
}
589+
}
590+
415591
/// Get the full path to the index file on disk.
416592
///
417593
/// Returns `None` if this is an in-memory index.

0 commit comments

Comments
 (0)