# HG changeset patch # User Pierre-Yves David # Date 2023-01-25 18:12:31 # Node ID 7a8bfc05b6918f03e2d3387fc945b81c9333f435 # Parent c166b212bdeeaaf7ed2ced4c90742c89a450f065 dirstate: rename parentchange to changing_parents Since the new argument breaks the API anyway, we can rename it to a better name. The previous name `parentchange` might be seen as something active, a function that would directly change the parents, however this is just a context manager to frame the operation that will change the parents and adjust the dirstate content accordingly. In addition, the future sister method that will be about changes to tracking and files would have a hard time fitting in the same naming scheme in a clear way. The new naming uses a clear prefix will make it more distinct from other dirstate methods and easier to extend with other similar contexts. 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,