"""
import sys, os
-from optparse import OptionParser, make_option
-
+from stgit.argparse import opt
from stgit.commands.common import *
from stgit.utils import *
-from stgit import stack, git
+from stgit.out import *
+from stgit import argparse, stack, git
+from stgit.stack import Series
+
+help = 'Import a patch from a different branch or a commit object'
+kind = 'patch'
+usage = ['[options] ([<patch1>] [<patch2>] [<patch3>..<patch4>])|<commit>']
+description = """
+Import one or more patches from a different branch or a commit object
+into the current series. By default, the name of the imported patch is
+used as the name of the current patch. It can be overridden with the
+'--name' option. A commit object can be reverted with the '--reverse'
+option. The log and author information are those of the commit
+object."""
+
+args = [argparse.patch_range(argparse.applied_patches,
+ argparse.unapplied_patches,
+ argparse.hidden_patches)]
+options = [
+ opt('-n', '--name',
+ short = 'Use NAME as the patch name'),
+ opt('-B', '--ref-branch', args = [argparse.stg_branches],
+ short = 'Pick patches from BRANCH'),
+ opt('-r', '--reverse', action = 'store_true',
+ short = 'Reverse the commit object before importing'),
+ opt('-p', '--parent', metavar = 'COMMITID', args = [argparse.commit],
+ short = 'Use COMMITID as parent'),
+ opt('-x', '--expose', action = 'store_true',
+ short = 'Append the imported commit id to the patch log'),
+ opt('--fold', action = 'store_true',
+ short = 'Fold the commit object into the current patch'),
+ opt('--update', action = 'store_true',
+ short = 'Like fold but only update the current patch files'),
+ opt('--unapplied', action = 'store_true',
+ short = 'Keep the patch unapplied')]
+
+directory = DirectoryGotoToplevel(log = True)
+
+def __pick_commit(commit_id, patchname, options):
+ """Pick a commit id.
+ """
+ commit = git.Commit(commit_id)
+ if options.name:
+ patchname = options.name
+ if patchname:
+ patchname = find_patch_name(patchname, crt_series.patch_exists)
-help = 'import a patch from a different branch or a commit object'
-usage = """%prog [options] [<patch@branch>|<commit>]
+ if options.parent:
+ parent = git_id(crt_series, options.parent)
+ else:
+ parent = commit.get_parent()
-Import a patch from a different branch or a commit object into the
-current series. By default, the name of the imported patch is used as
-the name of the current patch. It can be overriden with the '--name'
-option. A commit object can be reverted with the '--reverse'
-option. The log and author information are those of the commit object."""
+ if not options.reverse:
+ bottom = parent
+ top = commit_id
+ else:
+ bottom = commit_id
+ top = parent
-options = [make_option('-n', '--name',
- help = 'use NAME as the patch name'),
- make_option('-r', '--reverse',
- help = 'reverse the commit object before importing',
- action = 'store_true')]
+ if options.fold:
+ out.start('Folding commit %s' % commit_id)
+ # try a direct git apply first
+ if not git.apply_diff(bottom, top):
+ git.merge_recursive(bottom, git.get_head(), top)
-def func(parser, options, args):
- """Import a commit object as a new patch
- """
- if len(args) != 1:
- parser.error('incorrect number of arguments')
+ out.done()
+ elif options.update:
+ rev1 = git_id(crt_series, 'HEAD^')
+ rev2 = git_id(crt_series, 'HEAD')
+ files = git.barefiles(rev1, rev2).split('\n')
- check_local_changes()
- check_conflicts()
- check_head_top_equal()
+ out.start('Updating with commit %s' % commit_id)
- commit_str = args[0]
- patch_branch = commit_str.split('@')
+ if not git.apply_diff(bottom, top, files = files):
+ raise CmdException, 'Patch updating failed'
- if len(patch_branch) == 2:
- patch = patch_branch[0]
- elif options.name:
- patch = options.name
+ out.done()
else:
- raise CmdException, 'Unkown patch name'
+ message = commit.get_log()
+ if options.expose:
+ message += '(imported from commit %s)\n' % commit.get_id_hash()
+ author_name, author_email, author_date = \
+ name_email_date(commit.get_author())
+
+ out.start('Importing commit %s' % commit_id)
+
+ newpatch = crt_series.new_patch(patchname, message = message, can_edit = False,
+ unapplied = True, bottom = bottom, top = top,
+ author_name = author_name,
+ author_email = author_email,
+ author_date = author_date)
+ # in case the patch name was automatically generated
+ patchname = newpatch.get_name()
+
+ # find a patchlog to fork from
+ refbranchname, refpatchname = parse_rev(patchname)
+ if refpatchname:
+ if refbranchname:
+ # assume the refseries is OK, since we already resolved
+ # commit_str to a git_id
+ refseries = Series(refbranchname)
+ else:
+ refseries = crt_series
+ patch = refseries.get_patch(refpatchname)
+ if patch.get_log():
+ out.info("Log was %s" % newpatch.get_log())
+ out.info("Setting log to %s\n" % patch.get_log())
+ newpatch.set_log(patch.get_log())
+ out.info("Log is now %s" % newpatch.get_log())
+ else:
+ out.info("No log for %s\n" % patchname)
+
+ if not options.unapplied:
+ modified = crt_series.push_patch(patchname)
+ else:
+ modified = False
+
+ if crt_series.empty_patch(patchname):
+ out.done('empty patch')
+ elif modified:
+ out.done('modified')
+ else:
+ out.done()
- commit_id = git_id(commit_str)
- commit = git.Commit(commit_id)
-
- if not options.reverse:
- bottom = commit.get_parent()
- top = commit_id
- else:
- bottom = commit_id
- top = commit.get_parent()
- message = commit.get_log()
- author_name, author_email, author_date = \
- name_email_date(commit.get_author())
+def func(parser, options, args):
+ """Import a commit object as a new patch
+ """
+ if not args:
+ parser.error('incorrect number of arguments')
- print 'Importing commit %s...' % commit_id,
- sys.stdout.flush()
+ if not options.unapplied:
+ check_local_changes()
+ check_conflicts()
+ check_head_top_equal(crt_series)
- crt_series.new_patch(patch, message = message, can_edit = False,
- unapplied = True, bottom = bottom, top = top,
- author_name = author_name,
- author_email = author_email,
- author_date = author_date)
- crt_series.push_patch(patch)
+ 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 'done'
- print_crt_patch()
+ print_crt_patch(crt_series)