Add support for initializing a branch for stgit from Emacs.
[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
CM
21import os
22from optparse import make_option
fcee87cf 23
3f19450c 24from stgit.commands import common
20a52e06 25from stgit import argparse, git, templates
3f19450c
CM
26from stgit.out import out
27from stgit.lib import git as gitlib
fcee87cf 28
4ec67741 29help = 'exports patches to a directory'
8560c67b 30usage = """%prog [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]
26aab5b0 31
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
48 %(commemail)s - committer's e-mail
8560c67b 49"""
26aab5b0 50
3f19450c 51directory = common.DirectoryHasRepositoryLib()
8560c67b
CM
52options = [make_option('-d', '--dir',
53 help = 'export patches to DIR instead of the default'),
099ff6cd
CM
54 make_option('-p', '--patch',
55 help = 'append .patch to the patch names',
56 action = 'store_true'),
8560c67b
CM
57 make_option('-e', '--extension',
58 help = 'append .EXTENSION to the patch names'),
59 make_option('-n', '--numbered',
60 help = 'prefix the patch names with order numbers',
61 action = 'store_true'),
fcee87cf
CM
62 make_option('-t', '--template', metavar = 'FILE',
63 help = 'Use FILE as a template'),
2f7c8b0b 64 make_option('-b', '--branch',
1fceece7
CM
65 help = 'use BRANCH instead of the default one'),
66 make_option('-s', '--stdout',
67 help = 'dump the patches to the standard output',
0b635fe6 68 action = 'store_true')
20a52e06 69 ] + argparse.diff_opts_option()
fcee87cf
CM
70
71def func(parser, options, args):
8560c67b
CM
72 """Export a range of patches.
73 """
3f19450c
CM
74 stack = directory.repository.get_stack(options.branch)
75
8560c67b
CM
76 if options.dir:
77 dirname = options.dir
fcee87cf 78 else:
3f19450c 79 dirname = 'patches-%s' % stack.name
7b601c9e 80 directory.cd_to_topdir()
fcee87cf 81
2f7c8b0b 82 if not options.branch and git.local_changes():
27ac2b7e
KH
83 out.warn('Local changes in the tree;'
84 ' you might want to commit them first')
fcee87cf 85
1fceece7
CM
86 if not options.stdout:
87 if not os.path.isdir(dirname):
88 os.makedirs(dirname)
89 series = file(os.path.join(dirname, 'series'), 'w+')
fcee87cf 90
3f19450c
CM
91 applied = stack.patchorder.applied
92 unapplied = stack.patchorder.unapplied
8560c67b 93 if len(args) != 0:
06f9bd6b 94 patches = common.parse_patches(args, applied + unapplied, len(applied))
fcee87cf 95 else:
6b1e0111 96 patches = applied
fcee87cf
CM
97
98 num = len(patches)
16ad223e 99 if num == 0:
4675b4bb 100 raise common.CmdException, 'No patches applied'
16ad223e 101
fcee87cf
CM
102 zpadding = len(str(num))
103 if zpadding < 2:
104 zpadding = 2
105
23a88c7d
CM
106 # get the template
107 if options.template:
1f3bb017 108 tmpl = file(options.template).read()
23a88c7d 109 else:
1f3bb017
CM
110 tmpl = templates.get_template('patchexport.tmpl')
111 if not tmpl:
112 tmpl = ''
23a88c7d 113
6c4e4b68 114 # note the base commit for this series
1fceece7 115 if not options.stdout:
3f19450c 116 base_commit = stack.patches.get(patches[0]).commit.sha1
1fceece7 117 print >> series, '# This series applies on GIT commit %s' % base_commit
6c4e4b68 118
fcee87cf
CM
119 patch_no = 1;
120 for p in patches:
121 pname = p
8560c67b 122 if options.patch:
099ff6cd 123 pname = '%s.patch' % pname
8560c67b
CM
124 elif options.extension:
125 pname = '%s.%s' % (pname, options.extension)
fcee87cf
CM
126 if options.numbered:
127 pname = '%s-%s' % (str(patch_no).zfill(zpadding), pname)
128 pfile = os.path.join(dirname, pname)
1fceece7
CM
129 if not options.stdout:
130 print >> series, pname
fcee87cf 131
fcee87cf 132 # get the patch description
3f19450c
CM
133 patch = stack.patches.get(p)
134 cd = patch.commit.data
fcee87cf 135
3f19450c 136 descr = cd.message.strip()
99e73103
CM
137 descr_lines = descr.split('\n')
138
139 short_descr = descr_lines[0].rstrip()
140 long_descr = reduce(lambda x, y: x + '\n' + y,
141 descr_lines[1:], '').strip()
142
3f19450c
CM
143 diff = stack.repository.diff_tree(cd.parent.data.tree, cd.tree, options.diff_flags)
144
145 tmpl_dict = {'description': descr,
99e73103
CM
146 'shortdescr': short_descr,
147 'longdescr': long_descr,
3f19450c
CM
148 'diffstat': git.diffstat(diff).rstrip(),
149 'authname': cd.author.name,
150 'authemail': cd.author.email,
151 'authdate': cd.author.date.isoformat(),
152 'commname': cd.committer.name,
153 'commemail': cd.committer.email}
fcee87cf
CM
154 for key in tmpl_dict:
155 if not tmpl_dict[key]:
156 tmpl_dict[key] = ''
157
158 try:
159 descr = tmpl % tmpl_dict
160 except KeyError, err:
4675b4bb 161 raise common.CmdException, 'Unknown patch template variable: %s' \
fcee87cf
CM
162 % err
163 except TypeError:
4675b4bb 164 raise common.CmdException, 'Only "%(name)s" variables are ' \
fcee87cf 165 'supported in the patch template'
fcee87cf 166
1fceece7
CM
167 if options.stdout:
168 f = sys.stdout
169 else:
170 f = open(pfile, 'w+')
171
172 if options.stdout and num > 1:
27ac2b7e 173 print '-'*79
3f19450c 174 print patch.name
27ac2b7e 175 print '-'*79
1fceece7 176
1fceece7 177 f.write(descr)
a45cea15 178 f.write(diff)
1fceece7
CM
179 if not options.stdout:
180 f.close()
fcee87cf
CM
181 patch_no += 1
182
1fceece7
CM
183 if not options.stdout:
184 series.close()