narrow: delegate the dirstate's narrow spec writing to the transaction
This make it more transactional and will help us to simplify their backup.
The implementation is not great, but it keep the patch simple as this is not the
time for a larger refactoring yet.
--- a/mercurial/localrepo.py Thu Feb 23 04:15:16 2023 +0100
+++ b/mercurial/localrepo.py Thu Feb 23 03:25:44 2023 +0100
@@ -1470,6 +1470,7 @@
self._postdsstatus = []
self._pending_narrow_pats = None
+ self._pending_narrow_pats_dirstate = None
# generic mapping between names and nodes
self.names = namespaces.namespaces()
--- a/mercurial/narrowspec.py Thu Feb 23 04:15:16 2023 +0100
+++ b/mercurial/narrowspec.py Thu Feb 23 03:25:44 2023 +0100
@@ -212,8 +212,34 @@
def copytoworkingcopy(repo):
+ repo = repo.unfiltered()
+ tr = repo.currenttransaction()
spec = format(*repo.narrowpats)
- repo.vfs.write(DIRSTATE_FILENAME, spec)
+ if tr is None:
+ repo.vfs.write(DIRSTATE_FILENAME, spec)
+ else:
+
+ reporef = weakref.ref(repo)
+
+ def clean_pending(tr):
+ r = reporef()
+ if r is not None:
+ r._pending_narrow_pats_dirstate = None
+
+ tr.addpostclose(b'narrow-spec-dirstate', clean_pending)
+ tr.addabort(b'narrow-spec-dirstate', clean_pending)
+ repo._pending_narrow_pats_dirstate = repo.narrowpats
+
+ def write_spec(f):
+ f.write(spec)
+
+ tr.addfilegenerator(
+ # XXX think about order at some point
+ b"narrow-spec-dirstate",
+ (DIRSTATE_FILENAME,),
+ write_spec,
+ location=b'plain',
+ )
def savebackup(repo, backupname):
@@ -328,8 +354,10 @@
if getattr(repo, '_updatingnarrowspec', False):
return
storespec = repo.narrowpats
- wcspec = repo.vfs.tryread(DIRSTATE_FILENAME)
- wcspec = parseconfig(repo.ui, wcspec)
+ wcspec = repo._pending_narrow_pats_dirstate
+ if wcspec is None:
+ oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+ wcspec = parseconfig(repo.ui, oldspec)
if wcspec != storespec:
raise error.StateError(
_(b"working copy's narrowspec is stale"),
@@ -343,11 +371,15 @@
When assumeclean=True, files that are not known to be clean will also
be deleted. It is then up to the caller to make sure they are clean.
"""
- oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+ old = repo._pending_narrow_pats_dirstate
+ if old is None:
+ oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+ oldincludes, oldexcludes = parseconfig(repo.ui, oldspec)
+ else:
+ oldincludes, oldexcludes = old
newincludes, newexcludes = repo.narrowpats
repo._updatingnarrowspec = True
- oldincludes, oldexcludes = parseconfig(repo.ui, oldspec)
oldmatch = match(repo.root, include=oldincludes, exclude=oldexcludes)
newmatch = match(repo.root, include=newincludes, exclude=newexcludes)
addedmatch = matchmod.differencematcher(newmatch, oldmatch)