mercurial/patch.py
author Taapas Agrawal <taapas2897@gmail.com>
Sun, 09 Jun 2019 00:43:36 +0530
changeset 42530 dc3fdd1b5af4
parent 42071 db72f9f6580e
child 42566 f802a75da585
permissions -rw-r--r--
state: created new class statecheck to handle unfinishedstates For the purpose of handling states for various multistep operations like `hg graft`, `hg histedit`, `hg bisect` et al a new class called statecheck is created .This will help in having a unified approach towards these commands and handle them with ease. The class takes in 4 basic arguments which include the name of the command, the name of the state file associated with it , clearable flag , allowcommit flag. This also also adds the support of`checkunfinished()` and `clearunfinished()` to the class. Tests remain unchanged. Differential Revision: https://phab.mercurial-scm.org/D6501
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
42071
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1068
def filterpatch(ui, headers, match, 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)
42071
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1185
        files = h.files()
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1186
        msg = (_('examine changes to %s?') %
42071
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1187
               _(' and ').join("'%s'" % f for f in files))
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1188
        if all(match.exact(f) for f in files):
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1189
            r, skipall, np = True, None, None
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1190
        else:
db72f9f6580e interactive: do not prompt about files given in command line
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 41987
diff changeset
  1191
            r, skipfile, skipall, np = prompt(skipfile, skipall, msg, None)
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1192
        if not r:
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
        applied[h.filename()] = [h]
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1195
        if h.allhunks():
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1196
            applied[h.filename()] += h.hunks
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1197
            continue
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1198
        for i, chunk in enumerate(h.hunks):
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1199
            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
  1200
                chunk.pretty(ui)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1201
            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
  1202
                msg = messages['single'][operation] % chunk.filename()
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1203
            else:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1204
                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
  1205
                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
  1206
                                                         chunk.filename())
24269
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1207
            r, skipfile, skipall, newpatches = prompt(skipfile,
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1208
                    skipall, msg, chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1209
            if r:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1210
                if fixoffset:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1211
                    chunk = copy.copy(chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1212
                    chunk.toline += fixoffset
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1213
                applied[chunk.filename()].append(chunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1214
            elif newpatches is not None:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1215
                for newpatch in newpatches:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1216
                    for newhunk in newpatch.hunks:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1217
                        if fixoffset:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1218
                            newhunk.toline += fixoffset
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1219
                        applied[newhunk.filename()].append(newhunk)
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1220
            else:
9a745ced79a9 record: move filterpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24268
diff changeset
  1221
                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
  1222
    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
  1223
               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
  1224
class hunk(object):
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1225
    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
  1226
        self.number = num
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1227
        self.desc = desc
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1228
        self.hunk = [desc]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1229
        self.a = []
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1230
        self.b = []
9682
bd70f645cfb0 patch: initialize all attributes of the hunk class
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9681
diff changeset
  1231
        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
  1232
        self.startb = self.lenb = None
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1233
        if lr is not None:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1234
            if context:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1235
                self.read_context_hunk(lr)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1236
            else:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1237
                self.read_unified_hunk(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1238
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1239
    def getnormalized(self):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1240
        """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
  1241
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1242
        def normalize(lines):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1243
            nlines = []
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1244
            for line in lines:
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1245
                if line.endswith('\r\n'):
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1246
                    line = line[:-2] + '\n'
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1247
                nlines.append(line)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1248
            return nlines
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1249
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1250
        # Dummy object, it is rebuilt manually
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1251
        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
  1252
        nh.number = self.number
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1253
        nh.desc = self.desc
10524
3212afb33116 patch: fix patching with fuzz and eol normalization
Patrick Mezard <pmezard@gmail.com>
parents: 10518
diff changeset
  1254
        nh.hunk = self.hunk
10127
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1255
        nh.a = normalize(self.a)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1256
        nh.b = normalize(self.b)
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1257
        nh.starta = self.starta
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1258
        nh.startb = self.startb
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1259
        nh.lena = self.lena
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1260
        nh.lenb = self.lenb
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1261
        return nh
d8214e944b84 patch: fix eolmode=auto with new files
Patrick Mezard <pmezard@gmail.com>
parents: 10102
diff changeset
  1262
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1263
    def read_unified_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1264
        m = unidesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1265
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1266
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1267
        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
  1268
        if self.lena is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1269
            self.lena = 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.lena = int(self.lena)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1272
        if self.lenb is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1273
            self.lenb = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1274
        else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1275
            self.lenb = int(self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1276
        self.starta = int(self.starta)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1277
        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
  1278
        try:
37803
72f6498c040b diffhelper: rename module to avoid conflicts with ancient C module (issue5846)
Yuya Nishihara <yuya@tcha.org>
parents: 37764
diff changeset
  1279
            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
  1280
                                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
  1281
        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
  1282
            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
  1283
        # 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
  1284
        # 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
  1285
        while len(self.hunk[-1]) == 0:
6948
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1286
            del self.hunk[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1287
            del self.a[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1288
            del self.b[-1]
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1289
            self.lena -= 1
359e93ceee3a fix double indentation and trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
  1290
            self.lenb -= 1
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1291
        self._fixnewline(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1292
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1293
    def read_context_hunk(self, lr):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1294
        self.desc = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1295
        m = contextdesc.match(self.desc)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1296
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1297
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1298
        self.starta, aend = m.groups()
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1299
        self.starta = int(self.starta)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1300
        if aend is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1301
            aend = self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1302
        self.lena = int(aend) - self.starta
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1303
        if self.starta:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1304
            self.lena += 1
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1305
        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
  1306
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1307
            if l.startswith('---'):
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1308
                # lines addition, old block is empty
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1309
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1310
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1311
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1312
            if l.startswith('- ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1313
                u = '-' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1314
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1315
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1316
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1317
                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
  1318
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1319
            self.a.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1320
            self.hunk.append(u)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1321
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1322
        l = lr.readline()
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
  1323
        if l.startswith(br'\ '):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1324
            s = self.a[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1325
            self.a[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1326
            self.hunk[-1] = s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1327
            l = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1328
        m = contextdesc.match(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1329
        if not m:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1330
            raise PatchError(_("bad hunk #%d") % self.number)
15510
5414b56cfad6 patch: simplify hunk extents parsing
Patrick Mezard <pmezard@gmail.com>
parents: 15462
diff changeset
  1331
        self.startb, bend = m.groups()
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1332
        self.startb = int(self.startb)
8527
f9a80054dd3c use 'x is None' instead of 'x == None'
Martin Geisler <mg@lazybytes.net>
parents: 8526
diff changeset
  1333
        if bend is None:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1334
            bend = self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1335
        self.lenb = int(bend) - self.startb
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1336
        if self.startb:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1337
            self.lenb += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1338
        hunki = 1
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1339
        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
  1340
            l = lr.readline()
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
  1341
            if l.startswith(br'\ '):
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1342
                # 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
  1343
                # 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
  1344
                # 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
  1345
                s = self.b[-1][:-1]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1346
                self.b[-1] = s
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1347
                self.hunk[hunki - 1] = s
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1348
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1349
            if not l:
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1350
                # 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
  1351
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1352
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1353
            s = l[2:]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1354
            if l.startswith('+ ') or l.startswith('! '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1355
                u = '+' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1356
            elif l.startswith('  '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1357
                u = ' ' + s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1358
            elif len(self.b) == 0:
12825
61f48581d8ef Test applying context diffs
Patrick Mezard <pmezard@gmail.com>
parents: 12728
diff changeset
  1359
                # line deletions, new block is empty
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1360
                lr.push(l)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1361
                break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1362
            else:
4898
bc905a6c0e76 patch.py: fix some incorrect uses of _() for i18n
Bryan O'Sullivan <bos@serpentine.com>
parents: 4897
diff changeset
  1363
                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
  1364
                                 (self.number, x))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1365
            self.b.append(s)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1366
            while True:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1367
                if hunki >= len(self.hunk):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1368
                    h = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1369
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1370
                    h = self.hunk[hunki]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1371
                hunki += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1372
                if h == u:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1373
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1374
                elif h.startswith('-'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1375
                    continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1376
                else:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1377
                    self.hunk.insert(hunki - 1, u)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1378
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1379
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1380
        if not self.a:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1381
            # 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
  1382
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1383
                if x.startswith('-') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1384
                    self.a.append(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1385
        if not self.b:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1386
            # 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
  1387
            for x in self.hunk:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1388
                if x.startswith('+') or x.startswith(' '):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1389
                    self.b.append(x[1:])
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1390
        # @@ -start,len +start,len @@
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1391
        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
  1392
                                             self.startb, self.lenb)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1393
        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
  1394
        self._fixnewline(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1395
13699
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1396
    def _fixnewline(self, lr):
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1397
        l = lr.readline()
41534
47c92f8ed128 patch: properly escape \ in string literals
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41532
diff changeset
  1398
        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
  1399
            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
  1400
        else:
d3c0e0033f13 patch: fix hunk newlines when parsing hunks, not in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13395
diff changeset
  1401
            lr.push(l)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1402
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1403
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1404
        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
  1405
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
  1406
    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
  1407
        # 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
  1408
        # 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
  1409
        # 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
  1410
        fuzz = min(fuzz, len(old))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1411
        if fuzz:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1412
            top = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1413
            bot = 0
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1414
            hlen = len(self.hunk)
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1415
            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
  1416
                # 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
  1417
                if self.hunk[x + 1].startswith(' '):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1418
                    top += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1419
                else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1420
                    break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1421
            if not toponly:
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38773
diff changeset
  1422
                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
  1423
                    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
  1424
                        bot += 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1425
                    else:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1426
                        break
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1427
16124
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1428
            bot = min(fuzz, bot)
0e0060bf2f44 patch: fuzz more aggressively to match patch(1) behaviour
Patrick Mezard <patrick@mezard.eu>
parents: 16123
diff changeset
  1429
            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
  1430
            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
  1431
        return old, new, 0
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1432
16121
ccba74472af2 patch: fuzz old and new lines at the same time
Patrick Mezard <patrick@mezard.eu>
parents: 16112
diff changeset
  1433
    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
  1434
        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
  1435
        oldstart = self.starta + top
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1436
        newstart = self.startb + top
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1437
        # 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
  1438
        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
  1439
            oldstart -= 1
16650
fcb97d9a26cd patch: fix segfault against unified diffs which start line is zero
Yuya Nishihara <yuya@tcha.org>
parents: 16524
diff changeset
  1440
        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
  1441
            newstart -= 1
9ef3a4a2c6c0 patch: make hunk.fuzzit() compute the fuzzed start locations
Patrick Mezard <patrick@mezard.eu>
parents: 16121
diff changeset
  1442
        return old, oldstart, new, newstart
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1443
14764
a7d5816087a9 classes: fix class style problems found by b071cd58af50
Thomas Arendsen Hein <thomas@intevation.de>
parents: 14695
diff changeset
  1444
class binhunk(object):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1445
    'A binary patch file.'
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1446
    def __init__(self, lr, fname):
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1447
        self.text = None
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1448
        self.delta = False
9585
ea1935e2020a patch: handle symlinks without symlinkhunk
Patrick Mezard <pmezard@gmail.com>
parents: 9573
diff changeset
  1449
        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
  1450
        self._fname = fname
14384
9d59c596eb9e patch: construct and parse binary hunks at the same time
Patrick Mezard <pmezard@gmail.com>
parents: 14383
diff changeset
  1451
        self._read(lr)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1452
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1453
    def complete(self):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1454
        return self.text is not None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1455
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1456
    def new(self, lines):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1457
        if self.delta:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1458
            return [applybindelta(self.text, ''.join(lines))]
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1459
        return [self.text]
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1460
14384
9d59c596eb9e patch: construct and parse binary hunks at the same time
Patrick Mezard <pmezard@gmail.com>
parents: 14383
diff changeset
  1461
    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
  1462
        def getline(lr, hunk):
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1463
            l = lr.readline()
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1464
            hunk.append(l)
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1465
            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
  1466
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1467
        while True:
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1468
            line = getline(lr, self.hunk)
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1469
            if not line:
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1470
                raise PatchError(_('could not extract "%s" binary data')
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1471
                                 % self._fname)
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1472
            if line.startswith('literal '):
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1473
                size = int(line[8:].rstrip())
16567
aef3d0d4631c patch: clarify binary hunk parsing loop
Patrick Mezard <patrick@mezard.eu>
parents: 16524
diff changeset
  1474
                break
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1475
            if line.startswith('delta '):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1476
                size = int(line[6:].rstrip())
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1477
                self.delta = True
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1478
                break
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1479
        dec = []
16524
ed6a74312176 patch: be more tolerant with EOLs in binary diffs (issue2870)
Patrick Mezard <patrick@mezard.eu>
parents: 16523
diff changeset
  1480
        line = getline(lr, self.hunk)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1481
        while len(line) > 1:
36192
eb91ffdaaece py3: slice over bytes to prevent getting ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 36046
diff changeset
  1482
            l = line[0:1]
3374
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
  1483
            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
  1484
                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
  1485
            else:
fd43ff3b4442 Use line length field when extracting git binary patches
Brendan Cully <brendan@kublai.com>
parents: 3367
diff changeset
  1486
                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
  1487
            try:
32201
4462a981e8df base85: proxy through util module
Yuya Nishihara <yuya@tcha.org>
parents: 32191
diff changeset
  1488
                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
  1489
            except ValueError as e:
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1490
                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
  1491
                                 % (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
  1492
            line = getline(lr, self.hunk)
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1493
        text = zlib.decompress(''.join(dec))
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1494
        if len(text) != size:
16523
727068417b95 patch: include file name in binary patch error messages
Patrick Mezard <patrick@mezard.eu>
parents: 16522
diff changeset
  1495
            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
  1496
                             % (self._fname, len(text), size))
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1497
        self.text = text
3367
7f486971d263 Add git-1.4 binary patch support
Brendan Cully <brendan@kublai.com>
parents: 3329
diff changeset
  1498
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1499
def parsefilename(str):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1500
    # --- filename \t|space stuff
5851
03f550f9b554 patch: remove CRLF when parsing file names
Patrick Mezard <pmezard@gmail.com>
parents: 5669
diff changeset
  1501
    s = str[4:].rstrip('\r\n')
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1502
    i = s.find('\t')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1503
    if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1504
        i = s.find(' ')
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1505
        if i < 0:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1506
            return s
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1507
    return s[:i]
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1508
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1509
def reversehunks(hunks):
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1510
    '''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
  1511
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1512
    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
  1513
    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
  1514
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1515
    >>> 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
  1516
    ... --- a/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1517
    ... +++ b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1518
    ... @@ -1,7 +1,7 @@
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1519
    ... +firstline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1520
    ...  c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1521
    ...  1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1522
    ...  2
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1523
    ... + 3
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1524
    ... -4
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1525
    ...  5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1526
    ...  d
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1527
    ... +lastline"""
34253
5ce32fe7df34 py3: fix doctests in patch.py to be compatible with Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34252
diff changeset
  1528
    >>> hunks = parsepatch([rawpatch])
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1529
    >>> hunkscomingfromfilterpatch = []
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1530
    >>> for h in hunks:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1531
    ...     hunkscomingfromfilterpatch.append(h)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1532
    ...     hunkscomingfromfilterpatch.extend(h.hunks)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1533
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1534
    >>> reversedhunks = reversehunks(hunkscomingfromfilterpatch)
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1535
    >>> from . import util
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1536
    >>> fp = util.stringio()
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1537
    >>> for c in reversedhunks:
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1538
    ...      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
  1539
    >>> 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
  1540
    >>> 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
  1541
    >>> print(pycompat.sysstr(reversedpatch))
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1542
    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
  1543
    --- a/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1544
    +++ b/folder1/g
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1545
    @@ -1,4 +1,3 @@
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1546
    -firstline
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
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1550
    @@ -2,6 +1,6 @@
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1551
     c
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1552
     1
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1553
     2
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1554
    - 3
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1555
    +4
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1556
     5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1557
     d
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1558
    @@ -6,3 +5,2 @@
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1559
     5
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1560
     d
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1561
    -lastline
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1562
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1563
    '''
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1564
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1565
    newhunks = []
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1566
    for c in hunks:
32979
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1567
        if util.safehasattr(c, 'reversehunk'):
66117dae87f9 patch: rewrite reversehunks (issue5337)
Jun Wu <quark@fb.com>
parents: 32370
diff changeset
  1568
            c = c.reversehunk()
25424
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1569
        newhunks.append(c)
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1570
    return newhunks
69609f43c752 revert: add an experimental config to use inverted selection
Laurent Charignon <lcharignon@fb.com>
parents: 25359
diff changeset
  1571
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1572
def parsepatch(originalchunks, maxcontext=None):
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1573
    """patch -> [] of headers -> [] of hunks
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1574
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1575
    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
  1576
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34067
diff changeset
  1577
    >>> 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
  1578
    ... --- a/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1579
    ... +++ b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1580
    ... @@ -1,8 +1,10 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1581
    ...  1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1582
    ...  2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1583
    ... -3
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1584
    ...  4
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1585
    ...  5
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1586
    ...  6
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1587
    ... +6.1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1588
    ... +6.2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1589
    ...  7
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1590
    ...  8
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1591
    ... +9'''
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1592
    >>> out = util.stringio()
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1593
    >>> headers = parsepatch([rawpatch], maxcontext=1)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1594
    >>> for header in headers:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1595
    ...     header.write(out)
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1596
    ...     for hunk in header.hunks:
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1597
    ...         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
  1598
    >>> print(pycompat.sysstr(out.getvalue()))
33270
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1599
    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
  1600
    --- a/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1601
    +++ b/folder1/g
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1602
    @@ -2,3 +2,2 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1603
     2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1604
    -3
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1605
     4
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1606
    @@ -6,2 +5,4 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1607
     6
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1608
    +6.1
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1609
    +6.2
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1610
     7
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1611
    @@ -8,1 +9,2 @@
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1612
     8
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1613
    +9
f7b635716ef2 patch: make parsepatch optionally trim context lines
Jun Wu <quark@fb.com>
parents: 33229
diff changeset
  1614
    """
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1615
    class parser(object):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1616
        """patch parsing state machine"""
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1617
        def __init__(self):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1618
            self.fromline = 0
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1619
            self.toline = 0
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1620
            self.proc = ''
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1621
            self.header = None
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1622
            self.context = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1623
            self.before = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1624
            self.hunk = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1625
            self.headers = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1626
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1627
        def 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
  1628
            self.addcontext([])
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1629
            fromstart, fromend, tostart, toend, proc = limits
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1630
            self.fromline = int(fromstart)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1631
            self.toline = int(tostart)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1632
            self.proc = proc
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1633
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1634
        def addcontext(self, context):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1635
            if self.hunk:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1636
                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
  1637
                        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
  1638
                self.header.hunks.append(h)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1639
                self.fromline += len(self.before) + h.removed
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1640
                self.toline += len(self.before) + h.added
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1641
                self.before = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1642
                self.hunk = []
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1643
            self.context = context
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1644
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1645
        def addhunk(self, hunk):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1646
            if self.context:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1647
                self.before = self.context
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1648
                self.context = []
41454
d1d3094b54f9 patch: handle 0 context lines (diff.unified=0) when parsing patches
Kyle Lippincott <spectral@google.com>
parents: 41401
diff changeset
  1649
            if self.hunk:
d1d3094b54f9 patch: handle 0 context lines (diff.unified=0) when parsing patches
Kyle Lippincott <spectral@google.com>
parents: 41401
diff changeset
  1650
                self.addcontext([])
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1651
            self.hunk = hunk
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1652
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1653
        def newfile(self, hdr):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1654
            self.addcontext([])
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1655
            h = header(hdr)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1656
            self.headers.append(h)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1657
            self.header = h
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1658
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1659
        def addother(self, line):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1660
            pass # 'other' lines are ignored
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
        def finished(self):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1663
            self.addcontext([])
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1664
            return self.headers
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1665
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1666
        transitions = {
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1667
            'file': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1668
                     'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1669
                     'hunk': addhunk,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1670
                     'range': addrange},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1671
            'context': {'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1672
                        'hunk': addhunk,
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
                        'other': addother},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1675
            'hunk': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1676
                     'file': newfile,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1677
                     'range': addrange},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1678
            'range': {'context': addcontext,
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1679
                      'hunk': addhunk},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1680
            'other': {'other': addother},
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1681
            }
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1682
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1683
    p = parser()
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1684
    fp = stringio()
24341
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1685
    fp.write(''.join(originalchunks))
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1686
    fp.seek(0)
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1687
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1688
    state = 'context'
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1689
    for newstate, data in scanpatch(fp):
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1690
        try:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1691
            p.transitions[state][newstate](p, data)
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1692
        except KeyError:
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1693
            raise PatchError('unhandled transition: %s -> %s' %
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1694
                                   (state, newstate))
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1695
        state = newstate
24341
616c01b69898 record: change interface of the filtering function
Laurent Charignon <lcharignon@fb.com>
parents: 24306
diff changeset
  1696
    del fp
24265
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1697
    return p.finished()
dc655360bccb record: move parsepatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24264
diff changeset
  1698
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1699
def pathtransform(path, strip, prefix):
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1700
    '''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
  1701
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1702
    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
  1703
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1704
    Returns (stripped components, path in repository).
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1705
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', 0, 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'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1709
    ('', '   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'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1711
    ('a/b/', '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', 0, b'd/e/')
24385
885a573fa619 patch.pathtransform: prepend prefix even if strip is 0
Siddharth Agarwal <sid0@fb.com>
parents: 24371
diff changeset
  1713
    ('', '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
  1714
    >>> 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
  1715
    ('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
  1716
    >>> pathtransform(b'a/b/c', 3, b'')
24243
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1717
    Traceback (most recent call last):
daee2039dd11 patch.pathtransform: add doctests
Siddharth Agarwal <sid0@fb.com>
parents: 24242
diff changeset
  1718
    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
  1719
    '''
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1720
    pathlen = len(path)
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1721
    i = 0
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1722
    if strip == 0:
24385
885a573fa619 patch.pathtransform: prepend prefix even if strip is 0
Siddharth Agarwal <sid0@fb.com>
parents: 24371
diff changeset
  1723
        return '', prefix + path.rstrip()
11022
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1724
    count = strip
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1725
    while count > 0:
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1726
        i = path.find('/', i)
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1727
        if i == -1:
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1728
            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
  1729
                             (count, strip, path))
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1730
        i += 1
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1731
        # 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
  1732
        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
  1733
            i += 1
0429d0d49f92 patch: strip paths in leaked git patchmeta objects
Mads Kiilerich <mads@kiilerich.com>
parents: 11021
diff changeset
  1734
        count -= 1
24244
5918bb365c72 patch.pathtransform: add a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24243
diff changeset
  1735
    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
  1736
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1737
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
  1738
    nulla = afile_orig == "/dev/null"
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1739
    nullb = bfile_orig == "/dev/null"
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1740
    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
  1741
    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
  1742
    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
  1743
    gooda = not nulla and backend.exists(afile)
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  1744
    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
  1745
    if afile == bfile:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1746
        goodb = gooda
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1747
    else:
14351
d54f9bbcc640 patch: add lexists() to backends, use it in selectfile()
Patrick Mezard <pmezard@gmail.com>
parents: 14350
diff changeset
  1748
        goodb = not nullb and backend.exists(bfile)
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1749
    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
  1750
11820
75de514a50f3 patch: fix typo in comment
Martin Geisler <mg@aragost.com>
parents: 11645
diff changeset
  1751
    # 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
  1752
    # 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
  1753
    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
  1754
    bbasedir = bfile[:bfile.rfind('/') + 1]
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1755
    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
  1756
        and hunk.starta == 0 and hunk.lena == 0):
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1757
        create = True
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1758
        missing = False
9328
648d6a1a1cf2 patch: create file even if source is not /dev/null
Brendan Cully <brendan@kublai.com>
parents: 9248
diff changeset
  1759
6295
bace1990ab12 patch: fix corner case with update + copy patch handling (issue 937)
Patrick Mezard <pmezard@gmail.com>
parents: 6280
diff changeset
  1760
    # 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
  1761
    # 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
  1762
    # 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
  1763
    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
  1764
    fname = None
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1765
    if not missing:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1766
        if gooda and goodb:
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1767
            if isbackup:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1768
                fname = afile
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1769
            else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1770
                fname = bfile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1771
        elif gooda:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1772
            fname = afile
5760
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5706
diff changeset
  1773
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1774
    if not fname:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1775
        if not nullb:
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1776
            if isbackup:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1777
                fname = afile
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1778
            else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  1779
                fname = bfile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1780
        elif not nulla:
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1781
            fname = afile
5652
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1782
        else:
e90e72c6b4c7 patch: write rej files for missing targets (issue 853)
Patrick Mezard <pmezard@gmail.com>
parents: 5651
diff changeset
  1783
            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
  1784
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1785
    gp = patchmeta(fname)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1786
    if create:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1787
        gp.op = 'ADD'
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1788
    elif remove:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1789
        gp.op = 'DELETE'
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1790
    return gp
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1791
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1792
def scanpatch(fp):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1793
    """like patch.iterhunks, but yield different events
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1794
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1795
    - ('file',    [header_lines + fromfile + tofile])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1796
    - ('context', [context_lines])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1797
    - ('hunk',    [hunk_lines])
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1798
    - ('range',   (-start,len, +start,len, proc))
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1799
    """
34066
871a58b5f428 py3: fix type of regex literals in patch.py
Yuya Nishihara <yuya@tcha.org>
parents: 34042
diff changeset
  1800
    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
  1801
    lr = linereader(fp)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1802
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1803
    def scanwhile(first, p):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1804
        """scan lr while predicate holds"""
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1805
        lines = [first]
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1806
        for line in iter(lr.readline, ''):
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1807
            if p(line):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1808
                lines.append(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1809
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1810
                lr.push(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1811
                break
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1812
        return lines
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1813
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1814
    for line in iter(lr.readline, ''):
24264
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1815
        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
  1816
            def notheader(line):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1817
                s = line.split(None, 1)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1818
                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
  1819
            header = scanwhile(line, notheader)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1820
            fromfile = lr.readline()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1821
            if fromfile.startswith('---'):
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1822
                tofile = lr.readline()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1823
                header += [fromfile, tofile]
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1824
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1825
                lr.push(fromfile)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1826
            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
  1827
        elif line.startswith(' '):
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1828
            cs = (' ', '\\')
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1829
            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
  1830
        elif line.startswith(('-', '+')):
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1831
            cs = ('-', '+', '\\')
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  1832
            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
  1833
        else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1834
            m = lines_re.match(line)
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1835
            if m:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1836
                yield 'range', m.groups()
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1837
            else:
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1838
                yield 'other', line
c4205452f1b7 record: move scanpatch from record to patch
Laurent Charignon <lcharignon@fb.com>
parents: 24263
diff changeset
  1839
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1840
def scangitpatch(lr, firstline):
7186
f77c8d8331ca clean up trailing spaces, leading spaces in C
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7153
diff changeset
  1841
    """
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1842
    Git patches can emit:
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1843
    - rename a to b
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1844
    - change b
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1845
    - copy a to c
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1846
    - change c
7186
f77c8d8331ca clean up trailing spaces, leading spaces in C
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7153
diff changeset
  1847
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1848
    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
  1849
    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
  1850
    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
  1851
    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
  1852
    perform the copies ahead of time.
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1853
    """
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1854
    pos = 0
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1855
    try:
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1856
        pos = lr.fp.tell()
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1857
        fp = lr.fp
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1858
    except IOError:
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
  1859
        fp = stringio(lr.fp.read())
14418
0174d1f79280 patch: remove EOL support from linereader class
Patrick Mezard <pmezard@gmail.com>
parents: 14402
diff changeset
  1860
    gitlr = linereader(fp)
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1861
    gitlr.push(firstline)
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
  1862
    gitpatches = readgitpatch(gitlr)
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1863
    fp.seek(pos)
12669
b0fa39c68370 patch: remove unused flags from readgitpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 12645
diff changeset
  1864
    return gitpatches
7152
f0055cec8446 patch: pass linereader to scangitpatch(), extract from iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 7151
diff changeset
  1865
14240
28762bb767dc patch: remove unused ui arg to iterhunks
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
  1866
def iterhunks(fp):
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1867
    """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
  1868
    - ("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
  1869
    - ("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
  1870
    "file" event.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1871
    - ("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
  1872
    maps filenames to gitpatch records. Unique event.
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1873
    """
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1874
    afile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1875
    bfile = ""
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1876
    state = None
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1877
    hunknum = 0
14017
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1878
    emitfile = newfile = False
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1879
    gitpatches = None
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1880
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1881
    # our states
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1882
    BFILE = 1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1883
    context = None
10128
ea7c392f2b08 patch: drop eol normalization fast-path for 'lf' and 'crlf'
Patrick Mezard <pmezard@gmail.com>
parents: 10127
diff changeset
  1884
    lr = linereader(fp)
2861
0f08f2c042ec Move patch-related code into its own module.
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
  1885
29726
160c829dd5d0 patch: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29422
diff changeset
  1886
    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
  1887
        if state == BFILE and (
36646
463df2986814 py3: fix slicing of bytes in patch.iterhunks()
Yuya Nishihara <yuya@tcha.org>
parents: 36607
diff changeset
  1888
            (not context and x.startswith('@'))
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1889
            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
  1890
            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
  1891
            gp = None
14534
ecc79816d31e patch: fix patchmeta/hunk synchronization in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 14533
diff changeset
  1892
            if (gitpatches and
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1893
                gitpatches[-1].ispatching(afile, bfile)):
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1894
                gp = gitpatches.pop()
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1895
            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
  1896
                h = binhunk(lr, gp.path)
14383
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1897
            else:
1bd52cb12a55 patch: refactor iterhunks() regular and binary files emission
Patrick Mezard <pmezard@gmail.com>
parents: 14382
diff changeset
  1898
                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
  1899
                    context = True
14451
c78d41db6f88 patch: refactor file creation/removal detection
Patrick Mezard <pmezard@gmail.com>
parents: 14437
diff changeset
  1900
                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
  1901
            hunknum += 1
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1902
            if emitfile:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1903
                emitfile = False
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1904
                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
  1905
            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
  1906
        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
  1907
            m = gitre.match(x.rstrip(' \r\n'))
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1908
            if not m:
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1909
                continue
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1910
            if gitpatches is None:
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1911
                # scan whole input for git metadata
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1912
                gitpatches = scangitpatch(lr, x)
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1913
                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
  1914
                              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
  1915
                gitpatches.reverse()
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1916
            afile = 'a/' + m.group(1)
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1917
            bfile = 'b/' + m.group(2)
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1918
            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
  1919
                gp = gitpatches.pop()
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1920
                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
  1921
            if not gitpatches:
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1922
                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
  1923
                                 % afile[2:])
14387
e1b4a7a7263a patch: reindent code
Patrick Mezard <pmezard@gmail.com>
parents: 14386
diff changeset
  1924
            newfile = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1925
        elif x.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1926
            # check for a unified diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1927
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1928
            if not l2.startswith('+++'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1929
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1930
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1931
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1932
            context = False
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1933
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1934
            bfile = parsefilename(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1935
        elif x.startswith('***'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1936
            # check for a context diff
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1937
            l2 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1938
            if not l2.startswith('---'):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1939
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1940
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1941
            l3 = lr.readline()
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1942
            lr.push(l3)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1943
            if not l3.startswith("***************"):
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1944
                lr.push(l2)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1945
                continue
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1946
            newfile = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1947
            context = True
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1948
            afile = parsefilename(x)
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1949
            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
  1950
14017
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1951
        if newfile:
19a7b48446e3 patch: remove redundant variable in iterhunks()
Patrick Mezard <pmezard@gmail.com>
parents: 13971
diff changeset
  1952
            newfile = False
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1953
            emitfile = True
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1954
            state = BFILE
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  1955
            hunknum = 0
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  1956
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  1957
    while gitpatches:
16506
fc4e0fecf403 patch: fix patch hunk/metdata synchronization (issue3384)
Patrick Mezard <patrick@mezard.eu>
parents: 16475
diff changeset
  1958
        gp = gitpatches.pop()
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  1959
        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
  1960
20137
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1961
def applybindelta(binchunk, data):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1962
    """Apply a binary delta hunk
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1963
    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
  1964
    """
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1965
    def deltahead(binchunk):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1966
        i = 0
38085
e887381e2976 py3: bytestr() bytes to get bytechar while iterating on it
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38084
diff changeset
  1967
        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
  1968
            i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1969
            if not (ord(c) & 0x80):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1970
                return i
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1971
        return i
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1972
    out = ""
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1973
    s = deltahead(binchunk)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1974
    binchunk = binchunk[s:]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1975
    s = deltahead(binchunk)
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1976
    binchunk = binchunk[s:]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1977
    i = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1978
    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
  1979
        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
  1980
        i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1981
        if (cmd & 0x80):
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1982
            offset = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1983
            size = 0
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1984
            if (cmd & 0x01):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1985
                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
  1986
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1987
            if (cmd & 0x02):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1988
                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
  1989
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1990
            if (cmd & 0x04):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1991
                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
  1992
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1993
            if (cmd & 0x08):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1994
                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
  1995
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1996
            if (cmd & 0x10):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  1997
                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
  1998
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  1999
            if (cmd & 0x20):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  2000
                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
  2001
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2002
            if (cmd & 0x40):
38084
86e0a4bede5d py3: slice over bytes to prevent getting the ascii values
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38052
diff changeset
  2003
                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
  2004
                i += 1
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2005
            if size == 0:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2006
                size = 0x10000
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2007
            offset_end = offset + size
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2008
            out += data[offset:offset_end]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2009
        elif cmd != 0:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2010
            offset_end = i + cmd
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2011
            out += binchunk[i:offset_end]
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2012
            i += cmd
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2013
        else:
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2014
            raise PatchError(_('unexpected delta opcode 0'))
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2015
    return out
9f1d4323c749 patch: add support for git delta hunks
Nicolas Vigier <boklm@mars-attacks.org>
parents: 20035
diff changeset
  2016
24247
6e19516094a3 patch.applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24246
diff changeset
  2017
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
  2018
    """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
  2019
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2020
    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
  2021
    there was any fuzz.
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2022
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  2023
    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
  2024
    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
  2025
    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
  2026
    """
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2027
    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
  2028
                      prefix=prefix, eolmode=eolmode)
10966
91c58cf54eee patch: refactor applydiff to allow for mempatching
Augie Fackler <durin42@gmail.com>
parents: 10965
diff changeset
  2029
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2030
def _canonprefix(repo, prefix):
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2031
    if prefix:
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2032
        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
  2033
        if prefix != '':
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2034
            prefix += '/'
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2035
    return prefix
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2036
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2037
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
  2038
               eolmode='strict'):
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2039
    prefix = _canonprefix(backend.repo, prefix)
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2040
    def pstrip(p):
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2041
        return pathtransform(p, strip - 1, prefix)[1]
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2042
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2043
    rejects = 0
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2044
    err = 0
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2045
    current_file = None
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2046
14240
28762bb767dc patch: remove unused ui arg to iterhunks
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
  2047
    for state, values in iterhunks(fp):
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2048
        if state == 'hunk':
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2049
            if not current_file:
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2050
                continue
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2051
            ret = current_file.apply(values)
14565
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2052
            if ret > 0:
3cacc232f27f patch: stop updating changed files set in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14564
diff changeset
  2053
                err = 1
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2054
        elif state == 'file':
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2055
            if current_file:
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2056
                rejects += current_file.close()
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2057
                current_file = None
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2058
            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
  2059
            if gp:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2060
                gp.path = pstrip(gp.path)
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2061
                if gp.oldpath:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2062
                    gp.oldpath = pstrip(gp.oldpath)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2063
            else:
24246
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2064
                gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
394a91cb3d4a patch._applydiff: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24245
diff changeset
  2065
                                   prefix)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2066
            if gp.op == 'RENAME':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2067
                backend.unlink(gp.oldpath)
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2068
            if not first_hunk:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2069
                if gp.op == 'DELETE':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2070
                    backend.unlink(gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2071
                    continue
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2072
                data, mode = None, None
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2073
                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
  2074
                    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
  2075
                    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
  2076
                        # 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
  2077
                        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
  2078
                                           % gp.oldpath)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2079
                if gp.mode:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2080
                    mode = gp.mode
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2081
                    if gp.op == 'ADD':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2082
                        # 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
  2083
                        # must be created
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2084
                        data = ''
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2085
                if data or mode:
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2086
                    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
  2087
                        and backend.exists(gp.path)):
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2088
                        raise PatchError(_("cannot create %s: destination "
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2089
                                           "already exists") % gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2090
                    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
  2091
                continue
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2092
            try:
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2093
                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
  2094
                                       eolmode=eolmode)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25658
diff changeset
  2095
            except PatchError as inst:
14218
202ff575d49b patch: fix clash between local variable and exception instance
Martin Geisler <mg@aragost.com>
parents: 14217
diff changeset
  2096
                ui.warn(str(inst) + '\n')
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2097
                current_file = None
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2098
                rejects += 1
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2099
                continue
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2100
        elif state == 'git':
11021
c47a1cfad572 patch: minor cleanup of _applydiff
Mads Kiilerich <mads@kiilerich.com>
parents: 11020
diff changeset
  2101
            for gp in values:
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2102
                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
  2103
                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
  2104
                if data is None:
16813
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2105
                    # 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
  2106
                    # 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
  2107
                    # 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
  2108
                    # process.
22296
650b5b6e75ed convert: use None value for missing files instead of overloading IOError
Mads Kiilerich <madski@unity3d.com>
parents: 21833
diff changeset
  2109
                    pass
16813
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2110
                else:
6d42c797ca6e patch: keep patching after missing copy source (issue3480)
Patrick Mezard <patrick@mezard.eu>
parents: 16650
diff changeset
  2111
                    store.setfile(path, data, mode)
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2112
        else:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26560
diff changeset
  2113
            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
  2114
13701
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2115
    if current_file:
bc38ff7cb919 patch: move closefile() into patchfile.close()
Patrick Mezard <pmezard@gmail.com>
parents: 13700
diff changeset
  2116
        rejects += current_file.close()
5650
5d3e2f918d65 patch: move diff parsing in iterhunks generator
Patrick Mezard <pmezard@gmail.com>
parents: 5649
diff changeset
  2117
4897
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2118
    if rejects:
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2119
        return -1
4574925db5c0 Add Chris Mason's mpatch library.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4778
diff changeset
  2120
    return err
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2121
14382
2d16f15da7bd patch: remove patch.patch() cwd argument
Patrick Mezard <pmezard@gmail.com>
parents: 14381
diff changeset
  2122
def _externalpatch(ui, repo, patcher, patchname, strip, files,
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2123
                   similarity):
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2124
    """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
  2125
    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
  2126
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2127
    fuzz = False
12673
9ad16d1bce4b patch: simplify externalpatch() arguments
Patrick Mezard <pmezard@gmail.com>
parents: 12671
diff changeset
  2128
    args = []
14382
2d16f15da7bd patch: remove patch.patch() cwd argument
Patrick Mezard <pmezard@gmail.com>
parents: 14381
diff changeset
  2129
    cwd = repo.root
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2130
    if cwd:
37120
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
  2131
        args.append('-d %s' % procutil.shellquote(cwd))
37458
00e4bd97b095 procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents: 37456
diff changeset
  2132
    cmd = ('%s %s -p%d < %s'
00e4bd97b095 procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents: 37456
diff changeset
  2133
           % (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
  2134
    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
  2135
    fp = procutil.popen(cmd, 'rb')
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2136
    try:
30397
564b33acc21f patch: migrate to util.iterfile
Jun Wu <quark@fb.com>
parents: 30078
diff changeset
  2137
        for line in util.iterfile(fp):
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2138
            line = line.rstrip()
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2139
            ui.note(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2140
            if line.startswith('patching file '):
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2141
                pf = util.parsepatchoutput(line)
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2142
                printed_file = False
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2143
                files.add(pf)
14381
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2144
            elif line.find('with fuzz') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2145
                fuzz = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2146
                if not printed_file:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2147
                    ui.warn(pf + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2148
                    printed_file = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2149
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2150
            elif line.find('saving rejects to file') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2151
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2152
            elif line.find('FAILED') >= 0:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2153
                if not printed_file:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2154
                    ui.warn(pf + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2155
                    printed_file = True
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2156
                ui.warn(line + '\n')
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2157
    finally:
d4192500586a patch: merge _updatedir() into externalpatch()
Patrick Mezard <pmezard@gmail.com>
parents: 14370
diff changeset
  2158
        if files:
19155
0b3689a08df5 patch: use scmutil.marktouched instead of scmutil.addremove
Siddharth Agarwal <sid0@fb.com>
parents: 18830
diff changeset
  2159
            scmutil.marktouched(repo, files, similarity)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2160
    code = fp.close()
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2161
    if code:
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2162
        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
  2163
                         procutil.explainexit(code))
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2164
    return fuzz
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2165
24253
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2166
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
  2167
                 eolmode='strict'):
9683
5c8651e2f5e0 patch: don't use mutable object as default argument
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9682
diff changeset
  2168
    if files is None:
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2169
        files = set()
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2170
    if eolmode is None:
33229
dd50a370c8cb configitems: register the 'patch.eol' config
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 33156
diff changeset
  2171
        eolmode = ui.config('patch', 'eol')
10101
155fe35534d3 patch: propagate eolmode down to patchfile
Martin Geisler <mg@lazybytes.net>
parents: 9725
diff changeset
  2172
    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
  2173
        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
  2174
    eolmode = eolmode.lower()
8843
eb7b247a98ea kill trailing whitespace
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8817
diff changeset
  2175
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2176
    store = filestore()
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2177
    try:
9031
3b76321aa0de compat: use open() instead of file() everywhere
Alejandro Santos <alejolp@alejolp.com>
parents: 9029
diff changeset
  2178
        fp = open(patchobj, 'rb')
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2179
    except TypeError:
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2180
        fp = patchobj
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2181
    try:
24253
26fa5ff9e660 patch.patchbackend: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24247
diff changeset
  2182
        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
  2183
                        eolmode=eolmode)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2184
    finally:
10203
6e26e3c2083f patch: explicitely close input patch files when leaving
Patrick Mezard <pmezard@gmail.com>
parents: 10135
diff changeset
  2185
        if fp != patchobj:
6e26e3c2083f patch: explicitely close input patch files when leaving
Patrick Mezard <pmezard@gmail.com>
parents: 10135
diff changeset
  2186
            fp.close()
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2187
        files.update(backend.close())
14452
ee574cfd0c32 patch: use temporary files to handle intermediate copies
Patrick Mezard <pmezard@gmail.com>
parents: 14451
diff changeset
  2188
        store.close()
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2189
    if ret < 0:
12674
aa2fe1f52ff4 patch: always raise PatchError with a message, simplify handling
Patrick Mezard <pmezard@gmail.com>
parents: 12673
diff changeset
  2190
        raise PatchError(_('patch failed to apply'))
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2191
    return ret > 0
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2192
24268
cf7d252d8c30 patch.internalpatch: add a default value for prefix
Siddharth Agarwal <sid0@fb.com>
parents: 24265
diff changeset
  2193
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
  2194
                  eolmode='strict', similarity=0):
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2195
    """use builtin patch to apply <patchobj> to the working directory.
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2196
    returns whether patch was applied with fuzz factor."""
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2197
    backend = workingbackend(ui, repo, similarity)
24254
60c279ab7bd3 patch.internalpatch: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24253
diff changeset
  2198
    return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2199
24260
76225ab5a5da cmdutil.tryimportone: allow importing relative patches with --bypass
Siddharth Agarwal <sid0@fb.com>
parents: 24259
diff changeset
  2200
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
  2201
              eolmode='strict'):
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2202
    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
  2203
    return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
14611
adbf5e7df96d import: add --bypass option
Patrick Mezard <pmezard@gmail.com>
parents: 14609
diff changeset
  2204
24259
5ac8ce04baa2 cmdutil.tryimportone: allow importing relative patches into the working dir
Siddharth Agarwal <sid0@fb.com>
parents: 24254
diff changeset
  2205
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
  2206
          similarity=0):
8810
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2207
    """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
  2208
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2209
    '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
  2210
    - '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
  2211
    - '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
  2212
    - '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
  2213
    - 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
  2214
    '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
  2215
ac92775b3b80 Add patch.eol to ignore EOLs when patching (issue1019)
Patrick Mezard <pmezard@gmail.com>
parents: 8778
diff changeset
  2216
    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
  2217
    """
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2218
    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
  2219
    if files is None:
14564
65f4512e40e4 patch: turn patch() touched files dict into a set
Patrick Mezard <pmezard@gmail.com>
parents: 14535
diff changeset
  2220
        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
  2221
    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
  2222
        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
  2223
                              files, similarity)
24259
5ac8ce04baa2 cmdutil.tryimportone: allow importing relative patches into the working dir
Siddharth Agarwal <sid0@fb.com>
parents: 24254
diff changeset
  2224
    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
  2225
                         similarity)
7151
b5bc5293021c patch: change functions definition order for readability
Patrick Mezard <pmezard@gmail.com>
parents: 7150
diff changeset
  2226
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2227
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
  2228
    backend = fsbackend(ui, repo.root)
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2229
    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
  2230
    with open(patchpath, 'rb') as fp:
14255
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2231
        changed = set()
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2232
        for state, values in iterhunks(fp):
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2233
            if state == 'file':
14388
37c997d21752 patch: stop handling hunkless git blocks out of stream
Patrick Mezard <pmezard@gmail.com>
parents: 14387
diff changeset
  2234
                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
  2235
                if gp:
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2236
                    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
  2237
                    if gp.oldpath:
35062
1706eae096e2 patch: accept prefix argument to changedfiles() helper
Martin von Zweigbergk <martinvonz@google.com>
parents: 34968
diff changeset
  2238
                        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
  2239
                                                   prefix)[1]
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2240
                else:
24245
740a17f885a1 patch.makepatchmeta: accept a prefix parameter
Siddharth Agarwal <sid0@fb.com>
parents: 24244
diff changeset
  2241
                    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
  2242
                                       prefix)
14566
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2243
                changed.add(gp.path)
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2244
                if gp.op == 'RENAME':
d0c2cc11e611 patch: generalize the use of patchmeta in applydiff()
Patrick Mezard <pmezard@gmail.com>
parents: 14565
diff changeset
  2245
                    changed.add(gp.oldpath)
14389
909ac6b9636b patch: stop modifying gitpatch objects
Patrick Mezard <pmezard@gmail.com>
parents: 14388
diff changeset
  2246
            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
  2247
                raise error.Abort(_('unsupported parser state: %s') % state)
14255
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2248
        return changed
576256a81cb6 patch: introduce changedfiles
Idan Kamara <idankk86@gmail.com>
parents: 14240
diff changeset
  2249
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2250
class GitDiffRequired(Exception):
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2251
    pass
7198
df79ee9b6278 patch: extract local function addmodehdr
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7186
diff changeset
  2252
38587
b62000a28812 diffutil: remove diffopts() in favor of diffallopts()
Yuya Nishihara <yuya@tcha.org>
parents: 38562
diff changeset
  2253
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
  2254
diffallopts = diffutil.diffallopts
c88d2c9b00dd diffutil: extract diff options code into a dedicated util-module
Boris Feld <boris.feld@octobus.net>
parents: 38493
diff changeset
  2255
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
  2256
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2257
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
  2258
         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
  2259
         copysourcematch=None, hunksfilterfn=None):
7308
b6f5490effbf patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7267
diff changeset
  2260
    '''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
  2261
    working directory.
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2262
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2263
    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
  2264
    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
  2265
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2266
    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
  2267
    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
  2268
    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
  2269
    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
  2270
    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
  2271
    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
  2272
    necessary.
12167
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2273
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2274
    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
  2275
    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
  2276
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2277
    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
  2278
    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
  2279
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2280
    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
  2281
    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
  2282
41620
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2283
    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
  2284
    matcher
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2285
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
  2286
    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
  2287
    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
  2288
    '''
41618
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2289
    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
  2290
        node1 = repo.dirstate.p1()
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2291
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2292
    ctx1 = repo[node1]
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2293
    ctx2 = repo[node2]
e834f6f6f221 patch: pass in context objects into diffhunks() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41534
diff changeset
  2294
34855
35c6a54ec1ff diff: also yield file context objects in patch.trydiff() (API)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 34566
diff changeset
  2295
    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
  2296
            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
  2297
            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
  2298
            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
  2299
        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
  2300
            # 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
  2301
            # 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
  2302
            # 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
  2303
            assert fctx2 is not None, (
aaad36b88298 cleanup: use () to wrap long lines instead of \
Augie Fackler <augie@google.com>
parents: 41646
diff changeset
  2304
                '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
  2305
            hunks = hunksfilterfn(fctx2, hunks)
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2306
        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
  2307
        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
  2308
            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
  2309
        if text:
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2310
            yield text
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2311
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2312
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
  2313
              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
  2314
    """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
  2315
    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
  2316
    (`hunkrange`, `hunklines`) tuples.
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2317
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2318
    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
  2319
    """
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2320
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2321
    if opts is None:
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2322
        opts = mdiff.defaultopts
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2323
9123
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2324
    def lrugetfilectx():
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2325
        cache = {}
25113
0ca8410ea345 util: drop alias for collections.deque
Martin von Zweigbergk <martinvonz@google.com>
parents: 24845
diff changeset
  2326
        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
  2327
        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
  2328
            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
  2329
            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
  2330
                if len(cache) > 20:
16803
107a3270a24a cleanup: use the deque type where appropriate
Bryan O'Sullivan <bryano@fb.com>
parents: 16705
diff changeset
  2331
                    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
  2332
                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
  2333
            else:
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2334
                order.remove(f)
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2335
            order.append(f)
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2336
            return fctx
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2337
        return getfilectx
360f61c2919f Make patch.diff filelog cache LRU of 20 files. Fixes issue1738.
Brendan Cully <brendan@kublai.com>
parents: 8891
diff changeset
  2338
    getfilectx = lrugetfilectx()
2934
2f190e998eb3 Teach mq about git patches
Brendan Cully <brendan@kublai.com>
parents: 2933
diff changeset
  2339
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2340
    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
  2341
        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
  2342
    modified, added, removed = changes[:3]
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2343
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2344
    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
  2345
        return []
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2346
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2347
    if repo.ui.debugflag:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2348
        hexfunc = hex
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2349
    else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 24269
diff changeset
  2350
        hexfunc = short
21833
c1ceec0c8cb4 patch: use ctx.node() instead of bare node variable
Sean Farley <sean.michael.farley@gmail.com>
parents: 21790
diff changeset
  2351
    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
  2352
29422
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2353
    if copy is None:
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2354
        copy = {}
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2355
        if opts.git or opts.upgrade:
40d53d4b5925 patch: allow copy information to be passed in
Henrik Stuart <henriks@unity3d.com>
parents: 29341
diff changeset
  2356
            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
  2357
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:
74f53d3bd685 patch: accept second matcher that applies only to copy sources (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41619
diff changeset
  2359
        # 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
  2360
        # (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
  2361
        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
  2362
                if copysourcematch(src)}
24417
f2e1e097cda1 patch.diff: add support for diffs relative to a subdirectory
Siddharth Agarwal <sid0@fb.com>
parents: 24416
diff changeset
  2363
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2364
    modifiedset = set(modified)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2365
    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
  2366
    removedset = set(removed)
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2367
    for f in modified:
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2368
        if f not in ctx1:
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2369
            # 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
  2370
            # modifications during merges
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2371
            modifiedset.remove(f)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2372
            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
  2373
    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
  2374
        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
  2375
            # 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
  2376
            # 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
  2377
            removedset.remove(f)
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2378
    modified = sorted(modifiedset)
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2379
    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
  2380
    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
  2381
    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
  2382
        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
  2383
            # 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
  2384
            # 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
  2385
            del copy[dst]
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2386
37764
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2387
    prefetchmatch = scmutil.matchfiles(
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2388
        repo, list(modifiedset | addedset | removedset))
5e67c20915a7 diff: invoke the file prefetch hook
Matt Harbison <matt_harbison@yahoo.com>
parents: 37732
diff changeset
  2389
    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
  2390
17299
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
  2391
    def difffn(opts, losedata):
e51d4aedace9 check-code: indent 4 spaces in py files
Mads Kiilerich <mads@kiilerich.com>
parents: 16834
diff changeset
  2392
        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
  2393
                       copy, getfilectx, opts, losedata, pathfn)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2394
    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
  2395
        try:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2396
            def losedata(fn):
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2397
                if not losedatafn or not losedatafn(fn=fn):
16687
e34106fa0dc3 cleanup: "raise SomeException()" -> "raise SomeException"
Brodie Rao <brodie@sf.io>
parents: 16686
diff changeset
  2398
                    raise GitDiffRequired
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2399
            # 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
  2400
            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
  2401
        except GitDiffRequired:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2402
            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
  2403
    else:
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2404
        return difffn(opts, None)
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2405
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2406
def diffsinglehunk(hunklines):
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2407
    """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
  2408
    for line in hunklines:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2409
        # chomp
38630
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2410
        chompline = line.rstrip('\r\n')
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2411
        # highlight tabs and trailing whitespace
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2412
        stripline = chompline.rstrip()
38048
b403e87df069 py3: use .startswith() instead of bytes[0]
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37803
diff changeset
  2413
        if line.startswith('-'):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2414
            label = 'diff.deleted'
38048
b403e87df069 py3: use .startswith() instead of bytes[0]
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37803
diff changeset
  2415
        elif line.startswith('+'):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2416
            label = 'diff.inserted'
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2417
        else:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2418
            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
  2419
        for token in tabsplitter.findall(stripline):
38048
b403e87df069 py3: use .startswith() instead of bytes[0]
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37803
diff changeset
  2420
            if token.startswith('\t'):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2421
                yield (token, 'diff.tab')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2422
            else:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2423
                yield (token, label)
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2424
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2425
        if chompline != stripline:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2426
            yield (chompline[len(stripline):], 'diff.trailingwhitespace')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2427
        if chompline != line:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2428
            yield (line[len(chompline):], '')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2429
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2430
def diffsinglehunkinline(hunklines):
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2431
    """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
  2432
    # prepare deleted, and inserted content
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2433
    a = ''
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2434
    b = ''
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2435
    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
  2436
        if line[0:1] == '-':
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2437
            a += line[1:]
39616
5a2bf7f941fa py3: slice through bytes to prevent getting ascii value
Pulkit Goyal <pulkit@yandex-team.ru>
parents: 38783
diff changeset
  2438
        elif line[0:1] == '+':
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2439
            b += line[1:]
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2440
        else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2441
            raise error.ProgrammingError('unexpected hunk line: %s' % line)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2442
    # 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
  2443
    if not a or not b:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2444
        for t in diffsinglehunk(hunklines):
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2445
            yield t
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2446
        return
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2447
    # re-split the content into words
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2448
    al = wordsplitter.findall(a)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2449
    bl = wordsplitter.findall(b)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2450
    # 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
  2451
    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
  2452
    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
  2453
    an = ''.join(aln)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2454
    bn = ''.join(bln)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2455
    # run the diff algorithm, prepare atokens and btokens
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2456
    atokens = []
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2457
    btokens = []
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2458
    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
  2459
    for (a1, a2, b1, b2), btype in blocks:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2460
        changed = btype == '!'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2461
        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
  2462
            atokens.append((changed, token))
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2463
        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
  2464
            btokens.append((changed, token))
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2465
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2466
    # yield deleted tokens, then inserted ones
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2467
    for prefix, label, tokens in [('-', 'diff.deleted', atokens),
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2468
                                  ('+', 'diff.inserted', btokens)]:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2469
        nextisnewline = True
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2470
        for changed, token in tokens:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2471
            if nextisnewline:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2472
                yield (prefix, label)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2473
                nextisnewline = False
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2474
            # special handling line end
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2475
            isendofline = token.endswith('\n')
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2476
            if isendofline:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2477
                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
  2478
                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
  2479
                    chomp = chomp[:-1]
e1987261dd05 patch: don't separate \r and \n when colorizing diff output
Sune Foldager <cryo@cyanite.org>
parents: 38588
diff changeset
  2480
                endofline = token[len(chomp):]
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2481
                token = chomp.rstrip() # detect spaces at the end
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2482
                endspaces = chomp[len(token):]
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2483
            # scan tabs
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2484
            for maybetab in tabsplitter.findall(token):
40282
e4f82db071a4 py3: fix test-diff-color.t
Mark Thomas <mbthomas@fb.com>
parents: 39616
diff changeset
  2485
                if b'\t' == maybetab[0:1]:
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2486
                    currentlabel = 'diff.tab'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2487
                else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2488
                    if changed:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2489
                        currentlabel = label + '.changed'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2490
                    else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2491
                        currentlabel = label + '.unchanged'
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2492
                yield (maybetab, currentlabel)
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2493
            if isendofline:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2494
                if endspaces:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2495
                    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
  2496
                yield (endofline, '')
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2497
                nextisnewline = True
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2498
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2499
def difflabel(func, *args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2500
    '''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
  2501
    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
  2502
        dodiffhunk = diffsinglehunkinline
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2503
    else:
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2504
        dodiffhunk = diffsinglehunk
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2505
    headprefixes = [('diff', 'diff.diffline'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2506
                    ('copy', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2507
                    ('rename', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2508
                    ('old', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2509
                    ('new', 'diff.extended'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2510
                    ('deleted', 'diff.extended'),
30790
dbcc10cf7f8d patch: add label for coloring the index extended header
Sean Farley <sean@farley.io>
parents: 30789
diff changeset
  2511
                    ('index', 'diff.extended'),
30808
8540967cd9e0 patch: add label for coloring the similarity extended header
Sean Farley <sean@farley.io>
parents: 30807
diff changeset
  2512
                    ('similarity', 'diff.extended'),
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2513
                    ('---', 'diff.file_a'),
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2514
                    ('+++', 'diff.file_b')]
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2515
    textprefixes = [('@', 'diff.hunk'),
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2516
                    # - and + are handled by diffsinglehunk
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2517
                   ]
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2518
    head = False
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2519
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2520
    # 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
  2521
    hunkbuffer = []
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2522
    def consumehunkbuffer():
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2523
        if hunkbuffer:
37732
35632d392279 patch: implement a new worddiff algorithm
Jun Wu <quark@fb.com>
parents: 37731
diff changeset
  2524
            for token in dodiffhunk(hunkbuffer):
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2525
                yield token
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2526
            hunkbuffer[:] = []
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2527
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2528
    for chunk in func(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2529
        lines = chunk.split('\n')
37730
8d730f96e792 patch: move yielding "\n" to the end of loop
Jun Wu <quark@fb.com>
parents: 37621
diff changeset
  2530
        linecount = len(lines)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2531
        for i, line in enumerate(lines):
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2532
            if head:
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2533
                if line.startswith('@'):
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2534
                    head = False
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2535
            else:
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  2536
                if line and not line.startswith((' ', '+', '-', '@', '\\')):
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2537
                    head = True
22460
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2538
            diffline = False
37471
51d5e1ff0613 py3: use s.startswith() instead of s[n] while parsing patches
Yuya Nishihara <yuya@tcha.org>
parents: 37468
diff changeset
  2539
            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
  2540
                diffline = True
c343557a8442 patch: enable diff.tab markup for the color extension
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 22296
diff changeset
  2541
15201
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2542
            prefixes = textprefixes
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2543
            if head:
2c4fdee4d1a8 diff: enhance highlighting with color (issue3034)
Kirill Elagin <kirelagin@gmail.com>
parents: 15159
diff changeset
  2544
                prefixes = headprefixes
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2545
            if diffline:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2546
                # buffered
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2547
                bufferedline = line
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2548
                if i + 1 < linecount:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2549
                    bufferedline += "\n"
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2550
                hunkbuffer.append(bufferedline)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2551
            else:
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2552
                # unbuffered
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2553
                for token in consumehunkbuffer():
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2554
                    yield token
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2555
                stripline = line.rstrip()
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2556
                for prefix, label in prefixes:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2557
                    if stripline.startswith(prefix):
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2558
                        yield (stripline, label)
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2559
                        if line != stripline:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2560
                            yield (line[len(stripline):],
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2561
                                   'diff.trailingwhitespace')
35277
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35191
diff changeset
  2562
                        break
37731
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2563
                else:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2564
                    yield (line, '')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2565
                if i + 1 < linecount:
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2566
                    yield ('\n', '')
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2567
        for token in consumehunkbuffer():
5471348921c1 patch: buffer lines for a same hunk
Jun Wu <quark@fb.com>
parents: 37730
diff changeset
  2568
            yield token
35277
6ba79cf34f5e patch: add within-line color diff capacity
Matthieu Laneuville <matthieu.laneuville@octobus.net>
parents: 35191
diff changeset
  2569
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2570
def diffui(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2571
    '''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
  2572
    return difflabel(diff, *args, **kw)
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2573
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2574
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
  2575
    '''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
  2576
    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
  2577
    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
  2578
    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
  2579
    gone = set()
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
    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
  2582
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2583
    addedset, removedset = set(added), set(removed)
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2584
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2585
    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
  2586
        copyop = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2587
        f1, f2 = f, f
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2588
        if f in addedset:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2589
            f1 = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2590
            if f in copy:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2591
                if opts.git:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2592
                    f1 = copy[f]
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2593
                    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
  2594
                        copyop = 'rename'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2595
                        gone.add(f1)
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2596
                    else:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2597
                        copyop = 'copy'
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2598
        elif f in removedset:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2599
            f2 = None
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2600
            if opts.git:
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2601
                # 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
  2602
                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
  2603
                    and copy[copyto[f]] == f):
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2604
                    continue
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2605
        yield f1, f2, copyop
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2606
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2607
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
  2608
            copy, getfilectx, opts, losedatafn, pathfn):
24371
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2609
    '''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
  2610
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2611
    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
  2612
    losedatafn is not None, it will be called.
8a997bd73448 patch.trydiff: add a docstring
Siddharth Agarwal <sid0@fb.com>
parents: 24346
diff changeset
  2613
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2614
    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
  2615
    '''
12167
d2c5b0927c28 diff: recurse into subrepositories with --subrepos/-S flag
Martin Geisler <mg@lazybytes.net>
parents: 12144
diff changeset
  2616
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2617
    def gitindex(text):
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2618
        if not text:
19875
c172660eee01 patch: Fix nullid for binary git diffs (issue4054)
Johan Bjork <jbjoerk@gmail.com>
parents: 19513
diff changeset
  2619
            text = ""
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2620
        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
  2621
        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
  2622
        s.update(text)
35582
72b91f905065 py3: use node.hex(h.digest()) instead of h.hexdigest()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35383
diff changeset
  2623
        return hex(s.digest())
17946
1e13b1184292 diff: move index header generation to patch
Guillermo Pérez <bisho@fb.com>
parents: 17945
diff changeset
  2624
23300
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2625
    if opts.noprefix:
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2626
        aprefix = bprefix = ''
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2627
    else:
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2628
        aprefix = 'a/'
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2629
        bprefix = 'b/'
f8b5c3e77d4b patch.trydiff: add support for noprefix
Siddharth Agarwal <sid0@fb.com>
parents: 23297
diff changeset
  2630
24021
f51a822dcf3b trydiff: remove unused argument to diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24020
diff changeset
  2631
    def diffline(f, revs):
24024
a5c7e86a81c1 trydiff: move check for quietness out of diffline()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24023
diff changeset
  2632
        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
  2633
        return 'diff %s %s' % (revinfo, f)
17941
9a6e4d5d7ea8 diff: move diffline to patch module
Guillermo Pérez <bisho@fb.com>
parents: 17940
diff changeset
  2634
32188
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2635
    def isempty(fctx):
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2636
        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
  2637
36607
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36447
diff changeset
  2638
    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
  2639
    date2 = dateutil.datestr(ctx2.date())
3967
dccb83241dd0 patch: use contexts for diff
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3963
diff changeset
  2640
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2641
    gitmode = {'l': '120000', 'x': '100755', '': '100644'}
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2642
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2643
    if not pathfn:
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2644
        pathfn = lambda f: f
24416
f07047a506d1 patch.trydiff: add support for stripping a relative root
Siddharth Agarwal <sid0@fb.com>
parents: 24390
diff changeset
  2645
27900
27572a5cc409 diff: move status fixup earlier, out of _filepairs()
Martin von Zweigbergk <martinvonz@google.com>
parents: 27796
diff changeset
  2646
    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
  2647
        content1 = None
0f8baebcdbea trydiff: read file data in only one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24104
diff changeset
  2648
        content2 = None
32187
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2649
        fctx1 = None
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2650
        fctx2 = None
24103
c666c85f71ba trydiff: read flags in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24102
diff changeset
  2651
        flag1 = None
c666c85f71ba trydiff: read flags in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24102
diff changeset
  2652
        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
  2653
        if f1:
32187
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2654
            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
  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
                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
  2657
        if f2:
32187
e62cf13e0858 diff: use fctx.isbinary() to test binary
Jun Wu <quark@fb.com>
parents: 32068
diff changeset
  2658
            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
  2659
            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
  2660
                flag2 = ctx2.flags(f2)
32190
0c67ab3d77d5 diff: correct binary testing logic
Jun Wu <quark@fb.com>
parents: 32189
diff changeset
  2661
        # 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
  2662
        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
  2663
            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
  2664
        else:
35951
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35888
diff changeset
  2665
            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
  2666
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2667
        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
  2668
            if (binary or
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2669
                # copy/rename
24106
9cf9432a505b trydiff: extract function that generates filename pairs
Martin von Zweigbergk <martinvonz@google.com>
parents: 24105
diff changeset
  2670
                f2 in copy or
24057
696d0fd77d94 trydiff: collect all lossiness checks in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 24056
diff changeset
  2671
                # empty file creation
32188
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2672
                (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
  2673
                # empty file deletion
32188
776127b29a5c diff: use fctx.size() to test empty
Jun Wu <quark@fb.com>
parents: 32187
diff changeset
  2674
                (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
  2675
                # create with flags
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2676
                (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
  2677
                # change flags
24101
1ea90d140ee3 trydiff: make filenames None when they don't exist
Martin von Zweigbergk <martinvonz@google.com>
parents: 24058
diff changeset
  2678
                (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
  2679
                losedatafn(f2 or f1)
10189
e451e599fbcf patch: support diff data loss detection and upgrade
Patrick Mezard <pmezard@gmail.com>
parents: 10151
diff changeset
  2680
41646
d4c9eebdd72d patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 41624
diff changeset
  2681
        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
  2682
        path2 = pathfn(f2 or f1)
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2683
        header = []
24022
da63f557d0dc trydiff: make 'revs' ignored if opts.git is set
Martin von Zweigbergk <martinvonz@google.com>
parents: 24021
diff changeset
  2684
        if opts.git:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2685
            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
  2686
                          (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
  2687
            if not f1: # added
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2688
                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
  2689
            elif not f2: # removed
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2690
                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
  2691
            else:  # modified/copied/renamed
24000
82e3324c4df9 trydiff: inline sole addmodehdr() call
Martin von Zweigbergk <martinvonz@google.com>
parents: 23999
diff changeset
  2692
                mode1, mode2 = gitmode[flag1], gitmode[flag2]
82e3324c4df9 trydiff: inline sole addmodehdr() call
Martin von Zweigbergk <martinvonz@google.com>
parents: 23999
diff changeset
  2693
                if mode1 != mode2:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2694
                    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
  2695
                    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
  2696
                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
  2697
                    if opts.showsimilarity:
6381a6dbc325 patch: use opt.showsimilarity to calculate and show the similarity
Sean Farley <sean@farley.io>
parents: 30806
diff changeset
  2698
                        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
  2699
                        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
  2700
                    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
  2701
                    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
  2702
        elif revs:
24022
da63f557d0dc trydiff: make 'revs' ignored if opts.git is set
Martin von Zweigbergk <martinvonz@google.com>
parents: 24021
diff changeset
  2703
            header.append(diffline(path1, revs))
23998
b65637247c69 trydiff: collect header-writing in one place
Martin von Zweigbergk <martinvonz@google.com>
parents: 23997
diff changeset
  2704
32189
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2705
        #  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
  2706
        #  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
  2707
        # ------------------------------------|----------------------------
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2708
        #  yes      | no   no       no  *     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2709
        #  yes      | no   no       yes *     | base85    | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2710
        #  yes      | no   yes      no  *     | summary   | no
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2711
        #  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
  2712
        #  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
  2713
        #  yes      | yes  *        *   *     | text diff | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2714
        #  no       | *    *        *   *     | text diff | yes
15f10ee778f8 diff: draw a table about binary diff behaviors
Jun Wu <quark@fb.com>
parents: 32188
diff changeset
  2715
        # [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
  2716
        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
  2717
                                        opts.index)):
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2718
            # 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
  2719
            # 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
  2720
            # fast path.
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2721
            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
  2722
                content1 = b'\0'
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2723
            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
  2724
                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
  2725
                    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
  2726
                else:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2727
                    content2 = b'\0\0'
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2728
        else:
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2729
            # normal path: load contents
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2730
            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
  2731
                content1 = fctx1.data()
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2732
            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
  2733
                content2 = fctx2.data()
31f42e683321 diff: add a fast path to avoid loading binary contents
Jun Wu <quark@fb.com>
parents: 32190
diff changeset
  2734
32190
0c67ab3d77d5 diff: correct binary testing logic
Jun Wu <quark@fb.com>
parents: 32189
diff changeset
  2735
        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
  2736
            text = mdiff.b85diff(content1, content2)
24056
ae453d166d51 trydiff: replace 'binarydiff' variable by 'binary' variable
Martin von Zweigbergk <martinvonz@google.com>
parents: 24055
diff changeset
  2737
            if text:
24025
bbb011f4eb32 trydiff: join elements in 'header' list by '\n'
Martin von Zweigbergk <martinvonz@google.com>
parents: 24024
diff changeset
  2738
                header.append('index %s..%s' %
24005
2c166f6b5d10 trydiff: inline indexmeta()
Martin von Zweigbergk <martinvonz@google.com>
parents: 24001
diff changeset
  2739
                              (gitindex(content1), gitindex(content2)))
31274
a8023a64c40d patch: add a diffhunks function yielding (diffheaders, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31273
diff changeset
  2740
            hunks = (None, [text]),
23753
e30c6aa6f2a2 trydiff: replace 'dodiff = False' by 'continue'
Martin von Zweigbergk <martinvonz@google.com>
parents: 23752
diff changeset
  2741
        else:
30789
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2742
            if opts.git and opts.index > 0:
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2743
                flag = flag1
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2744
                if flag is None:
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2745
                    flag = flag2
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2746
                header.append('index %s..%s %s' %
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2747
                              (gitindex(content1)[0:opts.index],
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2748
                               gitindex(content2)[0:opts.index],
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2749
                               gitmode[flag]))
b8ad243f5ded patch: add index line for diff output
Sean Farley <sean@farley.io>
parents: 30788
diff changeset
  2750
31273
92714858dd3e mdiff: let unidiff return (diffheader, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31271
diff changeset
  2751
            uheaders, hunks = mdiff.unidiff(content1, date1,
92714858dd3e mdiff: let unidiff return (diffheader, hunks)
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31271
diff changeset
  2752
                                            content2, date2,
35951
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35888
diff changeset
  2753
                                            path1, path2,
8b6dd3922f70 patch: unify check_binary and binary flags
Yuya Nishihara <yuya@tcha.org>
parents: 35888
diff changeset
  2754
                                            binary=binary, opts=opts)
31271
b3861be6aa6c mdiff: distinguish diff headers from hunks in unidiff()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 31233
diff changeset
  2755
            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
  2756
        yield fctx1, fctx2, header, hunks
2874
4ec58b157265 refactor text diff/patch code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2868
diff changeset
  2757
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2758
def diffstatsum(stats):
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2759
    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
  2760
    for f, a, r, b in stats:
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2761
        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
  2762
        maxtotal = max(maxtotal, a + r)
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2763
        addtotal += a
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2764
        removetotal += r
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2765
        binary = binary or b
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2766
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2767
    return maxfile, maxtotal, addtotal, removetotal, binary
14401
7bb7be1c1385 patch: add diffstatsum helper
Matt Mackall <mpm@selenic.com>
parents: 14400
diff changeset
  2768
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2769
def diffstatdata(lines):
41532
bd3f03d8cc9f global: use raw strings for regular expressions with escapes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 41499
diff changeset
  2770
    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
  2771
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2772
    results = []
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2773
    filename, adds, removes, isbinary = None, 0, 0, False
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2774
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2775
    def addresult():
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2776
        if filename:
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2777
            results.append((filename, adds, removes, isbinary))
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2778
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2779
    # 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
  2780
    # 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
  2781
    # 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
  2782
    inheader = False
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2783
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2784
    for line in lines:
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2785
        if line.startswith('diff'):
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2786
            addresult()
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2787
            # starting a new file diff
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2788
            # 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
  2789
            inheader = True
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2790
            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
  2791
            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
  2792
                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
  2793
            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
  2794
                # 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
  2795
                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
  2796
        elif line.startswith('@@'):
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2797
            inheader = False
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2798
        elif line.startswith('+') and not inheader:
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2799
            adds += 1
32320
0e29ce16ec38 diffstat: properly count lines starting in '--' or '++' (issue5479)
Andrew Zwicky <andrew.zwicky@gmail.com>
parents: 32201
diff changeset
  2800
        elif line.startswith('-') and not inheader:
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2801
            removes += 1
15363
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2802
        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
  2803
              line.startswith('Binary file')):
628a4a9e411d diffstat: be more picky when marking file as 'binary' (issue2816)
Patrick Mezard <pmezard@gmail.com>
parents: 15201
diff changeset
  2804
            isbinary = True
41375
f1b0d9988825 diffstat: make --git work properly on renames (issue6025)
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41365
diff changeset
  2805
        elif line.startswith('rename from'):
41401
4a33a6bf2b52 diffstat: support filenames with whitespaces on renames
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41375
diff changeset
  2806
            filename = line[12:]
41375
f1b0d9988825 diffstat: make --git work properly on renames (issue6025)
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41365
diff changeset
  2807
        elif line.startswith('rename to'):
41401
4a33a6bf2b52 diffstat: support filenames with whitespaces on renames
Navaneeth Suresh <navaneeths1998@gmail.com>
parents: 41375
diff changeset
  2808
            filename += ' => %s' % line[10:]
14400
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2809
    addresult()
cd1ca2556cac diffstatdata: no longer a generator
Matt Mackall <mpm@selenic.com>
parents: 14392
diff changeset
  2810
    return results
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2811
30407
e1677cc29da6 patch: remove unused git parameter from patch.diffstat()
Henning Schild <henning@hennsch.de>
parents: 30397
diff changeset
  2812
def diffstat(lines, width=80):
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2813
    output = []
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2814
    stats = diffstatdata(lines)
14437
cbe13e6bdc34 patch: restore the previous output of 'diff --stat'
Steven Brown <StevenGBrown@gmail.com>
parents: 14435
diff changeset
  2815
    maxname, maxtotal, totaladds, totalremoves, hasbinary = diffstatsum(stats)
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2816
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2817
    countwidth = len(str(maxtotal))
9642
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2818
    if hasbinary and countwidth < 3:
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2819
        countwidth = 3
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2820
    graphwidth = width - countwidth - maxname - 6
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2821
    if graphwidth < 10:
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2822
        graphwidth = 10
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2823
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2824
    def scale(i):
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2825
        if maxtotal <= graphwidth:
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2826
            return i
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2827
        # 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
  2828
        # 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
  2829
        # 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
  2830
        return max(i * graphwidth // maxtotal, int(bool(i)))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2831
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2832
    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
  2833
        if isbinary:
9642
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2834
            count = 'Bin'
7d17794f08a9 diffstat: with --git, mark binary files with Bin
Brodie Rao <me+hg@dackz.net>
parents: 9639
diff changeset
  2835
        else:
33104
53238678b1ca py3: use '%d' to convert integers to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 33096
diff changeset
  2836
            count = '%d' % (adds + removes)
9330
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2837
        pluses = '+' * scale(adds)
be2a13153372 diffstat: scale adds/removes proportionally to graph width
Brodie Rao <me+hg@dackz.net>
parents: 9328
diff changeset
  2838
        minuses = '-' * scale(removes)
11611
4f5a6df2af92 i18n: use encoding.colwidth() for correct column width
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11377
diff changeset
  2839
        output.append(' %s%s |  %*s %s%s\n' %
14402
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2840
                      (filename, ' ' * (maxname - encoding.colwidth(filename)),
f03f08240c32 patch: use diffstatsum in diffstat
Matt Mackall <mpm@selenic.com>
parents: 14401
diff changeset
  2841
                       countwidth, count, pluses, minuses))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2842
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2843
    if stats:
16683
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  2844
        output.append(_(' %d files changed, %d insertions(+), '
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 16662
diff changeset
  2845
                        '%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
  2846
                      % (len(stats), totaladds, totalremoves))
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2847
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7521
diff changeset
  2848
    return ''.join(output)
10818
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
def diffstatui(*args, **kw):
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2851
    '''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
  2852
    ui.write()
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2853
    '''
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2854
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2855
    for line in diffstat(*args, **kw).splitlines():
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2856
        if line and line[-1] in '+-':
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2857
            name, graph = line.rsplit(' ', 1)
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2858
            yield (name + ' ', '')
33096
d9962854a4a2 py3: add b'' to make the regex pattern bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32990
diff changeset
  2859
            m = re.search(br'\++', graph)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2860
            if m:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2861
                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
  2862
            m = re.search(br'-+', graph)
10818
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2863
            if m:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2864
                yield (m.group(0), 'diffstat.deleted')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2865
        else:
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2866
            yield (line, '')
d14d45fae927 diff: make use of output labeling
Brodie Rao <brodie@bitheap.org>
parents: 10751
diff changeset
  2867
        yield ('\n', '')