/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1
#!/usr/bin/env python
2
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
17
6379.6.3 by Jelmer Vernooij
Use absolute_import.
18
from __future__ import absolute_import
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
19
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
20
from .lazy_import import lazy_import
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
21
lazy_import(globals(), """
22
import os
23
import sys
24
import time
25
import difflib
26
""")
27
28
7031.1.1 by Jelmer Vernooij
Fix breezy.tests.test_diff.
29
__all__ = ['PatienceSequenceMatcher', 'unified_diff', 'unified_diff_bytes',
30
           'unified_diff_files']
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
31
32
33
# This is a version of unified_diff which only adds a factory parameter
34
# so that you can override the default SequenceMatcher
35
# this has been submitted as a patch to python
36
def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
37
                 tofiledate='', n=3, lineterm='\n',
38
                 sequencematcher=None):
39
    r"""
40
    Compare two sequences of lines; generate the delta as a unified diff.
41
42
    Unified diffs are a compact way of showing line changes and a few
43
    lines of context.  The number of context lines is set by 'n' which
44
    defaults to three.
45
46
    By default, the diff control lines (those with ---, +++, or @@) are
47
    created with a trailing newline.  This is helpful so that inputs
48
    created from file.readlines() result in diffs that are suitable for
49
    file.writelines() since both the inputs and outputs have trailing
50
    newlines.
51
52
    For inputs that do not have trailing newlines, set the lineterm
53
    argument to "" so that the output will be uniformly newline free.
54
55
    The unidiff format normally has a header for filenames and modification
56
    times.  Any or all of these may be specified using strings for
57
    'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.  The modification
58
    times are normally expressed in the format returned by time.ctime().
59
60
    Example:
61
62
    >>> for line in unified_diff('one two three four'.split(),
63
    ...             'zero one tree four'.split(), 'Original', 'Current',
64
    ...             'Sat Jan 26 23:30:50 1991', 'Fri Jun 06 10:20:52 2003',
65
    ...             lineterm=''):
66
    ...     print line
67
    --- Original Sat Jan 26 23:30:50 1991
68
    +++ Current Fri Jun 06 10:20:52 2003
69
    @@ -1,4 +1,4 @@
70
    +zero
71
     one
72
    -two
73
    -three
74
    +tree
75
     four
76
    """
77
    if sequencematcher is None:
78
        sequencematcher = difflib.SequenceMatcher
79
3922.1.1 by Adeodato Simo
Change the patience_diff.unified_diff code to not add trailing whitespace when no timestamp is supplied.
80
    if fromfiledate:
3922.1.4 by John Arbash Meinel
It turns out that internal_diff worked around the trailing whitespace problem
81
        fromfiledate = '\t' + str(fromfiledate)
3922.1.1 by Adeodato Simo
Change the patience_diff.unified_diff code to not add trailing whitespace when no timestamp is supplied.
82
    if tofiledate:
3922.1.4 by John Arbash Meinel
It turns out that internal_diff worked around the trailing whitespace problem
83
        tofiledate = '\t' + str(tofiledate)
3922.1.1 by Adeodato Simo
Change the patience_diff.unified_diff code to not add trailing whitespace when no timestamp is supplied.
84
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
85
    started = False
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
86
    for group in sequencematcher(None, a, b).get_grouped_opcodes(n):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
87
        if not started:
3922.1.1 by Adeodato Simo
Change the patience_diff.unified_diff code to not add trailing whitespace when no timestamp is supplied.
88
            yield '--- %s%s%s' % (fromfile, fromfiledate, lineterm)
89
            yield '+++ %s%s%s' % (tofile, tofiledate, lineterm)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
90
            started = True
91
        i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]
92
        yield "@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm)
93
        for tag, i1, i2, j1, j2 in group:
94
            if tag == 'equal':
95
                for line in a[i1:i2]:
96
                    yield ' ' + line
97
                continue
98
            if tag == 'replace' or tag == 'delete':
99
                for line in a[i1:i2]:
100
                    yield '-' + line
101
            if tag == 'replace' or tag == 'insert':
102
                for line in b[j1:j2]:
103
                    yield '+' + line
104
105
7031.1.1 by Jelmer Vernooij
Fix breezy.tests.test_diff.
106
def unified_diff_bytes(a, b, fromfile=b'', tofile=b'', fromfiledate=b'',
107
                       tofiledate=b'', n=3, lineterm=b'\n', sequencematcher=None):
108
    r"""
109
    Compare two sequences of lines; generate the delta as a unified diff.
110
111
    Unified diffs are a compact way of showing line changes and a few
112
    lines of context.  The number of context lines is set by 'n' which
113
    defaults to three.
114
115
    By default, the diff control lines (those with ---, +++, or @@) are
116
    created with a trailing newline.  This is helpful so that inputs
117
    created from file.readlines() result in diffs that are suitable for
118
    file.writelines() since both the inputs and outputs have trailing
119
    newlines.
120
121
    For inputs that do not have trailing newlines, set the lineterm
122
    argument to "" so that the output will be uniformly newline free.
123
124
    The unidiff format normally has a header for filenames and modification
125
    times.  Any or all of these may be specified using strings for
126
    'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.  The modification
127
    times are normally expressed in the format returned by time.ctime().
128
129
    Example:
130
131
    >>> for line in bytes_unified_diff(b'one two three four'.split(),
132
    ...             b'zero one tree four'.split(), b'Original', b'Current',
133
    ...             b'Sat Jan 26 23:30:50 1991', b'Fri Jun 06 10:20:52 2003',
134
    ...             lineterm=b''):
135
    ...     print line
136
    --- Original Sat Jan 26 23:30:50 1991
137
    +++ Current Fri Jun 06 10:20:52 2003
138
    @@ -1,4 +1,4 @@
139
    +zero
140
     one
141
    -two
142
    -three
143
    +tree
144
     four
145
    """
146
    if sequencematcher is None:
147
        sequencematcher = difflib.SequenceMatcher
148
149
    if fromfiledate:
150
        fromfiledate = b'\t' + byes(fromfiledate)
151
    if tofiledate:
152
        tofiledate = b'\t' + bytes(tofiledate)
153
154
    started = False
155
    for group in sequencematcher(None, a, b).get_grouped_opcodes(n):
156
        if not started:
157
            yield b'--- %s%s%s' % (fromfile, fromfiledate, lineterm)
158
            yield b'+++ %s%s%s' % (tofile, tofiledate, lineterm)
159
            started = True
160
        i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]
161
        yield b"@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm)
162
        for tag, i1, i2, j1, j2 in group:
163
            if tag == 'equal':
164
                for line in a[i1:i2]:
165
                    yield b' ' + line
166
                continue
167
            if tag == 'replace' or tag == 'delete':
168
                for line in a[i1:i2]:
169
                    yield b'-' + line
170
            if tag == 'replace' or tag == 'insert':
171
                for line in b[j1:j2]:
172
                    yield b'+' + line
173
174
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
175
def unified_diff_files(a, b, sequencematcher=None):
176
    """Generate the diff for two files.
177
    """
178
    # Should this actually be an error?
179
    if a == b:
180
        return []
181
    if a == '-':
182
        file_a = sys.stdin
183
        time_a = time.time()
184
    else:
185
        file_a = open(a, 'rb')
186
        time_a = os.stat(a).st_mtime
187
188
    if b == '-':
189
        file_b = sys.stdin
190
        time_b = time.time()
191
    else:
192
        file_b = open(b, 'rb')
193
        time_b = os.stat(b).st_mtime
194
195
    # TODO: Include fromfiledate and tofiledate
7031.1.1 by Jelmer Vernooij
Fix breezy.tests.test_diff.
196
    return unified_diff_bytes(file_a.readlines(), file_b.readlines(),
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
197
                        fromfile=a, tofile=b,
198
                        sequencematcher=sequencematcher)
199
200
201
try:
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
202
    from ._patiencediff_c import (
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
203
        unique_lcs_c as unique_lcs,
204
        recurse_matches_c as recurse_matches,
205
        PatienceSequenceMatcher_c as PatienceSequenceMatcher
206
        )
207
except ImportError:
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
208
    from ._patiencediff_py import (
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
209
        unique_lcs_py as unique_lcs,
210
        recurse_matches_py as recurse_matches,
211
        PatienceSequenceMatcher_py as PatienceSequenceMatcher
212
        )
213
214
215
def main(args):
216
    import optparse
217
    p = optparse.OptionParser(usage='%prog [options] file_a file_b'
218
                                    '\nFiles can be "-" to read from stdin')
219
    p.add_option('--patience', dest='matcher', action='store_const', const='patience',
220
                 default='patience', help='Use the patience difference algorithm')
221
    p.add_option('--difflib', dest='matcher', action='store_const', const='difflib',
222
                 default='patience', help='Use python\'s difflib algorithm')
223
224
    algorithms = {'patience':PatienceSequenceMatcher, 'difflib':difflib.SequenceMatcher}
225
226
    (opts, args) = p.parse_args(args)
227
    matcher = algorithms[opts.matcher]
228
229
    if len(args) != 2:
6619.3.3 by Jelmer Vernooij
Apply 2to3 print fix.
230
        print('You must supply 2 filenames to diff')
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
231
        return -1
232
233
    for line in unified_diff_files(args[0], args[1], sequencematcher=matcher):
234
        sys.stdout.write(line)
235
236
237
if __name__ == '__main__':
238
    sys.exit(main(sys.argv[1:]))