1
# Copyright (C) 2004 - 2006, 2008 Aaron Bentley, Canonical Ltd
1
# Copyright (C) 2005-2010 Aaron Bentley, Canonical Ltd
2
2
# <aaron.bentley@utoronto.ca>
4
4
# This program is free software; you can redistribute it and/or modify
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
from bzrlib.errors import (
20
30
binary_files_re = 'Binary files (.*) and (.*) differ\n'
23
class BinaryFiles(Exception):
25
def __init__(self, orig_name, mod_name):
26
self.orig_name = orig_name
27
self.mod_name = mod_name
28
Exception.__init__(self, 'Binary files section encountered.')
31
class PatchSyntax(Exception):
32
def __init__(self, msg):
33
Exception.__init__(self, msg)
36
class MalformedPatchHeader(PatchSyntax):
37
def __init__(self, desc, line):
40
msg = "Malformed patch header. %s\n%r" % (self.desc, self.line)
41
PatchSyntax.__init__(self, msg)
44
class MalformedHunkHeader(PatchSyntax):
45
def __init__(self, desc, line):
48
msg = "Malformed hunk header. %s\n%r" % (self.desc, self.line)
49
PatchSyntax.__init__(self, msg)
52
class MalformedLine(PatchSyntax):
53
def __init__(self, desc, line):
56
msg = "Malformed line. %s\n%s" % (self.desc, self.line)
57
PatchSyntax.__init__(self, msg)
60
class PatchConflict(Exception):
61
def __init__(self, line_no, orig_line, patch_line):
62
orig = orig_line.rstrip('\n')
63
patch = str(patch_line).rstrip('\n')
64
msg = 'Text contents mismatch at line %d. Original has "%s",'\
65
' but patch says it should be "%s"' % (line_no, orig, patch)
66
Exception.__init__(self, msg)
69
32
def get_patch_names(iter_lines):
71
34
line = iter_lines.next()
253
def iter_hunks(iter_lines):
216
def iter_hunks(iter_lines, allow_dirty=False):
218
:arg iter_lines: iterable of lines to parse for hunks
219
:kwarg allow_dirty: If True, when we encounter something that is not
220
a hunk header when we're looking for one, assume the rest of the lines
221
are not part of the patch (comments or other junk). Default False
255
224
for line in iter_lines:
261
230
if hunk is not None:
263
hunk = hunk_from_header(line)
233
hunk = hunk_from_header(line)
234
except MalformedHunkHeader:
236
# If the line isn't a hunk header, then we've reached the end
237
# of this patch and there's "junk" at the end. Ignore the
238
# rest of this patch.
266
243
while orig_size < hunk.orig_range or mod_size < hunk.mod_range:
342
def parse_patch(iter_lines):
319
def parse_patch(iter_lines, allow_dirty=False):
321
:arg iter_lines: iterable of lines to parse
322
:kwarg allow_dirty: If True, allow the patch to have trailing junk.
343
325
iter_lines = iter_lines_handle_nl(iter_lines)
345
327
(orig_name, mod_name) = get_patch_names(iter_lines)
347
329
return BinaryPatch(e.orig_name, e.mod_name)
349
331
patch = Patch(orig_name, mod_name)
350
for hunk in iter_hunks(iter_lines):
332
for hunk in iter_hunks(iter_lines, allow_dirty):
351
333
patch.hunks.append(hunk)
355
def iter_file_patch(iter_lines):
337
def iter_file_patch(iter_lines, allow_dirty=False):
339
:arg iter_lines: iterable of lines to parse for patches
340
:kwarg allow_dirty: If True, allow comments and other non-patch text
341
before the first patch. Note that the algorithm here can only find
342
such text before any patches have been found. Comments after the
343
first patch are stripped away in iter_hunks() if it is also passed
344
allow_dirty=True. Default False.
346
### FIXME: Docstring is not quite true. We allow certain comments no
347
# matter what, If they startwith '===', '***', or '#' Someone should
348
# reexamine this logic and decide if we should include those in
349
# allow_dirty or restrict those to only being before the patch is found
350
# (as allow_dirty does).
356
351
regex = re.compile(binary_files_re)
359
355
for line in iter_lines:
360
356
if line.startswith('=== ') or line.startswith('*** '):
365
361
if line.startswith('-') or line.startswith(' '):
367
363
elif line.startswith('--- ') or regex.match(line):
368
if len(saved_lines) > 0:
364
if allow_dirty and beginning:
365
# Patches can have "junk" at the beginning
366
# Stripping junk from the end of patches is handled when we
369
elif len(saved_lines) > 0:
369
370
yield saved_lines
371
372
elif line.startswith('@@'):
400
def parse_patches(iter_lines):
401
return [parse_patch(f.__iter__()) for f in iter_file_patch(iter_lines)]
401
def parse_patches(iter_lines, allow_dirty=False):
403
:arg iter_lines: iterable of lines to parse for patches
404
:kwarg allow_dirty: If True, allow text that's not part of the patch at
405
selected places. This includes comments before and after a patch
406
for instance. Default False.
408
return [parse_patch(f.__iter__(), allow_dirty) for f in
409
iter_file_patch(iter_lines, allow_dirty)]
404
412
def difference_index(atext, btext):