Add a merged upstream test for pull and push
[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
388f63b6 31can be overridden with the '--name' option. The patch can either be a
b8a0986f
CM
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 81 lasthdr = 0
99e73103
CM
82 end = len(descr_lines)
83
0543bc5f 84 # Parse the patch header
61dabd0e 85 for pos in range(0, end):
0543bc5f
TM
86 if not descr_lines[pos]:
87 continue
88 # check for a "From|Author:" line
89 if re.match('\s*(?:from|author):\s+', descr_lines[pos], re.I):
90 auth = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
91 authname, authemail = name_email(auth)
92 lasthdr = pos + 1
93 continue
94 # check for a "Date:" line
95 if re.match('\s*date:\s+', descr_lines[pos], re.I):
96 authdate = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
97 lasthdr = pos + 1
98 continue
99 if subject:
100 break
101 # get the subject
102 subject = descr_lines[pos]
103 lasthdr = pos + 1
99e73103
CM
104
105 # get the body
0543bc5f
TM
106 if lasthdr < end:
107 body = reduce(lambda x, y: x + '\n' + y, descr_lines[lasthdr:], '')
99e73103 108
0543bc5f 109 return (subject + body, authname, authemail, authdate)
99e73103 110
0d2cd1e4
CM
111def __parse_mail(filename = None):
112 """Parse the input file in a mail format and return (description,
113 authname, authemail, authdate)
114 """
115 if filename:
116 f = file(filename)
117 else:
118 f = sys.stdin
119
120 descr = authname = authemail = authdate = None
121
122 # parse the headers
6fe6b1bd
CM
123 while True:
124 line = f.readline()
125 if not line:
126 break
0d2cd1e4
CM
127 line = line.strip()
128 if re.match('from:\s+', line, re.I):
129 auth = re.findall('^.*?:\s+(.*)$', line)[0]
130 authname, authemail = name_email(auth)
131 elif re.match('date:\s+', line, re.I):
132 authdate = re.findall('^.*?:\s+(.*)$', line)[0]
133 elif re.match('subject:\s+', line, re.I):
134 descr = re.findall('^.*?:\s+(.*)$', line)[0]
135 elif line == '':
136 # end of headers
137 break
138
186e6b6b 139 # remove the '[*PATCH*]' expression in the subject
0d2cd1e4 140 if descr:
7c02f338
CM
141 descr = re.findall('^(\[[^\s]*[Pp][Aa][Tt][Cc][Hh].*?\])?\s*(.*)$',
142 descr)[0][1]
0d2cd1e4
CM
143 descr += '\n\n'
144 else:
145 raise CmdException, 'Subject: line not found'
146
147 # the rest of the patch description
6fe6b1bd
CM
148 while True:
149 line = f.readline()
150 if not line:
151 break
d4c43e19 152 if __end_descr(line):
0d2cd1e4
CM
153 break
154 else:
155 descr += line
156 descr.rstrip()
157
158 if filename:
159 f.close()
160
99e73103 161 # parse the description for author information
0543bc5f 162 descr, descr_authname, descr_authemail, descr_authdate = __parse_description(descr)
99e73103
CM
163 if descr_authname:
164 authname = descr_authname
165 if descr_authemail:
166 authemail = descr_authemail
0543bc5f
TM
167 if descr_authdate:
168 authdate = descr_authdate
99e73103 169
0d2cd1e4
CM
170 return (descr, authname, authemail, authdate)
171
172def __parse_patch(filename = None):
173 """Parse the input file and return (description, authname,
174 authemail, authdate)
175 """
176 if filename:
177 f = file(filename)
178 else:
179 f = sys.stdin
180
0d2cd1e4 181 descr = ''
6fe6b1bd
CM
182 while True:
183 line = f.readline()
184 if not line:
185 break
186
d4c43e19 187 if __end_descr(line):
0d2cd1e4
CM
188 break
189 else:
190 descr += line
191 descr.rstrip()
192
0d2cd1e4
CM
193 if filename:
194 f.close()
195
0543bc5f 196 descr, authname, authemail, authdate = __parse_description(descr)
99e73103
CM
197
198 # we don't yet have an agreed place for the creation date.
199 # Just return None
0543bc5f 200 return (descr, authname, authemail, authdate)
0d2cd1e4 201
b8a0986f 202def func(parser, options, args):
0d2cd1e4
CM
203 """Import a GNU diff file as a new patch
204 """
205 if len(args) > 1:
206 parser.error('incorrect number of arguments')
b8a0986f
CM
207
208 check_local_changes()
209 check_conflicts()
210 check_head_top_equal()
211
212 if len(args) == 1:
0d2cd1e4 213 filename = args[0]
5185abc1 214 else:
0d2cd1e4 215 filename = None
5185abc1
CM
216
217 if options.name:
0d2cd1e4 218 patch = options.name
5185abc1
CM
219 elif filename:
220 patch = os.path.basename(filename)
0d2cd1e4 221 else:
388f63b6 222 raise CmdException, 'Unknown patch name'
0d2cd1e4
CM
223
224 # the defaults
225 message = author_name = author_email = author_date = committer_name = \
226 committer_email = None
227
228 if options.author:
229 options.authname, options.authemail = name_email(options.author)
230
231 if options.mail:
232 message, author_name, author_email, author_date = \
233 __parse_mail(filename)
234 else:
235 message, author_name, author_email, author_date = \
236 __parse_patch(filename)
237
95742cfc
PBG
238 # refresh_patch() will invoke the editor in this case, with correct
239 # patch content
9d15ccd8 240 if not message:
95742cfc 241 can_edit = False
9d15ccd8 242
0d2cd1e4
CM
243 # override the automatically parsed settings
244 if options.authname:
245 author_name = options.authname
246 if options.authemail:
247 author_email = options.authemail
248 if options.authdate:
249 author_date = options.authdate
250 if options.commname:
251 committer_name = options.commname
252 if options.commemail:
253 committer_email = options.commemail
254
95742cfc 255 crt_series.new_patch(patch, message = message, can_edit = False,
0d2cd1e4
CM
256 author_name = author_name,
257 author_email = author_email,
258 author_date = author_date,
259 committer_name = committer_name,
260 committer_email = committer_email)
261
262 print 'Importing patch %s...' % patch,
263 sys.stdout.flush()
264
35344f86 265 if options.base:
be3e6bd9 266 git.apply_patch(filename, git_id(options.base))
35344f86
CM
267 else:
268 git.apply_patch(filename)
269
6ad48e48
PBG
270 crt_series.refresh_patch(edit = options.edit,
271 show_patch = options.showpatch)
0d2cd1e4
CM
272
273 print 'done'
274 print_crt_patch()