diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c --- a/mercurial/cext/parsers.c +++ b/mercurial/cext/parsers.c @@ -507,6 +507,17 @@ Py_RETURN_NONE; } +static PyObject *dirstate_item_set_tracked(dirstateItemObject *self) +{ + self->flags |= dirstate_flag_wc_tracked; + self->flags |= dirstate_flag_possibly_dirty; + /* size = None on the python size turn into size = NON_NORMAL when + * accessed. So the next line is currently required, but a some future + * clean up would be welcome. */ + self->size = dirstate_v1_nonnormal; + Py_RETURN_NONE; +} + static PyObject *dirstate_item_set_untracked(dirstateItemObject *self) { self->flags &= ~dirstate_flag_wc_tracked; @@ -548,6 +559,8 @@ METH_NOARGS, "mark a file as \"possibly dirty\""}, {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS, "mark a file as \"clean\""}, + {"set_tracked", (PyCFunction)dirstate_item_set_tracked, METH_NOARGS, + "mark a file as \"tracked\""}, {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS, "mark a file as \"untracked\""}, {NULL} /* Sentinel */ diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -478,18 +478,9 @@ self._dirty = True self._updatedfiles.add(filename) entry = self._map.get(filename) - if entry is None: + if entry is None or not entry.tracked: self._check_new_tracked_filename(filename) - self._map.addfile(filename, added=True) - return True - elif not entry.tracked: - self._normallookup(filename) - return True - # XXX This is probably overkill for more case, but we need this to - # fully replace the `normallookup` call with `set_tracked` one. - # Consider smoothing this in the future. - self.set_possibly_dirty(filename) - return False + return self._map.set_tracked(filename) @requires_no_parents_change def set_untracked(self, filename): diff --git a/mercurial/dirstatemap.py b/mercurial/dirstatemap.py --- a/mercurial/dirstatemap.py +++ b/mercurial/dirstatemap.py @@ -307,6 +307,36 @@ self.otherparentset.discard(filename) self._map[filename] = entry + def set_tracked(self, filename): + new = False + entry = self.get(filename) + if entry is None: + self._dirs_incr(filename) + entry = DirstateItem( + p1_tracked=False, + p2_tracked=False, + wc_tracked=True, + merged=False, + clean_p1=False, + clean_p2=False, + possibly_dirty=False, + parentfiledata=None, + ) + self._map[filename] = entry + if entry.dm_nonnormal: + self.nonnormalset.add(filename) + new = True + elif not entry.tracked: + self._dirs_incr(filename, entry) + entry.set_tracked() + new = True + else: + # XXX This is probably overkill for more case, but we need this to + # fully replace the `normallookup` call with `set_tracked` one. + # Consider smoothing this in the future. + self.set_possibly_dirty(filename) + return new + def set_untracked(self, f): """Mark a file as no longer tracked in the dirstate map""" entry = self.get(f) @@ -663,6 +693,23 @@ else: assert False, 'unreachable' + def set_tracked(self, filename): + new = False + entry = self.get(filename) + if entry is None: + self.addfile(filename, added=True) + new = True + elif not entry.tracked: + entry.set_tracked() + self._rustmap.set_v1(filename, entry) + new = True + else: + # XXX This is probably overkill for more case, but we need this to + # fully replace the `normallookup` call with `set_tracked` one. + # Consider smoothing this in the future. + self.set_possibly_dirty(filename) + return new + 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. diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py --- a/mercurial/pure/parsers.py +++ b/mercurial/pure/parsers.py @@ -240,6 +240,18 @@ self._size = size self._mtime = mtime + def set_tracked(self): + """mark a file as tracked in the working copy + + This will ultimately be called by command like `hg add`. + """ + self._wc_tracked = True + # `set_tracked` is replacing various `normallookup` call. So we set + # "possibly dirty" to stay on the safe side. + # + # Consider dropping this in the future in favor of something less broad. + self._possibly_dirty = True + def set_untracked(self): """mark a file as untracked in the working copy