154 def extract(ui, fileobj): |
154 def extract(ui, fileobj): |
155 '''extract patch from data read from fileobj. |
155 '''extract patch from data read from fileobj. |
156 |
156 |
157 patch can be a normal patch or contained in an email message. |
157 patch can be a normal patch or contained in an email message. |
158 |
158 |
159 return tuple (filename, message, user, date, branch, node, p1, p2). |
159 return a dictionnary. Standard keys are: |
160 Any item in the returned tuple can be None. If filename is None, |
160 - filename, |
|
161 - message, |
|
162 - user, |
|
163 - date, |
|
164 - branch, |
|
165 - node, |
|
166 - p1, |
|
167 - p2. |
|
168 Any item can be missing from the dictionary. If filename is mising, |
161 fileobj did not contain a patch. Caller must unlink filename when done.''' |
169 fileobj did not contain a patch. Caller must unlink filename when done.''' |
162 |
170 |
163 # attempt to detect the start of a patch |
171 # attempt to detect the start of a patch |
164 # (this heuristic is borrowed from quilt) |
172 # (this heuristic is borrowed from quilt) |
165 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' |
173 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' |
166 r'retrieving revision [0-9]+(\.[0-9]+)*$|' |
174 r'retrieving revision [0-9]+(\.[0-9]+)*$|' |
167 r'---[ \t].*?^\+\+\+[ \t]|' |
175 r'---[ \t].*?^\+\+\+[ \t]|' |
168 r'\*\*\*[ \t].*?^---[ \t])', re.MULTILINE|re.DOTALL) |
176 r'\*\*\*[ \t].*?^---[ \t])', re.MULTILINE|re.DOTALL) |
169 |
177 |
|
178 data = {} |
170 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') |
179 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') |
171 tmpfp = os.fdopen(fd, 'w') |
180 tmpfp = os.fdopen(fd, 'w') |
172 try: |
181 try: |
173 msg = email.Parser.Parser().parse(fileobj) |
182 msg = email.Parser.Parser().parse(fileobj) |
174 |
183 |
254 if subject and not message.startswith(subject): |
263 if subject and not message.startswith(subject): |
255 message = '%s\n%s' % (subject, message) |
264 message = '%s\n%s' % (subject, message) |
256 tmpfp.close() |
265 tmpfp.close() |
257 if not diffs_seen: |
266 if not diffs_seen: |
258 os.unlink(tmpname) |
267 os.unlink(tmpname) |
259 return None, message, user, date, branch, None, None, None |
268 data['message'] = message |
|
269 data['user'] = user |
|
270 data['date'] = date |
|
271 data['branch'] = branch |
|
272 return data |
260 |
273 |
261 if parents: |
274 if parents: |
262 p1 = parents.pop(0) |
275 p1 = parents.pop(0) |
263 else: |
276 else: |
264 p1 = None |
277 p1 = None |
266 if parents: |
279 if parents: |
267 p2 = parents.pop(0) |
280 p2 = parents.pop(0) |
268 else: |
281 else: |
269 p2 = None |
282 p2 = None |
270 |
283 |
271 return tmpname, message, user, date, branch, nodeid, p1, p2 |
284 data['filename'] = tmpname |
|
285 data['message'] = message |
|
286 data['user'] = user |
|
287 data['date'] = date |
|
288 data['branch'] = branch |
|
289 data['nodeid'] = nodeid |
|
290 data['p1'] = p1 |
|
291 data['p2'] = p2 |
|
292 return data |
272 |
293 |
273 class patchmeta(object): |
294 class patchmeta(object): |
274 """Patched file metadata |
295 """Patched file metadata |
275 |
296 |
276 'op' is the performed operation within ADD, DELETE, RENAME, MODIFY |
297 'op' is the performed operation within ADD, DELETE, RENAME, MODIFY |