# HG changeset patch # User Pierre-Yves David # Date 1629451621 -7200 # Node ID 3853e6ee160d381e78dec4dbd4bb748c6109047b # Parent 6614ab9f061df7f99023416a16f10297e2095676 dirstatemap: replace `removefile` by an explicit `entry.set_untracked()` All the other caller goes through `reset_state`, so we can safely have an explicit method on `DirstateItem` object. This means that all the logic to preserve the previous state (from p2, merged, etc) is now properly encapsulated within the DirstateItem. This pave the way to using different storage for these information. Differential Revision: https://phab.mercurial-scm.org/D11315 diff -r 6614ab9f061d -r 3853e6ee160d mercurial/cext/parsers.c --- a/mercurial/cext/parsers.c Fri Aug 20 11:23:52 2021 +0200 +++ b/mercurial/cext/parsers.c Fri Aug 20 11:27:01 2021 +0200 @@ -223,6 +223,21 @@ Py_RETURN_NONE; } +static PyObject *dirstate_item_set_untracked(dirstateItemObject *self) +{ + if (self->state == 'm') { + self->size = dirstate_v1_nonnormal; + } else if (self->state == 'n' && self->size == dirstate_v1_from_p2) { + self->size = dirstate_v1_from_p2; + } else { + self->size = 0; + } + self->state = 'r'; + self->mode = 0; + self->mtime = 0; + Py_RETURN_NONE; +} + static PyMethodDef dirstate_item_methods[] = { {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS, "return a \"state\" suitable for v1 serialization"}, @@ -238,6 +253,8 @@ "build a new DirstateItem object from V1 data"}, {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty, METH_NOARGS, "mark a file as \"possibly dirty\""}, + {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS, + "mark a file as \"untracked\""}, {"dm_nonnormal", (PyCFunction)dm_nonnormal, METH_NOARGS, "True is the entry is non-normal in the dirstatemap sense"}, {"dm_otherparent", (PyCFunction)dm_otherparent, METH_NOARGS, diff -r 6614ab9f061d -r 3853e6ee160d mercurial/dirstate.py --- a/mercurial/dirstate.py Fri Aug 20 11:23:52 2021 +0200 +++ b/mercurial/dirstate.py Fri Aug 20 11:27:01 2021 +0200 @@ -502,7 +502,7 @@ else: self._dirty = True self._updatedfiles.add(filename) - self._map.removefile(filename, in_merge=self.in_merge) + self._map.set_untracked(filename) return True @requires_no_parents_change diff -r 6614ab9f061d -r 3853e6ee160d mercurial/dirstatemap.py --- a/mercurial/dirstatemap.py Fri Aug 20 11:23:52 2021 +0200 +++ b/mercurial/dirstatemap.py Fri Aug 20 11:27:01 2021 +0200 @@ -303,32 +303,15 @@ else: assert False, 'unreachable' - def removefile(self, f, in_merge=False): - """ - Mark a file as removed in the dirstate. - - The `size` parameter is used to store sentinel values that indicate - the file's previous state. In the future, we should refactor this - to be more explicit about what that state is. - """ - entry = self.get(f) - size = 0 - if in_merge: - # XXX we should not be able to have 'm' state and 'FROM_P2' if not - # during a merge. So I (marmoute) am not sure we need the - # conditionnal at all. Adding double checking this with assert - # would be nice. - if entry is not None: - # backup the previous state - if entry.merged: # merge - size = NONNORMAL - elif entry.from_p2: - size = FROM_P2 - self.otherparentset.add(f) - if entry is not None and not (entry.merged or entry.from_p2): + def set_untracked(self, f): + """Mark a file as no longer tracked in the dirstate map""" + entry = self[f] + self._dirs_decr(f, old_entry=entry, remove_variant=True) + if entry.from_p2: + self.otherparentset.add(f) + elif not entry.merged: self.copymap.pop(f, None) - self._dirs_decr(f, old_entry=entry, remove_variant=True) - self._map[f] = DirstateItem(b'r', 0, size, 0) + entry.set_untracked() self.nonnormalset.add(f) def dropfile(self, f): @@ -664,6 +647,14 @@ else: assert False, 'unreachable' + def set_untracked(self, f): + """Mark a file as no longer tracked in the dirstate map""" + # in merge is only trigger more logic, so it "fine" to pass it. + # + # the inner rust dirstate map code need to be adjusted once the API + # for dirstate/dirstatemap/DirstateItem is a bit more settled + self._rustmap.removefile(f, in_merge=True) + def removefile(self, *args, **kwargs): return self._rustmap.removefile(*args, **kwargs) diff -r 6614ab9f061d -r 3853e6ee160d mercurial/pure/parsers.py --- a/mercurial/pure/parsers.py Fri Aug 20 11:23:52 2021 +0200 +++ b/mercurial/pure/parsers.py Fri Aug 20 11:27:01 2021 +0200 @@ -89,6 +89,22 @@ """ self._mtime = AMBIGUOUS_TIME + def set_untracked(self): + """mark a file as untracked in the working copy + + This will ultimately be called by command like `hg remove`. + """ + # backup the previous state (useful for merge) + size = 0 + if self.merged: # merge + size = NONNORMAL + elif self.from_p2: + size = FROM_P2 + self._state = b'r' + self._mode = 0 + self._size = size + self._mtime = 0 + def __getitem__(self, idx): if idx == 0 or idx == -4: msg = b"do not use item[x], use item.state"