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)
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
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) ]
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)
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
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)
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
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
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
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
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
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
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
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
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") ]
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
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()
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', ) ]
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
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)
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
def compare(self, other, source=None): return Difference(None, self.path, other.path, source='md5sums', comment="Files in package differs")
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' ]