##// END OF EJS Templates
deps: bumped test requirements
deps: bumped test requirements

File last commit:

r1327:278da2b3 default
r1328:942ebeb1 default
Show More
svn_diff.py
212 lines | 8.2 KiB | text/x-python | PythonLexer
initial commit
r0 #
# Copyright (C) 2004-2009 Edgewall Software
# Copyright (C) 2004-2006 Christopher Lenz <cmlenz@gmx.de>
core: updated copyrights to 2024
r1327 # Copyright (C) 2014-2024 RhodeCode GmbH
initial commit
r0 # All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Christopher Lenz <cmlenz@gmx.de>
import difflib
app: new optimized remote endpoints for python3 rewrite
r1124 def get_filtered_hunks(from_lines, to_lines, context=None,
ignore_blank_lines: bool = False, ignore_case: bool = False,
ignore_space_changes: bool = False):
initial commit
r0 """Retrieve differences in the form of `difflib.SequenceMatcher`
opcodes, grouped according to the ``context`` and ``ignore_*``
parameters.
app: new optimized remote endpoints for python3 rewrite
r1124 :param from_lines: list of lines corresponding to the old content
:param to_lines: list of lines corresponding to the new content
initial commit
r0 :param ignore_blank_lines: differences about empty lines only are ignored
:param ignore_case: upper case / lower case only differences are ignored
:param ignore_space_changes: differences in amount of spaces are ignored
:param context: the number of "equal" lines kept for representing
the context of the change
:return: generator of grouped `difflib.SequenceMatcher` opcodes
If none of the ``ignore_*`` parameters is `True`, there's nothing
to filter out the results will come straight from the
SequenceMatcher.
"""
app: new optimized remote endpoints for python3 rewrite
r1124 hunks = get_hunks(from_lines, to_lines, context)
initial commit
r0 if ignore_space_changes or ignore_case or ignore_blank_lines:
app: new optimized remote endpoints for python3 rewrite
r1124 hunks = filter_ignorable_lines(hunks, from_lines, to_lines, context,
initial commit
r0 ignore_blank_lines, ignore_case,
ignore_space_changes)
return hunks
app: new optimized remote endpoints for python3 rewrite
r1124 def get_hunks(from_lines, to_lines, context=None):
initial commit
r0 """Generator yielding grouped opcodes describing differences .
See `get_filtered_hunks` for the parameter descriptions.
"""
app: new optimized remote endpoints for python3 rewrite
r1124 matcher = difflib.SequenceMatcher(None, from_lines, to_lines)
initial commit
r0 if context is None:
return (hunk for hunk in [matcher.get_opcodes()])
else:
return matcher.get_grouped_opcodes(context)
app: new optimized remote endpoints for python3 rewrite
r1124 def filter_ignorable_lines(hunks, from_lines, to_lines, context,
initial commit
r0 ignore_blank_lines, ignore_case,
ignore_space_changes):
"""Detect line changes that should be ignored and emits them as
tagged as "equal", possibly joined with the preceding and/or
following "equal" block.
See `get_filtered_hunks` for the parameter descriptions.
"""
def is_ignorable(tag, fromlines, tolines):
app: new optimized remote endpoints for python3 rewrite
r1124
initial commit
r0 if tag == 'delete' and ignore_blank_lines:
app: new optimized remote endpoints for python3 rewrite
r1124 if b''.join(fromlines) == b'':
initial commit
r0 return True
elif tag == 'insert' and ignore_blank_lines:
app: new optimized remote endpoints for python3 rewrite
r1124 if b''.join(tolines) == b'':
initial commit
r0 return True
elif tag == 'replace' and (ignore_case or ignore_space_changes):
if len(fromlines) != len(tolines):
return False
pep8: fixed issue with shadowing reserved python variables.
r119
def f(input_str):
initial commit
r0 if ignore_case:
pep8: fixed issue with shadowing reserved python variables.
r119 input_str = input_str.lower()
initial commit
r0 if ignore_space_changes:
app: new optimized remote endpoints for python3 rewrite
r1124 input_str = b' '.join(input_str.split())
pep8: fixed issue with shadowing reserved python variables.
r119 return input_str
initial commit
r0 for i in range(len(fromlines)):
if f(fromlines[i]) != f(tolines[i]):
return False
return True
hunks = list(hunks)
opcodes = []
ignored_lines = False
prev = None
for hunk in hunks:
for tag, i1, i2, j1, j2 in hunk:
if tag == 'equal':
if prev:
prev = (tag, prev[1], i2, prev[3], j2)
else:
prev = (tag, i1, i2, j1, j2)
else:
app: new optimized remote endpoints for python3 rewrite
r1124 if is_ignorable(tag, from_lines[i1:i2], to_lines[j1:j2]):
initial commit
r0 ignored_lines = True
if prev:
prev = 'equal', prev[1], i2, prev[3], j2
else:
prev = 'equal', i1, i2, j1, j2
continue
if prev:
opcodes.append(prev)
opcodes.append((tag, i1, i2, j1, j2))
prev = None
if prev:
opcodes.append(prev)
if ignored_lines:
if context is None:
yield opcodes
else:
# we leave at most n lines with the tag 'equal' before and after
# every change
n = context
nn = n + n
group = []
app: new optimized remote endpoints for python3 rewrite
r1124
initial commit
r0 def all_equal():
all(op[0] == 'equal' for op in group)
for idx, (tag, i1, i2, j1, j2) in enumerate(opcodes):
app: new optimized remote endpoints for python3 rewrite
r1124 if idx == 0 and tag == 'equal': # Fixup leading unchanged block
initial commit
r0 i1, j1 = max(i1, i2 - n), max(j1, j2 - n)
elif tag == 'equal' and i2 - i1 > nn:
group.append((tag, i1, min(i2, i1 + n), j1,
min(j2, j1 + n)))
if not all_equal():
yield group
group = []
i1, j1 = max(i1, i2 - n), max(j1, j2 - n)
group.append((tag, i1, i2, j1, j2))
if group and not (len(group) == 1 and group[0][0] == 'equal'):
app: new optimized remote endpoints for python3 rewrite
r1124 if group[-1][0] == 'equal': # Fixup trailing unchanged block
initial commit
r0 tag, i1, i2, j1, j2 = group[-1]
group[-1] = tag, i1, min(i2, i1 + n), j1, min(j2, j1 + n)
if not all_equal():
yield group
else:
for hunk in hunks:
yield hunk
app: new optimized remote endpoints for python3 rewrite
r1124 NO_NEWLINE_AT_END = b'\\ No newline at end of file'
LINE_TERM = b'\n'
initial commit
r0
app: new optimized remote endpoints for python3 rewrite
r1124 def unified_diff(from_lines, to_lines, context=None, ignore_blank_lines: bool = False,
ignore_case: bool = False, ignore_space_changes: bool = False, lineterm=LINE_TERM) -> bytes:
initial commit
r0 """
Generator producing lines corresponding to a textual diff.
See `get_filtered_hunks` for the parameter descriptions.
"""
# TODO: johbo: Check if this can be nicely integrated into the matching
core: few python3 fixes found during ce tests runs
r1085
initial commit
r0 if ignore_space_changes:
app: new optimized remote endpoints for python3 rewrite
r1124 from_lines = [l.strip() for l in from_lines]
to_lines = [l.strip() for l in to_lines]
initial commit
r0
app: new optimized remote endpoints for python3 rewrite
r1124 def _hunk_range(start, length) -> bytes:
if length != 1:
return b'%d,%d' % (start, length)
else:
return b'%d' % (start,)
for group in get_filtered_hunks(from_lines, to_lines, context,
initial commit
r0 ignore_blank_lines, ignore_case,
ignore_space_changes):
i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]
if i1 == 0 and i2 == 0:
i1, i2 = -1, -1 # support for Add changes
if j1 == 0 and j2 == 0:
j1, j2 = -1, -1 # support for Delete changes
app: new optimized remote endpoints for python3 rewrite
r1124 yield b'@@ -%b +%b @@%b' % (
initial commit
r0 _hunk_range(i1 + 1, i2 - i1),
_hunk_range(j1 + 1, j2 - j1),
lineterm)
for tag, i1, i2, j1, j2 in group:
if tag == 'equal':
app: new optimized remote endpoints for python3 rewrite
r1124 for line in from_lines[i1:i2]:
initial commit
r0 if not line.endswith(lineterm):
app: new optimized remote endpoints for python3 rewrite
r1124 yield b' ' + line + lineterm
initial commit
r0 yield NO_NEWLINE_AT_END + lineterm
else:
app: new optimized remote endpoints for python3 rewrite
r1124 yield b' ' + line
initial commit
r0 else:
if tag in ('replace', 'delete'):
app: new optimized remote endpoints for python3 rewrite
r1124 for line in from_lines[i1:i2]:
initial commit
r0 if not line.endswith(lineterm):
app: new optimized remote endpoints for python3 rewrite
r1124 yield b'-' + line + lineterm
initial commit
r0 yield NO_NEWLINE_AT_END + lineterm
else:
app: new optimized remote endpoints for python3 rewrite
r1124 yield b'-' + line
initial commit
r0 if tag in ('replace', 'insert'):
app: new optimized remote endpoints for python3 rewrite
r1124 for line in to_lines[j1:j2]:
initial commit
r0 if not line.endswith(lineterm):
app: new optimized remote endpoints for python3 rewrite
r1124 yield b'+' + line + lineterm
initial commit
r0 yield NO_NEWLINE_AT_END + lineterm
else:
app: new optimized remote endpoints for python3 rewrite
r1124 yield b'+' + line