Commit 3d5f0d7b authored by Jérémy Bobbio's avatar Jérémy Bobbio

Perform content comparison when creating Difference objects

Instead of storing the full content twice when creating Difference objects, we
now directly run `diff` and store the unified diff. Large blocks in the diff
are still trimmed. This results in huge memory savings and debbindiff can now
happily compare changes for installation-guide.

As tool_required() is not only for comparators anymore, we move it to
debbindiff, together with logger.

Text output becomes really straightforward as we just have to write what
we've previously recorded.

For the HTML output, we stop using vim and instead borrow code from
diff2html.py found at <http://git.droids-corp.org/?p=diff2html.git>.

Closes: #772029
Closes: #779476
parent 383b4e8f
......@@ -73,7 +73,7 @@ def make_printer(path):
class ListToolsAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
from debbindiff.comparators.utils import tool_required, RequiredToolNotFound
from debbindiff import tool_required, RequiredToolNotFound
print("External tools required:")
print(', '.join(tool_required.all))
print()
......
......@@ -18,6 +18,7 @@
# along with debbindiff. If not, see <http://www.gnu.org/licenses/>.
import logging
from distutils.spawn import find_executable
VERSION = "11"
......@@ -28,3 +29,57 @@ ch.setLevel(logging.DEBUG)
logger.addHandler(ch)
formatter = logging.Formatter('%(levelname)8s %(message)s')
ch.setFormatter(formatter)
class RequiredToolNotFound(Exception):
PROVIDERS = { 'ar': { 'debian': 'binutils-multiarch' }
, 'bzip2': { 'debian': 'bzip2' }
, 'cpio': { 'debian': 'cpio' }
, 'diff': { 'debian': 'diffutils' }
, 'file': { 'debian': 'file' }
, 'getfacl': { 'debian': 'acl' }
, 'ghc': { 'debian': 'ghc' }
, 'gpg': { 'debian': 'gnupg' }
, 'gzip': { 'debian': 'gzip' }
, 'ls': { 'debian': 'coreutils' }
, 'lsattr': { 'debian': 'e2fsprogs' }
, 'msgunfmt': { 'debian': 'gettext' }
, 'objdump': { 'debian': 'binutils-multiarch' }
, 'pdftk': { 'debian': 'pdftk' }
, 'pdftotext': { 'debian': 'poppler-utils' }
, 'readelf': { 'debian': 'binutils-multiarch' }
, 'rpm2cpio': { 'debian': 'rpm2cpio' }
, 'showttf': { 'debian': 'fontforge-extras' }
, 'sng': { 'debian': 'sng' }
, 'stat': { 'debian': 'coreutils' }
, 'unsquashfs': { 'debian': 'squashfs-tools' }
, 'xxd': { 'debian': 'vim-common' }
, 'xz': { 'debian': 'xz-utils' }
, 'zipinfo': { 'debian': 'unzip' }
}
def __init__(self, command):
self.command = command
def get_package(self):
providers = RequiredToolNotFound.PROVIDERS.get(self.command, None)
if not providers:
return None
# XXX: hardcode Debian for now
return providers['debian']
# decorator that checks if the specified tool is installed
def tool_required(command):
if not hasattr(tool_required, 'all'):
tool_required.all = set()
tool_required.all.add(command)
def wrapper(original_function):
if find_executable(command):
def tool_check(*args, **kwargs):
return original_function(*args, **kwargs)
else:
def tool_check(*args, **kwargs):
raise RequiredToolNotFound(command)
return tool_check
return wrapper
......@@ -30,5 +30,4 @@ def compare_binary_files(path1, path2, source=None):
hexdump2 = get_hexdump(path2)
if hexdump1 == hexdump2:
return []
return [Difference(hexdump1.splitlines(1), hexdump2.splitlines(1),
path1, path2, source)]
return [Difference(hexdump1, hexdump2, path1, path2, source)]
......@@ -21,8 +21,9 @@ from contextlib import contextmanager
import os.path
import subprocess
import debbindiff.comparators
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
from debbindiff.difference import get_source
from debbindiff import tool_required
@contextmanager
......
......@@ -45,12 +45,10 @@ def compare_changes_files(path1, path2, source=None):
differences = []
for field in DOT_CHANGES_FIELDS:
if dot_changes1[field] != dot_changes2[field]:
lines1 = dot_changes1[field].splitlines(1)
lines2 = dot_changes2[field].splitlines(1)
lines1[0] = "%s: %s" % (field, lines1[0])
lines2[0] = "%s: %s" % (field, lines2[0])
content1 = "%s: %s" % (field, dot_changes1[field])
content2 = "%s: %s" % (field, dot_changes2[field])
differences.append(Difference(
lines1, lines2,
content1, content2,
dot_changes1.get_changes_file(),
dot_changes2.get_changes_file(),
source=source))
......@@ -64,8 +62,8 @@ def compare_changes_files(path1, path2, source=None):
return differences
files_difference = Difference(
dot_changes1.get_as_string('Files').splitlines(1),
dot_changes2.get_as_string('Files').splitlines(1),
dot_changes1.get_as_string('Files'),
dot_changes2.get_as_string('Files'),
dot_changes1.get_changes_file(),
dot_changes2.get_changes_file(),
source=source,
......
......@@ -20,8 +20,8 @@
import subprocess
import os.path
import debbindiff.comparators
from debbindiff import logger
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff import logger, tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
from debbindiff.difference import Difference
......@@ -54,8 +54,7 @@ def compare_cpio_files(path1, path2, source=None):
content2 = get_cpio_content(path2, verbose=True)
if content1 != content2:
differences.append(Difference(
content1.splitlines(1), content2.splitlines(1),
path1, path2, source="metadata"))
content1, content2, path1, path2, source="metadata"))
# compare files contained in archive
content1 = get_cpio_content(path1, verbose=False)
......
......@@ -57,8 +57,7 @@ def compare_deb_files(path1, path2, source=None):
content2 = get_ar_content(path2)
if content1 != content2:
differences.append(Difference(
content1.splitlines(1), content2.splitlines(1),
path1, path2, source="metadata"))
content1, content2, path1, path2, source="metadata"))
return differences
......
......@@ -20,9 +20,8 @@
import os.path
import re
import subprocess
from debbindiff import logger
from debbindiff import logger, tool_required
from debbindiff.difference import Difference
from debbindiff.comparators.utils import tool_required
import debbindiff.comparators
......@@ -63,8 +62,7 @@ def compare_meta(path1, path2):
stat2 = stat(path2)
if stat1 != stat2:
differences.append(Difference(
stat1.splitlines(1), stat2.splitlines(1),
path1, path2, source="stat"))
stat1, stat2, path1, path2, source="stat"))
except RequiredToolNotFound:
logger.warn("'stat' not found! Is PATH wrong?")
......@@ -73,8 +71,7 @@ def compare_meta(path1, path2):
lsattr2 = lsattr(path2)
if lsattr1 != lsattr2:
differences.append(Difference(
lsattr1.splitlines(1), lsattr2.splitlines(1),
path1, path2, source="lattr"))
lsattr1, lsattr2, path1, path2, source="lattr"))
except RequiredToolNotFound:
logger.info("Unable to find 'lsattr'.")
......@@ -83,8 +80,7 @@ def compare_meta(path1, path2):
acl2 = getfacl(path2)
if acl1 != acl2:
differences.append(Difference(
acl1.splitlines(1), acl2.splitlines(1),
path1, path2, source="getfacl"))
acl1, acl2, path1, path2, source="getfacl"))
except RequiredToolNotFound:
logger.info("Unable to find 'getfacl'.")
return differences
......@@ -112,9 +108,7 @@ def compare_directories(path1, path2, source=None):
ls1 = sorted(ls(path1))
ls2 = sorted(ls(path2))
if ls1 != ls2:
differences.append(Difference(
ls1.splitlines(1), ls2.splitlines(1),
path1, path2, source="ls"))
differences.append(Difference(ls1, ls2, path1, path2, source="ls"))
differences.extend(compare_meta(path1, path2))
if differences:
d = Difference(None, None, path1, path2, source=source)
......
......@@ -20,7 +20,8 @@
import os.path
import re
import subprocess
from debbindiff.comparators.utils import binary_fallback, get_ar_content, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback, get_ar_content
from debbindiff.difference import Difference
......@@ -59,19 +60,18 @@ def _compare_elf_data(path1, path2, source=None):
all2 = readelf_all(path2)
if all1 != all2:
differences.append(Difference(
all1.splitlines(1), all2.splitlines(1),
path1, path2, source='readelf --all'))
all1, all2, path1, path2, source='readelf --all'))
debug_dump1 = readelf_debug_dump(path1)
debug_dump2 = readelf_debug_dump(path2)
if debug_dump1 != debug_dump2:
differences.append(Difference(
debug_dump1.splitlines(1), debug_dump2.splitlines(1),
debug_dump1, debug_dump2,
path1, path2, source='readelf --debug-dump'))
objdump1 = objdump_disassemble(path1)
objdump2 = objdump_disassemble(path2)
if objdump1 != objdump2:
differences.append(Difference(
objdump1.splitlines(1), objdump2.splitlines(1),
objdump1, objdump2,
path1, path2, source='objdump --disassemble --full-contents'))
return differences
......@@ -89,7 +89,6 @@ def compare_static_lib_files(path1, path2, source=None):
content2 = get_ar_content(path2)
if content1 != content2:
differences.append(Difference(
content1.splitlines(1), content2.splitlines(1),
path1, path2, source="metadata"))
content1, content2, path1, path2, source="metadata"))
differences.extend(_compare_elf_data(path1, path2, source))
return differences
......@@ -19,7 +19,8 @@
import locale
import subprocess
from debbindiff.comparators.utils import binary_fallback, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback
from debbindiff.difference import Difference
......@@ -33,6 +34,5 @@ def compare_ttf_files(path1, path2, source=None):
ttf1 = show_ttf(path1)
ttf2 = show_ttf(path2)
if ttf1 != ttf2:
return [Difference(ttf1.splitlines(1), ttf2.splitlines(1),
path1, path2, source='showttf')]
return [Difference(ttf1, ttf2, path1, path2, source='showttf')]
return []
......@@ -18,7 +18,8 @@
# along with debbindiff. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from debbindiff.comparators.utils import binary_fallback, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback
from debbindiff.difference import Difference
......@@ -32,6 +33,5 @@ def compare_mo_files(path1, path2, source=None):
mo1 = msgunfmt(path1)
mo2 = msgunfmt(path2)
if mo1 != mo2:
return [Difference(mo1.splitlines(1), mo2.splitlines(1),
path1, path2, source='msgunfmt')]
return [Difference(mo1, mo2, path1, path2, source='msgunfmt')]
return []
......@@ -21,7 +21,8 @@ from contextlib import contextmanager
import subprocess
import os.path
import debbindiff.comparators
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
from debbindiff.difference import Difference, get_source
......@@ -53,8 +54,7 @@ def compare_gzip_files(path1, path2, source=None):
metadata2 = get_gzip_metadata(path2)
if metadata1 != metadata2:
differences.append(Difference(
metadata1.splitlines(1), metadata2.splitlines(1),
path1, path2, source='metadata'))
metadata1, metadata2, path1, path2, source='metadata'))
# check content
with decompress_gzip(path1) as new_path1:
with decompress_gzip(path2) as new_path2:
......
......@@ -18,7 +18,8 @@
# along with debbindiff. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from debbindiff.comparators.utils import binary_fallback, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback
from debbindiff.difference import Difference
......@@ -32,6 +33,6 @@ def compare_hi_files(path1, path2, source=None):
iface1 = show_iface(path1)
iface2 = show_iface(path2)
if iface1 != iface2:
return [Difference(iface1.splitlines(1), iface2.splitlines(1),
return [Difference(iface1, iface2,
path1, path2, source='ghc --show-iface')]
return []
......@@ -18,7 +18,8 @@
# along with debbindiff. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from debbindiff.comparators.utils import binary_fallback, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback
from debbindiff.difference import Difference, get_source
......@@ -45,14 +46,12 @@ def compare_pdf_files(path1, path2, source=None):
text2 = pdftotext(path2)
if text1 != text2:
differences.append(
Difference(text1.splitlines(1), text2.splitlines(1),
text1, text2,
Difference(text1, text2, path1, path2,
source="pdftotext %s" % src))
uncompressed1 = uncompress(path1)
uncompressed2 = uncompress(path2)
if uncompressed1 != uncompressed2:
differences.append(
Difference(uncompressed1.splitlines(1), uncompressed2.splitlines(1),
path1, path2,
Difference(uncompressed1, uncompressed2, path1, path2,
source="pdftk %s output - uncompress" % src))
return differences
......@@ -18,7 +18,8 @@
# along with debbindiff. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from debbindiff.comparators.utils import binary_fallback, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback
from debbindiff.difference import Difference
......@@ -38,7 +39,6 @@ def compare_png_files(path1, path2, source=None):
sng1 = sng(path1)
sng2 = sng(path2)
if sng1 != sng2:
return [Difference(sng1.splitlines(1), sng2.splitlines(1),
path1, path2, source='sng')]
return [Difference(sng1, sng2, path1, path2, source='sng')]
return []
......@@ -22,8 +22,8 @@ import os.path
import subprocess
from contextlib import contextmanager
import debbindiff.comparators
from debbindiff import logger
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff import logger, tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
from debbindiff.difference import Difference, get_source
def get_rpm_header(path, ts):
......@@ -82,8 +82,7 @@ def compare_rpm_files(path1, path2, source=None):
header2 = get_rpm_header(path2, ts)
if header1 != header2:
differences.append(Difference(
header1.splitlines(1), header2.splitlines(2),
path1, path2, source="header"))
header1, header2, path1, path2, source="header"))
# extract cpio archive
with extract_rpm_payload(path1) as archive1:
......
......@@ -20,8 +20,8 @@
import subprocess
import os.path
import debbindiff.comparators
from debbindiff import logger
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff import logger, tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
from debbindiff.difference import Difference
......@@ -58,8 +58,7 @@ def compare_squashfs_files(path1, path2, source=None):
content2 = get_squashfs_content(path2)
if content1 != content2:
differences.append(Difference(
content1.splitlines(1), content2.splitlines(1),
path1, path2, source="metadata"))
content1, content2, path1, path2, source="metadata"))
# compare files contained in archive
content1 = get_squashfs_content(path1, verbose=False)
......
......@@ -70,6 +70,5 @@ def compare_tar_files(path1, path2, source=None):
content2 = get_tar_content(tar2).decode('utf-8')
if content1 != content2:
differences.append(Difference(
content1.splitlines(1), content2.splitlines(1),
path1, path2, source="metadata"))
content1, content2, path1, path2, source="metadata"))
return differences
......@@ -26,11 +26,11 @@ def compare_text_files(path1, path2, encoding, source=None):
if encoding is None:
encoding = 'utf-8'
try:
lines1 = codecs.open(path1, 'r', encoding=encoding).readlines()
lines2 = codecs.open(path2, 'r', encoding=encoding).readlines()
content1 = codecs.open(path1, 'r', encoding=encoding).read()
content2 = codecs.open(path2, 'r', encoding=encoding).read()
except (LookupError, UnicodeDecodeError):
# unknown or misdetected encoding
return compare_binary_files(path1, path2, source)
if lines1 == lines2:
if content1 == content2:
return []
return [Difference(lines1, lines2, path1, path2, source)]
return [Difference(content1, content2, path1, path2, source)]
......@@ -19,7 +19,6 @@
from contextlib import contextmanager
# The following would be shutil.which in Python 3.3
from distutils.spawn import find_executable
import hashlib
import re
import os
......@@ -83,60 +82,6 @@ def binary_fallback(original_function):
return with_fallback
class RequiredToolNotFound(Exception):
PROVIDERS = { 'ar': { 'debian': 'binutils-multiarch' }
, 'bzip2': { 'debian': 'bzip2' }
, 'cpio': { 'debian': 'cpio' }
, 'file': { 'debian': 'file' }
, 'getfacl': { 'debian': 'acl' }
, 'ghc': { 'debian': 'ghc' }
, 'gpg': { 'debian': 'gnupg' }
, 'gzip': { 'debian': 'gzip' }
, 'ls': { 'debian': 'coreutils' }
, 'lsattr': { 'debian': 'e2fsprogs' }
, 'msgunfmt': { 'debian': 'gettext' }
, 'objdump': { 'debian': 'binutils-multiarch' }
, 'pdftk': { 'debian': 'pdftk' }
, 'pdftotext': { 'debian': 'poppler-utils' }
, 'readelf': { 'debian': 'binutils-multiarch' }
, 'rpm2cpio': { 'debian': 'rpm2cpio' }
, 'showttf': { 'debian': 'fontforge-extras' }
, 'sng': { 'debian': 'sng' }
, 'stat': { 'debian': 'coreutils' }
, 'unsquashfs': { 'debian': 'squashfs-tools' }
, 'vim': { 'debian': 'vim' }
, 'xxd': { 'debian': 'vim-common' }
, 'xz': { 'debian': 'xz-utils' }
, 'zipinfo': { 'debian': 'unzip' }
}
def __init__(self, command):
self.command = command
def get_package(self):
providers = RequiredToolNotFound.PROVIDERS.get(self.command, None)
if not providers:
return None
# XXX: hardcode Debian for now
return providers['debian']
# decorator that checks if the specified tool is installed
def tool_required(command):
if not hasattr(tool_required, 'all'):
tool_required.all = set()
tool_required.all.add(command)
def wrapper(original_function):
if find_executable(command):
def tool_check(*args, **kwargs):
return original_function(*args, **kwargs)
else:
def tool_check(*args, **kwargs):
raise RequiredToolNotFound(command)
return tool_check
return wrapper
@contextmanager
def make_temp_directory():
temp_dir = tempfile.mkdtemp(suffix='debbindiff')
......
......@@ -21,7 +21,8 @@ from contextlib import contextmanager
import os.path
import subprocess
import debbindiff.comparators
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
from debbindiff.difference import get_source
......
......@@ -24,7 +24,8 @@ from zipfile import ZipFile
from debbindiff import logger
from debbindiff.difference import Difference
import debbindiff.comparators
from debbindiff.comparators.utils import binary_fallback, make_temp_directory, tool_required
from debbindiff import tool_required
from debbindiff.comparators.utils import binary_fallback, make_temp_directory
@tool_required('zipinfo')
......@@ -71,6 +72,5 @@ def compare_zip_files(path1, path2, source=None):
zipinfo2 = get_zipinfo(path2, verbose=True)
if zipinfo1 != zipinfo2:
differences.append(Difference(
zipinfo1.splitlines(1), zipinfo2.splitlines(1),
path1, path2, source="metadata"))
zipinfo1, zipinfo2, path1, path2, source="metadata"))
return differences
......@@ -18,15 +18,134 @@
# along with debbindiff. If not, see <http://www.gnu.org/licenses/>.
import os.path
from functools import partial
from tempfile import NamedTemporaryFile
import re
import subprocess
from debbindiff import logger, tool_required, RequiredToolNotFound
MAX_DIFF_BLOCK_LINES = 50
class DiffParser(object):
RANGE_RE = re.compile(r'^@@\s+-(?P<start1>\d+)(,(?P<len1>\d+))?\s+\+(?P<start2>\d+)(,(?P<len2>\d+))?\s+@@$')
def __init__(self, output):
self._output = output
self._action = self.read_headers
self._diff = ''
self._remaining_hunk_lines = None
self._block_len = None
self._direction = None
def parse(self):
while True:
line = self._output.readline().decode('utf-8')
if line == '': # EOF
return self._diff
self._action = self._action(line)
def read_headers(self, line):
found = DiffParser.RANGE_RE.match(line)
if line.startswith('---'):
return self.read_headers
elif line.startswith('+++'):
return self.read_headers
elif not found:
raise ValueError('Unable to parse diff headers: %s' % repr(line))
self._diff += line
if found.group('len1'):
self._remaining_hunk_lines = int(found.group('len1'))
else:
self._remaining_hunk_lines = 1
if found.group('len2'):
self._remaining_hunk_lines += int(found.group('len2'))
else:
self._remaining_hunk_lines += 1
self._direction = None
return self.read_hunk
def read_hunk(self, line):
if line[0] == ' ':
self._remaining_hunk_lines -= 2
elif line[0] == '+':
self._remaining_hunk_lines -= 1
elif line[0] == '-':
self._remaining_hunk_lines -= 1
elif line[0] == '\\':
pass
elif self._remaining_hunk_lines == 0:
return self.read_headers(line)
else:
raise ValueError('Unable to parse diff hunk: %s' % repr(line))
self._diff += line
if line[0] in ('-', '+') and line[0] == self._direction:
self._block_len += 1
if self._block_len >= MAX_DIFF_BLOCK_LINES:
return self.skip_block
else:
self._block_len = 1
self._direction = line[0]
return self.read_hunk
def skip_block(self, line):
if not line.startswith(self._direction):
self._diff += '%s[ %d lines removed ]\n' % (self._direction, self._block_len - MAX_DIFF_BLOCK_LINES)
return self.read_hunk(line)
self._block_len += 1
self._remaining_hunk_lines -= 1
if self._remaining_hunk_lines == 0:
self._diff += '%s[ %d lines removed ]\n' % (self._direction, self._block_len - MAX_DIFF_BLOCK_LINES)
return self.read_headers
return self.skip_block
@tool_required('diff')
def diff(content1, content2):
with NamedTemporaryFile('w') as tmp_file1:
with NamedTemporaryFile('w') as tmp_file2:
# fill temporary files
tmp_file1.write(content1.encode('utf-8'))
tmp_file2.write(content2.encode('utf-8'))
# work-around unified diff limitation: if there's no newlines in both
# don't make it a difference
if content1[-1] != '\n' and content2[-1] != '\n':
tmp_file1.write('\n')
tmp_file2.write('\n')
tmp_file1.flush()
tmp_file2.flush()
# run diff
logger.debug('running diff')
cmd = ['diff', '-au7', tmp_file1.name, tmp_file2.name]
p = subprocess.Popen(cmd, shell=False,
close_fds=True, stdin=None, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# parse ouptut
logger.debug('parsing diff output')
diff = DiffParser(p.stdout).parse()
p.wait()
if p.returncode not in (0, 1):
raise subprocess.CalledProcessError(cmd, p.returncode, output=diff)
return diff
class Difference(object):
def __init__(self, lines1, lines2, path1, path2, source=None,
def __init__(self, content1, content2, path1, path2, source=None,
comment=None):
if lines1 and type(lines1[0]) is not unicode:
raise UnicodeError('lines1 has not been decoded')
if lines2 and type(lines2[0]) is not unicode:
raise UnicodeError('lines2 has not been decoded')
self._comment = comment
if content1 and type(content1) is not unicode:
raise UnicodeError('content1 has not been decoded')
if content2 and type(content2) is not unicode:
raise UnicodeError('content2 has not been decoded')
self._unified_diff = None
if content1 is not None and content2 is not None:
try:
self._unified_diff = diff(content1, content2)
except RequiredToolNotFound:
self._comment = 'diff is not available!'
if comment:
self._comment += '\n\n' + comment
# allow to override declared file paths, useful when comparing
# tempfiles
if source:
......@@ -38,9 +157,6 @@ class Difference(object):
else:
self._source1 = path1
self._source2 = path2
self._lines1 = lines1
self._lines2 = lines2
self._comment = comment
self._details = []
@property
......@@ -60,12 +176,8 @@ class Difference(object):
return self._source2
@property
def lines1(self):
return self._lines1
@property
def lines2(self):
return self._lines2
def unified_diff(self):
return self._unified_diff
@property
def details(self):
......
This diff is collapsed.
......@@ -29,21 +29,9 @@ def print_difference(difference, print_func):
if difference.comment:
for line in difference.comment.split('\n'):
print_func(u"│┄ %s" % line)
if difference.lines1 or difference.lines2:
if difference.lines1 and not difference.lines1[-1].endswith('\n'):
difference.lines1[-1] = difference.lines1[-1] + '\n'
difference.lines1.append('<No newline at the end>\n')