# 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/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_),
#             )


import re
import io
import os
import errno
import fcntl
import hashlib
import logging
import threading
import subprocess
from multiprocessing.dummy import Queue
from diffoscope.tempfiles import get_temporary_directory
from .tools import tool_required
from .config import Config
#
# You should have received a copy of the GNU General Public License
# along with diffoscope.  If not, see <https://www.gnu.org/licenses/>.





DIFF_CHUNK = 4096

logger = logging.getLogger(__name__)
re_diff_change = re.compile(r'^([+-@]).*', re.MULTILINE)


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, end_nl_q1, end_nl_q2):
        self._output = output
        self._end_nl_q1 = end_nl_q1
        self._end_nl_q2 = end_nl_q2
        self._action = self.read_headers
        self._diff = io.StringIO()
        self._success = False
        self._remaining_hunk_lines = None
        self._block_len = None
        self._direction = None
        self._end_nl = 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/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/diff.py
import re
import io
import os
import errno
import fcntl
import hashlib
import logging
import threading
import subprocess
from multiprocessing.dummy import Queue
from diffoscope.tempfiles import get_temporary_directory
from .tools import tool_required
from .config import Config

#
# You should have received a copy of the GNU General Public License
# along with diffoscope.  If not, see <https://www.gnu.org/licenses/>.





DIFF_CHUNK = 4096

logger = logging.getLogger(__name__)
re_diff_change = re.compile(r'^([+-@]).*', re.MULTILINE)


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, end_nl_q1, end_nl_q2):
        self._output = output
        self._end_nl_q1 = end_nl_q1
        self._end_nl_q2 = end_nl_q2
        self._action = self.read_headers
        self._diff = io.StringIO()
        self._success = False
        self._remaining_hunk_lines = None
        self._block_len = None
        self._direction = None
        self._end_nl = None

        self._max_lines = Config().max_diff_block_lines_saved