# Path: diffoscope/tools.py
# def tool_required(command):
#     """
#     Decorator that checks if the specified tool is installed
#     """
#     if not hasattr(tool_required, 'all'):
#         tool_required.all = set()
#     tool_required.all.add(command)
#     def wrapper(original_function):
#         if find_executable(command):
#             @functools.wraps(original_function)
#             def tool_check(*args, **kwargs):
#                 with profile('command', command):
#                     return original_function(*args, **kwargs)
#         else:
#             @functools.wraps(original_function)
#             def tool_check(*args, **kwargs):
#                 from .exc import RequiredToolNotFound
#                 raise RequiredToolNotFound(command)
#         return tool_check
#     return wrapper
# 
# Path: diffoscope/exc.py
# class RequiredToolNotFound(Exception):
#     def __init__(self, command):
#         self.command = command
# 
#     def get_package(self):
#         try:
#             providers = EXTERNAL_TOOLS[self.command]
#         except KeyError:  # noqa
#             return None
# 
#         return providers.get(get_current_os(), None)
# 
# Path: diffoscope/config.py
# class Config(object):
#     max_diff_block_lines = 256
#     max_diff_block_lines_parent = 50
#     max_diff_block_lines_saved = float("inf")
#     # html-dir output uses ratio * max-diff-block-lines as its limit
#     max_diff_block_lines_html_dir_ratio = 4
#     # GNU diff cannot process arbitrary large files :(
#     max_diff_input_lines = 2 ** 20
#     max_report_size = 2000 * 2 ** 10 # 2000 kB
#     max_text_report_size = 0
#     max_report_child_size = 500 * 2 ** 10
#     new_file = False
#     fuzzy_threshold = 60
#     enforce_constraints = True
#     excludes = ()
# 
#     _singleton = {}
# 
#     def __init__(self):
#         self.__dict__ = self._singleton
# 
#     def __setattr__(self, k, v):
#         super(Config, self).__setattr__(k, v)
# 
#         if self.enforce_constraints:
#             self.check_constraints()
# 
#     def check_constraints(self):
#         if self.max_diff_block_lines < self.max_diff_block_lines_parent:  # noqa
#             raise ValueError("max_diff_block_lines ({0.max_diff_block_lines}) "
#                 "cannot be smaller than max_diff_block_lines_parent "
#                 "({0.max_diff_block_lines_parent})".format(self),
#             )
# 
#         max_ = self.max_diff_block_lines_html_dir_ratio * \
#             self.max_diff_block_lines
#         if self.max_diff_block_lines_saved < max_:  # noqa
#             raise ValueError("max_diff_block_lines_saved "
#                 "({0.max_diff_block_lines_saved}) cannot be smaller than "
#                 "{0.max_diff_block_lines_html_dir_ratio} * "
#                 "max_diff_block_lines ({1})".format(self, max_),
#             )
# 
# Path: diffoscope/excludes.py
# def any_excluded(*filenames):
#     return len(filter_excludes(filenames)) != len(filenames)
# 
# Path: diffoscope/comparators/utils/specialize.py
# def specialize(file):
#     for cls in ComparatorManager().classes:
#         if isinstance(file, cls):
#             return file
# 
#         # Does this file class match?
#         flag = False
#         if hasattr(cls, 'recognizes'):
#             with profile('recognizes', file):
#                 flag = cls.recognizes(file)
#         else:
#             re_tests = [(x, y) for x, y in (
#                 (cls.RE_FILE_TYPE, file.magic_file_type),
#                 (cls.RE_FILE_EXTENSION, file.name),
#             ) if x]
# 
#             # If neither are defined, it's *not* a match.
#             if re_tests:
#                 flag = all(x.search(y) for x, y in re_tests)
# 
#         if not flag:
#             continue
# 
#         # Found a match; perform type magic
#         logger.debug("Using %s for %s", cls.__name__, file.name)
#         new_cls = type(cls.__name__, (cls, type(file)), {})
#         file.__class__ = new_cls
# 
#         return file
# 
#     logger.debug("Unidentified file. Magic says: %s", file.magic_file_type)
# 
#     return file


import io
import os
import sys
import logging
import binascii
    import tlsh
from diffoscope.tools import tool_required
from diffoscope.exc import RequiredToolNotFound
from diffoscope.config import Config
from diffoscope.excludes import any_excluded
from diffoscope.profiling import profile
from diffoscope.difference import Difference
from ..missing_file import MissingFile
from .command import Command
from .specialize import specialize
    from ..directory import FilesystemDirectory, FilesystemFile, compare_directories
def compare_root_paths(path1, path2):

    if not Config().new_file:
        bail_if_non_existing(path1, path2)
    if any_excluded(path1, path2):
        return None
    if os.path.isdir(path1) and os.path.isdir(path2):
        return compare_directories(path1, path2)
    container1 = FilesystemDirectory(os.path.dirname(path1)).as_container
    file1 = specialize(FilesystemFile(path1, container=container1))
    container2 = FilesystemDirectory(os.path.dirname(path2)).as_container
    file2 = specialize(FilesystemFile(path2, container=container2))
    return compare_files(file1, file2)

def compare_files(file1, file2, source=None):
    logger.debug(
        "Comparing %s (%s) and %s (%s)",
        file1.name,
        file1.__class__.__name__,
        file2.name,
        file2.__class__.__name__,
    )

    if any_excluded(file1.name, file2.name):
        return None

    with profile('has_same_content_as', file1):
        if file1.has_same_content_as(file2):
            logger.debug("has_same_content_as returned True; skipping further comparisons")
            return None

# Path: diffoscope/tools.py
# def tool_required(command):
#     """
#     Decorator that checks if the specified tool is installed
#     """
#     if not hasattr(tool_required, 'all'):
#         tool_required.all = set()
#     tool_required.all.add(command)
#     def wrapper(original_function):
#         if find_executable(command):
#             @functools.wraps(original_function)
#             def tool_check(*args, **kwargs):
#                 with profile('command', command):
#                     return original_function(*args, **kwargs)
#         else:
#             @functools.wraps(original_function)
#             def tool_check(*args, **kwargs):
#                 from .exc import RequiredToolNotFound
#                 raise RequiredToolNotFound(command)
#         return tool_check
#     return wrapper
# 
# Path: diffoscope/exc.py
# class RequiredToolNotFound(Exception):
#     def __init__(self, command):
#         self.command = command
# 
#     def get_package(self):
#         try:
#             providers = EXTERNAL_TOOLS[self.command]
#         except KeyError:  # noqa
#             return None
# 
#         return providers.get(get_current_os(), None)
# 
# Path: diffoscope/config.py
# class Config(object):
#     max_diff_block_lines = 256
#     max_diff_block_lines_parent = 50
#     max_diff_block_lines_saved = float("inf")
#     # html-dir output uses ratio * max-diff-block-lines as its limit
#     max_diff_block_lines_html_dir_ratio = 4
#     # GNU diff cannot process arbitrary large files :(
#     max_diff_input_lines = 2 ** 20
#     max_report_size = 2000 * 2 ** 10 # 2000 kB
#     max_text_report_size = 0
#     max_report_child_size = 500 * 2 ** 10
#     new_file = False
#     fuzzy_threshold = 60
#     enforce_constraints = True
#     excludes = ()
# 
#     _singleton = {}
# 
#     def __init__(self):
#         self.__dict__ = self._singleton
# 
#     def __setattr__(self, k, v):
#         super(Config, self).__setattr__(k, v)
# 
#         if self.enforce_constraints:
#             self.check_constraints()
# 
#     def check_constraints(self):
#         if self.max_diff_block_lines < self.max_diff_block_lines_parent:  # noqa
#             raise ValueError("max_diff_block_lines ({0.max_diff_block_lines}) "
#                 "cannot be smaller than max_diff_block_lines_parent "
#                 "({0.max_diff_block_lines_parent})".format(self),
#             )
# 
#         max_ = self.max_diff_block_lines_html_dir_ratio * \
#             self.max_diff_block_lines
#         if self.max_diff_block_lines_saved < max_:  # noqa
#             raise ValueError("max_diff_block_lines_saved "
#                 "({0.max_diff_block_lines_saved}) cannot be smaller than "
#                 "{0.max_diff_block_lines_html_dir_ratio} * "
#                 "max_diff_block_lines ({1})".format(self, max_),
#             )
# 
# Path: diffoscope/excludes.py
# def any_excluded(*filenames):
#     return len(filter_excludes(filenames)) != len(filenames)
# 
# Path: diffoscope/comparators/utils/specialize.py
# def specialize(file):
#     for cls in ComparatorManager().classes:
#         if isinstance(file, cls):
#             return file
# 
#         # Does this file class match?
#         flag = False
#         if hasattr(cls, 'recognizes'):
#             with profile('recognizes', file):
#                 flag = cls.recognizes(file)
#         else:
#             re_tests = [(x, y) for x, y in (
#                 (cls.RE_FILE_TYPE, file.magic_file_type),
#                 (cls.RE_FILE_EXTENSION, file.name),
#             ) if x]
# 
#             # If neither are defined, it's *not* a match.
#             if re_tests:
#                 flag = all(x.search(y) for x, y in re_tests)
# 
#         if not flag:
#             continue
# 
#         # Found a match; perform type magic
#         logger.debug("Using %s for %s", cls.__name__, file.name)
#         new_cls = type(cls.__name__, (cls, type(file)), {})
#         file.__class__ = new_cls
# 
#         return file
# 
#     logger.debug("Unidentified file. Magic says: %s", file.magic_file_type)
# 
#     return file


# Path: diffoscope/comparators/utils/compare.py
import io
import os
import sys
import logging
import binascii
    import tlsh
from diffoscope.tools import tool_required
from diffoscope.exc import RequiredToolNotFound
from diffoscope.config import Config
from diffoscope.excludes import any_excluded
from diffoscope.profiling import profile
from diffoscope.difference import Difference
from ..missing_file import MissingFile
from .command import Command
from .specialize import specialize
    from ..directory import FilesystemDirectory, FilesystemFile, compare_directories

def compare_root_paths(path1, path2):

    if not Config().new_file:
        bail_if_non_existing(path1, path2)
    if any_excluded(path1, path2):
        return None
    if os.path.isdir(path1) and os.path.isdir(path2):
        return compare_directories(path1, path2)
    container1 = FilesystemDirectory(os.path.dirname(path1)).as_container
    file1 = specialize(FilesystemFile(path1, container=container1))
    container2 = FilesystemDirectory(os.path.dirname(path2)).as_container
    file2 = specialize(FilesystemFile(path2, container=container2))
    return compare_files(file1, file2)

def compare_files(file1, file2, source=None):
    logger.debug(
        "Comparing %s (%s) and %s (%s)",
        file1.name,
        file1.__class__.__name__,
        file2.name,
        file2.__class__.__name__,
    )

    if any_excluded(file1.name, file2.name):
        return None

    with profile('has_same_content_as', file1):
        if file1.has_same_content_as(file2):
            logger.debug("has_same_content_as returned True; skipping further comparisons")
            return None

    specialize(file1)