Skip to content
Commits on Source (7)
......@@ -20,8 +20,10 @@
import io
import os
import sys
import shlex
import logging
import binascii
import subprocess
from diffoscope.tools import tool_required
from diffoscope.exc import RequiredToolNotFound
......@@ -111,6 +113,9 @@ def compare_files(file1, file2, source=None, diff_content_only=False):
specialize(file1)
specialize(file2)
call_difftool(file1, file2)
if isinstance(file1, MissingFile):
file1.other_file = file2
elif isinstance(file2, MissingFile):
......@@ -123,6 +128,25 @@ def compare_files(file1, file2, source=None, diff_content_only=False):
return file1.compare(file2, source)
def call_difftool(file1, file2):
"""
Call an external difftool one-by-one, similar to git-difftool(1).
"""
if Config().difftool is None:
return
a = '/dev/null' if isinstance(file1, MissingFile) else file1.path
b = '/dev/null' if isinstance(file2, MissingFile) else file2.path
if os.path.isdir(a) or os.path.isdir(b):
return
cmd = " ".join((Config().difftool, shlex.quote(a), shlex.quote(b)))
logger.debug("Calling external command %r", cmd)
subprocess.call(cmd, shell=True)
def bail_if_non_existing(*paths):
if not all(map(os.path.lexists, paths)):
for path in paths:
......
......@@ -55,6 +55,7 @@ class Config:
self.max_text_report_size = 0
self.difftool = None
self.new_file = False
self.fuzzy_threshold = 60
self.enforce_constraints = True
......
......@@ -202,6 +202,13 @@ def create_parser():
dest='restructuredtext_output',
help='Write RsT text output to given file (use - for stdout)',
)
group1.add_argument(
'--difftool',
metavar='TOOL',
dest='difftool',
help='Compare differences one-by-one using the specified external '
'command similar to git-difftool(1)',
)
group1.add_argument(
'--profile',
metavar='OUTPUT_FILE',
......@@ -257,14 +264,6 @@ def create_parser():
'effect even with --no-default-limits)',
default=str(Config().max_page_size_child),
).completer = RangeCompleter(Config().max_page_size_child)
# TODO: old flag kept for backwards-compat, drop 6 months after v84
group2.add_argument(
'--max-report-size-child',
metavar='BYTES',
type=int,
help=argparse.SUPPRESS,
default=None,
)
group2.add_argument(
'--max-page-diff-block-lines',
metavar='LINES',
......@@ -277,14 +276,6 @@ def create_parser():
'effect even with --no-default-limits)',
default=Config().max_page_diff_block_lines,
).completer = RangeCompleter(Config().max_page_diff_block_lines)
# TODO: old flag kept for backwards-compat, drop 6 months after v84
group2.add_argument(
"--max-diff-block-lines-parent",
metavar='LINES',
type=int,
help=argparse.SUPPRESS,
default=None,
)
group3 = parser.add_argument_group('diff calculation')
group3.add_argument(
......@@ -594,72 +585,75 @@ class ListDebianSubstvarsAction(argparse._StoreTrueAction):
sys.exit(0)
def maybe_set_limit(config, parsed_args, key):
# apply limits affected by "no-default-limits"
v = getattr(parsed_args, key)
if v is not None:
setattr(config, key, float("inf") if v == 0 else v)
elif parsed_args.no_default_limits:
setattr(config, key, float("inf"))
def run_diffoscope(parsed_args):
"""
(This should not be considered a stable API suitable for external
consumption, and the lack of configuration of globals may result in
unpredictable behaviour.)
"""
def configure(parsed_args):
for x in (
"max_report_size",
"max_text_report_size",
"max_diff_block_lines",
"max_diff_block_lines_saved",
"max_diff_input_lines",
):
# Apply limits affected by "no-default-limits"
v = getattr(parsed_args, x)
if v is not None:
setattr(Config(), x, float("inf") if v == 0 else v)
logger.debug("Starting diffoscope %s", VERSION)
elif parsed_args.no_default_limits:
setattr(Config(), x, float("inf"))
ProfileManager().setup(parsed_args)
PresenterManager().configure(parsed_args)
if not tlsh:
logger.warning(
'Fuzzy-matching is currently disabled as the "tlsh" module is unavailable.'
)
maybe_set_limit(Config(), parsed_args, "max_report_size")
maybe_set_limit(Config(), parsed_args, "max_text_report_size")
maybe_set_limit(Config(), parsed_args, "max_diff_block_lines")
Config().max_page_size = parsed_args.max_page_size
# TODO: old flag kept for backwards-compat, drop 6 months after v84
if parsed_args.max_report_size_child is not None:
logger.warning(
"Detected deprecated flag --max-report-size-child; use --max-page-size-child instead."
)
Config().max_page_size_child = parsed_args.max_report_size_child
Config().max_page_size_child = parsed_args.max_page_size_child
# TODO: old flag kept for backwards-compat, drop 6 months after v84
if parsed_args.max_diff_block_lines_parent is not None:
logger.warning(
"Detected deprecated flag --max-diff-block-lines-parent; use --max-page-diff-block-lines instead."
)
logger.warning(
"Note that the new flag --max-page-diff-block-lines also applies to --html output."
)
Config().max_page_diff_block_lines = (
parsed_args.max_diff_block_lines_parent
)
Config().max_page_diff_block_lines = parsed_args.max_page_diff_block_lines
maybe_set_limit(Config(), parsed_args, "max_diff_block_lines_saved")
maybe_set_limit(Config(), parsed_args, "max_diff_input_lines")
Config().max_container_depth = parsed_args.max_container_depth
Config().difftool = parsed_args.difftool
Config().new_file = parsed_args.new_file
Config().use_dbgsym = parsed_args.use_dbgsym
Config().force_details = parsed_args.force_details
Config().fuzzy_threshold = parsed_args.fuzzy_threshold
Config().new_file = parsed_args.new_file
Config().max_container_depth = parsed_args.max_container_depth
Config().excludes = parsed_args.excludes
Config().exclude_commands = parsed_args.exclude_commands
Config().exclude_directory_metadata = (
parsed_args.exclude_directory_metadata
)
Config().compute_visual_diffs = PresenterManager().compute_visual_diffs()
Config().check_constraints()
tool_prepend_prefix(
parsed_args.tool_prefix_binutils,
*"ar as ld ld.bfd nm objcopy objdump ranlib readelf strip".split(),
'ar',
'as',
'ld',
'ld.bfd',
'nm',
'objcopy',
'objdump',
'ranlib',
'readelf',
'strip',
)
Config().check_constraints()
def run_diffoscope(parsed_args):
"""
(This should not be considered a stable API suitable for external
consumption, and the lack of configuration of globals may result in
unpredictable behaviour.)
"""
logger.debug("Starting diffoscope %s", VERSION)
ProfileManager().setup(parsed_args)
PresenterManager().configure(parsed_args)
if not tlsh:
logger.warning(
'Fuzzy-matching is currently disabled as the "tlsh" module is unavailable.'
)
configure(parsed_args)
set_path()
normalize_environment()
path1, path2 = parsed_args.path1, parsed_args.path2
......@@ -712,7 +706,7 @@ def main(args=None):
signal.signal(signal.SIGTERM, sigterm_handler)
try:
import libarchive
import libarchive # noqa
except (ImportError, AttributeError):
traceback.print_exc()
python_module_missing('libarchive')
......