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