1 use std::marker; 2 use std::mem; 3 use libc::c_uint; 4 5 use {raw, Oid, Commit, FileFavor}; 6 use util::Binding; 7 use call::Convert; 8 9 /// A structure to represent an annotated commit, the input to merge and rebase. 10 /// 11 /// An annotated commit contains information about how it was looked up, which 12 /// may be useful for functions like merge or rebase to provide context to the 13 /// operation. 14 pub struct AnnotatedCommit<'repo> { 15 raw: *mut raw::git_annotated_commit, 16 _marker: marker::PhantomData<Commit<'repo>>, 17 } 18 19 /// Options to specify when merging. 20 pub struct MergeOptions { 21 raw: raw::git_merge_options, 22 } 23 24 impl<'repo> AnnotatedCommit<'repo> { 25 /// Gets the commit ID that the given git_annotated_commit refers to id(&self) -> Oid26 pub fn id(&self) -> Oid { 27 unsafe { Binding::from_raw(raw::git_annotated_commit_id(self.raw)) } 28 } 29 } 30 31 impl Default for MergeOptions { default() -> Self32 fn default() -> Self { 33 Self::new() 34 } 35 } 36 37 impl MergeOptions { 38 /// Creates a default set of merge options. new() -> MergeOptions39 pub fn new() -> MergeOptions { 40 let mut opts = MergeOptions { 41 raw: unsafe { mem::zeroed() }, 42 }; 43 assert_eq!(unsafe { 44 raw::git_merge_init_options(&mut opts.raw, 1) 45 }, 0); 46 opts 47 } 48 49 /// Detect file renames find_renames(&mut self, find: bool) -> &mut MergeOptions50 pub fn find_renames(&mut self, find: bool) -> &mut MergeOptions { 51 if find { 52 self.raw.flags |= raw::GIT_MERGE_FIND_RENAMES; 53 } else { 54 self.raw.flags &= !raw::GIT_MERGE_FIND_RENAMES; 55 } 56 self 57 } 58 59 /// Similarity to consider a file renamed (default 50) rename_threshold(&mut self, thresh: u32) -> &mut MergeOptions60 pub fn rename_threshold(&mut self, thresh: u32) -> &mut MergeOptions { 61 self.raw.rename_threshold = thresh; 62 self 63 } 64 65 /// Maximum similarity sources to examine for renames (default 200). 66 /// If the number of rename candidates (add / delete pairs) is greater 67 /// than this value, inexact rename detection is aborted. This setting 68 /// overrides the `merge.renameLimit` configuration value. target_limit(&mut self, limit: u32) -> &mut MergeOptions69 pub fn target_limit(&mut self, limit: u32) -> &mut MergeOptions { 70 self.raw.target_limit = limit as c_uint; 71 self 72 } 73 74 /// Maximum number of times to merge common ancestors to build a 75 /// virtual merge base when faced with criss-cross merges. When 76 /// this limit is reached, the next ancestor will simply be used 77 /// instead of attempting to merge it. The default is unlimited. recursion_limit(&mut self, limit: u32) -> &mut MergeOptions78 pub fn recursion_limit(&mut self, limit: u32) -> &mut MergeOptions { 79 self.raw.recursion_limit = limit as c_uint; 80 self 81 } 82 83 /// Specify a side to favor for resolving conflicts file_favor(&mut self, favor: FileFavor) -> &mut MergeOptions84 pub fn file_favor(&mut self, favor: FileFavor) -> &mut MergeOptions { 85 self.raw.file_favor = favor.convert(); 86 self 87 } 88 flag(&mut self, opt: raw::git_merge_file_flag_t, val: bool) -> &mut MergeOptions89 fn flag(&mut self, opt: raw::git_merge_file_flag_t, val: bool) -> &mut MergeOptions { 90 if val { 91 self.raw.file_flags |= opt; 92 } else { 93 self.raw.file_flags &= !opt; 94 } 95 self 96 } 97 98 /// Create standard conflicted merge files standard_style(&mut self, standard: bool) -> &mut MergeOptions99 pub fn standard_style(&mut self, standard: bool) -> &mut MergeOptions { 100 self.flag(raw::GIT_MERGE_FILE_STYLE_MERGE, standard) 101 } 102 103 /// Create diff3-style file diff3_style(&mut self, diff3: bool) -> &mut MergeOptions104 pub fn diff3_style(&mut self, diff3: bool) -> &mut MergeOptions { 105 self.flag(raw::GIT_MERGE_FILE_STYLE_DIFF3, diff3) 106 } 107 108 /// Condense non-alphanumeric regions for simplified diff file simplify_alnum(&mut self, simplify: bool) -> &mut MergeOptions109 pub fn simplify_alnum(&mut self, simplify: bool) -> &mut MergeOptions { 110 self.flag(raw::GIT_MERGE_FILE_SIMPLIFY_ALNUM, simplify) 111 } 112 113 /// Ignore all whitespace ignore_whitespace(&mut self, ignore: bool) -> &mut MergeOptions114 pub fn ignore_whitespace(&mut self, ignore: bool) -> &mut MergeOptions { 115 self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE, ignore) 116 } 117 118 /// Ignore changes in amount of whitespace ignore_whitespace_change(&mut self, ignore: bool) -> &mut MergeOptions119 pub fn ignore_whitespace_change(&mut self, ignore: bool) -> &mut MergeOptions { 120 self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE, ignore) 121 } 122 123 /// Ignore whitespace at end of line ignore_whitespace_eol(&mut self, ignore: bool) -> &mut MergeOptions124 pub fn ignore_whitespace_eol(&mut self, ignore: bool) -> &mut MergeOptions { 125 self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL, ignore) 126 } 127 128 /// Use the "patience diff" algorithm patience(&mut self, patience: bool) -> &mut MergeOptions129 pub fn patience(&mut self, patience: bool) -> &mut MergeOptions { 130 self.flag(raw::GIT_MERGE_FILE_DIFF_PATIENCE, patience) 131 } 132 133 /// Take extra time to find minimal diff minimal(&mut self, minimal: bool) -> &mut MergeOptions134 pub fn minimal(&mut self, minimal: bool) -> &mut MergeOptions { 135 self.flag(raw::GIT_MERGE_FILE_DIFF_MINIMAL, minimal) 136 } 137 138 /// Acquire a pointer to the underlying raw options. raw(&self) -> *const raw::git_merge_options139 pub unsafe fn raw(&self) -> *const raw::git_merge_options { 140 &self.raw as *const _ 141 } 142 } 143 144 impl<'repo> Binding for AnnotatedCommit<'repo> { 145 type Raw = *mut raw::git_annotated_commit; from_raw(raw: *mut raw::git_annotated_commit) -> AnnotatedCommit<'repo>146 unsafe fn from_raw(raw: *mut raw::git_annotated_commit) 147 -> AnnotatedCommit<'repo> { 148 AnnotatedCommit { 149 raw: raw, 150 _marker: marker::PhantomData, 151 } 152 } raw(&self) -> *mut raw::git_annotated_commit153 fn raw(&self) -> *mut raw::git_annotated_commit { self.raw } 154 } 155 156 impl<'repo> Drop for AnnotatedCommit<'repo> { drop(&mut self)157 fn drop(&mut self) { 158 unsafe { raw::git_annotated_commit_free(self.raw) } 159 } 160 } 161