# HG changeset patch # User Pierre-Yves David # Date 2023-03-15 04:49:56 # Node ID 9fc0d244a753d9309cc9e9da9550086041d3dea8 # Parent edcc35a4f1dc7f982dd5aef172aa0bcaa9e9ec94 dirstate: fix a potential traceback when in `copy` and `rename` Before this changes, calling `hg copy` or `hg rename` could trigger a traceback about using an invalidated dirstate. This wasn't caught by the test as it needed the blackbox extension to preload the dirstate first in a way "refresh" invalidates it. Changing the context creation patterns fixes it. diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -2498,7 +2498,7 @@ def copy(ui, repo, *pats, **opts): """ opts = pycompat.byteskwargs(opts) - context = repo.dirstate.changing_files + context = lambda repo: repo.dirstate.changing_files(repo) rev = opts.get(b'at_rev') ctx = None if rev: @@ -6012,7 +6012,7 @@ def rename(ui, repo, *pats, **opts): Returns 0 on success, 1 if errors are encountered. """ opts = pycompat.byteskwargs(opts) - context = repo.dirstate.changing_files + context = lambda repo: repo.dirstate.changing_files(repo) rev = opts.get(b'at_rev') ctx = None if rev: diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -200,6 +200,12 @@ class dirstate: self._cwd def refresh(self): + # XXX if this happens, you likely did not enter the `changing_xxx` + # using `repo.dirstate`, so a later `repo.dirstate` accesss might call + # `refresh`. + if self.is_changing_any: + msg = "refreshing the dirstate in the middle of a change" + raise error.ProgrammingError(msg) if '_branch' in vars(self): del self._branch if '_map' in vars(self) and self._map.may_need_refresh(): diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -2951,6 +2951,7 @@ class localrepository: known good state).""" unfi = self.unfiltered() if 'dirstate' in unfi.__dict__: + assert not self.dirstate.is_changing_any del unfi.__dict__['dirstate'] def invalidate(self, clearfilecache=False): diff --git a/tests/test-blackbox.t b/tests/test-blackbox.t --- a/tests/test-blackbox.t +++ b/tests/test-blackbox.t @@ -470,15 +470,16 @@ blackbox should work if repo.ui.log is n > raise RuntimeError('raise') > EOF - $ cat >> $HGRCPATH << EOF + + $ hg init $TESTTMP/blackbox-exception-only --config blackbox.track=commandexception + $ cat >> $TESTTMP/blackbox-exception-only/.hg/hgrc << EOF > [blackbox] > track = commandexception > [extensions] > raise=$TESTTMP/raise.py > EOF + $ cd $TESTTMP/blackbox-exception-only - $ hg init $TESTTMP/blackbox-exception-only - $ cd $TESTTMP/blackbox-exception-only #if chg (chg exits 255 because it fails to receive an exit code) @@ -495,3 +496,25 @@ blackbox should work if repo.ui.log is n $ tail -2 .hg/blackbox.log RuntimeError: raise + $ cd .. + +Check we did not broke `hg mv` +------------------------------ +(we did in 6.4rc) + +basic setup + + $ hg init blackbox-file-move + $ cd blackbox-file-move + $ echo foo > foo + $ hg add foo + $ hg commit -m 'foo' + +copy a file + + $ hg copy foo bar + +move a file + + $ hg mv foo goo +