示例#1
0
def absorb(stack, patch_name, temp_name, edit_fun, annotate=None):
    """Absorb the temp patch into the target patch."""
    if annotate:
        log_msg = 'refresh\n\n' + annotate
    else:
        log_msg = 'refresh'
    trans = transaction.StackTransaction(stack, log_msg)
    iw = stack.repository.default_iw
    f = {
        True: absorb_applied,
        False: absorb_unapplied
    }[patch_name in trans.applied]
    if f(trans, iw, patch_name, temp_name, edit_fun):

        def info_msg():
            pass
    else:

        def info_msg():
            out.warn(
                'The new changes did not apply cleanly to %s.' % patch_name,
                'They were saved in %s.' % temp_name)

    r = trans.run(iw)
    info_msg()
    return r
示例#2
0
文件: reset.py 项目: wberrier/stgit
def func(parser, options, args):
    stack = directory.repository.current_stack
    iw = stack.repository.default_iw
    if len(args) >= 1:
        ref, patches = args[0], args[1:]
        state = log.get_log_entry(
            stack.repository, ref, stack.repository.rev_parse(ref)
        )
    elif options.hard:
        iw.checkout_hard(stack.head.data.tree)
        return utils.STGIT_SUCCESS
    else:
        raise CmdException('Wrong options or number of arguments')

    trans = transaction.StackTransaction(
        stack, 'reset', discard_changes=options.hard, allow_bad_head=True,
    )
    try:
        if patches:
            log.reset_stack_partially(trans, iw, state, patches)
        else:
            log.reset_stack(trans, iw, state)
    except transaction.TransactionHalted:
        pass
    return trans.run(iw, allow_bad_head=not patches)
示例#3
0
文件: publish.py 项目: snits/stgit
def __get_published(stack, tree):
    """Check the patches that were already published."""
    trans = transaction.StackTransaction(stack, 'publish')
    published = trans.check_merged(trans.applied, tree=tree, quiet=True)
    trans.abort()

    return published
示例#4
0
def func(parser, options, args):
    """Commit a number of patches."""
    stack = directory.repository.current_stack
    args = common.parse_patches(args, list(stack.patchorder.all_visible))
    if len([x for x in [args, options.number is not None, options.all] if x]) > 1:
        parser.error('too many options')
    if args:
        patches = [pn for pn in stack.patchorder.all_visible if pn in args]
        bad = set(args) - set(patches)
        if bad:
            raise common.CmdException('Nonexistent or hidden patch names: %s'
                                      % ', '.join(sorted(bad)))
    elif options.number is not None:
        if options.number <= len(stack.patchorder.applied):
            patches = stack.patchorder.applied[:options.number]
        else:
            raise common.CmdException('There are not that many applied patches')
    elif options.all:
        patches = stack.patchorder.applied
    else:
        patches = stack.patchorder.applied[:1]
    if not patches:
        raise common.CmdException('No patches to commit')

    iw = stack.repository.default_iw
    def allow_conflicts(trans):
        # As long as the topmost patch stays where it is, it's OK to
        # run "stg commit" with conflicts in the index.
        return len(trans.applied) >= 1
    trans = transaction.StackTransaction(stack, 'commit',
                                         allow_conflicts = allow_conflicts)
    try:
        common_prefix = 0
        for i in range(min(len(stack.patchorder.applied), len(patches))):
            if stack.patchorder.applied[i] == patches[i]:
                common_prefix += 1
            else:
                break
        if common_prefix < len(patches):
            to_push = [pn for pn in stack.patchorder.applied[common_prefix:]
                       if pn not in patches[common_prefix:]]
            # this pops all the applied patches from common_prefix
            trans.pop_patches(lambda pn: pn in to_push)
            for pn in patches[common_prefix:]:
                trans.push_patch(pn, iw)
        else:
            to_push = []
        new_base = trans.patches[patches[-1]]
        for pn in patches:
            trans.patches[pn] = None
        trans.applied = [pn for pn in trans.applied if pn not in patches]
        trans.base = new_base
        out.info('Committed %d patch%s' % (len(patches),
                                           ['es', ''][len(patches) == 1]))
        for pn in to_push:
            trans.push_patch(pn, iw)
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#5
0
def func(parser, options, args):
    """Pushes the given patches or the first unapplied onto the stack."""
    stack = directory.repository.current_stack
    iw = stack.repository.default_iw
    clean_iw = (not options.keep and iw) or None
    trans = transaction.StackTransaction(stack,
                                         'push',
                                         check_clean_iw=clean_iw)

    if options.number == 0:
        # explicitly allow this without any warning/error message
        return

    if not trans.unapplied:
        raise CmdException('No patches to push')

    if options.all:
        patches = list(trans.unapplied)
    elif options.number is not None:
        patches = trans.unapplied[:options.number]
    elif not args:
        patches = [trans.unapplied[0]]
    else:
        try:
            patches = parse_patches(args, trans.unapplied)
        except CmdException as e:
            try:
                patches = parse_patches(args, trans.applied)
            except CmdException:
                raise e
            else:
                raise CmdException(
                    'Patch%s already applied: %s' %
                    ('es' if len(patches) > 1 else '', ', '.join(patches)))

    assert patches

    if options.reverse:
        patches.reverse()

    if options.set_tree:
        for pn in patches:
            trans.push_tree(pn)
    else:
        try:
            if options.merged:
                merged = set(trans.check_merged(patches))
            else:
                merged = set()
            for pn in patches:
                trans.push_patch(pn,
                                 iw,
                                 allow_interactive=True,
                                 already_merged=pn in merged)
        except transaction.TransactionHalted:
            pass
    return trans.run(iw)
def func(parser, options, args):
    stack = directory.repository.current_stack
    if options.number < 1:
        raise CmdException('Bad number of commands to undo')
    state = log.undo_state(stack, options.number)
    trans = transaction.StackTransaction(stack, discard_changes=options.hard)
    try:
        log.reset_stack(trans, stack.repository.default_iw, state)
    except transaction.TransactionHalted:
        pass
    return trans.execute('undo %d' % options.number,
                         stack.repository.default_iw,
                         allow_bad_head=True)
示例#7
0
def make_temp_patch(stack, patch_name, paths, temp_index):
    """Commit index to temp patch, in a complete transaction. If any path
    limiting is in effect, use a temp index."""
    tree = write_tree(stack, paths, temp_index)
    commit = stack.repository.commit(git.CommitData(
            tree = tree, parents = [stack.head],
            message = 'Refresh of %s' % patch_name))
    temp_name = utils.make_patch_name('refresh-temp', stack.patches.exists)
    trans = transaction.StackTransaction(stack,
                                         'refresh (create temporary patch)')
    trans.patches[temp_name] = commit
    trans.applied.append(temp_name)
    return trans.run(stack.repository.default_iw,
                     print_current_patch = False), temp_name
def func(parser, options, args):
    if len(args) != 1:
        parser.error('incorrect number of arguments')
    name = args[0]

    stack = directory.repository.current_stack
    iw = stack.repository.default_iw

    check_head_top_equal(stack)
    if not options.keep:
        check_index_and_worktree_clean(stack)

    trans = transaction.StackTransaction(stack)

    if name not in trans.all_patches:
        candidates = [pn for pn in trans.all_patches if name in pn]
        if len(candidates) == 1:
            name = candidates[0]
        elif len(candidates) > 1:
            out.info('Possible patches:\n  %s' % '\n  '.join(candidates))
            raise CmdException('Ambiguous patch name "%s"' % name)
        elif re.match('[0-9A-Fa-f]{4,40}$', name):
            sha1 = name
            name = stack.patches.name_from_sha1(sha1)
            if not name:
                raise CmdException('No patch associated with %s' % sha1)
        else:
            raise CmdException('Patch "%s" does not exist' % name)

    if name in trans.applied:
        to_pop = set(trans.applied[trans.applied.index(name) + 1:])
        popped_extra = trans.pop_patches(lambda pn: pn in to_pop)
        assert not popped_extra
    elif name in trans.unapplied:
        try:
            to_push = trans.unapplied[:trans.unapplied.index(name) + 1]
            if options.merged:
                merged = set(trans.check_merged(to_push))
            else:
                merged = set()
            for pn in to_push:
                trans.push_patch(pn,
                                 iw,
                                 allow_interactive=True,
                                 already_merged=pn in merged)
        except transaction.TransactionHalted:
            pass
    else:
        raise CmdException('Cannot goto a hidden patch')
    return trans.execute('goto', iw)
示例#9
0
def _squash(stack, iw, name, msg, save_template, patches, no_verify=False):

    # If a name was supplied on the command line, make sure it's OK.
    def bad_name(pn):
        return pn not in patches and stack.patches.exists(pn)

    def get_name(cd):
        return name or utils.make_patch_name(cd.message, bad_name)

    if name and bad_name(name):
        raise common.CmdException('Patch name "%s" already taken')

    def make_squashed_patch(trans, new_commit_data):
        name = get_name(new_commit_data)
        trans.patches[name] = stack.repository.commit(new_commit_data)
        trans.unapplied.insert(0, name)

    trans = transaction.StackTransaction(stack, 'squash', allow_conflicts=True)
    push_new_patch = bool(set(patches) & set(trans.applied))
    try:
        new_commit_data = _squash_patches(trans, patches, msg, save_template,
                                          no_verify)
        if new_commit_data:
            # We were able to construct the squashed commit
            # automatically. So just delete its constituent patches.
            to_push = trans.delete_patches(lambda pn: pn in patches)
        else:
            # Automatic construction failed. So push the patches
            # consecutively, so that a second construction attempt is
            # guaranteed to work.
            to_push = trans.pop_patches(lambda pn: pn in patches)
            for pn in patches:
                trans.push_patch(pn, iw)
            new_commit_data = _squash_patches(trans, patches, msg,
                                              save_template, no_verify)
            assert not trans.delete_patches(lambda pn: pn in patches)
        make_squashed_patch(trans, new_commit_data)

        # Push the new patch if necessary, and any unrelated patches we've
        # had to pop out of the way.
        if push_new_patch:
            trans.push_patch(get_name(new_commit_data), iw)
        for pn in to_push:
            trans.push_patch(pn, iw)
    except SaveTemplateDone:
        trans.abort(iw)
        return
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#10
0
def func(parser, options, args):
    """Reorder patches to make the named patch the topmost one."""
    if options.series and args:
        parser.error('<patches> cannot be used with --series')
    elif not options.series and not args:
        parser.error('incorrect number of arguments')

    stack = directory.repository.current_stack

    if options.series:
        if options.series == '-':
            f = io.open(sys.stdin.fileno())
        else:
            f = io.open(options.series)

        patches = []
        for line in f:
            patch = re.sub('#.*$', '', line).strip()
            if patch:
                patches.append(patch)
        patches = parse_patches(patches, stack.patchorder.all)
    else:
        patches = parse_patches(args, stack.patchorder.all)

    if not patches:
        raise CmdException('No patches to float')

    iw = stack.repository.default_iw
    check_head_top_equal(stack)

    if not options.keep and (not options.noapply
                             or any(pn in stack.patchorder.applied
                                    for pn in patches)):
        check_index_and_worktree_clean(stack)

    trans = transaction.StackTransaction(stack)

    if options.noapply:
        applied = [p for p in trans.applied if p not in patches]
        unapplied = patches + [p for p in trans.unapplied if p not in patches]
    else:
        applied = [p for p in trans.applied if p not in patches] + patches
        unapplied = [p for p in trans.unapplied if p not in patches]

    try:
        trans.reorder_patches(applied, unapplied, iw=iw)
    except transaction.TransactionHalted:
        pass
    return trans.execute('float', iw)
示例#11
0
def func(parser, options, args):
    """Sink patches down the stack."""
    stack = directory.repository.current_stack

    if options.to and options.to not in stack.patchorder.applied:
        raise CmdException('Cannot sink below %s since it is not applied' %
                           options.to)

    if len(args) > 0:
        patches = parse_patches(args, stack.patchorder.all)
    else:
        # current patch
        patches = list(stack.patchorder.applied[-1:])

    if not patches:
        raise CmdException('No patches to sink')
    if options.to and options.to in patches:
        raise CmdException('Cannot have a sinked patch as target')

    unapplied_rem = [p for p in stack.patchorder.unapplied if p not in patches]
    applied_rem = [p for p in stack.patchorder.applied if p not in patches]
    insert_idx = applied_rem.index(options.to) if options.to else 0
    stay_applied, re_applied = applied_rem[:insert_idx], applied_rem[
        insert_idx:]

    if options.nopush:
        applied = stay_applied + patches
        unapplied = re_applied + unapplied_rem
    else:
        applied = stay_applied + patches + re_applied
        unapplied = unapplied_rem

    iw = stack.repository.default_iw

    check_head_top_equal(stack)
    if not options.keep:
        check_index_and_worktree_clean(stack)

    trans = transaction.StackTransaction(stack)

    try:
        trans.reorder_patches(applied,
                              unapplied,
                              iw=iw,
                              allow_interactive=True)
    except transaction.TransactionHalted:
        pass
    return trans.execute('sink', iw)
示例#12
0
def _clean(stack, clean_applied, clean_unapplied):
    trans = transaction.StackTransaction(stack, 'clean', allow_conflicts = True)
    def del_patch(pn):
        if pn in stack.patchorder.applied:
            if pn == stack.patchorder.applied[-1]:
                # We're about to clean away the topmost patch. Don't
                # do that if we have conflicts, since that means the
                # patch is only empty because the conflicts have made
                # us dump its contents into the index and worktree.
                if stack.repository.default_index.conflicts():
                    return False
            return clean_applied and trans.patches[pn].data.is_nochange()
        elif pn in stack.patchorder.unapplied:
            return clean_unapplied and trans.patches[pn].data.is_nochange()
    for pn in trans.delete_patches(del_patch):
        trans.push_patch(pn)
    trans.run()
示例#13
0
def func(parser, options, args):
    """Delete one or more patches."""
    stack = directory.repository.get_stack(options.branch)
    if options.branch:
        iw = None  # can't use index/workdir to manipulate another branch
    else:
        iw = stack.repository.default_iw
    if args and options.top:
        parser.error('Either --top or patches must be specified')
    elif args:
        patches = set(
            parse_patches(
                args, list(stack.patchorder.all), len(stack.patchorder.applied)
            )
        )
    elif options.top:
        applied = stack.patchorder.applied
        if applied:
            patches = set([applied[-1]])
        else:
            raise CmdException('No patches applied')
    else:
        parser.error('No patches specified')

    if options.spill:
        if set(stack.patchorder.applied[-len(patches) :]) != patches:
            parser.error('Can only spill topmost applied patches')
        iw = None  # don't touch index+worktree

    def allow_conflicts(trans):
        # Allow conflicts if the topmost patch stays the same.
        if stack.patchorder.applied:
            return trans.applied and trans.applied[-1] == stack.patchorder.applied[-1]
        else:
            return not trans.applied

    trans = transaction.StackTransaction(
        stack, 'delete', allow_conflicts=allow_conflicts
    )
    try:
        to_push = trans.delete_patches(lambda pn: pn in patches)
        for pn in to_push:
            trans.push_patch(pn, iw)
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#14
0
def func(parser, options, args):
    """Pop the given patches or the topmost one from the stack."""
    stack = directory.repository.current_stack
    iw = stack.repository.default_iw
    check_head_top_equal(stack)
    if not options.keep and not options.spill:
        check_index_and_worktree_clean(stack)
    trans = transaction.StackTransaction(stack)

    if options.number == 0:
        # explicitly allow this without any warning/error message
        return

    if not trans.applied:
        raise CmdException('No patches applied')

    if options.all:
        patches = trans.applied
    elif options.number is not None:
        # reverse it twice to also work with negative or bigger than
        # the length numbers
        patches = trans.applied[::-1][:options.number][::-1]
    elif not args:
        patches = [trans.applied[-1]]
    else:
        patches = parse_patches(args, trans.applied, ordered=True)

    if not patches:
        # FIXME: Why is this an error, and not just a noop ?
        raise CmdException('No patches to pop')

    if options.spill:
        if set(stack.patchorder.applied[-len(patches):]) != set(patches):
            parser.error('Can only spill topmost applied patches')
        iw = None  # don't touch index+worktree

    try:
        trans.reorder_patches(
            applied=[p for p in trans.applied if p not in patches],
            unapplied=patches + trans.unapplied,
            iw=iw,
            allow_interactive=True,
        )
    except transaction.TransactionException:
        pass
    return trans.execute('pop', iw)
示例#15
0
def func(parser, options, args):
    """Create a new patch."""
    stack = directory.repository.current_stack
    if stack.repository.default_index.conflicts():
        raise common.CmdException(
            'Cannot create a new patch -- resolve conflicts first')

    # Choose a name for the new patch -- or None, which means make one
    # up later when we've gotten hold of the commit message.
    if len(args) == 0:
        name = None
    elif len(args) == 1:
        name = args[0]
        if stack.patches.exists(name):
            raise common.CmdException('%s: patch already exists' % name)
    else:
        parser.error('incorrect number of arguments')

    cd = gitlib.CommitData(
        tree=stack.head.data.tree,
        parents=[stack.head],
        message='',
        author=gitlib.Person.author(),
        committer=gitlib.Person.committer(),
    )
    cd = common.update_commit_data(cd, options)

    if options.save_template:
        options.save_template(cd.message.encode('utf-8'))
        return utils.STGIT_SUCCESS

    if not options.no_verify:
        cd = common.run_commit_msg_hook(stack.repository, cd)

    if name is None:
        name = utils.make_patch_name(cd.message,
                                     lambda name: stack.patches.exists(name))

    # Write the new patch.
    stack.repository.default_iw
    trans = transaction.StackTransaction(stack, 'new')
    trans.patches[name] = stack.repository.commit(cd)
    trans.applied.append(name)
    return trans.run()
示例#16
0
文件: unhide.py 项目: hasturkun/stgit
def func(parser, options, args):
    """Unhide a range of patch in the series."""
    stack = directory.repository.current_stack
    trans = transaction.StackTransaction(stack, 'unhide')

    if not args:
        parser.error('No patches specified')

    patches = parse_patches(args, trans.all_patches)
    for p in patches:
        if p not in trans.hidden:
            raise CmdException('Patch "%s" not hidden' % p)

    applied = list(trans.applied)
    unapplied = trans.unapplied + patches
    hidden = [p for p in trans.hidden if p not in set(patches)]

    trans.reorder_patches(applied, unapplied, hidden)
    return trans.run()
示例#17
0
def func(parser, options, args):
    """Reorder patches to make the named patch the topmost one.
    """
    if options.series and args:
        parser.error('<patches> cannot be used with --series')
    elif not options.series and not args:
        parser.error('incorrect number of arguments')

    stack = directory.repository.current_stack

    if options.series:
        if options.series == '-':
            f = io.open(sys.stdin.fileno())
        else:
            f = io.open(options.series)

        patches = []
        for line in f:
            patch = re.sub('#.*$', '', line).strip()
            if patch:
                patches.append(patch)
    else:
        patches = common.parse_patches(args, stack.patchorder.all)

    if not patches:
        raise common.CmdException('No patches to float')

    applied = [p for p in stack.patchorder.applied if p not in patches] + \
            patches
    unapplied = [p for p in stack.patchorder.unapplied if p not in patches]

    iw = stack.repository.default_iw
    clean_iw = (not options.keep and iw) or None
    trans = transaction.StackTransaction(stack,
                                         'float',
                                         check_clean_iw=clean_iw)

    try:
        trans.reorder_patches(applied, unapplied, iw=iw)
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#18
0
def func(parser, options, args):
    """Sink patches down the stack.
    """
    stack = directory.repository.current_stack

    if options.to and options.to not in stack.patchorder.applied:
        raise common.CmdException(
            'Cannot sink below %s since it is not applied' % options.to
        )

    if len(args) > 0:
        patches = common.parse_patches(args, stack.patchorder.all)
    else:
        # current patch
        patches = list(stack.patchorder.applied[-1:])

    if not patches:
        raise common.CmdException('No patches to sink')
    if options.to and options.to in patches:
        raise common.CmdException('Cannot have a sinked patch as target')

    applied = [p for p in stack.patchorder.applied if p not in patches]
    if options.to:
        insert_idx = applied.index(options.to)
    else:
        insert_idx = 0
    applied = applied[:insert_idx] + patches + applied[insert_idx:]
    unapplied = [p for p in stack.patchorder.unapplied if p not in patches]

    iw = stack.repository.default_iw
    clean_iw = (not options.keep and iw) or None
    trans = transaction.StackTransaction(
        stack, 'sink', check_clean_iw=clean_iw
    )

    try:
        trans.reorder_patches(
            applied, unapplied, iw=iw, allow_interactive=True
        )
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#19
0
def func(parser, options, args):
    """Hide a range of patch in the series."""
    stack = directory.repository.current_stack
    trans = transaction.StackTransaction(stack, 'hide')

    if not args:
        parser.error('No patches specified')

    patches = common.parse_patches(args, trans.all_patches)
    for p in patches:
        if p in trans.hidden:
            out.warn('Patch "%s" already hidden' % p)
    patches = [p for p in patches if p not in set(trans.hidden)]

    applied = [p for p in trans.applied if p not in set(patches)]
    unapplied = [p for p in trans.unapplied if p not in set(patches)]
    hidden = patches + trans.hidden

    trans.reorder_patches(applied, unapplied, hidden)
    return trans.run()
示例#20
0
文件: goto.py 项目: zaneb/stgit
def func(parser, options, args):
    if len(args) != 1:
        parser.error('incorrect number of arguments')
    patch = args[0]

    stack = directory.repository.current_stack
    iw = stack.repository.default_iw
    clean_iw = (not options.keep and iw) or None
    trans = transaction.StackTransaction(stack,
                                         'goto',
                                         check_clean_iw=clean_iw)

    if patch not in trans.all_patches:
        candidate = get_patch_from_list(patch, trans.all_patches)
        if candidate is None:
            raise CmdException('Patch "%s" does not exist' % patch)
        patch = candidate

    if patch in trans.applied:
        to_pop = set(trans.applied[trans.applied.index(patch) + 1:])
        popped_extra = trans.pop_patches(lambda pn: pn in to_pop)
        assert not popped_extra
    elif patch in trans.unapplied:
        try:
            to_push = trans.unapplied[:trans.unapplied.index(patch) + 1]
            if options.merged:
                merged = set(trans.check_merged(to_push))
            else:
                merged = set()
            for pn in to_push:
                trans.push_patch(pn,
                                 iw,
                                 allow_interactive=True,
                                 already_merged=pn in merged)
        except transaction.TransactionHalted:
            pass
    else:
        raise CmdException('Cannot goto a hidden patch')
    return trans.run(iw)
示例#21
0
def perform_edit(
    stack,
    cd,
    orig_patchname,
    new_patchname,
    edit_diff,
    diff_flags,
    set_tree=None,
):
    """Given instructions, performs required the edit.

    :returns: 2-tuple:
        - the result of the transaction
        - the new patch name, whether changed or not.
    """
    # Refresh the committer information
    cd = cd.set_committer(None)

    # Rewrite the StGit patch with the given diff (and any patches on top of
    # it).
    iw = stack.repository.default_iw
    common.check_head_top_equal(stack)
    trans = transaction.StackTransaction(stack, allow_conflicts=True)
    if orig_patchname in trans.applied:
        popped = trans.applied[trans.applied.index(orig_patchname) + 1:]
        popped_extra = trans.pop_patches(lambda pn: pn in popped)
        assert not popped_extra
    else:
        popped = []
    trans.patches[orig_patchname] = stack.repository.commit(cd)
    if new_patchname == "":
        new_patchname = stack.patches.make_name(cd.message_str,
                                                allow=orig_patchname)
    if new_patchname is not None and orig_patchname != new_patchname:
        out.start('Renaming patch "%s" to "%s"' %
                  (orig_patchname, new_patchname))
        trans.rename_patch(orig_patchname, new_patchname)
        out.done()
        log_stack_state(stack,
                        'rename %s to %s' % (orig_patchname, new_patchname))
    else:
        new_patchname = orig_patchname
    try:
        for pn in popped:
            if set_tree:
                trans.push_tree(pn)
            else:
                trans.push_patch(pn, iw, allow_interactive=True)
    except transaction.TransactionHalted:
        pass
    try:
        # Either a complete success, or a conflict during push. But in
        # either case, we've successfully effected the edits the user
        # asked us for.
        return trans.execute('edit', iw), new_patchname
    except transaction.TransactionException:
        # Transaction aborted -- we couldn't check out files due to
        # dirty index/worktree. The edits were not carried out.
        note_patch_application_failure(
            get_patch_description(stack.repository, cd, orig_patchname,
                                  edit_diff, diff_flags))
        return utils.STGIT_COMMAND_ERROR, new_patchname
示例#22
0
def func(parser, options, args):
    """Pushes the given patches or the first unapplied onto the stack."""
    stack = directory.repository.current_stack
    iw = stack.repository.default_iw

    if options.number == 0:
        # explicitly allow this without any warning/error message
        return

    if not stack.patchorder.unapplied:
        raise CmdException('No patches to push')

    if options.all:
        if options.noapply:
            raise CmdException('Cannot use --noapply with --all')
        patches = list(stack.patchorder.unapplied)
    elif options.number is not None:
        if options.noapply:
            raise CmdException('Cannot use --noapply with --number')
        patches = list(stack.patchorder.unapplied[: options.number])
    elif not args:
        if options.noapply:
            raise CmdException('Must supply patch names with --noapply')
        patches = [stack.patchorder.unapplied[0]]
    else:
        try:
            patches = parse_patches(args, stack.patchorder.unapplied)
        except CmdException as e:
            try:
                patches = parse_patches(args, stack.patchorder.applied)
            except CmdException:
                raise e
            else:
                raise CmdException(
                    'Patch%s already applied: %s'
                    % ('es' if len(patches) > 1 else '', ', '.join(patches))
                )

    assert patches

    check_head_top_equal(stack)
    if not options.keep and not options.noapply:
        check_index_and_worktree_clean(stack)

    trans = transaction.StackTransaction(stack)

    if options.reverse:
        patches.reverse()

    if options.set_tree:
        if options.noapply:
            raise CmdException('Cannot use --noapply with --set-tree')
        for pn in patches:
            trans.push_tree(pn)
    elif options.noapply:
        if options.merged:
            raise CmdException('Cannot use --noapply with --merged')
        unapplied = patches + [pn for pn in trans.unapplied if pn not in patches]
        trans.reorder_patches(trans.applied, unapplied)
    else:
        try:
            if options.merged:
                merged = set(trans.check_merged(patches))
            else:
                merged = set()
            for pn in patches:
                trans.push_patch(
                    pn, iw, allow_interactive=True, already_merged=pn in merged
                )
        except transaction.TransactionHalted:
            pass
    return trans.execute('push', iw)
示例#23
0
def func(parser, options, args):
    """Uncommit a number of patches.
    """
    stack = directory.repository.current_stack
    if options.to:
        if options.number:
            parser.error('cannot give both --to and --number')
        if len(args) != 0:
            parser.error('cannot specify patch name with --to')
        patch_nr = patchnames = None
        to_commit = stack.repository.rev_parse(options.to)
        # check whether the --to commit is on a different branch
        merge_bases = directory.repository.get_merge_bases(
            to_commit, stack.base
        )
        if to_commit not in merge_bases:
            to_commit = merge_bases[0]
            options.exclusive = True
    elif options.number:
        if options.number <= 0:
            parser.error('invalid value passed to --number')
        patch_nr = options.number
        if len(args) == 0:
            patchnames = None
        elif len(args) == 1:
            # prefix specified
            patchnames = ['%s%d' % (args[0], i)
                          for i in range(patch_nr, 0, -1)]
        else:
            parser.error('when using --number, specify at most one patch name')
    elif len(args) == 0:
        patchnames = None
        patch_nr = 1
    else:
        patchnames = args
        patch_nr = len(patchnames)

    def check_and_append(c, n):
        next = n.data.parents
        try:
            [next] = next
        except ValueError:
            out.done()
            raise CmdException(
                'Trying to uncommit %s, which does not have exactly one parent'
                % n.sha1)
        return c.append(n)

    commits = []
    next_commit = stack.base
    if patch_nr:
        out.start('Uncommitting %d patches' % patch_nr)
        for i in range(patch_nr):
            check_and_append(commits, next_commit)
            next_commit = next_commit.data.parent
    else:
        if options.exclusive:
            out.start('Uncommitting to %s (exclusive)' % to_commit.sha1)
        else:
            out.start('Uncommitting to %s' % to_commit.sha1)
        while True:
            if next_commit == to_commit:
                if not options.exclusive:
                    check_and_append(commits, next_commit)
                break
            check_and_append(commits, next_commit)
            next_commit = next_commit.data.parent
        patch_nr = len(commits)

    taken_names = set(stack.patchorder.all)
    if patchnames:
        for pn in patchnames:
            if pn in taken_names:
                raise CmdException('Patch name "%s" already taken' % pn)
            taken_names.add(pn)
    else:
        patchnames = []
        for c in reversed(commits):
            pn = utils.make_patch_name(c.data.message,
                                       lambda pn: pn in taken_names)
            patchnames.append(pn)
            taken_names.add(pn)
        patchnames.reverse()

    trans = transaction.StackTransaction(stack, 'uncommit',
                                         allow_conflicts=True,
                                         allow_bad_head=True)
    for commit, pn in zip(commits, patchnames):
        trans.patches[pn] = commit
    trans.applied = list(reversed(patchnames)) + trans.applied
    trans.run(set_head=False)
    out.done()
示例#24
0
def func(parser, options, args):
    """Edit the given patch or the current one.
    """
    stack = directory.repository.current_stack

    if len(args) == 0:
        if not stack.patchorder.applied:
            raise CmdException(
                'Cannot edit top patch, because no patches are applied')
        patchname = stack.patchorder.applied[-1]
    elif len(args) == 1:
        [patchname] = args
        if not stack.patches.exists(patchname):
            raise CmdException('%s: no such patch' % patchname)
    else:
        parser.error('Cannot edit more than one patch')

    cd = orig_cd = stack.patches.get(patchname).commit.data

    if options.set_tree:
        cd = cd.set_tree(
            stack.repository.rev_parse(options.set_tree,
                                       discard_stderr=True,
                                       object_type='tree'))

    cd = edit.auto_edit_patch(
        stack.repository,
        cd,
        msg=(None if options.message is None else options.message.encode(
            config.get('i18n.commitencoding'))),
        author=options.author,
        sign_str=options.sign_str,
    )

    if options.save_template:
        options.save_template(
            edit.patch_desc(
                stack.repository,
                cd,
                options.diff,
                options.diff_flags,
                replacement_diff=None,
            ))
        return utils.STGIT_SUCCESS

    use_editor = cd == orig_cd or options.edit or options.diff
    if use_editor:
        cd, failed_diff = edit.interactive_edit_patch(stack.repository, cd,
                                                      options.diff,
                                                      options.diff_flags)
    else:
        failed_diff = None

    def failed(reason='Edited patch did not apply.'):
        fn = '.stgit-failed.patch'
        with io.open(fn, 'wb') as f:
            f.write(
                edit.patch_desc(
                    stack.repository,
                    cd,
                    options.diff,
                    options.diff_flags,
                    replacement_diff=failed_diff,
                ))
        out.error(reason, 'The patch has been saved to "%s".' % fn)
        return utils.STGIT_COMMAND_ERROR

    # If we couldn't apply the patch, fail without even trying to
    # effect any of the changes.
    if failed_diff:
        return failed()

    if not options.no_verify and (use_editor or cd.message != orig_cd.message):
        try:
            cd = run_commit_msg_hook(stack.repository, cd, use_editor)
        except Exception:
            if options.diff:
                failed('The commit-msg hook failed.')
            raise

    # Refresh the committer information
    cd = cd.set_committer(None)

    # The patch applied, so now we have to rewrite the StGit patch
    # (and any patches on top of it).
    iw = stack.repository.default_iw
    trans = transaction.StackTransaction(stack, 'edit', allow_conflicts=True)
    if patchname in trans.applied:
        popped = trans.applied[trans.applied.index(patchname) + 1:]
        popped_extra = trans.pop_patches(lambda pn: pn in popped)
        assert not popped_extra
    else:
        popped = []
    trans.patches[patchname] = stack.repository.commit(cd)
    try:
        for pn in popped:
            if options.set_tree:
                trans.push_tree(pn)
            else:
                trans.push_patch(pn, iw, allow_interactive=True)
    except transaction.TransactionHalted:
        pass
    try:
        # Either a complete success, or a conflict during push. But in
        # either case, we've successfully effected the edits the user
        # asked us for.
        return trans.run(iw)
    except transaction.TransactionException:
        # Transaction aborted -- we couldn't check out files due to
        # dirty index/worktree. The edits were not carried out.
        return failed()