mercurial/patch.py
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
Sat, 06 Oct 2007 15:30:15 -0300
changeset 5403 477136fa6571
parent 5261 15a108ad7adb
child 5418 9b469bdb1ce1
permissions -rw-r--r--
Always copy the necessary files before applying a git patch This patch removes the "copymod" attribute from the gitpatch class. AFAICS, that attribute was only used to delay the copying of renamed/copied files if there are no other changes to the target, but in this case, if there are changes to the source, we'll end up copying the wrong version. This should fix issue762.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2860
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
#
2864
71e78f2ca5ae merge git patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2862
diff changeset
     3
# Copyright 2006 Brendan Cully <brendan@kublai.com>
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
     4
# Copyright 2007 Chris Mason <chris.mason@oracle.com>
2864
71e78f2ca5ae merge git patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2862
diff changeset
     5
#
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     6
# 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
     7
# 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
     8
3893
6b4127c7d52a Simplify i18n imports
Matt Mackall <mpm@selenic.com>
parents: 3886
diff changeset
     9
from i18n import _
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
    10
from node import *
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
    11
import base85, cmdutil, mdiff, util, context, revlog, diffhelpers
3963
ba45041827a2 remove various unused import
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3902
diff changeset
    12
import cStringIO, email.Parser, os, popen2, re, sha
3886
abaee83ce0a6 Replace demandload with new demandimport
Matt Mackall <mpm@selenic.com>
parents: 3717
diff changeset
    13
import sys, tempfile, zlib
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    14
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
    15
class PatchError(Exception):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
    16
    pass
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
    17
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
    18
class NoHunks(PatchError):
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
    19
    pass
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
    20
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    21
# helper functions
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    22
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    23
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
    24
    if not basedir:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    25
        basedir = os.getcwd()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    26
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    27
    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
    28
    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
    29
        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
    30
                         dst)
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    31
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    32
    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
    33
    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
    34
        os.makedirs(targetdir)
3632
4cfb72bcb978 util: add copyfile function
Matt Mackall <mpm@selenic.com>
parents: 3588
diff changeset
    35
4cfb72bcb978 util: add copyfile function
Matt Mackall <mpm@selenic.com>
parents: 3588
diff changeset
    36
    util.copyfile(abssrc, absdst)
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    37
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    38
# public functions
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    39
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    40
def extract(ui, fileobj):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    41
    '''extract patch from data read from fileobj.
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    42
4258
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
    43
    patch can be a normal patch or contained in an email message.
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    44
4258
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
    45
    return tuple (filename, message, user, date, node, p1, p2).
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
    46
    Any item in the returned tuple can be None. If filename is None,
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
    47
    fileobj did not contain a patch. Caller must unlink filename when done.'''
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    48
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    49
    # attempt to detect the start of a patch
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    50
    # (this heuristic is borrowed from quilt)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    51
    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: 2864
diff changeset
    52
                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    53
                        '(---|\*\*\*)[ \t])', re.MULTILINE)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    54
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    55
    fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    56
    tmpfp = os.fdopen(fd, 'w')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    57
    try:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    58
        msg = email.Parser.Parser().parse(fileobj)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    59
4770
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    60
        subject = msg['Subject']
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    61
        user = msg['From']
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    62
        # should try to parse msg['Date']
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    63
        date = None
4258
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
    64
        nodeid = None
4440
eff2eefdb65a Add ability to parse branch information to hg import
Eric Hopper <hopper@omnifarious.org>
parents: 4436
diff changeset
    65
        branch = None
4258
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
    66
        parents = []
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    67
4770
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    68
        if subject:
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    69
            if subject.startswith('[PATCH'):
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    70
                pend = subject.find(']')
4203
bd9b84b9a84b Make [PATCH] removal slightly more robust
Brendan Cully <brendan@kublai.com>
parents: 4196
diff changeset
    71
                if pend >= 0:
4770
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    72
                    subject = subject[pend+1:].lstrip()
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    73
            subject = subject.replace('\n\t', ' ')
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
    74
            ui.debug('Subject: %s\n' % subject)
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    75
        if user:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    76
            ui.debug('From: %s\n' % user)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    77
        diffs_seen = 0
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    78
        ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
    79
        message = ''
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    80
        for part in msg.walk():
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    81
            content_type = part.get_content_type()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    82
            ui.debug('Content-Type: %s\n' % content_type)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    83
            if content_type not in ok_types:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    84
                continue
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    85
            payload = part.get_payload(decode=True)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    86
            m = diffre.search(payload)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    87
            if m:
4211
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4203
diff changeset
    88
                hgpatch = False
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4203
diff changeset
    89
                ignoretext = False
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4203
diff changeset
    90
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    91
                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: 2864
diff changeset
    92
                diffs_seen += 1
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    93
                cfp = cStringIO.StringIO()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    94
                for line in payload[:m.start(0)].splitlines():
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    95
                    if line.startswith('# HG changeset patch'):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    96
                        ui.debug(_('patch generated by hg export\n'))
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    97
                        hgpatch = True
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    98
                        # drop earlier commit message content
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
    99
                        cfp.seek(0)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   100
                        cfp.truncate()
4771
e321f16f4eac patch.extract: fix test-import breakage introduced in the previous changeset
Brendan Cully <brendan@kublai.com>
parents: 4770
diff changeset
   101
                        subject = None
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   102
                    elif hgpatch:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   103
                        if line.startswith('# User '):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   104
                            user = line[7:]
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   105
                            ui.debug('From: %s\n' % user)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   106
                        elif line.startswith("# Date "):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   107
                            date = line[7:]
4440
eff2eefdb65a Add ability to parse branch information to hg import
Eric Hopper <hopper@omnifarious.org>
parents: 4436
diff changeset
   108
                        elif line.startswith("# Branch "):
eff2eefdb65a Add ability to parse branch information to hg import
Eric Hopper <hopper@omnifarious.org>
parents: 4436
diff changeset
   109
                            branch = line[9:]
4258
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   110
                        elif line.startswith("# Node ID "):
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   111
                            nodeid = line[10:]
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   112
                        elif line.startswith("# Parent "):
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   113
                            parents.append(line[10:])
4211
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4203
diff changeset
   114
                    elif line == '---' and 'git-send-email' in msg['X-Mailer']:
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4203
diff changeset
   115
                        ignoretext = True
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4203
diff changeset
   116
                    if not line.startswith('# ') and not ignoretext:
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   117
                        cfp.write(line)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   118
                        cfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   119
                message = cfp.getvalue()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   120
                if tmpfp:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   121
                    tmpfp.write(payload)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   122
                    if not payload.endswith('\n'):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   123
                        tmpfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   124
            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: 2864
diff changeset
   125
                message += '\n' + payload
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   126
    except:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   127
        tmpfp.close()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   128
        os.unlink(tmpname)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   129
        raise
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   130
4770
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   131
    if subject and not message.startswith(subject):
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   132
        message = '%s\n%s' % (subject, message)
2865
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   133
    tmpfp.close()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   134
    if not diffs_seen:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2864
diff changeset
   135
        os.unlink(tmpname)
4440
eff2eefdb65a Add ability to parse branch information to hg import
Eric Hopper <hopper@omnifarious.org>
parents: 4436
diff changeset
   136
        return None, message, user, date, branch, None, None, None
4258
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   137
    p1 = parents and parents.pop(0) or None
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   138
    p2 = parents and parents.pop(0) or None
4440
eff2eefdb65a Add ability to parse branch information to hg import
Eric Hopper <hopper@omnifarious.org>
parents: 4436
diff changeset
   139
    return tmpname, message, user, date, branch, nodeid, p1, p2
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   140
3716
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   141
GP_PATCH  = 1 << 0  # we have to run patch
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   142
GP_FILTER = 1 << 1  # there's some copy/rename operation
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   143
GP_BINARY = 1 << 2  # there's a binary patch
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   144
5035
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   145
def readgitpatch(fp, firstline=None):
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   146
    """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
   147
    class gitpatch:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   148
        "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
   149
        def __init__(self, path):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   150
            self.path = path
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   151
            self.oldpath = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   152
            self.mode = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   153
            self.op = 'MODIFY'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   154
            self.lineno = 0
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   155
            self.binary = False
3215
53e843840349 Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3192
diff changeset
   156
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   157
    def reader(fp, firstline):
5035
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   158
        if firstline is not None:
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   159
            yield firstline
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   160
        for line in fp:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   161
            yield line
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   162
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   163
    # Filter patch for git information
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   164
    gitre = re.compile('diff --git a/(.*) b/(.*)')
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   165
    gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   166
    gitpatches = []
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   167
    # Can have a git patch with only metadata, causing patch to complain
3716
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   168
    dopatch = 0
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   169
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   170
    lineno = 0
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   171
    for line in reader(fp, firstline):
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   172
        lineno += 1
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   173
        if line.startswith('diff --git'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   174
            m = gitre.match(line)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   175
            if m:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   176
                if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   177
                    gitpatches.append(gp)
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3632
diff changeset
   178
                src, dst = m.group(1, 2)
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   179
                gp = gitpatch(dst)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   180
                gp.lineno = lineno
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   181
        elif gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   182
            if line.startswith('--- '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   183
                if gp.op in ('COPY', 'RENAME'):
3716
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   184
                    dopatch |= GP_FILTER
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   185
                gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   186
                gp = None
3716
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   187
                dopatch |= GP_PATCH
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   188
                continue
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   189
            if line.startswith('rename from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   190
                gp.op = 'RENAME'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   191
                gp.oldpath = line[12:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   192
            elif line.startswith('rename to '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   193
                gp.path = line[10:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   194
            elif line.startswith('copy from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   195
                gp.op = 'COPY'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   196
                gp.oldpath = line[10:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   197
            elif line.startswith('copy to '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   198
                gp.path = line[8:].rstrip()
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   199
            elif line.startswith('deleted file'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   200
                gp.op = 'DELETE'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   201
            elif line.startswith('new file mode '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   202
                gp.op = 'ADD'
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
   203
                gp.mode = int(line.rstrip()[-6:], 8)
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   204
            elif line.startswith('new mode '):
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
   205
                gp.mode = int(line.rstrip()[-6:], 8)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   206
            elif line.startswith('GIT binary patch'):
3716
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   207
                dopatch |= GP_BINARY
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   208
                gp.binary = True
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   209
    if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   210
        gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   211
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   212
    if not gitpatches:
3716
ab5600428b08 handle files with both git binary patches and copy/rename ops
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3702
diff changeset
   213
        dopatch = GP_PATCH
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   214
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   215
    return (dopatch, gitpatches)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   216
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   217
def patch(patchname, ui, strip=1, cwd=None, files={}):
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   218
    """apply <patchname> to the working directory.
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   219
    returns whether patch was applied with fuzz factor."""
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   220
    patcher = ui.config('ui', 'patch')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   221
    args = []
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   222
    try:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   223
        if patcher:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   224
            return externalpatch(patcher, args, patchname, ui, strip, cwd,
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   225
                                 files)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   226
        else:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   227
            try:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   228
                return internalpatch(patchname, ui, strip, cwd, files)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   229
            except NoHunks:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   230
                patcher = util.find_exe('gpatch') or util.find_exe('patch')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   231
                ui.debug('no valid hunks found; trying with %r instead\n' %
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   232
                         patcher)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   233
                if util.needbinarypatch():
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   234
                    args.append('--binary')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   235
                return externalpatch(patcher, args, patchname, ui, strip, cwd,
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   236
                                     files)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   237
    except PatchError, err:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   238
        s = str(err)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   239
        if s:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   240
            raise util.Abort(s)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   241
        else:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   242
            raise util.Abort(_('patch failed to apply'))
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   243
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   244
def externalpatch(patcher, args, patchname, ui, strip, cwd, files):
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   245
    """use <patcher> to apply <patchname> to the working directory.
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   246
    returns whether patch was applied with fuzz factor."""
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   247
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   248
    fuzz = False
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   249
    if cwd:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   250
        args.append('-d %s' % util.shellquote(cwd))
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   251
    fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   252
                                       util.shellquote(patchname)))
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   253
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   254
    for line in fp:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   255
        line = line.rstrip()
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   256
        ui.note(line + '\n')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   257
        if line.startswith('patching file '):
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   258
            pf = util.parse_patch_output(line)
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   259
            printed_file = False
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   260
            files.setdefault(pf, (None, None))
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   261
        elif line.find('with fuzz') >= 0:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   262
            fuzz = True
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   263
            if not printed_file:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   264
                ui.warn(pf + '\n')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   265
                printed_file = True
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   266
            ui.warn(line + '\n')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   267
        elif line.find('saving rejects to file') >= 0:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   268
            ui.warn(line + '\n')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   269
        elif line.find('FAILED') >= 0:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   270
            if not printed_file:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   271
                ui.warn(pf + '\n')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   272
                printed_file = True
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   273
            ui.warn(line + '\n')
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   274
    code = fp.close()
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   275
    if code:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   276
        raise PatchError(_("patch command failed: %s") %
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   277
                         util.explain_exit(code)[0])
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   278
    return fuzz
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   279
5035
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   280
def internalpatch(patchobj, ui, strip, cwd, files={}):
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   281
    """use builtin patch to apply <patchobj> to the working directory.
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   282
    returns whether patch was applied with fuzz factor."""
5035
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   283
    try:
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   284
        fp = file(patchobj, 'rb')
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   285
    except TypeError:
a675f6d5d069 patch: make internal code a bit friendlier to use
Bryan O'Sullivan <bos@serpentine.com>
parents: 5033
diff changeset
   286
        fp = patchobj
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   287
    if cwd:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   288
        curdir = os.getcwd()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   289
        os.chdir(cwd)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   290
    try:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   291
        ret = applydiff(ui, fp, files, strip=strip)
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   292
    finally:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   293
        if cwd:
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   294
            os.chdir(curdir)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   295
    if ret < 0:
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   296
        raise PatchError
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   297
    return ret > 0
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   298
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   299
# @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   300
unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   301
contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   302
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   303
class patchfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   304
    def __init__(self, ui, fname):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   305
        self.fname = fname
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   306
        self.ui = ui
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   307
        try:
4904
59b8ff35c4ed patch: patches should be read and written in binary mode when possible.
Patrick Mezard <pmezard@gmail.com>
parents: 4903
diff changeset
   308
            fp = file(fname, 'rb')
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   309
            self.lines = fp.readlines()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   310
            self.exists = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   311
        except IOError:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   312
            dirname = os.path.dirname(fname)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   313
            if dirname and not os.path.isdir(dirname):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   314
                dirs = dirname.split(os.path.sep)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   315
                d = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   316
                for x in dirs:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   317
                    d = os.path.join(d, x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   318
                    if not os.path.isdir(d):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   319
                        os.mkdir(d)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   320
            self.lines = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   321
            self.exists = False
5117
d4fa6bafc43a Remove trailing spaces, fix indentation
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5071
diff changeset
   322
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   323
        self.hash = {}
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   324
        self.dirty = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   325
        self.offset = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   326
        self.rej = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   327
        self.fileprinted = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   328
        self.printfile(False)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   329
        self.hunks = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   330
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   331
    def printfile(self, warn):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   332
        if self.fileprinted:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   333
            return
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   334
        if warn or self.ui.verbose:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   335
            self.fileprinted = True
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   336
        s = _("patching file %s\n") % self.fname
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   337
        if warn:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   338
            self.ui.warn(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   339
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   340
            self.ui.note(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   341
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   342
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   343
    def findlines(self, l, linenum):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   344
        # looks through the hash and finds candidate lines.  The
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   345
        # result is a list of line numbers sorted based on distance
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   346
        # from linenum
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   347
        def sorter(a, b):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   348
            vala = abs(a - linenum)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   349
            valb = abs(b - linenum)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   350
            return cmp(vala, valb)
5117
d4fa6bafc43a Remove trailing spaces, fix indentation
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5071
diff changeset
   351
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   352
        try:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   353
            cand = self.hash[l]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   354
        except:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   355
            return []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   356
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   357
        if len(cand) > 1:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   358
            # resort our list of potentials forward then back.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   359
            cand.sort(cmp=sorter)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   360
        return cand
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   361
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   362
    def hashlines(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   363
        self.hash = {}
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   364
        for x in xrange(len(self.lines)):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   365
            s = self.lines[x]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   366
            self.hash.setdefault(s, []).append(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   367
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   368
    def write_rej(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   369
        # our rejects are a little different from patch(1).  This always
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   370
        # creates rejects in the same form as the original patch.  A file
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   371
        # header is inserted so that you can run the reject through patch again
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   372
        # without having to type the filename.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   373
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   374
        if not self.rej:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   375
            return
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   376
        if self.hunks != 1:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   377
            hunkstr = "s"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   378
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   379
            hunkstr = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   380
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   381
        fname = self.fname + ".rej"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   382
        self.ui.warn(
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   383
            _("%d out of %d hunk%s FAILED -- saving rejects to file %s\n") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   384
            (len(self.rej), self.hunks, hunkstr, fname))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   385
        try: os.unlink(fname)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   386
        except:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   387
            pass
4904
59b8ff35c4ed patch: patches should be read and written in binary mode when possible.
Patrick Mezard <pmezard@gmail.com>
parents: 4903
diff changeset
   388
        fp = file(fname, 'wb')
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   389
        base = os.path.basename(self.fname)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   390
        fp.write("--- %s\n+++ %s\n" % (base, base))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   391
        for x in self.rej:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   392
            for l in x.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   393
                fp.write(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   394
                if l[-1] != '\n':
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   395
                    fp.write("\n\ No newline at end of file\n")
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   396
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   397
    def write(self, dest=None):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   398
        if self.dirty:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   399
            if not dest:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   400
                dest = self.fname
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   401
            st = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   402
            try:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   403
                st = os.lstat(dest)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   404
                if st.st_nlink > 1:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   405
                    os.unlink(dest)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   406
            except: pass
4904
59b8ff35c4ed patch: patches should be read and written in binary mode when possible.
Patrick Mezard <pmezard@gmail.com>
parents: 4903
diff changeset
   407
            fp = file(dest, 'wb')
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   408
            if st:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   409
                os.chmod(dest, st.st_mode)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   410
            fp.writelines(self.lines)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   411
            fp.close()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   412
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   413
    def close(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   414
        self.write()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   415
        self.write_rej()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   416
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   417
    def apply(self, h, reverse):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   418
        if not h.complete():
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   419
            raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   420
                            (h.number, h.desc, len(h.a), h.lena, len(h.b),
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   421
                            h.lenb))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   422
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   423
        self.hunks += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   424
        if reverse:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   425
            h.reverse()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   426
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   427
        if self.exists and h.createfile():
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   428
            self.ui.warn(_("file %s already exists\n") % self.fname)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   429
            self.rej.append(h)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   430
            return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   431
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   432
        if isinstance(h, binhunk):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   433
            if h.rmfile():
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   434
                os.unlink(self.fname)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   435
            else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   436
                self.lines[:] = h.new()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   437
                self.offset += len(h.new())
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   438
                self.dirty = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   439
            return 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   440
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   441
        # fast case first, no offsets, no fuzz
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   442
        old = h.old()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   443
        # patch starts counting at 1 unless we are adding the file
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   444
        if h.starta == 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   445
            start = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   446
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   447
            start = h.starta + self.offset - 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   448
        orig_start = start
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   449
        if diffhelpers.testhunk(old, self.lines, start) == 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   450
            if h.rmfile():
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   451
                os.unlink(self.fname)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   452
            else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   453
                self.lines[start : start + h.lena] = h.new()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   454
                self.offset += h.lenb - h.lena
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   455
                self.dirty = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   456
            return 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   457
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   458
        # ok, we couldn't match the hunk.  Lets look for offsets and fuzz it
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   459
        self.hashlines()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   460
        if h.hunk[-1][0] != ' ':
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   461
            # if the hunk tried to put something at the bottom of the file
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   462
            # override the start line and use eof here
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   463
            search_start = len(self.lines)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   464
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   465
            search_start = orig_start
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   466
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   467
        for fuzzlen in xrange(3):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   468
            for toponly in [ True, False ]:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   469
                old = h.old(fuzzlen, toponly)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   470
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   471
                cand = self.findlines(old[0][1:], search_start)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   472
                for l in cand:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   473
                    if diffhelpers.testhunk(old, self.lines, l) == 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   474
                        newlines = h.new(fuzzlen, toponly)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   475
                        self.lines[l : l + len(old)] = newlines
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   476
                        self.offset += len(newlines) - len(old)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   477
                        self.dirty = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   478
                        if fuzzlen:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   479
                            fuzzstr = "with fuzz %d " % fuzzlen
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   480
                            f = self.ui.warn
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   481
                            self.printfile(True)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   482
                        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   483
                            fuzzstr = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   484
                            f = self.ui.note
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   485
                        offset = l - orig_start - fuzzlen
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   486
                        if offset == 1:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   487
                            linestr = "line"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   488
                        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   489
                            linestr = "lines"
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   490
                        f(_("Hunk #%d succeeded at %d %s(offset %d %s).\n") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   491
                          (h.number, l+1, fuzzstr, offset, linestr))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   492
                        return fuzzlen
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   493
        self.printfile(True)
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   494
        self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   495
        self.rej.append(h)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   496
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   497
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   498
class hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   499
    def __init__(self, desc, num, lr, context):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   500
        self.number = num
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   501
        self.desc = desc
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   502
        self.hunk = [ desc ]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   503
        self.a = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   504
        self.b = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   505
        if context:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   506
            self.read_context_hunk(lr)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   507
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   508
            self.read_unified_hunk(lr)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   509
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   510
    def read_unified_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   511
        m = unidesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   512
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   513
            raise PatchError(_("bad hunk #%d") % self.number)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   514
        self.starta, foo, self.lena, self.startb, foo2, self.lenb = m.groups()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   515
        if self.lena == None:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   516
            self.lena = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   517
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   518
            self.lena = int(self.lena)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   519
        if self.lenb == None:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   520
            self.lenb = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   521
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   522
            self.lenb = int(self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   523
        self.starta = int(self.starta)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   524
        self.startb = int(self.startb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   525
        diffhelpers.addlines(lr.fp, self.hunk, self.lena, self.lenb, self.a, self.b)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   526
        # if we hit eof before finishing out the hunk, the last line will
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   527
        # be zero length.  Lets try to fix it up.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   528
        while len(self.hunk[-1]) == 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   529
                del self.hunk[-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   530
                del self.a[-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   531
                del self.b[-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   532
                self.lena -= 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   533
                self.lenb -= 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   534
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   535
    def read_context_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   536
        self.desc = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   537
        m = contextdesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   538
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   539
            raise PatchError(_("bad hunk #%d") % self.number)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   540
        foo, self.starta, foo2, aend, foo3 = m.groups()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   541
        self.starta = int(self.starta)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   542
        if aend == None:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   543
            aend = self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   544
        self.lena = int(aend) - self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   545
        if self.starta:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   546
            self.lena += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   547
        for x in xrange(self.lena):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   548
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   549
            if l.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   550
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   551
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   552
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   553
            if l.startswith('- ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   554
                u = '-' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   555
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   556
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   557
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   558
                raise PatchError(_("bad hunk #%d old text line %d") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   559
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   560
            self.a.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   561
            self.hunk.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   562
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   563
        l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   564
        if l.startswith('\ '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   565
            s = self.a[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   566
            self.a[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   567
            self.hunk[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   568
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   569
        m = contextdesc.match(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   570
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   571
            raise PatchError(_("bad hunk #%d") % self.number)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   572
        foo, self.startb, foo2, bend, foo3 = m.groups()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   573
        self.startb = int(self.startb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   574
        if bend == None:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   575
            bend = self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   576
        self.lenb = int(bend) - self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   577
        if self.startb:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   578
            self.lenb += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   579
        hunki = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   580
        for x in xrange(self.lenb):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   581
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   582
            if l.startswith('\ '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   583
                s = self.b[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   584
                self.b[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   585
                self.hunk[hunki-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   586
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   587
            if not l:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   588
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   589
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   590
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   591
            if l.startswith('+ ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   592
                u = '+' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   593
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   594
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   595
            elif len(self.b) == 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   596
                # this can happen when the hunk does not add any lines
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   597
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   598
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   599
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   600
                raise PatchError(_("bad hunk #%d old text line %d") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   601
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   602
            self.b.append(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   603
            while True:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   604
                if hunki >= len(self.hunk):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   605
                    h = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   606
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   607
                    h = self.hunk[hunki]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   608
                hunki += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   609
                if h == u:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   610
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   611
                elif h.startswith('-'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   612
                    continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   613
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   614
                    self.hunk.insert(hunki-1, u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   615
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   616
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   617
        if not self.a:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   618
            # this happens when lines were only added to the hunk
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   619
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   620
                if x.startswith('-') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   621
                    self.a.append(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   622
        if not self.b:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   623
            # this happens when lines were only deleted from the hunk
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   624
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   625
                if x.startswith('+') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   626
                    self.b.append(x[1:])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   627
        # @@ -start,len +start,len @@
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   628
        self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   629
                                             self.startb, self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   630
        self.hunk[0] = self.desc
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   631
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   632
    def reverse(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   633
        origlena = self.lena
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   634
        origstarta = self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   635
        self.lena = self.lenb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   636
        self.starta = self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   637
        self.lenb = origlena
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   638
        self.startb = origstarta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   639
        self.a = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   640
        self.b = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   641
        # self.hunk[0] is the @@ description
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   642
        for x in xrange(1, len(self.hunk)):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   643
            o = self.hunk[x]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   644
            if o.startswith('-'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   645
                n = '+' + o[1:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   646
                self.b.append(o[1:])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   647
            elif o.startswith('+'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   648
                n = '-' + o[1:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   649
                self.a.append(n)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   650
            else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   651
                n = o
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   652
                self.b.append(o[1:])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   653
                self.a.append(o)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   654
            self.hunk[x] = o
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   655
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   656
    def fix_newline(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   657
        diffhelpers.fix_newline(self.hunk, self.a, self.b)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   658
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   659
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   660
        return len(self.a) == self.lena and len(self.b) == self.lenb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   661
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   662
    def createfile(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   663
        return self.starta == 0 and self.lena == 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   664
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   665
    def rmfile(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   666
        return self.startb == 0 and self.lenb == 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   667
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   668
    def fuzzit(self, l, fuzz, toponly):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   669
        # this removes context lines from the top and bottom of list 'l'.  It
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   670
        # checks the hunk to make sure only context lines are removed, and then
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   671
        # returns a new shortened list of lines.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   672
        fuzz = min(fuzz, len(l)-1)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   673
        if fuzz:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   674
            top = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   675
            bot = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   676
            hlen = len(self.hunk)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   677
            for x in xrange(hlen-1):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   678
                # the hunk starts with the @@ line, so use x+1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   679
                if self.hunk[x+1][0] == ' ':
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   680
                    top += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   681
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   682
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   683
            if not toponly:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   684
                for x in xrange(hlen-1):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   685
                    if self.hunk[hlen-bot-1][0] == ' ':
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   686
                        bot += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   687
                    else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   688
                        break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   689
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   690
            # top and bot now count context in the hunk
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   691
            # adjust them if either one is short
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   692
            context = max(top, bot, 3)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   693
            if bot < context:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   694
                bot = max(0, fuzz - (context - bot))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   695
            else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   696
                bot = min(fuzz, bot)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   697
            if top < context:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   698
                top = max(0, fuzz - (context - top))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   699
            else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   700
                top = min(fuzz, top)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   701
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   702
            return l[top:len(l)-bot]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   703
        return l
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   704
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   705
    def old(self, fuzz=0, toponly=False):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   706
        return self.fuzzit(self.a, fuzz, toponly)
5117
d4fa6bafc43a Remove trailing spaces, fix indentation
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5071
diff changeset
   707
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   708
    def newctrl(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   709
        res = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   710
        for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   711
            c = x[0]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   712
            if c == ' ' or c == '+':
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   713
                res.append(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   714
        return res
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   715
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   716
    def new(self, fuzz=0, toponly=False):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   717
        return self.fuzzit(self.b, fuzz, toponly)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   718
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   719
class binhunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   720
    'A binary patch file. Only understands literals so far.'
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   721
    def __init__(self, gitpatch):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   722
        self.gitpatch = gitpatch
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   723
        self.text = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   724
        self.hunk = ['GIT binary patch\n']
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   725
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   726
    def createfile(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   727
        return self.gitpatch.op in ('ADD', 'RENAME', 'COPY')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   728
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   729
    def rmfile(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   730
        return self.gitpatch.op == 'DELETE'
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   731
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   732
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   733
        return self.text is not None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   734
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   735
    def new(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   736
        return [self.text]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   737
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   738
    def extract(self, fp):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   739
        line = fp.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   740
        self.hunk.append(line)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   741
        while line and not line.startswith('literal '):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   742
            line = fp.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   743
            self.hunk.append(line)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   744
        if not line:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   745
            raise PatchError(_('could not extract binary patch'))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   746
        size = int(line[8:].rstrip())
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   747
        dec = []
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   748
        line = fp.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   749
        self.hunk.append(line)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   750
        while len(line) > 1:
3372
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   751
            l = line[0]
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   752
            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
   753
                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
   754
            else:
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
   755
                l = ord(l) - ord('a') + 27
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   756
            dec.append(base85.b85decode(line[1:-1])[:l])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   757
            line = fp.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   758
            self.hunk.append(line)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   759
        text = zlib.decompress(''.join(dec))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   760
        if len(text) != size:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   761
            raise PatchError(_('binary patch is %d bytes, not %d') %
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   762
                             len(text), size)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   763
        self.text = text
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   764
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   765
def parsefilename(str):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   766
    # --- filename \t|space stuff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   767
    s = str[4:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   768
    i = s.find('\t')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   769
    if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   770
        i = s.find(' ')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   771
        if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   772
            return s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   773
    return s[:i]
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   774
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   775
def selectfile(afile_orig, bfile_orig, hunk, strip, reverse):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   776
    def pathstrip(path, count=1):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   777
        pathlen = len(path)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   778
        i = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   779
        if count == 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   780
            return path.rstrip()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   781
        while count > 0:
4903
020ee9c781cf patch: fix normalized paths separators.
Patrick Mezard <pmezard@gmail.com>
parents: 4900
diff changeset
   782
            i = path.find('/', i)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   783
            if i == -1:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   784
                raise PatchError(_("unable to strip away %d dirs from %s") %
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   785
                                 (count, path))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   786
            i += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   787
            # consume '//' in the path
4903
020ee9c781cf patch: fix normalized paths separators.
Patrick Mezard <pmezard@gmail.com>
parents: 4900
diff changeset
   788
            while i < pathlen - 1 and path[i] == '/':
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   789
                i += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   790
            count -= 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   791
        return path[i:].rstrip()
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
   792
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   793
    nulla = afile_orig == "/dev/null"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   794
    nullb = bfile_orig == "/dev/null"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   795
    afile = pathstrip(afile_orig, strip)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   796
    gooda = os.path.exists(afile) and not nulla
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   797
    bfile = pathstrip(bfile_orig, strip)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   798
    if afile == bfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   799
        goodb = gooda
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   800
    else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   801
        goodb = os.path.exists(bfile) and not nullb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   802
    createfunc = hunk.createfile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   803
    if reverse:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   804
        createfunc = hunk.rmfile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   805
    if not goodb and not gooda and not createfunc():
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   806
        raise PatchError(_("unable to find %s or %s for patching") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   807
                         (afile, bfile))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   808
    if gooda and goodb:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   809
        fname = bfile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   810
        if afile in bfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   811
            fname = afile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   812
    elif gooda:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   813
        fname = afile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   814
    elif not nullb:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   815
        fname = bfile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   816
        if afile in bfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   817
            fname = afile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   818
    elif not nulla:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   819
        fname = afile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   820
    return fname
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   821
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   822
class linereader:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   823
    # simple class to allow pushing lines back into the input stream
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   824
    def __init__(self, fp):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   825
        self.fp = fp
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   826
        self.buf = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   827
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   828
    def push(self, line):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   829
        self.buf.append(line)
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   830
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   831
    def readline(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   832
        if self.buf:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   833
            l = self.buf[0]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   834
            del self.buf[0]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   835
            return l
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   836
        return self.fp.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   837
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   838
def applydiff(ui, fp, changed, strip=1, sourcefile=None, reverse=False,
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   839
              rejmerge=None, updatedir=None):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   840
    """reads a patch from fp and tries to apply it.  The dict 'changed' is
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   841
       filled in with all of the filenames changed by the patch.  Returns 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   842
       for a clean patch, -1 if any rejects were found and 1 if there was
5117
d4fa6bafc43a Remove trailing spaces, fix indentation
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5071
diff changeset
   843
       any fuzz."""
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   844
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   845
    def scangitpatch(fp, firstline, cwd=None):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   846
        '''git patches can modify a file, then copy that file to
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   847
        a new file, but expect the source to be the unmodified form.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   848
        So we scan the patch looking for that case so we can do
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   849
        the copies ahead of time.'''
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   850
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   851
        pos = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   852
        try:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   853
            pos = fp.tell()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   854
        except IOError:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   855
            fp = cStringIO.StringIO(fp.read())
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   856
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   857
        (dopatch, gitpatches) = readgitpatch(fp, firstline)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   858
        for gp in gitpatches:
5403
477136fa6571 Always copy the necessary files before applying a git patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5261
diff changeset
   859
            if gp.op in ('COPY', 'RENAME'):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   860
                copyfile(gp.oldpath, gp.path, basedir=cwd)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   861
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   862
        fp.seek(pos)
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   863
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   864
        return fp, dopatch, gitpatches
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   865
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   866
    current_hunk = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   867
    current_file = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   868
    afile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   869
    bfile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   870
    state = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   871
    hunknum = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   872
    rejects = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   873
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   874
    git = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   875
    gitre = re.compile('diff --git (a/.*) (b/.*)')
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   876
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   877
    # our states
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   878
    BFILE = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   879
    err = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   880
    context = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   881
    lr = linereader(fp)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   882
    dopatch = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   883
    gitworkdone = False
2860
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   884
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   885
    while True:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   886
        newfile = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   887
        x = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   888
        if not x:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   889
            break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   890
        if current_hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   891
            if x.startswith('\ '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   892
                current_hunk.fix_newline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   893
            ret = current_file.apply(current_hunk, reverse)
4899
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   894
            if ret >= 0:
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   895
                changed.setdefault(current_file.fname, (None, None))
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   896
                if ret > 0:
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   897
                    err = 1
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   898
            current_hunk = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   899
            gitworkdone = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   900
        if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   901
            ((context or context == None) and x.startswith('***************')))):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   902
            try:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   903
                if context == None and x.startswith('***************'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   904
                    context = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   905
                current_hunk = hunk(x, hunknum + 1, lr, context)
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   906
            except PatchError, err:
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   907
                ui.debug(err)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   908
                current_hunk = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   909
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   910
            hunknum += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   911
            if not current_file:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   912
                if sourcefile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   913
                    current_file = patchfile(ui, sourcefile)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   914
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   915
                    current_file = selectfile(afile, bfile, current_hunk,
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   916
                                              strip, reverse)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   917
                    current_file = patchfile(ui, current_file)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   918
        elif state == BFILE and x.startswith('GIT binary patch'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   919
            current_hunk = binhunk(changed[bfile[2:]][1])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   920
            if not current_file:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   921
                if sourcefile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   922
                    current_file = patchfile(ui, sourcefile)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   923
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   924
                    current_file = selectfile(afile, bfile, current_hunk,
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   925
                                              strip, reverse)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   926
                    current_file = patchfile(ui, current_file)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   927
            hunknum += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   928
            current_hunk.extract(fp)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   929
        elif x.startswith('diff --git'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   930
            # check for git diff, scanning the whole patch file if needed
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   931
            m = gitre.match(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   932
            if m:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   933
                afile, bfile = m.group(1, 2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   934
                if not git:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   935
                    git = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   936
                    fp, dopatch, gitpatches = scangitpatch(fp, x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   937
                    for gp in gitpatches:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   938
                        changed[gp.path] = (gp.op, gp)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   939
                # else error?
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   940
                # copy/rename + modify should modify target, not source
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   941
                if changed.get(bfile[2:], (None, None))[0] in ('COPY',
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   942
                                                               'RENAME'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   943
                    afile = bfile
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   944
                    gitworkdone = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   945
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   946
        elif x.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   947
            # check for a unified diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   948
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   949
            if not l2.startswith('+++'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   950
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   951
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   952
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   953
            context = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   954
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   955
            bfile = parsefilename(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   956
        elif x.startswith('***'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   957
            # check for a context diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   958
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   959
            if not l2.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   960
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   961
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   962
            l3 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   963
            lr.push(l3)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   964
            if not l3.startswith("***************"):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   965
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   966
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   967
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   968
            context = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   969
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   970
            bfile = parsefilename(l2)
3054
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3053
diff changeset
   971
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   972
        if newfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   973
            if current_file:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   974
                current_file.close()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   975
                if rejmerge:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   976
                    rejmerge(current_file)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   977
                rejects += len(current_file.rej)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   978
            state = BFILE
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   979
            current_file = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   980
            hunknum = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   981
    if current_hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   982
        if current_hunk.complete():
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   983
            ret = current_file.apply(current_hunk, reverse)
4899
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   984
            if ret >= 0:
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   985
                changed.setdefault(current_file.fname, (None, None))
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   986
                if ret > 0:
1b7bbc4349e7 patch.py: don't mark files as changed unless they have actually been changed
Bryan O'Sullivan <bos@serpentine.com>
parents: 4898
diff changeset
   987
                    err = 1
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   988
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   989
            fname = current_file and current_file.fname or None
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   990
            raise PatchError(_("malformed patch %s %s") % (fname,
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   991
                             current_hunk.desc))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   992
    if current_file:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   993
        current_file.close()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   994
        if rejmerge:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   995
            rejmerge(current_file)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   996
        rejects += len(current_file.rej)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   997
    if updatedir and git:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   998
        updatedir(gitpatches)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
   999
    if rejects:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
  1000
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
  1001
    if hunknum == 0 and dopatch and not gitworkdone:
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
  1002
        raise NoHunks
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4771
diff changeset
  1003
    return err
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1004
3540
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1005
def diffopts(ui, opts={}, untrusted=False):
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1006
    def get(key, name=None):
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1007
        return (opts.get(key) or
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1008
                ui.configbool('diff', name or key, None, untrusted=untrusted))
2908
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2880
diff changeset
  1009
    return mdiff.diffopts(
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2880
diff changeset
  1010
        text=opts.get('text'),
3540
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1011
        git=get('git'),
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1012
        nodates=get('nodates'),
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1013
        showfunc=get('show_function', 'showfunc'),
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1014
        ignorews=get('ignore_all_space', 'ignorews'),
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1015
        ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
da3ee7ca620f add untrusted argument to patch.diffopts
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3468
diff changeset
  1016
        ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'))
2908
3848488244fc Move ui.diffopts to patch.diffopts where it belongs
Matt Mackall <mpm@selenic.com>
parents: 2880
diff changeset
  1017
4961
126f527b3ba3 Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents: 4900
diff changeset
  1018
def updatedir(ui, repo, patches):
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1019
    '''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
  1020
    if not patches:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1021
        return
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1022
    copies = []
3701
05c8704a3743 handle git patches that rename a file to more than one destination
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3696
diff changeset
  1023
    removes = {}
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1024
    cfiles = patches.keys()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1025
    cwd = repo.getcwd()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1026
    if cwd:
4229
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4105
diff changeset
  1027
        cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1028
    for f in patches:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1029
        ctype, gp = patches[f]
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1030
        if ctype == 'RENAME':
5403
477136fa6571 Always copy the necessary files before applying a git patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5261
diff changeset
  1031
            copies.append((gp.oldpath, gp.path))
3701
05c8704a3743 handle git patches that rename a file to more than one destination
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3696
diff changeset
  1032
            removes[gp.oldpath] = 1
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1033
        elif ctype == 'COPY':
5403
477136fa6571 Always copy the necessary files before applying a git patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5261
diff changeset
  1034
            copies.append((gp.oldpath, gp.path))
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1035
        elif ctype == 'DELETE':
3701
05c8704a3743 handle git patches that rename a file to more than one destination
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3696
diff changeset
  1036
            removes[gp.path] = 1
5403
477136fa6571 Always copy the necessary files before applying a git patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5261
diff changeset
  1037
    for src, dst in copies:
4961
126f527b3ba3 Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents: 4900
diff changeset
  1038
        repo.copy(src, dst)
3701
05c8704a3743 handle git patches that rename a file to more than one destination
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3696
diff changeset
  1039
    removes = removes.keys()
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1040
    if removes:
3701
05c8704a3743 handle git patches that rename a file to more than one destination
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3696
diff changeset
  1041
        removes.sort()
4961
126f527b3ba3 Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents: 4900
diff changeset
  1042
        repo.remove(removes, True)
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1043
    for f in patches:
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1044
        ctype, gp = patches[f]
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1045
        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
  1046
            x = gp.mode & 0100 != 0
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1047
            l = gp.mode & 020000 != 0
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1048
            dst = os.path.join(repo.root, gp.path)
3588
45574a225632 git patch: create empty added files
Brendan Cully <brendan@kublai.com>
parents: 3540
diff changeset
  1049
            # patch won't create empty files
45574a225632 git patch: create empty added files
Brendan Cully <brendan@kublai.com>
parents: 3540
diff changeset
  1050
            if ctype == 'ADD' and not os.path.exists(dst):
4006
67982d3ee76c symlinks: add flags param to wwrite
Matt Mackall <mpm@selenic.com>
parents: 3996
diff changeset
  1051
                repo.wwrite(gp.path, '', x and 'x' or '')
67982d3ee76c symlinks: add flags param to wwrite
Matt Mackall <mpm@selenic.com>
parents: 3996
diff changeset
  1052
            else:
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1053
                util.set_link(dst, l)
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1054
                if not l:
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1055
                    util.set_exec(dst, x)
4961
126f527b3ba3 Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents: 4900
diff changeset
  1056
    cmdutil.addremove(repo, cfiles)
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1057
    files = patches.keys()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1058
    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
  1059
    files.sort()
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1060
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1061
    return files
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
  1062
5033
1b07668b8cc3 patch: remove unused parameter from b85diff
Bryan O'Sullivan <bos@serpentine.com>
parents: 4965
diff changeset
  1063
def b85diff(to, tn):
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1064
    '''print base85-encoded binary diff'''
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1065
    def gitindex(text):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1066
        if not text:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1067
            return '0' * 40
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1068
        l = len(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1069
        s = sha.new('blob %d\0' % l)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1070
        s.update(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1071
        return s.hexdigest()
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1072
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1073
    def fmtline(line):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1074
        l = len(line)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1075
        if l <= 26:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1076
            l = chr(ord('A') + l - 1)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1077
        else:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1078
            l = chr(l - 26 + ord('a') - 1)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1079
        return '%c%s\n' % (l, base85.b85encode(line, True))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1080
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1081
    def chunk(text, csize=52):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1082
        l = len(text)
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1083
        i = 0
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1084
        while i < l:
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1085
            yield text[i:i+csize]
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1086
            i += csize
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1087
4104
ed46895aa38c git binary patches: use hashes to detect identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4092
diff changeset
  1088
    tohash = gitindex(to)
ed46895aa38c git binary patches: use hashes to detect identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4092
diff changeset
  1089
    tnhash = gitindex(tn)
ed46895aa38c git binary patches: use hashes to detect identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4092
diff changeset
  1090
    if tohash == tnhash:
4105
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1091
        return ""
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1092
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1093
    # TODO: deltas
4105
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1094
    ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1095
           (tohash, tnhash, len(tn))]
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1096
    for l in chunk(zlib.compress(tn)):
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1097
        ret.append(fmtline(l))
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1098
    ret.append('\n')
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1099
    return ''.join(ret)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1100
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1101
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: 2867
diff changeset
  1102
         fp=None, changes=None, opts=None):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1103
    '''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: 2867
diff changeset
  1104
    working directory.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1105
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1106
    if node1 is None, use first dirstate parent instead.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1107
    if node2 is None, compare node1 with working directory.'''
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1108
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1109
    if opts is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1110
        opts = mdiff.defaultopts
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1111
    if fp is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1112
        fp = repo.ui
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1113
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1114
    if not node1:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1115
        node1 = repo.dirstate.parents()[0]
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
  1116
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1117
    ccache = {}
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1118
    def getctx(r):
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1119
        if r not in ccache:
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1120
            ccache[r] = context.changectx(repo, r)
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1121
        return ccache[r]
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1122
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1123
    flcache = {}
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1124
    def getfilectx(f, ctx):
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1125
        flctx = ctx.filectx(f, filelog=flcache.get(f))
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1126
        if f not in flcache:
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1127
            flcache[f] = flctx._filelog
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1128
        return flctx
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
  1129
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1130
    # reading the data for node1 early allows it to play nicely
2874
3d6efcbbd1c9 remove localrepository.changes.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2873
diff changeset
  1131
    # with repo.status and the revlog cache.
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1132
    ctx1 = context.changectx(repo, node1)
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1133
    # force manifest reading
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1134
    man1 = ctx1.manifest()
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1135
    date1 = util.datestr(ctx1.date())
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1136
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1137
    if not changes:
2874
3d6efcbbd1c9 remove localrepository.changes.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2873
diff changeset
  1138
        changes = repo.status(node1, node2, files, match=match)[:5]
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1139
    modified, added, removed, deleted, unknown = changes
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1140
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1141
    if not modified and not added and not removed:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1142
        return
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1143
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1144
    if node2:
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1145
        ctx2 = context.changectx(repo, node2)
4492
b79cdb7f0597 patch.diff: avoid calling workingctx().manifest()
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4484
diff changeset
  1146
        execf2 = ctx2.manifest().execf
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1147
        linkf2 = ctx2.manifest().linkf
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1148
    else:
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1149
        ctx2 = context.workingctx(repo)
4492
b79cdb7f0597 patch.diff: avoid calling workingctx().manifest()
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4484
diff changeset
  1150
        execf2 = util.execfunc(repo.root, None)
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1151
        linkf2 = util.linkfunc(repo.root, None)
4492
b79cdb7f0597 patch.diff: avoid calling workingctx().manifest()
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4484
diff changeset
  1152
        if execf2 is None:
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1153
            mc = ctx2.parents()[0].manifest().copy()
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1154
            execf2 = mc.execf
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1155
            linkf2 = mc.linkf
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1156
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1157
    # returns False if there was no rename between ctx1 and ctx2
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1158
    # returns None if the file was created between ctx1 and ctx2
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1159
    # returns the (file, node) present in ctx1 that was renamed to f in ctx2
5260
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1160
    # This will only really work if c1 is the Nth 1st parent of c2.
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1161
    def renamed(c1, c2, man, f):
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1162
        startrev = c1.rev()
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1163
        c = c2
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1164
        crev = c.rev()
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1165
        if crev is None:
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1166
            crev = repo.changelog.count()
3694
c0b1a0c72c7d renamedbetween: only return (file, node) pairs that exist in the original rev
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3693
diff changeset
  1167
        orig = f
5261
15a108ad7adb Avoid a working dir walk while trying to detect copies for diff --git
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5260
diff changeset
  1168
        files = (f,)
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1169
        while crev > startrev:
5261
15a108ad7adb Avoid a working dir walk while trying to detect copies for diff --git
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5260
diff changeset
  1170
            if f in files:
3693
454b3a8cdf28 diff: improve detection of renames when diffing across many revisions
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
  1171
                try:
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1172
                    src = getfilectx(f, c).renamed()
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1173
                except revlog.LookupError:
3693
454b3a8cdf28 diff: improve detection of renames when diffing across many revisions
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
  1174
                    return None
454b3a8cdf28 diff: improve detection of renames when diffing across many revisions
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
  1175
                if src:
454b3a8cdf28 diff: improve detection of renames when diffing across many revisions
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
  1176
                    f = src[0]
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1177
            crev = c.parents()[0].rev()
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1178
            # try to reuse
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1179
            c = getctx(crev)
5261
15a108ad7adb Avoid a working dir walk while trying to detect copies for diff --git
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5260
diff changeset
  1180
            files = c.files()
5260
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1181
        if f not in man:
3694
c0b1a0c72c7d renamedbetween: only return (file, node) pairs that exist in the original rev
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3693
diff changeset
  1182
            return None
3696
562a65635bcb diff: better detection of renames when comparing with the working dir.
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3695
diff changeset
  1183
        if f == orig:
562a65635bcb diff: better detection of renames when comparing with the working dir.
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3695
diff changeset
  1184
            return False
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1185
        return f
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1186
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1187
    if repo.ui.quiet:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1188
        r = None
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1189
    else:
3386
2065789f6a3e use short hashes with diff -v
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3376
diff changeset
  1190
        hexfunc = repo.ui.debugflag and hex or short
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1191
        r = [hexfunc(node) for node in [node1, node2] if node]
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1192
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1193
    if opts.git:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1194
        copied = {}
5260
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1195
        c1, c2 = ctx1, ctx2
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1196
        files = added
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1197
        man = man1
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1198
        if node2 and ctx1.rev() >= ctx2.rev():
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1199
            # renamed() starts at c2 and walks back in history until c1.
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1200
            # Since ctx1.rev() >= ctx2.rev(), invert ctx2 and ctx1 to
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1201
            # detect (inverted) copies.
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1202
            c1, c2 = ctx2, ctx1
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1203
            files = removed
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1204
            man = ctx2.manifest()
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1205
        for f in files:
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1206
            src = renamed(c1, c2, man, f)
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1207
            if src:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1208
                copied[f] = src
5260
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1209
        if ctx1 == c2:
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1210
            # invert the copied dict
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1211
            copied = dict([(v, k) for (k, v) in copied.iteritems()])
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1212
        # If we've renamed file foo to bar (copied['bar'] = 'foo'),
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1213
        # avoid showing a diff for foo if we're going to show
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1214
        # the rename to bar.
0fc16031bb45 Make hg diff --git -r revA:revB detect (inverted) copies if revA > revB
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5117
diff changeset
  1215
        srcs = [x[1] for x in copied.iteritems() if x[0] in added]
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1216
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1217
    all = modified + added + removed
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1218
    all.sort()
3702
70c3ee224c08 Don't generate git patches that rename a file to multiple destinations
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3701
diff changeset
  1219
    gone = {}
3996
c190df14338c exec: add execfunc to simplify exec flag support on non-exec filesystems
Matt Mackall <mpm@selenic.com>
parents: 3970
diff changeset
  1220
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1221
    for f in all:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1222
        to = None
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1223
        tn = None
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1224
        dodiff = True
3327
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3223
diff changeset
  1225
        header = []
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1226
        if f in man1:
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1227
            to = getfilectx(f, ctx1).data()
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1228
        if f not in removed:
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1229
            tn = getfilectx(f, ctx2).data()
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1230
        if opts.git:
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1231
            def gitmode(x, l):
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1232
                return l and '120000' or (x and '100755' or '100644')
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1233
            def addmodehdr(header, omode, nmode):
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1234
                if omode != nmode:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1235
                    header.append('old mode %s\n' % omode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1236
                    header.append('new mode %s\n' % nmode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1237
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1238
            a, b = f, f
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1239
            if f in added:
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1240
                mode = gitmode(execf2(f), linkf2(f))
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1241
                if f in copied:
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1242
                    a = copied[f]
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1243
                    omode = gitmode(man1.execf(a), man1.linkf(a))
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1244
                    addmodehdr(header, omode, mode)
3702
70c3ee224c08 Don't generate git patches that rename a file to multiple destinations
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3701
diff changeset
  1245
                    if a in removed and a not in gone:
70c3ee224c08 Don't generate git patches that rename a file to multiple destinations
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3701
diff changeset
  1246
                        op = 'rename'
70c3ee224c08 Don't generate git patches that rename a file to multiple destinations
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3701
diff changeset
  1247
                        gone[a] = 1
70c3ee224c08 Don't generate git patches that rename a file to multiple destinations
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3701
diff changeset
  1248
                    else:
70c3ee224c08 Don't generate git patches that rename a file to multiple destinations
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3701
diff changeset
  1249
                        op = 'copy'
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1250
                    header.append('%s from %s\n' % (op, a))
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1251
                    header.append('%s to %s\n' % (op, f))
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  1252
                    to = getfilectx(a, ctx1).data()
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1253
                else:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1254
                    header.append('new file mode %s\n' % mode)
4092
4ced663bebf0 git patches: handle renames of binary files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3900
diff changeset
  1255
                if util.binary(tn):
4ced663bebf0 git patches: handle renames of binary files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3900
diff changeset
  1256
                    dodiff = 'binary'
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1257
            elif f in removed:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1258
                if f in srcs:
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1259
                    dodiff = False
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1260
                else:
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1261
                    mode = gitmode(man1.execf(f), man1.linkf(f))
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1262
                    header.append('deleted file mode %s\n' % mode)
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1263
            else:
5071
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1264
                omode = gitmode(man1.execf(f), man1.linkf(f))
35d47b06d4e3 patch: add git symlink support
Brendan Cully <brendan@kublai.com>
parents: 5035
diff changeset
  1265
                nmode = gitmode(execf2(f), linkf2(f))
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1266
                addmodehdr(header, omode, nmode)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1267
                if util.binary(to) or util.binary(tn):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3327
diff changeset
  1268
                    dodiff = 'binary'
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1269
            r = None
3327
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3223
diff changeset
  1270
            header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
4105
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1271
        if dodiff:
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1272
            if dodiff == 'binary':
5033
1b07668b8cc3 patch: remove unused parameter from b85diff
Bryan O'Sullivan <bos@serpentine.com>
parents: 4965
diff changeset
  1273
                text = b85diff(to, tn)
4105
797dbdd4d7e1 git binary patches: don't print the header for identical files
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4104
diff changeset
  1274
            else:
4107
226df1808f16 merge with crew-stable
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4096 4105
diff changeset
  1275
                text = mdiff.unidiff(to, date1,
226df1808f16 merge with crew-stable
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4096 4105
diff changeset
  1276
                                    # ctx2 date may be dynamic
226df1808f16 merge with crew-stable
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4096 4105
diff changeset
  1277
                                    tn, util.datestr(ctx2.date()),
226df1808f16 merge with crew-stable
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4096 4105
diff changeset
  1278
                                    f, r, opts=opts)
3327
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3223
diff changeset
  1279
            if text or len(header) > 1:
2892
8b02af865990 Add diff --git option
Brendan Cully <brendan@kublai.com>
parents: 2880
diff changeset
  1280
                fp.write(''.join(header))
3327
319358e6bd96 Don't generate git diff header for empty diffs
Brendan Cully <brendan@kublai.com>
parents: 3223
diff changeset
  1281
            fp.write(text)
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1282
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1283
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: 2867
diff changeset
  1284
           opts=None):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1285
    '''export changesets as hg patches.'''
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1286
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1287
    total = len(revs)
3900
2b3175acb653 Don't use node length for calculating revision number length.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3899
diff changeset
  1288
    revwidth = max([len(str(rev)) for rev in revs])
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1289
3970
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1290
    def single(rev, seqno, fp):
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1291
        ctx = repo.changectx(rev)
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1292
        node = ctx.node()
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1293
        parents = [p.node() for p in ctx.parents() if p]
4436
a764edb6fc95 Add branch information to hg export.
Eric Hopper <hopper@omnifarious.org>
parents: 4435
diff changeset
  1294
        branch = ctx.branch()
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1295
        if switch_parent:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1296
            parents.reverse()
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1297
        prev = (parents and parents[0]) or nullid
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1298
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1299
        if not fp:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1300
            fp = cmdutil.make_file(repo, template, node, total=total,
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1301
                                   seqno=seqno, revwidth=revwidth)
4125
ef7c39ae5d4c Suppress <stdout> before hg export -v (regression from previous patch).
Brendan Cully <brendan@kublai.com>
parents: 4124
diff changeset
  1302
        if fp != sys.stdout and hasattr(fp, 'name'):
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1303
            repo.ui.note("%s\n" % fp.name)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1304
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1305
        fp.write("# HG changeset patch\n")
3970
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1306
        fp.write("# User %s\n" % ctx.user())
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1307
        fp.write("# Date %d %d\n" % ctx.date())
4436
a764edb6fc95 Add branch information to hg export.
Eric Hopper <hopper@omnifarious.org>
parents: 4435
diff changeset
  1308
        if branch and (branch != 'default'):
a764edb6fc95 Add branch information to hg export.
Eric Hopper <hopper@omnifarious.org>
parents: 4435
diff changeset
  1309
            fp.write("# Branch %s\n" % branch)
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1310
        fp.write("# Node ID %s\n" % hex(node))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1311
        fp.write("# Parent  %s\n" % hex(prev))
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1312
        if len(parents) > 1:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1313
            fp.write("# Parent  %s\n" % hex(parents[1]))
3970
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1314
        fp.write(ctx.description().rstrip())
2873
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1315
        fp.write("\n\n")
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1316
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1317
        diff(repo, prev, node, fp=fp, opts=opts)
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1318
        if fp not in (sys.stdout, repo.ui):
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1319
            fp.close()
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2867
diff changeset
  1320
3900
2b3175acb653 Don't use node length for calculating revision number length.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3899
diff changeset
  1321
    for seqno, rev in enumerate(revs):
3970
fff8a5345eb0 commands.py: use contexts in export
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3967
diff changeset
  1322
        single(rev, seqno+1, fp)
3093
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1323
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1324
def diffstat(patchlines):
4482
62019c4427e3 Introduce find_exe. Use instead of find_in_path for programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4436
diff changeset
  1325
    if not util.find_exe('diffstat'):
4316
6e4334be0aaa Try to find diffstat in PATH before calling it
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4229
diff changeset
  1326
        return
3093
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1327
    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: 3063
diff changeset
  1328
    try:
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1329
        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: 3063
diff changeset
  1330
        try:
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1331
            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: 3063
diff changeset
  1332
            p.tochild.close()
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1333
            if p.wait(): return
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1334
            fp = os.fdopen(fd, 'r')
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1335
            stat = []
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1336
            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: 3063
diff changeset
  1337
            last = stat.pop()
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1338
            stat.insert(0, last)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1339
            stat = ''.join(stat)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1340
            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: 3063
diff changeset
  1341
            return stat
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1342
        except: raise
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1343
    finally:
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1344
        try: os.unlink(name)
f422c8265ae5 Add support for diffstat in commit emails, and move diffstat from
Matt Doar <matt@xensource.com>
parents: 3063
diff changeset
  1345
        except: pass