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