comparison mercurial/dirstatemap.py @ 47692:e5fb14a07866

dirstate-map: move most of `dirstate.update_file` logic in the dsmap A new `reset_state` method is introduced to deal with most of that logic. This move things one layer lower, but the ultimate goal is to deal with most of this at the DirstateItem level. This reveal various imperfection with the data passed to update_file by `mergestate.recordupdates`, however this is orthogonal to this patch and should be dealt with at a higher level. Differential Revision: https://phab.mercurial-scm.org/D11134
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 19 Jul 2021 07:23:55 +0200
parents f2aef39abc14
children b0314d8deee1
comparison
equal deleted inserted replaced
47691:33beeb32f73a 47692:e5fb14a07866
217 if e.dm_nonnormal: 217 if e.dm_nonnormal:
218 self.nonnormalset.add(f) 218 self.nonnormalset.add(f)
219 if e.dm_otherparent: 219 if e.dm_otherparent:
220 self.otherparentset.add(f) 220 self.otherparentset.add(f)
221 221
222 def reset_state(
223 self,
224 filename,
225 wc_tracked,
226 p1_tracked,
227 p2_tracked=False,
228 merged=False,
229 clean_p1=False,
230 clean_p2=False,
231 possibly_dirty=False,
232 parentfiledata=None,
233 ):
234 """Set a entry to a given state, diregarding all previous state
235
236 This is to be used by the part of the dirstate API dedicated to
237 adjusting the dirstate after a update/merge.
238
239 note: calling this might result to no entry existing at all if the
240 dirstate map does not see any point at having one for this file
241 anymore.
242 """
243 if merged and (clean_p1 or clean_p2):
244 msg = b'`merged` argument incompatible with `clean_p1`/`clean_p2`'
245 raise error.ProgrammingError(msg)
246 # copy information are now outdated
247 # (maybe new information should be in directly passed to this function)
248 self.copymap.pop(filename, None)
249
250 if not (p1_tracked or p2_tracked or wc_tracked):
251 self.dropfile(filename)
252 elif merged:
253 # XXX might be merged and removed ?
254 entry = self.get(filename)
255 if entry is not None and entry.tracked:
256 # XXX mostly replicate dirstate.other parent. We should get
257 # the higher layer to pass us more reliable data where `merged`
258 # actually mean merged. Dropping the else clause will show
259 # failure in `test-graft.t`
260 self.addfile(filename, merged=True)
261 else:
262 self.addfile(filename, from_p2=True)
263 elif not (p1_tracked or p2_tracked) and wc_tracked:
264 self.addfile(filename, added=True, possibly_dirty=possibly_dirty)
265 elif (p1_tracked or p2_tracked) and not wc_tracked:
266 # XXX might be merged and removed ?
267 old_entry = self._map.get(filename)
268 self._dirs_decr(filename, old_entry=old_entry, remove_variant=True)
269 self._map[filename] = DirstateItem(b'r', 0, 0, 0)
270 self.nonnormalset.add(filename)
271 elif clean_p2 and wc_tracked:
272 if p1_tracked or self.get(filename) is not None:
273 # XXX the `self.get` call is catching some case in
274 # `test-merge-remove.t` where the file is tracked in p1, the
275 # p1_tracked argument is False.
276 #
277 # In addition, this seems to be a case where the file is marked
278 # as merged without actually being the result of a merge
279 # action. So thing are not ideal here.
280 self.addfile(filename, merged=True)
281 else:
282 self.addfile(filename, from_p2=True)
283 elif not p1_tracked and p2_tracked and wc_tracked:
284 self.addfile(filename, from_p2=True, possibly_dirty=possibly_dirty)
285 elif possibly_dirty:
286 self.addfile(filename, possibly_dirty=possibly_dirty)
287 elif wc_tracked:
288 # this is a "normal" file
289 if parentfiledata is None:
290 msg = b'failed to pass parentfiledata for a normal file: %s'
291 msg %= filename
292 raise error.ProgrammingError(msg)
293 mode, size, mtime = parentfiledata
294 self.addfile(filename, mode=mode, size=size, mtime=mtime)
295 self.nonnormalset.discard(filename)
296 else:
297 assert False, 'unreachable'
298
222 def removefile(self, f, in_merge=False): 299 def removefile(self, f, in_merge=False):
223 """ 300 """
224 Mark a file as removed in the dirstate. 301 Mark a file as removed in the dirstate.
225 302
226 The `size` parameter is used to store sentinel values that indicate 303 The `size` parameter is used to store sentinel values that indicate
497 merged, 574 merged,
498 from_p2, 575 from_p2,
499 possibly_dirty, 576 possibly_dirty,
500 ) 577 )
501 578
579 def reset_state(
580 self,
581 filename,
582 wc_tracked,
583 p1_tracked,
584 p2_tracked=False,
585 merged=False,
586 clean_p1=False,
587 clean_p2=False,
588 possibly_dirty=False,
589 parentfiledata=None,
590 ):
591 """Set a entry to a given state, disregarding all previous state
592
593 This is to be used by the part of the dirstate API dedicated to
594 adjusting the dirstate after a update/merge.
595
596 note: calling this might result to no entry existing at all if the
597 dirstate map does not see any point at having one for this file
598 anymore.
599 """
600 if merged and (clean_p1 or clean_p2):
601 msg = (
602 b'`merged` argument incompatible with `clean_p1`/`clean_p2`'
603 )
604 raise error.ProgrammingError(msg)
605 # copy information are now outdated
606 # (maybe new information should be in directly passed to this function)
607 self.copymap.pop(filename, None)
608
609 if not (p1_tracked or p2_tracked or wc_tracked):
610 self.dropfile(filename)
611 elif merged:
612 # XXX might be merged and removed ?
613 entry = self.get(filename)
614 if entry is not None and entry.tracked:
615 # XXX mostly replicate dirstate.other parent. We should get
616 # the higher layer to pass us more reliable data where `merged`
617 # actually mean merged. Dropping the else clause will show
618 # failure in `test-graft.t`
619 self.addfile(filename, merged=True)
620 else:
621 self.addfile(filename, from_p2=True)
622 elif not (p1_tracked or p2_tracked) and wc_tracked:
623 self.addfile(
624 filename, added=True, possibly_dirty=possibly_dirty
625 )
626 elif (p1_tracked or p2_tracked) and not wc_tracked:
627 # XXX might be merged and removed ?
628 self[filename] = DirstateItem(b'r', 0, 0, 0)
629 self.nonnormalset.add(filename)
630 elif clean_p2 and wc_tracked:
631 if p1_tracked or self.get(filename) is not None:
632 # XXX the `self.get` call is catching some case in
633 # `test-merge-remove.t` where the file is tracked in p1, the
634 # p1_tracked argument is False.
635 #
636 # In addition, this seems to be a case where the file is marked
637 # as merged without actually being the result of a merge
638 # action. So thing are not ideal here.
639 self.addfile(filename, merged=True)
640 else:
641 self.addfile(filename, from_p2=True)
642 elif not p1_tracked and p2_tracked and wc_tracked:
643 self.addfile(
644 filename, from_p2=True, possibly_dirty=possibly_dirty
645 )
646 elif possibly_dirty:
647 self.addfile(filename, possibly_dirty=possibly_dirty)
648 elif wc_tracked:
649 # this is a "normal" file
650 if parentfiledata is None:
651 msg = b'failed to pass parentfiledata for a normal file: %s'
652 msg %= filename
653 raise error.ProgrammingError(msg)
654 mode, size, mtime = parentfiledata
655 self.addfile(filename, mode=mode, size=size, mtime=mtime)
656 self.nonnormalset.discard(filename)
657 else:
658 assert False, 'unreachable'
659
502 def removefile(self, *args, **kwargs): 660 def removefile(self, *args, **kwargs):
503 return self._rustmap.removefile(*args, **kwargs) 661 return self._rustmap.removefile(*args, **kwargs)
504 662
505 def dropfile(self, *args, **kwargs): 663 def dropfile(self, *args, **kwargs):
506 return self._rustmap.dropfile(*args, **kwargs) 664 return self._rustmap.dropfile(*args, **kwargs)
746 f = {} 904 f = {}
747 normcase = util.normcase 905 normcase = util.normcase
748 for name in self._rustmap.tracked_dirs(): 906 for name in self._rustmap.tracked_dirs():
749 f[normcase(name)] = name 907 f[normcase(name)] = name
750 return f 908 return f
909
910 def __setitem__(self, key, value):
911 assert isinstance(value, DirstateItem)
912 self._rustmap.set_v1(key, value)