diff --git a/kiwi/builder/container.py b/kiwi/builder/container.py index c16f9ec7..6894b6f7 100644 --- a/kiwi/builder/container.py +++ b/kiwi/builder/container.py @@ -113,7 +113,7 @@ class ContainerBuilder: log.info( 'Setting up %s container', self.requested_container_type ) - container_setup = ContainerSetup( + container_setup = ContainerSetup.new( self.requested_container_type, self.root_dir, self.container_config ) @@ -130,7 +130,7 @@ class ContainerBuilder: log.info( '--> Creating container image' ) - container_image = ContainerImage( + container_image = ContainerImage.new( self.requested_container_type, self.root_dir, self.container_config ) self.filename = container_image.create( diff --git a/kiwi/container/__init__.py b/kiwi/container/__init__.py index eb515790..c6403161 100644 --- a/kiwi/container/__init__.py +++ b/kiwi/container/__init__.py @@ -15,16 +15,18 @@ # You should have received a copy of the GNU General Public License # along with kiwi. If not, see # -# project -from kiwi.container.oci import ContainerImageOCI -from kiwi.container.appx import ContainerImageAppx +import importlib +from abc import ( + ABCMeta, + abstractmethod +) from kiwi.exceptions import ( KiwiContainerImageSetupError ) -class ContainerImage: +class ContainerImage(metaclass=ABCMeta): """ **Container Image factory** @@ -32,20 +34,29 @@ class ContainerImage: :param string root_dir: root directory path name :param dict custom_args: custom arguments """ - def __new__(self, name, root_dir, custom_args=None): - if name == 'docker': - return ContainerImageOCI( - root_dir, 'docker-archive', custom_args=custom_args + @abstractmethod + def __init__(self) -> None: + return None # pragma: no cover + + @staticmethod + def new(name: str, root_dir: str, custom_args: dict = None): + name_map = { + 'docker': 'OCI', + 'oci': 'OCI', + 'appx': 'Appx' + } + args_map = { + 'docker': [root_dir, 'docker-archive', custom_args], + 'oci': [root_dir, 'oci-archive', custom_args], + 'appx': [root_dir, custom_args] + } + try: + container_image = importlib.import_module( + 'kiwi.container.{}'.format('oci' if name == 'docker' else name) ) - elif name == 'oci': - return ContainerImageOCI( - root_dir, 'oci-archive', custom_args=custom_args - ) - elif name == 'appx': - return ContainerImageAppx( - root_dir, custom_args=custom_args - ) - else: + module_name = 'ContainerImage{}'.format(name_map[name]) + return container_image.__dict__[module_name](*args_map[name]) + except Exception: raise KiwiContainerImageSetupError( 'Support for {0} container not implemented'.format(name) ) diff --git a/kiwi/container/oci.py b/kiwi/container/oci.py index 7ad5f38e..403ac9f4 100644 --- a/kiwi/container/oci.py +++ b/kiwi/container/oci.py @@ -118,7 +118,7 @@ class ContainerImageOCI: exclude_list.append('sys/*') exclude_list.append('proc/*') - oci = OCI() + oci = OCI.new() if base_image: oci.import_container_image( 'oci-archive:{0}:{1}'.format( diff --git a/kiwi/container/setup/__init__.py b/kiwi/container/setup/__init__.py index 43e7b37b..f84b4dfa 100644 --- a/kiwi/container/setup/__init__.py +++ b/kiwi/container/setup/__init__.py @@ -15,28 +15,40 @@ # You should have received a copy of the GNU General Public License # along with kiwi. If not, see # -# project -from kiwi.container.setup.docker import ContainerSetupDocker -from kiwi.container.setup.oci import ContainerSetupOCI -from kiwi.container.setup.appx import ContainerSetupAppx +import importlib +from abc import ( + ABCMeta, + abstractmethod +) +# project from kiwi.exceptions import ( KiwiContainerSetupError ) -class ContainerSetup: +class ContainerSetup(metaclass=ABCMeta): """ container setup factory """ - def __new__(self, name, root_dir, custom_args=None): - if name == 'docker': - return ContainerSetupDocker(root_dir, custom_args) - elif name == 'oci': - return ContainerSetupOCI(root_dir, custom_args) - elif name == 'appx': - return ContainerSetupAppx(root_dir, custom_args) - else: + @abstractmethod + def __init__(self) -> None: + return None # pragma: no cover + + @staticmethod + def new(name: str, root_dir: str, custom_args: dict = None): + name_map = { + 'docker': 'Docker', + 'oci': 'OCI', + 'appx': 'Appx' + } + try: + container_setup = importlib.import_module( + 'kiwi.container.setup.{}'.format(name) + ) + module_name = 'ContainerSetup{}'.format(name_map[name]) + return container_setup.__dict__[module_name](root_dir, custom_args) + except Exception: raise KiwiContainerSetupError( 'Support for {0} container not implemented'.format(name) ) diff --git a/kiwi/oci_tools/__init__.py b/kiwi/oci_tools/__init__.py index a5d0be46..8951d967 100644 --- a/kiwi/oci_tools/__init__.py +++ b/kiwi/oci_tools/__init__.py @@ -15,28 +15,42 @@ # You should have received a copy of the GNU General Public License # along with kiwi. If not, see # -# project -from kiwi.oci_tools.umoci import OCIUmoci -from kiwi.oci_tools.buildah import OCIBuildah -from kiwi.runtime_config import RuntimeConfig +import importlib +from abc import ( + ABCMeta, + abstractmethod +) +# project +from kiwi.runtime_config import RuntimeConfig from kiwi.exceptions import ( KiwiOCIArchiveToolError ) -class OCI: +class OCI(metaclass=ABCMeta): """ **OCI Factory** """ - def __new__(self): + @abstractmethod + def __init__(self) -> None: + return None # pragma: no cover + + @staticmethod + def new(): + name_map = { + 'umoci': 'Umoci', + 'buildah': 'Buildah' + } runtime_config = RuntimeConfig() tool_name = runtime_config.get_oci_archive_tool() - if tool_name == 'umoci': - return OCIUmoci() - elif tool_name == 'buildah': - return OCIBuildah() - else: + try: + oci_tool = importlib.import_module( + 'kiwi.oci_tools.{}'.format(tool_name) + ) + module_name = 'OCI{}'.format(name_map[tool_name]) + return oci_tool.__dict__[module_name]() + except Exception: raise KiwiOCIArchiveToolError( 'No support for {0} tool available'.format(tool_name) ) diff --git a/kiwi/system/root_import/oci.py b/kiwi/system/root_import/oci.py index 5eb07b30..6d8a3670 100644 --- a/kiwi/system/root_import/oci.py +++ b/kiwi/system/root_import/oci.py @@ -55,7 +55,7 @@ class RootImportOCI(RootImportBase): log.warning('Bypassing base image URI to OCI tools') image_uri = self.unknown_uri - oci = OCI() + oci = OCI.new() oci.import_container_image(image_uri) oci.unpack() oci.import_rootfs(self.root_dir) diff --git a/test/unit/builder/container_test.py b/test/unit/builder/container_test.py index 2a139232..ace87c86 100644 --- a/test/unit/builder/container_test.py +++ b/test/unit/builder/container_test.py @@ -112,22 +112,22 @@ class TestContainerBuilder: @patch('kiwi.builder.container.ContainerImage') def test_create(self, mock_image, mock_setup): container_setup = mock.Mock() - mock_setup.return_value = container_setup + mock_setup.new.return_value = container_setup container_image = mock.Mock() container_image.create = mock.Mock( return_value='target_dir/image_name.x86_64-1.2.3.docker.tar.xz' ) - mock_image.return_value = container_image + mock_image.new.return_value = container_image self.setup.export_package_verification.return_value = '.verified' self.setup.export_package_changes.return_value = '.changes' self.setup.export_package_list.return_value = '.packages' self.container.base_image = None self.container.create() - mock_setup.assert_called_once_with( + mock_setup.new.assert_called_once_with( 'docker', 'root_dir', self.container_config ) container_setup.setup.assert_called_once_with() - mock_image.assert_called_once_with( + mock_image.new.assert_called_once_with( 'docker', 'root_dir', self.container_config ) container_image.create.assert_called_once_with( @@ -188,7 +188,7 @@ class TestContainerBuilder: container_image.create = mock.Mock( return_value='target_dir/image_name.x86_64-1.2.3.docker.tar.xz' ) - mock_image.return_value = container_image + mock_image.new.return_value = container_image container = ContainerBuilder( self.xml_state, 'target_dir', 'root_dir' @@ -212,7 +212,7 @@ class TestContainerBuilder: 'checksumvalue', 'root_dir/image/imported_root.md5' ) - mock_image.assert_called_once_with( + mock_image.new.assert_called_once_with( 'docker', 'root_dir', self.container_config ) container_image.create.assert_called_once_with( diff --git a/test/unit/container/init_test.py b/test/unit/container/init_test.py index 7b9fa310..04eebbc8 100644 --- a/test/unit/container/init_test.py +++ b/test/unit/container/init_test.py @@ -9,25 +9,25 @@ from kiwi.exceptions import KiwiContainerImageSetupError class TestContainerImage: def test_container_image_not_implemented(self): with raises(KiwiContainerImageSetupError): - ContainerImage('foo', 'root_dir') + ContainerImage.new('foo', 'root_dir') - @patch('kiwi.container.ContainerImageOCI') + @patch('kiwi.container.oci.ContainerImageOCI') def test_container_image_docker(self, mock_docker): - ContainerImage('docker', 'root_dir') + ContainerImage.new('docker', 'root_dir') mock_docker.assert_called_once_with( - 'root_dir', 'docker-archive', custom_args=None + 'root_dir', 'docker-archive', None ) - @patch('kiwi.container.ContainerImageOCI') + @patch('kiwi.container.oci.ContainerImageOCI') def test_container_image_oci(self, mock_oci): - ContainerImage('oci', 'root_dir') + ContainerImage.new('oci', 'root_dir') mock_oci.assert_called_once_with( - 'root_dir', 'oci-archive', custom_args=None + 'root_dir', 'oci-archive', None ) - @patch('kiwi.container.ContainerImageAppx') + @patch('kiwi.container.appx.ContainerImageAppx') def test_container_image_appx(self, mock_appx): - ContainerImage('appx', 'root_dir') + ContainerImage.new('appx', 'root_dir') mock_appx.assert_called_once_with( - 'root_dir', custom_args=None + 'root_dir', None ) diff --git a/test/unit/container/oci_test.py b/test/unit/container/oci_test.py index 01f0d82d..761f1b55 100644 --- a/test/unit/container/oci_test.py +++ b/test/unit/container/oci_test.py @@ -120,7 +120,7 @@ class TestContainerImageOCI: def test_create_oci_archive(self, mock_cache, mock_OCI): mock_cache.return_value = 'var/cache/kiwi' mock_oci = mock.Mock() - mock_OCI.return_value = mock_oci + mock_OCI.new.return_value = mock_oci self.oci.runtime_config.get_container_compression = mock.Mock( return_value=None @@ -164,7 +164,7 @@ class TestContainerImageOCI: ): mock_cache.return_value = 'var/cache/kiwi' mock_oci = mock.Mock() - mock_OCI.return_value = mock_oci + mock_OCI.new.return_value = mock_oci self.oci.create('result.tar', 'root_dir/image/image_file') diff --git a/test/unit/container/setup/init_test.py b/test/unit/container/setup/init_test.py index 40ce4200..a57caca6 100644 --- a/test/unit/container/setup/init_test.py +++ b/test/unit/container/setup/init_test.py @@ -9,19 +9,19 @@ from kiwi.exceptions import KiwiContainerSetupError class TestContainerSetup: def test_container_not_implemented(self): with raises(KiwiContainerSetupError): - ContainerSetup('foo', 'root_dir') + ContainerSetup.new('foo', 'root_dir') - @patch('kiwi.container.setup.ContainerSetupDocker') + @patch('kiwi.container.setup.docker.ContainerSetupDocker') def test_container_docker(self, mock_docker): - ContainerSetup('docker', 'root_dir') + ContainerSetup.new('docker', 'root_dir') mock_docker.assert_called_once_with('root_dir', None) - @patch('kiwi.container.setup.ContainerSetupOCI') + @patch('kiwi.container.setup.oci.ContainerSetupOCI') def test_container_oci(self, mock_oci): - ContainerSetup('oci', 'root_dir') + ContainerSetup.new('oci', 'root_dir') mock_oci.assert_called_once_with('root_dir', None) - @patch('kiwi.container.setup.ContainerSetupAppx') + @patch('kiwi.container.setup.appx.ContainerSetupAppx') def test_container_appx(self, mock_appx): - ContainerSetup('appx', 'root_dir') + ContainerSetup.new('appx', 'root_dir') mock_appx.assert_called_once_with('root_dir', None) diff --git a/test/unit/oci_tools/init_test.py b/test/unit/oci_tools/init_test.py index f61f6ea2..7f303c6b 100644 --- a/test/unit/oci_tools/init_test.py +++ b/test/unit/oci_tools/init_test.py @@ -15,24 +15,24 @@ class TestOCI: self.runtime_config = Mock() self.runtime_config.get_oci_archive_tool = Mock() - @patch('kiwi.oci_tools.OCIUmoci') + @patch('kiwi.oci_tools.umoci.OCIUmoci') @patch('kiwi.oci_tools.RuntimeConfig') def test_oci_tool_umoci( self, mock_RuntimeConfig, mock_OCIUmoci ): self.runtime_config.get_oci_archive_tool.return_value = 'umoci' mock_RuntimeConfig.return_value = self.runtime_config - OCI() + OCI.new() mock_OCIUmoci.assert_called_once_with() - @patch('kiwi.oci_tools.OCIBuildah') + @patch('kiwi.oci_tools.buildah.OCIBuildah') @patch('kiwi.oci_tools.RuntimeConfig') def test_oci_tool_buildah( self, mock_RuntimeConfig, mock_OCIBuildah ): self.runtime_config.get_oci_archive_tool.return_value = 'buildah' mock_RuntimeConfig.return_value = self.runtime_config - OCI() + OCI.new() mock_OCIBuildah.assert_called_once_with() @patch('kiwi.oci_tools.RuntimeConfig') @@ -40,4 +40,4 @@ class TestOCI: self.runtime_config.get_oci_archive_tool.return_value = 'foo' mock_RuntimeConfig.return_value = self.runtime_config with raises(KiwiOCIArchiveToolError): - OCI() + OCI.new() diff --git a/test/unit/system/root_import/oci_test.py b/test/unit/system/root_import/oci_test.py index 71646d81..0981b2b2 100644 --- a/test/unit/system/root_import/oci_test.py +++ b/test/unit/system/root_import/oci_test.py @@ -42,7 +42,7 @@ class TestRootImportOCI: @patch('kiwi.system.root_import.oci.OCI') def test_sync_data(self, mock_OCI, mock_path, mock_md5, mock_compress): oci = Mock() - mock_OCI.return_value = oci + mock_OCI.new.return_value = oci md5 = Mock() mock_md5.return_value = Mock() @@ -52,7 +52,7 @@ class TestRootImportOCI: self.oci_import.sync_data() - mock_OCI.assert_called_once_with() + mock_OCI.new.assert_called_once_with() oci.unpack.assert_called_once_with() oci.import_rootfs.assert_called_once_with( @@ -70,7 +70,7 @@ class TestRootImportOCI: self, mock_OCI, mock_path, mock_md5, mock_compress ): oci = Mock() - mock_OCI.return_value = oci + mock_OCI.new.return_value = oci md5 = Mock() mock_md5.return_value = Mock() @@ -80,7 +80,7 @@ class TestRootImportOCI: self.oci_import.sync_data() - mock_OCI.assert_called_once_with() + mock_OCI.new.assert_called_once_with() oci.unpack.assert_called_once_with() oci.import_rootfs.assert_called_once_with( @@ -100,7 +100,7 @@ class TestRootImportOCI: ): mock_exists.return_value = True oci = Mock() - mock_OCI.return_value = oci + mock_OCI.new.return_value = oci md5 = Mock() mock_md5.return_value = Mock() with patch.dict('os.environ', {'HOME': '../data'}): @@ -111,7 +111,7 @@ class TestRootImportOCI: with self._caplog.at_level(logging.WARNING): oci_import.sync_data() - mock_OCI.assert_called_once_with() + mock_OCI.new.assert_called_once_with() oci.import_container_image.assert_called_once_with( 'docker:image:tag' )