hgext/narrow/narrowmerge.py
changeset 36079 a2a6e724d61a
child 36165 53fe5a1a92bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/narrow/narrowmerge.py	Mon Jan 29 16:19:33 2018 -0500
@@ -0,0 +1,76 @@
+# narrowmerge.py - extensions to mercurial merge module to support narrow clones
+#
+# Copyright 2017 Google, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+from mercurial.i18n import _
+from mercurial import (
+    copies,
+    error,
+    extensions,
+    merge,
+    util,
+)
+
+def setup():
+    def _manifestmerge(orig, repo, wctx, p2, pa, branchmerge, *args, **kwargs):
+        """Filter updates to only lay out files that match the narrow spec."""
+        actions, diverge, renamedelete = orig(
+            repo, wctx, p2, pa, branchmerge, *args, **kwargs)
+
+        if not util.safehasattr(repo, 'narrowmatch'):
+            return actions, diverge, renamedelete
+
+        nooptypes = set(['k']) # TODO: handle with nonconflicttypes
+        nonconflicttypes = set('a am c cm f g r e'.split())
+        narrowmatch = repo.narrowmatch()
+        for f, action in actions.items():
+            if narrowmatch(f):
+                pass
+            elif not branchmerge:
+                del actions[f] # just updating, ignore changes outside clone
+            elif action[0] in nooptypes:
+                del actions[f] # merge does not affect file
+            elif action[0] in nonconflicttypes:
+                raise error.Abort(_('merge affects file \'%s\' outside narrow, '
+                                    'which is not yet supported') % f,
+                                  hint=_('merging in the other direction '
+                                         'may work'))
+            else:
+                raise error.Abort(_('conflict in file \'%s\' is outside '
+                                    'narrow clone') % f)
+
+        return actions, diverge, renamedelete
+
+    extensions.wrapfunction(merge, 'manifestmerge', _manifestmerge)
+
+    def _checkcollision(orig, repo, wmf, actions):
+        if util.safehasattr(repo, 'narrowmatch'):
+            narrowmatch = repo.narrowmatch()
+            wmf = wmf.matches(narrowmatch)
+            if actions:
+                narrowactions = {}
+                for m, actionsfortype in actions.iteritems():
+                    narrowactions[m] = []
+                    for (f, args, msg) in actionsfortype:
+                        if narrowmatch(f):
+                            narrowactions[m].append((f, args, msg))
+                actions = narrowactions
+        return orig(repo, wmf, actions)
+
+    extensions.wrapfunction(merge, '_checkcollision', _checkcollision)
+
+    def _computenonoverlap(orig, repo, *args, **kwargs):
+        u1, u2 = orig(repo, *args, **kwargs)
+        if not util.safehasattr(repo, 'narrowmatch'):
+            return u1, u2
+
+        narrowmatch = repo.narrowmatch()
+        u1 = [f for f in u1 if narrowmatch(f)]
+        u2 = [f for f in u2 if narrowmatch(f)]
+        return u1, u2
+    extensions.wrapfunction(copies, '_computenonoverlap', _computenonoverlap)