Patchwork [8,of,9,sparse] sparse: move update action filtering into core

login
register
mail settings
Submitter Gregory Szorc
Date July 6, 2017, 9:54 p.m.
Message ID <61066164673a2d4213bb.1499378064@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/22061/
State Accepted
Headers show

Comments

Gregory Szorc - July 6, 2017, 9:54 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1499376320 25200
#      Thu Jul 06 14:25:20 2017 -0700
# Node ID 61066164673a2d4213bbfedc2081377b18f2d47c
# Parent  fa3cd4d3ec8273b09e684c71aa716a85dcbe9f20
sparse: move update action filtering into core

Sparse applies a filter on calculated update actions. This patch
moves the function to sparse.py and inlines the call in
merge.update() so we don't need to wrap the function.

If sparse isn't enabled, the function no-ops.

We should probably take sparse into account earlier in update().
This change preserves the existing functionality. It can be
iterated on later.
via Mercurial-devel - July 6, 2017, 11:11 p.m.
On Thu, Jul 6, 2017 at 2:54 PM, Gregory Szorc <gregory.szorc@gmail.com> wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1499376320 25200
> #      Thu Jul 06 14:25:20 2017 -0700
> # Node ID 61066164673a2d4213bbfedc2081377b18f2d47c
> # Parent  fa3cd4d3ec8273b09e684c71aa716a85dcbe9f20
> sparse: move update action filtering into core
> diff --git a/mercurial/merge.py b/mercurial/merge.py
> --- a/mercurial/merge.py
> +++ b/mercurial/merge.py
> @@ -977,6 +977,9 @@ def calculateupdates(repo, wctx, mctx, a
>                       acceptremote, followcopies, matcher=None,
>                       mergeforce=False):
>      "Calculate the actions needed to merge mctx into wctx using ancestors"
> +    # Avoid cycle.
> +    from . import sparse
> +
>      if len(ancestors) == 1: # default
>          actions, diverge, renamedelete = manifestmerge(
>              repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
> @@ -1075,7 +1078,8 @@ def calculateupdates(repo, wctx, mctx, a
>          fractions = _forgetremoved(wctx, mctx, branchmerge)
>          actions.update(fractions)
>
> -    return actions, diverge, renamedelete
> +    return sparse.calculateupdates(repo, wctx, mctx, branchmerge, actions,
> +                                   diverge, renamedelete)

This reads a little funny. Maybe rename it to
sparse.filterupdatesactions()? Should we also make it return only the
filtered actions since "diverge" and "renamedelete" are not modified?
Seems like we don't even need to pass them into the method. Maybe
split this patch up into two as well (one that moves
calculateupdates() into core and one that changes its signature and
name and starts calling it from merge.py)?

Patch

diff --git a/hgext/sparse.py b/hgext/sparse.py
--- a/hgext/sparse.py
+++ b/hgext/sparse.py
@@ -74,8 +74,6 @@  certain files::
 
 from __future__ import absolute_import
 
-import collections
-
 from mercurial.i18n import _
 from mercurial.node import nullid
 from mercurial import (
@@ -103,7 +101,6 @@  cmdtable = {}
 command = registrar.command(cmdtable)
 
 def uisetup(ui):
-    _setupupdates(ui)
     _setupcommit(ui)
 
 def extsetup(ui):
@@ -145,93 +142,6 @@  def replacefilecache(cls, propname, repl
         raise AttributeError(_("type '%s' has no property '%s'") % (origcls,
                              propname))
 
-def _setupupdates(ui):
-    def _calculateupdates(orig, repo, wctx, mctx, ancestors, branchmerge, *arg,
-                          **kwargs):
-        """Filter updates to only lay out files that match the sparse rules.
-        """
-        actions, diverge, renamedelete = orig(repo, wctx, mctx, ancestors,
-                                              branchmerge, *arg, **kwargs)
-
-        oldrevs = [pctx.rev() for pctx in wctx.parents()]
-        oldsparsematch = sparse.matcher(repo, oldrevs)
-
-        if oldsparsematch.always():
-            return actions, diverge, renamedelete
-
-        files = set()
-        prunedactions = {}
-
-        if branchmerge:
-            # If we're merging, use the wctx filter, since we're merging into
-            # the wctx.
-            sparsematch = sparse.matcher(repo, [wctx.parents()[0].rev()])
-        else:
-            # If we're updating, use the target context's filter, since we're
-            # moving to the target context.
-            sparsematch = sparse.matcher(repo, [mctx.rev()])
-
-        temporaryfiles = []
-        for file, action in actions.iteritems():
-            type, args, msg = action
-            files.add(file)
-            if sparsematch(file):
-                prunedactions[file] = action
-            elif type == 'm':
-                temporaryfiles.append(file)
-                prunedactions[file] = action
-            elif branchmerge:
-                if type != 'k':
-                    temporaryfiles.append(file)
-                    prunedactions[file] = action
-            elif type == 'f':
-                prunedactions[file] = action
-            elif file in wctx:
-                prunedactions[file] = ('r', args, msg)
-
-        if len(temporaryfiles) > 0:
-            ui.status(_("temporarily included %d file(s) in the sparse checkout"
-                " for merging\n") % len(temporaryfiles))
-            sparse.addtemporaryincludes(repo, temporaryfiles)
-
-            # Add the new files to the working copy so they can be merged, etc
-            actions = []
-            message = 'temporarily adding to sparse checkout'
-            wctxmanifest = repo[None].manifest()
-            for file in temporaryfiles:
-                if file in wctxmanifest:
-                    fctx = repo[None][file]
-                    actions.append((file, (fctx.flags(), False), message))
-
-            typeactions = collections.defaultdict(list)
-            typeactions['g'] = actions
-            mergemod.applyupdates(repo, typeactions, repo[None], repo['.'],
-                                  False)
-
-            dirstate = repo.dirstate
-            for file, flags, msg in actions:
-                dirstate.normal(file)
-
-        profiles = sparse.activeprofiles(repo)
-        changedprofiles = profiles & files
-        # If an active profile changed during the update, refresh the checkout.
-        # Don't do this during a branch merge, since all incoming changes should
-        # have been handled by the temporary includes above.
-        if changedprofiles and not branchmerge:
-            mf = mctx.manifest()
-            for file in mf:
-                old = oldsparsematch(file)
-                new = sparsematch(file)
-                if not old and new:
-                    flags = mf.flags(file)
-                    prunedactions[file] = ('g', (flags, False), '')
-                elif old and not new:
-                    prunedactions[file] = ('r', [], '')
-
-        return prunedactions, diverge, renamedelete
-
-    extensions.wrapfunction(mergemod, 'calculateupdates', _calculateupdates)
-
 def _setupcommit(ui):
     def _refreshoncommit(orig, self, node):
         """Refresh the checkout when commits touch .hgsparse
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -977,6 +977,9 @@  def calculateupdates(repo, wctx, mctx, a
                      acceptremote, followcopies, matcher=None,
                      mergeforce=False):
     "Calculate the actions needed to merge mctx into wctx using ancestors"
+    # Avoid cycle.
+    from . import sparse
+
     if len(ancestors) == 1: # default
         actions, diverge, renamedelete = manifestmerge(
             repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
@@ -1075,7 +1078,8 @@  def calculateupdates(repo, wctx, mctx, a
         fractions = _forgetremoved(wctx, mctx, branchmerge)
         actions.update(fractions)
 
-    return actions, diverge, renamedelete
+    return sparse.calculateupdates(repo, wctx, mctx, branchmerge, actions,
+                                   diverge, renamedelete)
 
 def batchremove(repo, wctx, actions):
     """apply removes to the working directory
diff --git a/mercurial/sparse.py b/mercurial/sparse.py
--- a/mercurial/sparse.py
+++ b/mercurial/sparse.py
@@ -371,3 +371,85 @@  def matcher(repo, revs=None, includetemp
     repo._sparsematchercache[key] = result
 
     return result
+
+def calculateupdates(repo, wctx, mctx, branchmerge, actions, diverge,
+                     renamedelete):
+    """Filter updates to only lay out files that match sparse rules."""
+    if not enabled:
+        return actions, diverge, renamedelete
+
+    oldrevs = [pctx.rev() for pctx in wctx.parents()]
+    oldsparsematch = matcher(repo, oldrevs)
+
+    if oldsparsematch.always():
+        return actions, diverge, renamedelete
+
+    files = set()
+    prunedactions = {}
+
+    if branchmerge:
+        # If we're merging, use the wctx filter, since we're merging into
+        # the wctx.
+        sparsematch = matcher(repo, [wctx.parents()[0].rev()])
+    else:
+        # If we're updating, use the target context's filter, since we're
+        # moving to the target context.
+        sparsematch = matcher(repo, [mctx.rev()])
+
+    temporaryfiles = []
+    for file, action in actions.iteritems():
+        type, args, msg = action
+        files.add(file)
+        if sparsematch(file):
+            prunedactions[file] = action
+        elif type == 'm':
+            temporaryfiles.append(file)
+            prunedactions[file] = action
+        elif branchmerge:
+            if type != 'k':
+                temporaryfiles.append(file)
+                prunedactions[file] = action
+        elif type == 'f':
+            prunedactions[file] = action
+        elif file in wctx:
+            prunedactions[file] = ('r', args, msg)
+
+    if len(temporaryfiles) > 0:
+        repo.ui.status(_('temporarily included %d file(s) in the sparse '
+                         'checkout for merging\n') % len(temporaryfiles))
+        addtemporaryincludes(repo, temporaryfiles)
+
+        # Add the new files to the working copy so they can be merged, etc
+        actions = []
+        message = _('temporarily adding to sparse checkout')
+        wctxmanifest = repo[None].manifest()
+        for file in temporaryfiles:
+            if file in wctxmanifest:
+                fctx = repo[None][file]
+                actions.append((file, (fctx.flags(), False), message))
+
+        typeactions = collections.defaultdict(list)
+        typeactions['g'] = actions
+        mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False)
+
+        dirstate = repo.dirstate
+        for file, flags, msg in actions:
+            dirstate.normal(file)
+
+    profiles = activeprofiles(repo)
+    changedprofiles = profiles & files
+    # If an active profile changed during the update, refresh the checkout.
+    # Don't do this during a branch merge, since all incoming changes should
+    # have been handled by the temporary includes above.
+    if changedprofiles and not branchmerge:
+        mf = mctx.manifest()
+        for file in mf:
+            old = oldsparsematch(file)
+            new = sparsematch(file)
+            if not old and new:
+                flags = mf.flags(file)
+                prunedactions[file] = ('g', (flags, False), '')
+            elif old and not new:
+                prunedactions[file] = ('r', [], '')
+
+    return prunedactions, diverge, renamedelete