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