From e45e647f390f23772c0ae5d1584198bd0b502ddc Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Mon, 23 Jul 2018 14:51:05 -0400 Subject: [PATCH] ISO9660: add a pycdlib backend This implements another backend for the avocado.utils.iso9660 library, based on the pure Python pycdlib. The library, as it's the case with all other ISO9660 utilities, is optional and should only attempted to be be used if they are available in the system. In theory, we're well equipped with backends, but this brings the interesting possibility of running on non-UNIX platforms. Signed-off-by: Cleber Rosa --- avocado/utils/iso9660.py | 63 +++++++++++++++++++++++++--- requirements-travis.txt | 1 + selftests/unit/test_utils_iso9660.py | 16 +++++++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/avocado/utils/iso9660.py b/avocado/utils/iso9660.py index 9b47337f..a6899518 100644 --- a/avocado/utils/iso9660.py +++ b/avocado/utils/iso9660.py @@ -21,18 +21,26 @@ either in userspace tools or on the Linux kernel itself (via mount). """ -__all__ = ['iso9660', 'Iso9660IsoInfo', 'Iso9660IsoRead', 'Iso9660Mount'] +__all__ = ['iso9660', 'Iso9660IsoInfo', 'Iso9660IsoRead', 'Iso9660Mount', + 'ISO9660PyCDLib'] -import os +import io import logging -import tempfile +import os +import re import shutil import sys -import re +import tempfile from . import process +try: + import pycdlib +except ImportError: + pycdlib = None + + def has_userland_tool(executable): """ Returns whether the system has a given executable @@ -74,6 +82,15 @@ def has_isoread(): return has_userland_tool('iso-read') +def has_pycdlib(): + """ + Returns whether the system has the Python "pycdlib" library + + :rtype: bool + """ + return pycdlib is not None + + def can_mount(): """ Test whether the current user can perform a loop mount @@ -366,6 +383,39 @@ class Iso9660Mount(BaseIso9660): return self._mnt_dir +class ISO9660PyCDLib(BaseIso9660): + + """ + Represents a ISO9660 filesystem + + This implementation is based on the pycdlib library + """ + + def __init__(self, path): + if not has_pycdlib(): + raise RuntimeError('This class requires the pycdlib library') + self._iso = pycdlib.PyCdlib() + self._iso.open(path) + self._iso_closed = False + + def read(self, path): + if not os.path.isabs(path): + path = '/' + path + data = io.BytesIO() + self._iso.get_file_from_iso_fp(data, joliet_path=path) + return data.getvalue() + + def copy(self, src, dst): + if not os.path.isabs(src): + src = '/' + src + self._iso.get_file_from_iso(dst, joliet_path=src) + + def close(self): + if not self._iso_closed: + self._iso.close() + self._iso_closed = True + + def iso9660(path): """ Checks the available tools on a system and chooses class accordingly @@ -377,9 +427,10 @@ def iso9660(path): :type path: str :return: an instance of any iso9660 capable tool :rtype: :class:`Iso9660IsoInfo`, :class:`Iso9660IsoRead`, - :class:`Iso9660Mount` or None + :class:`Iso9660Mount`, :class:`ISO9660PyCDLib` or None """ - implementations = [('isoinfo', has_isoinfo, Iso9660IsoInfo), + implementations = [('pycdlib', has_pycdlib, ISO9660PyCDLib), + ('isoinfo', has_isoinfo, Iso9660IsoInfo), ('iso-read', has_isoread, Iso9660IsoRead), ('mount', can_mount, Iso9660Mount)] diff --git a/requirements-travis.txt b/requirements-travis.txt index d68d34e0..cca07f97 100644 --- a/requirements-travis.txt +++ b/requirements-travis.txt @@ -24,3 +24,4 @@ lxml>=3.4.4 # pkg_resources.packaging, let's pin the version setuptools==25.1.1 libvirt-python==3.6.0 +pycdlib==1.6.0 diff --git a/selftests/unit/test_utils_iso9660.py b/selftests/unit/test_utils_iso9660.py index 2588cc2e..1e82d47a 100644 --- a/selftests/unit/test_utils_iso9660.py +++ b/selftests/unit/test_utils_iso9660.py @@ -127,5 +127,21 @@ class IsoMount(BaseIso9660): self.mnt_dir_workflow() +class PyCDLib(BaseIso9660): + + """ + PyCDLib-based check + """ + + @unittest.skipUnless(iso9660.has_pycdlib(), "pycdlib not installed") + def setUp(self): + super(PyCDLib, self).setUp() + self.iso = iso9660.ISO9660PyCDLib(self.iso_path) + + def test_basic_workflow(self): + """Call the basic workflow""" + self.basic_workflow() + + if __name__ == "__main__": unittest.main() -- GitLab