##// END OF EJS Templates
copies-rust: fix reverted argument when merging tiny minor or major...
marmoute -
r47313:3c5a8b13 default
parent child Browse files
Show More
@@ -1,871 +1,871 b''
1 use crate::utils::hg_path::HgPath;
1 use crate::utils::hg_path::HgPath;
2 use crate::utils::hg_path::HgPathBuf;
2 use crate::utils::hg_path::HgPathBuf;
3 use crate::Revision;
3 use crate::Revision;
4 use crate::NULL_REVISION;
4 use crate::NULL_REVISION;
5
5
6 use im_rc::ordmap::DiffItem;
6 use im_rc::ordmap::DiffItem;
7 use im_rc::ordmap::Entry;
7 use im_rc::ordmap::Entry;
8 use im_rc::ordmap::OrdMap;
8 use im_rc::ordmap::OrdMap;
9
9
10 use std::cmp::Ordering;
10 use std::cmp::Ordering;
11 use std::collections::HashMap;
11 use std::collections::HashMap;
12 use std::convert::TryInto;
12 use std::convert::TryInto;
13
13
14 pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>;
14 pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>;
15
15
16 type PathToken = usize;
16 type PathToken = usize;
17
17
18 #[derive(Clone, Debug, PartialEq, Copy)]
18 #[derive(Clone, Debug, PartialEq, Copy)]
19 struct CopySource {
19 struct CopySource {
20 /// revision at which the copy information was added
20 /// revision at which the copy information was added
21 rev: Revision,
21 rev: Revision,
22 /// the copy source, (Set to None in case of deletion of the associated
22 /// the copy source, (Set to None in case of deletion of the associated
23 /// key)
23 /// key)
24 path: Option<PathToken>,
24 path: Option<PathToken>,
25 }
25 }
26
26
27 /// maps CopyDestination to Copy Source (+ a "timestamp" for the operation)
27 /// maps CopyDestination to Copy Source (+ a "timestamp" for the operation)
28 type InternalPathCopies = OrdMap<PathToken, CopySource>;
28 type InternalPathCopies = OrdMap<PathToken, CopySource>;
29
29
30 /// hold parent 1, parent 2 and relevant files actions.
30 /// hold parent 1, parent 2 and relevant files actions.
31 pub type RevInfo<'a> = (Revision, Revision, ChangedFiles<'a>);
31 pub type RevInfo<'a> = (Revision, Revision, ChangedFiles<'a>);
32
32
33 /// represent the files affected by a changesets
33 /// represent the files affected by a changesets
34 ///
34 ///
35 /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need
35 /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need
36 /// all the data categories tracked by it.
36 /// all the data categories tracked by it.
37 /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need
37 /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need
38 /// all the data categories tracked by it.
38 /// all the data categories tracked by it.
39 pub struct ChangedFiles<'a> {
39 pub struct ChangedFiles<'a> {
40 nb_items: u32,
40 nb_items: u32,
41 index: &'a [u8],
41 index: &'a [u8],
42 data: &'a [u8],
42 data: &'a [u8],
43 }
43 }
44
44
45 /// Represent active changes that affect the copy tracing.
45 /// Represent active changes that affect the copy tracing.
46 enum Action<'a> {
46 enum Action<'a> {
47 /// The parent ? children edge is removing a file
47 /// The parent ? children edge is removing a file
48 ///
48 ///
49 /// (actually, this could be the edge from the other parent, but it does
49 /// (actually, this could be the edge from the other parent, but it does
50 /// not matters)
50 /// not matters)
51 Removed(&'a HgPath),
51 Removed(&'a HgPath),
52 /// The parent ? children edge introduce copy information between (dest,
52 /// The parent ? children edge introduce copy information between (dest,
53 /// source)
53 /// source)
54 Copied(&'a HgPath, &'a HgPath),
54 Copied(&'a HgPath, &'a HgPath),
55 }
55 }
56
56
57 /// This express the possible "special" case we can get in a merge
57 /// This express the possible "special" case we can get in a merge
58 ///
58 ///
59 /// See mercurial/metadata.py for details on these values.
59 /// See mercurial/metadata.py for details on these values.
60 #[derive(PartialEq)]
60 #[derive(PartialEq)]
61 enum MergeCase {
61 enum MergeCase {
62 /// Merged: file had history on both side that needed to be merged
62 /// Merged: file had history on both side that needed to be merged
63 Merged,
63 Merged,
64 /// Salvaged: file was candidate for deletion, but survived the merge
64 /// Salvaged: file was candidate for deletion, but survived the merge
65 Salvaged,
65 Salvaged,
66 /// Normal: Not one of the two cases above
66 /// Normal: Not one of the two cases above
67 Normal,
67 Normal,
68 }
68 }
69
69
70 type FileChange<'a> = (u8, &'a HgPath, &'a HgPath);
70 type FileChange<'a> = (u8, &'a HgPath, &'a HgPath);
71
71
72 const EMPTY: &[u8] = b"";
72 const EMPTY: &[u8] = b"";
73 const COPY_MASK: u8 = 3;
73 const COPY_MASK: u8 = 3;
74 const P1_COPY: u8 = 2;
74 const P1_COPY: u8 = 2;
75 const P2_COPY: u8 = 3;
75 const P2_COPY: u8 = 3;
76 const ACTION_MASK: u8 = 28;
76 const ACTION_MASK: u8 = 28;
77 const REMOVED: u8 = 12;
77 const REMOVED: u8 = 12;
78 const MERGED: u8 = 8;
78 const MERGED: u8 = 8;
79 const SALVAGED: u8 = 16;
79 const SALVAGED: u8 = 16;
80
80
81 impl<'a> ChangedFiles<'a> {
81 impl<'a> ChangedFiles<'a> {
82 const INDEX_START: usize = 4;
82 const INDEX_START: usize = 4;
83 const ENTRY_SIZE: u32 = 9;
83 const ENTRY_SIZE: u32 = 9;
84 const FILENAME_START: u32 = 1;
84 const FILENAME_START: u32 = 1;
85 const COPY_SOURCE_START: u32 = 5;
85 const COPY_SOURCE_START: u32 = 5;
86
86
87 pub fn new(data: &'a [u8]) -> Self {
87 pub fn new(data: &'a [u8]) -> Self {
88 assert!(
88 assert!(
89 data.len() >= 4,
89 data.len() >= 4,
90 "data size ({}) is too small to contain the header (4)",
90 "data size ({}) is too small to contain the header (4)",
91 data.len()
91 data.len()
92 );
92 );
93 let nb_items_raw: [u8; 4] = (&data[0..=3])
93 let nb_items_raw: [u8; 4] = (&data[0..=3])
94 .try_into()
94 .try_into()
95 .expect("failed to turn 4 bytes into 4 bytes");
95 .expect("failed to turn 4 bytes into 4 bytes");
96 let nb_items = u32::from_be_bytes(nb_items_raw);
96 let nb_items = u32::from_be_bytes(nb_items_raw);
97
97
98 let index_size = (nb_items * Self::ENTRY_SIZE) as usize;
98 let index_size = (nb_items * Self::ENTRY_SIZE) as usize;
99 let index_end = Self::INDEX_START + index_size;
99 let index_end = Self::INDEX_START + index_size;
100
100
101 assert!(
101 assert!(
102 data.len() >= index_end,
102 data.len() >= index_end,
103 "data size ({}) is too small to fit the index_data ({})",
103 "data size ({}) is too small to fit the index_data ({})",
104 data.len(),
104 data.len(),
105 index_end
105 index_end
106 );
106 );
107
107
108 let ret = ChangedFiles {
108 let ret = ChangedFiles {
109 nb_items,
109 nb_items,
110 index: &data[Self::INDEX_START..index_end],
110 index: &data[Self::INDEX_START..index_end],
111 data: &data[index_end..],
111 data: &data[index_end..],
112 };
112 };
113 let max_data = ret.filename_end(nb_items - 1) as usize;
113 let max_data = ret.filename_end(nb_items - 1) as usize;
114 assert!(
114 assert!(
115 ret.data.len() >= max_data,
115 ret.data.len() >= max_data,
116 "data size ({}) is too small to fit all data ({})",
116 "data size ({}) is too small to fit all data ({})",
117 data.len(),
117 data.len(),
118 index_end + max_data
118 index_end + max_data
119 );
119 );
120 ret
120 ret
121 }
121 }
122
122
123 pub fn new_empty() -> Self {
123 pub fn new_empty() -> Self {
124 ChangedFiles {
124 ChangedFiles {
125 nb_items: 0,
125 nb_items: 0,
126 index: EMPTY,
126 index: EMPTY,
127 data: EMPTY,
127 data: EMPTY,
128 }
128 }
129 }
129 }
130
130
131 /// internal function to return an individual entry at a given index
131 /// internal function to return an individual entry at a given index
132 fn entry(&'a self, idx: u32) -> FileChange<'a> {
132 fn entry(&'a self, idx: u32) -> FileChange<'a> {
133 if idx >= self.nb_items {
133 if idx >= self.nb_items {
134 panic!(
134 panic!(
135 "index for entry is higher that the number of file {} >= {}",
135 "index for entry is higher that the number of file {} >= {}",
136 idx, self.nb_items
136 idx, self.nb_items
137 )
137 )
138 }
138 }
139 let flags = self.flags(idx);
139 let flags = self.flags(idx);
140 let filename = self.filename(idx);
140 let filename = self.filename(idx);
141 let copy_idx = self.copy_idx(idx);
141 let copy_idx = self.copy_idx(idx);
142 let copy_source = self.filename(copy_idx);
142 let copy_source = self.filename(copy_idx);
143 (flags, filename, copy_source)
143 (flags, filename, copy_source)
144 }
144 }
145
145
146 /// internal function to return the filename of the entry at a given index
146 /// internal function to return the filename of the entry at a given index
147 fn filename(&self, idx: u32) -> &HgPath {
147 fn filename(&self, idx: u32) -> &HgPath {
148 let filename_start;
148 let filename_start;
149 if idx == 0 {
149 if idx == 0 {
150 filename_start = 0;
150 filename_start = 0;
151 } else {
151 } else {
152 filename_start = self.filename_end(idx - 1)
152 filename_start = self.filename_end(idx - 1)
153 }
153 }
154 let filename_end = self.filename_end(idx);
154 let filename_end = self.filename_end(idx);
155 let filename_start = filename_start as usize;
155 let filename_start = filename_start as usize;
156 let filename_end = filename_end as usize;
156 let filename_end = filename_end as usize;
157 HgPath::new(&self.data[filename_start..filename_end])
157 HgPath::new(&self.data[filename_start..filename_end])
158 }
158 }
159
159
160 /// internal function to return the flag field of the entry at a given
160 /// internal function to return the flag field of the entry at a given
161 /// index
161 /// index
162 fn flags(&self, idx: u32) -> u8 {
162 fn flags(&self, idx: u32) -> u8 {
163 let idx = idx as usize;
163 let idx = idx as usize;
164 self.index[idx * (Self::ENTRY_SIZE as usize)]
164 self.index[idx * (Self::ENTRY_SIZE as usize)]
165 }
165 }
166
166
167 /// internal function to return the end of a filename part at a given index
167 /// internal function to return the end of a filename part at a given index
168 fn filename_end(&self, idx: u32) -> u32 {
168 fn filename_end(&self, idx: u32) -> u32 {
169 let start = (idx * Self::ENTRY_SIZE) + Self::FILENAME_START;
169 let start = (idx * Self::ENTRY_SIZE) + Self::FILENAME_START;
170 let end = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START;
170 let end = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START;
171 let start = start as usize;
171 let start = start as usize;
172 let end = end as usize;
172 let end = end as usize;
173 let raw = (&self.index[start..end])
173 let raw = (&self.index[start..end])
174 .try_into()
174 .try_into()
175 .expect("failed to turn 4 bytes into 4 bytes");
175 .expect("failed to turn 4 bytes into 4 bytes");
176 u32::from_be_bytes(raw)
176 u32::from_be_bytes(raw)
177 }
177 }
178
178
179 /// internal function to return index of the copy source of the entry at a
179 /// internal function to return index of the copy source of the entry at a
180 /// given index
180 /// given index
181 fn copy_idx(&self, idx: u32) -> u32 {
181 fn copy_idx(&self, idx: u32) -> u32 {
182 let start = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START;
182 let start = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START;
183 let end = (idx + 1) * Self::ENTRY_SIZE;
183 let end = (idx + 1) * Self::ENTRY_SIZE;
184 let start = start as usize;
184 let start = start as usize;
185 let end = end as usize;
185 let end = end as usize;
186 let raw = (&self.index[start..end])
186 let raw = (&self.index[start..end])
187 .try_into()
187 .try_into()
188 .expect("failed to turn 4 bytes into 4 bytes");
188 .expect("failed to turn 4 bytes into 4 bytes");
189 u32::from_be_bytes(raw)
189 u32::from_be_bytes(raw)
190 }
190 }
191
191
192 /// Return an iterator over all the `Action` in this instance.
192 /// Return an iterator over all the `Action` in this instance.
193 fn iter_actions(&self, parent: Parent) -> ActionsIterator {
193 fn iter_actions(&self, parent: Parent) -> ActionsIterator {
194 ActionsIterator {
194 ActionsIterator {
195 changes: &self,
195 changes: &self,
196 parent: parent,
196 parent: parent,
197 current: 0,
197 current: 0,
198 }
198 }
199 }
199 }
200
200
201 /// return the MergeCase value associated with a filename
201 /// return the MergeCase value associated with a filename
202 fn get_merge_case(&self, path: &HgPath) -> MergeCase {
202 fn get_merge_case(&self, path: &HgPath) -> MergeCase {
203 if self.nb_items == 0 {
203 if self.nb_items == 0 {
204 return MergeCase::Normal;
204 return MergeCase::Normal;
205 }
205 }
206 let mut low_part = 0;
206 let mut low_part = 0;
207 let mut high_part = self.nb_items;
207 let mut high_part = self.nb_items;
208
208
209 while low_part < high_part {
209 while low_part < high_part {
210 let cursor = (low_part + high_part - 1) / 2;
210 let cursor = (low_part + high_part - 1) / 2;
211 let (flags, filename, _source) = self.entry(cursor);
211 let (flags, filename, _source) = self.entry(cursor);
212 match path.cmp(filename) {
212 match path.cmp(filename) {
213 Ordering::Less => low_part = cursor + 1,
213 Ordering::Less => low_part = cursor + 1,
214 Ordering::Greater => high_part = cursor,
214 Ordering::Greater => high_part = cursor,
215 Ordering::Equal => {
215 Ordering::Equal => {
216 return match flags & ACTION_MASK {
216 return match flags & ACTION_MASK {
217 MERGED => MergeCase::Merged,
217 MERGED => MergeCase::Merged,
218 SALVAGED => MergeCase::Salvaged,
218 SALVAGED => MergeCase::Salvaged,
219 _ => MergeCase::Normal,
219 _ => MergeCase::Normal,
220 };
220 };
221 }
221 }
222 }
222 }
223 }
223 }
224 MergeCase::Normal
224 MergeCase::Normal
225 }
225 }
226 }
226 }
227
227
228 /// A struct responsible for answering "is X ancestors of Y" quickly
228 /// A struct responsible for answering "is X ancestors of Y" quickly
229 ///
229 ///
230 /// The structure will delegate ancestors call to a callback, and cache the
230 /// The structure will delegate ancestors call to a callback, and cache the
231 /// result.
231 /// result.
232 #[derive(Debug)]
232 #[derive(Debug)]
233 struct AncestorOracle<'a, A: Fn(Revision, Revision) -> bool> {
233 struct AncestorOracle<'a, A: Fn(Revision, Revision) -> bool> {
234 inner: &'a A,
234 inner: &'a A,
235 pairs: HashMap<(Revision, Revision), bool>,
235 pairs: HashMap<(Revision, Revision), bool>,
236 }
236 }
237
237
238 impl<'a, A: Fn(Revision, Revision) -> bool> AncestorOracle<'a, A> {
238 impl<'a, A: Fn(Revision, Revision) -> bool> AncestorOracle<'a, A> {
239 fn new(func: &'a A) -> Self {
239 fn new(func: &'a A) -> Self {
240 Self {
240 Self {
241 inner: func,
241 inner: func,
242 pairs: HashMap::default(),
242 pairs: HashMap::default(),
243 }
243 }
244 }
244 }
245
245
246 fn record_overwrite(&mut self, anc: Revision, desc: Revision) {
246 fn record_overwrite(&mut self, anc: Revision, desc: Revision) {
247 self.pairs.insert((anc, desc), true);
247 self.pairs.insert((anc, desc), true);
248 }
248 }
249
249
250 /// returns `true` if `anc` is an ancestors of `desc`, `false` otherwise
250 /// returns `true` if `anc` is an ancestors of `desc`, `false` otherwise
251 fn is_overwrite(&mut self, anc: Revision, desc: Revision) -> bool {
251 fn is_overwrite(&mut self, anc: Revision, desc: Revision) -> bool {
252 if anc > desc {
252 if anc > desc {
253 false
253 false
254 } else if anc == desc {
254 } else if anc == desc {
255 true
255 true
256 } else {
256 } else {
257 if let Some(b) = self.pairs.get(&(anc, desc)) {
257 if let Some(b) = self.pairs.get(&(anc, desc)) {
258 *b
258 *b
259 } else {
259 } else {
260 let b = (self.inner)(anc, desc);
260 let b = (self.inner)(anc, desc);
261 self.pairs.insert((anc, desc), b);
261 self.pairs.insert((anc, desc), b);
262 b
262 b
263 }
263 }
264 }
264 }
265 }
265 }
266 }
266 }
267
267
268 struct ActionsIterator<'a> {
268 struct ActionsIterator<'a> {
269 changes: &'a ChangedFiles<'a>,
269 changes: &'a ChangedFiles<'a>,
270 parent: Parent,
270 parent: Parent,
271 current: u32,
271 current: u32,
272 }
272 }
273
273
274 impl<'a> Iterator for ActionsIterator<'a> {
274 impl<'a> Iterator for ActionsIterator<'a> {
275 type Item = Action<'a>;
275 type Item = Action<'a>;
276
276
277 fn next(&mut self) -> Option<Action<'a>> {
277 fn next(&mut self) -> Option<Action<'a>> {
278 let copy_flag = match self.parent {
278 let copy_flag = match self.parent {
279 Parent::FirstParent => P1_COPY,
279 Parent::FirstParent => P1_COPY,
280 Parent::SecondParent => P2_COPY,
280 Parent::SecondParent => P2_COPY,
281 };
281 };
282 while self.current < self.changes.nb_items {
282 while self.current < self.changes.nb_items {
283 let (flags, file, source) = self.changes.entry(self.current);
283 let (flags, file, source) = self.changes.entry(self.current);
284 self.current += 1;
284 self.current += 1;
285 if (flags & ACTION_MASK) == REMOVED {
285 if (flags & ACTION_MASK) == REMOVED {
286 return Some(Action::Removed(file));
286 return Some(Action::Removed(file));
287 }
287 }
288 let copy = flags & COPY_MASK;
288 let copy = flags & COPY_MASK;
289 if copy == copy_flag {
289 if copy == copy_flag {
290 return Some(Action::Copied(file, source));
290 return Some(Action::Copied(file, source));
291 }
291 }
292 }
292 }
293 return None;
293 return None;
294 }
294 }
295 }
295 }
296
296
297 /// A small struct whose purpose is to ensure lifetime of bytes referenced in
297 /// A small struct whose purpose is to ensure lifetime of bytes referenced in
298 /// ChangedFiles
298 /// ChangedFiles
299 ///
299 ///
300 /// It is passed to the RevInfoMaker callback who can assign any necessary
300 /// It is passed to the RevInfoMaker callback who can assign any necessary
301 /// content to the `data` attribute. The copy tracing code is responsible for
301 /// content to the `data` attribute. The copy tracing code is responsible for
302 /// keeping the DataHolder alive at least as long as the ChangedFiles object.
302 /// keeping the DataHolder alive at least as long as the ChangedFiles object.
303 pub struct DataHolder<D> {
303 pub struct DataHolder<D> {
304 /// RevInfoMaker callback should assign data referenced by the
304 /// RevInfoMaker callback should assign data referenced by the
305 /// ChangedFiles struct it return to this attribute. The DataHolder
305 /// ChangedFiles struct it return to this attribute. The DataHolder
306 /// lifetime will be at least as long as the ChangedFiles one.
306 /// lifetime will be at least as long as the ChangedFiles one.
307 pub data: Option<D>,
307 pub data: Option<D>,
308 }
308 }
309
309
310 pub type RevInfoMaker<'a, D> =
310 pub type RevInfoMaker<'a, D> =
311 Box<dyn for<'r> Fn(Revision, &'r mut DataHolder<D>) -> RevInfo<'r> + 'a>;
311 Box<dyn for<'r> Fn(Revision, &'r mut DataHolder<D>) -> RevInfo<'r> + 'a>;
312
312
313 /// enum used to carry information about the parent β†’ child currently processed
313 /// enum used to carry information about the parent β†’ child currently processed
314 #[derive(Copy, Clone, Debug)]
314 #[derive(Copy, Clone, Debug)]
315 enum Parent {
315 enum Parent {
316 /// The `p1(x) β†’ x` edge
316 /// The `p1(x) β†’ x` edge
317 FirstParent,
317 FirstParent,
318 /// The `p2(x) β†’ x` edge
318 /// The `p2(x) β†’ x` edge
319 SecondParent,
319 SecondParent,
320 }
320 }
321
321
322 /// A small "tokenizer" responsible of turning full HgPath into lighter
322 /// A small "tokenizer" responsible of turning full HgPath into lighter
323 /// PathToken
323 /// PathToken
324 ///
324 ///
325 /// Dealing with small object, like integer is much faster, so HgPath input are
325 /// Dealing with small object, like integer is much faster, so HgPath input are
326 /// turned into integer "PathToken" and converted back in the end.
326 /// turned into integer "PathToken" and converted back in the end.
327 #[derive(Clone, Debug, Default)]
327 #[derive(Clone, Debug, Default)]
328 struct TwoWayPathMap {
328 struct TwoWayPathMap {
329 token: HashMap<HgPathBuf, PathToken>,
329 token: HashMap<HgPathBuf, PathToken>,
330 path: Vec<HgPathBuf>,
330 path: Vec<HgPathBuf>,
331 }
331 }
332
332
333 impl TwoWayPathMap {
333 impl TwoWayPathMap {
334 fn tokenize(&mut self, path: &HgPath) -> PathToken {
334 fn tokenize(&mut self, path: &HgPath) -> PathToken {
335 match self.token.get(path) {
335 match self.token.get(path) {
336 Some(a) => *a,
336 Some(a) => *a,
337 None => {
337 None => {
338 let a = self.token.len();
338 let a = self.token.len();
339 let buf = path.to_owned();
339 let buf = path.to_owned();
340 self.path.push(buf.clone());
340 self.path.push(buf.clone());
341 self.token.insert(buf, a);
341 self.token.insert(buf, a);
342 a
342 a
343 }
343 }
344 }
344 }
345 }
345 }
346
346
347 fn untokenize(&self, token: PathToken) -> &HgPathBuf {
347 fn untokenize(&self, token: PathToken) -> &HgPathBuf {
348 assert!(token < self.path.len(), format!("Unknown token: {}", token));
348 assert!(token < self.path.len(), format!("Unknown token: {}", token));
349 &self.path[token]
349 &self.path[token]
350 }
350 }
351 }
351 }
352
352
353 /// Same as mercurial.copies._combine_changeset_copies, but in Rust.
353 /// Same as mercurial.copies._combine_changeset_copies, but in Rust.
354 ///
354 ///
355 /// Arguments are:
355 /// Arguments are:
356 ///
356 ///
357 /// revs: all revisions to be considered
357 /// revs: all revisions to be considered
358 /// children: a {parent ? [childrens]} mapping
358 /// children: a {parent ? [childrens]} mapping
359 /// target_rev: the final revision we are combining copies to
359 /// target_rev: the final revision we are combining copies to
360 /// rev_info(rev): callback to get revision information:
360 /// rev_info(rev): callback to get revision information:
361 /// * first parent
361 /// * first parent
362 /// * second parent
362 /// * second parent
363 /// * ChangedFiles
363 /// * ChangedFiles
364 /// isancestors(low_rev, high_rev): callback to check if a revision is an
364 /// isancestors(low_rev, high_rev): callback to check if a revision is an
365 /// ancestor of another
365 /// ancestor of another
366 pub fn combine_changeset_copies<A: Fn(Revision, Revision) -> bool, D>(
366 pub fn combine_changeset_copies<A: Fn(Revision, Revision) -> bool, D>(
367 revs: Vec<Revision>,
367 revs: Vec<Revision>,
368 mut children_count: HashMap<Revision, usize>,
368 mut children_count: HashMap<Revision, usize>,
369 target_rev: Revision,
369 target_rev: Revision,
370 rev_info: RevInfoMaker<D>,
370 rev_info: RevInfoMaker<D>,
371 is_ancestor: &A,
371 is_ancestor: &A,
372 ) -> PathCopies {
372 ) -> PathCopies {
373 let mut all_copies = HashMap::new();
373 let mut all_copies = HashMap::new();
374 let mut oracle = AncestorOracle::new(is_ancestor);
374 let mut oracle = AncestorOracle::new(is_ancestor);
375
375
376 let mut path_map = TwoWayPathMap::default();
376 let mut path_map = TwoWayPathMap::default();
377
377
378 for rev in revs {
378 for rev in revs {
379 let mut d: DataHolder<D> = DataHolder { data: None };
379 let mut d: DataHolder<D> = DataHolder { data: None };
380 let (p1, p2, changes) = rev_info(rev, &mut d);
380 let (p1, p2, changes) = rev_info(rev, &mut d);
381
381
382 // We will chain the copies information accumulated for the parent with
382 // We will chain the copies information accumulated for the parent with
383 // the individual copies information the curent revision. Creating a
383 // the individual copies information the curent revision. Creating a
384 // new TimeStampedPath for each `rev` β†’ `children` vertex.
384 // new TimeStampedPath for each `rev` β†’ `children` vertex.
385 let mut copies: Option<InternalPathCopies> = None;
385 let mut copies: Option<InternalPathCopies> = None;
386 if p1 != NULL_REVISION {
386 if p1 != NULL_REVISION {
387 // Retrieve data computed in a previous iteration
387 // Retrieve data computed in a previous iteration
388 let parent_copies = get_and_clean_parent_copies(
388 let parent_copies = get_and_clean_parent_copies(
389 &mut all_copies,
389 &mut all_copies,
390 &mut children_count,
390 &mut children_count,
391 p1,
391 p1,
392 );
392 );
393 if let Some(parent_copies) = parent_copies {
393 if let Some(parent_copies) = parent_copies {
394 // combine it with data for that revision
394 // combine it with data for that revision
395 let vertex_copies = add_from_changes(
395 let vertex_copies = add_from_changes(
396 &mut path_map,
396 &mut path_map,
397 &mut oracle,
397 &mut oracle,
398 &parent_copies,
398 &parent_copies,
399 &changes,
399 &changes,
400 Parent::FirstParent,
400 Parent::FirstParent,
401 rev,
401 rev,
402 );
402 );
403 // keep that data around for potential later combination
403 // keep that data around for potential later combination
404 copies = Some(vertex_copies);
404 copies = Some(vertex_copies);
405 }
405 }
406 }
406 }
407 if p2 != NULL_REVISION {
407 if p2 != NULL_REVISION {
408 // Retrieve data computed in a previous iteration
408 // Retrieve data computed in a previous iteration
409 let parent_copies = get_and_clean_parent_copies(
409 let parent_copies = get_and_clean_parent_copies(
410 &mut all_copies,
410 &mut all_copies,
411 &mut children_count,
411 &mut children_count,
412 p2,
412 p2,
413 );
413 );
414 if let Some(parent_copies) = parent_copies {
414 if let Some(parent_copies) = parent_copies {
415 // combine it with data for that revision
415 // combine it with data for that revision
416 let vertex_copies = add_from_changes(
416 let vertex_copies = add_from_changes(
417 &mut path_map,
417 &mut path_map,
418 &mut oracle,
418 &mut oracle,
419 &parent_copies,
419 &parent_copies,
420 &changes,
420 &changes,
421 Parent::SecondParent,
421 Parent::SecondParent,
422 rev,
422 rev,
423 );
423 );
424
424
425 copies = match copies {
425 copies = match copies {
426 None => Some(vertex_copies),
426 None => Some(vertex_copies),
427 // Merge has two parents needs to combines their copy
427 // Merge has two parents needs to combines their copy
428 // information.
428 // information.
429 //
429 //
430 // If we got data from both parents, We need to combine
430 // If we got data from both parents, We need to combine
431 // them.
431 // them.
432 Some(copies) => Some(merge_copies_dict(
432 Some(copies) => Some(merge_copies_dict(
433 &path_map,
433 &path_map,
434 rev,
434 rev,
435 vertex_copies,
435 vertex_copies,
436 copies,
436 copies,
437 &changes,
437 &changes,
438 &mut oracle,
438 &mut oracle,
439 )),
439 )),
440 };
440 };
441 }
441 }
442 }
442 }
443 match copies {
443 match copies {
444 Some(copies) => {
444 Some(copies) => {
445 all_copies.insert(rev, copies);
445 all_copies.insert(rev, copies);
446 }
446 }
447 _ => {}
447 _ => {}
448 }
448 }
449 }
449 }
450
450
451 // Drop internal information (like the timestamp) and return the final
451 // Drop internal information (like the timestamp) and return the final
452 // mapping.
452 // mapping.
453 let tt_result = all_copies
453 let tt_result = all_copies
454 .remove(&target_rev)
454 .remove(&target_rev)
455 .expect("target revision was not processed");
455 .expect("target revision was not processed");
456 let mut result = PathCopies::default();
456 let mut result = PathCopies::default();
457 for (dest, tt_source) in tt_result {
457 for (dest, tt_source) in tt_result {
458 if let Some(path) = tt_source.path {
458 if let Some(path) = tt_source.path {
459 let path_dest = path_map.untokenize(dest).to_owned();
459 let path_dest = path_map.untokenize(dest).to_owned();
460 let path_path = path_map.untokenize(path).to_owned();
460 let path_path = path_map.untokenize(path).to_owned();
461 result.insert(path_dest, path_path);
461 result.insert(path_dest, path_path);
462 }
462 }
463 }
463 }
464 result
464 result
465 }
465 }
466
466
467 /// fetch previous computed information
467 /// fetch previous computed information
468 ///
468 ///
469 /// If no other children are expected to need this information, we drop it from
469 /// If no other children are expected to need this information, we drop it from
470 /// the cache.
470 /// the cache.
471 ///
471 ///
472 /// If parent is not part of the set we are expected to walk, return None.
472 /// If parent is not part of the set we are expected to walk, return None.
473 fn get_and_clean_parent_copies(
473 fn get_and_clean_parent_copies(
474 all_copies: &mut HashMap<Revision, InternalPathCopies>,
474 all_copies: &mut HashMap<Revision, InternalPathCopies>,
475 children_count: &mut HashMap<Revision, usize>,
475 children_count: &mut HashMap<Revision, usize>,
476 parent_rev: Revision,
476 parent_rev: Revision,
477 ) -> Option<InternalPathCopies> {
477 ) -> Option<InternalPathCopies> {
478 let count = children_count.get_mut(&parent_rev)?;
478 let count = children_count.get_mut(&parent_rev)?;
479 *count -= 1;
479 *count -= 1;
480 if *count == 0 {
480 if *count == 0 {
481 match all_copies.remove(&parent_rev) {
481 match all_copies.remove(&parent_rev) {
482 Some(c) => Some(c),
482 Some(c) => Some(c),
483 None => Some(InternalPathCopies::default()),
483 None => Some(InternalPathCopies::default()),
484 }
484 }
485 } else {
485 } else {
486 match all_copies.get(&parent_rev) {
486 match all_copies.get(&parent_rev) {
487 Some(c) => Some(c.clone()),
487 Some(c) => Some(c.clone()),
488 None => Some(InternalPathCopies::default()),
488 None => Some(InternalPathCopies::default()),
489 }
489 }
490 }
490 }
491 }
491 }
492
492
493 /// Combine ChangedFiles with some existing PathCopies information and return
493 /// Combine ChangedFiles with some existing PathCopies information and return
494 /// the result
494 /// the result
495 fn add_from_changes<A: Fn(Revision, Revision) -> bool>(
495 fn add_from_changes<A: Fn(Revision, Revision) -> bool>(
496 path_map: &mut TwoWayPathMap,
496 path_map: &mut TwoWayPathMap,
497 oracle: &mut AncestorOracle<A>,
497 oracle: &mut AncestorOracle<A>,
498 base_copies: &InternalPathCopies,
498 base_copies: &InternalPathCopies,
499 changes: &ChangedFiles,
499 changes: &ChangedFiles,
500 parent: Parent,
500 parent: Parent,
501 current_rev: Revision,
501 current_rev: Revision,
502 ) -> InternalPathCopies {
502 ) -> InternalPathCopies {
503 let mut copies = base_copies.clone();
503 let mut copies = base_copies.clone();
504 for action in changes.iter_actions(parent) {
504 for action in changes.iter_actions(parent) {
505 match action {
505 match action {
506 Action::Copied(path_dest, path_source) => {
506 Action::Copied(path_dest, path_source) => {
507 let dest = path_map.tokenize(path_dest);
507 let dest = path_map.tokenize(path_dest);
508 let source = path_map.tokenize(path_source);
508 let source = path_map.tokenize(path_source);
509 let entry;
509 let entry;
510 if let Some(v) = base_copies.get(&source) {
510 if let Some(v) = base_copies.get(&source) {
511 entry = match &v.path {
511 entry = match &v.path {
512 Some(path) => Some((*(path)).to_owned()),
512 Some(path) => Some((*(path)).to_owned()),
513 None => Some(source.to_owned()),
513 None => Some(source.to_owned()),
514 }
514 }
515 } else {
515 } else {
516 entry = Some(source.to_owned());
516 entry = Some(source.to_owned());
517 }
517 }
518 // Each new entry is introduced by the children, we
518 // Each new entry is introduced by the children, we
519 // record this information as we will need it to take
519 // record this information as we will need it to take
520 // the right decision when merging conflicting copy
520 // the right decision when merging conflicting copy
521 // information. See merge_copies_dict for details.
521 // information. See merge_copies_dict for details.
522 match copies.entry(dest) {
522 match copies.entry(dest) {
523 Entry::Vacant(slot) => {
523 Entry::Vacant(slot) => {
524 let ttpc = CopySource {
524 let ttpc = CopySource {
525 rev: current_rev,
525 rev: current_rev,
526 path: entry,
526 path: entry,
527 };
527 };
528 slot.insert(ttpc);
528 slot.insert(ttpc);
529 }
529 }
530 Entry::Occupied(mut slot) => {
530 Entry::Occupied(mut slot) => {
531 let mut ttpc = slot.get_mut();
531 let mut ttpc = slot.get_mut();
532 oracle.record_overwrite(ttpc.rev, current_rev);
532 oracle.record_overwrite(ttpc.rev, current_rev);
533 ttpc.rev = current_rev;
533 ttpc.rev = current_rev;
534 ttpc.path = entry;
534 ttpc.path = entry;
535 }
535 }
536 }
536 }
537 }
537 }
538 Action::Removed(deleted_path) => {
538 Action::Removed(deleted_path) => {
539 // We must drop copy information for removed file.
539 // We must drop copy information for removed file.
540 //
540 //
541 // We need to explicitly record them as dropped to
541 // We need to explicitly record them as dropped to
542 // propagate this information when merging two
542 // propagate this information when merging two
543 // InternalPathCopies object.
543 // InternalPathCopies object.
544 let deleted = path_map.tokenize(deleted_path);
544 let deleted = path_map.tokenize(deleted_path);
545 copies.entry(deleted).and_modify(|old| {
545 copies.entry(deleted).and_modify(|old| {
546 oracle.record_overwrite(old.rev, current_rev);
546 oracle.record_overwrite(old.rev, current_rev);
547 old.rev = current_rev;
547 old.rev = current_rev;
548 old.path = None;
548 old.path = None;
549 });
549 });
550 }
550 }
551 }
551 }
552 }
552 }
553 copies
553 copies
554 }
554 }
555
555
556 /// merge two copies-mapping together, minor and major
556 /// merge two copies-mapping together, minor and major
557 ///
557 ///
558 /// In case of conflict, value from "major" will be picked, unless in some
558 /// In case of conflict, value from "major" will be picked, unless in some
559 /// cases. See inline documentation for details.
559 /// cases. See inline documentation for details.
560 fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>(
560 fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>(
561 path_map: &TwoWayPathMap,
561 path_map: &TwoWayPathMap,
562 current_merge: Revision,
562 current_merge: Revision,
563 mut minor: InternalPathCopies,
563 mut minor: InternalPathCopies,
564 mut major: InternalPathCopies,
564 mut major: InternalPathCopies,
565 changes: &ChangedFiles,
565 changes: &ChangedFiles,
566 oracle: &mut AncestorOracle<A>,
566 oracle: &mut AncestorOracle<A>,
567 ) -> InternalPathCopies {
567 ) -> InternalPathCopies {
568 // This closure exist as temporary help while multiple developper are
568 // This closure exist as temporary help while multiple developper are
569 // actively working on this code. Feel free to re-inline it once this
569 // actively working on this code. Feel free to re-inline it once this
570 // code is more settled.
570 // code is more settled.
571 let cmp_value = |oracle: &mut AncestorOracle<A>,
571 let cmp_value = |oracle: &mut AncestorOracle<A>,
572 dest: &PathToken,
572 dest: &PathToken,
573 src_minor: &CopySource,
573 src_minor: &CopySource,
574 src_major: &CopySource| {
574 src_major: &CopySource| {
575 compare_value(
575 compare_value(
576 path_map,
576 path_map,
577 current_merge,
577 current_merge,
578 changes,
578 changes,
579 oracle,
579 oracle,
580 dest,
580 dest,
581 src_minor,
581 src_minor,
582 src_major,
582 src_major,
583 )
583 )
584 };
584 };
585 if minor.is_empty() {
585 if minor.is_empty() {
586 major
586 major
587 } else if major.is_empty() {
587 } else if major.is_empty() {
588 minor
588 minor
589 } else if minor.len() * 2 < major.len() {
589 } else if minor.len() * 2 < major.len() {
590 // Lets says we are merging two InternalPathCopies instance A and B.
590 // Lets says we are merging two InternalPathCopies instance A and B.
591 //
591 //
592 // If A contains N items, the merge result will never contains more
592 // If A contains N items, the merge result will never contains more
593 // than N values differents than the one in A
593 // than N values differents than the one in A
594 //
594 //
595 // If B contains M items, with M > N, the merge result will always
595 // If B contains M items, with M > N, the merge result will always
596 // result in a minimum of M - N value differents than the on in
596 // result in a minimum of M - N value differents than the on in
597 // A
597 // A
598 //
598 //
599 // As a result, if N < (M-N), we know that simply iterating over A will
599 // As a result, if N < (M-N), we know that simply iterating over A will
600 // yield less difference than iterating over the difference
600 // yield less difference than iterating over the difference
601 // between A and B.
601 // between A and B.
602 //
602 //
603 // This help performance a lot in case were a tiny
603 // This help performance a lot in case were a tiny
604 // InternalPathCopies is merged with a much larger one.
604 // InternalPathCopies is merged with a much larger one.
605 for (dest, src_minor) in minor {
605 for (dest, src_minor) in minor {
606 let src_major = major.get(&dest);
606 let src_major = major.get(&dest);
607 match src_major {
607 match src_major {
608 None => {
608 None => {
609 major.insert(dest, src_minor);
609 major.insert(dest, src_minor);
610 }
610 }
611 Some(src_major) => {
611 Some(src_major) => {
612 let (pick, overwrite) =
612 let (pick, overwrite) =
613 cmp_value(oracle, &dest, &src_minor, src_major);
613 cmp_value(oracle, &dest, &src_minor, src_major);
614 if overwrite {
614 if overwrite {
615 oracle.record_overwrite(src_minor.rev, current_merge);
615 oracle.record_overwrite(src_minor.rev, current_merge);
616 oracle.record_overwrite(src_major.rev, current_merge);
616 oracle.record_overwrite(src_major.rev, current_merge);
617 let path = match pick {
617 let path = match pick {
618 MergePick::Major => src_major.path,
618 MergePick::Major => src_major.path,
619 MergePick::Minor => src_minor.path,
619 MergePick::Minor => src_minor.path,
620 MergePick::Any => src_major.path,
620 MergePick::Any => src_major.path,
621 };
621 };
622 let src = CopySource {
622 let src = CopySource {
623 rev: current_merge,
623 rev: current_merge,
624 path,
624 path,
625 };
625 };
626 major.insert(dest, src);
626 major.insert(dest, src);
627 } else {
627 } else {
628 match pick {
628 match pick {
629 MergePick::Any | MergePick::Major => None,
629 MergePick::Any | MergePick::Major => None,
630 MergePick::Minor => major.insert(dest, src_minor),
630 MergePick::Minor => major.insert(dest, src_minor),
631 };
631 };
632 }
632 }
633 }
633 }
634 };
634 };
635 }
635 }
636 major
636 major
637 } else if major.len() * 2 < minor.len() {
637 } else if major.len() * 2 < minor.len() {
638 // This use the same rational than the previous block.
638 // This use the same rational than the previous block.
639 // (Check previous block documentation for details.)
639 // (Check previous block documentation for details.)
640 for (dest, src_major) in major {
640 for (dest, src_major) in major {
641 let src_minor = minor.get(&dest);
641 let src_minor = minor.get(&dest);
642 match src_minor {
642 match src_minor {
643 None => {
643 None => {
644 minor.insert(dest, src_major);
644 minor.insert(dest, src_major);
645 }
645 }
646 Some(src_minor) => {
646 Some(src_minor) => {
647 let (pick, overwrite) =
647 let (pick, overwrite) =
648 cmp_value(oracle, &dest, &src_major, src_minor);
648 cmp_value(oracle, &dest, src_minor, &src_major);
649 if overwrite {
649 if overwrite {
650 oracle.record_overwrite(src_minor.rev, current_merge);
650 oracle.record_overwrite(src_minor.rev, current_merge);
651 oracle.record_overwrite(src_major.rev, current_merge);
651 oracle.record_overwrite(src_major.rev, current_merge);
652 let path = match pick {
652 let path = match pick {
653 MergePick::Major => src_minor.path,
653 MergePick::Major => src_minor.path,
654 MergePick::Minor => src_major.path,
654 MergePick::Minor => src_major.path,
655 MergePick::Any => src_major.path,
655 MergePick::Any => src_major.path,
656 };
656 };
657 let src = CopySource {
657 let src = CopySource {
658 rev: current_merge,
658 rev: current_merge,
659 path,
659 path,
660 };
660 };
661 minor.insert(dest, src);
661 minor.insert(dest, src);
662 } else {
662 } else {
663 match pick {
663 match pick {
664 MergePick::Any | MergePick::Major => None,
664 MergePick::Any | MergePick::Minor => None,
665 MergePick::Minor => minor.insert(dest, src_major),
665 MergePick::Major => minor.insert(dest, src_major),
666 };
666 };
667 }
667 }
668 }
668 }
669 };
669 };
670 }
670 }
671 minor
671 minor
672 } else {
672 } else {
673 let mut override_minor = Vec::new();
673 let mut override_minor = Vec::new();
674 let mut override_major = Vec::new();
674 let mut override_major = Vec::new();
675
675
676 let mut to_major = |k: &PathToken, v: &CopySource| {
676 let mut to_major = |k: &PathToken, v: &CopySource| {
677 override_major.push((k.clone(), v.clone()))
677 override_major.push((k.clone(), v.clone()))
678 };
678 };
679 let mut to_minor = |k: &PathToken, v: &CopySource| {
679 let mut to_minor = |k: &PathToken, v: &CopySource| {
680 override_minor.push((k.clone(), v.clone()))
680 override_minor.push((k.clone(), v.clone()))
681 };
681 };
682
682
683 // The diff function leverage detection of the identical subpart if
683 // The diff function leverage detection of the identical subpart if
684 // minor and major has some common ancestors. This make it very
684 // minor and major has some common ancestors. This make it very
685 // fast is most case.
685 // fast is most case.
686 //
686 //
687 // In case where the two map are vastly different in size, the current
687 // In case where the two map are vastly different in size, the current
688 // approach is still slowish because the iteration will iterate over
688 // approach is still slowish because the iteration will iterate over
689 // all the "exclusive" content of the larger on. This situation can be
689 // all the "exclusive" content of the larger on. This situation can be
690 // frequent when the subgraph of revision we are processing has a lot
690 // frequent when the subgraph of revision we are processing has a lot
691 // of roots. Each roots adding they own fully new map to the mix (and
691 // of roots. Each roots adding they own fully new map to the mix (and
692 // likely a small map, if the path from the root to the "main path" is
692 // likely a small map, if the path from the root to the "main path" is
693 // small.
693 // small.
694 //
694 //
695 // We could do better by detecting such situation and processing them
695 // We could do better by detecting such situation and processing them
696 // differently.
696 // differently.
697 for d in minor.diff(&major) {
697 for d in minor.diff(&major) {
698 match d {
698 match d {
699 DiffItem::Add(k, v) => to_minor(k, v),
699 DiffItem::Add(k, v) => to_minor(k, v),
700 DiffItem::Remove(k, v) => to_major(k, v),
700 DiffItem::Remove(k, v) => to_major(k, v),
701 DiffItem::Update { old, new } => {
701 DiffItem::Update { old, new } => {
702 let (dest, src_major) = new;
702 let (dest, src_major) = new;
703 let (_, src_minor) = old;
703 let (_, src_minor) = old;
704 let (pick, overwrite) =
704 let (pick, overwrite) =
705 cmp_value(oracle, dest, src_minor, src_major);
705 cmp_value(oracle, dest, src_minor, src_major);
706 if overwrite {
706 if overwrite {
707 oracle.record_overwrite(src_minor.rev, current_merge);
707 oracle.record_overwrite(src_minor.rev, current_merge);
708 oracle.record_overwrite(src_major.rev, current_merge);
708 oracle.record_overwrite(src_major.rev, current_merge);
709 let path = match pick {
709 let path = match pick {
710 MergePick::Major => src_major.path,
710 MergePick::Major => src_major.path,
711 MergePick::Minor => src_minor.path,
711 MergePick::Minor => src_minor.path,
712 // If the two entry are identical, no need to do
712 // If the two entry are identical, no need to do
713 // anything (but diff should not have yield them)
713 // anything (but diff should not have yield them)
714 MergePick::Any => src_major.path,
714 MergePick::Any => src_major.path,
715 };
715 };
716 let src = CopySource {
716 let src = CopySource {
717 rev: current_merge,
717 rev: current_merge,
718 path,
718 path,
719 };
719 };
720 to_minor(dest, &src);
720 to_minor(dest, &src);
721 to_major(dest, &src);
721 to_major(dest, &src);
722 } else {
722 } else {
723 match pick {
723 match pick {
724 MergePick::Major => to_minor(dest, src_major),
724 MergePick::Major => to_minor(dest, src_major),
725 MergePick::Minor => to_major(dest, src_minor),
725 MergePick::Minor => to_major(dest, src_minor),
726 // If the two entry are identical, no need to do
726 // If the two entry are identical, no need to do
727 // anything (but diff should not have yield them)
727 // anything (but diff should not have yield them)
728 MergePick::Any => unreachable!(),
728 MergePick::Any => unreachable!(),
729 }
729 }
730 }
730 }
731 }
731 }
732 };
732 };
733 }
733 }
734
734
735 let updates;
735 let updates;
736 let mut result;
736 let mut result;
737 if override_major.is_empty() {
737 if override_major.is_empty() {
738 result = major
738 result = major
739 } else if override_minor.is_empty() {
739 } else if override_minor.is_empty() {
740 result = minor
740 result = minor
741 } else {
741 } else {
742 if override_minor.len() < override_major.len() {
742 if override_minor.len() < override_major.len() {
743 updates = override_minor;
743 updates = override_minor;
744 result = minor;
744 result = minor;
745 } else {
745 } else {
746 updates = override_major;
746 updates = override_major;
747 result = major;
747 result = major;
748 }
748 }
749 for (k, v) in updates {
749 for (k, v) in updates {
750 result.insert(k, v);
750 result.insert(k, v);
751 }
751 }
752 }
752 }
753 result
753 result
754 }
754 }
755 }
755 }
756
756
757 /// represent the side that should prevail when merging two
757 /// represent the side that should prevail when merging two
758 /// InternalPathCopies
758 /// InternalPathCopies
759 enum MergePick {
759 enum MergePick {
760 /// The "major" (p1) side prevails
760 /// The "major" (p1) side prevails
761 Major,
761 Major,
762 /// The "minor" (p2) side prevails
762 /// The "minor" (p2) side prevails
763 Minor,
763 Minor,
764 /// Any side could be used (because they are the same)
764 /// Any side could be used (because they are the same)
765 Any,
765 Any,
766 }
766 }
767
767
768 /// decide which side prevails in case of conflicting values
768 /// decide which side prevails in case of conflicting values
769 #[allow(clippy::if_same_then_else)]
769 #[allow(clippy::if_same_then_else)]
770 fn compare_value<A: Fn(Revision, Revision) -> bool>(
770 fn compare_value<A: Fn(Revision, Revision) -> bool>(
771 path_map: &TwoWayPathMap,
771 path_map: &TwoWayPathMap,
772 current_merge: Revision,
772 current_merge: Revision,
773 changes: &ChangedFiles,
773 changes: &ChangedFiles,
774 oracle: &mut AncestorOracle<A>,
774 oracle: &mut AncestorOracle<A>,
775 dest: &PathToken,
775 dest: &PathToken,
776 src_minor: &CopySource,
776 src_minor: &CopySource,
777 src_major: &CopySource,
777 src_major: &CopySource,
778 ) -> (MergePick, bool) {
778 ) -> (MergePick, bool) {
779 if src_major.rev == current_merge {
779 if src_major.rev == current_merge {
780 if src_minor.rev == current_merge {
780 if src_minor.rev == current_merge {
781 if src_major.path.is_none() {
781 if src_major.path.is_none() {
782 // We cannot get different copy information for both p1 and p2
782 // We cannot get different copy information for both p1 and p2
783 // from the same revision. Unless this was a
783 // from the same revision. Unless this was a
784 // deletion
784 // deletion
785 (MergePick::Any, false)
785 (MergePick::Any, false)
786 } else {
786 } else {
787 unreachable!();
787 unreachable!();
788 }
788 }
789 } else {
789 } else {
790 // The last value comes the current merge, this value -will- win
790 // The last value comes the current merge, this value -will- win
791 // eventually.
791 // eventually.
792 (MergePick::Major, true)
792 (MergePick::Major, true)
793 }
793 }
794 } else if src_minor.rev == current_merge {
794 } else if src_minor.rev == current_merge {
795 // The last value comes the current merge, this value -will- win
795 // The last value comes the current merge, this value -will- win
796 // eventually.
796 // eventually.
797 (MergePick::Minor, true)
797 (MergePick::Minor, true)
798 } else if src_major.path == src_minor.path {
798 } else if src_major.path == src_minor.path {
799 // we have the same value, but from other source;
799 // we have the same value, but from other source;
800 if src_major.rev == src_minor.rev {
800 if src_major.rev == src_minor.rev {
801 // If the two entry are identical, they are both valid
801 // If the two entry are identical, they are both valid
802 (MergePick::Any, false)
802 (MergePick::Any, false)
803 } else if oracle.is_overwrite(src_major.rev, src_minor.rev) {
803 } else if oracle.is_overwrite(src_major.rev, src_minor.rev) {
804 (MergePick::Minor, false)
804 (MergePick::Minor, false)
805 } else if oracle.is_overwrite(src_minor.rev, src_major.rev) {
805 } else if oracle.is_overwrite(src_minor.rev, src_major.rev) {
806 (MergePick::Major, false)
806 (MergePick::Major, false)
807 } else {
807 } else {
808 (MergePick::Any, true)
808 (MergePick::Any, true)
809 }
809 }
810 } else if src_major.rev == src_minor.rev {
810 } else if src_major.rev == src_minor.rev {
811 // We cannot get copy information for both p1 and p2 in the
811 // We cannot get copy information for both p1 and p2 in the
812 // same rev. So this is the same value.
812 // same rev. So this is the same value.
813 unreachable!(
813 unreachable!(
814 "conflicting information from p1 and p2 in the same revision"
814 "conflicting information from p1 and p2 in the same revision"
815 );
815 );
816 } else {
816 } else {
817 let dest_path = path_map.untokenize(*dest);
817 let dest_path = path_map.untokenize(*dest);
818 let action = changes.get_merge_case(dest_path);
818 let action = changes.get_merge_case(dest_path);
819 if src_minor.path.is_some()
819 if src_minor.path.is_some()
820 && src_major.path.is_none()
820 && src_major.path.is_none()
821 && action == MergeCase::Salvaged
821 && action == MergeCase::Salvaged
822 {
822 {
823 // If the file is "deleted" in the major side but was
823 // If the file is "deleted" in the major side but was
824 // salvaged by the merge, we keep the minor side alive
824 // salvaged by the merge, we keep the minor side alive
825 (MergePick::Minor, true)
825 (MergePick::Minor, true)
826 } else if src_major.path.is_some()
826 } else if src_major.path.is_some()
827 && src_minor.path.is_none()
827 && src_minor.path.is_none()
828 && action == MergeCase::Salvaged
828 && action == MergeCase::Salvaged
829 {
829 {
830 // If the file is "deleted" in the minor side but was
830 // If the file is "deleted" in the minor side but was
831 // salvaged by the merge, unconditionnaly preserve the
831 // salvaged by the merge, unconditionnaly preserve the
832 // major side.
832 // major side.
833 (MergePick::Major, true)
833 (MergePick::Major, true)
834 } else if oracle.is_overwrite(src_minor.rev, src_major.rev) {
834 } else if oracle.is_overwrite(src_minor.rev, src_major.rev) {
835 // The information from the minor version are strictly older than
835 // The information from the minor version are strictly older than
836 // the major version
836 // the major version
837 if action == MergeCase::Merged {
837 if action == MergeCase::Merged {
838 // If the file was actively merged, its means some non-copy
838 // If the file was actively merged, its means some non-copy
839 // activity happened on the other branch. It
839 // activity happened on the other branch. It
840 // mean the older copy information are still relevant.
840 // mean the older copy information are still relevant.
841 //
841 //
842 // The major side wins such conflict.
842 // The major side wins such conflict.
843 (MergePick::Major, true)
843 (MergePick::Major, true)
844 } else {
844 } else {
845 // No activity on the minor branch, pick the newer one.
845 // No activity on the minor branch, pick the newer one.
846 (MergePick::Major, false)
846 (MergePick::Major, false)
847 }
847 }
848 } else if oracle.is_overwrite(src_major.rev, src_minor.rev) {
848 } else if oracle.is_overwrite(src_major.rev, src_minor.rev) {
849 if action == MergeCase::Merged {
849 if action == MergeCase::Merged {
850 // If the file was actively merged, its means some non-copy
850 // If the file was actively merged, its means some non-copy
851 // activity happened on the other branch. It
851 // activity happened on the other branch. It
852 // mean the older copy information are still relevant.
852 // mean the older copy information are still relevant.
853 //
853 //
854 // The major side wins such conflict.
854 // The major side wins such conflict.
855 (MergePick::Major, true)
855 (MergePick::Major, true)
856 } else {
856 } else {
857 // No activity on the minor branch, pick the newer one.
857 // No activity on the minor branch, pick the newer one.
858 (MergePick::Minor, false)
858 (MergePick::Minor, false)
859 }
859 }
860 } else if src_minor.path.is_none() {
860 } else if src_minor.path.is_none() {
861 // the minor side has no relevant information, pick the alive one
861 // the minor side has no relevant information, pick the alive one
862 (MergePick::Major, true)
862 (MergePick::Major, true)
863 } else if src_major.path.is_none() {
863 } else if src_major.path.is_none() {
864 // the major side has no relevant information, pick the alive one
864 // the major side has no relevant information, pick the alive one
865 (MergePick::Minor, true)
865 (MergePick::Minor, true)
866 } else {
866 } else {
867 // by default the major side wins
867 // by default the major side wins
868 (MergePick::Major, true)
868 (MergePick::Major, true)
869 }
869 }
870 }
870 }
871 }
871 }
General Comments 0
You need to be logged in to leave comments. Login now