5 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 from stgit
.argparse
import opt
24 from stgit
.commands
import common
25 from stgit
import argparse
, git
, templates
26 from stgit
.out
import out
27 from stgit
.lib
import git
as gitlib
29 help = 'Export patches to a directory'
31 usage
= ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
33 Export a range of applied patches to a given directory (defaults to
34 'patches-<branch>') in a standard unified GNU diff format. A template
35 file (defaulting to '.git/patchexport.tmpl' or
36 '~/.stgit/templates/patchexport.tmpl' or
37 '/usr/share/stgit/templates/patchexport.tmpl') can be used for the
38 patch format. The following variables are supported in the template
41 %(description)s - patch description
42 %(shortdescr)s - the first line of the patch description
43 %(longdescr)s - the rest of the patch description, after the first line
44 %(diffstat)s - the diff statistics
45 %(authname)s - author's name
46 %(authemail)s - author's e-mail
47 %(authdate)s - patch creation date
48 %(commname)s - committer's name
49 %(commemail)s - committer's e-mail"""
51 args
= [argparse
.patch_range(argparse
.applied_patches
,
52 argparse
.unapplied_patches
,
53 argparse
.hidden_patches
)]
55 opt('-d', '--dir', args
= [argparse
.dir],
56 short
= 'Export patches to DIR instead of the default'),
57 opt('-p', '--patch', action
= 'store_true',
58 short
= 'Append .patch to the patch names'),
59 opt('-e', '--extension',
60 short
= 'Append .EXTENSION to the patch names'),
61 opt('-n', '--numbered', action
= 'store_true',
62 short
= 'Prefix the patch names with order numbers'),
63 opt('-t', '--template', metavar
= 'FILE', args
= [argparse
.files
],
64 short
= 'Use FILE as a template'),
65 opt('-b', '--branch', args
= [argparse
.stg_branches
],
66 short
= 'Use BRANCH instead of the default branch'),
67 opt('-s', '--stdout', action
= 'store_true',
68 short
= 'Dump the patches to the standard output'),
69 ] + argparse
.diff_opts_option()
71 directory
= common
.DirectoryHasRepositoryLib()
73 def func(parser
, options
, args
):
74 """Export a range of patches.
76 stack
= directory
.repository
.get_stack(options
.branch
)
81 dirname
= 'patches-%s' % stack
.name
82 directory
.cd_to_topdir()
84 if not options
.branch
and git
.local_changes():
85 out
.warn('Local changes in the tree;'
86 ' you might want to commit them first')
88 if not options
.stdout
:
89 if not os
.path
.isdir(dirname
):
91 series
= file(os
.path
.join(dirname
, 'series'), 'w+')
93 applied
= stack
.patchorder
.applied
94 unapplied
= stack
.patchorder
.unapplied
96 patches
= common
.parse_patches(args
, applied
+ unapplied
, len(applied
))
102 raise common
.CmdException
, 'No patches applied'
104 zpadding
= len(str(num
))
110 tmpl
= file(options
.template
).read()
112 tmpl
= templates
.get_template('patchexport.tmpl')
116 # note the base commit for this series
117 if not options
.stdout
:
118 base_commit
= stack
.patches
.get(patches
[0]).commit
.sha1
119 print >> series
, '# This series applies on GIT commit %s' % base_commit
125 pname
= '%s.patch' % pname
126 elif options
.extension
:
127 pname
= '%s.%s' %
(pname
, options
.extension
)
129 pname
= '%s-%s' %
(str(patch_no
).zfill(zpadding
), pname
)
130 pfile
= os
.path
.join(dirname
, pname
)
131 if not options
.stdout
:
132 print >> series
, pname
134 # get the patch description
135 patch
= stack
.patches
.get(p
)
136 cd
= patch
.commit
.data
138 descr
= cd
.message
.strip()
139 descr_lines
= descr
.split('\n')
141 short_descr
= descr_lines
[0].rstrip()
142 long_descr
= reduce(lambda x
, y
: x
+ '\n' + y
,
143 descr_lines
[1:], '').strip()
145 diff
= stack
.repository
.diff_tree(cd
.parent
.data
.tree
, cd
.tree
, options
.diff_flags
)
147 tmpl_dict
= {'description': descr
,
148 'shortdescr': short_descr
,
149 'longdescr': long_descr
,
150 'diffstat': gitlib
.diffstat(diff
).rstrip(),
151 'authname': cd
.author
.name
,
152 'authemail': cd
.author
.email
,
153 'authdate': cd
.author
.date
.isoformat(),
154 'commname': cd
.committer
.name
,
155 'commemail': cd
.committer
.email
}
156 for key
in tmpl_dict
:
157 if not tmpl_dict
[key
]:
161 descr
= tmpl % tmpl_dict
162 except KeyError, err
:
163 raise common
.CmdException
, 'Unknown patch template variable: %s' \
166 raise common
.CmdException
, 'Only "%(name)s" variables are ' \
167 'supported in the patch template'
172 f
= open(pfile
, 'w+')
174 if options
.stdout
and num
> 1:
181 if not options
.stdout
:
185 if not options
.stdout
: