mercurial/dirstatemap.py
changeset 47692 e5fb14a07866
parent 47689 f2aef39abc14
child 47720 b0314d8deee1
--- 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)