# HG changeset patch # User Pierre-Yves David # Date 1674749784 -3600 # Node ID 0dc2fb4b4b117c1d59e5e9548b454d0319ced613 # Parent e1cff85484e2d74af921284b4edad01d7cfa0e8e dirstate: factor the "changing" context logic out This makes it reusable for other types of changes. diff -r e1cff85484e2 -r 0dc2fb4b4b11 mercurial/dirstate.py --- a/mercurial/dirstate.py Thu Jan 26 15:50:45 2023 +0100 +++ b/mercurial/dirstate.py Thu Jan 26 17:16:24 2023 +0100 @@ -91,6 +91,9 @@ return wrap +CHANGE_TYPE_PARENTS = "parents" + + @interfaceutil.implementer(intdirstate.idirstate) class dirstate: def __init__( @@ -129,6 +132,8 @@ self._filecache = {} # nesting level of `changing_parents` context self._changing_level = 0 + # the change currently underway + self._change_type = None # True if the current dirstate changing operations have been # invalidated (used to make sure all nested contexts have been exited) self._invalidated_context = False @@ -151,19 +156,25 @@ self._pl @contextlib.contextmanager - def changing_parents(self, repo): - """Context manager for handling dirstate parents. - - If an exception occurs in the scope of the context manager, - the incoherent dirstate won't be written when wlock is - released. - """ + def _changing(self, repo, change_type): if repo.currentwlock() is None: - msg = b"changing parents without holding the wlock" + msg = b"trying to change the dirstate without holding the wlock" raise error.ProgrammingError(msg) if self._invalidated_context: msg = "trying to use an invalidated dirstate before it has reset" raise error.ProgrammingError(msg) + + # different type of change are mutually exclusive + if self._change_type is None: + assert self._changing_level == 0 + self._change_type = change_type + elif self._change_type != change_type: + msg = ( + 'trying to open "%s" dirstate-changing context while a "%s" is' + ' already open' + ) + msg %= (change_type, self._change_type) + raise error.ProgrammingError(msg) self._changing_level += 1 try: yield @@ -180,6 +191,7 @@ # The invalidation is complete once we exit the final context # manager if self._changing_level <= 0: + self._change_type = None assert self._changing_level == 0 if self._invalidated_context: self._invalidated_context = False @@ -194,6 +206,11 @@ # instead of the top level one. self.write(repo.currenttransaction()) + @contextlib.contextmanager + def changing_parents(self, repo): + with self._changing(repo, CHANGE_TYPE_PARENTS) as c: + yield c + # here to help migration to the new code def parentchange(self): msg = ( @@ -211,6 +228,9 @@ return self._changing_level > 0 def pendingparentchange(self): + return self.is_changing_parent() + + def is_changing_parent(self): """Returns true if the dirstate is in the middle of a set of changes that modify the dirstate parent. """ @@ -222,7 +242,9 @@ """Returns true if the dirstate is in the middle of a set of changes that modify the dirstate parent. """ - return self._changing_level > 0 + if self._changing_level <= 0: + return False + return self._change_type == CHANGE_TYPE_PARENTS @propertycache def _map(self):