Esempio n. 1
0
def func(parser, options, args):
    """Repair inconsistencies in StGit metadata."""
    if args:
        parser.error('incorrect number of arguments')

    repository = directory.repository
    stack = repository.get_stack()

    if stack.protected:
        raise CmdException(
            'This branch is protected. Modification is not permitted.')

    patchorder = stack.patchorder
    patches = [stack.patches.get(pn) for pn in patchorder.all]

    # Find commits that aren't patches, and applied patches.
    patchify = []  # commits to definitely patchify
    maybe_patchify = []  # commits to patchify if we find a patch below them
    applied = []
    c = stack.head
    while len(c.data.parents) == 1:
        for p in patches:
            if p.commit == c:
                applied.append(p)
                patchify.extend(maybe_patchify)
                maybe_patchify = []
                break
        else:
            maybe_patchify.append(c)
        c = c.data.parent
    applied.reverse()
    patchify.reverse()

    # Find patches unreachable behind a merge.
    merge = c
    todo = set([c])
    seen = set()
    unreachable = set()
    while todo:
        c = todo.pop()
        seen.add(c)
        todo |= set(c.data.parents) - seen
        if any(p.commit == c for p in patches):
            unreachable.add(c)
    if unreachable:
        out.warn(('%d patch%s are hidden below the merge commit' %
                  (len(unreachable), ['es', ''][len(unreachable) == 1])),
                 '%s,' % merge.sha1, 'and will be considered unapplied.')

    # Make patches of any linear sequence of commits on top of a patch.
    if applied and patchify:
        out.start('Creating %d new patch%s' %
                  (len(patchify), ['es', ''][len(patchify) == 1]))

        for c in patchify:
            pn = make_patch_name(
                c.data.message,
                unacceptable=lambda name: any(p.name == name for p in patches),
            )
            out.info('Creating patch %s from commit %s' % (pn, c.sha1))
            applied.append(stack.patches.new(pn, c, 'repair'))
        out.done()

    # Figure out hidden
    hidden = [p for p in patches if p.name in patchorder.hidden]

    # Write the applied/unapplied files.
    out.start('Checking patch appliedness')
    unapplied = [p for p in patches if p not in applied and p not in hidden]
    for pn in patchorder.all:
        if all(pn != p.name for p in patches):
            out.info('%s is gone' % pn)
    for p in applied:
        if p.name not in patchorder.applied:
            out.info('%s is now applied' % p.name)
    for p in unapplied:
        if p.name not in patchorder.unapplied:
            out.info('%s is now unapplied' % p.name)
    for p in hidden:
        if p.name not in patchorder.hidden:
            out.info('%s is now hidden' % p.name)
    out.done()

    orig_order = dict((pn, i) for i, pn in enumerate(patchorder.all))

    def patchname_key(p):
        i = orig_order.get(p, len(orig_order))
        return i, p

    trans = StackTransaction(stack,
                             'repair',
                             check_clean_iw=False,
                             allow_bad_head=True)
    try:
        trans.applied = [p.name for p in applied]
        trans.unapplied = sorted((p.name for p in unapplied),
                                 key=patchname_key)
        trans.hidden = sorted((p.name for p in hidden), key=patchname_key)
    except TransactionHalted:
        pass
    return trans.run()
def func(parser, options, args):
    """Repair inconsistencies in StGit metadata."""
    if args:
        parser.error('incorrect number of arguments')

    repository = directory.repository
    stack = repository.get_stack()

    if stack.protected:
        raise CmdException(
            'This branch is protected. Modification is not permitted.')

    patchorder = stack.patchorder
    patches = list(patchorder.all)

    # Find commits that aren't patches, and applied patches.
    patchify = []  # commits to definitely patchify
    maybe_patchify = []  # commits to patchify if we find a patch below them
    applied = []
    c = stack.head
    while len(c.data.parents) == 1:
        for pn in patchorder.all:
            if stack.patches[pn] == c:
                applied.append(pn)
                patchify.extend(maybe_patchify)
                maybe_patchify = []
                break
        else:
            maybe_patchify.append(c)

        c = c.data.parent

        if stack.base == c:
            # Reaching the original stack base can happen if, for example, the first
            # applied patch is amended. In this case, any commits descending from the
            # stack base should be patchified.
            patchify.extend(maybe_patchify)
            maybe_patchify = []

            # Once the base commit has been found, we know that no existing patches
            # can be found be searching further.
            break

    applied.reverse()
    patchify.reverse()

    # Find patches unreachable behind a merge.
    if c != stack.base:
        merge = c
        todo = set([c])
        seen = set()
        unreachable = set()
        while todo:
            c = todo.pop()
            seen.add(c)
            todo |= set(c.data.parents) - seen
            if any(stack.patches[pn] == c for pn in patches):
                unreachable.add(c)
        if unreachable:
            out.warn(
                ('%d patch%s are hidden below the merge commit' %
                 (len(unreachable), ['es', ''][len(unreachable) == 1])),
                '%s,' % merge.sha1,
                'and will be considered unapplied.',
            )

    # Make patches of any linear sequence of commits on top of a patch.
    if patchify:
        out.start('Creating %d new patch%s' %
                  (len(patchify), ['es', ''][len(patchify) == 1]))

        for c in patchify:
            pn = stack.patches.make_name(c.data.message_str)
            out.info('Creating patch %s from commit %s' % (pn, c.sha1))
            stack.patches.new(pn, c, 'repair')
            applied.append(pn)
        out.done()

    # Figure out hidden
    hidden = [pn for pn in patches if pn in patchorder.hidden]

    # Write the applied/unapplied files.
    out.start('Checking patch appliedness')
    unapplied = [
        pn for pn in patches if pn not in applied and pn not in hidden
    ]
    for pn in patchorder.all:
        if pn not in patches:
            out.info('%s is gone' % pn)
    for pn in applied:
        if pn not in patchorder.applied:
            out.info('%s is now applied' % pn)
    for pn in unapplied:
        if pn not in patchorder.unapplied:
            out.info('%s is now unapplied' % pn)
    for pn in hidden:
        if pn not in patchorder.hidden:
            out.info('%s is now hidden' % pn)
    out.done()

    orig_order = {pn: i for i, pn in enumerate(patchorder.all)}

    def patchname_key(p):
        i = orig_order.get(p, len(orig_order))
        return i, p

    trans = StackTransaction(stack)
    try:
        trans.applied = applied
        trans.unapplied = sorted(unapplied, key=patchname_key)
        trans.hidden = sorted(hidden, key=patchname_key)
    except TransactionHalted:
        pass
    return trans.execute('repair')