hgext3rd/topic/stack.py
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
Sun, 14 Aug 2016 19:57:58 +0200
changeset 1985 03d6b685c16a
parent 1982 d87fc4f749e6
child 1988 9a5d797d25be
permissions -rw-r--r--
topic: list the number of 'behind' changeset when --verbose is used Displaying more information in the topic list is useful, we continue with the number of 'behind' changesets. This 'behind' count the number of new changesets on the default rebase destination. This will highlight topics that need rebasing.

# stack.py - code related to stack workflow
#
# 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.i18n import _
from mercurial import (
    destutil,
    error,
    node,
)
from .evolvebits import builddependencies, _orderrevs, _singlesuccessor

def getstack(repo, topic):
    # XXX need sorting
    trevs = repo.revs("topic(%s) - obsolete()", topic)
    return _orderrevs(repo, trevs)

def showstack(ui, repo, topic, opts):
    if not topic:
        topic = repo.currenttopic
    if not topic:
        raise error.Abort(_('no active topic to list'))
    fm = ui.formatter('topicstack', opts)
    prev = None
    entries = []
    for idx, r in enumerate(getstack(repo, topic), 1):
        ctx = repo[r]
        p1 = ctx.p1()
        if p1.obsolete():
            p1 = repo[_singlesuccessor(repo, p1)]
        if p1.rev() != prev and p1.node() != node.nullid:
            entries.append((None, p1))
        entries.append((idx, ctx))
        prev = r

    # super crude initial version
    for idx, ctx in entries[::-1]:
        if idx is None:
            symbol = '^'
            state = 'base'
        elif repo.revs('%d and parents()', ctx.rev()):
            symbol = '@'
            state = 'current'
        elif repo.revs('%d and unstable()', ctx.rev()):
            symbol = '$'
            state = 'unstable'
        else:
            symbol = ':'
            state = 'clean'
        fm.startitem()
        if idx is None:
            fm.plain('  ')
        else:
            fm.write('topic.stack.index', 't%d', idx,
                     label='topic.stack.index topic.stack.index.%s' % state)
        fm.write('topic.stack.state.symbol', '%s', symbol,
                 label='topic.stack.state topic.stack.state.%s' % state)
        fm.plain(' ')
        fm.write('topic.stack.desc', '%s', ctx.description().splitlines()[0],
                 label='topic.stack.desc topic.stack.desc.%s' % state)
        fm.condwrite(state != 'clean' and idx is not None, 'topic.stack.state',
                     ' (%s)', state,
                     label='topic.stack.state topic.stack.state.%s' % state)
        fm.plain('\n')
        fm.end()

def stackdata(repo, topic):
    """get various data about a stack

    :changesetcount: number of non-obsolete changesets in the stack
    :troubledcount: number on troubled changesets
    :headcount: number of heads on the topic
    :behindcount: number of changeset on rebase destination
    """
    data = {}
    revs = repo.revs("topic(%s) - obsolete()", topic)
    data['changesetcount'] = len(revs)
    data['troubledcount'] = len([r for r in revs if repo[r].troubled()])
    deps, rdeps = builddependencies(repo, revs)
    data['headcount'] = len([r for r in revs if not rdeps[r]])
    data['behindcount'] = 0
    if revs:
        minroot = [min(r for r in revs if not deps[r])]
        try:
            dest = destutil.destmerge(repo, action='rebase',
                                      sourceset=minroot,
                                      onheadcheck=False)
            data['behindcount'] = len(repo.revs("only(%d, %ld)", dest,
                                                minroot))
        except error.NoMergeDestAbort:
            data['behindcount'] = 0
        except error.ManyMergeDestAbort:
            data['behindcount'] = -1

    return data