--- a/mercurial/patch.py Sat Aug 12 12:47:18 2006 -0700
+++ b/mercurial/patch.py Sat Aug 12 13:16:48 2006 -0700
@@ -6,8 +6,92 @@
# of the GNU General Public License, incorporated herein by reference.
from demandload import demandload
+from i18n import gettext as _
demandload(globals(), "util")
-demandload(globals(), "os re shutil tempfile")
+demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
+
+def extract(ui, fileobj):
+ '''extract patch from data read from fileobj.
+
+ patch can be normal patch or contained in email message.
+
+ return tuple (filename, message, user, date). any item in returned
+ tuple can be None. if filename is None, fileobj did not contain
+ patch. caller must unlink filename when done.'''
+
+ # attempt to detect the start of a patch
+ # (this heuristic is borrowed from quilt)
+ diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
+ 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
+ '(---|\*\*\*)[ \t])', re.MULTILINE)
+
+ fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
+ tmpfp = os.fdopen(fd, 'w')
+ try:
+ hgpatch = False
+
+ msg = email.Parser.Parser().parse(fileobj)
+
+ message = msg['Subject']
+ user = msg['From']
+ # should try to parse msg['Date']
+ date = None
+
+ if message:
+ message = message.replace('\n\t', ' ')
+ ui.debug('Subject: %s\n' % message)
+ if user:
+ ui.debug('From: %s\n' % user)
+ diffs_seen = 0
+ ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
+
+ for part in msg.walk():
+ content_type = part.get_content_type()
+ ui.debug('Content-Type: %s\n' % content_type)
+ if content_type not in ok_types:
+ continue
+ payload = part.get_payload(decode=True)
+ m = diffre.search(payload)
+ if m:
+ ui.debug(_('found patch at byte %d\n') % m.start(0))
+ diffs_seen += 1
+ cfp = cStringIO.StringIO()
+ if message:
+ cfp.write(message)
+ cfp.write('\n')
+ for line in payload[:m.start(0)].splitlines():
+ if line.startswith('# HG changeset patch'):
+ ui.debug(_('patch generated by hg export\n'))
+ hgpatch = True
+ # drop earlier commit message content
+ cfp.seek(0)
+ cfp.truncate()
+ elif hgpatch:
+ if line.startswith('# User '):
+ user = line[7:]
+ ui.debug('From: %s\n' % user)
+ elif line.startswith("# Date "):
+ date = line[7:]
+ if not line.startswith('# '):
+ cfp.write(line)
+ cfp.write('\n')
+ message = cfp.getvalue()
+ if tmpfp:
+ tmpfp.write(payload)
+ if not payload.endswith('\n'):
+ tmpfp.write('\n')
+ elif not diffs_seen and message and content_type == 'text/plain':
+ message += '\n' + payload
+ except:
+ tmpfp.close()
+ os.unlink(tmpname)
+ raise
+
+ tmpfp.close()
+ if not diffs_seen:
+ os.unlink(tmpname)
+ return None, message, user, date
+ return tmpname, message, user, date
def readgitpatch(patchname):
"""extract git-style metadata about patches from <patchname>"""