chiark / gitweb /
Refactor stgit.commands.edit
[stgit] / stgit / commands / export.py
CommitLineData
fcee87cf
CM
1"""Export command
2"""
3
4__copyright__ = """
5Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
3f19450c 21import os
575bbdae 22from stgit.argparse import opt
3f19450c 23from stgit.commands import common
20a52e06 24from stgit import argparse, git, templates
3f19450c
CM
25from stgit.out import out
26from stgit.lib import git as gitlib
fcee87cf 27
575bbdae 28help = 'Export patches to a directory'
33ff9cdd 29kind = 'patch'
575bbdae
KH
30usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
31description = """
8560c67b
CM
32Export a range of applied patches to a given directory (defaults to
33'patches-<branch>') in a standard unified GNU diff format. A template
34file (defaulting to '.git/patchexport.tmpl' or
94d18868
YD
35'~/.stgit/templates/patchexport.tmpl' or
36'/usr/share/stgit/templates/patchexport.tmpl') can be used for the
23a88c7d
CM
37patch format. The following variables are supported in the template
38file:
26aab5b0
CM
39
40 %(description)s - patch description
99e73103
CM
41 %(shortdescr)s - the first line of the patch description
42 %(longdescr)s - the rest of the patch description, after the first line
26aab5b0
CM
43 %(diffstat)s - the diff statistics
44 %(authname)s - author's name
45 %(authemail)s - author's e-mail
46 %(authdate)s - patch creation date
47 %(commname)s - committer's name
575bbdae
KH
48 %(commemail)s - committer's e-mail"""
49
50options = [
51 opt('-d', '--dir',
52 short = 'Export patches to DIR instead of the default'),
53 opt('-p', '--patch', action = 'store_true',
54 short = 'Append .patch to the patch names'),
55 opt('-e', '--extension',
56 short = 'Append .EXTENSION to the patch names'),
57 opt('-n', '--numbered', action = 'store_true',
58 short = 'Prefix the patch names with order numbers'),
59 opt('-t', '--template', metavar = 'FILE',
60 short = 'Use FILE as a template'),
61 opt('-b', '--branch',
62 short = 'Use BRANCH instead of the default branch'),
63 opt('-s', '--stdout', action = 'store_true',
64 short = 'Dump the patches to the standard output'),
65 ] + argparse.diff_opts_option()
26aab5b0 66
3f19450c 67directory = common.DirectoryHasRepositoryLib()
fcee87cf
CM
68
69def func(parser, options, args):
8560c67b
CM
70 """Export a range of patches.
71 """
3f19450c
CM
72 stack = directory.repository.get_stack(options.branch)
73
8560c67b
CM
74 if options.dir:
75 dirname = options.dir
fcee87cf 76 else:
3f19450c 77 dirname = 'patches-%s' % stack.name
7b601c9e 78 directory.cd_to_topdir()
fcee87cf 79
2f7c8b0b 80 if not options.branch and git.local_changes():
27ac2b7e
KH
81 out.warn('Local changes in the tree;'
82 ' you might want to commit them first')
fcee87cf 83
1fceece7
CM
84 if not options.stdout:
85 if not os.path.isdir(dirname):
86 os.makedirs(dirname)
87 series = file(os.path.join(dirname, 'series'), 'w+')
fcee87cf 88
3f19450c
CM
89 applied = stack.patchorder.applied
90 unapplied = stack.patchorder.unapplied
8560c67b 91 if len(args) != 0:
06f9bd6b 92 patches = common.parse_patches(args, applied + unapplied, len(applied))
fcee87cf 93 else:
6b1e0111 94 patches = applied
fcee87cf
CM
95
96 num = len(patches)
16ad223e 97 if num == 0:
4675b4bb 98 raise common.CmdException, 'No patches applied'
16ad223e 99
fcee87cf
CM
100 zpadding = len(str(num))
101 if zpadding < 2:
102 zpadding = 2
103
23a88c7d
CM
104 # get the template
105 if options.template:
1f3bb017 106 tmpl = file(options.template).read()
23a88c7d 107 else:
1f3bb017
CM
108 tmpl = templates.get_template('patchexport.tmpl')
109 if not tmpl:
110 tmpl = ''
23a88c7d 111
6c4e4b68 112 # note the base commit for this series
1fceece7 113 if not options.stdout:
3f19450c 114 base_commit = stack.patches.get(patches[0]).commit.sha1
1fceece7 115 print >> series, '# This series applies on GIT commit %s' % base_commit
6c4e4b68 116
fcee87cf
CM
117 patch_no = 1;
118 for p in patches:
119 pname = p
8560c67b 120 if options.patch:
099ff6cd 121 pname = '%s.patch' % pname
8560c67b
CM
122 elif options.extension:
123 pname = '%s.%s' % (pname, options.extension)
fcee87cf
CM
124 if options.numbered:
125 pname = '%s-%s' % (str(patch_no).zfill(zpadding), pname)
126 pfile = os.path.join(dirname, pname)
1fceece7
CM
127 if not options.stdout:
128 print >> series, pname
fcee87cf 129
fcee87cf 130 # get the patch description
3f19450c
CM
131 patch = stack.patches.get(p)
132 cd = patch.commit.data
fcee87cf 133
3f19450c 134 descr = cd.message.strip()
99e73103
CM
135 descr_lines = descr.split('\n')
136
137 short_descr = descr_lines[0].rstrip()
138 long_descr = reduce(lambda x, y: x + '\n' + y,
139 descr_lines[1:], '').strip()
140
3f19450c
CM
141 diff = stack.repository.diff_tree(cd.parent.data.tree, cd.tree, options.diff_flags)
142
143 tmpl_dict = {'description': descr,
99e73103
CM
144 'shortdescr': short_descr,
145 'longdescr': long_descr,
ef954fe6 146 'diffstat': gitlib.diffstat(diff).rstrip(),
3f19450c
CM
147 'authname': cd.author.name,
148 'authemail': cd.author.email,
149 'authdate': cd.author.date.isoformat(),
150 'commname': cd.committer.name,
151 'commemail': cd.committer.email}
fcee87cf
CM
152 for key in tmpl_dict:
153 if not tmpl_dict[key]:
154 tmpl_dict[key] = ''
155
156 try:
157 descr = tmpl % tmpl_dict
158 except KeyError, err:
4675b4bb 159 raise common.CmdException, 'Unknown patch template variable: %s' \
fcee87cf
CM
160 % err
161 except TypeError:
4675b4bb 162 raise common.CmdException, 'Only "%(name)s" variables are ' \
fcee87cf 163 'supported in the patch template'
fcee87cf 164
1fceece7
CM
165 if options.stdout:
166 f = sys.stdout
167 else:
168 f = open(pfile, 'w+')
169
170 if options.stdout and num > 1:
27ac2b7e 171 print '-'*79
3f19450c 172 print patch.name
27ac2b7e 173 print '-'*79
1fceece7 174
1fceece7 175 f.write(descr)
a45cea15 176 f.write(diff)
1fceece7
CM
177 if not options.stdout:
178 f.close()
fcee87cf
CM
179 patch_no += 1
180
1fceece7
CM
181 if not options.stdout:
182 series.close()