mercurial/patch.py
author Gregory Szorc <gregory.szorc@gmail.com>
Mon, 02 Apr 2018 16:47:53 -0700
changeset 37285 d4e62df1c73d
parent 37123 a8a902d7176e
child 37456 19becdf565ef
permissions -rw-r--r--
debugcommands: drop offset and length from debugindex by default These fields are an implementation detail of revlog storage. As such, they are not part of the generic storage "index" interface and shouldn't be displayed by default. Because we don't have another way to display these fields, we've retained support for printing these fields via --verbose. Yes, I know we should probably be doing all this formatting using modern formatting/templater APIs. I didn't feel like scope bloating this patch. Differential Revision: https://phab.mercurial-scm.org/D3028
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     1
# patch.py - patch file parsing routines
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     2
#
2865
71e78f2ca5ae merge git patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2863
diff changeset
     3
# Copyright 2006 Brendan Cully <brendan@kublai.com>
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
     4
# Copyright 2007 Chris Mason <chris.mason@oracle.com>
2865
71e78f2ca5ae merge git patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2863
diff changeset
     5
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8209
diff changeset
     6
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 10203
diff changeset
     7
# GNU General Public License version 2 or any later version.
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
     8
34152
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34146
diff changeset
     9
from __future__ import absolute_import, print_function
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    10
25113
0ca8410ea345 util: drop alias for collections.deque
Martin von Zweigbergk <martinvonz@google.com>
parents: 24845
diff changeset
    11
import collections
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    12
import copy
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
    13
import difflib
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    14
import email
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    15
import errno
29341
0d83ad967bf8 cleanup: replace uses of util.(md5|sha1|sha256|sha512) with hashlib.\1
Augie Fackler <raf@durin42.com>
parents: 29326
diff changeset
    16
import hashlib
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    17
import os
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    18
import posixpath
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    19
import re
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    20
import shutil
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    21
import tempfile
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    22
import zlib
10965
7faef79a89c7 patch: move mercurial-specific imports after stdlib imports
Augie Fackler <durin42@gmail.com>
parents: 10905
diff changeset
    23
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    24
from .i18n import _
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    25
from .node import (
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    26
    hex,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    27
    short,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    28
)
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    29
from . import (
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    30
    copies,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    31
    encoding,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    32
    error,
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27902
diff changeset
    33
    mail,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    34
    mdiff,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    35
    pathutil,
32409
017ad85e5ac8 diffhelpers: switch to policy importer
Yuya Nishihara <yuya@tcha.org>
parents: 32360
diff changeset
    36
    policy,
30944
48dea083f66d py3: convert the mode argument of os.fdopen to unicodes (1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30819
diff changeset
    37
    pycompat,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    38
    scmutil,
30807
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
    39
    similar,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    40
    util,
31243
067f2a95e32c vfs: use 'vfs' module directly in 'mercurial.patch'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31226
diff changeset
    41
    vfs as vfsmod,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    42
)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36846
diff changeset
    43
from .utils import (
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36846
diff changeset
    44
    dateutil,
37123
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37087
diff changeset
    45
    procutil,
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36846
diff changeset
    46
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36846
diff changeset
    47
)
32409
017ad85e5ac8 diffhelpers: switch to policy importer
Yuya Nishihara <yuya@tcha.org>
parents: 32360
diff changeset
    48
017ad85e5ac8 diffhelpers: switch to policy importer
Yuya Nishihara <yuya@tcha.org>
parents: 32360
diff changeset
    49
diffhelpers = policy.importmod(r'diffhelpers')
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
    50
stringio = util.stringio
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    51
31635
451c980a8b57 patch: make regular expressions bytes by adding b''
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31284
diff changeset
    52
gitre = re.compile(br'diff --git a/(.*) b/(.*)')
451c980a8b57 patch: make regular expressions bytes by adding b''
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31284
diff changeset
    53
tabsplitter = re.compile(br'(\t+|[^\t]+)')
35392
82c3762349ac patch: do not break up multibyte character when highlighting word
Yuya Nishihara <yuya@tcha.org>
parents: 35375
diff changeset
    54
_nonwordre = re.compile(br'([^a-zA-Z0-9_\x80-\xff])')
7199
dd891d0d97a3 patch: consolidate two different regexes for parsing of git diffs
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7198
diff changeset
    55
34258
61714510220d error: move patch.PatchError so it can easily implement __bytes__ (API)
Yuya Nishihara <yuya@tcha.org>
parents: 34152
diff changeset
    56
PatchError = error.PatchError
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    57
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    58
# public functions
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    59
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    60
def split(stream):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    61
    '''return an iterator of individual patches from a stream'''
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    62
    def isheader(line, inheader):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    63
        if inheader and line[0] in (' ', '\t'):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    64
            # continuation
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    65
            return True
10883
196908117c27 patch: don't look for headers in diff lines
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 10748
diff changeset
    66
        if line[0] in (' ', '-', '+'):
196908117c27 patch: don't look for headers in diff lines
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 10748
diff changeset
    67
            # diff line - don't check for header pattern in there
196908117c27 patch: don't look for headers in diff lines
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 10748
diff changeset
    68
            return False
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    69
        l = line.split(': ', 1)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    70
        return len(l) == 2 and ' ' not in l[0]
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    71
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    72
    def chunk(lines):
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
    73
        return stringio(''.join(lines))
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    74
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    75
    def hgsplit(stream, cur):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    76
        inheader = True
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    77
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    78
        for line in stream:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    79
            if not line.strip():
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    80
                inheader = False
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    81
            if not inheader and line.startswith('# HG changeset patch'):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    82
                yield chunk(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    83
                cur = []
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    84
                inheader = True
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    85
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    86
            cur.append(line)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    87
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    88
        if cur:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    89
            yield chunk(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    90
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    91
    def mboxsplit(stream, cur):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    92
        for line in stream:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    93
            if line.startswith('From '):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    94
                for c in split(chunk(cur[1:])):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    95
                    yield c
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    96
                cur = []
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    97
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    98
            cur.append(line)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    99
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   100
        if cur:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   101
            for c in split(chunk(cur[1:])):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   102
                yield c
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   103
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   104
    def mimesplit(stream, cur):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   105
        def msgfp(m):
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
   106
            fp = stringio()
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   107
            g = email.Generator.Generator(fp, mangle_from_=False)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   108
            g.flatten(m)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   109
            fp.seek(0)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   110
            return fp
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   111
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   112
        for line in stream:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   113
            cur.append(line)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   114
        c = chunk(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   115
36083
04984f2e50ae py3: use email parser that operates on bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36073
diff changeset
   116
        m = pycompat.emailparser().parse(c)
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   117
        if not m.is_multipart():
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   118
            yield msgfp(m)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   119
        else:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   120
            ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   121
            for part in m.walk():
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   122
                ct = part.get_content_type()
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   123
                if ct not in ok_types:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   124
                    continue
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   125
                yield msgfp(part)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   126
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   127
    def headersplit(stream, cur):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   128
        inheader = False
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   129
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   130
        for line in stream:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   131
            if not inheader and isheader(line, inheader):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   132
                yield chunk(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   133
                cur = []
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   134
                inheader = True
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   135
            if inheader and not isheader(line, inheader):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   136
                inheader = False
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   137
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   138
            cur.append(line)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   139
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   140
        if cur:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   141
            yield chunk(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   142
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   143
    def remainder(cur):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   144
        yield chunk(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   145
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   146
    class fiter(object):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   147
        def __init__(self, fp):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   148
            self.fp = fp
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   149
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   150
        def __iter__(self):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   151
            return self
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   152
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   153
        def next(self):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   154
            l = self.fp.readline()
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   155
            if not l:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   156
                raise StopIteration
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   157
            return l
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   158
35202
a1d2fc32bb99 py3: define __next__ in patch.py
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35085
diff changeset
   159
        __next__ = next
a1d2fc32bb99 py3: define __next__ in patch.py
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35085
diff changeset
   160
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   161
    inheader = False
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   162
    cur = []
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   163
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   164
    mimeheaders = ['content-type']
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   165
14966
0588fb0e2e8d patch: use safehasattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14832
diff changeset
   166
    if not util.safehasattr(stream, 'next'):
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   167
        # http responses, for example, have readline but not next
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   168
        stream = fiter(stream)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   169
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   170
    for line in stream:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   171
        cur.append(line)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   172
        if line.startswith('# HG changeset patch'):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   173
            return hgsplit(stream, cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   174
        elif line.startswith('From '):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   175
            return mboxsplit(stream, cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   176
        elif isheader(line, inheader):
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   177
            inheader = True
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   178
            if line.split(':', 1)[0].lower() in mimeheaders:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   179
                # let email parser handle this
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   180
                return mimesplit(stream, cur)
10501
a27af7229850 import: if in doubt, consume stream until start of diff
Brendan Cully <brendan@kublai.com>
parents: 10467
diff changeset
   181
        elif line.startswith('--- ') and inheader:
a27af7229850 import: if in doubt, consume stream until start of diff
Brendan Cully <brendan@kublai.com>
parents: 10467
diff changeset
   182
            # No evil headers seen by diff start, split by hand
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   183
            return headersplit(stream, cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   184
        # Not enough info, keep reading
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   185
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   186
    # if we are here, we have a very plain patch
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   187
    return remainder(cur)
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   188
26557
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   189
## Some facility for extensible patch parsing:
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   190
# list of pairs ("header to match", "data key")
26559
dbd4392daedf extract: parse 'branch' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26558
diff changeset
   191
patchheadermap = [('Date', 'date'),
dbd4392daedf extract: parse 'branch' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26558
diff changeset
   192
                  ('Branch', 'branch'),
26560
75d448d56a9d extract: parse 'nodeid' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26559
diff changeset
   193
                  ('Node ID', 'nodeid'),
26559
dbd4392daedf extract: parse 'branch' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26558
diff changeset
   194
                 ]
26557
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   195
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   196
def extract(ui, fileobj):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   197
    '''extract patch from data read from fileobj.
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   198
4263
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   199
    patch can be a normal patch or contained in an email message.
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   200
26781
1aee2ab0f902 spelling: trivial spell checking
Mads Kiilerich <madski@unity3d.com>
parents: 26587
diff changeset
   201
    return a dictionary. Standard keys are:
26547
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   202
      - filename,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   203
      - message,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   204
      - user,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   205
      - date,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   206
      - branch,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   207
      - node,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   208
      - p1,
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   209
      - p2.
26781
1aee2ab0f902 spelling: trivial spell checking
Mads Kiilerich <madski@unity3d.com>
parents: 26587
diff changeset
   210
    Any item can be missing from the dictionary. If filename is missing,
4263
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   211
    fileobj did not contain a patch. Caller must unlink filename when done.'''
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   212
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   213
    # attempt to detect the start of a patch
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   214
    # (this heuristic is borrowed from quilt)
35020
7ebf850d3166 patch: improve heuristics to not take the word "diff" as header (issue1879)
Yuya Nishihara <yuya@tcha.org>
parents: 34908
diff changeset
   215
    diffre = re.compile(br'^(?:Index:[ \t]|diff[ \t]-|RCS file: |'
34083
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34059
diff changeset
   216
                        br'retrieving revision [0-9]+(\.[0-9]+)*$|'
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34059
diff changeset
   217
                        br'---[ \t].*?^\+\+\+[ \t]|'
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34059
diff changeset
   218
                        br'\*\*\*[ \t].*?^---[ \t])',
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34059
diff changeset
   219
                        re.MULTILINE | re.DOTALL)
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   220
26547
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   221
    data = {}
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   222
    fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
36843
5bc7ff103081 py3: use r'' instead of sysstr('') to get around code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 36705
diff changeset
   223
    tmpfp = os.fdopen(fd, r'wb')
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   224
    try:
36083
04984f2e50ae py3: use email parser that operates on bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36073
diff changeset
   225
        msg = pycompat.emailparser().parse(fileobj)
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   226
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27902
diff changeset
   227
        subject = msg['Subject'] and mail.headdecode(msg['Subject'])
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27902
diff changeset
   228
        data['user'] = msg['From'] and mail.headdecode(msg['From'])
26556
2bef84fad19f extract: remove the 'user' variable
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26555
diff changeset
   229
        if not subject and not data['user']:
9573
b8352a3617f3 patch: do not swallow header-like patch first line (issue1859)
Patrick Mezard <pmezard@gmail.com>
parents: 9243
diff changeset
   230
            # Not an email, restore parsed headers if any
b8352a3617f3 patch: do not swallow header-like patch first line (issue1859)
Patrick Mezard <pmezard@gmail.com>
parents: 9243
diff changeset
   231
            subject = '\n'.join(': '.join(h) for h in msg.items()) + '\n'
b8352a3617f3 patch: do not swallow header-like patch first line (issue1859)
Patrick Mezard <pmezard@gmail.com>
parents: 9243
diff changeset
   232
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   233
        # should try to parse msg['Date']
4263
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   234
        parents = []
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   235
4777
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   236
        if subject:
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   237
            if subject.startswith('[PATCH'):
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   238
                pend = subject.find(']')
4208
bd9b84b9a84b Make [PATCH] removal slightly more robust
Brendan Cully <brendan@kublai.com>
parents: 4201
diff changeset
   239
                if pend >= 0:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   240
                    subject = subject[pend + 1:].lstrip()
34083
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34059
diff changeset
   241
            subject = re.sub(br'\n[ \t]+', ' ', subject)
4777
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   242
            ui.debug('Subject: %s\n' % subject)
26556
2bef84fad19f extract: remove the 'user' variable
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26555
diff changeset
   243
        if data['user']:
2bef84fad19f extract: remove the 'user' variable
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26555
diff changeset
   244
            ui.debug('From: %s\n' % data['user'])
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   245
        diffs_seen = 0
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   246
        ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
4900
e56c7e05c7e6 patch.py: re-add the ability to use an external patch program
Bryan O'Sullivan <bos@serpentine.com>
parents: 4899
diff changeset
   247
        message = ''
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   248
        for part in msg.walk():
36073
95791b275b73 py3: convert content-type to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35990
diff changeset
   249
            content_type = pycompat.bytestr(part.get_content_type())
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   250
            ui.debug('Content-Type: %s\n' % content_type)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   251
            if content_type not in ok_types:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   252
                continue
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   253
            payload = part.get_payload(decode=True)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   254
            m = diffre.search(payload)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   255
            if m:
4220
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4208
diff changeset
   256
                hgpatch = False
12645
d7452292f9d3 import: don't strip '#' lines from patch descriptions (issue 2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12577
diff changeset
   257
                hgpatchheader = False
4220
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4208
diff changeset
   258
                ignoretext = False
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4208
diff changeset
   259
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9393
diff changeset
   260
                ui.debug('found patch at byte %d\n' % m.start(0))
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   261
                diffs_seen += 1
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
   262
                cfp = stringio()
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   263
                for line in payload[:m.start(0)].splitlines():
12728
80a3d1121c10 import: only the first hg patch marker should be processed (issue2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12675
diff changeset
   264
                    if line.startswith('# HG changeset patch') and not hgpatch:
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9393
diff changeset
   265
                        ui.debug('patch generated by hg export\n')
12728
80a3d1121c10 import: only the first hg patch marker should be processed (issue2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12675
diff changeset
   266
                        hgpatch = True
12645
d7452292f9d3 import: don't strip '#' lines from patch descriptions (issue 2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12577
diff changeset
   267
                        hgpatchheader = True
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   268
                        # drop earlier commit message content
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   269
                        cfp.seek(0)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   270
                        cfp.truncate()
4778
e321f16f4eac patch.extract: fix test-import breakage introduced in the previous changeset
Brendan Cully <brendan@kublai.com>
parents: 4777
diff changeset
   271
                        subject = None
12645
d7452292f9d3 import: don't strip '#' lines from patch descriptions (issue 2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12577
diff changeset
   272
                    elif hgpatchheader:
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   273
                        if line.startswith('# User '):
26556
2bef84fad19f extract: remove the 'user' variable
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26555
diff changeset
   274
                            data['user'] = line[7:]
2bef84fad19f extract: remove the 'user' variable
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26555
diff changeset
   275
                            ui.debug('From: %s\n' % data['user'])
4263
47ba52121433 Add import --exact.
Brendan Cully <brendan@kublai.com>
parents: 4232
diff changeset
   276
                        elif line.startswith("# Parent "):
16475
1f75c1decdeb patch: be more tolerant with "Parent" header (issue3356)
Patrick Mezard <patrick@mezard.eu>
parents: 16358
diff changeset
   277
                            parents.append(line[9:].lstrip())
26557
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   278
                        elif line.startswith("# "):
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   279
                            for header, key in patchheadermap:
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   280
                                prefix = '# %s ' % header
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   281
                                if line.startswith(prefix):
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   282
                                    data[key] = line[len(prefix):]
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   283
                        else:
12645
d7452292f9d3 import: don't strip '#' lines from patch descriptions (issue 2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12577
diff changeset
   284
                            hgpatchheader = False
19513
9e8298a324ac import: cut commit messages at --- unconditionally (issue2148)
Matt Mackall <mpm@selenic.com>
parents: 19155
diff changeset
   285
                    elif line == '---':
4220
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4208
diff changeset
   286
                        ignoretext = True
12645
d7452292f9d3 import: don't strip '#' lines from patch descriptions (issue 2417)
Mads Kiilerich <mads@kiilerich.com>
parents: 12577
diff changeset
   287
                    if not hgpatchheader and not ignoretext:
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   288
                        cfp.write(line)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   289
                        cfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   290
                message = cfp.getvalue()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   291
                if tmpfp:
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   292
                    tmpfp.write(payload)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   293
                    if not payload.endswith('\n'):
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   294
                        tmpfp.write('\n')
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   295
            elif not diffs_seen and message and content_type == 'text/plain':
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   296
                message += '\n' + payload
16705
c2d9ef43ff6c check-code: ignore naked excepts with a "re-raise" comment
Brodie Rao <brodie@sf.io>
parents: 16687
diff changeset
   297
    except: # re-raises
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   298
        tmpfp.close()
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   299
        os.unlink(tmpname)
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   300
        raise
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   301
4777
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   302
    if subject and not message.startswith(subject):
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   303
        message = '%s\n%s' % (subject, message)
26549
1a680ccdb09a extract: assign message only once
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26548
diff changeset
   304
    data['message'] = message
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   305
    tmpfp.close()
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
   306
    if parents:
26550
72782f60dbc9 extract: directly assign parent to data dictionary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26549
diff changeset
   307
        data['p1'] = parents.pop(0)
26548
25a58881efdd extract: simplify parents assignement
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26547
diff changeset
   308
        if parents:
26550
72782f60dbc9 extract: directly assign parent to data dictionary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26549
diff changeset
   309
            data['p2'] = parents.pop(0)
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
   310
26555
1e33384ff2ed extract: use a single return
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26554
diff changeset
   311
    if diffs_seen:
1e33384ff2ed extract: use a single return
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26554
diff changeset
   312
        data['filename'] = tmpname
1e33384ff2ed extract: use a single return
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26554
diff changeset
   313
    else:
1e33384ff2ed extract: use a single return
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26554
diff changeset
   314
        os.unlink(tmpname)
26547
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   315
    return data
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   316
8778
c5f36402daad use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 8761
diff changeset
   317
class patchmeta(object):
7148
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   318
    """Patched file metadata
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   319
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   320
    'op' is the performed operation within ADD, DELETE, RENAME, MODIFY
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   321
    or COPY.  'path' is patched file path. 'oldpath' is set to the
7149
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   322
    origin file when 'op' is either COPY or RENAME, None otherwise. If
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   323
    file mode is changed, 'mode' is a tuple (islink, isexec) where
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   324
    'islink' is True if the file is a symlink and 'isexec' is True if
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   325
    the file is executable. Otherwise, 'mode' is None.
7148
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   326
    """
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   327
    def __init__(self, path):
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   328
        self.path = path
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   329
        self.oldpath = None
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   330
        self.mode = None
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   331
        self.op = 'MODIFY'
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   332
        self.binary = False
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   333
7149
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   334
    def setmode(self, mode):
25658
e93036747902 global: mass rewrite to use modern octal syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25644
diff changeset
   335
        islink = mode & 0o20000
e93036747902 global: mass rewrite to use modern octal syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25644
diff changeset
   336
        isexec = mode & 0o100
7149
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   337
        self.mode = (islink, isexec)
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   338
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   339
    def copy(self):
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   340
        other = patchmeta(self.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   341
        other.oldpath = self.oldpath
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   342
        other.mode = self.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   343
        other.op = self.op
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   344
        other.binary = self.binary
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   345
        return other
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   346
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   347
    def _ispatchinga(self, afile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   348
        if afile == '/dev/null':
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   349
            return self.op == 'ADD'
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   350
        return afile == 'a/' + (self.oldpath or self.path)
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   351
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   352
    def _ispatchingb(self, bfile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   353
        if bfile == '/dev/null':
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   354
            return self.op == 'DELETE'
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   355
        return bfile == 'b/' + self.path
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   356
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   357
    def ispatching(self, afile, bfile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   358
        return self._ispatchinga(afile) and self._ispatchingb(bfile)
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   359
11018
17cf756ba25d patch: descriptive patchmeta.__repr__ to help debugging
Mads Kiilerich <mads@kiilerich.com>
parents: 10966
diff changeset
   360
    def __repr__(self):
17cf756ba25d patch: descriptive patchmeta.__repr__ to help debugging
Mads Kiilerich <mads@kiilerich.com>
parents: 10966
diff changeset
   361
        return "<patchmeta %s %r>" % (self.op, self.path)
17cf756ba25d patch: descriptive patchmeta.__repr__ to help debugging
Mads Kiilerich <mads@kiilerich.com>
parents: 10966
diff changeset
   362
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
   363
def readgitpatch(lr):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   364
    """extract git-style metadata about patches from <patchname>"""
3223
53e843840349 Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3199
diff changeset
   365
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   366
    # Filter patch for git information
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   367
    gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   368
    gitpatches = []
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
   369
    for line in lr:
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   370
        line = line.rstrip(' \r\n')
18830
6b827d84d286 patch: match 'diff --git a/' instead of 'diff --git'
Sean Farley <sean.michael.farley@gmail.com>
parents: 18824
diff changeset
   371
        if line.startswith('diff --git a/'):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   372
            m = gitre.match(line)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   373
            if m:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   374
                if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   375
                    gitpatches.append(gp)
9392
039bce1b505f patch: readgitpatch: remove unused variable 'src'
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9331
diff changeset
   376
                dst = m.group(2)
7148
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   377
                gp = patchmeta(dst)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   378
        elif gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   379
            if line.startswith('--- '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   380
                gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   381
                gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   382
                continue
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   383
            if line.startswith('rename from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   384
                gp.op = 'RENAME'
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   385
                gp.oldpath = line[12:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   386
            elif line.startswith('rename to '):
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   387
                gp.path = line[10:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   388
            elif line.startswith('copy from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   389
                gp.op = 'COPY'
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   390
                gp.oldpath = line[10:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   391
            elif line.startswith('copy to '):
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   392
                gp.path = line[8:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   393
            elif line.startswith('deleted file'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   394
                gp.op = 'DELETE'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   395
            elif line.startswith('new file mode '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   396
                gp.op = 'ADD'
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   397
                gp.setmode(int(line[-6:], 8))
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   398
            elif line.startswith('new mode '):
9243
df21a009c9c4 fix issue 1763: strip chars from end of line when parsing gitpatch lines
Bill Barry <after.fallout@gmail.com>
parents: 9123
diff changeset
   399
                gp.setmode(int(line[-6:], 8))
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   400
            elif line.startswith('GIT binary patch'):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   401
                gp.binary = True
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   402
    if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   403
        gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   404
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
   405
    return gitpatches
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   406
8891
5fe8dc75aa4a patch: use new style class in linereader
Simon Heimberg <simohe@besonet.ch>
parents: 8843
diff changeset
   407
class linereader(object):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   408
    # simple class to allow pushing lines back into the input stream
14418
0174d1f79280 patch: remove EOL support from linereader class
Patrick Mezard <pmezard@gmail.com>
parents: 14402
diff changeset
   409
    def __init__(self, fp):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   410
        self.fp = fp
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   411
        self.buf = []
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   412
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   413
    def push(self, line):
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   414
        if line is not None:
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   415
            self.buf.append(line)
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   416
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   417
    def readline(self):
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   418
        if self.buf:
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   419
            l = self.buf[0]
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   420
            del self.buf[0]
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   421
            return l
14418
0174d1f79280 patch: remove EOL support from linereader class
Patrick Mezard <pmezard@gmail.com>
parents: 14402
diff changeset
   422
        return self.fp.readline()
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   423
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   424
    def __iter__(self):
29738
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
   425
        return iter(self.readline, '')
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   426
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   427
class abstractbackend(object):
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   428
    def __init__(self, ui):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   429
        self.ui = ui
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   430
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   431
    def getfile(self, fname):
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   432
        """Return target file data and flags as a (data, (islink,
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   433
        isexec)) tuple. Data is None if file is missing/deleted.
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   434
        """
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   435
        raise NotImplementedError
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   436
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   437
    def setfile(self, fname, data, mode, copysource):
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   438
        """Write data to target file fname and set its mode. mode is a
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   439
        (islink, isexec) tuple. If data is None, the file content should
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   440
        be left unchanged. If the file is modified after being copied,
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   441
        copysource is set to the original file name.
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   442
        """
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   443
        raise NotImplementedError
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   444
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   445
    def unlink(self, fname):
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   446
        """Unlink target file."""
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   447
        raise NotImplementedError
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   448
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   449
    def writerej(self, fname, failed, total, lines):
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   450
        """Write rejected lines for fname. total is the number of hunks
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   451
        which failed to apply and total the total number of hunks for this
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   452
        files.
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   453
        """
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   454
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   455
    def exists(self, fname):
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   456
        raise NotImplementedError
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   457
33161
b8ae289a7707 patch: add close() to abstractbackend
Martin von Zweigbergk <martinvonz@google.com>
parents: 33116
diff changeset
   458
    def close(self):
b8ae289a7707 patch: add close() to abstractbackend
Martin von Zweigbergk <martinvonz@google.com>
parents: 33116
diff changeset
   459
        raise NotImplementedError
b8ae289a7707 patch: add close() to abstractbackend
Martin von Zweigbergk <martinvonz@google.com>
parents: 33116
diff changeset
   460
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   461
class fsbackend(abstractbackend):
14350
00da6624e167 patch: move copyfile() into backends, abstract basedir
Patrick Mezard <pmezard@gmail.com>
parents: 14349
diff changeset
   462
    def __init__(self, ui, basedir):
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   463
        super(fsbackend, self).__init__(ui)
31243
067f2a95e32c vfs: use 'vfs' module directly in 'mercurial.patch'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31226
diff changeset
   464
        self.opener = vfsmod.vfs(basedir)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   465
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   466
    def getfile(self, fname):
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   467
        if self.opener.islink(fname):
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   468
            return (self.opener.readlink(fname), (True, False))
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   469
14531
b88368a3ade4 patch: remove redundant islink() call
Patrick Mezard <pmezard@gmail.com>
parents: 14494
diff changeset
   470
        isexec = False
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   471
        try:
25658
e93036747902 global: mass rewrite to use modern octal syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25644
diff changeset
   472
            isexec = self.opener.lstat(fname).st_mode & 0o100 != 0
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25658
diff changeset
   473
        except OSError as e:
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   474
            if e.errno != errno.ENOENT:
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   475
                raise
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   476
        try:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   477
            return (self.opener.read(fname), (False, isexec))
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25658
diff changeset
   478
        except IOError as e:
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   479
            if e.errno != errno.ENOENT:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   480
                raise
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   481
            return None, None
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   482
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   483
    def setfile(self, fname, data, mode, copysource):
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   484
        islink, isexec = mode
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   485
        if data is None:
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   486
            self.opener.setflags(fname, islink, isexec)
14390
ce77c275bec3 patch: merge backend setmode() into writelines()
Patrick Mezard <pmezard@gmail.com>
parents: 14389
diff changeset
   487
            return
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   488
        if islink:
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   489
            self.opener.symlink(data, fname)
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   490
        else:
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   491
            self.opener.write(fname, data)
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   492
            if isexec:
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   493
                self.opener.setflags(fname, False, True)
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   494
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   495
    def unlink(self, fname):
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   496
        self.opener.unlinkpath(fname, ignoremissing=True)
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   497
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   498
    def writerej(self, fname, failed, total, lines):
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   499
        fname = fname + ".rej"
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   500
        self.ui.warn(
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   501
            _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   502
            (failed, total, fname))
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   503
        fp = self.opener(fname, 'w')
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   504
        fp.writelines(lines)
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   505
        fp.close()
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   506
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   507
    def exists(self, fname):
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   508
        return self.opener.lexists(fname)
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   509
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   510
class workingbackend(fsbackend):
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   511
    def __init__(self, ui, repo, similarity):
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   512
        super(workingbackend, self).__init__(ui, repo.root)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   513
        self.repo = repo
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   514
        self.similarity = similarity
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   515
        self.removed = set()
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   516
        self.changed = set()
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   517
        self.copied = []
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   518
14453
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   519
    def _checkknown(self, fname):
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   520
        if self.repo.dirstate[fname] == '?' and self.exists(fname):
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   521
            raise PatchError(_('cannot patch %s: file is not tracked') % fname)
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   522
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   523
    def setfile(self, fname, data, mode, copysource):
14453
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   524
        self._checkknown(fname)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   525
        super(workingbackend, self).setfile(fname, data, mode, copysource)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   526
        if copysource is not None:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   527
            self.copied.append((copysource, fname))
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   528
        self.changed.add(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   529
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   530
    def unlink(self, fname):
14453
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   531
        self._checkknown(fname)
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   532
        super(workingbackend, self).unlink(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   533
        self.removed.add(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   534
        self.changed.add(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   535
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   536
    def close(self):
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   537
        wctx = self.repo[None]
19155
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   538
        changed = set(self.changed)
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   539
        for src, dst in self.copied:
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   540
            scmutil.dirstatecopy(self.ui, self.repo, wctx, src, dst)
16112
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   541
        if self.removed:
14435
5f6090e559fa context: make forget work like commands.forget
Matt Mackall <mpm@selenic.com>
parents: 14418
diff changeset
   542
            wctx.forget(sorted(self.removed))
16112
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   543
            for f in self.removed:
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   544
                if f not in self.repo.dirstate:
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   545
                    # File was deleted and no longer belongs to the
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   546
                    # dirstate, it was probably marked added then
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   547
                    # deleted, and should not be considered by
19155
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   548
                    # marktouched().
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   549
                    changed.discard(f)
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   550
        if changed:
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   551
            scmutil.marktouched(self.repo, changed, self.similarity)
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   552
        return sorted(self.changed)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   553
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   554
class filestore(object):
14658
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   555
    def __init__(self, maxsize=None):
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   556
        self.opener = None
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   557
        self.files = {}
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   558
        self.created = 0
14658
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   559
        self.maxsize = maxsize
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   560
        if self.maxsize is None:
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   561
            self.maxsize = 4*(2**20)
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   562
        self.size = 0
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   563
        self.data = {}
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   564
14609
f53dc0787424 patch: extend filtestore to store an optional copy source
Patrick Mezard <pmezard@gmail.com>
parents: 14566
diff changeset
   565
    def setfile(self, fname, data, mode, copied=None):
14658
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   566
        if self.maxsize < 0 or (len(data) + self.size) <= self.maxsize:
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   567
            self.data[fname] = (data, mode, copied)
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   568
            self.size += len(data)
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   569
        else:
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   570
            if self.opener is None:
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   571
                root = tempfile.mkdtemp(prefix='hg-patch-')
31243
067f2a95e32c vfs: use 'vfs' module directly in 'mercurial.patch'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31226
diff changeset
   572
                self.opener = vfsmod.vfs(root)
14658
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   573
            # Avoid filename issues with these simple names
36453
2831d918e1b4 py3: convert known-int values to bytes using %d
Augie Fackler <augie@google.com>
parents: 36267
diff changeset
   574
            fn = '%d' % self.created
14658
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   575
            self.opener.write(fn, data)
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   576
            self.created += 1
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   577
            self.files[fname] = (fn, mode, copied)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   578
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   579
    def getfile(self, fname):
14658
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   580
        if fname in self.data:
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   581
            return self.data[fname]
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   582
        if not self.opener or fname not in self.files:
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   583
            return None, None, None
14609
f53dc0787424 patch: extend filtestore to store an optional copy source
Patrick Mezard <pmezard@gmail.com>
parents: 14566
diff changeset
   584
        fn, mode, copied = self.files[fname]
f53dc0787424 patch: extend filtestore to store an optional copy source
Patrick Mezard <pmezard@gmail.com>
parents: 14566
diff changeset
   585
        return self.opener.read(fn), mode, copied
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   586
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   587
    def close(self):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   588
        if self.opener:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   589
            shutil.rmtree(self.opener.base)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   590
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   591
class repobackend(abstractbackend):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   592
    def __init__(self, ui, repo, ctx, store):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   593
        super(repobackend, self).__init__(ui)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   594
        self.repo = repo
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   595
        self.ctx = ctx
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   596
        self.store = store
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   597
        self.changed = set()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   598
        self.removed = set()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   599
        self.copied = {}
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   600
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   601
    def _checkknown(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   602
        if fname not in self.ctx:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   603
            raise PatchError(_('cannot patch %s: file is not tracked') % fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   604
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   605
    def getfile(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   606
        try:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   607
            fctx = self.ctx[fname]
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   608
        except error.LookupError:
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   609
            return None, None
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   610
        flags = fctx.flags()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   611
        return fctx.data(), ('l' in flags, 'x' in flags)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   612
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   613
    def setfile(self, fname, data, mode, copysource):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   614
        if copysource:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   615
            self._checkknown(copysource)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   616
        if data is None:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   617
            data = self.ctx[fname].data()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   618
        self.store.setfile(fname, data, mode, copysource)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   619
        self.changed.add(fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   620
        if copysource:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   621
            self.copied[fname] = copysource
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   622
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   623
    def unlink(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   624
        self._checkknown(fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   625
        self.removed.add(fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   626
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   627
    def exists(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   628
        return fname in self.ctx
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   629
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   630
    def close(self):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   631
        return self.changed | self.removed
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   632
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   633
# @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
   634
unidesc = re.compile('@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@')
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
   635
contextdesc = re.compile('(?:---|\*\*\*) (\d+)(?:,(\d+))? (?:---|\*\*\*)')
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   636
eolmodes = ['strict', 'crlf', 'lf', 'auto']
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   637
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   638
class patchfile(object):
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   639
    def __init__(self, ui, gp, backend, store, eolmode='strict'):
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   640
        self.fname = gp.path
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   641
        self.eolmode = eolmode
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   642
        self.eol = None
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   643
        self.backend = backend
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   644
        self.ui = ui
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   645
        self.lines = []
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   646
        self.exists = False
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   647
        self.missing = True
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   648
        self.mode = gp.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   649
        self.copysource = gp.oldpath
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   650
        self.create = gp.op in ('ADD', 'COPY', 'RENAME')
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   651
        self.remove = gp.op == 'DELETE'
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   652
        if self.copysource is None:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   653
            data, mode = backend.getfile(self.fname)
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   654
        else:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   655
            data, mode = store.getfile(self.copysource)[:2]
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   656
        if data is not None:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   657
            self.exists = self.copysource is None or backend.exists(self.fname)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   658
            self.missing = False
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   659
            if data:
14832
d60e4f227d75 patch: fix parsing patch files containing CRs not followed by LFs
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 14764
diff changeset
   660
                self.lines = mdiff.splitnewlines(data)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   661
            if self.mode is None:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   662
                self.mode = mode
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   663
            if self.lines:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   664
                # Normalize line endings
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   665
                if self.lines[0].endswith('\r\n'):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   666
                    self.eol = '\r\n'
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   667
                elif self.lines[0].endswith('\n'):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   668
                    self.eol = '\n'
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   669
                if eolmode != 'strict':
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   670
                    nlines = []
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   671
                    for l in self.lines:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   672
                        if l.endswith('\r\n'):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   673
                            l = l[:-2] + '\n'
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   674
                        nlines.append(l)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   675
                    self.lines = nlines
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   676
        else:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   677
            if self.create:
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   678
                self.missing = False
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   679
            if self.mode is None:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   680
                self.mode = (False, False)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   681
        if self.missing:
17299
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
   682
            self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
29904
50f2966f86ca import: report directory-relative paths in error messages (issue5224)
liscju <piotr.listkiewicz@gmail.com>
parents: 29738
diff changeset
   683
            self.ui.warn(_("(use '--prefix' to apply patch relative to the "
50f2966f86ca import: report directory-relative paths in error messages (issue5224)
liscju <piotr.listkiewicz@gmail.com>
parents: 29738
diff changeset
   684
                           "current directory)\n"))
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   685
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   686
        self.hash = {}
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   687
        self.dirty = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   688
        self.offset = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   689
        self.skew = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   690
        self.rej = []
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   691
        self.fileprinted = False
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   692
        self.printfile(False)
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   693
        self.hunks = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   694
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   695
    def writelines(self, fname, lines, mode):
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   696
        if self.eolmode == 'auto':
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   697
            eol = self.eol
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   698
        elif self.eolmode == 'crlf':
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   699
            eol = '\r\n'
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   700
        else:
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   701
            eol = '\n'
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   702
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   703
        if self.eolmode != 'strict' and eol and eol != '\n':
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   704
            rawlines = []
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   705
            for l in lines:
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   706
                if l and l[-1] == '\n':
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   707
                    l = l[:-1] + eol
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   708
                rawlines.append(l)
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   709
            lines = rawlines
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   710
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   711
        self.backend.setfile(fname, ''.join(lines), mode, self.copysource)
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   712
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   713
    def printfile(self, warn):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   714
        if self.fileprinted:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   715
            return
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   716
        if warn or self.ui.verbose:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   717
            self.fileprinted = True
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   718
        s = _("patching file %s\n") % self.fname
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   719
        if warn:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   720
            self.ui.warn(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   721
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   722
            self.ui.note(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   723
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   724
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   725
    def findlines(self, l, linenum):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   726
        # looks through the hash and finds candidate lines.  The
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   727
        # result is a list of line numbers sorted based on distance
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   728
        # from linenum
5143
d4fa6bafc43a Remove trailing spaces, fix indentation
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5116
diff changeset
   729
9681
ac3a68cb16eb patch: simplify logic
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9642
diff changeset
   730
        cand = self.hash.get(l, [])
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   731
        if len(cand) > 1:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   732
            # resort our list of potentials forward then back.
9032
1fa80c5428b8 compat: use 'key' argument instead of 'cmp' when sorting a list
Alejandro Santos <alejolp@alejolp.com>
parents: 9031
diff changeset
   733
            cand.sort(key=lambda x: abs(x - linenum))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   734
        return cand
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   735
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   736
    def write_rej(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   737
        # our rejects are a little different from patch(1).  This always
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   738
        # creates rejects in the same form as the original patch.  A file
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   739
        # header is inserted so that you can run the reject through patch again
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   740
        # without having to type the filename.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   741
        if not self.rej:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   742
            return
14349
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   743
        base = os.path.basename(self.fname)
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   744
        lines = ["--- %s\n+++ %s\n" % (base, base)]
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   745
        for x in self.rej:
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   746
            for l in x.hunk:
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   747
                lines.append(l)
31720
6c80f985a13c diff: slice over bytes to make sure conditions work normally
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31636
diff changeset
   748
                if l[-1:] != '\n':
14349
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   749
                    lines.append("\n\ No newline at end of file\n")
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   750
        self.backend.writerej(self.fname, len(self.rej), self.hunks, lines)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   751
9393
23c4e772c172 patch: remove the unused, broken reverse() function
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9392
diff changeset
   752
    def apply(self, h):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   753
        if not h.complete():
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   754
            raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   755
                            (h.number, h.desc, len(h.a), h.lena, len(h.b),
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   756
                            h.lenb))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   757
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   758
        self.hunks += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   759
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   760
        if self.missing:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   761
            self.rej.append(h)
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   762
            return -1
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   763
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
   764
        if self.exists and self.create:
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   765
            if self.copysource:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   766
                self.ui.warn(_("cannot create %s: destination already "
20869
9658a79968c6 i18n: fix "% inside _()" problems
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20137
diff changeset
   767
                               "exists\n") % self.fname)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   768
            else:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   769
                self.ui.warn(_("file %s already exists\n") % self.fname)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   770
            self.rej.append(h)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   771
            return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   772
9585
ea1935e2020a patch: handle symlinks without symlinkhunk
Patrick Mezard <pmezard@gmail.com>
parents: 9573
diff changeset
   773
        if isinstance(h, binhunk):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
   774
            if self.remove:
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   775
                self.backend.unlink(self.fname)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   776
            else:
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
   777
                l = h.new(self.lines)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
   778
                self.lines[:] = l
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
   779
                self.offset += len(l)
14217
71d5287351e9 patchfile: use real Booleans instead of 0/1
Martin Geisler <mg@aragost.com>
parents: 14017
diff changeset
   780
                self.dirty = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   781
            return 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   782
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   783
        horig = h
10128
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
   784
        if (self.eolmode in ('crlf', 'lf')
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
   785
            or self.eolmode == 'auto' and self.eol):
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
   786
            # If new eols are going to be normalized, then normalize
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
   787
            # hunk data before patching. Otherwise, preserve input
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
   788
            # line-endings.
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   789
            h = h.getnormalized()
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   790
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   791
        # fast case first, no offsets, no fuzz
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   792
        old, oldstart, new, newstart = h.fuzzit(0, False)
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   793
        oldstart += self.offset
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   794
        orig_start = oldstart
10135
9a4034b630c4 patch: better handling of sequence of offset patch hunks (issue1941)
Greg Onufer <gonufer@jazzhaiku.com>
parents: 9725
diff changeset
   795
        # if there's skew we want to emit the "(offset %d lines)" even
9a4034b630c4 patch: better handling of sequence of offset patch hunks (issue1941)
Greg Onufer <gonufer@jazzhaiku.com>
parents: 9725
diff changeset
   796
        # when the hunk cleanly applies at start + skew, so skip the
9a4034b630c4 patch: better handling of sequence of offset patch hunks (issue1941)
Greg Onufer <gonufer@jazzhaiku.com>
parents: 9725
diff changeset
   797
        # fast case code
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   798
        if (self.skew == 0 and
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   799
            diffhelpers.testhunk(old, self.lines, oldstart) == 0):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
   800
            if self.remove:
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   801
                self.backend.unlink(self.fname)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   802
            else:
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   803
                self.lines[oldstart:oldstart + len(old)] = new
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   804
                self.offset += len(new) - len(old)
14217
71d5287351e9 patchfile: use real Booleans instead of 0/1
Martin Geisler <mg@aragost.com>
parents: 14017
diff changeset
   805
                self.dirty = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   806
            return 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   807
13700
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   808
        # ok, we couldn't match the hunk. Lets look for offsets and fuzz it
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   809
        self.hash = {}
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   810
        for x, s in enumerate(self.lines):
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   811
            self.hash.setdefault(s, []).append(x)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   812
33006
1d5d7e2b7ab5 configitems: register 'patch.fuzz' as first example for 'configint'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32997
diff changeset
   813
        for fuzzlen in xrange(self.ui.configint("patch", "fuzz") + 1):
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   814
            for toponly in [True, False]:
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   815
                old, oldstart, new, newstart = h.fuzzit(fuzzlen, toponly)
16123
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   816
                oldstart = oldstart + self.offset + self.skew
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   817
                oldstart = min(oldstart, len(self.lines))
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   818
                if old:
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   819
                    cand = self.findlines(old[0][1:], oldstart)
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   820
                else:
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   821
                    # Only adding lines with no or fuzzed context, just
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   822
                    # take the skew in account
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   823
                    cand = [oldstart]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   824
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   825
                for l in cand:
16123
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   826
                    if not old or diffhelpers.testhunk(old, self.lines, l) == 0:
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
   827
                        self.lines[l : l + len(old)] = new
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
   828
                        self.offset += len(new) - len(old)
10135
9a4034b630c4 patch: better handling of sequence of offset patch hunks (issue1941)
Greg Onufer <gonufer@jazzhaiku.com>
parents: 9725
diff changeset
   829
                        self.skew = l - orig_start
14217
71d5287351e9 patchfile: use real Booleans instead of 0/1
Martin Geisler <mg@aragost.com>
parents: 14017
diff changeset
   830
                        self.dirty = True
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   831
                        offset = l - orig_start - fuzzlen
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   832
                        if fuzzlen:
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   833
                            msg = _("Hunk #%d succeeded at %d "
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   834
                                    "with fuzz %d "
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   835
                                    "(offset %d lines).\n")
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   836
                            self.printfile(True)
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   837
                            self.ui.warn(msg %
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   838
                                (h.number, l + 1, fuzzlen, offset))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   839
                        else:
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   840
                            msg = _("Hunk #%d succeeded at %d "
8090
388bb482024e patch, i18n: avoid parameterized plural
Wagner Bruna <wbruna@yahoo.com>
parents: 7972
diff changeset
   841
                                    "(offset %d lines).\n")
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   842
                            self.ui.note(msg % (h.number, l + 1, offset))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   843
                        return fuzzlen
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   844
        self.printfile(True)
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   845
        self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   846
        self.rej.append(horig)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   847
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   848
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   849
    def close(self):
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   850
        if self.dirty:
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   851
            self.writelines(self.fname, self.lines, self.mode)
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   852
        self.write_rej()
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   853
        return len(self.rej)
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   854
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   855
class header(object):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   856
    """patch header
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   857
    """
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   858
    diffgit_re = re.compile('diff --git a/(.*) b/(.*)$')
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   859
    diff_re = re.compile('diff -r .* (.*)$')
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   860
    allhunks_re = re.compile('(?:index|deleted file) ')
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   861
    pretty_re = re.compile('(?:new file|deleted file) ')
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   862
    special_re = re.compile('(?:index|deleted|copy|rename) ')
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   863
    newfile_re = re.compile('(?:new file)')
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   864
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   865
    def __init__(self, header):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   866
        self.header = header
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   867
        self.hunks = []
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   868
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   869
    def binary(self):
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   870
        return any(h.startswith('index ') for h in self.header)
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   871
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   872
    def pretty(self, fp):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   873
        for h in self.header:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   874
            if h.startswith('index '):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   875
                fp.write(_('this modifies a binary file (all or nothing)\n'))
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   876
                break
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   877
            if self.pretty_re.match(h):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   878
                fp.write(h)
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   879
                if self.binary():
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   880
                    fp.write(_('this is a binary file\n'))
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   881
                break
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   882
            if h.startswith('---'):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   883
                fp.write(_('%d hunks, %d lines changed\n') %
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   884
                         (len(self.hunks),
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   885
                          sum([max(h.added, h.removed) for h in self.hunks])))
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   886
                break
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   887
            fp.write(h)
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   888
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   889
    def write(self, fp):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   890
        fp.write(''.join(self.header))
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   891
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   892
    def allhunks(self):
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   893
        return any(self.allhunks_re.match(h) for h in self.header)
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   894
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   895
    def files(self):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   896
        match = self.diffgit_re.match(self.header[0])
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   897
        if match:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   898
            fromfile, tofile = match.groups()
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   899
            if fromfile == tofile:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   900
                return [fromfile]
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   901
            return [fromfile, tofile]
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   902
        else:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   903
            return self.diff_re.match(self.header[0]).groups()
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   904
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   905
    def filename(self):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   906
        return self.files()[-1]
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   907
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   908
    def __repr__(self):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   909
        return '<header %s>' % (' '.join(map(repr, self.files())))
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   910
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   911
    def isnewfile(self):
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   912
        return any(self.newfile_re.match(h) for h in self.header)
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   913
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   914
    def special(self):
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   915
        # Special files are shown only at the header level and not at the hunk
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   916
        # level for example a file that has been deleted is a special file.
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   917
        # The user cannot change the content of the operation, in the case of
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   918
        # the deleted file he has to take the deletion or not take it, he
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   919
        # cannot take some of it.
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   920
        # Newly added files are special if they are empty, they are not special
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   921
        # if they have some content as we want to be able to change it
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   922
        nocontent = len(self.header) == 2
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   923
        emptynewfile = self.isnewfile() and nocontent
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   924
        return emptynewfile or \
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   925
                any(self.special_re.match(h) for h in self.header)
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   926
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   927
class recordhunk(object):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   928
    """patch hunk
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   929
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   930
    XXX shouldn't we merge this with the other hunk class?
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   931
    """
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   932
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   933
    def __init__(self, header, fromline, toline, proc, before, hunk, after,
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   934
                 maxcontext=None):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   935
        def trimcontext(lines, reverse=False):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   936
            if maxcontext is not None:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   937
                delta = len(lines) - maxcontext
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   938
                if delta > 0:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   939
                    if reverse:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   940
                        return delta, lines[delta:]
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   941
                    else:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   942
                        return delta, lines[:maxcontext]
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   943
            return 0, lines
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   944
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   945
        self.header = header
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   946
        trimedbefore, self.before = trimcontext(before, True)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   947
        self.fromline = fromline + trimedbefore
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   948
        self.toline = toline + trimedbefore
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   949
        _trimedafter, self.after = trimcontext(after, False)
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   950
        self.proc = proc
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   951
        self.hunk = hunk
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   952
        self.added, self.removed = self.countchanges(self.hunk)
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   953
24346
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   954
    def __eq__(self, v):
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   955
        if not isinstance(v, recordhunk):
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   956
            return False
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   957
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   958
        return ((v.hunk == self.hunk) and
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   959
                (v.proc == self.proc) and
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   960
                (self.fromline == v.fromline) and
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   961
                (self.header.files() == v.header.files()))
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   962
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   963
    def __hash__(self):
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   964
        return hash((tuple(self.hunk),
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   965
            tuple(self.header.files()),
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   966
            self.fromline,
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   967
            self.proc))
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   968
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   969
    def countchanges(self, hunk):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   970
        """hunk -> (n+,n-)"""
34259
c43d055ae405 py3: stop using bytes[n] in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34258
diff changeset
   971
        add = len([h for h in hunk if h.startswith('+')])
c43d055ae405 py3: stop using bytes[n] in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34258
diff changeset
   972
        rem = len([h for h in hunk if h.startswith('-')])
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   973
        return add, rem
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   974
32997
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   975
    def reversehunk(self):
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   976
        """return another recordhunk which is the reverse of the hunk
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   977
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   978
        If this hunk is diff(A, B), the returned hunk is diff(B, A). To do
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   979
        that, swap fromline/toline and +/- signs while keep other things
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   980
        unchanged.
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   981
        """
33671
5707bfe04deb record: fix revert -i for lines without newline (issue5651)
Jun Wu <quark@fb.com>
parents: 33584
diff changeset
   982
        m = {'+': '-', '-': '+', '\\': '\\'}
34259
c43d055ae405 py3: stop using bytes[n] in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34258
diff changeset
   983
        hunk = ['%s%s' % (m[l[0:1]], l[1:]) for l in self.hunk]
32997
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   984
        return recordhunk(self.header, self.toline, self.fromline, self.proc,
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   985
                          self.before, hunk, self.after)
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
   986
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   987
    def write(self, fp):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   988
        delta = len(self.before) + len(self.after)
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   989
        if self.after and self.after[-1] == '\\ No newline at end of file\n':
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   990
            delta -= 1
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   991
        fromlen = delta + self.removed
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   992
        tolen = delta + self.added
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   993
        fp.write('@@ -%d,%d +%d,%d @@%s\n' %
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   994
                 (self.fromline, fromlen, self.toline, tolen,
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   995
                  self.proc and (' ' + self.proc)))
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   996
        fp.write(''.join(self.before + self.hunk + self.after))
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   997
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   998
    pretty = write
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   999
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1000
    def filename(self):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1001
        return self.header.filename()
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1002
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1003
    def __repr__(self):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1004
        return '<hunk %r@%d>' % (self.filename(), self.fromline)
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1005
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1006
def getmessages():
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1007
    return {
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1008
        'multiple': {
35023
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1009
            'apply': _("apply change %d/%d to '%s'?"),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1010
            'discard': _("discard change %d/%d to '%s'?"),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1011
            'record': _("record change %d/%d to '%s'?"),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1012
        },
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1013
        'single': {
35023
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1014
            'apply': _("apply this change to '%s'?"),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1015
            'discard': _("discard this change to '%s'?"),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1016
            'record': _("record this change to '%s'?"),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1017
        },
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1018
        'help': {
35023
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1019
            'apply': _('[Ynesfdaq?]'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1020
                         '$$ &Yes, apply this change'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1021
                         '$$ &No, skip this change'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1022
                         '$$ &Edit this change manually'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1023
                         '$$ &Skip remaining changes to this file'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1024
                         '$$ Apply remaining changes to this &file'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1025
                         '$$ &Done, skip remaining changes and files'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1026
                         '$$ Apply &all changes to all remaining files'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1027
                         '$$ &Quit, applying no changes'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 35020
diff changeset
  1028
                         '$$ &? (display help)'),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1029
            'discard': _('[Ynesfdaq?]'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1030
                         '$$ &Yes, discard this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1031
                         '$$ &No, skip this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1032
                         '$$ &Edit this change manually'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1033
                         '$$ &Skip remaining changes to this file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1034
                         '$$ Discard remaining changes to this &file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1035
                         '$$ &Done, skip remaining changes and files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1036
                         '$$ Discard &all changes to all remaining files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1037
                         '$$ &Quit, discarding no changes'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1038
                         '$$ &? (display help)'),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1039
            'record': _('[Ynesfdaq?]'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1040
                        '$$ &Yes, record this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1041
                        '$$ &No, skip this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1042
                        '$$ &Edit this change manually'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1043
                        '$$ &Skip remaining changes to this file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1044
                        '$$ Record remaining changes to this &file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1045
                        '$$ &Done, skip remaining changes and files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1046
                        '$$ Record &all changes to all remaining files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1047
                        '$$ &Quit, recording no changes'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1048
                        '$$ &? (display help)'),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1049
        }
34059
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34031
diff changeset
  1050
    }
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34031
diff changeset
  1051
25310
c1f5ef76d1c2 record: add an operation arguments to customize recording ui
Laurent Charignon <lcharignon@fb.com>
parents: 25149
diff changeset
  1052
def filterpatch(ui, headers, operation=None):
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1053
    """Interactively filter patch chunks into applied-only chunks"""
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1054
    messages = getmessages()
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1055
25359
724421cb4745 record: add default value for operation argument
Laurent Charignon <lcharignon@fb.com>
parents: 25310
diff changeset
  1056
    if operation is None:
29326
d48fc6f318a3 patch: define full messages for interactive record/revert
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 29283
diff changeset
  1057
        operation = 'record'
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1058
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1059
    def prompt(skipfile, skipall, query, chunk):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1060
        """prompt query, and process base inputs
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1061
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1062
        - y/n for the rest of file
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1063
        - y/n for the rest
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1064
        - ? (help)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1065
        - q (quit)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1066
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1067
        Return True/False and possibly updated skipfile and skipall.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1068
        """
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1069
        newpatches = None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1070
        if skipall is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1071
            return skipall, skipfile, skipall, newpatches
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1072
        if skipfile is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1073
            return skipfile, skipfile, skipall, newpatches
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1074
        while True:
34059
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34031
diff changeset
  1075
            resps = messages['help'][operation]
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1076
            r = ui.promptchoice("%s %s" % (query, resps))
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1077
            ui.write("\n")
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1078
            if r == 8: # ?
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1079
                for c, t in ui.extractchoices(resps)[1]:
29154
9d38a2061fd8 patch: show lower-ed translated message correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28861
diff changeset
  1080
                    ui.write('%s - %s\n' % (c, encoding.lower(t)))
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1081
                continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1082
            elif r == 0: # yes
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1083
                ret = True
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1084
            elif r == 1: # no
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1085
                ret = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1086
            elif r == 2: # Edit patch
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1087
                if chunk is None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1088
                    ui.write(_('cannot edit patch for whole file'))
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1089
                    ui.write("\n")
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1090
                    continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1091
                if chunk.header.binary():
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1092
                    ui.write(_('cannot edit patch for binary file'))
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1093
                    ui.write("\n")
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1094
                    continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1095
                # Patch comment based on the Git one (based on comment at end of
26421
4b0fc75f9403 urls: bulk-change primary website URLs
Matt Mackall <mpm@selenic.com>
parents: 25660
diff changeset
  1096
                # https://mercurial-scm.org/wiki/RecordExtension)
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1097
                phelp = '---' + _("""
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1098
To remove '-' lines, make them ' ' lines (context).
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1099
To remove '+' lines, delete them.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1100
Lines starting with # will be removed from the patch.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1101
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1102
If the patch applies cleanly, the edited hunk will immediately be
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1103
added to the record list. If it does not apply cleanly, a rejects
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1104
file will be generated: you can use that when you try again. If
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1105
all lines of the hunk are removed, then the edit is aborted and
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1106
the hunk is left unchanged.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1107
""")
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1108
                (patchfd, patchfn) = tempfile.mkstemp(prefix="hg-editor-",
36845
472c68cda3f8 py3: wrap file object to write patch in native eol preserving byte-ness
Yuya Nishihara <yuya@tcha.org>
parents: 36843
diff changeset
  1109
                                                      suffix=".diff")
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1110
                ncpatchfp = None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1111
                try:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1112
                    # Write the initial patch
36845
472c68cda3f8 py3: wrap file object to write patch in native eol preserving byte-ness
Yuya Nishihara <yuya@tcha.org>
parents: 36843
diff changeset
  1113
                    f = util.nativeeolwriter(os.fdopen(patchfd, r'wb'))
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1114
                    chunk.header.write(f)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1115
                    chunk.write(f)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1116
                    f.write('\n'.join(['# ' + i for i in phelp.splitlines()]))
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1117
                    f.close()
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1118
                    # Start the editor and wait for it to complete
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1119
                    editor = ui.geteditor()
25483
fb04372d7b38 record: exiting editor with non-zero status should not stop recording session
Laurent Charignon <lcharignon@fb.com>
parents: 25424
diff changeset
  1120
                    ret = ui.system("%s \"%s\"" % (editor, patchfn),
31208
71a6723c0029 patch: set a blockedtag when running an external filter
Simon Farnsworth <simonfar@fb.com>
parents: 30944
diff changeset
  1121
                                    environ={'HGUSER': ui.username()},
71a6723c0029 patch: set a blockedtag when running an external filter
Simon Farnsworth <simonfar@fb.com>
parents: 30944
diff changeset
  1122
                                    blockedtag='filterpatch')
25483
fb04372d7b38 record: exiting editor with non-zero status should not stop recording session
Laurent Charignon <lcharignon@fb.com>
parents: 25424
diff changeset
  1123
                    if ret != 0:
fb04372d7b38 record: exiting editor with non-zero status should not stop recording session
Laurent Charignon <lcharignon@fb.com>
parents: 25424
diff changeset
  1124
                        ui.warn(_("editor exited with exit code %d\n") % ret)
fb04372d7b38 record: exiting editor with non-zero status should not stop recording session
Laurent Charignon <lcharignon@fb.com>
parents: 25424
diff changeset
  1125
                        continue
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1126
                    # Remove comment lines
36846
c268ba15deb3 py3: open patch file in binary mode and convert eol manually
Yuya Nishihara <yuya@tcha.org>
parents: 36845
diff changeset
  1127
                    patchfp = open(patchfn, r'rb')
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1128
                    ncpatchfp = stringio()
30407
564b33acc21f patch: migrate to util.iterfile
Jun Wu <quark@fb.com>
parents: 30078
diff changeset
  1129
                    for line in util.iterfile(patchfp):
36846
c268ba15deb3 py3: open patch file in binary mode and convert eol manually
Yuya Nishihara <yuya@tcha.org>
parents: 36845
diff changeset
  1130
                        line = util.fromnativeeol(line)
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1131
                        if not line.startswith('#'):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1132
                            ncpatchfp.write(line)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1133
                    patchfp.close()
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1134
                    ncpatchfp.seek(0)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1135
                    newpatches = parsepatch(ncpatchfp)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1136
                finally:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1137
                    os.unlink(patchfn)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1138
                    del ncpatchfp
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1139
                # Signal that the chunk shouldn't be applied as-is, but
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1140
                # provide the new patch to be used instead.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1141
                ret = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1142
            elif r == 3: # Skip
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1143
                ret = skipfile = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1144
            elif r == 4: # file (Record remaining)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1145
                ret = skipfile = True
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1146
            elif r == 5: # done, skip remaining
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1147
                ret = skipall = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1148
            elif r == 6: # all
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1149
                ret = skipall = True
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1150
            elif r == 7: # quit
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26560
diff changeset
  1151
                raise error.Abort(_('user quit'))
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1152
            return ret, skipfile, skipall, newpatches
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1153
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1154
    seen = set()
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1155
    applied = {}        # 'filename' -> [] of chunks
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1156
    skipfile, skipall = None, None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1157
    pos, total = 1, sum(len(h.hunks) for h in headers)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1158
    for h in headers:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1159
        pos += len(h.hunks)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1160
        skipfile = None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1161
        fixoffset = 0
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1162
        hdr = ''.join(h.header)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1163
        if hdr in seen:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1164
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1165
        seen.add(hdr)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1166
        if skipall is None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1167
            h.pretty(ui)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1168
        msg = (_('examine changes to %s?') %
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1169
               _(' and ').join("'%s'" % f for f in h.files()))
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1170
        r, skipfile, skipall, np = prompt(skipfile, skipall, msg, None)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1171
        if not r:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1172
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1173
        applied[h.filename()] = [h]
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1174
        if h.allhunks():
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1175
            applied[h.filename()] += h.hunks
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1176
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1177
        for i, chunk in enumerate(h.hunks):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1178
            if skipfile is None and skipall is None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1179
                chunk.pretty(ui)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1180
            if total == 1:
34059
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34031
diff changeset
  1181
                msg = messages['single'][operation] % chunk.filename()
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1182
            else:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1183
                idx = pos - len(h.hunks) + i
34059
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34031
diff changeset
  1184
                msg = messages['multiple'][operation] % (idx, total,
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34031
diff changeset
  1185
                                                         chunk.filename())
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1186
            r, skipfile, skipall, newpatches = prompt(skipfile,
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1187
                    skipall, msg, chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1188
            if r:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1189
                if fixoffset:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1190
                    chunk = copy.copy(chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1191
                    chunk.toline += fixoffset
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1192
                applied[chunk.filename()].append(chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1193
            elif newpatches is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1194
                for newpatch in newpatches:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1195
                    for newhunk in newpatch.hunks:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1196
                        if fixoffset:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1197
                            newhunk.toline += fixoffset
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1198
                        applied[newhunk.filename()].append(newhunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1199
            else:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1200
                fixoffset += chunk.removed - chunk.added
27155
8d3c5797a175 commit: add a way to return more information from the chunkselector
Laurent Charignon <lcharignon@fb.com>
parents: 26781
diff changeset
  1201
    return (sum([h for h in applied.itervalues()
8d3c5797a175 commit: add a way to return more information from the chunkselector
Laurent Charignon <lcharignon@fb.com>
parents: 26781
diff changeset
  1202
               if h[0].special() or len(h) > 1], []), {})
8778
c5f36402daad use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 8761
diff changeset
  1203
class hunk(object):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1204
    def __init__(self, desc, num, lr, context):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1205
        self.number = num
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1206
        self.desc = desc
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1207
        self.hunk = [desc]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1208
        self.a = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1209
        self.b = []
9682
bd70f645cfb0 patch: initialize all attributes of the hunk class
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9681
diff changeset
  1210
        self.starta = self.lena = None
bd70f645cfb0 patch: initialize all attributes of the hunk class
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9681
diff changeset
  1211
        self.startb = self.lenb = None
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1212
        if lr is not None:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1213
            if context:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1214
                self.read_context_hunk(lr)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1215
            else:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1216
                self.read_unified_hunk(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1217
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1218
    def getnormalized(self):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1219
        """Return a copy with line endings normalized to LF."""
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1220
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1221
        def normalize(lines):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1222
            nlines = []
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1223
            for line in lines:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1224
                if line.endswith('\r\n'):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1225
                    line = line[:-2] + '\n'
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1226
                nlines.append(line)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1227
            return nlines
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1228
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1229
        # Dummy object, it is rebuilt manually
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1230
        nh = hunk(self.desc, self.number, None, None)
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1231
        nh.number = self.number
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1232
        nh.desc = self.desc
10524
3212afb33116 patch: fix patching with fuzz and eol normalization
Patrick Mezard <pmezard@gmail.com>
parents: 10518
diff changeset
  1233
        nh.hunk = self.hunk
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1234
        nh.a = normalize(self.a)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1235
        nh.b = normalize(self.b)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1236
        nh.starta = self.starta
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1237
        nh.startb = self.startb
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1238
        nh.lena = self.lena
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1239
        nh.lenb = self.lenb
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1240
        return nh
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1241
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1242
    def read_unified_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1243
        m = unidesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1244
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1245
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1246
        self.starta, self.lena, self.startb, self.lenb = m.groups()
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1247
        if self.lena is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1248
            self.lena = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1249
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1250
            self.lena = int(self.lena)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1251
        if self.lenb is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1252
            self.lenb = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1253
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1254
            self.lenb = int(self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1255
        self.starta = int(self.starta)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1256
        self.startb = int(self.startb)
16683
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  1257
        diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a,
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  1258
                             self.b)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1259
        # if we hit eof before finishing out the hunk, the last line will
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1260
        # be zero length.  Lets try to fix it up.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1261
        while len(self.hunk[-1]) == 0:
6948
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1262
            del self.hunk[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1263
            del self.a[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1264
            del self.b[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1265
            self.lena -= 1
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1266
            self.lenb -= 1
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1267
        self._fixnewline(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1268
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1269
    def read_context_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1270
        self.desc = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1271
        m = contextdesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1272
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1273
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1274
        self.starta, aend = m.groups()
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1275
        self.starta = int(self.starta)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1276
        if aend is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1277
            aend = self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1278
        self.lena = int(aend) - self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1279
        if self.starta:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1280
            self.lena += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1281
        for x in xrange(self.lena):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1282
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1283
            if l.startswith('---'):
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1284
                # lines addition, old block is empty
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1285
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1286
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1287
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1288
            if l.startswith('- ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1289
                u = '-' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1290
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1291
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1292
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1293
                raise PatchError(_("bad hunk #%d old text line %d") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1294
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1295
            self.a.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1296
            self.hunk.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1297
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1298
        l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1299
        if l.startswith('\ '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1300
            s = self.a[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1301
            self.a[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1302
            self.hunk[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1303
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1304
        m = contextdesc.match(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1305
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1306
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1307
        self.startb, bend = m.groups()
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1308
        self.startb = int(self.startb)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1309
        if bend is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1310
            bend = self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1311
        self.lenb = int(bend) - self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1312
        if self.startb:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1313
            self.lenb += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1314
        hunki = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1315
        for x in xrange(self.lenb):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1316
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1317
            if l.startswith('\ '):
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1318
                # XXX: the only way to hit this is with an invalid line range.
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1319
                # The no-eol marker is not counted in the line range, but I
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1320
                # guess there are diff(1) out there which behave differently.
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1321
                s = self.b[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1322
                self.b[-1] = s
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1323
                self.hunk[hunki - 1] = s
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1324
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1325
            if not l:
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1326
                # line deletions, new block is empty and we hit EOF
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1327
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1328
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1329
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1330
            if l.startswith('+ ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1331
                u = '+' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1332
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1333
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1334
            elif len(self.b) == 0:
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1335
                # line deletions, new block is empty
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1336
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1337
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1338
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1339
                raise PatchError(_("bad hunk #%d old text line %d") %
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1340
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1341
            self.b.append(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1342
            while True:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1343
                if hunki >= len(self.hunk):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1344
                    h = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1345
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1346
                    h = self.hunk[hunki]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1347
                hunki += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1348
                if h == u:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1349
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1350
                elif h.startswith('-'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1351
                    continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1352
                else:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1353
                    self.hunk.insert(hunki - 1, u)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1354
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1355
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1356
        if not self.a:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1357
            # this happens when lines were only added to the hunk
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1358
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1359
                if x.startswith('-') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1360
                    self.a.append(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1361
        if not self.b:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1362
            # this happens when lines were only deleted from the hunk
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1363
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1364
                if x.startswith('+') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1365
                    self.b.append(x[1:])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1366
        # @@ -start,len +start,len @@
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1367
        self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1368
                                             self.startb, self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1369
        self.hunk[0] = self.desc
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1370
        self._fixnewline(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1371
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1372
    def _fixnewline(self, lr):
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1373
        l = lr.readline()
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1374
        if l.startswith('\ '):
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1375
            diffhelpers.fix_newline(self.hunk, self.a, self.b)
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1376
        else:
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1377
            lr.push(l)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1378
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1379
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1380
        return len(self.a) == self.lena and len(self.b) == self.lenb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1381
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
  1382
    def _fuzzit(self, old, new, fuzz, toponly):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1383
        # this removes context lines from the top and bottom of list 'l'.  It
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1384
        # checks the hunk to make sure only context lines are removed, and then
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1385
        # returns a new shortened list of lines.
16124
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1386
        fuzz = min(fuzz, len(old))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1387
        if fuzz:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1388
            top = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1389
            bot = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1390
            hlen = len(self.hunk)
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1391
            for x in xrange(hlen - 1):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1392
                # the hunk starts with the @@ line, so use x+1
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1393
                if self.hunk[x + 1][0] == ' ':
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1394
                    top += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1395
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1396
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1397
            if not toponly:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1398
                for x in xrange(hlen - 1):
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1399
                    if self.hunk[hlen - bot - 1][0] == ' ':
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1400
                        bot += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1401
                    else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1402
                        break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1403
16124
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1404
            bot = min(fuzz, bot)
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1405
            top = min(fuzz, top)
18054
b35e3364f94a check-code: there must also be whitespace between ')' and operator
Mads Kiilerich <madski@unity3d.com>
parents: 17968
diff changeset
  1406
            return old[top:len(old) - bot], new[top:len(new) - bot], top
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1407
        return old, new, 0
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1408
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
  1409
    def fuzzit(self, fuzz, toponly):
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1410
        old, new, top = self._fuzzit(self.a, self.b, fuzz, toponly)
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1411
        oldstart = self.starta + top
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1412
        newstart = self.startb + top
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1413
        # zero length hunk ranges already have their start decremented
16650
fcb97d9a26cd patch: fix segfault against unified diffs which start line is zero
Yuya Nishihara <yuya@tcha.org>
parents: 16524
diff changeset
  1414
        if self.lena and oldstart > 0:
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1415
            oldstart -= 1
16650
fcb97d9a26cd patch: fix segfault against unified diffs which start line is zero
Yuya Nishihara <yuya@tcha.org>
parents: 16524
diff changeset
  1416
        if self.lenb and newstart > 0:
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1417
            newstart -= 1
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1418
        return old, oldstart, new, newstart
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1419
14764
a7d5816087a9 classes: fix class style problems found by b071cd58af50
Thomas Arendsen Hein <thomas@intevation.de>
parents: 14695
diff changeset
  1420
class binhunk(object):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1421
    'A binary patch file.'
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1422
    def __init__(self, lr, fname):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1423
        self.text = None
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1424
        self.delta = False
9585
ea1935e2020a patch: handle symlinks without symlinkhunk
Patrick Mezard <pmezard@gmail.com>
parents: 9573
diff changeset
  1425
        self.hunk = ['GIT binary patch\n']
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1426
        self._fname = fname
14384
9d59c596eb9e patch: construct and parse binary hunks at the same time
Patrick Mezard <pmezard@gmail.com>
parents: 14383
diff changeset
  1427
        self._read(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1428
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1429
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1430
        return self.text is not None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1431
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1432
    def new(self, lines):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1433
        if self.delta:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1434
            return [applybindelta(self.text, ''.join(lines))]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1435
        return [self.text]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1436
14384
9d59c596eb9e patch: construct and parse binary hunks at the same time
Patrick Mezard <pmezard@gmail.com>
parents: 14383
diff changeset
  1437
    def _read(self, lr):
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1438
        def getline(lr, hunk):
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1439
            l = lr.readline()
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1440
            hunk.append(l)
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1441
            return l.rstrip('\r\n')
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1442
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1443
        size = 0
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1444
        while True:
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1445
            line = getline(lr, self.hunk)
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1446
            if not line:
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1447
                raise PatchError(_('could not extract "%s" binary data')
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1448
                                 % self._fname)
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1449
            if line.startswith('literal '):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1450
                size = int(line[8:].rstrip())
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1451
                break
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1452
            if line.startswith('delta '):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1453
                size = int(line[6:].rstrip())
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1454
                self.delta = True
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1455
                break
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1456
        dec = []
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1457
        line = getline(lr, self.hunk)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1458
        while len(line) > 1:
36230
eb91ffdaaece py3: slice over bytes to prevent getting ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 36084
diff changeset
  1459
            l = line[0:1]
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
  1460
            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
  1461
                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
  1462
            else:
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
  1463
                l = ord(l) - ord('a') + 27
16522
a8065323c003 patch: display a nice error for invalid base85 data
Patrick Mezard <patrick@mezard.eu>
parents: 16506
diff changeset
  1464
            try:
32245
4462a981e8df base85: proxy through util module
Yuya Nishihara <yuya@tcha.org>
parents: 32237
diff changeset
  1465
                dec.append(util.b85decode(line[1:])[:l])
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25658
diff changeset
  1466
            except ValueError as e:
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1467
                raise PatchError(_('could not decode "%s" binary patch: %s')
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36846
diff changeset
  1468
                                 % (self._fname, stringutil.forcebytestr(e)))
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1469
            line = getline(lr, self.hunk)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1470
        text = zlib.decompress(''.join(dec))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1471
        if len(text) != size:
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1472
            raise PatchError(_('"%s" length is %d bytes, should be %d')
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1473
                             % (self._fname, len(text), size))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1474
        self.text = text
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1475
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1476
def parsefilename(str):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1477
    # --- filename \t|space stuff
5851
03f550f9b554 patch: remove CRLF when parsing file names
Patrick Mezard <pmezard@gmail.com>
parents: 5669
diff changeset
  1478
    s = str[4:].rstrip('\r\n')
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1479
    i = s.find('\t')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1480
    if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1481
        i = s.find(' ')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1482
        if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1483
            return s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1484
    return s[:i]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1485
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1486
def reversehunks(hunks):
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1487
    '''reverse the signs in the hunks given as argument
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1488
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1489
    This function operates on hunks coming out of patch.filterpatch, that is
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1490
    a list of the form: [header1, hunk1, hunk2, header2...]. Example usage:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1491
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1492
    >>> rawpatch = b"""diff --git a/folder1/g b/folder1/g
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1493
    ... --- a/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1494
    ... +++ b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1495
    ... @@ -1,7 +1,7 @@
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1496
    ... +firstline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1497
    ...  c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1498
    ...  1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1499
    ...  2
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1500
    ... + 3
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1501
    ... -4
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1502
    ...  5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1503
    ...  d
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1504
    ... +lastline"""
34260
5ce32fe7df34 py3: fix doctests in patch.py to be compatible with Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34259
diff changeset
  1505
    >>> hunks = parsepatch([rawpatch])
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1506
    >>> hunkscomingfromfilterpatch = []
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1507
    >>> for h in hunks:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1508
    ...     hunkscomingfromfilterpatch.append(h)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1509
    ...     hunkscomingfromfilterpatch.extend(h.hunks)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1510
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1511
    >>> reversedhunks = reversehunks(hunkscomingfromfilterpatch)
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1512
    >>> from . import util
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1513
    >>> fp = util.stringio()
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1514
    >>> for c in reversedhunks:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1515
    ...      c.write(fp)
34260
5ce32fe7df34 py3: fix doctests in patch.py to be compatible with Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34259
diff changeset
  1516
    >>> fp.seek(0) or None
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1517
    >>> reversedpatch = fp.read()
34152
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34146
diff changeset
  1518
    >>> print(pycompat.sysstr(reversedpatch))
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1519
    diff --git a/folder1/g b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1520
    --- a/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1521
    +++ b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1522
    @@ -1,4 +1,3 @@
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1523
    -firstline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1524
     c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1525
     1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1526
     2
32997
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
  1527
    @@ -2,6 +1,6 @@
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1528
     c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1529
     1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1530
     2
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1531
    - 3
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1532
    +4
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1533
     5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1534
     d
32997
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
  1535
    @@ -6,3 +5,2 @@
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1536
     5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1537
     d
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1538
    -lastline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1539
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1540
    '''
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1541
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1542
    newhunks = []
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1543
    for c in hunks:
32997
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
  1544
        if util.safehasattr(c, 'reversehunk'):
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32409
diff changeset
  1545
            c = c.reversehunk()
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1546
        newhunks.append(c)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1547
    return newhunks
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1548
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1549
def parsepatch(originalchunks, maxcontext=None):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1550
    """patch -> [] of headers -> [] of hunks
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1551
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1552
    If maxcontext is not None, trim context lines if necessary.
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1553
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1554
    >>> rawpatch = b'''diff --git a/folder1/g b/folder1/g
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1555
    ... --- a/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1556
    ... +++ b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1557
    ... @@ -1,8 +1,10 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1558
    ...  1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1559
    ...  2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1560
    ... -3
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1561
    ...  4
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1562
    ...  5
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1563
    ...  6
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1564
    ... +6.1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1565
    ... +6.2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1566
    ...  7
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1567
    ...  8
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1568
    ... +9'''
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1569
    >>> out = util.stringio()
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1570
    >>> headers = parsepatch([rawpatch], maxcontext=1)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1571
    >>> for header in headers:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1572
    ...     header.write(out)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1573
    ...     for hunk in header.hunks:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1574
    ...         hunk.write(out)
34152
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34146
diff changeset
  1575
    >>> print(pycompat.sysstr(out.getvalue()))
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1576
    diff --git a/folder1/g b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1577
    --- a/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1578
    +++ b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1579
    @@ -2,3 +2,2 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1580
     2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1581
    -3
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1582
     4
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1583
    @@ -6,2 +5,4 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1584
     6
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1585
    +6.1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1586
    +6.2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1587
     7
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1588
    @@ -8,1 +9,2 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1589
     8
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1590
    +9
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1591
    """
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1592
    class parser(object):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1593
        """patch parsing state machine"""
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1594
        def __init__(self):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1595
            self.fromline = 0
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1596
            self.toline = 0
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1597
            self.proc = ''
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1598
            self.header = None
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1599
            self.context = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1600
            self.before = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1601
            self.hunk = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1602
            self.headers = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1603
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1604
        def addrange(self, limits):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1605
            fromstart, fromend, tostart, toend, proc = limits
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1606
            self.fromline = int(fromstart)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1607
            self.toline = int(tostart)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1608
            self.proc = proc
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1609
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1610
        def addcontext(self, context):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1611
            if self.hunk:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1612
                h = recordhunk(self.header, self.fromline, self.toline,
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1613
                        self.proc, self.before, self.hunk, context, maxcontext)
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1614
                self.header.hunks.append(h)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1615
                self.fromline += len(self.before) + h.removed
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1616
                self.toline += len(self.before) + h.added
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1617
                self.before = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1618
                self.hunk = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1619
            self.context = context
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1620
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1621
        def addhunk(self, hunk):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1622
            if self.context:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1623
                self.before = self.context
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1624
                self.context = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1625
            self.hunk = hunk
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1626
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1627
        def newfile(self, hdr):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1628
            self.addcontext([])
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1629
            h = header(hdr)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1630
            self.headers.append(h)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1631
            self.header = h
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1632
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1633
        def addother(self, line):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1634
            pass # 'other' lines are ignored
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1635
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1636
        def finished(self):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1637
            self.addcontext([])
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1638
            return self.headers
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1639
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1640
        transitions = {
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1641
            'file': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1642
                     'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1643
                     'hunk': addhunk,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1644
                     'range': addrange},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1645
            'context': {'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1646
                        'hunk': addhunk,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1647
                        'range': addrange,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1648
                        'other': addother},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1649
            'hunk': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1650
                     'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1651
                     'range': addrange},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1652
            'range': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1653
                      'hunk': addhunk},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1654
            'other': {'other': addother},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1655
            }
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1656
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1657
    p = parser()
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1658
    fp = stringio()
24341
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1659
    fp.write(''.join(originalchunks))
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1660
    fp.seek(0)
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1661
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1662
    state = 'context'
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1663
    for newstate, data in scanpatch(fp):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1664
        try:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1665
            p.transitions[state][newstate](p, data)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1666
        except KeyError:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1667
            raise PatchError('unhandled transition: %s -> %s' %
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1668
                                   (state, newstate))
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1669
        state = newstate
24341
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1670
    del fp
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1671
    return p.finished()
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1672
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1673
def pathtransform(path, strip, prefix):
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1674
    '''turn a path from a patch into a path suitable for the repository
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1675
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1676
    prefix, if not empty, is expected to be normalized with a / at the end.
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1677
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1678
    Returns (stripped components, path in repository).
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1679
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1680
    >>> pathtransform(b'a/b/c', 0, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1681
    ('', 'a/b/c')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1682
    >>> pathtransform(b'   a/b/c   ', 0, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1683
    ('', '   a/b/c')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1684
    >>> pathtransform(b'   a/b/c   ', 2, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1685
    ('a/b/', 'c')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1686
    >>> pathtransform(b'a/b/c', 0, b'd/e/')
24385
885a573fa619 patch.pathtransform: prepend prefix even if strip is 0
Siddharth Agarwal <sid0@fb.com>
parents: 24371
diff changeset
  1687
    ('', 'd/e/a/b/c')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1688
    >>> pathtransform(b'   a//b/c   ', 2, b'd/e/')
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1689
    ('a//b/', 'd/e/c')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34084
diff changeset
  1690
    >>> pathtransform(b'a/b/c', 3, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1691
    Traceback (most recent call last):
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1692
    PatchError: unable to strip away 1 of 3 dirs from a/b/c
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1693
    '''
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1694
    pathlen = len(path)
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1695
    i = 0
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1696
    if strip == 0:
24385
885a573fa619 patch.pathtransform: prepend prefix even if strip is 0
Siddharth Agarwal <sid0@fb.com>
parents: 24371
diff changeset
  1697
        return '', prefix + path.rstrip()
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1698
    count = strip
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1699
    while count > 0:
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1700
        i = path.find('/', i)
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1701
        if i == -1:
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1702
            raise PatchError(_("unable to strip away %d of %d dirs from %s") %
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1703
                             (count, strip, path))
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1704
        i += 1
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1705
        # consume '//' in the path
34084
8b8b70cb4288 py3: replace bytes[n] with bytes[n:n + 1] in patch.py where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34083
diff changeset
  1706
        while i < pathlen - 1 and path[i:i + 1] == '/':
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1707
            i += 1
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1708
        count -= 1
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1709
    return path[:i].lstrip(), prefix + path[i:].rstrip()
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1710
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1711
def makepatchmeta(backend, afile_orig, bfile_orig, hunk, strip, prefix):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1712
    nulla = afile_orig == "/dev/null"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1713
    nullb = bfile_orig == "/dev/null"
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1714
    create = nulla and hunk.starta == 0 and hunk.lena == 0
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1715
    remove = nullb and hunk.startb == 0 and hunk.lenb == 0
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1716
    abase, afile = pathtransform(afile_orig, strip, prefix)
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
  1717
    gooda = not nulla and backend.exists(afile)
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1718
    bbase, bfile = pathtransform(bfile_orig, strip, prefix)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1719
    if afile == bfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1720
        goodb = gooda
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1721
    else:
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
  1722
        goodb = not nullb and backend.exists(bfile)
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1723
    missing = not goodb and not gooda and not create
9328
648d6a1a1cf2 patch: create file even if source is not /dev/null
Brendan Cully <brendan@kublai.com>
parents: 9248
diff changeset
  1724
11820
75de514a50f3 patch: fix typo in comment
Martin Geisler <mg@aragost.com>
parents: 11645
diff changeset
  1725
    # some diff programs apparently produce patches where the afile is
75de514a50f3 patch: fix typo in comment
Martin Geisler <mg@aragost.com>
parents: 11645
diff changeset
  1726
    # not /dev/null, but afile starts with bfile
10745
d94832c4a31d patch: try harder to find the file to patch on file creation (issue2041)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10736
diff changeset
  1727
    abasedir = afile[:afile.rfind('/') + 1]
d94832c4a31d patch: try harder to find the file to patch on file creation (issue2041)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10736
diff changeset
  1728
    bbasedir = bfile[:bfile.rfind('/') + 1]
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1729
    if (missing and abasedir == bbasedir and afile.startswith(bfile)
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1730
        and hunk.starta == 0 and hunk.lena == 0):
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1731
        create = True
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1732
        missing = False
9328
648d6a1a1cf2 patch: create file even if source is not /dev/null
Brendan Cully <brendan@kublai.com>
parents: 9248
diff changeset
  1733
6295
bace1990ab12 patch: fix corner case with update + copy patch handling (issue 937)
Patrick Mezard <pmezard@gmail.com>
parents: 6280
diff changeset
  1734
    # If afile is "a/b/foo" and bfile is "a/b/foo.orig" we assume the
bace1990ab12 patch: fix corner case with update + copy patch handling (issue 937)
Patrick Mezard <pmezard@gmail.com>
parents: 6280
diff changeset
  1735
    # diff is between a file and its backup. In this case, the original
bace1990ab12 patch: fix corner case with update + copy patch handling (issue 937)
Patrick Mezard <pmezard@gmail.com>
parents: 6280
diff changeset
  1736
    # file should be patched (see original mpatch code).
bace1990ab12 patch: fix corner case with update + copy patch handling (issue 937)
Patrick Mezard <pmezard@gmail.com>
parents: 6280
diff changeset
  1737
    isbackup = (abase == bbase and bfile.startswith(afile))
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1738
    fname = None
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1739
    if not missing:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1740
        if gooda and goodb:
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1741
            if isbackup:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1742
                fname = afile
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1743
            else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1744
                fname = bfile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1745
        elif gooda:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1746
            fname = afile
5760
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5706
diff changeset
  1747
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1748
    if not fname:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1749
        if not nullb:
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1750
            if isbackup:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1751
                fname = afile
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1752
            else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1753
                fname = bfile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1754
        elif not nulla:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1755
            fname = afile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1756
        else:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1757
            raise PatchError(_("undefined source and destination files"))
5760
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5706
diff changeset
  1758
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1759
    gp = patchmeta(fname)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1760
    if create:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1761
        gp.op = 'ADD'
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1762
    elif remove:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1763
        gp.op = 'DELETE'
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1764
    return gp
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1765
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1766
def scanpatch(fp):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1767
    """like patch.iterhunks, but yield different events
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1768
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1769
    - ('file',    [header_lines + fromfile + tofile])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1770
    - ('context', [context_lines])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1771
    - ('hunk',    [hunk_lines])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1772
    - ('range',   (-start,len, +start,len, proc))
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1773
    """
34083
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34059
diff changeset
  1774
    lines_re = re.compile(br'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1775
    lr = linereader(fp)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1776
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1777
    def scanwhile(first, p):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1778
        """scan lr while predicate holds"""
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1779
        lines = [first]
29738
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1780
        for line in iter(lr.readline, ''):
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1781
            if p(line):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1782
                lines.append(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1783
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1784
                lr.push(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1785
                break
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1786
        return lines
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1787
29738
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1788
    for line in iter(lr.readline, ''):
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1789
        if line.startswith('diff --git a/') or line.startswith('diff -r '):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1790
            def notheader(line):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1791
                s = line.split(None, 1)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1792
                return not s or s[0] not in ('---', 'diff')
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1793
            header = scanwhile(line, notheader)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1794
            fromfile = lr.readline()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1795
            if fromfile.startswith('---'):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1796
                tofile = lr.readline()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1797
                header += [fromfile, tofile]
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1798
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1799
                lr.push(fromfile)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1800
            yield 'file', header
34084
8b8b70cb4288 py3: replace bytes[n] with bytes[n:n + 1] in patch.py where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34083
diff changeset
  1801
        elif line[0:1] == ' ':
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1802
            yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1803
        elif line[0] in '-+':
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1804
            yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1805
        else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1806
            m = lines_re.match(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1807
            if m:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1808
                yield 'range', m.groups()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1809
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1810
                yield 'other', line
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1811
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1812
def scangitpatch(lr, firstline):
7186
f77c8d8331ca clean up trailing spaces, leading spaces in C
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7153
diff changeset
  1813
    """
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1814
    Git patches can emit:
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1815
    - rename a to b
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1816
    - change b
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1817
    - copy a to c
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1818
    - change c
7186
f77c8d8331ca clean up trailing spaces, leading spaces in C
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7153
diff changeset
  1819
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1820
    We cannot apply this sequence as-is, the renamed 'a' could not be
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1821
    found for it would have been renamed already. And we cannot copy
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1822
    from 'b' instead because 'b' would have been changed already. So
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1823
    we scan the git patch for copy and rename commands so we can
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1824
    perform the copies ahead of time.
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1825
    """
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1826
    pos = 0
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1827
    try:
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1828
        pos = lr.fp.tell()
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1829
        fp = lr.fp
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1830
    except IOError:
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1831
        fp = stringio(lr.fp.read())
14418
0174d1f79280 patch: remove EOL support from linereader class
Patrick Mezard <pmezard@gmail.com>
parents: 14402
diff changeset
  1832
    gitlr = linereader(fp)
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1833
    gitlr.push(firstline)
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
  1834
    gitpatches = readgitpatch(gitlr)
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1835
    fp.seek(pos)
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
  1836
    return gitpatches
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1837
14240
28762bb767dc patch: remove unused ui arg to iterhunks
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
  1838
def iterhunks(fp):
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1839
    """Read a patch and yield the following events:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1840
    - ("file", afile, bfile, firsthunk): select a new target file.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1841
    - ("hunk", hunk): a new hunk is ready to be applied, follows a
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1842
    "file" event.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1843
    - ("git", gitchanges): current diff is in git format, gitchanges
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1844
    maps filenames to gitpatch records. Unique event.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1845
    """
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1846
    afile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1847
    bfile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1848
    state = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1849
    hunknum = 0
14017
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1850
    emitfile = newfile = False
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1851
    gitpatches = None
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1852
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1853
    # our states
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1854
    BFILE = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1855
    context = None
10128
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
  1856
    lr = linereader(fp)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1857
29738
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1858
    for x in iter(lr.readline, ''):
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1859
        if state == BFILE and (
36675
463df2986814 py3: fix slicing of bytes in patch.iterhunks()
Yuya Nishihara <yuya@tcha.org>
parents: 36636
diff changeset
  1860
            (not context and x.startswith('@'))
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1861
            or (context is not False and x.startswith('***************'))
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1862
            or x.startswith('GIT binary patch')):
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1863
            gp = None
14534
ecc79816d31e patch: fix patchmeta/hunk synchronization in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 14533
diff changeset
  1864
            if (gitpatches and
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1865
                gitpatches[-1].ispatching(afile, bfile)):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1866
                gp = gitpatches.pop()
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1867
            if x.startswith('GIT binary patch'):
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1868
                h = binhunk(lr, gp.path)
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1869
            else:
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1870
                if context is None and x.startswith('***************'):
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1871
                    context = True
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1872
                h = hunk(x, hunknum + 1, lr, context)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1873
            hunknum += 1
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1874
            if emitfile:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1875
                emitfile = False
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1876
                yield 'file', (afile, bfile, h, gp and gp.copy() or None)
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1877
            yield 'hunk', h
18830
6b827d84d286 patch: match 'diff --git a/' instead of 'diff --git'
Sean Farley <sean.michael.farley@gmail.com>
parents: 18824
diff changeset
  1878
        elif x.startswith('diff --git a/'):
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1879
            m = gitre.match(x.rstrip(' \r\n'))
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1880
            if not m:
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1881
                continue
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1882
            if gitpatches is None:
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1883
                # scan whole input for git metadata
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1884
                gitpatches = scangitpatch(lr, x)
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1885
                yield 'git', [g.copy() for g in gitpatches
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1886
                              if g.op in ('COPY', 'RENAME')]
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1887
                gitpatches.reverse()
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1888
            afile = 'a/' + m.group(1)
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1889
            bfile = 'b/' + m.group(2)
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1890
            while gitpatches and not gitpatches[-1].ispatching(afile, bfile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1891
                gp = gitpatches.pop()
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1892
                yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1893
            if not gitpatches:
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1894
                raise PatchError(_('failed to synchronize metadata for "%s"')
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1895
                                 % afile[2:])
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1896
            gp = gitpatches[-1]
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1897
            newfile = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1898
        elif x.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1899
            # check for a unified diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1900
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1901
            if not l2.startswith('+++'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1902
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1903
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1904
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1905
            context = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1906
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1907
            bfile = parsefilename(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1908
        elif x.startswith('***'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1909
            # check for a context diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1910
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1911
            if not l2.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1912
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1913
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1914
            l3 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1915
            lr.push(l3)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1916
            if not l3.startswith("***************"):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1917
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1918
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1919
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1920
            context = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1921
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1922
            bfile = parsefilename(l2)
3057
d16b93f4a6ca unlink temporary patch files even when an exception is raised
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3056
diff changeset
  1923
14017
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1924
        if newfile:
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1925
            newfile = False
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1926
            emitfile = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1927
            state = BFILE
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1928
            hunknum = 0
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1929
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1930
    while gitpatches:
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1931
        gp = gitpatches.pop()
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1932
        yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1933
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1934
def applybindelta(binchunk, data):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1935
    """Apply a binary delta hunk
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1936
    The algorithm used is the algorithm from git's patch-delta.c
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1937
    """
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1938
    def deltahead(binchunk):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1939
        i = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1940
        for c in binchunk:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1941
            i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1942
            if not (ord(c) & 0x80):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1943
                return i
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1944
        return i
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1945
    out = ""
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1946
    s = deltahead(binchunk)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1947
    binchunk = binchunk[s:]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1948
    s = deltahead(binchunk)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1949
    binchunk = binchunk[s:]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1950
    i = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1951
    while i < len(binchunk):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1952
        cmd = ord(binchunk[i])
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1953
        i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1954
        if (cmd & 0x80):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1955
            offset = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1956
            size = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1957
            if (cmd & 0x01):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1958
                offset = ord(binchunk[i])
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1959
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1960
            if (cmd & 0x02):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1961
                offset |= ord(binchunk[i]) << 8
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1962
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1963
            if (cmd & 0x04):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1964
                offset |= ord(binchunk[i]) << 16
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1965
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1966
            if (cmd & 0x08):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1967
                offset |= ord(binchunk[i]) << 24
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1968
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1969
            if (cmd & 0x10):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1970
                size = ord(binchunk[i])
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1971
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1972
            if (cmd & 0x20):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1973
                size |= ord(binchunk[i]) << 8
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1974
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1975
            if (cmd & 0x40):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1976
                size |= ord(binchunk[i]) << 16
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1977
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1978
            if size == 0:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1979
                size = 0x10000
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1980
            offset_end = offset + size
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1981
            out += data[offset:offset_end]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1982
        elif cmd != 0:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1983
            offset_end = i + cmd
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1984
            out += binchunk[i:offset_end]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1985
            i += cmd
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1986
        else:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1987
            raise PatchError(_('unexpected delta opcode 0'))
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1988
    return out
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1989
24247
6e19516094a3 patch.applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24246
diff changeset
  1990
def applydiff(ui, fp, backend, store, strip=1, prefix='', eolmode='strict'):
10966
91c58cf54eee patch: refactor applydiff to allow for mempatching
Augie Fackler <durin42@gmail.com>
parents: 10965
diff changeset
  1991
    """Reads a patch from fp and tries to apply it.
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1992
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  1993
    Returns 0 for a clean patch, -1 if any rejects were found and 1 if
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  1994
    there was any fuzz.
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  1995
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  1996
    If 'eolmode' is 'strict', the patch content and patched file are
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  1997
    read in binary mode. Otherwise, line endings are ignored when
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  1998
    patching then normalized according to 'eolmode'.
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  1999
    """
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2000
    return _applydiff(ui, fp, patchfile, backend, store, strip=strip,
24247
6e19516094a3 patch.applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24246
diff changeset
  2001
                      prefix=prefix, eolmode=eolmode)
10966
91c58cf54eee patch: refactor applydiff to allow for mempatching
Augie Fackler <durin42@gmail.com>
parents: 10965
diff changeset
  2002
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2003
def _canonprefix(repo, prefix):
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2004
    if prefix:
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2005
        prefix = pathutil.canonpath(repo.root, repo.getcwd(), prefix)
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2006
        if prefix != '':
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2007
            prefix += '/'
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2008
    return prefix
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2009
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2010
def _applydiff(ui, fp, patcher, backend, store, strip=1, prefix='',
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2011
               eolmode='strict'):
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2012
    prefix = _canonprefix(backend.repo, prefix)
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2013
    def pstrip(p):
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2014
        return pathtransform(p, strip - 1, prefix)[1]
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2015
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2016
    rejects = 0
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2017
    err = 0
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2018
    current_file = None
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2019
14240
28762bb767dc patch: remove unused ui arg to iterhunks
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
  2020
    for state, values in iterhunks(fp):
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2021
        if state == 'hunk':
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2022
            if not current_file:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2023
                continue
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2024
            ret = current_file.apply(values)
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2025
            if ret > 0:
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2026
                err = 1
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2027
        elif state == 'file':
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2028
            if current_file:
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2029
                rejects += current_file.close()
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2030
                current_file = None
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2031
            afile, bfile, first_hunk, gp = values
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2032
            if gp:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2033
                gp.path = pstrip(gp.path)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2034
                if gp.oldpath:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2035
                    gp.oldpath = pstrip(gp.oldpath)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2036
            else:
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2037
                gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2038
                                   prefix)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2039
            if gp.op == 'RENAME':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2040
                backend.unlink(gp.oldpath)
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2041
            if not first_hunk:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2042
                if gp.op == 'DELETE':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2043
                    backend.unlink(gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2044
                    continue
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2045
                data, mode = None, None
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2046
                if gp.op in ('RENAME', 'COPY'):
14609
f53dc0787424 patch: extend filtestore to store an optional copy source
Patrick Mezard <pmezard@gmail.com>
parents: 14566
diff changeset
  2047
                    data, mode = store.getfile(gp.oldpath)[:2]
30078
173bdb502503 import: abort instead of crashing when copy source does not exist (issue5375)
Ryan McElroy <rmcelroy@fb.com>
parents: 29952
diff changeset
  2048
                    if data is None:
173bdb502503 import: abort instead of crashing when copy source does not exist (issue5375)
Ryan McElroy <rmcelroy@fb.com>
parents: 29952
diff changeset
  2049
                        # This means that the old path does not exist
173bdb502503 import: abort instead of crashing when copy source does not exist (issue5375)
Ryan McElroy <rmcelroy@fb.com>
parents: 29952
diff changeset
  2050
                        raise PatchError(_("source file '%s' does not exist")
173bdb502503 import: abort instead of crashing when copy source does not exist (issue5375)
Ryan McElroy <rmcelroy@fb.com>
parents: 29952
diff changeset
  2051
                                           % gp.oldpath)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2052
                if gp.mode:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2053
                    mode = gp.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2054
                    if gp.op == 'ADD':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2055
                        # Added files without content have no hunk and
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2056
                        # must be created
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2057
                        data = ''
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2058
                if data or mode:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2059
                    if (gp.op in ('ADD', 'RENAME', 'COPY')
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2060
                        and backend.exists(gp.path)):
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2061
                        raise PatchError(_("cannot create %s: destination "
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2062
                                           "already exists") % gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2063
                    backend.setfile(gp.path, data, mode, gp.oldpath)
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2064
                continue
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2065
            try:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2066
                current_file = patcher(ui, gp, backend, store,
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2067
                                       eolmode=eolmode)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25658
diff changeset
  2068
            except PatchError as inst:
14218
202ff575d49b patch: fix clash between local variable and exception instance
Martin Geisler <mg@aragost.com>
parents: 14217
diff changeset
  2069
                ui.warn(str(inst) + '\n')
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2070
                current_file = None
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2071
                rejects += 1
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2072
                continue
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2073
        elif state == 'git':
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2074
            for gp in values:
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2075
                path = pstrip(gp.oldpath)
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
  2076
                data, mode = backend.getfile(path)
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
  2077
                if data is None:
16813
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2078
                    # The error ignored here will trigger a getfile()
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2079
                    # error in a place more appropriate for error
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2080
                    # handling, and will not interrupt the patching
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2081
                    # process.
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
  2082
                    pass
16813
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2083
                else:
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2084
                    store.setfile(path, data, mode)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2085
        else:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26560
diff changeset
  2086
            raise error.Abort(_('unsupported parser state: %s') % state)
5649
a583117b536a patch: move NoHunk detection up with parsing code
Patrick Mezard <pmezard@gmail.com>
parents: 5581
diff changeset
  2087
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2088
    if current_file:
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2089
        rejects += current_file.close()
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2090
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2091
    if rejects:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2092
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2093
    return err
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2094
14382
2d16f15da7bd patch: remove patch.patch() cwd argument
Patrick Mezard <pmezard@gmail.com>
parents: 14381
diff changeset
  2095
def _externalpatch(ui, repo, patcher, patchname, strip, files,
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2096
                   similarity):
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2097
    """use <patcher> to apply <patchname> to the working directory.
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2098
    returns whether patch was applied with fuzz factor."""
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2099
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2100
    fuzz = False
12673
9ad16d1bce4b patch: simplify externalpatch() arguments
Patrick Mezard <pmezard@gmail.com>
parents: 12671
diff changeset
  2101
    args = []
14382
2d16f15da7bd patch: remove patch.patch() cwd argument
Patrick Mezard <pmezard@gmail.com>
parents: 14381
diff changeset
  2102
    cwd = repo.root
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2103
    if cwd:
37123
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37087
diff changeset
  2104
        args.append('-d %s' % procutil.shellquote(cwd))
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37087
diff changeset
  2105
    fp = procutil.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37087
diff changeset
  2106
                                             procutil.shellquote(patchname)))
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2107
    try:
30407
564b33acc21f patch: migrate to util.iterfile
Jun Wu <quark@fb.com>
parents: 30078
diff changeset
  2108
        for line in util.iterfile(fp):
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2109
            line = line.rstrip()
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2110
            ui.note(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2111
            if line.startswith('patching file '):
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2112
                pf = util.parsepatchoutput(line)
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2113
                printed_file = False
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2114
                files.add(pf)
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2115
            elif line.find('with fuzz') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2116
                fuzz = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2117
                if not printed_file:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2118
                    ui.warn(pf + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2119
                    printed_file = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2120
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2121
            elif line.find('saving rejects to file') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2122
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2123
            elif line.find('FAILED') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2124
                if not printed_file:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2125
                    ui.warn(pf + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2126
                    printed_file = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2127
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2128
    finally:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2129
        if files:
19155
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
  2130
            scmutil.marktouched(repo, files, similarity)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2131
    code = fp.close()
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2132
    if code:
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2133
        raise PatchError(_("patch command failed: %s") %
37123
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37087
diff changeset
  2134
                         procutil.explainexit(code)[0])
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2135
    return fuzz
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2136
24253
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2137
def patchbackend(ui, backend, patchobj, strip, prefix, files=None,
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2138
                 eolmode='strict'):
9683
5c8651e2f5e0 patch: don't use mutable object as default argument
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9682
diff changeset
  2139
    if files is None:
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2140
        files = set()
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2141
    if eolmode is None:
33229
dd50a370c8cb configitems: register the 'patch.eol' config
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 33162
diff changeset
  2142
        eolmode = ui.config('patch', 'eol')
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  2143
    if eolmode.lower() not in eolmodes:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26560
diff changeset
  2144
        raise error.Abort(_('unsupported line endings type: %s') % eolmode)
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  2145
    eolmode = eolmode.lower()
8843
eb7b247a98ea kill trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8817
diff changeset
  2146
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2147
    store = filestore()
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2148
    try:
9031
3b76321aa0de compat: use open() instead of file() everywhere
Alejandro Santos <alejolp@alejolp.com>
parents: 9029
diff changeset
  2149
        fp = open(patchobj, 'rb')
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2150
    except TypeError:
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2151
        fp = patchobj
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2152
    try:
24253
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2153
        ret = applydiff(ui, fp, backend, store, strip=strip, prefix=prefix,
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2154
                        eolmode=eolmode)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2155
    finally:
10203
6e26e3c2083f patch: explicitely close input patch files when leaving
Patrick Mezard <pmezard@gmail.com>
parents: 10135
diff changeset
  2156
        if fp != patchobj:
6e26e3c2083f patch: explicitely close input patch files when leaving
Patrick Mezard <pmezard@gmail.com>
parents: 10135
diff changeset
  2157
            fp.close()
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2158
        files.update(backend.close())
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2159
        store.close()
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2160
    if ret < 0:
12674
aa2fe1f52ff4 patch: always raise PatchError with a message, simplify handling
Patrick Mezard <pmezard@gmail.com>
parents: 12673
diff changeset
  2161
        raise PatchError(_('patch failed to apply'))
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2162
    return ret > 0
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2163
24268
cf7d252d8c30 patch.internalpatch: add a default value for prefix
Siddharth Agarwal <sid0@fb.com>
parents: 24265
diff changeset
  2164
def internalpatch(ui, repo, patchobj, strip, prefix='', files=None,
24254
60c279ab7bd3 patch.internalpatch: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24253
diff changeset
  2165
                  eolmode='strict', similarity=0):
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2166
    """use builtin patch to apply <patchobj> to the working directory.
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2167
    returns whether patch was applied with fuzz factor."""
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2168
    backend = workingbackend(ui, repo, similarity)
24254
60c279ab7bd3 patch.internalpatch: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24253
diff changeset
  2169
    return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2170
24260
76225ab5a5da cmdutil.tryimportone: allow importing relative patches with --bypass
Siddharth Agarwal <sid0@fb.com>
parents: 24259
diff changeset
  2171
def patchrepo(ui, repo, ctx, store, patchobj, strip, prefix, files=None,
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2172
              eolmode='strict'):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2173
    backend = repobackend(ui, repo, ctx, store)
24260
76225ab5a5da cmdutil.tryimportone: allow importing relative patches with --bypass
Siddharth Agarwal <sid0@fb.com>
parents: 24259
diff changeset
  2174
    return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2175
24259
5ac8ce04baa2 cmdutil.tryimportone: allow importing relative patches into the working dir
Siddharth Agarwal <sid0@fb.com>
parents: 24254
diff changeset
  2176
def patch(ui, repo, patchname, strip=1, prefix='', files=None, eolmode='strict',
14260
00a881581400 patch: make patch()/internalpatch() always update the dirstate
Patrick Mezard <pmezard@gmail.com>
parents: 14259
diff changeset
  2177
          similarity=0):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2178
    """Apply <patchname> to the working directory.
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2179
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2180
    'eolmode' specifies how end of lines should be handled. It can be:
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2181
    - 'strict': inputs are read in binary mode, EOLs are preserved
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2182
    - 'crlf': EOLs are ignored when patching and reset to CRLF
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2183
    - 'lf': EOLs are ignored when patching and reset to LF
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2184
    - None: get it from user settings, default to 'strict'
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2185
    'eolmode' is ignored when using an external patcher program.
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2186
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2187
    Returns whether patch was applied with fuzz factor.
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2188
    """
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2189
    patcher = ui.config('ui', 'patch')
9683
5c8651e2f5e0 patch: don't use mutable object as default argument
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9682
diff changeset
  2190
    if files is None:
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2191
        files = set()
21553
bee0e1cffdd3 import: add --partial flag to create a changeset despite failed hunks
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20972
diff changeset
  2192
    if patcher:
bee0e1cffdd3 import: add --partial flag to create a changeset despite failed hunks
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20972
diff changeset
  2193
        return _externalpatch(ui, repo, patcher, patchname, strip,
bee0e1cffdd3 import: add --partial flag to create a changeset despite failed hunks
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20972
diff changeset
  2194
                              files, similarity)
24259
5ac8ce04baa2 cmdutil.tryimportone: allow importing relative patches into the working dir
Siddharth Agarwal <sid0@fb.com>
parents: 24254
diff changeset
  2195
    return internalpatch(ui, repo, patchname, strip, prefix, files, eolmode,
21553
bee0e1cffdd3 import: add --partial flag to create a changeset despite failed hunks
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20972
diff changeset
  2196
                         similarity)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2197
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2198
def changedfiles(ui, repo, patchpath, strip=1, prefix=''):
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
  2199
    backend = fsbackend(ui, repo.root)
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2200
    prefix = _canonprefix(repo, prefix)
27796
f7f3958d39c0 with: use context manager for I/O in changedfiles in patch
Bryan O'Sullivan <bryano@fb.com>
parents: 27485
diff changeset
  2201
    with open(patchpath, 'rb') as fp:
14255
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2202
        changed = set()
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2203
        for state, values in iterhunks(fp):
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2204
            if state == 'file':
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2205
                afile, bfile, first_hunk, gp = values
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2206
                if gp:
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2207
                    gp.path = pathtransform(gp.path, strip - 1, prefix)[1]
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2208
                    if gp.oldpath:
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2209
                        gp.oldpath = pathtransform(gp.oldpath, strip - 1,
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2210
                                                   prefix)[1]
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2211
                else:
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  2212
                    gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
35085
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 35023
diff changeset
  2213
                                       prefix)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2214
                changed.add(gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2215
                if gp.op == 'RENAME':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2216
                    changed.add(gp.oldpath)
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2217
            elif state not in ('hunk', 'git'):
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26560
diff changeset
  2218
                raise error.Abort(_('unsupported parser state: %s') % state)
14255
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2219
        return changed
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2220
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2221
class GitDiffRequired(Exception):
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2222
    pass
7198
df79ee9b6278 patch: extract local function addmodehdr
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7186
diff changeset
  2223
23431
10223d2278f4 patch: rename diffopts to diffallopts
Siddharth Agarwal <sid0@fb.com>
parents: 23430
diff changeset
  2224
def diffallopts(ui, opts=None, untrusted=False, section='diff'):
23430
3821be85fd4d patch: add a new function to initialize diffopts by feature
Siddharth Agarwal <sid0@fb.com>
parents: 23429
diff changeset
  2225
    '''return diffopts with all features supported and parsed'''
23433
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2226
    return difffeatureopts(ui, opts=opts, untrusted=untrusted, section=section,
23434
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2227
                           git=True, whitespace=True, formatchanging=True)
23430
3821be85fd4d patch: add a new function to initialize diffopts by feature
Siddharth Agarwal <sid0@fb.com>
parents: 23429
diff changeset
  2228
23431
10223d2278f4 patch: rename diffopts to diffallopts
Siddharth Agarwal <sid0@fb.com>
parents: 23430
diff changeset
  2229
diffopts = diffallopts
10223d2278f4 patch: rename diffopts to diffallopts
Siddharth Agarwal <sid0@fb.com>
parents: 23430
diff changeset
  2230
23433
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2231
def difffeatureopts(ui, opts=None, untrusted=False, section='diff', git=False,
23434
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2232
                    whitespace=False, formatchanging=False):
23432
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2233
    '''return diffopts with only opted-in features parsed
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2234
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2235
    Features:
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2236
    - git: git-style diffs
23433
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2237
    - whitespace: whitespace options like ignoreblanklines and ignorews
23434
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2238
    - formatchanging: options that will likely break or cause correctness issues
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2239
      with most diff parsers
23432
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2240
    '''
23295
ac072c79bd9d patch.diffopts: break get function into if statements
Siddharth Agarwal <sid0@fb.com>
parents: 22460
diff changeset
  2241
    def get(key, name=None, getter=ui.configbool, forceplain=None):
ac072c79bd9d patch.diffopts: break get function into if statements
Siddharth Agarwal <sid0@fb.com>
parents: 22460
diff changeset
  2242
        if opts:
ac072c79bd9d patch.diffopts: break get function into if statements
Siddharth Agarwal <sid0@fb.com>
parents: 22460
diff changeset
  2243
            v = opts.get(key)
29952
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2244
            # diffopts flags are either None-default (which is passed
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2245
            # through unchanged, so we can identify unset values), or
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2246
            # some other falsey default (eg --unified, which defaults
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2247
            # to an empty string). We only want to override the config
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2248
            # entries from hgrc with command line values if they
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2249
            # appear to have been set, which is any truthy value,
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2250
            # True, or False.
e40343ce9c4c diffopts: notice a negated boolean flag in diffopts
Augie Fackler <augie@google.com>
parents: 29904
diff changeset
  2251
            if v or isinstance(v, bool):
23295
ac072c79bd9d patch.diffopts: break get function into if statements
Siddharth Agarwal <sid0@fb.com>
parents: 22460
diff changeset
  2252
                return v
23296
922fcfb02e77 patch.diffopts: allow a setting to be forced in plain mode
Siddharth Agarwal <sid0@fb.com>
parents: 23295
diff changeset
  2253
        if forceplain is not None and ui.plain():
922fcfb02e77 patch.diffopts: allow a setting to be forced in plain mode
Siddharth Agarwal <sid0@fb.com>
parents: 23295
diff changeset
  2254
            return forceplain
34521
aacb17cc0ee4 configitems: register the 'diff.*' config
Boris Feld <boris.feld@octobus.net>
parents: 34381
diff changeset
  2255
        return getter(section, name or key, untrusted=untrusted)
23295
ac072c79bd9d patch.diffopts: break get function into if statements
Siddharth Agarwal <sid0@fb.com>
parents: 22460
diff changeset
  2256
23434
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2257
    # core options, expected to be understood by every diff parser
23429
f35526b999f4 patch.diffopts: use a dict for initialization
Siddharth Agarwal <sid0@fb.com>
parents: 23300
diff changeset
  2258
    buildopts = {
f35526b999f4 patch.diffopts: use a dict for initialization
Siddharth Agarwal <sid0@fb.com>
parents: 23300
diff changeset
  2259
        'nodates': get('nodates'),
f35526b999f4 patch.diffopts: use a dict for initialization
Siddharth Agarwal <sid0@fb.com>
parents: 23300
diff changeset
  2260
        'showfunc': get('show_function', 'showfunc'),
f35526b999f4 patch.diffopts: use a dict for initialization
Siddharth Agarwal <sid0@fb.com>
parents: 23300
diff changeset
  2261
        'context': get('unified', getter=ui.config),
f35526b999f4 patch.diffopts: use a dict for initialization
Siddharth Agarwal <sid0@fb.com>
parents: 23300
diff changeset
  2262
    }
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2263
    buildopts['worddiff'] = ui.configbool('experimental', 'worddiff')
36705
c6a61298ac32 mdiff: add a config option to use xdiff algorithm
Jun Wu <quark@fb.com>
parents: 36675
diff changeset
  2264
    buildopts['xdiff'] = ui.configbool('experimental', 'xdiff')
23429
f35526b999f4 patch.diffopts: use a dict for initialization
Siddharth Agarwal <sid0@fb.com>
parents: 23300
diff changeset
  2265
23432
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2266
    if git:
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2267
        buildopts['git'] = get('git')
30788
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2268
30806
e2796f193f06 patch: add similarity config knob in experimental section
Sean Farley <sean@farley.io>
parents: 30790
diff changeset
  2269
        # since this is in the experimental section, we need to call
e2796f193f06 patch: add similarity config knob in experimental section
Sean Farley <sean@farley.io>
parents: 30790
diff changeset
  2270
        # ui.configbool directory
e2796f193f06 patch: add similarity config knob in experimental section
Sean Farley <sean@farley.io>
parents: 30790
diff changeset
  2271
        buildopts['showsimilarity'] = ui.configbool('experimental',
e2796f193f06 patch: add similarity config knob in experimental section
Sean Farley <sean@farley.io>
parents: 30790
diff changeset
  2272
                                                    'extendedheader.similarity')
e2796f193f06 patch: add similarity config knob in experimental section
Sean Farley <sean@farley.io>
parents: 30790
diff changeset
  2273
30788
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2274
        # need to inspect the ui object instead of using get() since we want to
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2275
        # test for an int
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2276
        hconf = ui.config('experimental', 'extendedheader.index')
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2277
        if hconf is not None:
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2278
            hlen = None
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2279
            try:
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2280
                # the hash config could be an integer (for length of hash) or a
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2281
                # word (e.g. short, full, none)
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2282
                hlen = int(hconf)
30819
897726622877 patch: check length of git index header only if integer is specified
Yuya Nishihara <yuya@tcha.org>
parents: 30808
diff changeset
  2283
                if hlen < 0 or hlen > 40:
897726622877 patch: check length of git index header only if integer is specified
Yuya Nishihara <yuya@tcha.org>
parents: 30808
diff changeset
  2284
                    msg = _("invalid length for extendedheader.index: '%d'\n")
897726622877 patch: check length of git index header only if integer is specified
Yuya Nishihara <yuya@tcha.org>
parents: 30808
diff changeset
  2285
                    ui.warn(msg % hlen)
30788
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2286
            except ValueError:
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2287
                # default value
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2288
                if hconf == 'short' or hconf == '':
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2289
                    hlen = 12
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2290
                elif hconf == 'full':
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2291
                    hlen = 40
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2292
                elif hconf != 'none':
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2293
                    msg = _("invalid value for extendedheader.index: '%s'\n")
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2294
                    ui.warn(msg % hconf)
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2295
            finally:
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2296
                buildopts['index'] = hlen
d1901c4c8ec0 patch: add config knob for displaying the index header
Sean Farley <sean@farley.io>
parents: 30417
diff changeset
  2297
23433
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2298
    if whitespace:
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2299
        buildopts['ignorews'] = get('ignore_all_space', 'ignorews')
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2300
        buildopts['ignorewsamount'] = get('ignore_space_change',
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2301
                                          'ignorewsamount')
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2302
        buildopts['ignoreblanklines'] = get('ignore_blank_lines',
41dd76b3facb patch.difffeatureopts: add a feature for whitespace diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23432
diff changeset
  2303
                                            'ignoreblanklines')
34031
da07367d683b mdiff: add a --ignore-space-at-eol option
David Soria Parra <davidsp@fb.com>
parents: 33671
diff changeset
  2304
        buildopts['ignorewseol'] = get('ignore_space_at_eol', 'ignorewseol')
23434
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2305
    if formatchanging:
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2306
        buildopts['text'] = opts and opts.get('text')
31822
fde4822b0102 diff: add --binary option for git mode diffs
Alexander Fomin <afomin@fb.com>
parents: 31821
diff changeset
  2307
        binary = None if opts is None else opts.get('binary')
fde4822b0102 diff: add --binary option for git mode diffs
Alexander Fomin <afomin@fb.com>
parents: 31821
diff changeset
  2308
        buildopts['nobinary'] = (not binary if binary is not None
fde4822b0102 diff: add --binary option for git mode diffs
Alexander Fomin <afomin@fb.com>
parents: 31821
diff changeset
  2309
                                 else get('nobinary', forceplain=False))
23434
60300a4c0ae5 patch.difffeatureopts: add a feature for format-changing diffopts
Siddharth Agarwal <sid0@fb.com>
parents: 23433
diff changeset
  2310
        buildopts['noprefix'] = get('noprefix', forceplain=False)
23432
27af986a332b patch.difffeatureopts: add a feature for diff.git
Siddharth Agarwal <sid0@fb.com>
parents: 23431
diff changeset
  2311
31636
a7acda2de4b8 diff: use pycompat.{byteskwargs, strkwargs} to switch opts b/w bytes and str
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31635
diff changeset
  2312
    return mdiff.diffopts(**pycompat.strkwargs(buildopts))
10615
3bb438ce4458 patch/diff: move diff related code next to each other
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10611
diff changeset
  2313
31284
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2314
def diff(repo, node1=None, node2=None, match=None, changes=None,
34856
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2315
         opts=None, losedatafn=None, prefix='', relroot='', copy=None,
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2316
         hunksfilterfn=None):
7308
b6f5490effbf patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7267
diff changeset
  2317
    '''yields diff of changes to files between two nodes, or node and
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2318
    working directory.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2319
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2320
    if node1 is None, use first dirstate parent instead.
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2321
    if node2 is None, compare node1 with working directory.
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2322
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2323
    losedatafn(**kwarg) is a callable run when opts.upgrade=True and
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2324
    every time some change cannot be represented with the current
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2325
    patch format. Return False to upgrade to git patch format, True to
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2326
    accept the loss or raise an exception to abort the diff. It is
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2327
    called with the name of current file being diffed as 'fn'. If set
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2328
    to None, patches will always be upgraded to git format when
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2329
    necessary.
12167
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2330
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2331
    prefix is a filename prefix that is prepended to all filenames on
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2332
    display (used for subrepos).
24417
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2333
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2334
    relroot, if not empty, must be normalized with a trailing /. Any match
29422
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2335
    patterns that fall outside it will be ignored.
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2336
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2337
    copy, if not empty, should contain mappings {dst@y: src@x} of copy
34856
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2338
    information.
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2339
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2340
    hunksfilterfn, if not None, should be a function taking a filectx and
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2341
    hunks generator that may yield filtered hunks.
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2342
    '''
34855
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2343
    for fctx1, fctx2, hdr, hunks in diffhunks(
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2344
            repo, node1=node1, node2=node2,
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2345
            match=match, changes=changes, opts=opts,
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2346
            losedatafn=losedatafn, prefix=prefix, relroot=relroot, copy=copy,
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2347
    ):
34856
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2348
        if hunksfilterfn is not None:
34908
907ff34e1460 log: add an assertion about fctx not being None in patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34856
diff changeset
  2349
            # If the file has been removed, fctx2 is None; but this should
907ff34e1460 log: add an assertion about fctx not being None in patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34856
diff changeset
  2350
            # not occur here since we catch removed files early in
35928
c8e2d6ed1f9e cmdutil: drop aliases for logcmdutil functions (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35890
diff changeset
  2351
            # logcmdutil.getlinerangerevs() for 'hg log -L'.
34908
907ff34e1460 log: add an assertion about fctx not being None in patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34856
diff changeset
  2352
            assert fctx2 is not None, \
907ff34e1460 log: add an assertion about fctx not being None in patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34856
diff changeset
  2353
                'fctx2 unexpectly None in diff hunks filtering'
34856
890afefa7296 diff: pass a diff hunks filter function from changeset_printer to patch.diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34855
diff changeset
  2354
            hunks = hunksfilterfn(fctx2, hunks)
31284
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2355
        text = ''.join(sum((list(hlines) for hrange, hlines in hunks), []))
34561
fe6125ebdf91 patch: rename "header" variable into "hdr" in diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34521
diff changeset
  2356
        if hdr and (text or len(hdr) > 1):
fe6125ebdf91 patch: rename "header" variable into "hdr" in diff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34521
diff changeset
  2357
            yield '\n'.join(hdr) + '\n'
31284
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2358
        if text:
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2359
            yield text
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2360
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2361
def diffhunks(repo, node1=None, node2=None, match=None, changes=None,
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2362
              opts=None, losedatafn=None, prefix='', relroot='', copy=None):
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2363
    """Yield diff of changes to files in the form of (`header`, `hunks`) tuples
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2364
    where `header` is a list of diff headers and `hunks` is an iterable of
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2365
    (`hunkrange`, `hunklines`) tuples.
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2366
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2367
    See diff() for the meaning of parameters.
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2368
    """
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2369
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2370
    if opts is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2371
        opts = mdiff.defaultopts
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2372
9725
3f522d2fa633 diff: add --inverse option
Yannick Gingras <ygingras@ygingras.net>
parents: 9712
diff changeset
  2373
    if not node1 and not node2:
13878
a8d13ee0ce68 misc: replace .parents()[0] with p1()
Matt Mackall <mpm@selenic.com>
parents: 13751
diff changeset
  2374
        node1 = repo.dirstate.p1()
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
  2375
9123
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2376
    def lrugetfilectx():
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2377
        cache = {}
25113
0ca8410ea345 util: drop alias for collections.deque
Martin von Zweigbergk <martinvonz@google.com>
parents: 24845
diff changeset
  2378
        order = collections.deque()
9123
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2379
        def getfilectx(f, ctx):
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2380
            fctx = ctx.filectx(f, filelog=cache.get(f))
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2381
            if f not in cache:
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2382
                if len(cache) > 20:
16803
107a3270a24a cleanup: use the deque type where appropriate
Bryan O'Sullivan <bryano@fb.com>
parents: 16705
diff changeset
  2383
                    del cache[order.popleft()]
9684
618af2034ca6 patch: use the public ctx API instead of the internals
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9683
diff changeset
  2384
                cache[f] = fctx.filelog()
9123
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2385
            else:
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2386
                order.remove(f)
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2387
            order.append(f)
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2388
            return fctx
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2389
        return getfilectx
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2390
    getfilectx = lrugetfilectx()
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
  2391
6747
f6c00b17387c use repo[changeid] to get a changectx
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
  2392
    ctx1 = repo[node1]
7090
7b5c063b0b94 diff: pass contexts to status
Matt Mackall <mpm@selenic.com>
parents: 6953
diff changeset
  2393
    ctx2 = repo[node2]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2394
24433
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2395
    relfiltered = False
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2396
    if relroot != '' and match.always():
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2397
        # as a special case, create a new matcher with just the relroot
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2398
        pats = [relroot]
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2399
        match = scmutil.match(ctx2, pats, default='path')
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2400
        relfiltered = True
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2401
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2402
    if not changes:
7090
7b5c063b0b94 diff: pass contexts to status
Matt Mackall <mpm@selenic.com>
parents: 6953
diff changeset
  2403
        changes = repo.status(ctx1, ctx2, match=match)
6760
4faaa0535ea7 status: clean up all users for unknown files
Matt Mackall <mpm@selenic.com>
parents: 6758
diff changeset
  2404
    modified, added, removed = changes[:3]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2405
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2406
    if not modified and not added and not removed:
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2407
        return []
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2408
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2409
    if repo.ui.debugflag:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2410
        hexfunc = hex
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2411
    else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2412
        hexfunc = short
21833
c1ceec0c8cb4 patch: use ctx.node() instead of bare node variable
Sean Farley <sean.michael.farley@gmail.com>
parents: 21790
diff changeset
  2413
    revs = [hexfunc(node) for node in [ctx1.node(), ctx2.node()] if node]
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2414
29422
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2415
    if copy is None:
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2416
        copy = {}
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2417
        if opts.git or opts.upgrade:
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2418
            copy = copies.pathcopies(ctx1, ctx2, match=match)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2419
24417
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2420
    if relroot is not None:
24433
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2421
        if not relfiltered:
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2422
            # XXX this would ideally be done in the matcher, but that is
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2423
            # generally meant to 'or' patterns, not 'and' them. In this case we
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2424
            # need to 'and' all the patterns from the matcher with relroot.
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2425
            def filterrel(l):
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2426
                return [f for f in l if f.startswith(relroot)]
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2427
            modified = filterrel(modified)
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2428
            added = filterrel(added)
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2429
            removed = filterrel(removed)
f5f4dc115fb2 patch.diff: restrict matcher to relative root in certain cases
Siddharth Agarwal <sid0@fb.com>
parents: 24417
diff changeset
  2430
            relfiltered = True
24417
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2431
        # filter out copies where either side isn't inside the relative root
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2432
        copy = dict(((dst, src) for (dst, src) in copy.iteritems()
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2433
                     if dst.startswith(relroot)
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2434
                     and src.startswith(relroot)))
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2435
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2436
    modifiedset = set(modified)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2437
    addedset = set(added)
27901
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2438
    removedset = set(removed)
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2439
    for f in modified:
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2440
        if f not in ctx1:
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2441
            # Fix up added, since merged-in additions appear as
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2442
            # modifications during merges
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2443
            modifiedset.remove(f)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2444
            addedset.add(f)
27901
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2445
    for f in removed:
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2446
        if f not in ctx1:
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2447
            # Merged-in additions that are then removed are reported as removed.
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2448
            # They are not in ctx1, so We don't want to show them in the diff.
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2449
            removedset.remove(f)
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2450
    modified = sorted(modifiedset)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2451
    added = sorted(addedset)
27901
29c8e35d3283 diff: don't crash when merged-in addition was removed (issue4786)
Martin von Zweigbergk <martinvonz@google.com>
parents: 27900
diff changeset
  2452
    removed = sorted(removedset)
35589
3328d53254d9 py3: use list() to get a list of items using dict.items()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35582
diff changeset
  2453
    for dst, src in list(copy.items()):
27902
51b6ce257e0a diff: don't crash when merged-in addition is copied
Martin von Zweigbergk <martinvonz@google.com>
parents: 27901
diff changeset
  2454
        if src not in ctx1:
51b6ce257e0a diff: don't crash when merged-in addition is copied
Martin von Zweigbergk <martinvonz@google.com>
parents: 27901
diff changeset
  2455
            # Files merged in during a merge and then copied/renamed are
51b6ce257e0a diff: don't crash when merged-in addition is copied
Martin von Zweigbergk <martinvonz@google.com>
parents: 27901
diff changeset
  2456
            # reported as copies. We want to show them in the diff as additions.
51b6ce257e0a diff: don't crash when merged-in addition is copied
Martin von Zweigbergk <martinvonz@google.com>
parents: 27901
diff changeset
  2457
            del copy[dst]
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2458
17299
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
  2459
    def difffn(opts, losedata):
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
  2460
        return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
24417
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2461
                       copy, getfilectx, opts, losedata, prefix, relroot)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2462
    if opts.upgrade and not opts.git:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2463
        try:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2464
            def losedata(fn):
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2465
                if not losedatafn or not losedatafn(fn=fn):
16687
e34106fa0dc3 cleanup: "raise SomeException()" -> "raise SomeException"
Brodie Rao <brodie@sf.io>
parents: 16686
diff changeset
  2466
                    raise GitDiffRequired
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2467
            # Buffer the whole output until we are sure it can be generated
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2468
            return list(difffn(opts.copy(git=False), losedata))
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2469
        except GitDiffRequired:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2470
            return difffn(opts.copy(git=True), None)
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2471
    else:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2472
        return difffn(opts, None)
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2473
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2474
def difflabel(func, *args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2475
    '''yields 2-tuples of (output, label) based on the output of func()'''
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2476
    inlinecolor = False
35375
dce761558329 py3: handle keyword arguments correctly in patch.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35337
diff changeset
  2477
    if kw.get(r'opts'):
dce761558329 py3: handle keyword arguments correctly in patch.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35337
diff changeset
  2478
        inlinecolor = kw[r'opts'].worddiff
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2479
    headprefixes = [('diff', 'diff.diffline'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2480
                    ('copy', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2481
                    ('rename', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2482
                    ('old', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2483
                    ('new', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2484
                    ('deleted', 'diff.extended'),
30790
dbcc10cf7f8d patch: add label for coloring the index extended header
Sean Farley <sean@farley.io>
parents: 30789
diff changeset
  2485
                    ('index', 'diff.extended'),
30808
8540967cd9e0 patch: add label for coloring the similarity extended header
Sean Farley <sean@farley.io>
parents: 30807
diff changeset
  2486
                    ('similarity', 'diff.extended'),
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2487
                    ('---', 'diff.file_a'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2488
                    ('+++', 'diff.file_b')]
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2489
    textprefixes = [('@', 'diff.hunk'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2490
                    ('-', 'diff.deleted'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2491
                    ('+', 'diff.inserted')]
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2492
    head = False
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2493
    for chunk in func(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2494
        lines = chunk.split('\n')
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2495
        matches = {}
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2496
        if inlinecolor:
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2497
            matches = _findmatches(lines)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2498
        for i, line in enumerate(lines):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2499
            if i != 0:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2500
                yield ('\n', '')
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2501
            if head:
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2502
                if line.startswith('@'):
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2503
                    head = False
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2504
            else:
16686
67964cda8701 cleanup: "not x in y" -> "x not in y"
Brodie Rao <brodie@sf.io>
parents: 16683
diff changeset
  2505
                if line and line[0] not in ' +-@\\':
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2506
                    head = True
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2507
            stripline = line
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2508
            diffline = False
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2509
            if not head and line and line[0] in '+-':
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2510
                # highlight tabs and trailing whitespace, but only in
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2511
                # changed lines
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2512
                stripline = line.rstrip()
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2513
                diffline = True
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2514
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2515
            prefixes = textprefixes
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2516
            if head:
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2517
                prefixes = headprefixes
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2518
            for prefix, label in prefixes:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2519
                if stripline.startswith(prefix):
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2520
                    if diffline:
35337
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2521
                        if i in matches:
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2522
                            for t, l in _inlinediff(lines[i].rstrip(),
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2523
                                                    lines[matches[i]].rstrip(),
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2524
                                                    label):
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2525
                                yield (t, l)
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2526
                        else:
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2527
                            for token in tabsplitter.findall(stripline):
36477
588048a6a8d3 py3: slice over bytes or use .startswith() to prevent getting ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 36453
diff changeset
  2528
                                if token.startswith('\t'):
35337
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2529
                                    yield (token, 'diff.tab')
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2530
                                else:
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2531
                                    yield (token, label)
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2532
                    else:
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2533
                        yield (stripline, label)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2534
                    break
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2535
            else:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2536
                yield (line, '')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2537
            if line != stripline:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2538
                yield (line[len(stripline):], 'diff.trailingwhitespace')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2539
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2540
def _findmatches(slist):
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2541
    '''Look for insertion matches to deletion and returns a dict of
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2542
    correspondences.
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2543
    '''
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2544
    lastmatch = 0
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2545
    matches = {}
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2546
    for i, line in enumerate(slist):
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2547
        if line == '':
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2548
            continue
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2549
        if line[0] == '-':
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2550
            lastmatch = max(lastmatch, i)
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2551
            newgroup = False
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2552
            for j, newline in enumerate(slist[lastmatch + 1:]):
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2553
                if newline == '':
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2554
                    continue
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2555
                if newline[0] == '-' and newgroup: # too far, no match
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2556
                    break
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2557
                if newline[0] == '+': # potential match
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2558
                    newgroup = True
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2559
                    sim = difflib.SequenceMatcher(None, line, newline).ratio()
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2560
                    if sim > 0.7:
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2561
                        lastmatch = lastmatch + 1 + j
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2562
                        matches[i] = lastmatch
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2563
                        matches[lastmatch] = i
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2564
                        break
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2565
    return matches
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2566
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2567
def _inlinediff(s1, s2, operation):
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2568
    '''Perform string diff to highlight specific changes.'''
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2569
    operation_skip = '+?' if operation == 'diff.deleted' else '-?'
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2570
    if operation == 'diff.deleted':
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2571
        s2, s1 = s1, s2
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2572
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2573
    buff = []
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2574
    # we never want to higlight the leading +-
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2575
    if operation == 'diff.deleted' and s2.startswith('-'):
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2576
        label = operation
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2577
        token = '-'
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2578
        s2 = s2[1:]
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2579
        s1 = s1[1:]
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2580
    elif operation == 'diff.inserted' and s1.startswith('+'):
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2581
        label = operation
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2582
        token = '+'
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2583
        s2 = s2[1:]
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2584
        s1 = s1[1:]
35320
12ce62c72c24 patch: catch unexpected case in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35319
diff changeset
  2585
    else:
12ce62c72c24 patch: catch unexpected case in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35319
diff changeset
  2586
        raise error.ProgrammingError("Case not expected, operation = %s" %
12ce62c72c24 patch: catch unexpected case in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35319
diff changeset
  2587
                                     operation)
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2588
35392
82c3762349ac patch: do not break up multibyte character when highlighting word
Yuya Nishihara <yuya@tcha.org>
parents: 35375
diff changeset
  2589
    s = difflib.ndiff(_nonwordre.split(s2), _nonwordre.split(s1))
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2590
    for part in s:
35337
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2591
        if part[0] in operation_skip or len(part) == 2:
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2592
            continue
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2593
        l = operation + '.highlight'
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2594
        if part[0] in ' ':
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2595
            l = operation
35337
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2596
        if part[2:] == '\t':
4937db58b663 patch: move part of tabsplitter logic in _inlinediff
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35320
diff changeset
  2597
            l = 'diff.tab'
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2598
        if l == label: # contiguous token with same label
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2599
            token += part[2:]
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2600
            continue
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2601
        else:
35319
10cce12fdcd3 patch: reverse _inlinediff output for consistency
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35286
diff changeset
  2602
            buff.append((token, label))
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2603
            label = l
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2604
            token = part[2:]
35319
10cce12fdcd3 patch: reverse _inlinediff output for consistency
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35286
diff changeset
  2605
    buff.append((token, label))
35286
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2606
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2607
    return buff
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35202
diff changeset
  2608
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2609
def diffui(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2610
    '''like diff(), but yields 2-tuples of (output, label) for ui.write()'''
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2611
    return difflabel(diff, *args, **kw)
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2612
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2613
def _filepairs(modified, added, removed, copy, opts):
24106
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2614
    '''generates tuples (f1, f2, copyop), where f1 is the name of the file
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2615
    before and f2 is the the name after. For added files, f1 will be None,
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2616
    and for removed files, f2 will be None. copyop may be set to None, 'copy'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2617
    or 'rename' (the latter two only if opts.git is set).'''
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2618
    gone = set()
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2619
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2620
    copyto = dict([(v, k) for k, v in copy.items()])
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2621
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2622
    addedset, removedset = set(added), set(removed)
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2623
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2624
    for f in sorted(modified + added + removed):
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2625
        copyop = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2626
        f1, f2 = f, f
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2627
        if f in addedset:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2628
            f1 = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2629
            if f in copy:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2630
                if opts.git:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2631
                    f1 = copy[f]
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2632
                    if f1 in removedset and f1 not in gone:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2633
                        copyop = 'rename'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2634
                        gone.add(f1)
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2635
                    else:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2636
                        copyop = 'copy'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2637
        elif f in removedset:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2638
            f2 = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2639
            if opts.git:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2640
                # have we already reported a copy above?
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2641
                if (f in copyto and copyto[f] in addedset
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2642
                    and copy[copyto[f]] == f):
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2643
                    continue
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2644
        yield f1, f2, copyop
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2645
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2646
def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2647
            copy, getfilectx, opts, losedatafn, prefix, relroot):
24371
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2648
    '''given input data, generate a diff and yield it in blocks
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2649
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2650
    If generating a diff would lose data like flags or binary data and
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2651
    losedatafn is not None, it will be called.
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2652
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2653
    relroot is removed and prefix is added to every path in the diff output.
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2654
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2655
    If relroot is not empty, this function expects every path in modified,
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2656
    added, removed and copy to start with it.'''
12167
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2657
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2658
    def gitindex(text):
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2659
        if not text:
19875
c172660eee01 patch: Fix nullid for binary git diffs (issue4054)
Johan Bjork <jbjoerk@gmail.com>
parents: 19513
diff changeset
  2660
            text = ""
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2661
        l = len(text)
29341
0d83ad967bf8 cleanup: replace uses of util.(md5|sha1|sha256|sha512) with hashlib.\1
Augie Fackler <raf@durin42.com>
parents: 29326
diff changeset
  2662
        s = hashlib.sha1('blob %d\0' % l)
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2663
        s.update(text)
35582
72b91f905065 py3: use node.hex(h.digest()) instead of h.hexdigest()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35392
diff changeset
  2664
        return hex(s.digest())
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2665
23300
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2666
    if opts.noprefix:
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2667
        aprefix = bprefix = ''
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2668
    else:
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2669
        aprefix = 'a/'
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2670
        bprefix = 'b/'
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2671
24021
f51a822dcf3b trydiff: remove unused argument to diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24020
diff changeset
  2672
    def diffline(f, revs):
24024
a5c7e86a81c1 trydiff: move check for quietness out of diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24023
diff changeset
  2673
        revinfo = ' '.join(["-r %s" % rev for rev in revs])
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2674
        return 'diff %s %s' % (revinfo, f)
17941
9a6e4d5d7ea8 diff: move diffline to patch module
Guillermo Pérez <bisho@fb.com>
parents: 17940
diff changeset
  2675
32234
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32233
diff changeset
  2676
    def isempty(fctx):
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32233
diff changeset
  2677
        return fctx is None or fctx.size() == 0
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32233
diff changeset
  2678
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36477
diff changeset
  2679
    date1 = dateutil.datestr(ctx1.date())
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36477
diff changeset
  2680
    date2 = dateutil.datestr(ctx2.date())
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  2681
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2682
    gitmode = {'l': '120000', 'x': '100755', '': '100644'}
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2683
33495
d78b7d734b63 patch: use devel.all-warnings to replace devel.all
Jun Wu <quark@fb.com>
parents: 33270
diff changeset
  2684
    if relroot != '' and (repo.ui.configbool('devel', 'all-warnings')
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2685
                          or repo.ui.configbool('devel', 'check-relroot')):
33584
ea8c2478c907 patch: update copying of dict keys and values to work on Python 3
Augie Fackler <augie@google.com>
parents: 33495
diff changeset
  2686
        for f in modified + added + removed + list(copy) + list(copy.values()):
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2687
            if f is not None and not f.startswith(relroot):
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2688
                raise AssertionError(
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2689
                    "file %s doesn't start with relroot %s" % (f, relroot))
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2690
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2691
    for f1, f2, copyop in _filepairs(modified, added, removed, copy, opts):
24105
0f8baebcdbea trydiff: read file data in only one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24104
diff changeset
  2692
        content1 = None
0f8baebcdbea trydiff: read file data in only one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24104
diff changeset
  2693
        content2 = None
32233
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2694
        fctx1 = None
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2695
        fctx2 = None
24103
c666c85f71ba trydiff: read flags in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24102
diff changeset
  2696
        flag1 = None
c666c85f71ba trydiff: read flags in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24102
diff changeset
  2697
        flag2 = None
24107
32e8d94b9473 trydiff: transpose 'if opts.git or losedatafn' with 'if f[12]'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24106
diff changeset
  2698
        if f1:
32233
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2699
            fctx1 = getfilectx(f1, ctx1)
24107
32e8d94b9473 trydiff: transpose 'if opts.git or losedatafn' with 'if f[12]'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24106
diff changeset
  2700
            if opts.git or losedatafn:
32e8d94b9473 trydiff: transpose 'if opts.git or losedatafn' with 'if f[12]'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24106
diff changeset
  2701
                flag1 = ctx1.flags(f1)
32e8d94b9473 trydiff: transpose 'if opts.git or losedatafn' with 'if f[12]'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24106
diff changeset
  2702
        if f2:
32233
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2703
            fctx2 = getfilectx(f2, ctx2)
24107
32e8d94b9473 trydiff: transpose 'if opts.git or losedatafn' with 'if f[12]'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24106
diff changeset
  2704
            if opts.git or losedatafn:
32e8d94b9473 trydiff: transpose 'if opts.git or losedatafn' with 'if f[12]'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24106
diff changeset
  2705
                flag2 = ctx2.flags(f2)
32236
0c67ab3d77d5 diff: correct binary testing logic
Jun Wu <quark@fb.com>
parents: 32235
diff changeset
  2706
        # if binary is True, output "summary" or "base85", but not "text diff"
35890
079b27b5a869 patch: avoid repeated binary checks if all files in a patch are text
Joerg Sonnenberger <joerg@bec.de>
parents: 35633
diff changeset
  2707
        if opts.text:
079b27b5a869 patch: avoid repeated binary checks if all files in a patch are text
Joerg Sonnenberger <joerg@bec.de>
parents: 35633
diff changeset
  2708
            binary = False
079b27b5a869 patch: avoid repeated binary checks if all files in a patch are text
Joerg Sonnenberger <joerg@bec.de>
parents: 35633
diff changeset
  2709
        else:
35990
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35928
diff changeset
  2710
            binary = any(f.isbinary() for f in [fctx1, fctx2] if f is not None)
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2711
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2712
        if losedatafn and not opts.git:
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2713
            if (binary or
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2714
                # copy/rename
24106
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2715
                f2 in copy or
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2716
                # empty file creation
32234
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32233
diff changeset
  2717
                (not f1 and isempty(fctx2)) or
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2718
                # empty file deletion
32234
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32233
diff changeset
  2719
                (isempty(fctx1) and not f2) or
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2720
                # create with flags
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2721
                (not f1 and flag2) or
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2722
                # change flags
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2723
                (f1 and f2 and flag1 != flag2)):
24106
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2724
                losedatafn(f2 or f1)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2725
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2726
        path1 = f1 or f2
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2727
        path2 = f2 or f1
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2728
        path1 = posixpath.join(prefix, path1[len(relroot):])
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2729
        path2 = posixpath.join(prefix, path2[len(relroot):])
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2730
        header = []
24022
da63f557d0dc trydiff: make 'revs' ignored if opts.git is set
Martin von Zweigbergk <martinvonz@google.com>
parents: 24021
diff changeset
  2731
        if opts.git:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2732
            header.append('diff --git %s%s %s%s' %
24020
cc81e6da0757 trydiff: move git-header code out of diffline function
Martin von Zweigbergk <martinvonz@google.com>
parents: 24005
diff changeset
  2733
                          (aprefix, path1, bprefix, path2))
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2734
            if not f1: # added
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2735
                header.append('new file mode %s' % gitmode[flag2])
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2736
            elif not f2: # removed
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2737
                header.append('deleted file mode %s' % gitmode[flag1])
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2738
            else:  # modified/copied/renamed
24000
82e3324c4df9 trydiff: inline sole addmodehdr() call
Martin von Zweigbergk <martinvonz@google.com>
parents: 23999
diff changeset
  2739
                mode1, mode2 = gitmode[flag1], gitmode[flag2]
82e3324c4df9 trydiff: inline sole addmodehdr() call
Martin von Zweigbergk <martinvonz@google.com>
parents: 23999
diff changeset
  2740
                if mode1 != mode2:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2741
                    header.append('old mode %s' % mode1)
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2742
                    header.append('new mode %s' % mode2)
24055
7f4e6b5fce03 trydiff: rename 'op' to make it more specific
Martin von Zweigbergk <martinvonz@google.com>
parents: 24025
diff changeset
  2743
                if copyop is not None:
30807
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
  2744
                    if opts.showsimilarity:
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
  2745
                        sim = similar.score(ctx1[path1], ctx2[path2]) * 100
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
  2746
                        header.append('similarity index %d%%' % sim)
24055
7f4e6b5fce03 trydiff: rename 'op' to make it more specific
Martin von Zweigbergk <martinvonz@google.com>
parents: 24025
diff changeset
  2747
                    header.append('%s from %s' % (copyop, path1))
7f4e6b5fce03 trydiff: rename 'op' to make it more specific
Martin von Zweigbergk <martinvonz@google.com>
parents: 24025
diff changeset
  2748
                    header.append('%s to %s' % (copyop, path2))
24024
a5c7e86a81c1 trydiff: move check for quietness out of diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24023
diff changeset
  2749
        elif revs and not repo.ui.quiet:
24022
da63f557d0dc trydiff: make 'revs' ignored if opts.git is set
Martin von Zweigbergk <martinvonz@google.com>
parents: 24021
diff changeset
  2750
            header.append(diffline(path1, revs))
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2751
32235
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2752
        #  fctx.is  | diffopts                | what to   | is fctx.data()
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2753
        #  binary() | text nobinary git index | output?   | outputted?
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2754
        # ------------------------------------|----------------------------
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2755
        #  yes      | no   no       no  *     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2756
        #  yes      | no   no       yes *     | base85    | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2757
        #  yes      | no   yes      no  *     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2758
        #  yes      | no   yes      yes 0     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2759
        #  yes      | no   yes      yes >0    | summary   | semi [1]
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2760
        #  yes      | yes  *        *   *     | text diff | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2761
        #  no       | *    *        *   *     | text diff | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32234
diff changeset
  2762
        # [1]: hash(fctx.data()) is outputted. so fctx.data() cannot be faked
32237
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2763
        if binary and (not opts.git or (opts.git and opts.nobinary and not
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2764
                                        opts.index)):
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2765
            # fast path: no binary content will be displayed, content1 and
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2766
            # content2 are only used for equivalent test. cmp() could have a
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2767
            # fast path.
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2768
            if fctx1 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2769
                content1 = b'\0'
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2770
            if fctx2 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2771
                if fctx1 is not None and not fctx1.cmp(fctx2):
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2772
                    content2 = b'\0' # not different
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2773
                else:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2774
                    content2 = b'\0\0'
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2775
        else:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2776
            # normal path: load contents
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2777
            if fctx1 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2778
                content1 = fctx1.data()
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2779
            if fctx2 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2780
                content2 = fctx2.data()
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
  2781
32236
0c67ab3d77d5 diff: correct binary testing logic
Jun Wu <quark@fb.com>
parents: 32235
diff changeset
  2782
        if binary and opts.git and not opts.nobinary:
23997
8b88870cbd1e trydiff: make variable names more consistent
Martin von Zweigbergk <martinvonz@google.com>
parents: 23996
diff changeset
  2783
            text = mdiff.b85diff(content1, content2)
24056
ae453d166d51 trydiff: replace 'binarydiff' variable by 'binary' variable
Martin von Zweigbergk <martinvonz@google.com>
parents: 24055
diff changeset
  2784
            if text:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2785
                header.append('index %s..%s' %
24005
2c166f6b5d10 trydiff: inline indexmeta()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24001
diff changeset
  2786
                              (gitindex(content1), gitindex(content2)))
31284
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31283
diff changeset
  2787
            hunks = (None, [text]),
23753
e30c6aa6f2a2 trydiff: replace 'dodiff = False' by 'continue'
Martin von Zweigbergk <martinvonz@google.com>
parents: 23752
diff changeset
  2788
        else:
30789
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2789
            if opts.git and opts.index > 0:
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2790
                flag = flag1
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2791
                if flag is None:
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2792
                    flag = flag2
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2793
                header.append('index %s..%s %s' %
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2794
                              (gitindex(content1)[0:opts.index],
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2795
                               gitindex(content2)[0:opts.index],
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2796
                               gitmode[flag]))
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2797
31283
92714858dd3e mdiff: let unidiff return (diffheader, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31281
diff changeset
  2798
            uheaders, hunks = mdiff.unidiff(content1, date1,
92714858dd3e mdiff: let unidiff return (diffheader, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31281
diff changeset
  2799
                                            content2, date2,
35990
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35928
diff changeset
  2800
                                            path1, path2,
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35928
diff changeset
  2801
                                            binary=binary, opts=opts)
31281
b3861be6aa6c mdiff: distinguish diff headers from hunks in unidiff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31243
diff changeset
  2802
            header.extend(uheaders)
34855
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2803
        yield fctx1, fctx2, header, hunks
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2804
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2805
def diffstatsum(stats):
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2806
    maxfile, maxtotal, addtotal, removetotal, binary = 0, 0, 0, 0, False
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2807
    for f, a, r, b in stats:
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2808
        maxfile = max(maxfile, encoding.colwidth(f))
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2809
        maxtotal = max(maxtotal, a + r)
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2810
        addtotal += a
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2811
        removetotal += r
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2812
        binary = binary or b
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2813
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2814
    return maxfile, maxtotal, addtotal, removetotal, binary
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2815
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2816
def diffstatdata(lines):
13395
104c9ed93fc5 diffstat: fix parsing of filenames with spaces
Gastón Kleiman <gaston.kleiman@gmail.com>
parents: 13112
diff changeset
  2817
    diffre = re.compile('^diff .*-r [a-z0-9]+\s(.*)$')
104c9ed93fc5 diffstat: fix parsing of filenames with spaces
Gastón Kleiman <gaston.kleiman@gmail.com>
parents: 13112
diff changeset
  2818
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2819
    results = []
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2820
    filename, adds, removes, isbinary = None, 0, 0, False
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2821
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2822
    def addresult():
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2823
        if filename:
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2824
            results.append((filename, adds, removes, isbinary))
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2825
32360
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2826
    # inheader is used to track if a line is in the
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2827
    # header portion of the diff.  This helps properly account
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2828
    # for lines that start with '--' or '++'
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2829
    inheader = False
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2830
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2831
    for line in lines:
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2832
        if line.startswith('diff'):
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2833
            addresult()
32360
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2834
            # starting a new file diff
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2835
            # set numbers to 0 and reset inheader
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2836
            inheader = True
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2837
            adds, removes, isbinary = 0, 0, False
18830
6b827d84d286 patch: match 'diff --git a/' instead of 'diff --git'
Sean Farley <sean.michael.farley@gmail.com>
parents: 18824
diff changeset
  2838
            if line.startswith('diff --git a/'):
20972
4e2fb0ad00a9 diff: use second filename for --stat reporting on git patches (issue4221)
Matt Mackall <mpm@selenic.com>
parents: 20869
diff changeset
  2839
                filename = gitre.search(line).group(2)
13395
104c9ed93fc5 diffstat: fix parsing of filenames with spaces
Gastón Kleiman <gaston.kleiman@gmail.com>
parents: 13112
diff changeset
  2840
            elif line.startswith('diff -r'):
8761
0289f384e1e5 Generally replace "file name" with "filename" in help and comments.
timeless <timeless@gmail.com>
parents: 8632
diff changeset
  2841
                # format: "diff -r ... -r ... filename"
13395
104c9ed93fc5 diffstat: fix parsing of filenames with spaces
Gastón Kleiman <gaston.kleiman@gmail.com>
parents: 13112
diff changeset
  2842
                filename = diffre.search(line).group(1)
32360
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2843
        elif line.startswith('@@'):
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2844
            inheader = False
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2845
        elif line.startswith('+') and not inheader:
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2846
            adds += 1
32360
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32245
diff changeset
  2847
        elif line.startswith('-') and not inheader:
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2848
            removes += 1
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2849
        elif (line.startswith('GIT binary patch') or
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2850
              line.startswith('Binary file')):
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2851
            isbinary = True
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2852
    addresult()
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2853
    return results
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2854
30417
e1677cc29da6 patch: remove unused git parameter from patch.diffstat()
Henning Schild <henning@hennsch.de>
parents: 30407
diff changeset
  2855
def diffstat(lines, width=80):
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2856
    output = []
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2857
    stats = diffstatdata(lines)
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2858
    maxname, maxtotal, totaladds, totalremoves, hasbinary = diffstatsum(stats)
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2859
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2860
    countwidth = len(str(maxtotal))
9642
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2861
    if hasbinary and countwidth < 3:
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2862
        countwidth = 3
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2863
    graphwidth = width - countwidth - maxname - 6
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2864
    if graphwidth < 10:
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2865
        graphwidth = 10
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2866
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2867
    def scale(i):
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2868
        if maxtotal <= graphwidth:
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2869
            return i
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2870
        # If diffstat runs out of room it doesn't print anything,
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2871
        # which isn't very useful, so always print at least one + or -
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2872
        # if there were at least some changes.
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2873
        return max(i * graphwidth // maxtotal, int(bool(i)))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2874
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2875
    for filename, adds, removes, isbinary in stats:
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2876
        if isbinary:
9642
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2877
            count = 'Bin'
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2878
        else:
33116
53238678b1ca py3: use '%d' to convert integers to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 33108
diff changeset
  2879
            count = '%d' % (adds + removes)
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2880
        pluses = '+' * scale(adds)
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2881
        minuses = '-' * scale(removes)
11611
4f5a6df2af92 i18n: use encoding.colwidth() for correct column width
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11377
diff changeset
  2882
        output.append(' %s%s |  %*s %s%s\n' %
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2883
                      (filename, ' ' * (maxname - encoding.colwidth(filename)),
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2884
                       countwidth, count, pluses, minuses))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2885
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2886
    if stats:
16683
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  2887
        output.append(_(' %d files changed, %d insertions(+), '
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  2888
                        '%d deletions(-)\n')
7860
162fd31bbd93 diffstat: use width 80 by default and avoid division by zero
Matt Mackall <mpm@selenic.com>
parents: 7783
diff changeset
  2889
                      % (len(stats), totaladds, totalremoves))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2890
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2891
    return ''.join(output)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2892
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2893
def diffstatui(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2894
    '''like diffstat(), but yields 2-tuples of (output, label) for
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2895
    ui.write()
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2896
    '''
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2897
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2898
    for line in diffstat(*args, **kw).splitlines():
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2899
        if line and line[-1] in '+-':
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2900
            name, graph = line.rsplit(' ', 1)
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2901
            yield (name + ' ', '')
33108
d9962854a4a2 py3: add b'' to make the regex pattern bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 33006
diff changeset
  2902
            m = re.search(br'\++', graph)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2903
            if m:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2904
                yield (m.group(0), 'diffstat.inserted')
33108
d9962854a4a2 py3: add b'' to make the regex pattern bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 33006
diff changeset
  2905
            m = re.search(br'-+', graph)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2906
            if m:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2907
                yield (m.group(0), 'diffstat.deleted')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2908
        else:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2909
            yield (line, '')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2910
        yield ('\n', '')