comparison mercurial/patch.py @ 2865:2893e51407a4

commands.import: refactor patch parsing into patch.extract.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Sat, 12 Aug 2006 13:16:48 -0700
parents 71e78f2ca5ae
children 9a2a481ec3ea
comparison
equal deleted inserted replaced
2864:71e78f2ca5ae 2865:2893e51407a4
4 # 4 #
5 # This software may be used and distributed according to the terms 5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference. 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 from demandload import demandload 8 from demandload import demandload
9 from i18n import gettext as _
9 demandload(globals(), "util") 10 demandload(globals(), "util")
10 demandload(globals(), "os re shutil tempfile") 11 demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
12
13 def extract(ui, fileobj):
14 '''extract patch from data read from fileobj.
15
16 patch can be normal patch or contained in email message.
17
18 return tuple (filename, message, user, date). any item in returned
19 tuple can be None. if filename is None, fileobj did not contain
20 patch. caller must unlink filename when done.'''
21
22 # attempt to detect the start of a patch
23 # (this heuristic is borrowed from quilt)
24 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
25 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
26 '(---|\*\*\*)[ \t])', re.MULTILINE)
27
28 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
29 tmpfp = os.fdopen(fd, 'w')
30 try:
31 hgpatch = False
32
33 msg = email.Parser.Parser().parse(fileobj)
34
35 message = msg['Subject']
36 user = msg['From']
37 # should try to parse msg['Date']
38 date = None
39
40 if message:
41 message = message.replace('\n\t', ' ')
42 ui.debug('Subject: %s\n' % message)
43 if user:
44 ui.debug('From: %s\n' % user)
45 diffs_seen = 0
46 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
47
48 for part in msg.walk():
49 content_type = part.get_content_type()
50 ui.debug('Content-Type: %s\n' % content_type)
51 if content_type not in ok_types:
52 continue
53 payload = part.get_payload(decode=True)
54 m = diffre.search(payload)
55 if m:
56 ui.debug(_('found patch at byte %d\n') % m.start(0))
57 diffs_seen += 1
58 cfp = cStringIO.StringIO()
59 if message:
60 cfp.write(message)
61 cfp.write('\n')
62 for line in payload[:m.start(0)].splitlines():
63 if line.startswith('# HG changeset patch'):
64 ui.debug(_('patch generated by hg export\n'))
65 hgpatch = True
66 # drop earlier commit message content
67 cfp.seek(0)
68 cfp.truncate()
69 elif hgpatch:
70 if line.startswith('# User '):
71 user = line[7:]
72 ui.debug('From: %s\n' % user)
73 elif line.startswith("# Date "):
74 date = line[7:]
75 if not line.startswith('# '):
76 cfp.write(line)
77 cfp.write('\n')
78 message = cfp.getvalue()
79 if tmpfp:
80 tmpfp.write(payload)
81 if not payload.endswith('\n'):
82 tmpfp.write('\n')
83 elif not diffs_seen and message and content_type == 'text/plain':
84 message += '\n' + payload
85 except:
86 tmpfp.close()
87 os.unlink(tmpname)
88 raise
89
90 tmpfp.close()
91 if not diffs_seen:
92 os.unlink(tmpname)
93 return None, message, user, date
94 return tmpname, message, user, date
11 95
12 def readgitpatch(patchname): 96 def readgitpatch(patchname):
13 """extract git-style metadata about patches from <patchname>""" 97 """extract git-style metadata about patches from <patchname>"""
14 class gitpatch: 98 class gitpatch:
15 "op is one of ADD, DELETE, RENAME, MODIFY or COPY" 99 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"