diff --git a/hgext/absorb.py b/hgext/absorb.py --- a/hgext/absorb.py +++ b/hgext/absorb.py @@ -881,7 +881,7 @@ class fixupstate: dirstate._fsmonitorstate.invalidate = noop try: - with dirstate.parentchange(self.repo): + with dirstate.changing_parents(self.repo): dirstate.rebuild(ctx.node(), ctx.manifest(), self.paths) finally: restore() diff --git a/hgext/fix.py b/hgext/fix.py --- a/hgext/fix.py +++ b/hgext/fix.py @@ -776,7 +776,7 @@ def writeworkingdir(repo, ctx, filedata, newp1 = replacements.get(oldp1, oldp1) if newp1 != oldp1: assert repo.dirstate.p2() == nullid - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): scmutil.movedirstate(repo, repo[newp1]) diff --git a/hgext/git/dirstate.py b/hgext/git/dirstate.py --- a/hgext/git/dirstate.py +++ b/hgext/git/dirstate.py @@ -384,7 +384,7 @@ class gitdirstate: pass @contextlib.contextmanager - def parentchange(self, repo): + def changing_parents(self, repo): # TODO: track this maybe? yield diff --git a/hgext/keyword.py b/hgext/keyword.py --- a/hgext/keyword.py +++ b/hgext/keyword.py @@ -696,7 +696,7 @@ def kw_amend(orig, ui, repo, old, extra, kwt = getattr(repo, '_keywordkwt', None) if kwt is None: return orig(ui, repo, old, extra, pats, opts) - with repo.wlock(), repo.dirstate.parentchange(repo): + with repo.wlock(), repo.dirstate.changing_parents(repo): kwt.postcommit = True newid = orig(ui, repo, old, extra, pats, opts) if newid != old.node(): @@ -762,7 +762,7 @@ def kw_dorecord(orig, ui, repo, commitfu if ctx != recctx: modified, added = _preselect(wstatus, recctx.files()) kwt.restrict = False - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): kwt.overwrite(recctx, modified, False, True) kwt.overwrite(recctx, added, False, True, True) kwt.restrict = True diff --git a/hgext/largefiles/lfcommands.py b/hgext/largefiles/lfcommands.py --- a/hgext/largefiles/lfcommands.py +++ b/hgext/largefiles/lfcommands.py @@ -517,7 +517,7 @@ def updatelfiles( filelist = set(filelist) lfiles = [f for f in lfiles if f in filelist] - with lfdirstate.parentchange(repo): + with lfdirstate.changing_parents(repo): update = {} dropped = set() updated, removed = 0, 0 @@ -580,7 +580,7 @@ def updatelfiles( statuswriter(_(b'getting changed largefiles\n')) cachelfiles(ui, repo, None, lfiles) - with lfdirstate.parentchange(repo): + with lfdirstate.changing_parents(repo): for lfile in lfiles: update1 = 0 diff --git a/hgext/largefiles/lfutil.py b/hgext/largefiles/lfutil.py --- a/hgext/largefiles/lfutil.py +++ b/hgext/largefiles/lfutil.py @@ -231,7 +231,7 @@ def openlfdirstate(ui, repo, create=True if len(standins) > 0: vfs.makedirs(lfstoredir) - with lfdirstate.parentchange(repo): + with lfdirstate.changing_parents(repo): for standin in standins: lfile = splitstandin(standin) lfdirstate.update_file( @@ -581,7 +581,7 @@ def markcommitted(orig, ctx, node): repo = ctx.repo() lfdirstate = openlfdirstate(repo.ui, repo) - with lfdirstate.parentchange(repo): + with lfdirstate.changing_parents(repo): orig(node) # ATTENTION: "ctx.files()" may differ from "repo[node].files()" diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -660,7 +660,7 @@ def overridecalculateupdates( def mergerecordupdates(orig, repo, actions, branchmerge, getfiledata): if MERGE_ACTION_LARGEFILE_MARK_REMOVED in actions: lfdirstate = lfutil.openlfdirstate(repo.ui, repo) - with lfdirstate.parentchange(repo): + with lfdirstate.changing_parents(repo): for lfile, args, msg in actions[ MERGE_ACTION_LARGEFILE_MARK_REMOVED ]: @@ -1800,7 +1800,7 @@ def mergeupdate(orig, repo, node, branch raise error.ProgrammingError( b'largefiles is not compatible with in-memory merge' ) - with lfdirstate.parentchange(repo): + with lfdirstate.changing_parents(repo): result = orig(repo, node, branchmerge, force, *args, **kwargs) newstandins = lfutil.getstandinsstate(repo) diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -1082,7 +1082,7 @@ class queue: if merge and files: # Mark as removed/merged and update dirstate parent info - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): for f in files: repo.dirstate.update_file_p1(f, p1_tracked=True) p1 = repo.dirstate.p1() @@ -1830,7 +1830,7 @@ class queue: if keepchanges and tobackup: raise error.Abort(_(b"local changes found, qrefresh first")) self.backup(repo, tobackup) - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): for f in a: repo.wvfs.unlinkpath(f, ignoremissing=True) repo.dirstate.update_file( @@ -1988,7 +1988,7 @@ class queue: bmlist = repo[top].bookmarks() - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): # XXX do we actually need the dirstateguard dsguard = None try: diff --git a/hgext/narrow/narrowcommands.py b/hgext/narrow/narrowcommands.py --- a/hgext/narrow/narrowcommands.py +++ b/hgext/narrow/narrowcommands.py @@ -320,7 +320,7 @@ def _narrow( repo.store.markremoved(f) ui.status(_(b'deleting unwanted files from working copy\n')) - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): narrowspec.updateworkingcopy(repo, assumeclean=True) narrowspec.copytoworkingcopy(repo) @@ -380,7 +380,7 @@ def _widen( if ellipsesremote: ds = repo.dirstate p1, p2 = ds.p1(), ds.p2() - with ds.parentchange(repo): + with ds.changing_parents(repo): ds.setparents(repo.nullid, repo.nullid) if isoldellipses: with wrappedextraprepare: @@ -419,10 +419,12 @@ def _widen( bundle2.processbundle(repo, bundle, op=op, remote=remote) if ellipsesremote: - with ds.parentchange(repo): + with ds.changing_parents(repo): ds.setparents(p1, p2) - with repo.transaction(b'widening'), repo.dirstate.parentchange(repo): + with repo.transaction(b'widening'), repo.dirstate.changing_parents( + repo + ): repo.setnewnarrowpats() narrowspec.updateworkingcopy(repo) narrowspec.copytoworkingcopy(repo) @@ -591,7 +593,7 @@ def trackedcmd(ui, repo, remotepath=None if update_working_copy: with repo.wlock(), repo.lock(), repo.transaction( b'narrow-wc' - ), repo.dirstate.parentchange(repo): + ), repo.dirstate.changing_parents(repo): narrowspec.updateworkingcopy(repo) narrowspec.copytoworkingcopy(repo) return 0 diff --git a/hgext/split.py b/hgext/split.py --- a/hgext/split.py +++ b/hgext/split.py @@ -134,7 +134,7 @@ def dosplit(ui, repo, tr, ctx, opts): # Set working parent to ctx.p1(), and keep working copy as ctx's content if ctx.node() != repo.dirstate.p1(): hg.clean(repo, ctx.node(), show_stats=False) - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): scmutil.movedirstate(repo, ctx.p1()) # Any modified, added, removed, deleted result means split is incomplete diff --git a/hgext/uncommit.py b/hgext/uncommit.py --- a/hgext/uncommit.py +++ b/hgext/uncommit.py @@ -236,7 +236,7 @@ def uncommit(ui, repo, *pats, **opts): # Fully removed the old commit mapping[old.node()] = () - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): scmutil.movedirstate(repo, repo[newid], match) scmutil.cleanupnodes(repo, mapping, b'uncommit', fixphase=True) @@ -317,7 +317,7 @@ def unamend(ui, repo, **opts): newpredctx = repo[newprednode] dirstate = repo.dirstate - with dirstate.parentchange(repo): + with dirstate.changing_parents(repo): scmutil.movedirstate(repo, newpredctx) mapping = {curctx.node(): (newprednode,)} diff --git a/hgext/win32text.py b/hgext/win32text.py --- a/hgext/win32text.py +++ b/hgext/win32text.py @@ -216,7 +216,7 @@ def reposetup(ui, repo): def wrap_revert(orig, repo, ctx, names, uipathfn, actions, *args, **kwargs): # reset dirstate cache for file we touch ds = repo.dirstate - with ds.parentchange(repo): + with ds.changing_parents(repo): for filename in actions[b'revert'][0]: entry = ds.get_entry(filename) if entry is not None: diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -638,7 +638,7 @@ def dorecord( # already called within a `pendingchange`, However we # are taking a shortcut here in order to be able to # quickly deprecated the older API. - with dirstate.parentchange(repo): + with dirstate.changing_parents(repo): dirstate.update_file( realname, p1_tracked=True, @@ -1532,7 +1532,7 @@ def copy(ui, repo, pats, opts, rename=Fa new_node = mem_ctx.commit() if repo.dirstate.p1() == ctx.node(): - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): scmutil.movedirstate(repo, repo[new_node]) replacements = {ctx.node(): [new_node]} scmutil.cleanupnodes( @@ -1625,7 +1625,7 @@ def copy(ui, repo, pats, opts, rename=Fa new_node = mem_ctx.commit() if repo.dirstate.p1() == ctx.node(): - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): scmutil.movedirstate(repo, repo[new_node]) replacements = {ctx.node(): [new_node]} scmutil.cleanupnodes(repo, replacements, b'copy', fixphase=True) @@ -3024,7 +3024,7 @@ def amend(ui, repo, old, extra, pats, op newid = repo.commitctx(new) ms.reset() - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): # Reroute the working copy parent to the new changeset repo.setparents(newid, repo.nullid) diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -6264,7 +6264,7 @@ def resolve(ui, repo, *pats, **opts): # # All this should eventually happens, but in the mean time, we use this # context manager slightly out of the context it should be. - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None) if not didwork and pats: diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -1595,7 +1595,7 @@ class workingctx(committablectx): if p2node is None: p2node = self._repo.nodeconstants.nullid dirstate = self._repo.dirstate - with dirstate.parentchange(self._repo): + with dirstate.changing_parents(self._repo): copies = dirstate.setparents(p1node, p2node) pctx = self._repo[p1node] if copies: @@ -2050,7 +2050,7 @@ class workingctx(committablectx): return sorted(f for f in ds.matches(match) if ds.get_entry(f).tracked) def markcommitted(self, node): - with self._repo.dirstate.parentchange(self._repo): + with self._repo.dirstate.changing_parents(self._repo): for f in self.modified() + self.added(): self._repo.dirstate.update_file( f, p1_tracked=True, wc_tracked=True diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -69,7 +69,7 @@ class rootcache(filecache): def requires_parents_change(func): def wrap(self, *args, **kwargs): if not self.pendingparentchange(): - msg = 'calling `%s` outside of a parentchange context' + msg = 'calling `%s` outside of a changing_parents context' msg %= func.__name__ raise error.ProgrammingError(msg) if self._invalidated_context: @@ -83,7 +83,7 @@ def requires_parents_change(func): def requires_no_parents_change(func): def wrap(self, *args, **kwargs): if self.pendingparentchange(): - msg = 'calling `%s` inside of a parentchange context' + msg = 'calling `%s` inside of a changing_parents context' msg %= func.__name__ raise error.ProgrammingError(msg) return func(self, *args, **kwargs) @@ -127,7 +127,7 @@ class dirstate: self._dirty_tracked_set = False self._ui = ui self._filecache = {} - # nesting level of `parentchange` context + # nesting level of `changing_parents` context self._parentwriters = 0 # True if the current dirstate changing operations have been # invalidated (used to make sure all nested contexts have been exited) @@ -151,7 +151,7 @@ class dirstate: self._pl @contextlib.contextmanager - def parentchange(self, repo): + def changing_parents(self, repo): """Context manager for handling dirstate parents. If an exception occurs in the scope of the context manager, @@ -180,6 +180,14 @@ class dirstate: assert self._parentwriters == 0 self._invalidated_context = False + # here to help migration to the new code + def parentchange(self): + msg = ( + "Mercurial 6.4 and later requires call to " + "`dirstate.changing_parents(repo)`" + ) + raise error.ProgrammingError(msg) + def pendingparentchange(self): """Returns true if the dirstate is in the middle of a set of changes that modify the dirstate parent. @@ -399,7 +407,7 @@ class dirstate: if self._parentwriters == 0: raise ValueError( b"cannot set dirstate parent outside of " - b"dirstate.parentchange context manager" + b"dirstate.changing_parents context manager" ) self._dirty = True @@ -523,7 +531,7 @@ class dirstate: rewriting operation. It should not be called during a merge (p2 != nullid) and only within - a `with dirstate.parentchange(repo):` context. + a `with dirstate.changing_parents(repo):` context. """ if self.in_merge: msg = b'update_file_reference should not be called when merging' @@ -566,7 +574,7 @@ class dirstate: This is to be called when the direstates parent changes to keep track of what is the file situation in regards to the working copy and its parent. - This function must be called within a `dirstate.parentchange` context. + This function must be called within a `dirstate.changing_parents` context. note: the API is at an early stage and we might need to adjust it depending of what information ends up being relevant and useful to diff --git a/mercurial/interfaces/dirstate.py b/mercurial/interfaces/dirstate.py --- a/mercurial/interfaces/dirstate.py +++ b/mercurial/interfaces/dirstate.py @@ -35,7 +35,7 @@ class idirstate(interfaceutil.Interface) _checkexec = interfaceutil.Attribute("""Callable for checking exec bits.""") @contextlib.contextmanager - def parentchange(repo): + def changing_parents(repo): """Context manager for handling dirstate parents. If an exception occurs in the scope of the context manager, diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -2155,7 +2155,7 @@ def _update( assert len(getfiledata) == ( mresult.len((mergestatemod.ACTION_GET,)) if wantfiledata else 0 ) - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): ### Filter Filedata # # We gathered "cache" information for the clean file while @@ -2377,7 +2377,7 @@ def graft( # fix up dirstate for copies and renames copies.graftcopies(wctx, ctx, base) else: - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): repo.setparents(pctx.node(), pother) repo.dirstate.write(repo.currenttransaction()) # fix up dirstate for copies and renames diff --git a/mercurial/shelve.py b/mercurial/shelve.py --- a/mercurial/shelve.py +++ b/mercurial/shelve.py @@ -637,7 +637,7 @@ def _docreatecmd(ui, repo, pats, opts): ui.status(_(b'shelved as %s\n') % name) if opts[b'keep']: - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): scmutil.movedirstate(repo, parent, match) else: hg.update(repo, parent.node()) @@ -862,14 +862,14 @@ def unshelvecontinue(ui, repo, state, op shelvectx = repo[state.parents[1]] pendingctx = state.pendingctx - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): repo.setparents(state.pendingctx.node(), repo.nullid) repo.dirstate.write(repo.currenttransaction()) targetphase = _target_phase(repo) overrides = {(b'phases', b'new-commit'): targetphase} with repo.ui.configoverride(overrides, b'unshelve'): - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): repo.setparents(state.parents[0], repo.nullid) newnode, ispartialunshelve = _createunshelvectx( ui, repo, shelvectx, basename, interactive, opts @@ -1068,7 +1068,7 @@ def _rebaserestoredcommit( ) raise error.ConflictResolutionRequired(b'unshelve') - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): repo.setparents(tmpwctx.node(), repo.nullid) newnode, ispartialunshelve = _createunshelvectx( ui, repo, shelvectx, basename, interactive, opts diff --git a/mercurial/sparse.py b/mercurial/sparse.py --- a/mercurial/sparse.py +++ b/mercurial/sparse.py @@ -451,7 +451,7 @@ def filterupdatesactions(repo, wctx, mct message, ) - with repo.dirstate.parentchange(repo): + with repo.dirstate.changing_parents(repo): mergemod.applyupdates( repo, tmresult, @@ -655,7 +655,7 @@ def clearrules(repo, force=False): The remaining sparse config only has profiles, if defined. The working directory is refreshed, as needed. """ - with repo.wlock(), repo.dirstate.parentchange(repo): + with repo.wlock(), repo.dirstate.changing_parents(repo): raw = repo.vfs.tryread(b'sparse') includes, excludes, profiles = parseconfig(repo.ui, raw, b'sparse') @@ -671,7 +671,7 @@ def importfromfiles(repo, opts, paths, f The updated sparse config is written out and the working directory is refreshed, as needed. """ - with repo.wlock(), repo.dirstate.parentchange(repo): + with repo.wlock(), repo.dirstate.changing_parents(repo): # read current configuration raw = repo.vfs.tryread(b'sparse') includes, excludes, profiles = parseconfig(repo.ui, raw, b'sparse') @@ -730,7 +730,7 @@ def updateconfig( The new config is written out and a working directory refresh is performed. """ - with repo.wlock(), repo.lock(), repo.dirstate.parentchange(repo): + with repo.wlock(), repo.lock(), repo.dirstate.changing_parents(repo): raw = repo.vfs.tryread(b'sparse') oldinclude, oldexclude, oldprofiles = parseconfig( repo.ui, raw, b'sparse' diff --git a/tests/test-narrow-expanddirstate.t b/tests/test-narrow-expanddirstate.t --- a/tests/test-narrow-expanddirstate.t +++ b/tests/test-narrow-expanddirstate.t @@ -74,7 +74,7 @@ have this method available in narrowhg p > narrowspec.copytoworkingcopy(repo) > newmatcher = narrowspec.match(repo.root, includes, excludes) > added = matchmod.differencematcher(newmatcher, currentmatcher) - > with repo.dirstate.parentchange(repo): + > with repo.dirstate.changing_parents(repo): > for f in repo[b'.'].manifest().walk(added): > repo.dirstate.update_file( > f, diff --git a/tests/test-rebuildstate.t b/tests/test-rebuildstate.t --- a/tests/test-rebuildstate.t +++ b/tests/test-rebuildstate.t @@ -17,7 +17,7 @@ > try: > for file in pats: > if opts.get('normal_lookup'): - > with repo.dirstate.parentchange(repo): + > with repo.dirstate.changing_parents(repo): > repo.dirstate.update_file( > file, > p1_tracked=True,