view hgext/narrow/narrowmerge.py @ 36160:9fd8c2a3db5a

narrowspec: move module into core Having support for parsing the narrow specification in core is necessary for moving many other parts of narrow to core. We do still want to harmonize the narrow spec with the sparse spec. And the format needs to be documented. But this shouldn't hold up the code moving to core. Differential Revision: https://phab.mercurial-scm.org/D2201
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 12 Feb 2018 16:21:34 -0800
parents a2a6e724d61a
children 53fe5a1a92bd
line wrap: on
line source

# 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)