[PATCH 7 of 9 sparse] sparse: move pruning of temporary includes into core

Gregory Szorc gregory.szorc at gmail.com
Thu Jul 6 17:54:23 EDT 2017


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1499376798 25200
#      Thu Jul 06 14:33:18 2017 -0700
# Node ID fa3cd4d3ec8273b09e684c71aa716a85dcbe9f20
# Parent  f7f5f791854ec1ee1cc8679d7cb1193f7d7f05b6
sparse: move pruning of temporary includes into core

This was our last method on the custom repo type, meaning we could
remove that custom type and inline the 2 lines of code into
reposetup().

As part of the move, instead of wrapping merge.update() from
the sparse extension, we inline the function call. The ported
function now no-ops if sparse isn't enabled, making it safe to
always call.

The call site in update() may not be the most appropriate. But
it matches the previous behavior, which is the safest thing
to do. It can be improved later.

diff --git a/hgext/sparse.py b/hgext/sparse.py
--- a/hgext/sparse.py
+++ b/hgext/sparse.py
@@ -126,7 +126,8 @@ def reposetup(ui, repo):
     if not util.safehasattr(repo, 'dirstate'):
         return
 
-    _wraprepo(ui, repo)
+    if 'dirstate' in repo._filecache:
+        repo.dirstate.repo = repo
 
 def replacefilecache(cls, propname, replacement):
     """Replace a filecache property with a new class. This allows changing the
@@ -231,17 +232,6 @@ def _setupupdates(ui):
 
     extensions.wrapfunction(mergemod, 'calculateupdates', _calculateupdates)
 
-    def _update(orig, repo, node, branchmerge, *args, **kwargs):
-        results = orig(repo, node, branchmerge, *args, **kwargs)
-
-        # If we're updating to a location, clean up any stale temporary includes
-        # (ex: this happens during hg rebase --abort).
-        if not branchmerge and util.safehasattr(repo, 'prunetemporaryincludes'):
-            repo.prunetemporaryincludes()
-        return results
-
-    extensions.wrapfunction(mergemod, 'update', _update)
-
 def _setupcommit(ui):
     def _refreshoncommit(orig, self, node):
         """Refresh the checkout when commits touch .hgsparse
@@ -258,8 +248,7 @@ def _setupcommit(ui):
             origsparsematch = sparse.matcher(repo)
             _refresh(repo.ui, repo, origstatus, origsparsematch, True)
 
-        if util.safehasattr(repo, 'prunetemporaryincludes'):
-            repo.prunetemporaryincludes()
+        sparse.prunetemporaryincludes(repo)
 
     extensions.wrapfunction(context.committablectx, 'markcommitted',
         _refreshoncommit)
@@ -410,47 +399,6 @@ def _setupdirstate(ui):
             return orig(self, *args)
         extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
 
-def _wraprepo(ui, repo):
-    class SparseRepo(repo.__class__):
-        def prunetemporaryincludes(self):
-            if repo.vfs.exists('tempsparse'):
-                origstatus = self.status()
-                modified, added, removed, deleted, a, b, c = origstatus
-                if modified or added or removed or deleted:
-                    # Still have pending changes. Don't bother trying to prune.
-                    return
-
-                sparsematch = sparse.matcher(self, includetemp=False)
-                dirstate = self.dirstate
-                actions = []
-                dropped = []
-                tempincludes = sparse.readtemporaryincludes(self)
-                for file in tempincludes:
-                    if file in dirstate and not sparsematch(file):
-                        message = 'dropping temporarily included sparse files'
-                        actions.append((file, None, message))
-                        dropped.append(file)
-
-                typeactions = collections.defaultdict(list)
-                typeactions['r'] = actions
-                mergemod.applyupdates(self, typeactions, self[None], self['.'],
-                                      False)
-
-                # Fix dirstate
-                for file in dropped:
-                    dirstate.drop(file)
-
-                self.vfs.unlink('tempsparse')
-                sparse.invalidatesignaturecache(self)
-                msg = _("cleaned up %d temporarily added file(s) from the "
-                        "sparse checkout\n")
-                ui.status(msg % len(tempincludes))
-
-    if 'dirstate' in repo._filecache:
-        repo.dirstate.repo = repo
-
-    repo.__class__ = SparseRepo
-
 @command('^debugsparse', [
     ('I', 'include', False, _('include files in the sparse checkout')),
     ('X', 'exclude', False, _('exclude files in the sparse checkout')),
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1515,6 +1515,8 @@ def update(repo, node, branchmerge, forc
 
     Return the same tuple as applyupdates().
     """
+    # Avoid cycle.
+    from . import sparse
 
     # This function used to find the default destination if node was None, but
     # that's now in destutil.py.
@@ -1704,6 +1706,11 @@ def update(repo, node, branchmerge, forc
                 if not branchmerge:
                     repo.dirstate.setbranch(p2.branch())
 
+    # If we're updating to a location, clean up any stale temporary includes
+    # (ex: this happens during hg rebase --abort).
+    if not branchmerge:
+        sparse.prunetemporaryincludes(repo)
+
     if not partial:
         repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
     return stats
diff --git a/mercurial/sparse.py b/mercurial/sparse.py
--- a/mercurial/sparse.py
+++ b/mercurial/sparse.py
@@ -7,6 +7,7 @@
 
 from __future__ import absolute_import
 
+import collections
 import hashlib
 import os
 
@@ -15,6 +16,7 @@ from .node import nullid
 from . import (
     error,
     match as matchmod,
+    merge as mergemod,
     pycompat,
     util,
 )
@@ -198,6 +200,41 @@ def addtemporaryincludes(repo, additiona
         includes.add(i)
     writetemporaryincludes(repo, includes)
 
+def prunetemporaryincludes(repo):
+    if not enabled or not repo.vfs.exists('tempsparse'):
+        return
+
+    origstatus = repo.status()
+    modified, added, removed, deleted, a, b, c = origstatus
+    if modified or added or removed or deleted:
+        # Still have pending changes. Don't bother trying to prune.
+        return
+
+    sparsematch = matcher(repo, includetemp=False)
+    dirstate = repo.dirstate
+    actions = []
+    dropped = []
+    tempincludes = readtemporaryincludes(repo)
+    for file in tempincludes:
+        if file in dirstate and not sparsematch(file):
+            message = _('dropping temporarily included sparse files')
+            actions.append((file, None, message))
+            dropped.append(file)
+
+    typeactions = collections.defaultdict(list)
+    typeactions['r'] = actions
+    mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False)
+
+    # Fix dirstate
+    for file in dropped:
+        dirstate.drop(file)
+
+    repo.vfs.unlink('tempsparse')
+    invalidatesignaturecache(repo)
+    msg = _('cleaned up %d temporarily added file(s) from the '
+            'sparse checkout\n')
+    repo.ui.status(msg % len(tempincludes))
+
 class forceincludematcher(matchmod.basematcher):
     """A matcher that returns true for any of the forced includes before testing
     against the actual matcher."""


More information about the Mercurial-devel mailing list