[Reproducible-commits] [diffoscope] 01/01: Added comparator for filesystem images

Reiner Herrmann reiner at reiner-h.de
Wed Dec 2 22:08:15 UTC 2015


This is an automated email from the git hooks/post-receive script.

deki-guest pushed a commit to branch master
in repository diffoscope.

commit 9593b9bade96713a6efc99b96f39438818a54d2f
Author: Reiner Herrmann <reiner at reiner-h.de>
Date:   Wed Dec 2 22:56:25 2015 +0100

    Added comparator for filesystem images
---
 debian/control                     |   1 +
 diffoscope/comparators/__init__.py |   2 +
 diffoscope/comparators/fsimage.py  |  91 +++++++++++++++++++++++++++++++++++++
 tests/comparators/test_fsimage.py  |  76 +++++++++++++++++++++++++++++++
 tests/data/ext4_expected_diffs     |  12 +++++
 tests/data/test1.ext4              | Bin 0 -> 256000 bytes
 tests/data/test2.ext4              | Bin 0 -> 256000 bytes
 7 files changed, 182 insertions(+)

diff --git a/debian/control b/debian/control
index 28bed7e..29fadd2 100644
--- a/debian/control
+++ b/debian/control
@@ -11,6 +11,7 @@ Build-Depends: binutils-multiarch,
                python3-all,
                python3-debian,
                python3-docutils,
+               python3-guestfs,
                python3-libarchive-c,
                python3-magic,
                python3-pytest,
diff --git a/diffoscope/comparators/__init__.py b/diffoscope/comparators/__init__.py
index efa85c7..00cd242 100644
--- a/diffoscope/comparators/__init__.py
+++ b/diffoscope/comparators/__init__.py
@@ -47,6 +47,7 @@ from diffoscope.comparators.device import Device
 from diffoscope.comparators.dex import DexFile
 from diffoscope.comparators.directory import Directory, compare_directories
 from diffoscope.comparators.elf import ElfFile, StaticLibFile
+from diffoscope.comparators.fsimage import FsImageFile
 from diffoscope.comparators.fonts import TtfFile
 from diffoscope.comparators.gettext import MoFile
 from diffoscope.comparators.gzip import GzipFile
@@ -132,6 +133,7 @@ FILE_CLASSES = (
     DebFile,
     DexFile,
     ElfFile,
+    FsImageFile,
     StaticLibFile,
     Sqlite3Database,
     TtfFile,
diff --git a/diffoscope/comparators/fsimage.py b/diffoscope/comparators/fsimage.py
new file mode 100644
index 0000000..f6dd8b3
--- /dev/null
+++ b/diffoscope/comparators/fsimage.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+#
+# diffoscope: in-depth comparison of files, archives, and directories
+#
+# Copyright © 2015 Reiner Herrmann <reiner at reiner-h.de>
+#
+# diffoscope is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# diffoscope is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with diffoscope.  If not, see <http://www.gnu.org/licenses/>.
+
+import re
+import os.path
+try:
+    import guestfs
+except ImportError:
+    guestfs = None
+from diffoscope import logger
+from diffoscope.comparators.binary import File, needs_content
+from diffoscope.comparators.utils import Archive, get_compressed_content_name
+from diffoscope.difference import Difference
+
+
+class FsImageContainer(Archive):
+    @property
+    def path(self):
+        return self._path
+
+    def open_archive(self, path):
+        self._path = path
+
+        if not guestfs:
+            return None
+
+        self.g = guestfs.GuestFS (python_return_dict=True)
+        self.g.add_drive_opts (self.path, format="raw", readonly=1)
+        self.g.launch()
+        devices = self.g.list_devices()
+        self.g.mount(devices[0], "/")
+        self.fs = self.g.list_filesystems()[devices[0]]
+        return self
+
+    def close_archive(self):
+        self.g.umount_all()
+        self.g.close()
+        self._path = None
+
+    def get_members(self):
+        return {'fsimage-content': self.get_member(self.get_member_names()[0])}
+
+    def get_member_names(self):
+        return [os.path.basename(self.path) + '.tar']
+
+    def extract(self, member_name, dest_dir):
+        dest_path = os.path.join(dest_dir, member_name)
+        logger.debug('filesystem image extracting to %s', dest_path)
+        self.g.tar_out("/", dest_path)
+
+        return dest_path
+
+class FsImageFile(File):
+    RE_FILE_TYPE = re.compile(r'^(Linux.*filesystem data|BTRFS Filesystem).*')
+
+    @staticmethod
+    def recognizes(file):
+        return FsImageFile.RE_FILE_TYPE.match(file.magic_file_type)
+
+    @needs_content
+    def compare_details(self, other, source=None):
+        differences = []
+        with FsImageContainer(self).open() as my_container, \
+             FsImageContainer(other).open() as other_container:
+            my_fs = ''
+            other_fs = ''
+            if hasattr(my_container, 'fs'):
+                my_fs = my_container.fs
+            if hasattr(other_container, 'fs'):
+                other_fs = other_container.fs
+            if my_fs != other_fs:
+                differences.append(Difference.from_text(my_fs, other_fs,
+                    None, None, source="filesystem"))
+            differences.extend(my_container.compare(other_container))
+        return differences
diff --git a/tests/comparators/test_fsimage.py b/tests/comparators/test_fsimage.py
new file mode 100644
index 0000000..91d6cec
--- /dev/null
+++ b/tests/comparators/test_fsimage.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+#
+# diffoscope: in-depth comparison of files, archives, and directories
+#
+# Copyright © 2015 Reiner Herrmann <reiner at reiner-h.de>
+#
+# diffoscope is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# diffoscope is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with diffoscope.  If not, see <http://www.gnu.org/licenses/>.
+
+import os.path
+import pytest
+try:
+    import guestfs
+    miss_guestfs = False
+except ImportError:
+    miss_guestfs = True
+from diffoscope.comparators import specialize
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
+from diffoscope.comparators.fsimage import FsImageFile
+from diffoscope.config import Config
+from conftest import tool_missing
+
+TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.ext4')
+TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.ext4')
+
+ at pytest.fixture
+def img1():
+    return specialize(FilesystemFile(TEST_FILE1_PATH))
+
+ at pytest.fixture
+def img2():
+    return specialize(FilesystemFile(TEST_FILE2_PATH))
+
+def test_identification(img1):
+    assert isinstance(img1, FsImageFile)
+
+def test_no_differences(img1):
+    difference = img1.compare(img1)
+    assert difference is None
+
+ at pytest.fixture
+def differences(img1, img2):
+    return img1.compare(img2).details
+
+ at pytest.mark.skipif(miss_guestfs, reason='guestfs is missing')
+def test_differences(differences):
+    assert differences[0].source1 == 'test1.ext4.tar'
+    tarinfo = differences[0].details[0]
+    tardiff = differences[0].details[1]
+    encodingdiff = tardiff.details[0]
+    assert tarinfo.source1 == 'tar --full-time -tvf {}'
+    assert tarinfo.source2 == 'tar --full-time -tvf {}'
+    assert tardiff.source1 == './date.txt'
+    assert tardiff.source2 == './date.txt'
+    assert encodingdiff.source1 == 'encoding'
+    assert encodingdiff.source2 == 'encoding'
+    expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/ext4_expected_diffs')).read()
+    found_diff = tarinfo.unified_diff + tardiff.unified_diff + encodingdiff.unified_diff
+    assert expected_diff == found_diff
+
+ at pytest.mark.skipif(miss_guestfs, reason='guestfs is missing')
+def test_compare_non_existing(monkeypatch, img1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = img1.compare(NonExistingFile('/nonexisting', img1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/data/ext4_expected_diffs b/tests/data/ext4_expected_diffs
new file mode 100644
index 0000000..3b0ff80
--- /dev/null
+++ b/tests/data/ext4_expected_diffs
@@ -0,0 +1,12 @@
+@@ -1,3 +1,3 @@
+-drwxr-xr-x 0/0               0 2015-12-02 16:01:40 ./
++drwxr-xr-x 0/0               0 2015-12-02 16:03:11 ./
+ drwx------ 0/0               0 2015-12-02 16:00:55 ./lost+found/
+--rw-rw-rw- 1234/1234        28 2015-12-02 16:01:40 ./date.txt
++-r--r--r-- 4321/4321        44 2015-12-02 16:03:11 ./date.txt
+@@ -1 +1 @@
+-Wed Dec 2 17:01:40 CET 2015
++jeudi 3 décembre 2015, 06:03:11 (UTC+1400)
+@@ -1 +1 @@
+-us-ascii
++utf-8
diff --git a/tests/data/test1.ext4 b/tests/data/test1.ext4
new file mode 100644
index 0000000..3674521
Binary files /dev/null and b/tests/data/test1.ext4 differ
diff --git a/tests/data/test2.ext4 b/tests/data/test2.ext4
new file mode 100644
index 0000000..3183c03
Binary files /dev/null and b/tests/data/test2.ext4 differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/diffoscope.git



More information about the Reproducible-commits mailing list