print 'done'
+def parse_patches(patch_args, patch_list):
+ """Parse patch_args list for patch names in patch_list and return
+ a list. The names can be individual patches and/or in the
+ patch1..patch2 format.
+ """
+ patches = []
+
+ for name in patch_args:
+ pair = name.split('..')
+ for p in pair:
+ if p and not p in patch_list:
+ raise CmdException, 'Unknown patch name: %s' % p
+
+ if len(pair) == 1:
+ # single patch name
+ pl = pair
+ elif len(pair) == 2:
+ # patch range [p1]..[p2]
+ # inclusive boundary
+ if pair[0]:
+ first = patch_list.index(pair[0])
+ else:
+ first = 0
+ # exclusive boundary
+ if pair[1]:
+ last = patch_list.index(pair[1]) + 1
+ else:
+ last = len(patch_list)
+
+ if last > first:
+ pl = patch_list[first:last]
+ else:
+ pl = patch_list[(last - 1):(first + 1)]
+ pl.reverse()
+ else:
+ raise CmdException, 'Malformed patch name: %s' % name
+
+ for p in pl:
+ if p in patches:
+ raise CmdException, 'Duplicate patch name: %s' % p
+
+ patches += pl
+
+ return patches
+
def name_email(address):
"""Return a tuple consisting of the name and email parsed from a
standard 'name <email>' or 'email (name)' string
If neither bottom nor top are given but a '//' is present, the command
shows the specified patch (defaulting to the current one)."""
-options = [make_option('-r', metavar = 'rev1[:[rev2]]', dest = 'revs',
+options = [make_option('-r', metavar = 'rev1[..[rev2]]', dest = 'revs',
help = 'show the diff between revisions'),
make_option('-s', '--stat',
help = 'show the stat instead of the diff',
"""Show the tree diff
"""
if options.revs:
- rev_list = options.revs.split(':')
+ rev_list = options.revs.split('..')
rev_list_len = len(rev_list)
if rev_list_len == 1:
rev = rev_list[0]
make_option('-t', '--template', metavar = 'FILE',
help = 'Use FILE as a template'),
make_option('-r', '--range',
- metavar = '[PATCH1][:[PATCH2]]',
+ metavar = '[PATCH1][..[PATCH2]]',
help = 'export patches between PATCH1 and PATCH2'),
make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
series = file(os.path.join(dirname, 'series'), 'w+')
applied = crt_series.get_applied()
- unapplied = crt_series.get_unapplied()
if options.range:
- boundaries = options.range.split(':')
- if len(boundaries) == 1:
- start = boundaries[0]
- stop = boundaries[0]
- elif len(boundaries) == 2:
- if boundaries[0] == '':
- start = applied[0]
- else:
- start = boundaries[0]
- if boundaries[1] == '':
- stop = applied[-1]
- else:
- stop = boundaries[1]
- else:
- raise CmdException, 'incorrect parameters to "--range"'
-
- if start in applied:
- start_idx = applied.index(start)
- else:
- if start in unapplied:
- raise CmdException, 'Patch "%s" not applied' % start
- else:
- raise CmdException, 'Patch "%s" does not exist' % start
-
- if stop in applied:
- stop_idx = applied.index(stop) + 1
- else:
- if stop in unapplied:
- raise CmdException, 'Patch "%s" not applied' % stop
- else:
- raise CmdException, 'Patch "%s" does not exist' % stop
-
- if start_idx >= stop_idx:
- raise CmdException, 'Incorrect patch range order'
+ patches = parse_patches([options.range], applied)
else:
- start_idx = 0
- stop_idx = len(applied)
-
- patches = applied[start_idx:stop_idx]
+ patches = applied
num = len(patches)
if num == 0:
help = 'send a patch or series of patches by e-mail'
-usage = """%prog [options] [<patch> [<patch2...]]
+usage = """%prog [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]
-Send a patch or a range of patches (defaulting to the applied patches)
-by e-mail using the 'smtpserver' configuration option. The From
-address and the e-mail format are generated from the template file
-passed as argument to '--template' (defaulting to
-'.git/patchmail.tmpl' or '~/.stgit/templates/patchmail.tmpl' or or
+Send a patch or a range of patches by e-mail using the 'smtpserver'
+configuration option. The From address and the e-mail format are
+generated from the template file passed as argument to '--template'
+(defaulting to '.git/patchmail.tmpl' or
+'~/.stgit/templates/patchmail.tmpl' or or
'/usr/share/stgit/templates/patchmail.tmpl'). The To/Cc/Bcc addresses
can either be added to the template file or passed via the
corresponding command line options.
options = [make_option('-a', '--all',
help = 'e-mail all the applied patches',
action = 'store_true'),
- make_option('-r', '--range',
- metavar = '[PATCH1][:[PATCH2]]',
- help = 'e-mail patches between PATCH1 and PATCH2'),
make_option('--to',
help = 'add TO to the To: list',
action = 'append'),
smtppassword = config.get('stgit', 'smtppassword')
applied = crt_series.get_applied()
- unapplied = crt_series.get_unapplied()
-
- if len(args) >= 1:
- for patch in args:
- if patch in unapplied:
- raise CmdException, 'Patch "%s" not applied' % patch
- if not patch in applied:
- raise CmdException, 'Patch "%s" does not exist' % patch
- patches = args
- elif options.all:
- patches = applied
- elif options.range:
- boundaries = options.range.split(':')
- if len(boundaries) == 1:
- start = boundaries[0]
- stop = boundaries[0]
- elif len(boundaries) == 2:
- if boundaries[0] == '':
- start = applied[0]
- else:
- start = boundaries[0]
- if boundaries[1] == '':
- stop = applied[-1]
- else:
- stop = boundaries[1]
- else:
- raise CmdException, 'incorrect parameters to "--range"'
- if start in applied:
- start_idx = applied.index(start)
- else:
- if start in unapplied:
- raise CmdException, 'Patch "%s" not applied' % start
- else:
- raise CmdException, 'Patch "%s" does not exist' % start
- if stop in applied:
- stop_idx = applied.index(stop) + 1
- else:
- if stop in unapplied:
- raise CmdException, 'Patch "%s" not applied' % stop
- else:
- raise CmdException, 'Patch "%s" does not exist' % stop
-
- if start_idx >= stop_idx:
- raise CmdException, 'Incorrect patch range order'
-
- patches = applied[start_idx:stop_idx]
+ if options.all:
+ patches = applied
+ elif len(args) >= 1:
+ patches = parse_patches(args, applied)
else:
raise CmdException, 'Incorrect options. Unknown patches to send'
from stgit import stack, git
-help = 'pop the top of the series'
-usage = """%prog [options]
+help = 'pop one or more patches from the stack'
+usage = """%prog [options] [<patch>]
Pop the topmost patch or a range of patches starting with the topmost
one from the stack. The command fails if there are local changes or
-conflicts."""
+conflicts. If a patch name is given as argument, the command will pop
+all the patches up to the given one."""
options = [make_option('-a', '--all',
help = 'pop all the applied patches',
action = 'store_true'),
make_option('-n', '--number', type = 'int',
- help = 'pop the specified number of patches'),
- make_option('-t', '--to', metavar = 'PATCH',
- help = 'pop all patches up to PATCH')]
+ help = 'pop the specified number of patches')]
def func(parser, options, args):
"""Pop the topmost patch from the stack
"""
- if len(args) != 0:
+ if len(args) > 1:
parser.error('incorrect number of arguments')
check_local_changes()
applied = crt_series.get_applied()
if not applied:
raise CmdException, 'No patches applied'
+ # the popping is done in reverse order
applied.reverse()
- if options.to:
- if options.to not in applied:
- if options.to in crt_series.get_unapplied():
- raise CmdException, 'Patch "%s" is not currently applied.' % options.to
- else:
- raise CmdException, 'Patch "%s" does not exist.' % options.to
- patches = applied[:applied.index(options.to)]
+ if options.all:
+ patches = applied
elif options.number:
patches = applied[:options.number]
- elif options.all:
- patches = applied
+ elif len(args) == 1:
+ upto_patch = args[0]
+ if upto_patch not in applied:
+ if upto_patch in crt_series.get_unapplied():
+ raise CmdException, 'Patch "%s" is not currently applied' \
+ % upto_patch
+ else:
+ raise CmdException, 'Patch "%s" does not exist' % upto_patch
+ patches = applied[:applied.index(upto_patch)]
else:
patches = [applied[0]]
from stgit import stack, git
-help = 'push a patch on top of the series'
-usage = """%prog [options] [<patch1> [<patch2>...]]
+help = 'push one or more patches onto of the stack'
+usage = """%prog [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]
-Push a patch (defaulting to the first unapplied one) or range of
-patches to the stack. The 'push' operation allows patch reordering by
-commuting them with the three-way merge algorithm. If the result of
-the 'push' operation is not acceptable or if there are too many
-conflicts, the '--undo' option can be used to revert the patch and the
-tree to the state before the operation. Conflicts raised during the
-push operation have to be fixed and the 'resolved' command run.
+Push one or more patches (defaulting to the first unapplied one) onto
+the stack. The 'push' operation allows patch reordering by commuting
+them with the three-way merge algorithm. If the result of the 'push'
+operation is not acceptable or if there are too many conflicts, the
+'--undo' option can be used to revert the last pushed patch. Conflicts
+raised during the push operation have to be fixed and the 'resolved'
+command run.
The command also notifies when the patch becomes empty (fully merged
upstream) or is modified (three-way merged) by the 'push' operation."""
action = 'store_true'),
make_option('-n', '--number', type = 'int',
help = 'push the specified number of patches'),
- make_option('-t', '--to', metavar = 'PATCH1[:PATCH2]',
- help = 'push all patches to PATCH1 or between '
- 'PATCH1 and PATCH2'),
make_option('--reverse',
help = 'push the patches in reverse order',
action = 'store_true'),
help = 'check for patches merged upstream',
action = 'store_true'),
make_option('--undo',
- help = 'undo the last push operation',
+ help = 'undo the last patch pushing',
action = 'store_true')]
-def is_patch_appliable(p):
- """See if patch exists, or is already applied.
- """
- if p in applied:
- raise CmdException, 'Patch "%s" is already applied' % p
- if p not in unapplied:
- raise CmdException, 'Patch "%s" does not exist' % p
-
def func(parser, options, args):
"""Pushes the given patch or all onto the series
"""
- global applied, unapplied
# If --undo is passed, do the work and exit
if options.undo:
check_conflicts()
check_head_top_equal()
- applied = crt_series.get_applied()
unapplied = crt_series.get_unapplied()
if not unapplied:
raise CmdException, 'No more patches to push'
- if options.to:
- boundaries = options.to.split(':')
- if len(boundaries) == 1:
- is_patch_appliable(boundaries[0])
- patches = unapplied[:unapplied.index(boundaries[0])+1]
- elif len(boundaries) == 2:
- is_patch_appliable(boundaries[0])
- is_patch_appliable(boundaries[1])
- lb = unapplied.index(boundaries[0])
- hb = unapplied.index(boundaries[1])
- if lb > hb:
- raise CmdException, 'Patch "%s" after "%s"' \
- % (boundaries[0], boundaries[1])
- patches = unapplied[lb:hb+1]
- else:
- raise CmdException, 'incorrect parameters to "--to"'
- elif options.number:
+ if options.number:
patches = unapplied[:options.number]
elif options.all:
patches = unapplied
elif len(args) == 0:
patches = [unapplied[0]]
else:
- patches = args
- map(is_patch_appliable, patches)
+ patches = parse_patches(args, unapplied)
if patches == []:
raise CmdException, 'No patches to push'