Example #1
0
File: show.py Project: snits/stgit
def func(parser, options, args):
    """Show commit log and diff
    """
    if options.applied:
        patches = crt_series.get_applied()
    elif options.unapplied:
        patches = crt_series.get_unapplied()
    elif len(args) == 0:
        patches = ['HEAD']
    elif '..' in ' '.join(args):
        # patch ranges
        applied = crt_series.get_applied()
        unapplied = crt_series.get_unapplied()
        patches = parse_patches(args, applied + unapplied + \
                                crt_series.get_hidden(), len(applied))
    else:
        # individual patches or commit ids
        patches = args

    if not options.stat:
        options.diff_flags.extend(color_diff_flags())
    commit_ids = [git_id(crt_series, patch) for patch in patches]
    commit_str = '\n'.join([git.pretty_commit(commit_id,
                                              flags = options.diff_flags)
                            for commit_id in commit_ids])
    if options.stat:
        commit_str = gitlib.diffstat(commit_str)
    if commit_str:
        pager(commit_str)
Example #2
0
def func(parser, options, args):
    stack = directory.repository.current_stack
    patches = common.parse_patches(args, list(stack.patchorder.all))
    if len(patches) < 2:
        raise common.CmdException('Need at least two patches')
    return _squash(stack, stack.repository.default_iw, options.name,
                   options.message, options.save_template, patches)
Example #3
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:
        patches = set(common.parse_patches(args, list(stack.patchorder.all),
                                           len(stack.patchorder.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)
Example #4
0
def func(parser, options, args):
    if options.branch:
        stack = directory.repository.get_stack(options.branch)
    else:
        stack = directory.repository.current_stack
    patches = common.parse_patches(args, list(stack.patchorder.all))
    logref = log.log_ref(stack.name)
    try:
        logcommit = stack.repository.refs.get(logref)
    except KeyError:
        out.info('Log is empty')
        return

    if options.clear:
        log.delete_log(stack.repository, stack.name)
        return

    stacklog = log.get_log_entry(stack.repository, logref, logcommit)
    pathlim = [os.path.join('patches', pn) for pn in patches]

    if options.graphical:
        for o in ['diff', 'number', 'full']:
            if getattr(options, o):
                parser.error('cannot combine --graphical and --%s' % o)
        # Discard the exit codes generated by SIGINT, SIGKILL, and SIGTERM.
        run.Run(*(['gitk', stacklog.simplified.sha1, '--'] + pathlim)
                 ).returns([0, -2, -9, -15]).run()
    else:
        show_log(stacklog.simplified, pathlim,
                 options.number, options.full, options.diff)
Example #5
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)
Example #6
0
File: pick.py Project: snits/stgit
def func(parser, options, args):
    """Import a commit object as a new patch
    """
    if not args:
        parser.error('incorrect number of arguments')

    if options.file and not options.fold:
        parser.error('--file can only be specified with --fold')

    if not options.unapplied:
        check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

    if options.ref_branch:
        remote_series = Series(options.ref_branch)
    else:
        remote_series = crt_series

    applied = remote_series.get_applied()
    unapplied = remote_series.get_unapplied()
    try:
        patches = parse_patches(args, applied + unapplied, len(applied))
        commit_id = None
    except CmdException:
        if len(args) > 1:
            raise
        # no patches found, try a commit id
        commit_id = git_id(remote_series, args[0])

    if not commit_id and len(patches) > 1:
        if options.name:
            raise CmdException('--name can only be specified with one patch')
        if options.parent:
            raise CmdException('--parent can only be specified with one patch')

    if options.update and not crt_series.get_current():
        raise CmdException('No patches applied')

    if commit_id:
        # Try to guess a patch name if the argument was <branch>:<patch>
        try:
            patchname = args[0].split(':')[1]
        except IndexError:
            patchname = None
        __pick_commit(commit_id, patchname, options)
    else:
        if options.unapplied:
            patches.reverse()
        for patch in patches:
            __pick_commit(git_id(remote_series, patch), patch, options)

    print_crt_patch(crt_series)
Example #7
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 common.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:
        patches = common.parse_patches(args, trans.unapplied)

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

    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)
Example #8
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
    clean_iw = (not options.keep and not options.spill and iw) or None
    trans = transaction.StackTransaction(stack, 'pop', check_clean_iw=clean_iw)

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

    if not trans.applied:
        raise common.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 = common.parse_patches(args, trans.applied, ordered=True)

    if not patches:
        #FIXME: Why is this an error, and not just a noop ?
        raise common.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

    applied = [p for p in trans.applied if p not in set(patches)]
    unapplied = patches + trans.unapplied
    try:
        trans.reorder_patches(applied,
                              unapplied,
                              iw=iw,
                              allow_interactive=True)
    except transaction.TransactionException:
        pass
    return trans.run(iw)
Example #9
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(common.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 common.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)
Example #10
0
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 = common.parse_patches(args, trans.all_patches)
    for p in patches:
        if p not in trans.hidden:
            raise common.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()
Example #11
0
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()
Example #12
0
File: pop.py Project: snits/stgit
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
    clean_iw = (not options.keep and not options.spill and iw) or None
    trans = transaction.StackTransaction(stack, 'pop',
                                         check_clean_iw = clean_iw)

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

    if not trans.applied:
        raise common.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 = common.parse_patches(args, trans.applied, ordered = True)

    if not patches:
		#FIXME: Why is this an error, and not just a noop ?
        raise common.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

    applied = [p for p in trans.applied if p not in set(patches)]
    unapplied = patches + trans.unapplied
    try:
        trans.reorder_patches(applied, unapplied, iw = iw,
                              allow_interactive = True)
    except transaction.TransactionException:
        pass
    return trans.run(iw)
Example #13
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)
Example #14
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)
Example #15
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()
Example #16
0
File: hide.py Project: snits/stgit
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()
Example #17
0
File: float.py Project: snits/stgit
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 = sys.stdin
        else:
            f = 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)
Example #18
0
def func(parser, options, args):
    """Sink patches down the stack.
    """
    stack = directory.repository.current_stack

    if options.to and not options.to 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)
Example #19
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
    clean_iw = (not options.keep and iw) or None
    trans = transaction.StackTransaction(stack, 'pop',
                                         check_clean_iw = clean_iw)

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

    if not trans.applied:
        raise common.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 = common.parse_patches(args, trans.applied, ordered = True)

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

    applied = [p for p in trans.applied if not p in set(patches)]
    unapplied = patches + trans.unapplied
    try:
        trans.reorder_patches(applied, unapplied, iw = iw)
    except transaction.TransactionException:
        pass
    return trans.run(iw)
Example #20
0
def func(parser, options, args):
    if options.clear:
        if (options.diff or options.number or options.full
                or options.graphical):
            parser.error('cannot combine --clear with other options')
        elif args:
            parser.error('cannot combine --clear with patch arguments')

    if options.graphical:
        for o in ['diff', 'number', 'full']:
            if getattr(options, o):
                parser.error('cannot combine --graphical and --%s' % o)

    stack = directory.repository.get_stack(options.branch)
    patches = common.parse_patches(args, list(stack.patchorder.all))
    logref = log.log_ref(stack.name)
    try:
        logcommit = stack.repository.refs.get(logref)
    except KeyError:
        out.info('Log is empty')
        return

    if options.clear:
        log.delete_log(stack.repository, stack.name)
        return

    stacklog = log.get_log_entry(stack.repository, logref, logcommit)
    pathlim = [os.path.join('patches', pn) for pn in patches]

    if options.graphical:
        cmd = ['gitk', stacklog.simplified.sha1, '--'] + pathlim
        # Discard the exit codes generated by SIGINT, SIGKILL, and SIGTERM.
        Run(*cmd).returns([0, -2, -9, -15]).run()
    else:
        show_log(stacklog.simplified, pathlim, options.number, options.full,
                 options.diff)
Example #21
0
def func(parser, options, args):
    """Import a commit object as a new patch
    """
    if not args:
        parser.error('incorrect number of arguments')

    if options.file and not options.fold:
        parser.error('--file can only be specified with --fold')

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

    if not options.unapplied:
        check_local_changes(repository)
        check_conflicts(iw)
        check_head_top_equal(stack)

    if options.ref_branch:
        ref_stack = repository.get_stack(options.ref_branch)
    else:
        ref_stack = stack

    try:
        patches = parse_patches(
            args,
            ref_stack.patchorder.all_visible,
            len(ref_stack.patchorder.applied),
        )
        commit = None
    except CmdException:
        if len(args) > 1:
            raise

        branch, patch = parse_rev(args[0])

        if not branch:
            commit = git_commit(patch, repository, options.ref_branch)
            patches = []
        else:
            ref_stack = repository.get_stack(branch)
            patches = parse_patches(
                [patch],
                ref_stack.patchorder.all_visible,
                len(ref_stack.patchorder.applied),
            )
            commit = None

    if not commit and len(patches) > 1:
        if options.name:
            raise CmdException('--name can only be specified with one patch')
        if options.parent:
            raise CmdException('--parent can only be specified with one patch')

    if options.update and not stack.patchorder.applied:
        raise CmdException('No patches applied')

    if commit:
        patchname = None
        retval = __pick_commit(stack, ref_stack, iw, commit, patchname,
                               options)
    else:
        if options.unapplied:
            patches.reverse()
        for patchname in patches:
            commit = git_commit(patchname, repository, ref_stack.name)
            retval = __pick_commit(stack, ref_stack, iw, commit, patchname,
                                   options)
            if retval != STGIT_SUCCESS:
                break

    if retval == STGIT_SUCCESS:
        print_current_patch(stack)

    return retval
Example #22
0
def func(parser, options, args):
    """Send the patches by e-mail using the patchmail.tmpl file as
    a template
    """
    stack = directory.repository.current_stack
    applied = stack.patchorder.applied

    if options.all:
        patches = applied
    elif len(args) >= 1:
        unapplied = stack.patchorder.unapplied
        patches = parse_patches(args, applied + unapplied, len(applied))
    else:
        raise CmdException('Incorrect options. Unknown patches to send')

    # early test for sender identity
    __get_sender()

    out.start('Checking the validity of the patches')
    for p in patches:
        if stack.patches.get(p).is_empty():
            raise CmdException('Cannot send empty patch "%s"' % p)
    out.done()

    total_nr = len(patches)
    if total_nr == 0:
        raise CmdException('No patches to send')

    if options.in_reply_to:
        if options.no_thread or options.unrelated:
            raise CmdException('--in-reply-to option not allowed with '
                               '--no-thread or --unrelated')
        ref_id = options.in_reply_to
    else:
        ref_id = None

    # get username/password if sending by SMTP
    __set_smtp_credentials(options)

    # send the cover message (if any)
    if options.cover or options.edit_cover:
        if options.unrelated:
            raise CmdException('cover sending not allowed with --unrelated')

        # find the template file
        if options.cover:
            with io.open(options.cover, 'r') as f:
                tmpl = f.read()
        else:
            tmpl = templates.get_template('covermail.tmpl')
            if not tmpl:
                raise CmdException('No cover message template file found')

        msg_id = __send_message('cover', tmpl, options, patches)

        # subsequent e-mails are seen as replies to the first one
        if not options.no_thread:
            ref_id = msg_id

    # send the patches
    if options.template:
        with io.open(options.template, 'r') as f:
            tmpl = f.read()
    else:
        if options.attach:
            tmpl = templates.get_template('mailattch.tmpl')
        elif options.attach_inline:
            tmpl = templates.get_template('patchandattch.tmpl')
        else:
            tmpl = templates.get_template('patchmail.tmpl')
        if not tmpl:
            raise CmdException('No e-mail template file found')

    for (p, n) in zip(patches, range(1, total_nr + 1)):
        msg_id = __send_message('patch', tmpl, options, p, n, total_nr, ref_id)

        # subsequent e-mails are seen as replies to the first one
        if not options.no_thread and not options.unrelated and not ref_id:
            ref_id = msg_id
Example #23
0
def func(parser, options, args):
    """Show the patch series
    """
    if options.all and options.short:
        raise common.CmdException, 'combining --all and --short is meaningless'

    stack = directory.repository.get_stack(options.branch)
    if options.missing:
        cmp_stack = stack
        stack = directory.repository.get_stack(options.missing)

    # current series patches
    applied = unapplied = hidden = ()
    if options.applied or options.unapplied or options.hidden:
        if options.all:
            raise common.CmdException, \
                '--all cannot be used with --applied/unapplied/hidden'
        if options.applied:
            applied = stack.patchorder.applied
        if options.unapplied:
            unapplied = stack.patchorder.unapplied
        if options.hidden:
            hidden = stack.patchorder.hidden
    elif options.all:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied
        hidden = stack.patchorder.hidden
    else:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied

    if options.missing:
        cmp_patches = cmp_stack.patchorder.all
    else:
        cmp_patches = ()

    # the filtering range covers the whole series
    if args:
        show_patches = parse_patches(args, applied + unapplied + hidden,
                                     len(applied))
    else:
        show_patches = applied + unapplied + hidden

    # missing filtering
    show_patches = [p for p in show_patches if p not in cmp_patches]

    # filter the patches
    applied = [p for p in applied if p in show_patches]
    unapplied = [p for p in unapplied if p in show_patches]
    hidden = [p for p in hidden if p in show_patches]

    if options.short:
        nr = int(config.get('stgit.shortnr'))
        if len(applied) > nr:
            applied = applied[-(nr+1):]
        n = len(unapplied)
        if n > nr:
            unapplied = unapplied[:nr]
        elif n < nr:
            hidden = hidden[:nr-n]

    patches = applied + unapplied + hidden

    if options.count:
        out.stdout(len(patches))
        return

    if not patches:
        return

    if options.showbranch:
        branch_str = stack.name + ':'
    else:
        branch_str = ''

    max_len = 0
    if len(patches) > 0:
        max_len = max([len(i + branch_str) for i in patches])

    if applied:
        for p in applied[:-1]:
            __print_patch(stack, p, branch_str, '+ ', max_len, options, config.get("stgit.color.applied"))
        __print_patch(stack, applied[-1], branch_str, '> ', max_len, options, config.get("stgit.color.current"))

    for p in unapplied:
        __print_patch(stack, p, branch_str, '- ', max_len, options, config.get("stgit.color.unapplied"))

    for p in hidden:
        __print_patch(stack, p, branch_str, '! ', max_len, options, config.get("stgit.color.hidden"))
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)
Example #25
0
def func(parser, options, args):
    """Export a range of patches.
    """
    stack = directory.repository.get_stack(options.branch)

    if options.dir:
        dirname = options.dir
    else:
        dirname = 'patches-%s' % stack.name
        directory.cd_to_topdir()

    if not options.branch and git.local_changes():
        out.warn('Local changes in the tree;'
                 ' you might want to commit them first')

    if not options.stdout:
        if not os.path.isdir(dirname):
            os.makedirs(dirname)
        series = file(os.path.join(dirname, 'series'), 'w+')

    applied = stack.patchorder.applied
    unapplied = stack.patchorder.unapplied
    if len(args) != 0:
        patches = common.parse_patches(args, applied + unapplied, len(applied))
    else:
        patches = applied

    num = len(patches)
    if num == 0:
        raise common.CmdException, 'No patches applied'

    zpadding = len(str(num))
    if zpadding < 2:
        zpadding = 2

    # get the template
    if options.template:
        tmpl = file(options.template).read()
    else:
        tmpl = templates.get_template('patchexport.tmpl')
        if not tmpl:
            tmpl = ''

    # note the base commit for this series
    if not options.stdout:
        base_commit = stack.patches.get(patches[0]).commit.sha1
        print >> series, '# This series applies on GIT commit %s' % base_commit

    patch_no = 1;
    for p in patches:
        pname = p
        if options.patch:
            pname = '%s.patch' % pname
        elif options.extension:
            pname = '%s.%s' % (pname, options.extension)
        if options.numbered:
            pname = '%s-%s' % (str(patch_no).zfill(zpadding), pname)
        pfile = os.path.join(dirname, pname)
        if not options.stdout:
            print >> series, pname

        # get the patch description
        patch = stack.patches.get(p)
        cd = patch.commit.data

        descr = cd.message.strip()
        descr_lines = descr.split('\n')

        short_descr = descr_lines[0].rstrip()
        long_descr = reduce(lambda x, y: x + '\n' + y,
                            descr_lines[1:], '').strip()

        diff = stack.repository.diff_tree(cd.parent.data.tree, cd.tree, options.diff_flags)

        tmpl_dict = {'description': descr,
                     'shortdescr': short_descr,
                     'longdescr': long_descr,
                     'diffstat': gitlib.diffstat(diff).rstrip(),
                     'authname': cd.author.name,
                     'authemail': cd.author.email,
                     'authdate': cd.author.date.isoformat(),
                     'commname': cd.committer.name,
                     'commemail': cd.committer.email}
        for key in tmpl_dict:
            if not tmpl_dict[key]:
                tmpl_dict[key] = ''

        try:
            descr = tmpl % tmpl_dict
        except KeyError, err:
            raise common.CmdException, 'Unknown patch template variable: %s' \
                  % err
        except TypeError:
            raise common.CmdException, 'Only "%(name)s" variables are ' \
                  'supported in the patch template'
Example #26
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))
    exclusive = [args, options.number is not None, options.all]
    if sum(map(bool, exclusive)) > 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)
Example #27
0
def func(parser, options, args):
    """Synchronise a range of patches
    """
    repository = directory.repository
    stack = repository.get_stack()

    if options.ref_branch:
        remote_stack = repository.get_stack(options.ref_branch)
        if remote_stack.name == stack.name:
            raise CmdException('Cannot synchronise with the current branch')
        remote_patches = remote_stack.patchorder.applied

        def merge_patch(commit, pname):
            return __branch_merge_patch(remote_stack, stack, commit, pname)

    elif options.series:
        patchdir = os.path.dirname(options.series)

        remote_patches = []
        with open(options.series) as f:
            for line in f:
                pn = re.sub('#.*$', '', line).strip()
                if not pn:
                    continue
                remote_patches.append(pn)

        def merge_patch(commit, pname):
            return __series_merge_patch(patchdir, stack, commit, pname)

    else:
        raise CmdException('No remote branch or series specified')

    applied = list(stack.patchorder.applied)
    unapplied = list(stack.patchorder.unapplied)

    if options.all:
        patches = applied
    elif len(args) != 0:
        patches = parse_patches(args,
                                applied + unapplied,
                                len(applied),
                                ordered=True)
    elif applied:
        patches = [applied[-1]]
    else:
        parser.error('no patches applied')

    assert patches

    # only keep the patches to be synchronised
    sync_patches = [p for p in patches if p in remote_patches]
    if not sync_patches:
        raise CmdException('No common patches to be synchronised')

    iw = repository.default_iw

    # pop to the one before the first patch to be synchronised
    first_patch = sync_patches[0]
    if first_patch in applied:
        to_pop = applied[applied.index(first_patch) + 1:]
        if to_pop:
            trans = StackTransaction(stack, 'sync (pop)', check_clean_iw=iw)
            popped_extra = trans.pop_patches(lambda pn: pn in to_pop)
            assert not popped_extra
            retval = trans.run(iw)
            assert not retval
        pushed = [first_patch]
    else:
        to_pop = []
        pushed = []
    popped = to_pop + [p for p in patches if p in unapplied]

    trans = StackTransaction(stack, 'sync', check_clean_iw=iw)
    try:
        for p in pushed + popped:
            if p in popped:
                trans.push_patch(p, iw=iw)

            if p not in sync_patches:
                # nothing to synchronise
                continue

            # the actual sync
            out.start('Synchronising "%s"' % p)

            commit = trans.patches[p]

            # the actual merging (either from a branch or an external file)
            tree = merge_patch(commit, p)
            if tree:
                trans.patches[p] = commit.data.set_tree(tree).commit(
                    repository)
                out.done('updated')
            else:
                out.done()
    except TransactionHalted:
        pass
    return trans.run(iw)
Example #28
0
File: sync.py Project: snits/stgit
def func(parser, options, args):
    """Synchronise a range of patches
    """
    if options.ref_branch:
        remote_series = stack.Series(options.ref_branch)
        if options.ref_branch == crt_series.get_name():
            raise CmdException('Cannot synchronise with the current branch')
        remote_patches = remote_series.get_applied()

        # the merge function merge_patch(patch, pname)
        merge_patch = lambda patch, pname: \
                      __branch_merge_patch(remote_series, pname)
    elif options.series:
        patchdir = os.path.dirname(options.series)

        remote_patches = []
        with open(options.series) as f:
            for line in f:
                p = re.sub('#.*$', '', line).strip()
                if not p:
                    continue
                remote_patches.append(p)

        # the merge function merge_patch(patch, pname)
        merge_patch = lambda patch, pname: \
                      __series_merge_patch(patch.get_bottom(), patchdir, pname)
    else:
        raise CmdException('No remote branch or series specified')

    applied = crt_series.get_applied()
    unapplied = crt_series.get_unapplied()
    
    if options.all:
        patches = applied
    elif len(args) != 0:
        patches = parse_patches(args, applied + unapplied, len(applied),
                                ordered = True)
    elif applied:
        patches = [crt_series.get_current()]
    else:
        parser.error('no patches applied')

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

    __check_all()

    # only keep the patches to be synchronised
    sync_patches = [p for p in patches if p in remote_patches]
    if not sync_patches:
        raise CmdException('No common patches to be synchronised')

    # pop to the one before the first patch to be synchronised
    first_patch = sync_patches[0]
    if first_patch in applied:
        to_pop = applied[applied.index(first_patch) + 1:]
        if to_pop:
            pop_patches(crt_series, to_pop[::-1])
        pushed = [first_patch]
    else:
        to_pop = []
        pushed = []
    popped = to_pop + [p for p in patches if p in unapplied]

    for p in pushed + popped:
        if p in popped:
            # push this patch
            push_patches(crt_series, [p])
        if p not in sync_patches:
            # nothing to synchronise
            continue

        # the actual sync
        out.start('Synchronising "%s"' % p)

        patch = crt_series.get_patch(p)
        top = patch.get_top()

        # reset the patch backup information.
        patch.set_top(top, backup = True)

        # the actual merging (either from a branch or an external file)
        merge_patch(patch, p)

        if git.local_changes(verbose = False):
            # index (cache) already updated by the git merge. The
            # backup information was already reset above
            crt_series.refresh_patch(cache_update = False, backup = False,
                                     log = 'sync')
            out.done('updated')
        else:
            out.done()
Example #29
0
def func(parser, options, args):
    """Synchronise a range of patches
    """
    if options.ref_branch:
        remote_series = stack.Series(options.ref_branch)
        if options.ref_branch == crt_series.get_name():
            raise CmdException('Cannot synchronise with the current branch')
        remote_patches = remote_series.get_applied()

        def merge_patch(patch, pname):
            return __branch_merge_patch(remote_series, pname)
    elif options.series:
        patchdir = os.path.dirname(options.series)

        remote_patches = []
        with open(options.series) as f:
            for line in f:
                pn = re.sub('#.*$', '', line).strip()
                if not pn:
                    continue
                remote_patches.append(pn)

        def merge_patch(patch, pname):
            return __series_merge_patch(
                patch.get_bottom(),
                patchdir,
                pname,
            )
    else:
        raise CmdException('No remote branch or series specified')

    applied = crt_series.get_applied()
    unapplied = crt_series.get_unapplied()

    if options.all:
        patches = applied
    elif len(args) != 0:
        patches = parse_patches(args, applied + unapplied, len(applied),
                                ordered=True)
    elif applied:
        patches = [crt_series.get_current()]
    else:
        parser.error('no patches applied')

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

    __check_all()

    # only keep the patches to be synchronised
    sync_patches = [p for p in patches if p in remote_patches]
    if not sync_patches:
        raise CmdException('No common patches to be synchronised')

    # pop to the one before the first patch to be synchronised
    first_patch = sync_patches[0]
    if first_patch in applied:
        to_pop = applied[applied.index(first_patch) + 1:]
        if to_pop:
            pop_patches(crt_series, to_pop[::-1])
        pushed = [first_patch]
    else:
        to_pop = []
        pushed = []
    popped = to_pop + [p for p in patches if p in unapplied]

    for p in pushed + popped:
        if p in popped:
            # push this patch
            push_patches(crt_series, [p])
        if p not in sync_patches:
            # nothing to synchronise
            continue

        # the actual sync
        out.start('Synchronising "%s"' % p)

        patch = crt_series.get_patch(p)
        top = patch.get_top()

        # reset the patch backup information.
        patch.set_top(top, backup=True)

        # the actual merging (either from a branch or an external file)
        merge_patch(patch, p)

        if git.local_changes():
            # index (cache) already updated by the git merge. The
            # backup information was already reset above
            crt_series.refresh_patch(
                cache_update=False, backup=False, log='sync'
            )
            out.done('updated')
        else:
            out.done()
Example #30
0
def func(parser, options, args):
    """Show the patch series
    """
    if options.all and options.short:
        raise common.CmdException('combining --all and --short is meaningless')

    stack = directory.repository.get_stack(options.branch)
    if options.missing:
        cmp_stack = stack
        stack = directory.repository.get_stack(options.missing)

    # current series patches
    applied = unapplied = hidden = ()
    if options.applied or options.unapplied or options.hidden:
        if options.all:
            raise common.CmdException('--all cannot be used with'
                                      ' --applied/unapplied/hidden')
        if options.applied:
            applied = stack.patchorder.applied
        if options.unapplied:
            unapplied = stack.patchorder.unapplied
        if options.hidden:
            hidden = stack.patchorder.hidden
    elif options.all:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied
        hidden = stack.patchorder.hidden
    else:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied

    if options.missing:
        cmp_patches = cmp_stack.patchorder.all
    else:
        cmp_patches = ()

    # the filtering range covers the whole series
    if args:
        show_patches = parse_patches(args, applied + unapplied + hidden,
                                     len(applied))
    else:
        show_patches = applied + unapplied + hidden

    # missing filtering
    show_patches = [p for p in show_patches if p not in cmp_patches]

    # filter the patches
    applied = [p for p in applied if p in show_patches]
    unapplied = [p for p in unapplied if p in show_patches]
    hidden = [p for p in hidden if p in show_patches]

    if options.short:
        nr = int(config.get('stgit.shortnr'))
        if len(applied) > nr:
            applied = applied[-(nr + 1):]
        n = len(unapplied)
        if n > nr:
            unapplied = unapplied[:nr]
        elif n < nr:
            hidden = hidden[:nr - n]

    patches = applied + unapplied + hidden

    if options.count:
        out.stdout(len(patches))
        return

    if not patches:
        return

    if options.showbranch:
        branch_str = stack.name + ':'
    else:
        branch_str = ''

    max_len = 0
    if len(patches) > 0:
        max_len = max([len(i + branch_str) for i in patches])

    if applied:
        for p in applied[:-1]:
            __print_patch(
                stack,
                p,
                branch_str,
                '+ ',
                max_len,
                options,
                config.get("stgit.color.applied"),
            )
        __print_patch(
            stack,
            applied[-1],
            branch_str,
            '> ',
            max_len,
            options,
            config.get("stgit.color.current"),
        )

    for p in unapplied:
        __print_patch(
            stack,
            p,
            branch_str,
            '- ',
            max_len,
            options,
            config.get("stgit.color.unapplied"),
        )

    for p in hidden:
        __print_patch(
            stack,
            p,
            branch_str,
            '! ',
            max_len,
            options,
            config.get("stgit.color.hidden"),
        )
Example #31
0
def func(parser, options, args):
    """Export a range of patches.
    """
    stack = directory.repository.get_stack(options.branch)

    if options.dir:
        dirname = options.dir
    else:
        dirname = 'patches-%s' % stack.name
        directory.cd_to_topdir()

    if not options.branch and git.local_changes():
        out.warn('Local changes in the tree;'
                 ' you might want to commit them first')

    applied = stack.patchorder.applied
    unapplied = stack.patchorder.unapplied
    if len(args) != 0:
        patches = common.parse_patches(args, applied + unapplied, len(applied))
    else:
        patches = applied

    num = len(patches)
    if num == 0:
        raise common.CmdException('No patches applied')

    zpadding = len(str(num))
    if zpadding < 2:
        zpadding = 2

    # get the template
    if options.template:
        with io.open(options.template, 'r') as f:
            tmpl = f.read()
    else:
        tmpl = templates.get_template('patchexport.tmpl')
        if not tmpl:
            tmpl = ''

    if not options.stdout:
        if not os.path.isdir(dirname):
            os.makedirs(dirname)
        series = io.open(os.path.join(dirname, 'series'), 'w')
        # note the base commit for this series
        base_commit = stack.base.sha1
        print('# This series applies on GIT commit %s' % base_commit,
              file=series)

    for patch_no, p in enumerate(patches, 1):
        pname = p
        if options.patch:
            pname = '%s.patch' % pname
        elif options.extension:
            pname = '%s.%s' % (pname, options.extension)
        if options.numbered:
            pname = '%s-%s' % (str(patch_no).zfill(zpadding), pname)
        pfile = os.path.join(dirname, pname)
        if not options.stdout:
            print(pname, file=series)

        # get the patch description
        patch = stack.patches.get(p)
        cd = patch.commit.data

        descr = cd.message.strip()
        descr_lines = descr.split('\n')

        short_descr = descr_lines[0].rstrip()
        long_descr = '\n'.join(descr_lines[1:]).strip()

        diff = stack.repository.diff_tree(cd.parent.data.tree, cd.tree,
                                          options.diff_flags)

        tmpl_dict = {
            'description': descr,
            'shortdescr': short_descr,
            'longdescr': long_descr,
            'diffstat': gitlib.diffstat(diff).rstrip(),
            'authname': cd.author.name,
            'authemail': cd.author.email,
            'authdate': cd.author.date.isoformat(),
            'commname': cd.committer.name,
            'commemail': cd.committer.email
        }

        try:
            descr = templates.specialize_template(tmpl, tmpl_dict)
        except KeyError as err:
            raise common.CmdException('Unknown patch template variable: %s' %
                                      err)
        except TypeError:
            raise common.CmdException('Only "%(name)s" variables are '
                                      'supported in the patch template')

        if options.stdout:
            if hasattr(sys.stdout, 'buffer'):
                f = sys.stdout.buffer
            else:
                f = sys.stdout
        else:
            f = io.open(pfile, 'wb')

        if options.stdout and num > 1:
            f.write('\n'.join(['-' * 79, patch.name, '-' * 79,
                               '']).encode('utf-8'))

        f.write(descr)
        f.write(diff)
        if not options.stdout:
            f.close()

    if not options.stdout:
        series.close()
Example #32
0
File: mail.py Project: snits/stgit
def func(parser, options, args):
    """Send the patches by e-mail using the patchmail.tmpl file as
    a template
    """
    applied = crt_series.get_applied()

    if options.all:
        patches = applied
    elif len(args) >= 1:
        unapplied = crt_series.get_unapplied()
        patches = parse_patches(args, applied + unapplied, len(applied))
    else:
        raise CmdException('Incorrect options. Unknown patches to send')

    # early test for sender identity
    __get_sender()

    out.start('Checking the validity of the patches')
    for p in patches:
        if crt_series.empty_patch(p):
            raise CmdException('Cannot send empty patch "%s"' % p)
    out.done()

    total_nr = len(patches)
    if total_nr == 0:
        raise CmdException('No patches to send')

    if options.in_reply_to:
        if options.no_thread or options.unrelated:
            raise CmdException('--in-reply-to option not allowed with '
                               '--no-thread or --unrelated')
        ref_id = options.in_reply_to
    else:
        ref_id = None

    # get username/password if sending by SMTP
    __set_smtp_credentials(options)

    # send the cover message (if any)
    if options.cover or options.edit_cover:
        if options.unrelated:
            raise CmdException('cover sending not allowed with --unrelated')

        # find the template file
        if options.cover:
            with open(options.cover) as f:
                tmpl = f.read()
        else:
            tmpl = templates.get_template('covermail.tmpl')
            if not tmpl:
                raise CmdException('No cover message template file found')

        msg_id = __send_message('cover', tmpl, options, patches)

        # subsequent e-mails are seen as replies to the first one
        if not options.no_thread:
            ref_id = msg_id

    # send the patches
    if options.template:
        with open(options.template) as f:
            tmpl = f.read()
    else:
        if options.attach:
            tmpl = templates.get_template('mailattch.tmpl')
        elif options.attach_inline:
            tmpl = templates.get_template('patchandattch.tmpl')
        else:
            tmpl = templates.get_template('patchmail.tmpl')
        if not tmpl:
            raise CmdException('No e-mail template file found')

    for (p, n) in zip(patches, range(1, total_nr + 1)):
        msg_id = __send_message('patch', tmpl, options, p, n, total_nr, ref_id)

        # subsequent e-mails are seen as replies to the first one
        if not options.no_thread and not options.unrelated and not ref_id:
            ref_id = msg_id