X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/8f4d71da1803d581f3329628a18ac1bc46b38068..625e8de7db58c85f137e78aaef258afcb1a3151c:/stgit/commands/export.py diff --git a/stgit/commands/export.py b/stgit/commands/export.py index db7b560..8d05996 100644 --- a/stgit/commands/export.py +++ b/stgit/commands/export.py @@ -18,118 +18,137 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -import sys, os -from optparse import OptionParser, make_option - -from stgit.commands.common import * -from stgit.utils import * -from stgit import stack, git - - -help = 'exports a series of patches to (or patches)' -usage = """%prog [options] []""" - -options = [make_option('-n', '--numbered', - help = 'number the patch names', - action = 'store_true'), - make_option('-d', '--diff', - help = 'append .diff to the patch names', - action = 'store_true'), - make_option('-t', '--template', metavar = 'FILE', - help = 'Use FILE as a template'), - make_option('-r', '--range', - metavar = '[PATCH1][:[PATCH2]]', - help = 'export patches between PATCH1 and PATCH2')] - +import os +from stgit.argparse import opt +from stgit.commands import common +from stgit import argparse, git, templates +from stgit.out import out +from stgit.lib import git as gitlib + +help = 'Export patches to a directory' +kind = 'patch' +usage = ['[options] [] [] [..]'] +description = """ +Export a range of applied patches to a given directory (defaults to +'patches-') in a standard unified GNU diff format. A template +file (defaulting to '.git/patchexport.tmpl' or +'~/.stgit/templates/patchexport.tmpl' or +'/usr/share/stgit/templates/patchexport.tmpl') can be used for the +patch format. The following variables are supported in the template +file: + + %(description)s - patch description + %(shortdescr)s - the first line of the patch description + %(longdescr)s - the rest of the patch description, after the first line + %(diffstat)s - the diff statistics + %(authname)s - author's name + %(authemail)s - author's e-mail + %(authdate)s - patch creation date + %(commname)s - committer's name + %(commemail)s - committer's e-mail""" + +options = [ + opt('-d', '--dir', + short = 'Export patches to DIR instead of the default'), + opt('-p', '--patch', action = 'store_true', + short = 'Append .patch to the patch names'), + opt('-e', '--extension', + short = 'Append .EXTENSION to the patch names'), + opt('-n', '--numbered', action = 'store_true', + short = 'Prefix the patch names with order numbers'), + opt('-t', '--template', metavar = 'FILE', + short = 'Use FILE as a template'), + opt('-b', '--branch', + short = 'Use BRANCH instead of the default branch'), + opt('-s', '--stdout', action = 'store_true', + short = 'Dump the patches to the standard output'), + ] + argparse.diff_opts_option() + +directory = common.DirectoryHasRepositoryLib() def func(parser, options, args): - if len(args) == 0: - dirname = 'patches' - elif len(args) == 1: - dirname = args[0] - else: - parser.error('incorrect number of arguments') - - if git.local_changes(): - print 'Warning: local changes in the tree. ' \ - 'You might want to commit them first' - - if not os.path.isdir(dirname): - os.makedirs(dirname) - series = file(os.path.join(dirname, 'series'), 'w+') - - applied = crt_series.get_applied() - - 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"' + """Export a range of patches. + """ + stack = directory.repository.get_stack(options.branch) - if start in applied: - start_idx = applied.index(start) - else: - raise CmdException, 'Patch "%s" not applied' % start - if stop in applied: - stop_idx = applied.index(stop) + 1 - else: - raise CmdException, 'Patch "%s" not applied' % stop - - if start_idx >= stop_idx: - raise CmdException, 'Incorrect patch range order' + if options.dir: + dirname = options.dir else: - start_idx = 0 - stop_idx = len(applied) - - patches = applied[start_idx:stop_idx] + 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.diff: - pname = '%s.diff' % pname + 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) - print >> series, pname - - # get the template - if options.template: - patch_tmpl = options.template - else: - patch_tmpl = os.path.join(git.base_dir, 'patchexport.tmpl') - if os.path.isfile(patch_tmpl): - tmpl = file(patch_tmpl).read() - else: - tmpl = '' + if not options.stdout: + print >> series, pname # get the patch description - patch = crt_series.get_patch(p) - - tmpl_dict = {'description': patch.get_description().rstrip(), - 'diffstat': git.diffstat(rev1 = git_id('%s/bottom' % p), - rev2 = git_id('%s/top' % p)), - 'authname': patch.get_authname(), - 'authemail': patch.get_authemail(), - 'authdate': patch.get_authdate(), - 'commname': patch.get_commname(), - 'commemail': patch.get_commemail()} + 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': git.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] = '' @@ -137,19 +156,27 @@ def func(parser, options, args): try: descr = tmpl % tmpl_dict except KeyError, err: - raise CmdException, 'Unknown patch template variable: %s' \ + raise common.CmdException, 'Unknown patch template variable: %s' \ % err except TypeError: - raise CmdException, 'Only "%(name)s" variables are ' \ + raise common.CmdException, 'Only "%(name)s" variables are ' \ 'supported in the patch template' - f = open(pfile, 'w+') - f.write(descr) - # write the diff - git.diff(rev1 = git_id('%s/bottom' % p), - rev2 = git_id('%s/top' % p), - out_fd = f) - f.close() + if options.stdout: + f = sys.stdout + else: + f = open(pfile, 'w+') + + if options.stdout and num > 1: + print '-'*79 + print patch.name + print '-'*79 + + f.write(descr) + f.write(diff) + if not options.stdout: + f.close() patch_no += 1 - series.close() + if not options.stdout: + series.close()