author Axel Hecht <>
Fri, 08 May 2015 15:08:25 +0200
changeset 8 419586e1ba6646830b6cd5873af7d7fedd4edfe2
parent 7 d019b6817a312147d7061058afb50d74c48a345d
permissions -rw-r--r--
Use version-control-tools, the new home of hghooks.

# Copyright 2011 Mozilla Foundation
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from mercurial import hg, commands

class BaseMerge(object):
    def __call__(self, ui, repo, src, **opts):
        """Pull from src and do a no-op merge of the old head in this repository if present"""
        old_default_heads = repo.branchheads('default')
        assert len(old_default_heads) < 2
        if commands.pull(ui, repo, src, branch=['default']) == 1:
            return 1
        # if we have more than one head, fixup the old default head
        new_default_heads = repo.branchheads('default')
        if len(new_default_heads) > 1 and old_default_heads:
            assert len(repo.branchheads('default')) == 2
            old_head = old_default_heads[0]
            new_head = (old_head == new_default_heads[0]) and new_default_heads[1] \
                       or new_default_heads[0]
            old_head = repo[old_head].hex()
            new_head = repo[new_head].hex()
            if self.fixup(ui, repo, old_head, new_head, **opts) == 1:
                return 1
        assert len(repo.branchheads('default')) < 2
        return 0

    def fixup(self, ui, repo, old_head, new_head, **opts):
        raise NotImplementedError

class CloseBranch(BaseMerge):
    def fixup(self, ui, repo, old_head, new_head, **opts):
        if commands.update(ui, repo, node=old_head):
            return 1
        return commands.commit(ui, repo, close_branch=True, **opts)

revert_opts = filter(lambda t:t[0]=='C', commands.table['revert'][1])
class NoOpMerge(BaseMerge):
    def fixup(self, ui, repo, old_head, new_head, **opts):
        if commands.update(ui, repo, node=new_head, clean=True):
            return 1
        # override merge tool. Sadly, merge doesn't read options from ui, but repo.ui.
        repo.ui.setconfig('ui', 'merge', 'internal:local')
        # make us non-interactive, gives default answers if file actions conflict.
        repo.ui.setconfig('ui', 'interactive', False)
        if commands.merge(ui, repo, node=old_head):
            return 1
        ropts = {
            'rev': new_head,
            'all': True,
            'date': None
        if 'no_backup' in opts:
            ropts['no_backup'] = opts['no_backup']
        if commands.revert(ui, repo, **ropts):
            return 1
        return commands.commit(ui, repo, **opts)

def count_heads(ui, repo, **kwargs):
    """Count the maximum number of heads across the branches"""
    headcount = 0
    for b in repo.branchtags():
        headcount = max(headcount, len(repo.branchheads(b)))

cmdtable = {
     commands.commitopts + commands.commitopts2,
     'hg close-branch SOURCE'),
     commands.commitopts + commands.commitopts2 +
     'hg no-op-merge SOURCE')