--- a/mercurial/dirstatemap.py Fri Jul 16 22:30:11 2021 +0200
+++ b/mercurial/dirstatemap.py Mon Jul 19 07:23:55 2021 +0200
@@ -219,6 +219,83 @@
if e.dm_otherparent:
self.otherparentset.add(f)
+ def reset_state(
+ self,
+ filename,
+ wc_tracked,
+ p1_tracked,
+ p2_tracked=False,
+ merged=False,
+ clean_p1=False,
+ clean_p2=False,
+ possibly_dirty=False,
+ parentfiledata=None,
+ ):
+ """Set a entry to a given state, diregarding all previous state
+
+ This is to be used by the part of the dirstate API dedicated to
+ adjusting the dirstate after a update/merge.
+
+ note: calling this might result to no entry existing at all if the
+ dirstate map does not see any point at having one for this file
+ anymore.
+ """
+ if merged and (clean_p1 or clean_p2):
+ msg = b'`merged` argument incompatible with `clean_p1`/`clean_p2`'
+ raise error.ProgrammingError(msg)
+ # copy information are now outdated
+ # (maybe new information should be in directly passed to this function)
+ self.copymap.pop(filename, None)
+
+ if not (p1_tracked or p2_tracked or wc_tracked):
+ self.dropfile(filename)
+ elif merged:
+ # XXX might be merged and removed ?
+ entry = self.get(filename)
+ if entry is not None and entry.tracked:
+ # XXX mostly replicate dirstate.other parent. We should get
+ # the higher layer to pass us more reliable data where `merged`
+ # actually mean merged. Dropping the else clause will show
+ # failure in `test-graft.t`
+ self.addfile(filename, merged=True)
+ else:
+ self.addfile(filename, from_p2=True)
+ elif not (p1_tracked or p2_tracked) and wc_tracked:
+ self.addfile(filename, added=True, possibly_dirty=possibly_dirty)
+ elif (p1_tracked or p2_tracked) and not wc_tracked:
+ # XXX might be merged and removed ?
+ old_entry = self._map.get(filename)
+ self._dirs_decr(filename, old_entry=old_entry, remove_variant=True)
+ self._map[filename] = DirstateItem(b'r', 0, 0, 0)
+ self.nonnormalset.add(filename)
+ elif clean_p2 and wc_tracked:
+ if p1_tracked or self.get(filename) is not None:
+ # XXX the `self.get` call is catching some case in
+ # `test-merge-remove.t` where the file is tracked in p1, the
+ # p1_tracked argument is False.
+ #
+ # In addition, this seems to be a case where the file is marked
+ # as merged without actually being the result of a merge
+ # action. So thing are not ideal here.
+ self.addfile(filename, merged=True)
+ else:
+ self.addfile(filename, from_p2=True)
+ elif not p1_tracked and p2_tracked and wc_tracked:
+ self.addfile(filename, from_p2=True, possibly_dirty=possibly_dirty)
+ elif possibly_dirty:
+ self.addfile(filename, possibly_dirty=possibly_dirty)
+ elif wc_tracked:
+ # this is a "normal" file
+ if parentfiledata is None:
+ msg = b'failed to pass parentfiledata for a normal file: %s'
+ msg %= filename
+ raise error.ProgrammingError(msg)
+ mode, size, mtime = parentfiledata
+ self.addfile(filename, mode=mode, size=size, mtime=mtime)
+ self.nonnormalset.discard(filename)
+ else:
+ assert False, 'unreachable'
+
def removefile(self, f, in_merge=False):
"""
Mark a file as removed in the dirstate.
@@ -499,6 +576,87 @@
possibly_dirty,
)
+ def reset_state(
+ self,
+ filename,
+ wc_tracked,
+ p1_tracked,
+ p2_tracked=False,
+ merged=False,
+ clean_p1=False,
+ clean_p2=False,
+ possibly_dirty=False,
+ parentfiledata=None,
+ ):
+ """Set a entry to a given state, disregarding all previous state
+
+ This is to be used by the part of the dirstate API dedicated to
+ adjusting the dirstate after a update/merge.
+
+ note: calling this might result to no entry existing at all if the
+ dirstate map does not see any point at having one for this file
+ anymore.
+ """
+ if merged and (clean_p1 or clean_p2):
+ msg = (
+ b'`merged` argument incompatible with `clean_p1`/`clean_p2`'
+ )
+ raise error.ProgrammingError(msg)
+ # copy information are now outdated
+ # (maybe new information should be in directly passed to this function)
+ self.copymap.pop(filename, None)
+
+ if not (p1_tracked or p2_tracked or wc_tracked):
+ self.dropfile(filename)
+ elif merged:
+ # XXX might be merged and removed ?
+ entry = self.get(filename)
+ if entry is not None and entry.tracked:
+ # XXX mostly replicate dirstate.other parent. We should get
+ # the higher layer to pass us more reliable data where `merged`
+ # actually mean merged. Dropping the else clause will show
+ # failure in `test-graft.t`
+ self.addfile(filename, merged=True)
+ else:
+ self.addfile(filename, from_p2=True)
+ elif not (p1_tracked or p2_tracked) and wc_tracked:
+ self.addfile(
+ filename, added=True, possibly_dirty=possibly_dirty
+ )
+ elif (p1_tracked or p2_tracked) and not wc_tracked:
+ # XXX might be merged and removed ?
+ self[filename] = DirstateItem(b'r', 0, 0, 0)
+ self.nonnormalset.add(filename)
+ elif clean_p2 and wc_tracked:
+ if p1_tracked or self.get(filename) is not None:
+ # XXX the `self.get` call is catching some case in
+ # `test-merge-remove.t` where the file is tracked in p1, the
+ # p1_tracked argument is False.
+ #
+ # In addition, this seems to be a case where the file is marked
+ # as merged without actually being the result of a merge
+ # action. So thing are not ideal here.
+ self.addfile(filename, merged=True)
+ else:
+ self.addfile(filename, from_p2=True)
+ elif not p1_tracked and p2_tracked and wc_tracked:
+ self.addfile(
+ filename, from_p2=True, possibly_dirty=possibly_dirty
+ )
+ elif possibly_dirty:
+ self.addfile(filename, possibly_dirty=possibly_dirty)
+ elif wc_tracked:
+ # this is a "normal" file
+ if parentfiledata is None:
+ msg = b'failed to pass parentfiledata for a normal file: %s'
+ msg %= filename
+ raise error.ProgrammingError(msg)
+ mode, size, mtime = parentfiledata
+ self.addfile(filename, mode=mode, size=size, mtime=mtime)
+ self.nonnormalset.discard(filename)
+ else:
+ assert False, 'unreachable'
+
def removefile(self, *args, **kwargs):
return self._rustmap.removefile(*args, **kwargs)
@@ -748,3 +906,7 @@
for name in self._rustmap.tracked_dirs():
f[normcase(name)] = name
return f
+
+ def __setitem__(self, key, value):
+ assert isinstance(value, DirstateItem)
+ self._rustmap.set_v1(key, value)