Esempio n. 1
0
def test_size_updates():
    d = Difference("0123456789", "path1", "path2")
    assert_size(d, 20)
    d.add_details([Difference("0123456789", "path1/a", "path2/a")])
    assert_size(d, 44)
    d.add_comment("lol1")
    assert_size(d, 48)
Esempio n. 2
0
 def compare(self, other, source=None):
     differences = []
     try:
         listing_diff = Difference.from_text(
             '\n'.join(list_files(self.path)),
             '\n'.join(list_files(other.path)),
             self.path,
             other.path,
             source='file list')
         if listing_diff:
             differences.append(listing_diff)
     except RequiredToolNotFound:
         logger.info("Unable to find 'getfacl'.")
     differences.extend(compare_meta(self.name, other.name))
     my_container = DirectoryContainer(self)
     other_container = DirectoryContainer(other)
     my_names = my_container.get_member_names()
     other_names = other_container.get_member_names()
     for name in sorted(set(my_names).intersection(other_names)):
         my_file = my_container.get_member(name)
         other_file = other_container.get_member(name)
         inner_difference = diffoscope.comparators.compare_files(
             my_file, other_file, source=name)
         meta_differences = compare_meta(my_file.name, other_file.name)
         if meta_differences and not inner_difference:
             inner_difference = Difference(None, my_file.path,
                                           other_file.path)
         if inner_difference:
             inner_difference.add_details(meta_differences)
             differences.append(inner_difference)
     if not differences:
         return None
     difference = Difference(None, self.path, other.path, source)
     difference.add_details(differences)
     return difference
Esempio n. 3
0
    def compare_details(self, other, source=None):
        """
        Compares self.object with another, returning a Difference object

        Args:
            other    -- A XMLFile object
            source

        Returns:
            A diffoscope.difference.Difference object
        """
        if isinstance(other, MissingFile):
            return [
                Difference(
                    None,
                    self.name,
                    other.name,
                    comment="Trying to compare two non-existing files.",
                )
            ]

        return [
            Difference.from_text(self.dumps(self), self.dumps(other),
                                 self.name, other.name)
        ]
Esempio n. 4
0
def compare_files(file1, file2, source=None, diff_content_only=False):
    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
    if diff_content_only:
        difference = Difference(None, file1.name, file2.name)
        difference.add_comment("Files differ")
        return difference
    specialize(file1)
    specialize(file2)
    if isinstance(file1, MissingFile):
        file1.other_file = file2
    elif isinstance(file2, MissingFile):
        file2.other_file = file1
    elif file1.__class__.__name__ != file2.__class__.__name__:
        return file1.compare_bytes(file2, source)
    with profile('compare_files (cumulative)', file1):
        return file1.compare(file2, source)
Esempio n. 5
0
    def compare(self, other, source=None):
        differences = []

        listing_diff = Difference.from_text(
            '\n'.join(list_files(self.path)),
            '\n'.join(list_files(other.path)),
            self.path,
            other.path,
            source='file list',
        )
        if listing_diff:
            differences.append(listing_diff)

        differences.extend(compare_meta(self.name, other.name))

        my_container = DirectoryContainer(self)
        other_container = DirectoryContainer(other)
        differences.extend(my_container.compare(other_container))

        if not differences:
            return None

        difference = Difference(None, self.path, other.path, source)
        difference.add_details(differences)
        return difference
Esempio n. 6
0
 def compare(self, other, source=None):
     my_encoding = self.encoding or 'utf-8'
     other_encoding = other.encoding or 'utf-8'
     try:
         with codecs.open(self.path, 'r', encoding=my_encoding) as my_content, \
              codecs.open(other.path, 'r', encoding=other_encoding) as other_content:
             difference = Difference.from_text_readers(
                 my_content, other_content, self.name, other.name, source)
             # Check if difference is only in line order.
             if difference and order_only_difference(
                     difference.unified_diff):
                 difference.add_comment("ordering differences only")
             if my_encoding != other_encoding:
                 if difference is None:
                     difference = Difference(None, self.path, other.path,
                                             source)
                 difference.add_details([
                     Difference.from_text(my_encoding,
                                          other_encoding,
                                          None,
                                          None,
                                          source='encoding')
                 ])
             return difference
     except (LookupError, UnicodeDecodeError):
         # unknown or misdetected encoding
         return self.compare_bytes(other, source)
Esempio n. 7
0
def compare_commented_files(file1, file2, comment=None, source=None):
    difference = compare_files(file1, file2, source=source)
    if comment:
        if difference is None:
            difference = Difference(None, file1.name, file2.name)
        difference.add_comment(comment)
    return difference
Esempio n. 8
0
def compare_root_paths(path1, path2):
    from ..directory import (
        FilesystemDirectory,
        FilesystemFile,
        compare_directories,
        compare_meta,
    )

    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))
    difference = compare_files(file1, file2)

    if Config().exclude_directory_metadata in ('no', 'recursive'):
        meta = compare_meta(path1, path2)
        if meta:
            # Create an "empty" difference so we have something to attach file
            # metadata to.
            if difference is None:
                difference = Difference(None, file1.name, file2.name)
            difference.add_details(meta)
    return difference
Esempio n. 9
0
    def compare_details(self, other, source=None):
        sng_diff = Difference.from_command(
            Sng, self.path, other.path, source='sng'
        )
        differences = [sng_diff]

        if (
            sng_diff is not None
            and Config().compute_visual_diffs
            and same_size(self, other)
        ):
            try:
                logger.debug(
                    "Generating visual difference for %s and %s",
                    self.path,
                    other.path,
                )
                content_diff = Difference(
                    None, self.path, other.path, source="Image content"
                )
                content_diff.add_visuals(
                    [
                        pixel_difference(self.path, other.path),
                        flicker_difference(self.path, other.path),
                    ]
                )
                differences.append(content_diff)
            except subprocess.CalledProcessError:  # noqa
                pass

        return differences
Esempio n. 10
0
    def compare_details(self, other, source=None):
        gifbuild_diff = Difference.from_command(
            Gifbuild,
            self.path,
            other.path,
            source="gifbuild",
        )

        differences = [gifbuild_diff]

        if gifbuild_diff is not None and Config().compute_visual_diffs and \
                can_compose_gif_images(self, other):
            try:
                logger.debug(
                    "Generating visual difference for %s and %s",
                    self.path,
                    other.path,
                )
                content_diff = Difference(
                    None,
                    self.path,
                    other.path,
                    source="Image content",
                )
                content_diff.add_visuals([
                    pixel_difference(self.path, other.path),
                    flicker_difference(self.path, other.path),
                ])
                differences.append(content_diff)
            except subprocess.CalledProcessError:  # noqa
                pass

        return differences
Esempio n. 11
0
def test_with_compare_details():
    d = Difference('diff', TEST_FILE1_PATH, TEST_FILE2_PATH, source='source')
    class MockFile(FilesystemFile):
        def compare_details(self, other, source=None):
            return [d]
    difference = MockFile(TEST_FILE1_PATH).compare(MockFile(TEST_FILE2_PATH), source='source')
    assert difference.details[0] == d
Esempio n. 12
0
 def compare_pair(file1, file2, source):
     inner_difference = compare_files(file1, file2, source=source)
     meta_differences = compare_meta(file1.name, file2.name)
     if meta_differences and not inner_difference:
         inner_difference = Difference(None, file1.path, file2.path)
     if inner_difference:
         inner_difference.add_details(meta_differences)
     return inner_difference
Esempio n. 13
0
 def compare_pair(file1, file2, comment):
     difference = compare_files(
         file1, file2, source=None, diff_content_only=no_recurse
     )
     if comment:
         if difference is None:
             difference = Difference(None, file1.name, file2.name)
         difference.add_comment(comment)
     return difference
Esempio n. 14
0
 def _compare_using_details(self, other, source):
     details = []
     if hasattr(self, 'compare_details'):
         details.extend(filter(None, self.compare_details(other, source)))
     if self.as_container:
         details.extend(
             filter(None, self.as_container.compare(other.as_container)))
     if not details:
         return None
     difference = Difference(None, self.name, other.name, source=source)
     difference.add_details(details)
     return difference
Esempio n. 15
0
 def compare_details(self, other, source=None):
     return [
         Difference(None,
                    self.path,
                    other.path,
                    source="md5sums",
                    comment="Files in package differ"),
         Difference.from_text_readers(self.strip_checksum(self.path),
                                      self.strip_checksum(other.path),
                                      self.path,
                                      other.path,
                                      source="line order")
     ]
Esempio n. 16
0
    def compare(self, other, source=None):
        """
        Override file's compare method to get rid of the binary diff fallback,
        as it would be redundant with other outputs
        """
        details = self.compare_details(other, source)
        details = [x for x in details if x]
        if not details:
            return None

        difference = Difference(None, self.name, other.name, source=source)
        difference.add_details(details)
        return difference
Esempio n. 17
0
 def compare(self, other, source=None):
     # So now that comparators are all object-oriented, we don't have any clue on how to
     # perform a meaningful comparison right here. So we are good do the comparison backward
     # (where knowledge of the file format lies) and and then reverse it.
     if isinstance(other, NonExistingFile):
         return Difference(
             None,
             self.name,
             other.name,
             comment='Trying to compare two non-existing files.')
     logger.debug('Performing backward comparison')
     backward_diff = other.compare(self, source)
     if not backward_diff:
         return None
     return backward_diff.get_reverse()
Esempio n. 18
0
    def compare_details(self, other, source=None):
        if isinstance(other, MissingFile):
            return [
                Difference(
                    None,
                    self.name,
                    other.name,
                    comment="Trying to compare two non-existing files.",
                )
            ]

        return [
            Difference.from_text(
                self.dump(self),
                self.dump(other),
                self.name,
                other.name,
                source='ssconvert',
            )
        ]
Esempio n. 19
0
    def _compare_using_details(self, other, source):
        details = []
        difference = Difference(None, self.name, other.name, source=source)

        if hasattr(self, 'compare_details'):
            details.extend(self.compare_details(other, source))
        if self.as_container:
            if self.as_container.auto_diff_metadata:
                details.extend([
                    Difference.from_text(
                        self.magic_file_type,
                        other.magic_file_type,
                        self,
                        other,
                        source='filetype from file(1)',
                    ),
                    Difference.from_text(
                        self.__class__.__name__,
                        other.__class__.__name__,
                        self,
                        other,
                        source='filetype from diffoscope',
                    ),
                ])
            # Don't recurse forever on archive quines, etc.
            depth = self._as_container.depth
            no_recurse = depth >= Config().max_container_depth
            if no_recurse:
                msg = "Reached max container depth ({})".format(depth)
                logger.debug(msg)
                difference.add_comment(msg)
            details.extend(
                self.as_container.compare(other.as_container,
                                          no_recurse=no_recurse))

        details = [x for x in details if x]
        if not details:
            return None
        difference.add_details(details)

        return difference
Esempio n. 20
0
def compare_files(file1, file2, source=None, diff_content_only=False):
    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

    force_details = Config().force_details
    with profile('has_same_content_as', file1):
        has_same_content = file1.has_same_content_as(file2)

    if has_same_content:
        if not force_details:
            logger.debug(
                "has_same_content_as returned True; skipping further comparisons"
            )
            return None
        if diff_content_only:
            return None
    elif diff_content_only:
        assert not has_same_content
        return Difference(None, file1.name, file2.name, comment="Files differ")

    specialize(file1)
    specialize(file2)
    if isinstance(file1, MissingFile):
        file1.other_file = file2
    elif isinstance(file2, MissingFile):
        file2.other_file = file1
    elif (file1.__class__.__name__ != file2.__class__.__name__) and (
            file1.as_container is None or file2.as_container is None):
        return file1.compare_bytes(file2, source)
    with profile('compare_files (cumulative)', file1):
        return file1.compare(file2, source)
Esempio n. 21
0
    def _compare_using_details(self, other, source):
        details = []
        difference = Difference(None, self.name, other.name, source=source)

        if hasattr(self, 'compare_details'):
            details.extend(self.compare_details(other, source))
        if self.as_container:
            # Don't recursve forever on archive quines, etc.
            depth = self._as_container.depth
            no_recurse = (depth >= Config().max_container_depth)
            if no_recurse:
                msg = "Reached max container depth ({})".format(depth)
                logger.debug(msg)
                difference.add_comment(msg)
            details.extend(
                self.as_container.compare(other.as_container,
                                          no_recurse=no_recurse))

        details = [x for x in details if x]
        if not details:
            return None
        difference.add_details(details)

        return difference
Esempio n. 22
0
 def compare(self, other, source=None):
     return Difference(None,
                       self.path,
                       other.path,
                       source='md5sums',
                       comment="Files in package differs")
Esempio n. 23
0
def test_traverse_heapq():
    d0 = Difference("0", "path1/a", "path2/a")
    d1 = Difference("012", "path1/b", "path2/b")
    d2 = Difference("01", "path1/c", "path2/c")
    d0.add_details([
        Difference("012345678", "path1/a/1", "path2/a/1"),
        Difference("0123", "path1/a/2", "path2/a/2"),
        Difference("012", "path1/a/3", "path2/a/3")
    ])
    d1.add_details([
        Difference("01234567", "path1/b/1", "path2/b/1"),
        Difference("01234", "path1/b/2", "path2/b/2"),
        Difference("012345", "path1/b/3", "path2/b/3")
    ])
    d2.add_details([
        Difference("01", "path1/c/1", "path2/c/1"),
        Difference("0123456789", "path1/c/2", "path2/c/2"),
        Difference("0123456", "path1/c/3", "path2/c/3")
    ])
    diff = Difference("0123456789", "path1", "path2")
    diff.add_details([d0, d1, d2])

    # traverse nodes in depth order, but at a given depth traverse the nodes
    # there from smallest diff (counted non-recursively) to largest
    def f(node, parscore):
        depth = parscore[0] + 1 if parscore else 0
        return depth, node.size_self()

    assert_size(diff, 284)
    results = [d.source1[6:] for d in diff.traverse_heapq(f)]
    assert results == [
        '', 'a', 'c', 'b', 'c/1', 'a/3', 'a/2', 'b/2', 'b/3', 'c/3', 'b/1',
        'a/1', 'c/2'
    ]