mercurial/patch.py
author Pierre-Yves David <pierre-yves.david@octobus.net>
Sun, 17 Mar 2019 12:30:52 +0000
changeset 42019 5a1e621b8186
parent 41987 c1d83d916e85
child 42071 db72f9f6580e
permissions -rw-r--r--
perf: introduce a `perf.run-limits` options This options make it possible to configure the number of run that the extensions will perform. This is useful for automated benchmark or for performance measurement that need better accuracy.
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
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
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
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
    12
import contextlib
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    13
import copy
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 re
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    19
import shutil
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    20
import zlib
10965
7faef79a89c7 patch: move mercurial-specific imports after stdlib imports
Augie Fackler <durin42@gmail.com>
parents: 10905
diff changeset
    21
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    22
from .i18n import _
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    23
from .node import (
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    24
    hex,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    25
    short,
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    26
)
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    27
from . import (
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    28
    copies,
37803
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
    29
    diffhelper,
38588
1c93e0237a24 diffutil: move the module out of utils package
Yuya Nishihara <yuya@tcha.org>
parents: 38587
diff changeset
    30
    diffutil,
27485
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,
30924
48dea083f66d py3: convert the mode argument of os.fdopen to unicodes (1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30819
diff changeset
    36
    pycompat,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    37
    scmutil,
30807
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
    38
    similar,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    39
    util,
31233
067f2a95e32c vfs: use 'vfs' module directly in 'mercurial.patch'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31216
diff changeset
    40
    vfs as vfsmod,
27485
60183975b5bc patch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27412
diff changeset
    41
)
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36838
diff changeset
    42
from .utils import (
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36838
diff changeset
    43
    dateutil,
37120
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
    44
    procutil,
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36838
diff changeset
    45
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36838
diff changeset
    46
)
32370
017ad85e5ac8 diffhelpers: switch to policy importer
Yuya Nishihara <yuya@tcha.org>
parents: 32320
diff changeset
    47
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
    48
stringio = util.stringio
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
    49
31630
451c980a8b57 patch: make regular expressions bytes by adding b''
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31274
diff changeset
    50
gitre = re.compile(br'diff --git a/(.*) b/(.*)')
451c980a8b57 patch: make regular expressions bytes by adding b''
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31274
diff changeset
    51
tabsplitter = re.compile(br'(\t+|[^\t]+)')
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
    52
wordsplitter = re.compile(br'(\t+| +|[a-zA-Z0-9_\x80-\xff]+|'
38052
468797392cc6 patch: fix import-time syntax error in test-check-module-imports.t
Augie Fackler <augie@google.com>
parents: 38048
diff changeset
    53
                          b'[^ \ta-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
    54
34251
61714510220d error: move patch.PatchError so it can easily implement __bytes__ (API)
Yuya Nishihara <yuya@tcha.org>
parents: 34137
diff changeset
    55
PatchError = error.PatchError
2933
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    56
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    57
# public functions
439fd013360d Move import's working dir update code into patch.updatedir
Brendan Cully <brendan@kublai.com>
parents: 2922
diff changeset
    58
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    59
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
    60
    '''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
    61
    def isheader(line, inheader):
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
    62
        if inheader and line.startswith((' ', '\t')):
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    63
            # continuation
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    64
            return True
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
    65
        if line.startswith((' ', '-', '+')):
10883
196908117c27 patch: don't look for headers in diff lines
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 10748
diff changeset
    66
            # 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
    67
            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
    68
        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
    69
        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
    70
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    71
    def chunk(lines):
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
    72
        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
    73
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    74
    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
    75
        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
    76
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    77
        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
    78
            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
    79
                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
    80
            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
    81
                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
    82
                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
                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
    84
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    85
            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
    86
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    87
        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
    88
            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
    89
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    90
    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
    91
        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
    92
            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
    93
                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
    94
                    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
    95
                cur = []
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    96
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    97
            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
    98
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
    99
        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
   100
            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
   101
                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
   102
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   103
    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
   104
        def msgfp(m):
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
   105
            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
   106
            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
   107
            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
   108
            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
   109
            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
   110
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   111
        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
   112
            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
   113
        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
   114
38332
7b12a2d2eedc py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents: 38329
diff changeset
   115
        m = mail.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
   116
        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
   117
            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
   118
        else:
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   119
            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
   120
            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
   121
                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
   122
                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
   123
                    continue
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   124
                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
   125
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   126
    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
   127
        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
   128
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   129
        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
   130
            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
   131
                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
   132
                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
                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
   134
            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
   135
                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
   136
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   137
            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
   138
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   139
        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
   140
            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
   141
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   142
    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
   143
        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
   144
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   145
    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
   146
        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
   147
            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
   148
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   149
        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
   150
            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
   151
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   152
        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
   153
            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
   154
            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
   155
                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
   156
            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
   157
35191
a1d2fc32bb99 py3: define __next__ in patch.py
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35062
diff changeset
   158
        __next__ = next
a1d2fc32bb99 py3: define __next__ in patch.py
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35062
diff changeset
   159
10384
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   160
    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
   161
    cur = []
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   162
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   163
    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
   164
14966
0588fb0e2e8d patch: use safehasattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14832
diff changeset
   165
    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
   166
        # 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
   167
        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
   168
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   169
    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
   170
        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
   171
        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
   172
            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
   173
        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
   174
            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
   175
        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
   176
            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
   177
            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
   178
                # 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
   179
                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
   180
        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
   181
            # 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
   182
            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
   183
        # 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
   184
832f35386067 import: import each patch in a file or stream as a separate change
Brendan Cully <brendan@kublai.com>
parents: 10282
diff changeset
   185
    # 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
   186
    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
   187
26557
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   188
## 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
   189
# 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
   190
patchheadermap = [('Date', 'date'),
dbd4392daedf extract: parse 'branch' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26558
diff changeset
   191
                  ('Branch', 'branch'),
26560
75d448d56a9d extract: parse 'nodeid' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26559
diff changeset
   192
                  ('Node ID', 'nodeid'),
26559
dbd4392daedf extract: parse 'branch' using the generic mechanism
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26558
diff changeset
   193
                 ]
26557
23f3f1cbd53b extract: add some facility for extensible header parsing
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26556
diff changeset
   194
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   195
@contextlib.contextmanager
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
38164
aac4be30e250 py3: wrap tempfile.mkstemp() to use bytes path
Yuya Nishihara <yuya@tcha.org>
parents: 38092
diff changeset
   213
    fd, tmpname = pycompat.mkstemp(prefix='hg-patch-')
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   214
    tmpfp = os.fdopen(fd, r'wb')
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   215
    try:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   216
        yield _extract(ui, fileobj, tmpname, tmpfp)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   217
    finally:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   218
        tmpfp.close()
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   219
        os.unlink(tmpname)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   220
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   221
def _extract(ui, fileobj, tmpname, tmpfp):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   222
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   223
    # 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
   224
    # (this heuristic is borrowed from quilt)
34964
7ebf850d3166 patch: improve heuristics to not take the word "diff" as header (issue1879)
Yuya Nishihara <yuya@tcha.org>
parents: 34908
diff changeset
   225
    diffre = re.compile(br'^(?:Index:[ \t]|diff[ \t]-|RCS file: |'
34066
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34042
diff changeset
   226
                        br'retrieving revision [0-9]+(\.[0-9]+)*$|'
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34042
diff changeset
   227
                        br'---[ \t].*?^\+\+\+[ \t]|'
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34042
diff changeset
   228
                        br'\*\*\*[ \t].*?^---[ \t])',
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34042
diff changeset
   229
                        re.MULTILINE | re.DOTALL)
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   230
26547
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   231
    data = {}
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   232
38332
7b12a2d2eedc py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents: 38329
diff changeset
   233
    msg = mail.parse(fileobj)
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   234
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   235
    subject = msg[r'Subject'] and mail.headdecode(msg[r'Subject'])
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   236
    data['user'] = msg[r'From'] and mail.headdecode(msg[r'From'])
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   237
    if not subject and not data['user']:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   238
        # Not an email, restore parsed headers if any
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   239
        subject = '\n'.join(': '.join(map(encoding.strtolocal, h))
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   240
                            for h in msg.items()) + '\n'
9573
b8352a3617f3 patch: do not swallow header-like patch first line (issue1859)
Patrick Mezard <pmezard@gmail.com>
parents: 9243
diff changeset
   241
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   242
    # should try to parse msg['Date']
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   243
    parents = []
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   244
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   245
    if subject:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   246
        if subject.startswith('[PATCH'):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   247
            pend = subject.find(']')
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   248
            if pend >= 0:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   249
                subject = subject[pend + 1:].lstrip()
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   250
        subject = re.sub(br'\n[ \t]+', ' ', subject)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   251
        ui.debug('Subject: %s\n' % subject)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   252
    if data['user']:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   253
        ui.debug('From: %s\n' % data['user'])
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   254
    diffs_seen = 0
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   255
    ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   256
    message = ''
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   257
    for part in msg.walk():
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   258
        content_type = pycompat.bytestr(part.get_content_type())
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   259
        ui.debug('Content-Type: %s\n' % content_type)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   260
        if content_type not in ok_types:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   261
            continue
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   262
        payload = part.get_payload(decode=True)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   263
        m = diffre.search(payload)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   264
        if m:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   265
            hgpatch = False
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   266
            hgpatchheader = False
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   267
            ignoretext = False
4220
1253703853a8 git-send-email compatibility: stop reading changelog after ^---$
Brendan Cully <brendan@kublai.com>
parents: 4208
diff changeset
   268
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   269
            ui.debug('found patch at byte %d\n' % m.start(0))
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   270
            diffs_seen += 1
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   271
            cfp = stringio()
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   272
            for line in payload[:m.start(0)].splitlines():
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   273
                if line.startswith('# HG changeset patch') and not hgpatch:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   274
                    ui.debug('patch generated by hg export\n')
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   275
                    hgpatch = True
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   276
                    hgpatchheader = True
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   277
                    # drop earlier commit message content
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   278
                    cfp.seek(0)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   279
                    cfp.truncate()
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   280
                    subject = None
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   281
                elif hgpatchheader:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   282
                    if line.startswith('# User '):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   283
                        data['user'] = line[7:]
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   284
                        ui.debug('From: %s\n' % data['user'])
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   285
                    elif line.startswith("# Parent "):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   286
                        parents.append(line[9:].lstrip())
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   287
                    elif line.startswith("# "):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   288
                        for header, key in patchheadermap:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   289
                            prefix = '# %s ' % header
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   290
                            if line.startswith(prefix):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   291
                                data[key] = line[len(prefix):]
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   292
                    else:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   293
                        hgpatchheader = False
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   294
                elif line == '---':
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   295
                    ignoretext = True
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   296
                if not hgpatchheader and not ignoretext:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   297
                    cfp.write(line)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   298
                    cfp.write('\n')
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   299
            message = cfp.getvalue()
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   300
            if tmpfp:
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   301
                tmpfp.write(payload)
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   302
                if not payload.endswith('\n'):
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   303
                    tmpfp.write('\n')
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   304
        elif not diffs_seen and message and content_type == 'text/plain':
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   305
            message += '\n' + payload
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   306
4777
5ee5cbfceff3 patch.extract: do not prepend subject if the description already starts with it
Brendan Cully <brendan@kublai.com>
parents: 4659
diff changeset
   307
    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
   308
        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
   309
    data['message'] = message
2866
2893e51407a4 commands.import: refactor patch parsing into patch.extract.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2865
diff changeset
   310
    tmpfp.close()
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
   311
    if parents:
26550
72782f60dbc9 extract: directly assign parent to data dictionary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26549
diff changeset
   312
        data['p1'] = parents.pop(0)
26548
25a58881efdd extract: simplify parents assignement
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26547
diff changeset
   313
        if parents:
26550
72782f60dbc9 extract: directly assign parent to data dictionary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26549
diff changeset
   314
            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
   315
26555
1e33384ff2ed extract: use a single return
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26554
diff changeset
   316
    if diffs_seen:
1e33384ff2ed extract: use a single return
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26554
diff changeset
   317
        data['filename'] = tmpname
37621
5537d8f5e989 patch: make extract() a context manager (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37574
diff changeset
   318
26547
b9be8ab6e628 patch: move 'extract' return to a dictionnary
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26421
diff changeset
   319
    return data
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   320
8778
c5f36402daad use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 8761
diff changeset
   321
class patchmeta(object):
7148
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   322
    """Patched file metadata
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   323
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   324
    '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
   325
    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
   326
    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
   327
    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
   328
    '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
   329
    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
   330
    """
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   331
    def __init__(self, path):
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   332
        self.path = path
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   333
        self.oldpath = None
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   334
        self.mode = None
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   335
        self.op = 'MODIFY'
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   336
        self.binary = False
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   337
7149
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   338
    def setmode(self, mode):
25658
e93036747902 global: mass rewrite to use modern octal syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25644
diff changeset
   339
        islink = mode & 0o20000
e93036747902 global: mass rewrite to use modern octal syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25644
diff changeset
   340
        isexec = mode & 0o100
7149
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   341
        self.mode = (islink, isexec)
01a056c54385 patch: patchmeta gives (islink, isexec) tuple instead of int mode
Patrick Mezard <pmezard@gmail.com>
parents: 7148
diff changeset
   342
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   343
    def copy(self):
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   344
        other = patchmeta(self.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   345
        other.oldpath = self.oldpath
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   346
        other.mode = self.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   347
        other.op = self.op
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   348
        other.binary = self.binary
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   349
        return other
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   350
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   351
    def _ispatchinga(self, afile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   352
        if afile == '/dev/null':
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   353
            return self.op == 'ADD'
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   354
        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
   355
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   356
    def _ispatchingb(self, bfile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   357
        if bfile == '/dev/null':
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   358
            return self.op == 'DELETE'
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   359
        return bfile == 'b/' + self.path
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   360
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   361
    def ispatching(self, afile, bfile):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
   362
        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
   363
11018
17cf756ba25d patch: descriptive patchmeta.__repr__ to help debugging
Mads Kiilerich <mads@kiilerich.com>
parents: 10966
diff changeset
   364
    def __repr__(self):
41624
3751595ec45e py3: make sure __repr__ returns str
Pulkit Goyal <pulkit@yandex-team.ru>
parents: 41620
diff changeset
   365
        return r"<patchmeta %s %r>" % (self.op, self.path)
11018
17cf756ba25d patch: descriptive patchmeta.__repr__ to help debugging
Mads Kiilerich <mads@kiilerich.com>
parents: 10966
diff changeset
   366
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
   367
def readgitpatch(lr):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   368
    """extract git-style metadata about patches from <patchname>"""
3223
53e843840349 Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3199
diff changeset
   369
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   370
    # Filter patch for git information
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   371
    gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   372
    gitpatches = []
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
   373
    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
   374
        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
   375
        if line.startswith('diff --git a/'):
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   376
            m = gitre.match(line)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   377
            if m:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   378
                if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   379
                    gitpatches.append(gp)
9392
039bce1b505f patch: readgitpatch: remove unused variable 'src'
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9331
diff changeset
   380
                dst = m.group(2)
7148
7d84e5b00e29 patch: extract and rename gitpatch into patchmeta, document
Patrick Mezard <pmezard@gmail.com>
parents: 7147
diff changeset
   381
                gp = patchmeta(dst)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   382
        elif gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   383
            if line.startswith('--- '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   384
                gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   385
                gp = None
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   386
                continue
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   387
            if line.startswith('rename from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   388
                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
   389
                gp.oldpath = line[12:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   390
            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
   391
                gp.path = line[10:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   392
            elif line.startswith('copy from '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   393
                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
   394
                gp.oldpath = line[10:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   395
            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
   396
                gp.path = line[8:]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   397
            elif line.startswith('deleted file'):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   398
                gp.op = 'DELETE'
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   399
            elif line.startswith('new file mode '):
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   400
                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
   401
                gp.setmode(int(line[-6:], 8))
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   402
            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
   403
                gp.setmode(int(line[-6:], 8))
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   404
            elif line.startswith('GIT binary patch'):
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
   405
                gp.binary = True
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   406
    if gp:
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   407
        gitpatches.append(gp)
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   408
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
   409
    return gitpatches
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
   410
8891
5fe8dc75aa4a patch: use new style class in linereader
Simon Heimberg <simohe@besonet.ch>
parents: 8843
diff changeset
   411
class linereader(object):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   412
    # 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
   413
    def __init__(self, fp):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   414
        self.fp = fp
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   415
        self.buf = []
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 push(self, line):
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   418
        if line is not None:
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   419
            self.buf.append(line)
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   420
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   421
    def readline(self):
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   422
        if self.buf:
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   423
            l = self.buf[0]
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   424
            del self.buf[0]
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   425
            return l
14418
0174d1f79280 patch: remove EOL support from linereader class
Patrick Mezard <pmezard@gmail.com>
parents: 14402
diff changeset
   426
        return self.fp.readline()
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   427
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   428
    def __iter__(self):
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
   429
        return iter(self.readline, '')
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
   430
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   431
class abstractbackend(object):
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   432
    def __init__(self, ui):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   433
        self.ui = ui
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   434
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   435
    def getfile(self, fname):
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   436
        """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
   437
        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
   438
        """
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   439
        raise NotImplementedError
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   440
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   441
    def setfile(self, fname, data, mode, copysource):
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   442
        """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
   443
        (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
   444
        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
   445
        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
   446
        """
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   447
        raise NotImplementedError
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   448
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   449
    def unlink(self, fname):
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   450
        """Unlink target file."""
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   451
        raise NotImplementedError
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   452
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   453
    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
   454
        """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
   455
        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
   456
        files.
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   457
        """
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   458
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   459
    def exists(self, fname):
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   460
        raise NotImplementedError
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   461
33155
b8ae289a7707 patch: add close() to abstractbackend
Martin von Zweigbergk <martinvonz@google.com>
parents: 33104
diff changeset
   462
    def close(self):
b8ae289a7707 patch: add close() to abstractbackend
Martin von Zweigbergk <martinvonz@google.com>
parents: 33104
diff changeset
   463
        raise NotImplementedError
b8ae289a7707 patch: add close() to abstractbackend
Martin von Zweigbergk <martinvonz@google.com>
parents: 33104
diff changeset
   464
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   465
class fsbackend(abstractbackend):
14350
00da6624e167 patch: move copyfile() into backends, abstract basedir
Patrick Mezard <pmezard@gmail.com>
parents: 14349
diff changeset
   466
    def __init__(self, ui, basedir):
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   467
        super(fsbackend, self).__init__(ui)
31233
067f2a95e32c vfs: use 'vfs' module directly in 'mercurial.patch'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31216
diff changeset
   468
        self.opener = vfsmod.vfs(basedir)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   469
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   470
    def getfile(self, fname):
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   471
        if self.opener.islink(fname):
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   472
            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
   473
14531
b88368a3ade4 patch: remove redundant islink() call
Patrick Mezard <pmezard@gmail.com>
parents: 14494
diff changeset
   474
        isexec = False
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   475
        try:
25658
e93036747902 global: mass rewrite to use modern octal syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25644
diff changeset
   476
            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
   477
        except OSError as e:
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   478
            if e.errno != errno.ENOENT:
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   479
                raise
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   480
        try:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   481
            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
   482
        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
   483
            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
   484
                raise
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   485
            return None, None
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   486
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   487
    def setfile(self, fname, data, mode, copysource):
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   488
        islink, isexec = mode
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   489
        if data is None:
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   490
            self.opener.setflags(fname, islink, isexec)
14390
ce77c275bec3 patch: merge backend setmode() into writelines()
Patrick Mezard <pmezard@gmail.com>
parents: 14389
diff changeset
   491
            return
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   492
        if islink:
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   493
            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
   494
        else:
14391
1e64e1e12195 patch: unify backend file access interface
Patrick Mezard <pmezard@gmail.com>
parents: 14390
diff changeset
   495
            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
   496
            if isexec:
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   497
                self.opener.setflags(fname, False, True)
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   498
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   499
    def unlink(self, fname):
38493
da2a7d8354b2 unlinkpath: make empty directory removal optional (issue5901) (issue5826)
Kyle Lippincott <spectral@google.com>
parents: 38332
diff changeset
   500
        rmdir = self.ui.configbool('experimental', 'removeemptydirs')
da2a7d8354b2 unlinkpath: make empty directory removal optional (issue5901) (issue5826)
Kyle Lippincott <spectral@google.com>
parents: 38332
diff changeset
   501
        self.opener.unlinkpath(fname, ignoremissing=True, rmdir=rmdir)
7392
564326a6ef9c patch: isolate patchfile filesystem calls into methods
Patrick Mezard <pmezard@gmail.com>
parents: 7391
diff changeset
   502
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   503
    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
   504
        fname = fname + ".rej"
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   505
        self.ui.warn(
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   506
            _("%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
   507
            (failed, total, fname))
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   508
        fp = self.opener(fname, 'w')
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   509
        fp.writelines(lines)
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   510
        fp.close()
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   511
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
   512
    def exists(self, fname):
21717
2a095d3442e0 patch: replace functions in fsbackend to use vfs
Chinmay Joshi <c@chinmayjoshi.com>
parents: 21553
diff changeset
   513
        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
   514
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   515
class workingbackend(fsbackend):
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   516
    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
   517
        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
   518
        self.repo = repo
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   519
        self.similarity = similarity
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   520
        self.removed = set()
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   521
        self.changed = set()
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   522
        self.copied = []
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   523
14453
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   524
    def _checkknown(self, fname):
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   525
        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
   526
            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
   527
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   528
    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
   529
        self._checkknown(fname)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   530
        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
   531
        if copysource is not None:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   532
            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
   533
        self.changed.add(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   534
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   535
    def unlink(self, fname):
14453
ea3d548132cc patch: do not patch unknown files (issue752)
Patrick Mezard <pmezard@gmail.com>
parents: 14452
diff changeset
   536
        self._checkknown(fname)
14370
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   537
        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
   538
        self.removed.add(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   539
        self.changed.add(fname)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   540
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   541
    def close(self):
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   542
        wctx = self.repo[None]
19155
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   543
        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
   544
        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
   545
            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
   546
        if self.removed:
14435
5f6090e559fa context: make forget work like commands.forget
Matt Mackall <mpm@selenic.com>
parents: 14418
diff changeset
   547
            wctx.forget(sorted(self.removed))
16112
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   548
            for f in self.removed:
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   549
                if f not in self.repo.dirstate:
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   550
                    # 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
   551
                    # dirstate, it was probably marked added then
d7829b2ecf32 import: handle git renames and --similarity (issue3187)
Patrick Mezard <patrick@mezard.eu>
parents: 15971
diff changeset
   552
                    # 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
   553
                    # marktouched().
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   554
                    changed.discard(f)
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   555
        if changed:
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
   556
            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
   557
        return sorted(self.changed)
17cea10c343e patch: add a workingbackend dirstate layer on top of fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14369
diff changeset
   558
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   559
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
   560
    def __init__(self, maxsize=None):
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   561
        self.opener = None
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   562
        self.files = {}
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   563
        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
   564
        self.maxsize = maxsize
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   565
        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
   566
            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
   567
        self.size = 0
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   568
        self.data = {}
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   569
14609
f53dc0787424 patch: extend filtestore to store an optional copy source
Patrick Mezard <pmezard@gmail.com>
parents: 14566
diff changeset
   570
    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
   571
        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
   572
            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
   573
            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
   574
        else:
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   575
            if self.opener is None:
38165
2ce60954b1b7 py3: wrap tempfile.mkdtemp() to use bytes path
Yuya Nishihara <yuya@tcha.org>
parents: 38164
diff changeset
   576
                root = pycompat.mkdtemp(prefix='hg-patch-')
31233
067f2a95e32c vfs: use 'vfs' module directly in 'mercurial.patch'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31216
diff changeset
   577
                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
   578
            # Avoid filename issues with these simple names
36423
2831d918e1b4 py3: convert known-int values to bytes using %d
Augie Fackler <augie@google.com>
parents: 36229
diff changeset
   579
            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
   580
            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
   581
            self.created += 1
7ddf9a607b75 patch: make filestore store data in memory and fallback to fs
Patrick Mezard <pmezard@gmail.com>
parents: 14611
diff changeset
   582
            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
   583
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   584
    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
   585
        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
   586
            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
   587
        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
   588
            return None, None, None
14609
f53dc0787424 patch: extend filtestore to store an optional copy source
Patrick Mezard <pmezard@gmail.com>
parents: 14566
diff changeset
   589
        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
   590
        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
   591
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   592
    def close(self):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   593
        if self.opener:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   594
            shutil.rmtree(self.opener.base)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   595
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   596
class repobackend(abstractbackend):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   597
    def __init__(self, ui, repo, ctx, store):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   598
        super(repobackend, self).__init__(ui)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   599
        self.repo = repo
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   600
        self.ctx = ctx
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   601
        self.store = store
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   602
        self.changed = set()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   603
        self.removed = set()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   604
        self.copied = {}
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   605
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   606
    def _checkknown(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   607
        if fname not in self.ctx:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   608
            raise PatchError(_('cannot patch %s: file is not tracked') % fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   609
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   610
    def getfile(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   611
        try:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   612
            fctx = self.ctx[fname]
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   613
        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
   614
            return None, None
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   615
        flags = fctx.flags()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   616
        return fctx.data(), ('l' in flags, 'x' in flags)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   617
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   618
    def setfile(self, fname, data, mode, copysource):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   619
        if copysource:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   620
            self._checkknown(copysource)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   621
        if data is None:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   622
            data = self.ctx[fname].data()
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   623
        self.store.setfile(fname, data, mode, copysource)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   624
        self.changed.add(fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   625
        if copysource:
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   626
            self.copied[fname] = copysource
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   627
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   628
    def unlink(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   629
        self._checkknown(fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   630
        self.removed.add(fname)
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   631
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   632
    def exists(self, fname):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   633
        return fname in self.ctx
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   634
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   635
    def close(self):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   636
        return self.changed | self.removed
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
   637
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   638
# @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
41532
bd3f03d8cc9f global: use raw strings for regular expressions with escapes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41499
diff changeset
   639
unidesc = re.compile(br'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@')
bd3f03d8cc9f global: use raw strings for regular expressions with escapes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41499
diff changeset
   640
contextdesc = re.compile(br'(?:---|\*\*\*) (\d+)(?:,(\d+))? (?:---|\*\*\*)')
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   641
eolmodes = ['strict', 'crlf', 'lf', 'auto']
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   642
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   643
class patchfile(object):
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   644
    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
   645
        self.fname = gp.path
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   646
        self.eolmode = eolmode
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   647
        self.eol = None
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   648
        self.backend = backend
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   649
        self.ui = ui
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   650
        self.lines = []
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   651
        self.exists = False
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   652
        self.missing = True
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   653
        self.mode = gp.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   654
        self.copysource = gp.oldpath
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   655
        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
   656
        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
   657
        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
   658
            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
   659
        else:
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
   660
            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
   661
        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
   662
            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
   663
            self.missing = False
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   664
            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
   665
                self.lines = mdiff.splitnewlines(data)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   666
            if self.mode is None:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   667
                self.mode = mode
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   668
            if self.lines:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   669
                # Normalize line endings
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   670
                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
   671
                    self.eol = '\r\n'
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   672
                elif self.lines[0].endswith('\n'):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   673
                    self.eol = '\n'
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   674
                if eolmode != 'strict':
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   675
                    nlines = []
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   676
                    for l in self.lines:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   677
                        if l.endswith('\r\n'):
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   678
                            l = l[:-2] + '\n'
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   679
                        nlines.append(l)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   680
                    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
   681
        else:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
   682
            if self.create:
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   683
                self.missing = False
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   684
            if self.mode is None:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   685
                self.mode = (False, False)
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   686
        if self.missing:
17299
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
   687
            self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
29900
50f2966f86ca import: report directory-relative paths in error messages (issue5224)
liscju <piotr.listkiewicz@gmail.com>
parents: 29726
diff changeset
   688
            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: 29726
diff changeset
   689
                           "current directory)\n"))
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   690
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   691
        self.hash = {}
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   692
        self.dirty = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   693
        self.offset = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   694
        self.skew = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   695
        self.rej = []
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   696
        self.fileprinted = False
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   697
        self.printfile(False)
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   698
        self.hunks = 0
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   699
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   700
    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
   701
        if self.eolmode == 'auto':
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   702
            eol = self.eol
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   703
        elif self.eolmode == 'crlf':
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   704
            eol = '\r\n'
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   705
        else:
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   706
            eol = '\n'
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   707
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   708
        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
   709
            rawlines = []
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   710
            for l in lines:
38329
f47608575c10 py3: replace s[-1] with s.endswith() in eol handling
Yuya Nishihara <yuya@tcha.org>
parents: 38165
diff changeset
   711
                if l and l.endswith('\n'):
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   712
                    l = l[:-1] + eol
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   713
                rawlines.append(l)
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   714
            lines = rawlines
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   715
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   716
        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
   717
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   718
    def printfile(self, warn):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   719
        if self.fileprinted:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   720
            return
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   721
        if warn or self.ui.verbose:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   722
            self.fileprinted = True
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   723
        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
   724
        if warn:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   725
            self.ui.warn(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   726
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   727
            self.ui.note(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   728
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   729
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   730
    def findlines(self, l, linenum):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   731
        # 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
   732
        # 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
   733
        # from linenum
5143
d4fa6bafc43a Remove trailing spaces, fix indentation
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5116
diff changeset
   734
9681
ac3a68cb16eb patch: simplify logic
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9642
diff changeset
   735
        cand = self.hash.get(l, [])
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   736
        if len(cand) > 1:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   737
            # 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
   738
            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
   739
        return cand
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   740
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   741
    def write_rej(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   742
        # 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
   743
        # 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
   744
        # 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
   745
        # without having to type the filename.
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   746
        if not self.rej:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   747
            return
14349
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   748
        base = os.path.basename(self.fname)
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   749
        lines = ["--- %s\n+++ %s\n" % (base, base)]
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   750
        for x in self.rej:
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   751
            for l in x.hunk:
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   752
                lines.append(l)
31715
6c80f985a13c diff: slice over bytes to make sure conditions work normally
Pulkit Goyal <7895pulkit@gmail.com>
parents: 31631
diff changeset
   753
                if l[-1:] != '\n':
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
   754
                    lines.append("\n\\ No newline at end of file\n")
14349
776ae95b8835 patch: merge makerejlines() into write_rej()
Patrick Mezard <pmezard@gmail.com>
parents: 14348
diff changeset
   755
        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
   756
9393
23c4e772c172 patch: remove the unused, broken reverse() function
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9392
diff changeset
   757
    def apply(self, h):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   758
        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
   759
            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
   760
                            (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
   761
                            h.lenb))
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   762
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   763
        self.hunks += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   764
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   765
        if self.missing:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   766
            self.rej.append(h)
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   767
            return -1
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
   768
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
   769
        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
   770
            if self.copysource:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   771
                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
   772
                               "exists\n") % self.fname)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   773
            else:
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
   774
                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
   775
            self.rej.append(h)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   776
            return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   777
9585
ea1935e2020a patch: handle symlinks without symlinkhunk
Patrick Mezard <pmezard@gmail.com>
parents: 9573
diff changeset
   778
        if isinstance(h, binhunk):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
   779
            if self.remove:
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   780
                self.backend.unlink(self.fname)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   781
            else:
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
   782
                l = h.new(self.lines)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
   783
                self.lines[:] = l
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
   784
                self.offset += len(l)
14217
71d5287351e9 patchfile: use real Booleans instead of 0/1
Martin Geisler <mg@aragost.com>
parents: 14017
diff changeset
   785
                self.dirty = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   786
            return 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   787
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   788
        horig = h
10128
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
   789
        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
   790
            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
   791
            # 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
   792
            # 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
   793
            # line-endings.
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   794
            h = h.getnormalized()
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
   795
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   796
        # 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
   797
        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
   798
        oldstart += self.offset
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   799
        orig_start = oldstart
10135
9a4034b630c4 patch: better handling of sequence of offset patch hunks (issue1941)
Greg Onufer <gonufer@jazzhaiku.com>
parents: 9725
diff changeset
   800
        # 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
   801
        # 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
   802
        # fast case code
37803
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
   803
        if self.skew == 0 and diffhelper.testhunk(old, self.lines, oldstart):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
   804
            if self.remove:
14348
c1c719103392 patch: extract fs access from patchfile into fsbackend
Patrick Mezard <pmezard@gmail.com>
parents: 14347
diff changeset
   805
                self.backend.unlink(self.fname)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   806
            else:
16122
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
   807
                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
   808
                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
   809
                self.dirty = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   810
            return 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   811
13700
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   812
        # 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
   813
        self.hash = {}
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   814
        for x, s in enumerate(self.lines):
63307feb59dd patch: inline patchfile.hashlines()
Patrick Mezard <pmezard@gmail.com>
parents: 13699
diff changeset
   815
            self.hash.setdefault(s, []).append(x)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   816
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
   817
        for fuzzlen in pycompat.xrange(self.ui.configint("patch", "fuzz") + 1):
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   818
            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
   819
                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
   820
                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
   821
                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
   822
                if old:
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   823
                    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
   824
                else:
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   825
                    # 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
   826
                    # take the skew in account
b0c7525f826d patch: fix fuzzing of hunks without previous lines (issue3264)
Patrick Mezard <patrick@mezard.eu>
parents: 16122
diff changeset
   827
                    cand = [oldstart]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   828
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   829
                for l in cand:
37803
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
   830
                    if not old or diffhelper.testhunk(old, self.lines, l):
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
   831
                        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
   832
                        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
   833
                        self.skew = l - orig_start
14217
71d5287351e9 patchfile: use real Booleans instead of 0/1
Martin Geisler <mg@aragost.com>
parents: 14017
diff changeset
   834
                        self.dirty = True
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   835
                        offset = l - orig_start - fuzzlen
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   836
                        if fuzzlen:
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   837
                            msg = _("Hunk #%d succeeded at %d "
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   838
                                    "with fuzz %d "
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   839
                                    "(offset %d lines).\n")
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   840
                            self.printfile(True)
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   841
                            self.ui.warn(msg %
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   842
                                (h.number, l + 1, fuzzlen, offset))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   843
                        else:
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   844
                            msg = _("Hunk #%d succeeded at %d "
8090
388bb482024e patch, i18n: avoid parameterized plural
Wagner Bruna <wbruna@yahoo.com>
parents: 7972
diff changeset
   845
                                    "(offset %d lines).\n")
10518
5fe51d348daf patch, i18n: avoid parameterized messages
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 10501
diff changeset
   846
                            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
   847
                        return fuzzlen
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   848
        self.printfile(True)
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
   849
        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
   850
        self.rej.append(horig)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   851
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
   852
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   853
    def close(self):
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   854
        if self.dirty:
14367
468d7d1744b4 patch: set desired mode when patching, not in updatedir()
Patrick Mezard <pmezard@gmail.com>
parents: 14366
diff changeset
   855
            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
   856
        self.write_rej()
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   857
        return len(self.rej)
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
   858
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   859
class header(object):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   860
    """patch header
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   861
    """
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   862
    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
   863
    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
   864
    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
   865
    pretty_re = re.compile('(?:new file|deleted file) ')
41982
f8c5225b9054 patch: include flag-only file changes in "special" when filtering (issue5864)
Sushil khanchi <sushilkhanchi97@gmail.com>
parents: 41784
diff changeset
   866
    special_re = re.compile('(?:index|deleted|copy|rename|new mode) ')
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   867
    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
   868
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   869
    def __init__(self, header):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   870
        self.header = header
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   871
        self.hunks = []
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   872
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   873
    def binary(self):
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   874
        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
   875
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   876
    def pretty(self, fp):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   877
        for h in self.header:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   878
            if h.startswith('index '):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   879
                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
   880
                break
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   881
            if self.pretty_re.match(h):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   882
                fp.write(h)
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   883
                if self.binary():
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   884
                    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
   885
                break
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   886
            if h.startswith('---'):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   887
                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
   888
                         (len(self.hunks),
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   889
                          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
   890
                break
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   891
            fp.write(h)
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   892
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   893
    def write(self, fp):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   894
        fp.write(''.join(self.header))
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   895
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   896
    def allhunks(self):
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   897
        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
   898
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   899
    def files(self):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   900
        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
   901
        if match:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   902
            fromfile, tofile = match.groups()
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   903
            if fromfile == tofile:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   904
                return [fromfile]
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   905
            return [fromfile, tofile]
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   906
        else:
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   907
            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
   908
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   909
    def filename(self):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   910
        return self.files()[-1]
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   911
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   912
    def __repr__(self):
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   913
        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
   914
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   915
    def isnewfile(self):
25149
3f0744eeaeaf cleanup: use __builtins__.any instead of util.any
Augie Fackler <augie@google.com>
parents: 25138
diff changeset
   916
        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
   917
24261
20aac24e2114 record: move header class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24260
diff changeset
   918
    def special(self):
24845
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   919
        # 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
   920
        # 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
   921
        # 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
   922
        # 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
   923
        # cannot take some of it.
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   924
        # 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
   925
        # 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
   926
        nocontent = len(self.header) == 2
8133494accf1 record: edit patch of newly added files (issue4304)
Laurent Charignon <lcharignon@fb.com>
parents: 24837
diff changeset
   927
        emptynewfile = self.isnewfile() and nocontent
41759
aaad36b88298 cleanup: use () to wrap long lines instead of \
Augie Fackler <augie@google.com>
parents: 41646
diff changeset
   928
        return (emptynewfile
aaad36b88298 cleanup: use () to wrap long lines instead of \
Augie Fackler <augie@google.com>
parents: 41646
diff changeset
   929
                or 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
   930
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   931
class recordhunk(object):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   932
    """patch hunk
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   933
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   934
    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
   935
    """
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   936
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   937
    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
   938
                 maxcontext=None):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   939
        def trimcontext(lines, reverse=False):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   940
            if maxcontext is not None:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   941
                delta = len(lines) - maxcontext
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   942
                if delta > 0:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   943
                    if reverse:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   944
                        return delta, lines[delta:]
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   945
                    else:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   946
                        return delta, lines[:maxcontext]
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   947
            return 0, lines
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   948
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   949
        self.header = header
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   950
        trimedbefore, self.before = trimcontext(before, True)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   951
        self.fromline = fromline + trimedbefore
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   952
        self.toline = toline + trimedbefore
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
   953
        _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
   954
        self.proc = proc
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   955
        self.hunk = hunk
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   956
        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
   957
24346
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   958
    def __eq__(self, v):
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   959
        if not isinstance(v, recordhunk):
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   960
            return False
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   961
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   962
        return ((v.hunk == self.hunk) and
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   963
                (v.proc == self.proc) and
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   964
                (self.fromline == v.fromline) and
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   965
                (self.header.files() == v.header.files()))
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   966
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   967
    def __hash__(self):
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   968
        return hash((tuple(self.hunk),
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   969
            tuple(self.header.files()),
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   970
            self.fromline,
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   971
            self.proc))
31edcea517c1 record: add comparison methods for recordhunk class
Laurent Charignon <lcharignon@fb.com>
parents: 24341
diff changeset
   972
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   973
    def countchanges(self, hunk):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   974
        """hunk -> (n+,n-)"""
34252
c43d055ae405 py3: stop using bytes[n] in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34251
diff changeset
   975
        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: 34251
diff changeset
   976
        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
   977
        return add, rem
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   978
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   979
    def reversehunk(self):
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   980
        """return another recordhunk which is the reverse of the hunk
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   981
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   982
        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: 32370
diff changeset
   983
        that, swap fromline/toline and +/- signs while keep other things
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   984
        unchanged.
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   985
        """
33884
5707bfe04deb record: fix revert -i for lines without newline (issue5651)
Jun Wu <quark@fb.com>
parents: 33584
diff changeset
   986
        m = {'+': '-', '-': '+', '\\': '\\'}
34252
c43d055ae405 py3: stop using bytes[n] in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34251
diff changeset
   987
        hunk = ['%s%s' % (m[l[0:1]], l[1:]) for l in self.hunk]
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   988
        return recordhunk(self.header, self.toline, self.fromline, self.proc,
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   989
                          self.before, hunk, self.after)
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
   990
24263
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   991
    def write(self, fp):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   992
        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
   993
        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
   994
            delta -= 1
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   995
        fromlen = delta + self.removed
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   996
        tolen = delta + self.added
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   997
        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
   998
                 (self.fromline, fromlen, self.toline, tolen,
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
   999
                  self.proc and (' ' + self.proc)))
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1000
        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
  1001
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1002
    pretty = write
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1003
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1004
    def filename(self):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1005
        return self.header.filename()
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1006
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1007
    def __repr__(self):
a45d1c51109e record: move hunk class from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24261
diff changeset
  1008
        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
  1009
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1010
def getmessages():
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1011
    return {
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1012
        'multiple': {
34968
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34964
diff changeset
  1013
            '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
  1014
            'discard': _("discard change %d/%d to '%s'?"),
41987
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1015
            'keep': _("keep change %d/%d to '%s'?"),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1016
            'record': _("record change %d/%d 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
        'single': {
34968
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34964
diff changeset
  1019
            'apply': _("apply this change to '%s'?"),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1020
            'discard': _("discard this change to '%s'?"),
41987
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1021
            'keep': _("keep this change to '%s'?"),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1022
            'record': _("record this change to '%s'?"),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1023
        },
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1024
        'help': {
34968
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34964
diff changeset
  1025
            'apply': _('[Ynesfdaq?]'
3649c3f2cd90 revert: do not reverse hunks in interactive when REV is not parent (issue5096)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34964
diff changeset
  1026
                         '$$ &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: 34964
diff changeset
  1027
                         '$$ &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: 34964
diff changeset
  1028
                         '$$ &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: 34964
diff changeset
  1029
                         '$$ &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: 34964
diff changeset
  1030
                         '$$ 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: 34964
diff changeset
  1031
                         '$$ &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: 34964
diff changeset
  1032
                         '$$ 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: 34964
diff changeset
  1033
                         '$$ &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: 34964
diff changeset
  1034
                         '$$ &? (display help)'),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1035
            'discard': _('[Ynesfdaq?]'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1036
                         '$$ &Yes, discard this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1037
                         '$$ &No, skip this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1038
                         '$$ &Edit this change manually'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1039
                         '$$ &Skip remaining changes to this file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1040
                         '$$ Discard remaining changes to this &file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1041
                         '$$ &Done, skip remaining changes and files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1042
                         '$$ Discard &all changes to all remaining files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1043
                         '$$ &Quit, discarding no changes'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1044
                         '$$ &? (display help)'),
41987
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1045
            'keep': _('[Ynesfdaq?]'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1046
                         '$$ &Yes, keep this change'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1047
                         '$$ &No, skip this change'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1048
                         '$$ &Edit this change manually'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1049
                         '$$ &Skip remaining changes to this file'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1050
                         '$$ Keep remaining changes to this &file'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1051
                         '$$ &Done, skip remaining changes and files'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1052
                         '$$ Keep &all changes to all remaining files'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1053
                         '$$ &Quit, keeping all changes'
c1d83d916e85 revert: option to choose what to keep, not what to discard
Martin von Zweigbergk <martinvonz@google.com>
parents: 41986
diff changeset
  1054
                         '$$ &? (display help)'),
34566
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1055
            'record': _('[Ynesfdaq?]'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1056
                        '$$ &Yes, record this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1057
                        '$$ &No, skip this change'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1058
                        '$$ &Edit this change manually'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1059
                        '$$ &Skip remaining changes to this file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1060
                        '$$ Record remaining changes to this &file'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1061
                        '$$ &Done, skip remaining changes and files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1062
                        '$$ Record &all changes to all remaining files'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1063
                        '$$ &Quit, recording no changes'
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1064
                        '$$ &? (display help)'),
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1065
        }
34042
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34013
diff changeset
  1066
    }
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34013
diff changeset
  1067
25310
c1f5ef76d1c2 record: add an operation arguments to customize recording ui
Laurent Charignon <lcharignon@fb.com>
parents: 25149
diff changeset
  1068
def filterpatch(ui, headers, operation=None):
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1069
    """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
  1070
    messages = getmessages()
60213a2eca81 patch: do not cache translated messages (API)
Jun Wu <quark@fb.com>
parents: 34561
diff changeset
  1071
25359
724421cb4745 record: add default value for operation argument
Laurent Charignon <lcharignon@fb.com>
parents: 25310
diff changeset
  1072
    if operation is None:
29326
d48fc6f318a3 patch: define full messages for interactive record/revert
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 29283
diff changeset
  1073
        operation = 'record'
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1074
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1075
    def prompt(skipfile, skipall, query, chunk):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1076
        """prompt query, and process base inputs
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1077
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1078
        - y/n for the rest of file
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1079
        - y/n for the rest
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1080
        - ? (help)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1081
        - q (quit)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1082
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1083
        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
  1084
        """
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1085
        newpatches = None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1086
        if skipall is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1087
            return skipall, skipfile, skipall, newpatches
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1088
        if skipfile is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1089
            return skipfile, skipfile, skipall, newpatches
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1090
        while True:
34042
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34013
diff changeset
  1091
            resps = messages['help'][operation]
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1092
            r = ui.promptchoice("%s %s" % (query, resps))
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
            if r == 8: # ?
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1095
                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
  1096
                    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
  1097
                continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1098
            elif r == 0: # yes
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1099
                ret = True
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1100
            elif r == 1: # no
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1101
                ret = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1102
            elif r == 2: # Edit patch
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1103
                if chunk is None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1104
                    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
  1105
                    ui.write("\n")
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1106
                    continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1107
                if chunk.header.binary():
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1108
                    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
  1109
                    ui.write("\n")
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1110
                    continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1111
                # 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
  1112
                # https://mercurial-scm.org/wiki/RecordExtension)
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1113
                phelp = '---' + _("""
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1114
To remove '-' lines, make them ' ' lines (context).
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1115
To remove '+' lines, delete them.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1116
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
  1117
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1118
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
  1119
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
  1120
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
  1121
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
  1122
the hunk is left unchanged.
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1123
""")
38164
aac4be30e250 py3: wrap tempfile.mkstemp() to use bytes path
Yuya Nishihara <yuya@tcha.org>
parents: 38092
diff changeset
  1124
                (patchfd, patchfn) = pycompat.mkstemp(prefix="hg-editor-",
36837
472c68cda3f8 py3: wrap file object to write patch in native eol preserving byte-ness
Yuya Nishihara <yuya@tcha.org>
parents: 36835
diff changeset
  1125
                                                      suffix=".diff")
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1126
                ncpatchfp = None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1127
                try:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1128
                    # Write the initial patch
36837
472c68cda3f8 py3: wrap file object to write patch in native eol preserving byte-ness
Yuya Nishihara <yuya@tcha.org>
parents: 36835
diff changeset
  1129
                    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
  1130
                    chunk.header.write(f)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1131
                    chunk.write(f)
41986
95e4ae86329f patch: include newline at EOF in help text for interactive patch
Martin von Zweigbergk <martinvonz@google.com>
parents: 41982
diff changeset
  1132
                    f.write(''.join(['# ' + i + '\n'
95e4ae86329f patch: include newline at EOF in help text for interactive patch
Martin von Zweigbergk <martinvonz@google.com>
parents: 41982
diff changeset
  1133
                                     for i in phelp.splitlines()]))
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1134
                    f.close()
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1135
                    # 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
  1136
                    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
  1137
                    ret = ui.system("%s \"%s\"" % (editor, patchfn),
31198
71a6723c0029 patch: set a blockedtag when running an external filter
Simon Farnsworth <simonfar@fb.com>
parents: 30924
diff changeset
  1138
                                    environ={'HGUSER': ui.username()},
71a6723c0029 patch: set a blockedtag when running an external filter
Simon Farnsworth <simonfar@fb.com>
parents: 30924
diff changeset
  1139
                                    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
  1140
                    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
  1141
                        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
  1142
                        continue
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1143
                    # Remove comment lines
36838
c268ba15deb3 py3: open patch file in binary mode and convert eol manually
Yuya Nishihara <yuya@tcha.org>
parents: 36837
diff changeset
  1144
                    patchfp = open(patchfn, r'rb')
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1145
                    ncpatchfp = stringio()
30397
564b33acc21f patch: migrate to util.iterfile
Jun Wu <quark@fb.com>
parents: 30078
diff changeset
  1146
                    for line in util.iterfile(patchfp):
36838
c268ba15deb3 py3: open patch file in binary mode and convert eol manually
Yuya Nishihara <yuya@tcha.org>
parents: 36837
diff changeset
  1147
                        line = util.fromnativeeol(line)
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1148
                        if not line.startswith('#'):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1149
                            ncpatchfp.write(line)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1150
                    patchfp.close()
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1151
                    ncpatchfp.seek(0)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1152
                    newpatches = parsepatch(ncpatchfp)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1153
                finally:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1154
                    os.unlink(patchfn)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1155
                    del ncpatchfp
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1156
                # 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
  1157
                # 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
  1158
                ret = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1159
            elif r == 3: # Skip
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1160
                ret = skipfile = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1161
            elif r == 4: # file (Record remaining)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1162
                ret = skipfile = True
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1163
            elif r == 5: # done, skip remaining
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1164
                ret = skipall = False
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1165
            elif r == 6: # all
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1166
                ret = skipall = True
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1167
            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
  1168
                raise error.Abort(_('user quit'))
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1169
            return ret, skipfile, skipall, newpatches
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1170
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1171
    seen = set()
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1172
    applied = {}        # 'filename' -> [] of chunks
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1173
    skipfile, skipall = None, None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1174
    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
  1175
    for h in headers:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1176
        pos += len(h.hunks)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1177
        skipfile = None
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1178
        fixoffset = 0
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1179
        hdr = ''.join(h.header)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1180
        if hdr in seen:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1181
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1182
        seen.add(hdr)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1183
        if skipall is None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1184
            h.pretty(ui)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1185
        msg = (_('examine changes to %s?') %
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1186
               _(' 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
  1187
        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
  1188
        if not r:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1189
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1190
        applied[h.filename()] = [h]
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1191
        if h.allhunks():
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1192
            applied[h.filename()] += h.hunks
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1193
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1194
        for i, chunk in enumerate(h.hunks):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1195
            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
  1196
                chunk.pretty(ui)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1197
            if total == 1:
34042
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34013
diff changeset
  1198
                msg = messages['single'][operation] % chunk.filename()
24269
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
                idx = pos - len(h.hunks) + i
34042
c0170d88ed2b patch: take messages out of the function so that extensions can add entries
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34013
diff changeset
  1201
                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: 34013
diff changeset
  1202
                                                         chunk.filename())
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1203
            r, skipfile, skipall, newpatches = prompt(skipfile,
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1204
                    skipall, msg, chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1205
            if r:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1206
                if fixoffset:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1207
                    chunk = copy.copy(chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1208
                    chunk.toline += fixoffset
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1209
                applied[chunk.filename()].append(chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1210
            elif newpatches is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1211
                for newpatch in newpatches:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1212
                    for newhunk in newpatch.hunks:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1213
                        if fixoffset:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1214
                            newhunk.toline += fixoffset
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1215
                        applied[newhunk.filename()].append(newhunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1216
            else:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1217
                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
  1218
    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
  1219
               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
  1220
class hunk(object):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1221
    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
  1222
        self.number = num
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1223
        self.desc = desc
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1224
        self.hunk = [desc]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1225
        self.a = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1226
        self.b = []
9682
bd70f645cfb0 patch: initialize all attributes of the hunk class
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9681
diff changeset
  1227
        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
  1228
        self.startb = self.lenb = None
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1229
        if lr is not None:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1230
            if context:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1231
                self.read_context_hunk(lr)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1232
            else:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1233
                self.read_unified_hunk(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1234
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1235
    def getnormalized(self):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1236
        """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
  1237
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1238
        def normalize(lines):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1239
            nlines = []
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1240
            for line in lines:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1241
                if line.endswith('\r\n'):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1242
                    line = line[:-2] + '\n'
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1243
                nlines.append(line)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1244
            return nlines
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1245
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1246
        # Dummy object, it is rebuilt manually
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1247
        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
  1248
        nh.number = self.number
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1249
        nh.desc = self.desc
10524
3212afb33116 patch: fix patching with fuzz and eol normalization
Patrick Mezard <pmezard@gmail.com>
parents: 10518
diff changeset
  1250
        nh.hunk = self.hunk
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1251
        nh.a = normalize(self.a)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1252
        nh.b = normalize(self.b)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1253
        nh.starta = self.starta
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1254
        nh.startb = self.startb
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1255
        nh.lena = self.lena
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1256
        nh.lenb = self.lenb
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1257
        return nh
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1258
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1259
    def read_unified_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1260
        m = unidesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1261
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1262
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1263
        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
  1264
        if self.lena is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1265
            self.lena = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1266
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1267
            self.lena = int(self.lena)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1268
        if self.lenb is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1269
            self.lenb = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1270
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1271
            self.lenb = int(self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1272
        self.starta = int(self.starta)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1273
        self.startb = int(self.startb)
37573
49b82cdb5983 patch: error out if reached to EOF while reading hunk
Yuya Nishihara <yuya@tcha.org>
parents: 37571
diff changeset
  1274
        try:
37803
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
  1275
            diffhelper.addlines(lr, self.hunk, self.lena, self.lenb,
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
  1276
                                self.a, self.b)
37573
49b82cdb5983 patch: error out if reached to EOF while reading hunk
Yuya Nishihara <yuya@tcha.org>
parents: 37571
diff changeset
  1277
        except error.ParseError as e:
49b82cdb5983 patch: error out if reached to EOF while reading hunk
Yuya Nishihara <yuya@tcha.org>
parents: 37571
diff changeset
  1278
            raise PatchError(_("bad hunk #%d: %s") % (self.number, e))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1279
        # 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
  1280
        # 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
  1281
        while len(self.hunk[-1]) == 0:
6948
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1282
            del self.hunk[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1283
            del self.a[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1284
            del self.b[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1285
            self.lena -= 1
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1286
            self.lenb -= 1
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1287
        self._fixnewline(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1288
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1289
    def read_context_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1290
        self.desc = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1291
        m = contextdesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1292
        if not m:
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") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1294
        self.starta, aend = m.groups()
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1295
        self.starta = int(self.starta)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1296
        if aend is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1297
            aend = self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1298
        self.lena = int(aend) - self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1299
        if self.starta:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1300
            self.lena += 1
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1301
        for x in pycompat.xrange(self.lena):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1302
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1303
            if l.startswith('---'):
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1304
                # lines addition, old block is empty
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1305
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1306
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1307
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1308
            if l.startswith('- ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1309
                u = '-' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1310
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1311
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1312
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1313
                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
  1314
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1315
            self.a.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1316
            self.hunk.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1317
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1318
        l = lr.readline()
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
  1319
        if l.startswith(br'\ '):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1320
            s = self.a[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1321
            self.a[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1322
            self.hunk[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1323
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1324
        m = contextdesc.match(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1325
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1326
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1327
        self.startb, bend = m.groups()
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1328
        self.startb = int(self.startb)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1329
        if bend is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1330
            bend = self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1331
        self.lenb = int(bend) - self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1332
        if self.startb:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1333
            self.lenb += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1334
        hunki = 1
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1335
        for x in pycompat.xrange(self.lenb):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1336
            l = lr.readline()
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
  1337
            if l.startswith(br'\ '):
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1338
                # 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
  1339
                # 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
  1340
                # 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
  1341
                s = self.b[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1342
                self.b[-1] = s
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1343
                self.hunk[hunki - 1] = s
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1344
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1345
            if not l:
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1346
                # 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
  1347
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1348
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1349
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1350
            if l.startswith('+ ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1351
                u = '+' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1352
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1353
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1354
            elif len(self.b) == 0:
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1355
                # line deletions, new block is empty
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1356
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1357
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1358
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1359
                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
  1360
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1361
            self.b.append(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1362
            while True:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1363
                if hunki >= len(self.hunk):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1364
                    h = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1365
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1366
                    h = self.hunk[hunki]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1367
                hunki += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1368
                if h == u:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1369
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1370
                elif h.startswith('-'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1371
                    continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1372
                else:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1373
                    self.hunk.insert(hunki - 1, u)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1374
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1375
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1376
        if not self.a:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1377
            # 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
  1378
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1379
                if x.startswith('-') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1380
                    self.a.append(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1381
        if not self.b:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1382
            # 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
  1383
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1384
                if x.startswith('+') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1385
                    self.b.append(x[1:])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1386
        # @@ -start,len +start,len @@
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1387
        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
  1388
                                             self.startb, self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1389
        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
  1390
        self._fixnewline(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1391
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1392
    def _fixnewline(self, lr):
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1393
        l = lr.readline()
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
  1394
        if l.startswith(br'\ '):
37803
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
  1395
            diffhelper.fixnewline(self.hunk, self.a, self.b)
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1396
        else:
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1397
            lr.push(l)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1398
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1399
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1400
        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
  1401
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
  1402
    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
  1403
        # 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
  1404
        # 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
  1405
        # 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
  1406
        fuzz = min(fuzz, len(old))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1407
        if fuzz:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1408
            top = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1409
            bot = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1410
            hlen = len(self.hunk)
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1411
            for x in pycompat.xrange(hlen - 1):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1412
                # the hunk starts with the @@ line, so use x+1
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1413
                if self.hunk[x + 1].startswith(' '):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1414
                    top += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1415
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1416
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1417
            if not toponly:
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1418
                for x in pycompat.xrange(hlen - 1):
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1419
                    if self.hunk[hlen - bot - 1].startswith(' '):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1420
                        bot += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1421
                    else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1422
                        break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1423
16124
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1424
            bot = min(fuzz, bot)
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1425
            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
  1426
            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
  1427
        return old, new, 0
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1428
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
  1429
    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
  1430
        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
  1431
        oldstart = self.starta + top
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1432
        newstart = self.startb + top
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1433
        # 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
  1434
        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
  1435
            oldstart -= 1
16650
fcb97d9a26cd patch: fix segfault against unified diffs which start line is zero
Yuya Nishihara <yuya@tcha.org>
parents: 16524
diff changeset
  1436
        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
  1437
            newstart -= 1
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1438
        return old, oldstart, new, newstart
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1439
14764
a7d5816087a9 classes: fix class style problems found by b071cd58af50
Thomas Arendsen Hein <thomas@intevation.de>
parents: 14695
diff changeset
  1440
class binhunk(object):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1441
    'A binary patch file.'
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1442
    def __init__(self, lr, fname):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1443
        self.text = None
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1444
        self.delta = False
9585
ea1935e2020a patch: handle symlinks without symlinkhunk
Patrick Mezard <pmezard@gmail.com>
parents: 9573
diff changeset
  1445
        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
  1446
        self._fname = fname
14384
9d59c596eb9e patch: construct and parse binary hunks at the same time
Patrick Mezard <pmezard@gmail.com>
parents: 14383
diff changeset
  1447
        self._read(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1448
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1449
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1450
        return self.text is not None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1451
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1452
    def new(self, lines):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1453
        if self.delta:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1454
            return [applybindelta(self.text, ''.join(lines))]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1455
        return [self.text]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1456
14384
9d59c596eb9e patch: construct and parse binary hunks at the same time
Patrick Mezard <pmezard@gmail.com>
parents: 14383
diff changeset
  1457
    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
  1458
        def getline(lr, hunk):
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1459
            l = lr.readline()
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1460
            hunk.append(l)
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1461
            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
  1462
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1463
        while True:
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1464
            line = getline(lr, self.hunk)
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1465
            if not line:
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1466
                raise PatchError(_('could not extract "%s" binary data')
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1467
                                 % self._fname)
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1468
            if line.startswith('literal '):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1469
                size = int(line[8:].rstrip())
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1470
                break
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1471
            if line.startswith('delta '):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1472
                size = int(line[6:].rstrip())
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1473
                self.delta = True
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1474
                break
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1475
        dec = []
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1476
        line = getline(lr, self.hunk)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1477
        while len(line) > 1:
36192
eb91ffdaaece py3: slice over bytes to prevent getting ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 36046
diff changeset
  1478
            l = line[0:1]
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
  1479
            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
  1480
                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
  1481
            else:
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
  1482
                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
  1483
            try:
32201
4462a981e8df base85: proxy through util module
Yuya Nishihara <yuya@tcha.org>
parents: 32191
diff changeset
  1484
                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
  1485
            except ValueError as e:
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1486
                raise PatchError(_('could not decode "%s" binary patch: %s')
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36838
diff changeset
  1487
                                 % (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
  1488
            line = getline(lr, self.hunk)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1489
        text = zlib.decompress(''.join(dec))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1490
        if len(text) != size:
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1491
            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
  1492
                             % (self._fname, len(text), size))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1493
        self.text = text
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1494
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1495
def parsefilename(str):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1496
    # --- filename \t|space stuff
5851
03f550f9b554 patch: remove CRLF when parsing file names
Patrick Mezard <pmezard@gmail.com>
parents: 5669
diff changeset
  1497
    s = str[4:].rstrip('\r\n')
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1498
    i = s.find('\t')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1499
    if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1500
        i = s.find(' ')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1501
        if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1502
            return s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1503
    return s[:i]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1504
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1505
def reversehunks(hunks):
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1506
    '''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
  1507
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1508
    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
  1509
    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
  1510
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1511
    >>> 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
  1512
    ... --- a/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1513
    ... +++ b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1514
    ... @@ -1,7 +1,7 @@
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1515
    ... +firstline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1516
    ...  c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1517
    ...  1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1518
    ...  2
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1519
    ... + 3
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1520
    ... -4
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1521
    ...  5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1522
    ...  d
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1523
    ... +lastline"""
34253
5ce32fe7df34 py3: fix doctests in patch.py to be compatible with Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34252
diff changeset
  1524
    >>> hunks = parsepatch([rawpatch])
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1525
    >>> hunkscomingfromfilterpatch = []
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1526
    >>> for h in hunks:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1527
    ...     hunkscomingfromfilterpatch.append(h)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1528
    ...     hunkscomingfromfilterpatch.extend(h.hunks)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1529
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1530
    >>> reversedhunks = reversehunks(hunkscomingfromfilterpatch)
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1531
    >>> from . import util
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1532
    >>> fp = util.stringio()
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1533
    >>> for c in reversedhunks:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1534
    ...      c.write(fp)
34253
5ce32fe7df34 py3: fix doctests in patch.py to be compatible with Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34252
diff changeset
  1535
    >>> 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
  1536
    >>> reversedpatch = fp.read()
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
  1537
    >>> print(pycompat.sysstr(reversedpatch))
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1538
    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
  1539
    --- a/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1540
    +++ b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1541
    @@ -1,4 +1,3 @@
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1542
    -firstline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1543
     c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1544
     1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1545
     2
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1546
    @@ -2,6 +1,6 @@
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1547
     c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1548
     1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1549
     2
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1550
    - 3
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1551
    +4
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1552
     5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1553
     d
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1554
    @@ -6,3 +5,2 @@
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1555
     5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1556
     d
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1557
    -lastline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1558
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1559
    '''
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1560
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1561
    newhunks = []
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1562
    for c in hunks:
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1563
        if util.safehasattr(c, 'reversehunk'):
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1564
            c = c.reversehunk()
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1565
        newhunks.append(c)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1566
    return newhunks
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1567
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1568
def parsepatch(originalchunks, maxcontext=None):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1569
    """patch -> [] of headers -> [] of hunks
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1570
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1571
    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
  1572
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1573
    >>> 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
  1574
    ... --- a/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1575
    ... +++ b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1576
    ... @@ -1,8 +1,10 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1577
    ...  1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1578
    ...  2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1579
    ... -3
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1580
    ...  4
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1581
    ...  5
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1582
    ...  6
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1583
    ... +6.1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1584
    ... +6.2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1585
    ...  7
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1586
    ...  8
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1587
    ... +9'''
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1588
    >>> out = util.stringio()
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1589
    >>> headers = parsepatch([rawpatch], maxcontext=1)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1590
    >>> for header in headers:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1591
    ...     header.write(out)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1592
    ...     for hunk in header.hunks:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1593
    ...         hunk.write(out)
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
  1594
    >>> print(pycompat.sysstr(out.getvalue()))
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1595
    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
  1596
    --- a/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1597
    +++ b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1598
    @@ -2,3 +2,2 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1599
     2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1600
    -3
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1601
     4
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1602
    @@ -6,2 +5,4 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1603
     6
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1604
    +6.1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1605
    +6.2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1606
     7
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1607
    @@ -8,1 +9,2 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1608
     8
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1609
    +9
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1610
    """
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1611
    class parser(object):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1612
        """patch parsing state machine"""
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1613
        def __init__(self):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1614
            self.fromline = 0
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1615
            self.toline = 0
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1616
            self.proc = ''
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1617
            self.header = None
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1618
            self.context = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1619
            self.before = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1620
            self.hunk = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1621
            self.headers = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1622
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1623
        def addrange(self, limits):
41454
d1d3094b54f9 patch: handle 0 context lines (diff.unified=0) when parsing patches
Kyle Lippincott <spectral@google.com>
parents: 41401
diff changeset
  1624
            self.addcontext([])
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1625
            fromstart, fromend, tostart, toend, proc = limits
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1626
            self.fromline = int(fromstart)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1627
            self.toline = int(tostart)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1628
            self.proc = proc
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1629
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1630
        def addcontext(self, context):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1631
            if self.hunk:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1632
                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
  1633
                        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
  1634
                self.header.hunks.append(h)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1635
                self.fromline += len(self.before) + h.removed
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1636
                self.toline += len(self.before) + h.added
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1637
                self.before = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1638
                self.hunk = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1639
            self.context = context
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1640
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1641
        def addhunk(self, hunk):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1642
            if self.context:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1643
                self.before = self.context
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1644
                self.context = []
41454
d1d3094b54f9 patch: handle 0 context lines (diff.unified=0) when parsing patches
Kyle Lippincott <spectral@google.com>
parents: 41401
diff changeset
  1645
            if self.hunk:
d1d3094b54f9 patch: handle 0 context lines (diff.unified=0) when parsing patches
Kyle Lippincott <spectral@google.com>
parents: 41401
diff changeset
  1646
                self.addcontext([])
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1647
            self.hunk = hunk
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1648
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1649
        def newfile(self, hdr):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1650
            self.addcontext([])
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1651
            h = header(hdr)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1652
            self.headers.append(h)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1653
            self.header = h
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1654
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1655
        def addother(self, line):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1656
            pass # 'other' lines are ignored
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1657
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1658
        def finished(self):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1659
            self.addcontext([])
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1660
            return self.headers
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
        transitions = {
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1663
            'file': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1664
                     'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1665
                     'hunk': addhunk,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1666
                     'range': addrange},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1667
            'context': {'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1668
                        'hunk': addhunk,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1669
                        'range': addrange,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1670
                        'other': addother},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1671
            'hunk': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1672
                     'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1673
                     'range': addrange},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1674
            'range': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1675
                      'hunk': addhunk},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1676
            'other': {'other': addother},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1677
            }
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1678
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1679
    p = parser()
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1680
    fp = stringio()
24341
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1681
    fp.write(''.join(originalchunks))
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1682
    fp.seek(0)
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1683
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1684
    state = 'context'
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1685
    for newstate, data in scanpatch(fp):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1686
        try:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1687
            p.transitions[state][newstate](p, data)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1688
        except KeyError:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1689
            raise PatchError('unhandled transition: %s -> %s' %
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1690
                                   (state, newstate))
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1691
        state = newstate
24341
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1692
    del fp
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1693
    return p.finished()
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1694
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1695
def pathtransform(path, strip, prefix):
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1696
    '''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
  1697
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1698
    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
  1699
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1700
    Returns (stripped components, path in repository).
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1701
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1702
    >>> pathtransform(b'a/b/c', 0, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1703
    ('', 'a/b/c')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1704
    >>> pathtransform(b'   a/b/c   ', 0, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1705
    ('', '   a/b/c')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1706
    >>> pathtransform(b'   a/b/c   ', 2, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1707
    ('a/b/', 'c')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1708
    >>> 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
  1709
    ('', 'd/e/a/b/c')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1710
    >>> 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
  1711
    ('a//b/', 'd/e/c')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1712
    >>> pathtransform(b'a/b/c', 3, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1713
    Traceback (most recent call last):
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1714
    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
  1715
    '''
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1716
    pathlen = len(path)
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1717
    i = 0
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1718
    if strip == 0:
24385
885a573fa619 patch.pathtransform: prepend prefix even if strip is 0
Siddharth Agarwal <sid0@fb.com>
parents: 24371
diff changeset
  1719
        return '', prefix + path.rstrip()
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1720
    count = strip
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1721
    while count > 0:
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1722
        i = path.find('/', i)
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1723
        if i == -1:
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1724
            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
  1725
                             (count, strip, path))
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1726
        i += 1
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1727
        # consume '//' in the path
34067
8b8b70cb4288 py3: replace bytes[n] with bytes[n:n + 1] in patch.py where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34066
diff changeset
  1728
        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
  1729
            i += 1
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1730
        count -= 1
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1731
    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
  1732
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1733
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
  1734
    nulla = afile_orig == "/dev/null"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1735
    nullb = bfile_orig == "/dev/null"
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1736
    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
  1737
    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
  1738
    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
  1739
    gooda = not nulla and backend.exists(afile)
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1740
    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
  1741
    if afile == bfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1742
        goodb = gooda
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1743
    else:
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
  1744
        goodb = not nullb and backend.exists(bfile)
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1745
    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
  1746
11820
75de514a50f3 patch: fix typo in comment
Martin Geisler <mg@aragost.com>
parents: 11645
diff changeset
  1747
    # 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
  1748
    # 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
  1749
    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
  1750
    bbasedir = bfile[:bfile.rfind('/') + 1]
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1751
    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
  1752
        and hunk.starta == 0 and hunk.lena == 0):
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1753
        create = True
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1754
        missing = False
9328
648d6a1a1cf2 patch: create file even if source is not /dev/null
Brendan Cully <brendan@kublai.com>
parents: 9248
diff changeset
  1755
6295
bace1990ab12 patch: fix corner case with update + copy patch handling (issue 937)
Patrick Mezard <pmezard@gmail.com>
parents: 6280
diff changeset
  1756
    # 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
  1757
    # 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
  1758
    # 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
  1759
    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
  1760
    fname = None
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1761
    if not missing:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1762
        if gooda and goodb:
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1763
            if isbackup:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1764
                fname = afile
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1765
            else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1766
                fname = bfile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1767
        elif gooda:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1768
            fname = afile
5760
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5706
diff changeset
  1769
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1770
    if not fname:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1771
        if not nullb:
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1772
            if isbackup:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1773
                fname = afile
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1774
            else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1775
                fname = bfile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1776
        elif not nulla:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1777
            fname = afile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1778
        else:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1779
            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
  1780
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1781
    gp = patchmeta(fname)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1782
    if create:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1783
        gp.op = 'ADD'
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1784
    elif remove:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1785
        gp.op = 'DELETE'
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1786
    return gp
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1787
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1788
def scanpatch(fp):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1789
    """like patch.iterhunks, but yield different events
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1790
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1791
    - ('file',    [header_lines + fromfile + tofile])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1792
    - ('context', [context_lines])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1793
    - ('hunk',    [hunk_lines])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1794
    - ('range',   (-start,len, +start,len, proc))
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1795
    """
34066
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34042
diff changeset
  1796
    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
  1797
    lr = linereader(fp)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1798
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1799
    def scanwhile(first, p):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1800
        """scan lr while predicate holds"""
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1801
        lines = [first]
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1802
        for line in iter(lr.readline, ''):
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1803
            if p(line):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1804
                lines.append(line)
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
                lr.push(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1807
                break
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1808
        return lines
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1809
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1810
    for line in iter(lr.readline, ''):
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1811
        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
  1812
            def notheader(line):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1813
                s = line.split(None, 1)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1814
                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
  1815
            header = scanwhile(line, notheader)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1816
            fromfile = lr.readline()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1817
            if fromfile.startswith('---'):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1818
                tofile = lr.readline()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1819
                header += [fromfile, tofile]
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1820
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1821
                lr.push(fromfile)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1822
            yield 'file', header
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1823
        elif line.startswith(' '):
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1824
            cs = (' ', '\\')
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1825
            yield 'context', scanwhile(line, lambda l: l.startswith(cs))
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1826
        elif line.startswith(('-', '+')):
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1827
            cs = ('-', '+', '\\')
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1828
            yield 'hunk', scanwhile(line, lambda l: l.startswith(cs))
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1829
        else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1830
            m = lines_re.match(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1831
            if m:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1832
                yield 'range', m.groups()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1833
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1834
                yield 'other', line
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1835
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1836
def scangitpatch(lr, firstline):
7186
f77c8d8331ca clean up trailing spaces, leading spaces in C
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7153
diff changeset
  1837
    """
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1838
    Git patches can emit:
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1839
    - rename a to b
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1840
    - change b
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1841
    - copy a to c
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1842
    - change c
7186
f77c8d8331ca clean up trailing spaces, leading spaces in C
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7153
diff changeset
  1843
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1844
    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
  1845
    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
  1846
    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
  1847
    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
  1848
    perform the copies ahead of time.
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1849
    """
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1850
    pos = 0
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1851
    try:
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1852
        pos = lr.fp.tell()
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1853
        fp = lr.fp
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1854
    except IOError:
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1855
        fp = stringio(lr.fp.read())
14418
0174d1f79280 patch: remove EOL support from linereader class
Patrick Mezard <pmezard@gmail.com>
parents: 14402
diff changeset
  1856
    gitlr = linereader(fp)
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1857
    gitlr.push(firstline)
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
  1858
    gitpatches = readgitpatch(gitlr)
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1859
    fp.seek(pos)
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
  1860
    return gitpatches
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1861
14240
28762bb767dc patch: remove unused ui arg to iterhunks
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
  1862
def iterhunks(fp):
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1863
    """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
  1864
    - ("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
  1865
    - ("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
  1866
    "file" event.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1867
    - ("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
  1868
    maps filenames to gitpatch records. Unique event.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1869
    """
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1870
    afile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1871
    bfile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1872
    state = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1873
    hunknum = 0
14017
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1874
    emitfile = newfile = False
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1875
    gitpatches = None
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1876
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1877
    # our states
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1878
    BFILE = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1879
    context = None
10128
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
  1880
    lr = linereader(fp)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1881
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1882
    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
  1883
        if state == BFILE and (
36646
463df2986814 py3: fix slicing of bytes in patch.iterhunks()
Yuya Nishihara <yuya@tcha.org>
parents: 36607
diff changeset
  1884
            (not context and x.startswith('@'))
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1885
            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
  1886
            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
  1887
            gp = None
14534
ecc79816d31e patch: fix patchmeta/hunk synchronization in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 14533
diff changeset
  1888
            if (gitpatches and
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1889
                gitpatches[-1].ispatching(afile, bfile)):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1890
                gp = gitpatches.pop()
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1891
            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
  1892
                h = binhunk(lr, gp.path)
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1893
            else:
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1894
                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
  1895
                    context = True
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1896
                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
  1897
            hunknum += 1
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1898
            if emitfile:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1899
                emitfile = False
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1900
                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
  1901
            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
  1902
        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
  1903
            m = gitre.match(x.rstrip(' \r\n'))
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1904
            if not m:
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1905
                continue
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1906
            if gitpatches is None:
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1907
                # scan whole input for git metadata
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1908
                gitpatches = scangitpatch(lr, x)
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1909
                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
  1910
                              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
  1911
                gitpatches.reverse()
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1912
            afile = 'a/' + m.group(1)
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1913
            bfile = 'b/' + m.group(2)
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1914
            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
  1915
                gp = gitpatches.pop()
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1916
                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
  1917
            if not gitpatches:
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1918
                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
  1919
                                 % afile[2:])
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1920
            newfile = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1921
        elif x.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1922
            # check for a unified diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1923
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1924
            if not l2.startswith('+++'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1925
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1926
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1927
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1928
            context = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1929
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1930
            bfile = parsefilename(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1931
        elif x.startswith('***'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1932
            # check for a context diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1933
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1934
            if not l2.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1935
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1936
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1937
            l3 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1938
            lr.push(l3)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1939
            if not l3.startswith("***************"):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1940
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1941
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1942
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1943
            context = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1944
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1945
            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
  1946
14017
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1947
        if newfile:
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1948
            newfile = False
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1949
            emitfile = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1950
            state = BFILE
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1951
            hunknum = 0
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1952
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1953
    while gitpatches:
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1954
        gp = gitpatches.pop()
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1955
        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
  1956
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1957
def applybindelta(binchunk, data):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1958
    """Apply a binary delta hunk
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1959
    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
  1960
    """
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1961
    def deltahead(binchunk):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1962
        i = 0
38085
e887381e2976 py3: bytestr() bytes to get bytechar while iterating on it
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38084
diff changeset
  1963
        for c in pycompat.bytestr(binchunk):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1964
            i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1965
            if not (ord(c) & 0x80):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1966
                return i
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1967
        return i
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1968
    out = ""
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1969
    s = deltahead(binchunk)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1970
    binchunk = binchunk[s:]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1971
    s = deltahead(binchunk)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1972
    binchunk = binchunk[s:]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1973
    i = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1974
    while i < len(binchunk):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1975
        cmd = ord(binchunk[i:i + 1])
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1976
        i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1977
        if (cmd & 0x80):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1978
            offset = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1979
            size = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1980
            if (cmd & 0x01):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1981
                offset = ord(binchunk[i:i + 1])
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1982
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1983
            if (cmd & 0x02):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1984
                offset |= ord(binchunk[i:i + 1]) << 8
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1985
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1986
            if (cmd & 0x04):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1987
                offset |= ord(binchunk[i:i + 1]) << 16
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1988
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1989
            if (cmd & 0x08):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1990
                offset |= ord(binchunk[i:i + 1]) << 24
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1991
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1992
            if (cmd & 0x10):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1993
                size = ord(binchunk[i:i + 1])
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1994
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1995
            if (cmd & 0x20):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1996
                size |= ord(binchunk[i:i + 1]) << 8
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1997
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1998
            if (cmd & 0x40):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1999
                size |= ord(binchunk[i:i + 1]) << 16
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2000
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2001
            if size == 0:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2002
                size = 0x10000
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2003
            offset_end = offset + size
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2004
            out += data[offset:offset_end]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2005
        elif cmd != 0:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2006
            offset_end = i + cmd
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2007
            out += binchunk[i:offset_end]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2008
            i += cmd
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2009
        else:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2010
            raise PatchError(_('unexpected delta opcode 0'))
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2011
    return out
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2012
24247
6e19516094a3 patch.applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24246
diff changeset
  2013
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
  2014
    """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
  2015
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2016
    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
  2017
    there was any fuzz.
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2018
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  2019
    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
  2020
    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
  2021
    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
  2022
    """
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2023
    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
  2024
                      prefix=prefix, eolmode=eolmode)
10966
91c58cf54eee patch: refactor applydiff to allow for mempatching
Augie Fackler <durin42@gmail.com>
parents: 10965
diff changeset
  2025
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2026
def _canonprefix(repo, prefix):
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2027
    if prefix:
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2028
        prefix = pathutil.canonpath(repo.root, repo.getcwd(), prefix)
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2029
        if prefix != '':
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2030
            prefix += '/'
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2031
    return prefix
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2032
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2033
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
  2034
               eolmode='strict'):
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2035
    prefix = _canonprefix(backend.repo, prefix)
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2036
    def pstrip(p):
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2037
        return pathtransform(p, strip - 1, prefix)[1]
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2038
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2039
    rejects = 0
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2040
    err = 0
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2041
    current_file = None
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2042
14240
28762bb767dc patch: remove unused ui arg to iterhunks
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
  2043
    for state, values in iterhunks(fp):
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2044
        if state == 'hunk':
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2045
            if not current_file:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2046
                continue
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2047
            ret = current_file.apply(values)
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2048
            if ret > 0:
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2049
                err = 1
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2050
        elif state == 'file':
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2051
            if current_file:
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2052
                rejects += current_file.close()
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2053
                current_file = None
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2054
            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
  2055
            if gp:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2056
                gp.path = pstrip(gp.path)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2057
                if gp.oldpath:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2058
                    gp.oldpath = pstrip(gp.oldpath)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2059
            else:
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2060
                gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2061
                                   prefix)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2062
            if gp.op == 'RENAME':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2063
                backend.unlink(gp.oldpath)
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2064
            if not first_hunk:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2065
                if gp.op == 'DELETE':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2066
                    backend.unlink(gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2067
                    continue
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2068
                data, mode = None, None
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2069
                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
  2070
                    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: 29948
diff changeset
  2071
                    if data is None:
173bdb502503 import: abort instead of crashing when copy source does not exist (issue5375)
Ryan McElroy <rmcelroy@fb.com>
parents: 29948
diff changeset
  2072
                        # 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: 29948
diff changeset
  2073
                        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: 29948
diff changeset
  2074
                                           % gp.oldpath)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2075
                if gp.mode:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2076
                    mode = gp.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2077
                    if gp.op == 'ADD':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2078
                        # 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
  2079
                        # must be created
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2080
                        data = ''
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2081
                if data or mode:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2082
                    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
  2083
                        and backend.exists(gp.path)):
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2084
                        raise PatchError(_("cannot create %s: destination "
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2085
                                           "already exists") % gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2086
                    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
  2087
                continue
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2088
            try:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2089
                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
  2090
                                       eolmode=eolmode)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25658
diff changeset
  2091
            except PatchError as inst:
14218
202ff575d49b patch: fix clash between local variable and exception instance
Martin Geisler <mg@aragost.com>
parents: 14217
diff changeset
  2092
                ui.warn(str(inst) + '\n')
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2093
                current_file = None
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2094
                rejects += 1
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2095
                continue
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2096
        elif state == 'git':
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2097
            for gp in values:
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2098
                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
  2099
                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
  2100
                if data is None:
16813
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2101
                    # 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
  2102
                    # 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
  2103
                    # 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
  2104
                    # process.
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
  2105
                    pass
16813
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2106
                else:
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2107
                    store.setfile(path, data, mode)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2108
        else:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26560
diff changeset
  2109
            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
  2110
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2111
    if current_file:
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2112
        rejects += current_file.close()
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2113
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2114
    if rejects:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2115
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2116
    return err
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2117
14382
2d16f15da7bd patch: remove patch.patch() cwd argument
Patrick Mezard <pmezard@gmail.com>
parents: 14381
diff changeset
  2118
def _externalpatch(ui, repo, patcher, patchname, strip, files,
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2119
                   similarity):
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2120
    """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
  2121
    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
  2122
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2123
    fuzz = False
12673
9ad16d1bce4b patch: simplify externalpatch() arguments
Patrick Mezard <pmezard@gmail.com>
parents: 12671
diff changeset
  2124
    args = []
14382
2d16f15da7bd patch: remove patch.patch() cwd argument
Patrick Mezard <pmezard@gmail.com>
parents: 14381
diff changeset
  2125
    cwd = repo.root
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2126
    if cwd:
37120
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
  2127
        args.append('-d %s' % procutil.shellquote(cwd))
37458
00e4bd97b095 procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents: 37456
diff changeset
  2128
    cmd = ('%s %s -p%d < %s'
00e4bd97b095 procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents: 37456
diff changeset
  2129
           % (patcher, ' '.join(args), strip, procutil.shellquote(patchname)))
38092
f3776f70985e patch: add debug message to show external patch tool invocation
Augie Fackler <augie@google.com>
parents: 38085
diff changeset
  2130
    ui.debug('Using external patch tool: %s\n' % cmd)
37458
00e4bd97b095 procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents: 37456
diff changeset
  2131
    fp = procutil.popen(cmd, 'rb')
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2132
    try:
30397
564b33acc21f patch: migrate to util.iterfile
Jun Wu <quark@fb.com>
parents: 30078
diff changeset
  2133
        for line in util.iterfile(fp):
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2134
            line = line.rstrip()
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2135
            ui.note(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2136
            if line.startswith('patching file '):
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2137
                pf = util.parsepatchoutput(line)
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2138
                printed_file = False
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2139
                files.add(pf)
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2140
            elif line.find('with fuzz') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2141
                fuzz = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2142
                if not printed_file:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2143
                    ui.warn(pf + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2144
                    printed_file = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2145
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2146
            elif line.find('saving rejects to file') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2147
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2148
            elif line.find('FAILED') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2149
                if not printed_file:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2150
                    ui.warn(pf + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2151
                    printed_file = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2152
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2153
    finally:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2154
        if files:
19155
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
  2155
            scmutil.marktouched(repo, files, similarity)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2156
    code = fp.close()
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2157
    if code:
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2158
        raise PatchError(_("patch command failed: %s") %
37463
bbd240f81ac5 procutil: make explainexit() simply return a message (API)
Yuya Nishihara <yuya@tcha.org>
parents: 37458
diff changeset
  2159
                         procutil.explainexit(code))
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2160
    return fuzz
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2161
24253
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2162
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
  2163
                 eolmode='strict'):
9683
5c8651e2f5e0 patch: don't use mutable object as default argument
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9682
diff changeset
  2164
    if files is None:
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2165
        files = set()
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2166
    if eolmode is None:
33229
dd50a370c8cb configitems: register the 'patch.eol' config
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 33156
diff changeset
  2167
        eolmode = ui.config('patch', 'eol')
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  2168
    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
  2169
        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
  2170
    eolmode = eolmode.lower()
8843
eb7b247a98ea kill trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8817
diff changeset
  2171
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2172
    store = filestore()
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2173
    try:
9031
3b76321aa0de compat: use open() instead of file() everywhere
Alejandro Santos <alejolp@alejolp.com>
parents: 9029
diff changeset
  2174
        fp = open(patchobj, 'rb')
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2175
    except TypeError:
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2176
        fp = patchobj
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2177
    try:
24253
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2178
        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
  2179
                        eolmode=eolmode)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2180
    finally:
10203
6e26e3c2083f patch: explicitely close input patch files when leaving
Patrick Mezard <pmezard@gmail.com>
parents: 10135
diff changeset
  2181
        if fp != patchobj:
6e26e3c2083f patch: explicitely close input patch files when leaving
Patrick Mezard <pmezard@gmail.com>
parents: 10135
diff changeset
  2182
            fp.close()
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2183
        files.update(backend.close())
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2184
        store.close()
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2185
    if ret < 0:
12674
aa2fe1f52ff4 patch: always raise PatchError with a message, simplify handling
Patrick Mezard <pmezard@gmail.com>
parents: 12673
diff changeset
  2186
        raise PatchError(_('patch failed to apply'))
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2187
    return ret > 0
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2188
24268
cf7d252d8c30 patch.internalpatch: add a default value for prefix
Siddharth Agarwal <sid0@fb.com>
parents: 24265
diff changeset
  2189
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
  2190
                  eolmode='strict', similarity=0):
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2191
    """use builtin patch to apply <patchobj> to the working directory.
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2192
    returns whether patch was applied with fuzz factor."""
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2193
    backend = workingbackend(ui, repo, similarity)
24254
60c279ab7bd3 patch.internalpatch: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24253
diff changeset
  2194
    return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2195
24260
76225ab5a5da cmdutil.tryimportone: allow importing relative patches with --bypass
Siddharth Agarwal <sid0@fb.com>
parents: 24259
diff changeset
  2196
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
  2197
              eolmode='strict'):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2198
    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
  2199
    return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2200
24259
5ac8ce04baa2 cmdutil.tryimportone: allow importing relative patches into the working dir
Siddharth Agarwal <sid0@fb.com>
parents: 24254
diff changeset
  2201
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
  2202
          similarity=0):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2203
    """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
  2204
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2205
    '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
  2206
    - '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
  2207
    - '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
  2208
    - '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
  2209
    - 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
  2210
    '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
  2211
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2212
    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
  2213
    """
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2214
    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
  2215
    if files is None:
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2216
        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
  2217
    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
  2218
        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
  2219
                              files, similarity)
24259
5ac8ce04baa2 cmdutil.tryimportone: allow importing relative patches into the working dir
Siddharth Agarwal <sid0@fb.com>
parents: 24254
diff changeset
  2220
    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
  2221
                         similarity)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2222
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2223
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
  2224
    backend = fsbackend(ui, repo.root)
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2225
    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
  2226
    with open(patchpath, 'rb') as fp:
14255
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2227
        changed = set()
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2228
        for state, values in iterhunks(fp):
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2229
            if state == 'file':
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2230
                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
  2231
                if gp:
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2232
                    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
  2233
                    if gp.oldpath:
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2234
                        gp.oldpath = pathtransform(gp.oldpath, strip - 1,
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2235
                                                   prefix)[1]
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2236
                else:
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  2237
                    gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2238
                                       prefix)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2239
                changed.add(gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2240
                if gp.op == 'RENAME':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2241
                    changed.add(gp.oldpath)
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2242
            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
  2243
                raise error.Abort(_('unsupported parser state: %s') % state)
14255
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2244
        return changed
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2245
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2246
class GitDiffRequired(Exception):
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2247
    pass
7198
df79ee9b6278 patch: extract local function addmodehdr
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7186
diff changeset
  2248
38587
b62000a28812 diffutil: remove diffopts() in favor of diffallopts()
Yuya Nishihara <yuya@tcha.org>
parents: 38562
diff changeset
  2249
diffopts = diffutil.diffallopts
38562
c88d2c9b00dd diffutil: extract diff options code into a dedicated util-module
Boris Feld <boris.feld@octobus.net>
parents: 38493
diff changeset
  2250
diffallopts = diffutil.diffallopts
c88d2c9b00dd diffutil: extract diff options code into a dedicated util-module
Boris Feld <boris.feld@octobus.net>
parents: 38493
diff changeset
  2251
difffeatureopts = diffutil.difffeatureopts
10615
3bb438ce4458 patch/diff: move diff related code next to each other
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10611
diff changeset
  2252
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2253
def diff(repo, node1=None, node2=None, match=None, changes=None,
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2254
         opts=None, losedatafn=None, pathfn=None, copy=None,
41620
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2255
         copysourcematch=None, hunksfilterfn=None):
7308
b6f5490effbf patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7267
diff changeset
  2256
    '''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
  2257
    working directory.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2258
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2259
    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
  2260
    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
  2261
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2262
    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
  2263
    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
  2264
    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
  2265
    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
  2266
    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
  2267
    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
  2268
    necessary.
12167
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2269
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2270
    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
  2271
    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
  2272
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2273
    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
  2274
    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
  2275
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2276
    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
  2277
    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
  2278
41620
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2279
    if copysourcematch is not None, then copy sources will be filtered by this
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2280
    matcher
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2281
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
  2282
    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
  2283
    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
  2284
    '''
41618
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2285
    if not node1 and not node2:
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2286
        node1 = repo.dirstate.p1()
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2287
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2288
    ctx1 = repo[node1]
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2289
    ctx2 = repo[node2]
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2290
34855
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2291
    for fctx1, fctx2, hdr, hunks in diffhunks(
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2292
            repo, ctx1=ctx1, ctx2=ctx2, match=match, changes=changes, opts=opts,
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2293
            losedatafn=losedatafn, pathfn=pathfn, copy=copy,
41620
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2294
            copysourcematch=copysourcematch):
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
  2295
        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
  2296
            # 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
  2297
            # not occur here since we catch removed files early in
35888
c8e2d6ed1f9e cmdutil: drop aliases for logcmdutil functions (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35850
diff changeset
  2298
            # logcmdutil.getlinerangerevs() for 'hg log -L'.
41759
aaad36b88298 cleanup: use () to wrap long lines instead of \
Augie Fackler <augie@google.com>
parents: 41646
diff changeset
  2299
            assert fctx2 is not None, (
aaad36b88298 cleanup: use () to wrap long lines instead of \
Augie Fackler <augie@google.com>
parents: 41646
diff changeset
  2300
                '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
  2301
            hunks = hunksfilterfn(fctx2, hunks)
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2302
        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
  2303
        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
  2304
            yield '\n'.join(hdr) + '\n'
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2305
        if text:
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2306
            yield text
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2307
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2308
def diffhunks(repo, ctx1, ctx2, match=None, changes=None, opts=None,
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2309
              losedatafn=None, pathfn=None, copy=None, copysourcematch=None):
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2310
    """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: 31273
diff changeset
  2311
    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: 31273
diff changeset
  2312
    (`hunkrange`, `hunklines`) tuples.
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2313
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2314
    See diff() for the meaning of parameters.
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2315
    """
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2316
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2317
    if opts is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2318
        opts = mdiff.defaultopts
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2319
9123
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2320
    def lrugetfilectx():
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2321
        cache = {}
25113
0ca8410ea345 util: drop alias for collections.deque
Martin von Zweigbergk <martinvonz@google.com>
parents: 24845
diff changeset
  2322
        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
  2323
        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
  2324
            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
  2325
            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
  2326
                if len(cache) > 20:
16803
107a3270a24a cleanup: use the deque type where appropriate
Bryan O'Sullivan <bryano@fb.com>
parents: 16705
diff changeset
  2327
                    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
  2328
                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
  2329
            else:
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2330
                order.remove(f)
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2331
            order.append(f)
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2332
            return fctx
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2333
        return getfilectx
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2334
    getfilectx = lrugetfilectx()
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
  2335
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2336
    if not changes:
38773
59af0c7d103f patch: use ctx1.status(ctx2) instead of repo.status(ctx1, ctx2)
Martin von Zweigbergk <martinvonz@google.com>
parents: 38630
diff changeset
  2337
        changes = ctx1.status(ctx2, match=match)
6760
4faaa0535ea7 status: clean up all users for unknown files
Matt Mackall <mpm@selenic.com>
parents: 6758
diff changeset
  2338
    modified, added, removed = changes[:3]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2339
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2340
    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
  2341
        return []
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2342
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2343
    if repo.ui.debugflag:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2344
        hexfunc = hex
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2345
    else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2346
        hexfunc = short
21833
c1ceec0c8cb4 patch: use ctx.node() instead of bare node variable
Sean Farley <sean.michael.farley@gmail.com>
parents: 21790
diff changeset
  2347
    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
  2348
29422
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2349
    if copy is None:
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2350
        copy = {}
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2351
        if opts.git or opts.upgrade:
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2352
            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
  2353
41620
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2354
    if copysourcematch:
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2355
        # filter out copies where source side isn't inside the matcher
41499
a5d8824483ba diff: drop duplicate filter of copies by destination
Martin von Zweigbergk <martinvonz@google.com>
parents: 41498
diff changeset
  2356
        # (copies.pathcopies() already filtered out the destination)
a5d8824483ba diff: drop duplicate filter of copies by destination
Martin von Zweigbergk <martinvonz@google.com>
parents: 41498
diff changeset
  2357
        copy = {dst: src for dst, src in copy.iteritems()
41620
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2358
                if copysourcematch(src)}
24417
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2359
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2360
    modifiedset = set(modified)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2361
    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
  2362
    removedset = set(removed)
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2363
    for f in modified:
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2364
        if f not in ctx1:
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2365
            # 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
  2366
            # modifications during merges
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2367
            modifiedset.remove(f)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2368
            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
  2369
    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
  2370
        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
  2371
            # 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
  2372
            # 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
  2373
            removedset.remove(f)
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2374
    modified = sorted(modifiedset)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2375
    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
  2376
    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
  2377
    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
  2378
        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
  2379
            # 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
  2380
            # 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
  2381
            del copy[dst]
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2382
37764
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2383
    prefetchmatch = scmutil.matchfiles(
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2384
        repo, list(modifiedset | addedset | removedset))
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2385
    scmutil.prefetchfiles(repo, [ctx1.rev(), ctx2.rev()], prefetchmatch)
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2386
17299
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
  2387
    def difffn(opts, losedata):
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
  2388
        return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2389
                       copy, getfilectx, opts, losedata, pathfn)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2390
    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
  2391
        try:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2392
            def losedata(fn):
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2393
                if not losedatafn or not losedatafn(fn=fn):
16687
e34106fa0dc3 cleanup: "raise SomeException()" -> "raise SomeException"
Brodie Rao <brodie@sf.io>
parents: 16686
diff changeset
  2394
                    raise GitDiffRequired
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2395
            # 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
  2396
            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
  2397
        except GitDiffRequired:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2398
            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
  2399
    else:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2400
        return difffn(opts, None)
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2401
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2402
def diffsinglehunk(hunklines):
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2403
    """yield tokens for a list of lines in a single hunk"""
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2404
    for line in hunklines:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2405
        # chomp
38630
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2406
        chompline = line.rstrip('\r\n')
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2407
        # highlight tabs and trailing whitespace
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2408
        stripline = chompline.rstrip()
38048
b403e87df069 py3: use .startswith() instead of bytes[0]
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37803
diff changeset
  2409
        if line.startswith('-'):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2410
            label = 'diff.deleted'
38048
b403e87df069 py3: use .startswith() instead of bytes[0]
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37803
diff changeset
  2411
        elif line.startswith('+'):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2412
            label = 'diff.inserted'
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2413
        else:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2414
            raise error.ProgrammingError('unexpected hunk line: %s' % line)
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2415
        for token in tabsplitter.findall(stripline):
38048
b403e87df069 py3: use .startswith() instead of bytes[0]
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37803
diff changeset
  2416
            if token.startswith('\t'):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2417
                yield (token, 'diff.tab')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2418
            else:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2419
                yield (token, label)
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2420
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2421
        if chompline != stripline:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2422
            yield (chompline[len(stripline):], 'diff.trailingwhitespace')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2423
        if chompline != line:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2424
            yield (line[len(chompline):], '')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2425
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2426
def diffsinglehunkinline(hunklines):
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2427
    """yield tokens for a list of lines in a single hunk, with inline colors"""
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2428
    # prepare deleted, and inserted content
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2429
    a = ''
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2430
    b = ''
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2431
    for line in hunklines:
39616
5a2bf7f941fa py3: slice through bytes to prevent getting ascii value
Pulkit Goyal <pulkit@yandex-team.ru>
parents: 38783
diff changeset
  2432
        if line[0:1] == '-':
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2433
            a += line[1:]
39616
5a2bf7f941fa py3: slice through bytes to prevent getting ascii value
Pulkit Goyal <pulkit@yandex-team.ru>
parents: 38783
diff changeset
  2434
        elif line[0:1] == '+':
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2435
            b += line[1:]
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2436
        else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2437
            raise error.ProgrammingError('unexpected hunk line: %s' % line)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2438
    # fast path: if either side is empty, use diffsinglehunk
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2439
    if not a or not b:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2440
        for t in diffsinglehunk(hunklines):
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2441
            yield t
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2442
        return
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2443
    # re-split the content into words
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2444
    al = wordsplitter.findall(a)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2445
    bl = wordsplitter.findall(b)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2446
    # re-arrange the words to lines since the diff algorithm is line-based
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2447
    aln = [s if s == '\n' else s + '\n' for s in al]
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2448
    bln = [s if s == '\n' else s + '\n' for s in bl]
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2449
    an = ''.join(aln)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2450
    bn = ''.join(bln)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2451
    # run the diff algorithm, prepare atokens and btokens
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2452
    atokens = []
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2453
    btokens = []
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2454
    blocks = mdiff.allblocks(an, bn, lines1=aln, lines2=bln)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2455
    for (a1, a2, b1, b2), btype in blocks:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2456
        changed = btype == '!'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2457
        for token in mdiff.splitnewlines(''.join(al[a1:a2])):
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2458
            atokens.append((changed, token))
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2459
        for token in mdiff.splitnewlines(''.join(bl[b1:b2])):
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2460
            btokens.append((changed, token))
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2461
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2462
    # yield deleted tokens, then inserted ones
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2463
    for prefix, label, tokens in [('-', 'diff.deleted', atokens),
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2464
                                  ('+', 'diff.inserted', btokens)]:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2465
        nextisnewline = True
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2466
        for changed, token in tokens:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2467
            if nextisnewline:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2468
                yield (prefix, label)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2469
                nextisnewline = False
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2470
            # special handling line end
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2471
            isendofline = token.endswith('\n')
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2472
            if isendofline:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2473
                chomp = token[:-1] # chomp
38630
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2474
                if chomp.endswith('\r'):
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2475
                    chomp = chomp[:-1]
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2476
                endofline = token[len(chomp):]
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2477
                token = chomp.rstrip() # detect spaces at the end
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2478
                endspaces = chomp[len(token):]
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2479
            # scan tabs
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2480
            for maybetab in tabsplitter.findall(token):
40282
e4f82db071a4 py3: fix test-diff-color.t
Mark Thomas <mbthomas@fb.com>
parents: 39616
diff changeset
  2481
                if b'\t' == maybetab[0:1]:
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2482
                    currentlabel = 'diff.tab'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2483
                else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2484
                    if changed:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2485
                        currentlabel = label + '.changed'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2486
                    else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2487
                        currentlabel = label + '.unchanged'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2488
                yield (maybetab, currentlabel)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2489
            if isendofline:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2490
                if endspaces:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2491
                    yield (endspaces, 'diff.trailingwhitespace')
38630
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2492
                yield (endofline, '')
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2493
                nextisnewline = True
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2494
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2495
def difflabel(func, *args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2496
    '''yields 2-tuples of (output, label) based on the output of func()'''
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2497
    if kw.get(r'opts') and kw[r'opts'].worddiff:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2498
        dodiffhunk = diffsinglehunkinline
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2499
    else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2500
        dodiffhunk = diffsinglehunk
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2501
    headprefixes = [('diff', 'diff.diffline'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2502
                    ('copy', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2503
                    ('rename', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2504
                    ('old', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2505
                    ('new', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2506
                    ('deleted', 'diff.extended'),
30790
dbcc10cf7f8d patch: add label for coloring the index extended header
Sean Farley <sean@farley.io>
parents: 30789
diff changeset
  2507
                    ('index', 'diff.extended'),
30808
8540967cd9e0 patch: add label for coloring the similarity extended header
Sean Farley <sean@farley.io>
parents: 30807
diff changeset
  2508
                    ('similarity', 'diff.extended'),
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2509
                    ('---', 'diff.file_a'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2510
                    ('+++', 'diff.file_b')]
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2511
    textprefixes = [('@', 'diff.hunk'),
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2512
                    # - and + are handled by diffsinglehunk
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2513
                   ]
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2514
    head = False
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2515
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2516
    # buffers a hunk, i.e. adjacent "-", "+" lines without other changes.
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2517
    hunkbuffer = []
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2518
    def consumehunkbuffer():
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2519
        if hunkbuffer:
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2520
            for token in dodiffhunk(hunkbuffer):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2521
                yield token
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2522
            hunkbuffer[:] = []
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2523
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2524
    for chunk in func(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2525
        lines = chunk.split('\n')
37730
8d730f96e792 patch: move yielding "\n" to the end of loop
Jun Wu <quark@fb.com>
parents: 37621
diff changeset
  2526
        linecount = len(lines)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2527
        for i, line in enumerate(lines):
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2528
            if head:
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2529
                if line.startswith('@'):
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2530
                    head = False
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2531
            else:
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  2532
                if line and not line.startswith((' ', '+', '-', '@', '\\')):
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2533
                    head = True
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2534
            diffline = False
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  2535
            if not head and line and line.startswith(('+', '-')):
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2536
                diffline = True
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2537
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2538
            prefixes = textprefixes
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2539
            if head:
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2540
                prefixes = headprefixes
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2541
            if diffline:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2542
                # buffered
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2543
                bufferedline = line
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2544
                if i + 1 < linecount:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2545
                    bufferedline += "\n"
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2546
                hunkbuffer.append(bufferedline)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2547
            else:
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2548
                # unbuffered
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2549
                for token in consumehunkbuffer():
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2550
                    yield token
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2551
                stripline = line.rstrip()
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2552
                for prefix, label in prefixes:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2553
                    if stripline.startswith(prefix):
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2554
                        yield (stripline, label)
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2555
                        if line != stripline:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2556
                            yield (line[len(stripline):],
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2557
                                   'diff.trailingwhitespace')
35277
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35191
diff changeset
  2558
                        break
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2559
                else:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2560
                    yield (line, '')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2561
                if i + 1 < linecount:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2562
                    yield ('\n', '')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2563
        for token in consumehunkbuffer():
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2564
            yield token
35277
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35191
diff changeset
  2565
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2566
def diffui(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2567
    '''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
  2568
    return difflabel(diff, *args, **kw)
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2569
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2570
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
  2571
    '''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
  2572
    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
  2573
    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
  2574
    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
  2575
    gone = set()
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2576
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2577
    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
  2578
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2579
    addedset, removedset = set(added), set(removed)
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2580
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2581
    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
  2582
        copyop = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2583
        f1, f2 = f, f
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2584
        if f in addedset:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2585
            f1 = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2586
            if f in copy:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2587
                if opts.git:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2588
                    f1 = copy[f]
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2589
                    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
  2590
                        copyop = 'rename'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2591
                        gone.add(f1)
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2592
                    else:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2593
                        copyop = 'copy'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2594
        elif f in removedset:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2595
            f2 = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2596
            if opts.git:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2597
                # 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
  2598
                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
  2599
                    and copy[copyto[f]] == f):
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2600
                    continue
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2601
        yield f1, f2, copyop
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2602
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2603
def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2604
            copy, getfilectx, opts, losedatafn, pathfn):
24371
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2605
    '''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
  2606
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2607
    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
  2608
    losedatafn is not None, it will be called.
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2609
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2610
    pathfn is applied to every path in the diff output.
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2611
    '''
12167
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2612
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2613
    def gitindex(text):
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2614
        if not text:
19875
c172660eee01 patch: Fix nullid for binary git diffs (issue4054)
Johan Bjork <jbjoerk@gmail.com>
parents: 19513
diff changeset
  2615
            text = ""
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2616
        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
  2617
        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
  2618
        s.update(text)
35582
72b91f905065 py3: use node.hex(h.digest()) instead of h.hexdigest()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35383
diff changeset
  2619
        return hex(s.digest())
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2620
23300
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2621
    if opts.noprefix:
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2622
        aprefix = bprefix = ''
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2623
    else:
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2624
        aprefix = 'a/'
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2625
        bprefix = 'b/'
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2626
24021
f51a822dcf3b trydiff: remove unused argument to diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24020
diff changeset
  2627
    def diffline(f, revs):
24024
a5c7e86a81c1 trydiff: move check for quietness out of diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24023
diff changeset
  2628
        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
  2629
        return 'diff %s %s' % (revinfo, f)
17941
9a6e4d5d7ea8 diff: move diffline to patch module
Guillermo Pérez <bisho@fb.com>
parents: 17940
diff changeset
  2630
32188
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2631
    def isempty(fctx):
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2632
        return fctx is None or fctx.size() == 0
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2633
36607
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36447
diff changeset
  2634
    date1 = dateutil.datestr(ctx1.date())
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36447
diff changeset
  2635
    date2 = dateutil.datestr(ctx2.date())
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  2636
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2637
    gitmode = {'l': '120000', 'x': '100755', '': '100644'}
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2638
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2639
    if not pathfn:
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2640
        pathfn = lambda f: f
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2641
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2642
    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
  2643
        content1 = None
0f8baebcdbea trydiff: read file data in only one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24104
diff changeset
  2644
        content2 = None
32187
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2645
        fctx1 = None
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2646
        fctx2 = None
24103
c666c85f71ba trydiff: read flags in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24102
diff changeset
  2647
        flag1 = None
c666c85f71ba trydiff: read flags in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24102
diff changeset
  2648
        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
  2649
        if f1:
32187
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2650
            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
  2651
            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
  2652
                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
  2653
        if f2:
32187
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2654
            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
  2655
            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
  2656
                flag2 = ctx2.flags(f2)
32190
0c67ab3d77d5 diff: correct binary testing logic
Jun Wu <quark@fb.com>
parents: 32189
diff changeset
  2657
        # if binary is True, output "summary" or "base85", but not "text diff"
35850
079b27b5a869 patch: avoid repeated binary checks if all files in a patch are text
Joerg Sonnenberger <joerg@bec.de>
parents: 35633
diff changeset
  2658
        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
  2659
            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
  2660
        else:
35951
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35888
diff changeset
  2661
            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
  2662
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2663
        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
  2664
            if (binary or
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2665
                # copy/rename
24106
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2666
                f2 in copy or
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2667
                # empty file creation
32188
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2668
                (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
  2669
                # empty file deletion
32188
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2670
                (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
  2671
                # create with flags
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2672
                (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
  2673
                # change flags
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2674
                (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
  2675
                losedatafn(f2 or f1)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2676
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2677
        path1 = pathfn(f1 or f2)
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2678
        path2 = pathfn(f2 or f1)
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2679
        header = []
24022
da63f557d0dc trydiff: make 'revs' ignored if opts.git is set
Martin von Zweigbergk <martinvonz@google.com>
parents: 24021
diff changeset
  2680
        if opts.git:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2681
            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
  2682
                          (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
  2683
            if not f1: # added
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2684
                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
  2685
            elif not f2: # removed
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2686
                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
  2687
            else:  # modified/copied/renamed
24000
82e3324c4df9 trydiff: inline sole addmodehdr() call
Martin von Zweigbergk <martinvonz@google.com>
parents: 23999
diff changeset
  2688
                mode1, mode2 = gitmode[flag1], gitmode[flag2]
82e3324c4df9 trydiff: inline sole addmodehdr() call
Martin von Zweigbergk <martinvonz@google.com>
parents: 23999
diff changeset
  2689
                if mode1 != mode2:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2690
                    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
  2691
                    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
  2692
                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
  2693
                    if opts.showsimilarity:
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
  2694
                        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
  2695
                        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
  2696
                    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
  2697
                    header.append('%s to %s' % (copyop, path2))
41784
251332dbf33d diff: make sure we output stat even when --git is not passed (issue4037) (BC)
Pulkit Goyal <pulkit@yandex-team.ru>
parents: 41759
diff changeset
  2698
        elif revs:
24022
da63f557d0dc trydiff: make 'revs' ignored if opts.git is set
Martin von Zweigbergk <martinvonz@google.com>
parents: 24021
diff changeset
  2699
            header.append(diffline(path1, revs))
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2700
32189
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2701
        #  fctx.is  | diffopts                | what to   | is fctx.data()
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2702
        #  binary() | text nobinary git index | output?   | outputted?
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2703
        # ------------------------------------|----------------------------
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2704
        #  yes      | no   no       no  *     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2705
        #  yes      | no   no       yes *     | base85    | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2706
        #  yes      | no   yes      no  *     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2707
        #  yes      | no   yes      yes 0     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2708
        #  yes      | no   yes      yes >0    | summary   | semi [1]
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2709
        #  yes      | yes  *        *   *     | text diff | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2710
        #  no       | *    *        *   *     | text diff | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2711
        # [1]: hash(fctx.data()) is outputted. so fctx.data() cannot be faked
32191
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2712
        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: 32190
diff changeset
  2713
                                        opts.index)):
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2714
            # 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: 32190
diff changeset
  2715
            # 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: 32190
diff changeset
  2716
            # fast path.
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2717
            if fctx1 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2718
                content1 = b'\0'
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2719
            if fctx2 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2720
                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: 32190
diff changeset
  2721
                    content2 = b'\0' # not different
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2722
                else:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2723
                    content2 = b'\0\0'
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2724
        else:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2725
            # normal path: load contents
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2726
            if fctx1 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2727
                content1 = fctx1.data()
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2728
            if fctx2 is not None:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2729
                content2 = fctx2.data()
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2730
32190
0c67ab3d77d5 diff: correct binary testing logic
Jun Wu <quark@fb.com>
parents: 32189
diff changeset
  2731
        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
  2732
            text = mdiff.b85diff(content1, content2)
24056
ae453d166d51 trydiff: replace 'binarydiff' variable by 'binary' variable
Martin von Zweigbergk <martinvonz@google.com>
parents: 24055
diff changeset
  2733
            if text:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2734
                header.append('index %s..%s' %
24005
2c166f6b5d10 trydiff: inline indexmeta()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24001
diff changeset
  2735
                              (gitindex(content1), gitindex(content2)))
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2736
            hunks = (None, [text]),
23753
e30c6aa6f2a2 trydiff: replace 'dodiff = False' by 'continue'
Martin von Zweigbergk <martinvonz@google.com>
parents: 23752
diff changeset
  2737
        else:
30789
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2738
            if opts.git and opts.index > 0:
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2739
                flag = flag1
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2740
                if flag is None:
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2741
                    flag = flag2
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2742
                header.append('index %s..%s %s' %
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2743
                              (gitindex(content1)[0:opts.index],
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2744
                               gitindex(content2)[0:opts.index],
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2745
                               gitmode[flag]))
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2746
31273
92714858dd3e mdiff: let unidiff return (diffheader, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31271
diff changeset
  2747
            uheaders, hunks = mdiff.unidiff(content1, date1,
92714858dd3e mdiff: let unidiff return (diffheader, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31271
diff changeset
  2748
                                            content2, date2,
35951
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35888
diff changeset
  2749
                                            path1, path2,
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35888
diff changeset
  2750
                                            binary=binary, opts=opts)
31271
b3861be6aa6c mdiff: distinguish diff headers from hunks in unidiff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31233
diff changeset
  2751
            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
  2752
        yield fctx1, fctx2, header, hunks
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2753
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2754
def diffstatsum(stats):
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2755
    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
  2756
    for f, a, r, b in stats:
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2757
        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
  2758
        maxtotal = max(maxtotal, a + r)
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2759
        addtotal += a
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2760
        removetotal += r
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2761
        binary = binary or b
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2762
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2763
    return maxfile, maxtotal, addtotal, removetotal, binary
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2764
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2765
def diffstatdata(lines):
41532
bd3f03d8cc9f global: use raw strings for regular expressions with escapes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41499
diff changeset
  2766
    diffre = re.compile(br'^diff .*-r [a-z0-9]+\s(.*)$')
13395
104c9ed93fc5 diffstat: fix parsing of filenames with spaces
Gastón Kleiman <gaston.kleiman@gmail.com>
parents: 13112
diff changeset
  2767
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2768
    results = []
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2769
    filename, adds, removes, isbinary = None, 0, 0, False
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2770
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2771
    def addresult():
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2772
        if filename:
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2773
            results.append((filename, adds, removes, isbinary))
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2774
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2775
    # 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: 32201
diff changeset
  2776
    # 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: 32201
diff changeset
  2777
    # for lines that start with '--' or '++'
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2778
    inheader = False
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2779
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2780
    for line in lines:
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2781
        if line.startswith('diff'):
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2782
            addresult()
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2783
            # starting a new file diff
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2784
            # set numbers to 0 and reset inheader
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2785
            inheader = True
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2786
            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
  2787
            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
  2788
                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
  2789
            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
  2790
                # 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
  2791
                filename = diffre.search(line).group(1)
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2792
        elif line.startswith('@@'):
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2793
            inheader = False
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2794
        elif line.startswith('+') and not inheader:
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2795
            adds += 1
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2796
        elif line.startswith('-') and not inheader:
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2797
            removes += 1
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2798
        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
  2799
              line.startswith('Binary file')):
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2800
            isbinary = True
41375
f1b0d9988825 diffstat: make --git work properly on renames (issue6025)
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41365
diff changeset
  2801
        elif line.startswith('rename from'):
41401
4a33a6bf2b52 diffstat: support filenames with whitespaces on renames
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41375
diff changeset
  2802
            filename = line[12:]
41375
f1b0d9988825 diffstat: make --git work properly on renames (issue6025)
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41365
diff changeset
  2803
        elif line.startswith('rename to'):
41401
4a33a6bf2b52 diffstat: support filenames with whitespaces on renames
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41375
diff changeset
  2804
            filename += ' => %s' % line[10:]
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2805
    addresult()
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2806
    return results
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2807
30407
e1677cc29da6 patch: remove unused git parameter from patch.diffstat()
Henning Schild <henning@hennsch.de>
parents: 30397
diff changeset
  2808
def diffstat(lines, width=80):
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2809
    output = []
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2810
    stats = diffstatdata(lines)
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2811
    maxname, maxtotal, totaladds, totalremoves, hasbinary = diffstatsum(stats)
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2812
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2813
    countwidth = len(str(maxtotal))
9642
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2814
    if hasbinary and countwidth < 3:
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2815
        countwidth = 3
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2816
    graphwidth = width - countwidth - maxname - 6
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2817
    if graphwidth < 10:
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2818
        graphwidth = 10
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2819
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2820
    def scale(i):
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2821
        if maxtotal <= graphwidth:
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2822
            return i
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2823
        # 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
  2824
        # 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
  2825
        # 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
  2826
        return max(i * graphwidth // maxtotal, int(bool(i)))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2827
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2828
    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
  2829
        if isbinary:
9642
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2830
            count = 'Bin'
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2831
        else:
33104
53238678b1ca py3: use '%d' to convert integers to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 33096
diff changeset
  2832
            count = '%d' % (adds + removes)
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2833
        pluses = '+' * scale(adds)
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2834
        minuses = '-' * scale(removes)
11611
4f5a6df2af92 i18n: use encoding.colwidth() for correct column width
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11377
diff changeset
  2835
        output.append(' %s%s |  %*s %s%s\n' %
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2836
                      (filename, ' ' * (maxname - encoding.colwidth(filename)),
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2837
                       countwidth, count, pluses, minuses))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2838
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2839
    if stats:
16683
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  2840
        output.append(_(' %d files changed, %d insertions(+), '
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  2841
                        '%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
  2842
                      % (len(stats), totaladds, totalremoves))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2843
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2844
    return ''.join(output)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2845
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2846
def diffstatui(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2847
    '''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
  2848
    ui.write()
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2849
    '''
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2850
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2851
    for line in diffstat(*args, **kw).splitlines():
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2852
        if line and line[-1] in '+-':
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2853
            name, graph = line.rsplit(' ', 1)
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2854
            yield (name + ' ', '')
33096
d9962854a4a2 py3: add b'' to make the regex pattern bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32990
diff changeset
  2855
            m = re.search(br'\++', graph)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2856
            if m:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2857
                yield (m.group(0), 'diffstat.inserted')
33096
d9962854a4a2 py3: add b'' to make the regex pattern bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32990
diff changeset
  2858
            m = re.search(br'-+', graph)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2859
            if m:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2860
                yield (m.group(0), 'diffstat.deleted')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2861
        else:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2862
            yield (line, '')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2863
        yield ('\n', '')