Update the TODO information
[stgit] / stgit / commands / imprt.py
CommitLineData
0d2cd1e4
CM
1__copyright__ = """
2Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License version 2 as
6published by the Free Software Foundation.
7
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License
14along with this program; if not, write to the Free Software
15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16"""
17
18import sys, os
19from optparse import OptionParser, make_option
20
21from stgit.commands.common import *
22from stgit.utils import *
23from stgit import stack, git
24
25
26help = 'import a GNU diff file as a new patch'
b8a0986f 27usage = """%prog [options] [<file>]
0d2cd1e4 28
b8a0986f
CM
29Create a new patch and apply the given GNU diff file (or the standard
30input). By default, the file name is used as the patch name but this
31can be overriden with the '--name' option. The patch can either be a
32normal file with the description at the top or it can have standard
33mail format, the Subject, From and Date headers being used for
34generating the patch information.
0d2cd1e4 35
b8a0986f 36The patch description has to be separated from the data with a '---'
99e73103 37line."""
0d2cd1e4
CM
38
39options = [make_option('-m', '--mail',
40 help = 'import the patch from a standard e-mail file',
41 action = 'store_true'),
42 make_option('-n', '--name',
43 help = 'use NAME as the patch name'),
b21bc8d1 44 make_option('-b', '--base',
35344f86 45 help = 'use BASE instead of HEAD for file importing'),
33e580e0
CM
46 make_option('-e', '--edit',
47 help = 'invoke an editor for the patch description',
48 action = 'store_true'),
6ad48e48
PBG
49 make_option('-s', '--showpatch',
50 help = 'show the patch content in the editor buffer',
51 action = 'store_true'),
0d2cd1e4
CM
52 make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
53 help = 'use "NAME <EMAIL>" as the author details'),
54 make_option('--authname',
55 help = 'use AUTHNAME as the author name'),
56 make_option('--authemail',
57 help = 'use AUTHEMAIL as the author e-mail'),
58 make_option('--authdate',
59 help = 'use AUTHDATE as the author date'),
60 make_option('--commname',
61 help = 'use COMMNAME as the committer name'),
62 make_option('--commemail',
63 help = 'use COMMEMAIL as the committer e-mail')]
64
65
d4c43e19
PBG
66def __end_descr(line):
67 return re.match('---\s*$', line) or re.match('diff -', line) or \
68 re.match('Index: ', line)
99e73103
CM
69
70def __parse_description(descr):
71 """Parse the patch description and return the new description and
72 author information (if any).
73 """
74 subject = body = ''
0543bc5f 75 authname = authemail = authdate = None
99e73103 76
0543bc5f 77 descr_lines = [line.rstrip() for line in descr.split('\n')]
99e73103
CM
78 if not descr_lines:
79 raise CmdException, "Empty patch description"
80
0543bc5f
TM
81 pos = -1
82 lasthdr = 0
99e73103
CM
83 end = len(descr_lines)
84
0543bc5f
TM
85 # Parse the patch header
86 while pos < end:
99e73103 87 pos += 1
0543bc5f
TM
88 if not descr_lines[pos]:
89 continue
90 # check for a "From|Author:" line
91 if re.match('\s*(?:from|author):\s+', descr_lines[pos], re.I):
92 auth = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
93 authname, authemail = name_email(auth)
94 lasthdr = pos + 1
95 continue
96 # check for a "Date:" line
97 if re.match('\s*date:\s+', descr_lines[pos], re.I):
98 authdate = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
99 lasthdr = pos + 1
100 continue
101 if subject:
102 break
103 # get the subject
104 subject = descr_lines[pos]
105 lasthdr = pos + 1
99e73103
CM
106
107 # get the body
0543bc5f
TM
108 if lasthdr < end:
109 body = reduce(lambda x, y: x + '\n' + y, descr_lines[lasthdr:], '')
99e73103 110
0543bc5f 111 return (subject + body, authname, authemail, authdate)
99e73103 112
0d2cd1e4
CM
113def __parse_mail(filename = None):
114 """Parse the input file in a mail format and return (description,
115 authname, authemail, authdate)
116 """
117 if filename:
118 f = file(filename)
119 else:
120 f = sys.stdin
121
122 descr = authname = authemail = authdate = None
123
124 # parse the headers
6fe6b1bd
CM
125 while True:
126 line = f.readline()
127 if not line:
128 break
0d2cd1e4
CM
129 line = line.strip()
130 if re.match('from:\s+', line, re.I):
131 auth = re.findall('^.*?:\s+(.*)$', line)[0]
132 authname, authemail = name_email(auth)
133 elif re.match('date:\s+', line, re.I):
134 authdate = re.findall('^.*?:\s+(.*)$', line)[0]
135 elif re.match('subject:\s+', line, re.I):
136 descr = re.findall('^.*?:\s+(.*)$', line)[0]
137 elif line == '':
138 # end of headers
139 break
140
186e6b6b 141 # remove the '[*PATCH*]' expression in the subject
0d2cd1e4 142 if descr:
7c02f338
CM
143 descr = re.findall('^(\[[^\s]*[Pp][Aa][Tt][Cc][Hh].*?\])?\s*(.*)$',
144 descr)[0][1]
0d2cd1e4
CM
145 descr += '\n\n'
146 else:
147 raise CmdException, 'Subject: line not found'
148
149 # the rest of the patch description
6fe6b1bd
CM
150 while True:
151 line = f.readline()
152 if not line:
153 break
d4c43e19 154 if __end_descr(line):
0d2cd1e4
CM
155 break
156 else:
157 descr += line
158 descr.rstrip()
159
160 if filename:
161 f.close()
162
99e73103 163 # parse the description for author information
0543bc5f 164 descr, descr_authname, descr_authemail, descr_authdate = __parse_description(descr)
99e73103
CM
165 if descr_authname:
166 authname = descr_authname
167 if descr_authemail:
168 authemail = descr_authemail
0543bc5f
TM
169 if descr_authdate:
170 authdate = descr_authdate
99e73103 171
0d2cd1e4
CM
172 return (descr, authname, authemail, authdate)
173
174def __parse_patch(filename = None):
175 """Parse the input file and return (description, authname,
176 authemail, authdate)
177 """
178 if filename:
179 f = file(filename)
180 else:
181 f = sys.stdin
182
0d2cd1e4 183 descr = ''
6fe6b1bd
CM
184 while True:
185 line = f.readline()
186 if not line:
187 break
188
d4c43e19 189 if __end_descr(line):
0d2cd1e4
CM
190 break
191 else:
192 descr += line
193 descr.rstrip()
194
0d2cd1e4
CM
195 if filename:
196 f.close()
197
0543bc5f 198 descr, authname, authemail, authdate = __parse_description(descr)
99e73103
CM
199
200 # we don't yet have an agreed place for the creation date.
201 # Just return None
0543bc5f 202 return (descr, authname, authemail, authdate)
0d2cd1e4 203
b8a0986f 204def func(parser, options, args):
0d2cd1e4
CM
205 """Import a GNU diff file as a new patch
206 """
207 if len(args) > 1:
208 parser.error('incorrect number of arguments')
b8a0986f
CM
209
210 check_local_changes()
211 check_conflicts()
212 check_head_top_equal()
213
214 if len(args) == 1:
0d2cd1e4 215 filename = args[0]
5185abc1 216 else:
0d2cd1e4 217 filename = None
5185abc1
CM
218
219 if options.name:
0d2cd1e4 220 patch = options.name
5185abc1
CM
221 elif filename:
222 patch = os.path.basename(filename)
0d2cd1e4
CM
223 else:
224 raise CmdException, 'Unkown patch name'
225
226 # the defaults
227 message = author_name = author_email = author_date = committer_name = \
228 committer_email = None
229
230 if options.author:
231 options.authname, options.authemail = name_email(options.author)
232
233 if options.mail:
234 message, author_name, author_email, author_date = \
235 __parse_mail(filename)
236 else:
237 message, author_name, author_email, author_date = \
238 __parse_patch(filename)
239
95742cfc
PBG
240 # refresh_patch() will invoke the editor in this case, with correct
241 # patch content
9d15ccd8 242 if not message:
95742cfc 243 can_edit = False
9d15ccd8 244
0d2cd1e4
CM
245 # override the automatically parsed settings
246 if options.authname:
247 author_name = options.authname
248 if options.authemail:
249 author_email = options.authemail
250 if options.authdate:
251 author_date = options.authdate
252 if options.commname:
253 committer_name = options.commname
254 if options.commemail:
255 committer_email = options.commemail
256
95742cfc 257 crt_series.new_patch(patch, message = message, can_edit = False,
0d2cd1e4
CM
258 author_name = author_name,
259 author_email = author_email,
260 author_date = author_date,
261 committer_name = committer_name,
262 committer_email = committer_email)
263
264 print 'Importing patch %s...' % patch,
265 sys.stdout.flush()
266
35344f86 267 if options.base:
be3e6bd9 268 git.apply_patch(filename, git_id(options.base))
35344f86
CM
269 else:
270 git.apply_patch(filename)
271
6ad48e48
PBG
272 crt_series.refresh_patch(edit = options.edit,
273 show_patch = options.showpatch)
0d2cd1e4
CM
274
275 print 'done'
276 print_crt_patch()