mercurial/patch.py
changeset 2866 2893e51407a4
parent 2865 71e78f2ca5ae
child 2868 9a2a481ec3ea
equal deleted inserted replaced
2865:71e78f2ca5ae 2866: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"