mercurial/patch.py
author Matt Mackall <mpm@selenic.com>
Wed, 25 Oct 2006 18:29:54 -0500
changeset 3521 ba94e80e5540
parent 3473 0e68608bd11d
child 3554 da3ee7ca620f
permissions -rw-r--r--
Remove update -m, deprecated for 0.9.1
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     1
# patch.py - patch file parsing routines
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     2
#
2865
71e78f2ca5ae merge git patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2863
diff changeset
     3
# Copyright 2006 Brendan Cully <brendan@kublai.com>
71e78f2ca5ae merge git patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2863
diff changeset
     4
#
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     6
# of the GNU General Public License, incorporated herein by reference.
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     7
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     8
from demandload import demandload
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
     9
from i18n import gettext as _
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
    10
from node import *
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
    11
demandload(globals(), "base85 cmdutil mdiff util")
3378
1106e00e6847 Add popen2 demandload to patch.py, required by diffstat
Brendan Cully <brendan@kublai.com>
parents: 3374
diff changeset
    12
demandload(globals(), "cStringIO email.Parser errno os popen2 re shutil sha")
1106e00e6847 Add popen2 demandload to patch.py, required by diffstat
Brendan Cully <brendan@kublai.com>
parents: 3374
diff changeset
    13
demandload(globals(), "sys tempfile zlib")
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    14
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    15
# helper functions
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    16
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    17
def copyfile(src, dst, basedir=None):
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    18
    if not basedir:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    19
        basedir = os.getcwd()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    20
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    21
    abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    22
    if os.path.exists(absdst):
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    23
        raise util.Abort(_("cannot create %s: destination already exists") %
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    24
                         dst)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    25
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    26
    targetdir = os.path.dirname(absdst)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    27
    if not os.path.isdir(targetdir):
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    28
        os.makedirs(targetdir)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    29
    try:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    30
        shutil.copyfile(abssrc, absdst)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    31
        shutil.copymode(abssrc, absdst)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    32
    except shutil.Error, inst:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    33
        raise util.Abort(str(inst))
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    34
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    35
# public functions
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    36
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    37
def extract(ui, fileobj):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    38
    '''extract patch from data read from fileobj.
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    39
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    40
    patch can be normal patch or contained in email message.
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    41
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    42
    return tuple (filename, message, user, date). any item in returned
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    43
    tuple can be None.  if filename is None, fileobj did not contain
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    44
    patch. caller must unlink filename when done.'''
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    45
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    46
    # attempt to detect the start of a patch
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    47
    # (this heuristic is borrowed from quilt)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    48
    diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    49
                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    50
                        '(---|\*\*\*)[ \t])', re.MULTILINE)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    51
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    52
    fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    53
    tmpfp = os.fdopen(fd, 'w')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    54
    try:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    55
        hgpatch = False
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    56
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    57
        msg = email.Parser.Parser().parse(fileobj)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    58
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    59
        message = msg['Subject']
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    60
        user = msg['From']
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    61
        # should try to parse msg['Date']
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    62
        date = None
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    63
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    64
        if message:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    65
            message = message.replace('\n\t', ' ')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    66
            ui.debug('Subject: %s\n' % message)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    67
        if user:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    68
            ui.debug('From: %s\n' % user)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    69
        diffs_seen = 0
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    70
        ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    71
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    72
        for part in msg.walk():
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    73
            content_type = part.get_content_type()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    74
            ui.debug('Content-Type: %s\n' % content_type)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    75
            if content_type not in ok_types:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    76
                continue
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    77
            payload = part.get_payload(decode=True)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    78
            m = diffre.search(payload)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    79
            if m:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    80
                ui.debug(_('found patch at byte %d\n') % m.start(0))
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    81
                diffs_seen += 1
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    82
                cfp = cStringIO.StringIO()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    83
                if message:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    84
                    cfp.write(message)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    85
                    cfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    86
                for line in payload[:m.start(0)].splitlines():
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    87
                    if line.startswith('# HG changeset patch'):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    88
                        ui.debug(_('patch generated by hg export\n'))
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    89
                        hgpatch = True
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    90
                        # drop earlier commit message content
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    91
                        cfp.seek(0)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    92
                        cfp.truncate()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    93
                    elif hgpatch:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    94
                        if line.startswith('# User '):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    95
                            user = line[7:]
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    96
                            ui.debug('From: %s\n' % user)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    97
                        elif line.startswith("# Date "):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    98
                            date = line[7:]
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    99
                    if not line.startswith('# '):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   100
                        cfp.write(line)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   101
                        cfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   102
                message = cfp.getvalue()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   103
                if tmpfp:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   104
                    tmpfp.write(payload)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   105
                    if not payload.endswith('\n'):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   106
                        tmpfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   107
            elif not diffs_seen and message and content_type == 'text/plain':
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   108
                message += '\n' + payload
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   109
    except:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   110
        tmpfp.close()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   111
        os.unlink(tmpname)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   112
        raise
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   113
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   114
    tmpfp.close()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   115
    if not diffs_seen:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   116
        os.unlink(tmpname)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   117
        return None, message, user, date
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   118
    return tmpname, message, user, date
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   119
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   120
def readgitpatch(patchname):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   121
    """extract git-style metadata about patches from <patchname>"""
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   122
    class gitpatch:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   123
        "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   124
        def __init__(self, path):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   125
            self.path = path
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   126
            self.oldpath = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   127
            self.mode = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   128
            self.op = 'MODIFY'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   129
            self.copymod = False
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   130
            self.lineno = 0
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   131
            self.binary = False
3223
53e843840349 Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3199
diff changeset
   132
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   133
    # Filter patch for git information
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   134
    gitre = re.compile('diff --git a/(.*) b/(.*)')
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   135
    pf = file(patchname)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   136
    gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   137
    gitpatches = []
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   138
    # Can have a git patch with only metadata, causing patch to complain
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   139
    dopatch = False
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   140
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   141
    lineno = 0
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   142
    for line in pf:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   143
        lineno += 1
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   144
        if line.startswith('diff --git'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   145
            m = gitre.match(line)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   146
            if m:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   147
                if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   148
                    gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   149
                src, dst = m.group(1,2)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   150
                gp = gitpatch(dst)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   151
                gp.lineno = lineno
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   152
        elif gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   153
            if line.startswith('--- '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   154
                if gp.op in ('COPY', 'RENAME'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   155
                    gp.copymod = True
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   156
                    dopatch = 'filter'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   157
                gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   158
                gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   159
                if not dopatch:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   160
                    dopatch = True
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   161
                continue
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   162
            if line.startswith('rename from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   163
                gp.op = 'RENAME'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   164
                gp.oldpath = line[12:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   165
            elif line.startswith('rename to '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   166
                gp.path = line[10:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   167
            elif line.startswith('copy from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   168
                gp.op = 'COPY'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   169
                gp.oldpath = line[10:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   170
            elif line.startswith('copy to '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   171
                gp.path = line[8:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   172
            elif line.startswith('deleted file'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   173
                gp.op = 'DELETE'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   174
            elif line.startswith('new file mode '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   175
                gp.op = 'ADD'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   176
                gp.mode = int(line.rstrip()[-3:], 8)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   177
            elif line.startswith('new mode '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   178
                gp.mode = int(line.rstrip()[-3:], 8)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   179
            elif line.startswith('GIT binary patch'):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   180
                if not dopatch:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   181
                    dopatch = 'binary'
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   182
                gp.binary = True
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   183
    if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   184
        gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   185
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   186
    if not gitpatches:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   187
        dopatch = True
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   188
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   189
    return (dopatch, gitpatches)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   190
3055
efd26ceedafb Fix git patch application when cwd != repo.root
Brendan Cully <brendan@kublai.com>
parents: 2952
diff changeset
   191
def dogitpatch(patchname, gitpatches, cwd=None):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   192
    """Preprocess git patch so that vanilla patch can handle it"""
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   193
    def extractbin(fp):
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   194
        line = fp.readline().rstrip()
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   195
        while line and not line.startswith('literal '):
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   196
            line = fp.readline().rstrip()
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   197
        if not line:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   198
            return
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   199
        size = int(line[8:])
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   200
        dec = []
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   201
        line = fp.readline().rstrip()
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   202
        while line:
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   203
            l = line[0]
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   204
            if l <= 'Z' and l >= 'A':
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   205
                l = ord(l) - ord('A') + 1
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   206
            else:
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   207
                l = ord(l) - ord('a') + 27
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   208
            dec.append(base85.b85decode(line[1:])[:l])
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   209
            line = fp.readline().rstrip()
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   210
        text = zlib.decompress(''.join(dec))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   211
        if len(text) != size:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   212
            raise util.Abort(_('binary patch is %d bytes, not %d') %
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   213
                             (len(text), size))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   214
        return text
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   215
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   216
    pf = file(patchname)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   217
    pfline = 1
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   218
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   219
    fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   220
    tmpfp = os.fdopen(fd, 'w')
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   221
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   222
    try:
3473
0e68608bd11d use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3465
diff changeset
   223
        for i in xrange(len(gitpatches)):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   224
            p = gitpatches[i]
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   225
            if not p.copymod and not p.binary:
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   226
                continue
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   227
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   228
            # rewrite patch hunk
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   229
            while pfline < p.lineno:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   230
                tmpfp.write(pf.readline())
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   231
                pfline += 1
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   232
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   233
            if p.binary:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   234
                text = extractbin(pf)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   235
                if not text:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   236
                    raise util.Abort(_('binary patch extraction failed'))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   237
                if not cwd:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   238
                    cwd = os.getcwd()
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   239
                absdst = os.path.join(cwd, p.path)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   240
                basedir = os.path.dirname(absdst)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   241
                if not os.path.isdir(basedir):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   242
                    os.makedirs(basedir)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   243
                out = file(absdst, 'wb')
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   244
                out.write(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   245
                out.close()
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   246
            elif p.copymod:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   247
                copyfile(p.oldpath, p.path, basedir=cwd)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   248
                tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   249
                line = pf.readline()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   250
                pfline += 1
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   251
                while not line.startswith('--- a/'):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   252
                    tmpfp.write(line)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   253
                    line = pf.readline()
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   254
                    pfline += 1
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   255
                tmpfp.write('--- a/%s\n' % p.path)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   256
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   257
        line = pf.readline()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   258
        while line:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   259
            tmpfp.write(line)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   260
            line = pf.readline()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   261
    except:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   262
        tmpfp.close()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   263
        os.unlink(patchname)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   264
        raise
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   265
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   266
    tmpfp.close()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   267
    return patchname
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   268
3465
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   269
def patch(patchname, ui, strip=1, cwd=None, files={}):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   270
    """apply the patch <patchname> to the working directory.
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   271
    a list of patched files is returned"""
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   272
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   273
    # helper function
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   274
    def __patch(patchname):
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   275
        """patch and updates the files and fuzz variables"""
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   276
        fuzz = False
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   277
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   278
        patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''),
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   279
                                    'patch')
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   280
        args = []
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   281
        if cwd:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   282
            args.append('-d %s' % util.shellquote(cwd))
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   283
        fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   284
                                           util.shellquote(patchname)))
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   285
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   286
        for line in fp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   287
            line = line.rstrip()
2919
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   288
            ui.note(line + '\n')
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   289
            if line.startswith('patching file '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   290
                pf = util.parse_patch_output(line)
2919
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   291
                printed_file = False
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   292
                files.setdefault(pf, (None, None))
2919
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   293
            elif line.find('with fuzz') >= 0:
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   294
                fuzz = True
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   295
                if not printed_file:
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   296
                    ui.warn(pf + '\n')
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   297
                    printed_file = True
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   298
                ui.warn(line + '\n')
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   299
            elif line.find('saving rejects to file') >= 0:
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   300
                ui.warn(line + '\n')
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   301
            elif line.find('FAILED') >= 0:
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   302
                if not printed_file:
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   303
                    ui.warn(pf + '\n')
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   304
                    printed_file = True
b70740aefa4d Unify mq and hg patch invocation.
Brendan Cully <brendan@kublai.com>
parents: 2907
diff changeset
   305
                ui.warn(line + '\n')
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   306
        code = fp.close()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   307
        if code:
2868
9a2a481ec3ea util: qualify name properly.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2866
diff changeset
   308
            raise util.Abort(_("patch command failed: %s") %
9a2a481ec3ea util: qualify name properly.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2866
diff changeset
   309
                             util.explain_exit(code)[0])
3465
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   310
        return fuzz
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   311
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   312
    (dopatch, gitpatches) = readgitpatch(patchname)
3465
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   313
    for gp in gitpatches:
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   314
        files[gp.path] = (gp.op, gp)
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   315
3465
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   316
    fuzz = False
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   317
    if dopatch:
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   318
        if dopatch in ('filter', 'binary'):
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   319
            patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   320
        try:
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   321
            if dopatch != 'binary':
3465
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   322
                fuzz = __patch(patchname)
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   323
        finally:
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   324
            if dopatch == 'filter':
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
   325
                os.unlink(patchname)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   326
3465
2d35a8d2b32d patch: return list of modified files even when an exception is raised
Brendan Cully <brendan@kublai.com>
parents: 3387
diff changeset
   327
    return fuzz
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   328
2888
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   329
def diffopts(ui, opts={}):
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   330
    return mdiff.diffopts(
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   331
        text=opts.get('text'),
2921
addb58e3b41c redo merge with mpm.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2919 2888
diff changeset
   332
        git=(opts.get('git') or
addb58e3b41c redo merge with mpm.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2919 2888
diff changeset
   333
                  ui.configbool('diff', 'git', None)),
3199
096f1c73cdc3 Add -D/--nodates options to hg diff/export that removes dates from diff headers
Stephen Darnell <stephen@darnell.plus.com>
parents: 3159
diff changeset
   334
        nodates=(opts.get('nodates') or
096f1c73cdc3 Add -D/--nodates options to hg diff/export that removes dates from diff headers
Stephen Darnell <stephen@darnell.plus.com>
parents: 3159
diff changeset
   335
                  ui.configbool('diff', 'nodates', None)),
2888
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   336
        showfunc=(opts.get('show_function') or
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   337
                  ui.configbool('diff', 'showfunc', None)),
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   338
        ignorews=(opts.get('ignore_all_space') or
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   339
                  ui.configbool('diff', 'ignorews', None)),
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   340
        ignorewsamount=(opts.get('ignore_space_change') or
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   341
                        ui.configbool('diff', 'ignorewsamount', None)),
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   342
        ignoreblanklines=(opts.get('ignore_blank_lines') or
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   343
                          ui.configbool('diff', 'ignoreblanklines', None)))
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2881
diff changeset
   344
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   345
def updatedir(ui, repo, patches, wlock=None):
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   346
    '''Update dirstate after patch application according to metadata'''
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   347
    if not patches:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   348
        return
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   349
    copies = []
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   350
    removes = []
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   351
    cfiles = patches.keys()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   352
    cwd = repo.getcwd()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   353
    if cwd:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   354
        cfiles = [util.pathto(cwd, f) for f in patches.keys()]
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   355
    for f in patches:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   356
        ctype, gp = patches[f]
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   357
        if ctype == 'RENAME':
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   358
            copies.append((gp.oldpath, gp.path, gp.copymod))
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   359
            removes.append(gp.oldpath)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   360
        elif ctype == 'COPY':
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   361
            copies.append((gp.oldpath, gp.path, gp.copymod))
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   362
        elif ctype == 'DELETE':
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   363
            removes.append(gp.path)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   364
    for src, dst, after in copies:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   365
        if not after:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   366
            copyfile(src, dst, repo.root)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   367
        repo.copy(src, dst, wlock=wlock)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   368
    if removes:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   369
        repo.remove(removes, True, wlock=wlock)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   370
    for f in patches:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   371
        ctype, gp = patches[f]
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   372
        if gp and gp.mode:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   373
            x = gp.mode & 0100 != 0
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   374
            dst = os.path.join(repo.root, gp.path)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   375
            util.set_exec(dst, x)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   376
    cmdutil.addremove(repo, cfiles, wlock=wlock)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   377
    files = patches.keys()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   378
    files.extend([r for r in removes if r not in files])
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   379
    files.sort()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   380
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   381
    return files
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
   382
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   383
def b85diff(fp, to, tn):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   384
    '''print base85-encoded binary diff'''
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   385
    def gitindex(text):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   386
        if not text:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   387
            return '0' * 40
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   388
        l = len(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   389
        s = sha.new('blob %d\0' % l)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   390
        s.update(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   391
        return s.hexdigest()
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   392
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   393
    def fmtline(line):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   394
        l = len(line)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   395
        if l <= 26:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   396
            l = chr(ord('A') + l - 1)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   397
        else:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   398
            l = chr(l - 26 + ord('a') - 1)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   399
        return '%c%s\n' % (l, base85.b85encode(line, True))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   400
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   401
    def chunk(text, csize=52):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   402
        l = len(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   403
        i = 0
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   404
        while i < l:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   405
            yield text[i:i+csize]
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   406
            i += csize
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   407
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   408
    # TODO: deltas
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   409
    l = len(tn)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   410
    fp.write('index %s..%s\nGIT binary patch\nliteral %s\n' %
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   411
             (gitindex(to), gitindex(tn), len(tn)))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   412
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   413
    tn = ''.join([fmtline(l) for l in chunk(zlib.compress(tn))])
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   414
    fp.write(tn)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   415
    fp.write('\n')
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   416
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   417
def diff(repo, node1=None, node2=None, files=None, match=util.always,
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   418
         fp=None, changes=None, opts=None):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   419
    '''print diff of changes to files between two nodes, or node and
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   420
    working directory.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   421
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   422
    if node1 is None, use first dirstate parent instead.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   423
    if node2 is None, compare node1 with working directory.'''
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   424
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   425
    if opts is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   426
        opts = mdiff.defaultopts
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   427
    if fp is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   428
        fp = repo.ui
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   429
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   430
    if not node1:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   431
        node1 = repo.dirstate.parents()[0]
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   432
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   433
    clcache = {}
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   434
    def getchangelog(n):
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   435
        if n not in clcache:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   436
            clcache[n] = repo.changelog.read(n)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   437
        return clcache[n]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   438
    mcache = {}
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   439
    def getmanifest(n):
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   440
        if n not in mcache:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   441
            mcache[n] = repo.manifest.read(n)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   442
        return mcache[n]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   443
    fcache = {}
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   444
    def getfile(f):
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   445
        if f not in fcache:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   446
            fcache[f] = repo.file(f)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   447
        return fcache[f]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   448
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   449
    # reading the data for node1 early allows it to play nicely
2875
3d6efcbbd1c9 remove localrepository.changes.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2874
diff changeset
   450
    # with repo.status and the revlog cache.
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   451
    change = getchangelog(node1)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   452
    mmap = getmanifest(change[0])
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   453
    date1 = util.datestr(change[2])
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   454
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   455
    if not changes:
2875
3d6efcbbd1c9 remove localrepository.changes.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2874
diff changeset
   456
        changes = repo.status(node1, node2, files, match=match)[:5]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   457
    modified, added, removed, deleted, unknown = changes
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   458
    if files:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   459
        def filterfiles(filters):
2881
eab07a7b7491 fix patch.patch.filterfiles.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2875
diff changeset
   460
            l = [x for x in filters if x in files]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   461
2881
eab07a7b7491 fix patch.patch.filterfiles.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2875
diff changeset
   462
            for t in files:
eab07a7b7491 fix patch.patch.filterfiles.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2875
diff changeset
   463
                if not t.endswith("/"):
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   464
                    t += "/"
2881
eab07a7b7491 fix patch.patch.filterfiles.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2875
diff changeset
   465
                l += [x for x in filters if x.startswith(t)]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   466
            return l
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   467
2881
eab07a7b7491 fix patch.patch.filterfiles.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2875
diff changeset
   468
        modified, added, removed = map(filterfiles, (modified, added, removed))
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   469
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   470
    if not modified and not added and not removed:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   471
        return
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   472
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   473
    def renamedbetween(f, n1, n2):
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   474
        r1, r2 = map(repo.changelog.rev, (n1, n2))
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   475
        src = None
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   476
        while r2 > r1:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   477
            cl = getchangelog(n2)[0]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   478
            m = getmanifest(cl)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   479
            try:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   480
                src = getfile(f).renamed(m[f])
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   481
            except KeyError:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   482
                return None
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   483
            if src:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   484
                f = src[0]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   485
            n2 = repo.changelog.parents(n2)[0]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   486
            r2 = repo.changelog.rev(n2)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   487
        return src
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   488
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   489
    if node2:
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   490
        change = getchangelog(node2)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   491
        mmap2 = getmanifest(change[0])
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   492
        _date2 = util.datestr(change[2])
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   493
        def date2(f):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   494
            return _date2
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   495
        def read(f):
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   496
            return getfile(f).read(mmap2[f])
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   497
        def renamed(f):
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   498
            return renamedbetween(f, node1, node2)
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   499
    else:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   500
        tz = util.makedate()[1]
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   501
        _date2 = util.datestr()
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   502
        def date2(f):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   503
            try:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   504
                return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   505
            except OSError, err:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   506
                if err.errno != errno.ENOENT: raise
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   507
                return _date2
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   508
        def read(f):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   509
            return repo.wread(f)
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   510
        def renamed(f):
3159
e43fd1623fe1 fix users of dirstate.copies broken by b1f10d3223c1
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3096
diff changeset
   511
            src = repo.dirstate.copied(f)
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   512
            parent = repo.dirstate.parents()[0]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   513
            if src:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   514
                f = src[0]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   515
            of = renamedbetween(f, node1, parent)
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   516
            if of:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   517
                return of
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   518
            elif src:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   519
                cl = getchangelog(parent)[0]
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   520
                return (src, getmanifest(cl)[src])
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   521
            else:
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   522
                return None
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   523
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   524
    if repo.ui.quiet:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   525
        r = None
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   526
    else:
3387
2065789f6a3e use short hashes with diff -v
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3378
diff changeset
   527
        hexfunc = repo.ui.debugflag and hex or short
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   528
        r = [hexfunc(node) for node in [node1, node2] if node]
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   529
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   530
    if opts.git:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   531
        copied = {}
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   532
        for f in added:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   533
            src = renamed(f)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   534
            if src:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   535
                copied[f] = src
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   536
        srcs = [x[1][0] for x in copied.items()]
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   537
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   538
    all = modified + added + removed
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   539
    all.sort()
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   540
    for f in all:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   541
        to = None
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   542
        tn = None
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   543
        dodiff = True
3329
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3231
diff changeset
   544
        header = []
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   545
        if f in mmap:
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   546
            to = getfile(f).read(mmap[f])
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   547
        if f not in removed:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   548
            tn = read(f)
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   549
        if opts.git:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   550
            def gitmode(x):
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   551
                return x and '100755' or '100644'
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   552
            def addmodehdr(header, omode, nmode):
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   553
                if omode != nmode:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   554
                    header.append('old mode %s\n' % omode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   555
                    header.append('new mode %s\n' % nmode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   556
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   557
            a, b = f, f
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   558
            if f in added:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   559
                if node2:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   560
                    mode = gitmode(mmap2.execf(f))
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   561
                else:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   562
                    mode = gitmode(util.is_exec(repo.wjoin(f), None))
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   563
                if f in copied:
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   564
                    a, arev = copied[f]
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   565
                    omode = gitmode(mmap.execf(a))
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   566
                    addmodehdr(header, omode, mode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   567
                    op = a in removed and 'rename' or 'copy'
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   568
                    header.append('%s from %s\n' % (op, a))
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   569
                    header.append('%s to %s\n' % (op, f))
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
   570
                    to = getfile(a).read(arev)
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   571
                else:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   572
                    header.append('new file mode %s\n' % mode)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   573
                    if util.binary(tn):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   574
                        dodiff = 'binary'
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   575
            elif f in removed:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   576
                if f in srcs:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   577
                    dodiff = False
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   578
                else:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   579
                    mode = gitmode(mmap.execf(f))
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   580
                    header.append('deleted file mode %s\n' % mode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   581
            else:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   582
                omode = gitmode(mmap.execf(f))
3066
035fd2029575 git --diff: fix traceback when getting mode change
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3057
diff changeset
   583
                if node2:
035fd2029575 git --diff: fix traceback when getting mode change
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3057
diff changeset
   584
                    nmode = gitmode(mmap2.execf(f))
035fd2029575 git --diff: fix traceback when getting mode change
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3057
diff changeset
   585
                else:
035fd2029575 git --diff: fix traceback when getting mode change
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3057
diff changeset
   586
                    nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   587
                addmodehdr(header, omode, nmode)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   588
                if util.binary(to) or util.binary(tn):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   589
                    dodiff = 'binary'
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   590
            r = None
3329
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3231
diff changeset
   591
            header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   592
        if dodiff == 'binary':
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   593
            fp.write(''.join(header))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   594
            b85diff(fp, to, tn)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   595
        elif dodiff:
3329
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3231
diff changeset
   596
            text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3231
diff changeset
   597
            if text or len(header) > 1:
2907
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2881
diff changeset
   598
                fp.write(''.join(header))
3329
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3231
diff changeset
   599
            fp.write(text)
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   600
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   601
def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   602
           opts=None):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   603
    '''export changesets as hg patches.'''
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   604
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   605
    total = len(revs)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   606
    revwidth = max(map(len, revs))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   607
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   608
    def single(node, seqno, fp):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   609
        parents = [p for p in repo.changelog.parents(node) if p != nullid]
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   610
        if switch_parent:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   611
            parents.reverse()
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   612
        prev = (parents and parents[0]) or nullid
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   613
        change = repo.changelog.read(node)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   614
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   615
        if not fp:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   616
            fp = cmdutil.make_file(repo, template, node, total=total,
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   617
                                   seqno=seqno, revwidth=revwidth)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   618
        if fp not in (sys.stdout, repo.ui):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   619
            repo.ui.note("%s\n" % fp.name)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   620
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   621
        fp.write("# HG changeset patch\n")
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   622
        fp.write("# User %s\n" % change[1])
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   623
        fp.write("# Date %d %d\n" % change[2])
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   624
        fp.write("# Node ID %s\n" % hex(node))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   625
        fp.write("# Parent  %s\n" % hex(prev))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   626
        if len(parents) > 1:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   627
            fp.write("# Parent  %s\n" % hex(parents[1]))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   628
        fp.write(change[4].rstrip())
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   629
        fp.write("\n\n")
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   630
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   631
        diff(repo, prev, node, fp=fp, opts=opts)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   632
        if fp not in (sys.stdout, repo.ui):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   633
            fp.close()
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   634
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   635
    for seqno, cset in enumerate(revs):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
   636
        single(cset, seqno, fp)
3096
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   637
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   638
def diffstat(patchlines):
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   639
    fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   640
    try:
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   641
        p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   642
        try:
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   643
            for line in patchlines: print >> p.tochild, line
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   644
            p.tochild.close()
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   645
            if p.wait(): return
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   646
            fp = os.fdopen(fd, 'r')
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   647
            stat = []
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   648
            for line in fp: stat.append(line.lstrip())
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   649
            last = stat.pop()
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   650
            stat.insert(0, last)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   651
            stat = ''.join(stat)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   652
            if stat.startswith('0 files'): raise ValueError
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   653
            return stat
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   654
        except: raise
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   655
    finally:
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   656
        try: os.unlink(name)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3066
diff changeset
   657
        except: pass