diff --git a/diskimage_builder/elements/package-installs/README.rst b/diskimage_builder/elements/package-installs/README.rst index c7792286..0da2b708 100644 --- a/diskimage_builder/elements/package-installs/README.rst +++ b/diskimage_builder/elements/package-installs/README.rst @@ -96,6 +96,29 @@ packages), you can use something like:: You can also use a list of items in the ``when`` statement, which will be effectively combined with *and*. +If you need to filter multiple paths for a single package, you can +make the parameters a list. For example, if ``linux-image-generic`` +package should be installed when ``DIB_UBUNTU_KERNEL = +linux-image-generic`` is set *except* on ``arm64`` Xenial hosts, where +we would like to install ``linux-generic-hwe-16.04`` you could use the +following: + +.. code-block:: YAML + + linux-image-generic: + - not-arch: arm64 + when: DIB_UBUNTU_KERNEL = linux-image-generic + - arch: arm64 + when: + - DIB_RELEASE != xenial + - DIB_UBUNTU_KERNEL = linux-image-generic + + linux-generic-hwe-16.04: + arch: arm64 + when: + - DIB_RELEASE = xenial + - DIB_UBUNTU_KERNEL = linux-image-generic + DEPRECATED: Adding a file under your elements pre-install.d, install.d, or post-install.d directories called package-installs- will cause the list of packages in that file to be installed at the beginning of the diff --git a/diskimage_builder/elements/package-installs/bin/package-installs-squash b/diskimage_builder/elements/package-installs/bin/package-installs-squash index c59b3563..44f26c9b 100755 --- a/diskimage_builder/elements/package-installs/bin/package-installs-squash +++ b/diskimage_builder/elements/package-installs/bin/package-installs-squash @@ -76,10 +76,8 @@ def _when(statements): # No statement means install if statements is None: return True - - if not isinstance(statements, list): + if not isinstance(statements, (list, tuple)): statements = [statements] - result = [] for s in statements: @@ -98,7 +96,7 @@ def _when(statements): if var not in os.environ: raise RuntimeError("The variable <%s> is not set" % var) - logger.debug("when eval %s%s%s against <%s>" % + logger.debug("... when eval %s%s%s against <%s>" % (var, op, val, os.environ[var])) if op == '=': @@ -121,34 +119,50 @@ def _when(statements): def collect_data(data, objs, element_name): for pkg_name, params in objs.items(): if not params: - params = {} - phase = params.get('phase', 'install.d') - installs = ["install"] - if 'uninstall' in params: - installs = ["uninstall"] - if 'build-only' in params: - installs = ["install", "uninstall"] + params = [{}] + if not isinstance(params, (list, tuple)): + params = [params] - # Filter out incorrect installtypes - installtype = params.get('installtype', None) - elem_installtype = get_element_installtype(element_name) - valid_installtype = (installtype is None or - installtype == elem_installtype) - valid_arch = _valid_for_arch(pkg_name, params.get('arch', None), - params.get('not-arch', None)) - dib_py_version = str(params.get('dib_python_version', '')) - dib_py_version_env = os.environ.get('DIB_PYTHON_VERSION', '') - valid_dib_python_version = (dib_py_version == '' or - dib_py_version == dib_py_version_env) + for param in params: + logger.debug("Considering %s/%s param:%s" % + (element_name, pkg_name, param)) + phase = param.get('phase', 'install.d') + installs = ["install"] + if 'uninstall' in param: + installs = ["uninstall"] + if 'build-only' in param: + installs = ["install", "uninstall"] - # True means install, false skip - if _when(params.get('when', None)) is False: - logger.debug("Skipped due to when: %s/%s" % - (element_name, pkg_name)) - continue + # Filter out incorrect installtypes + installtype = param.get('installtype', None) + elem_installtype = get_element_installtype(element_name) + valid_installtype = (installtype is None or + installtype == elem_installtype) + if not valid_installtype: + logger.debug("... skipping due to installtype") + continue + + valid_arch = _valid_for_arch(pkg_name, param.get('arch', None), + param.get('not-arch', None)) + if not valid_arch: + logger.debug("... skipping due to arch match") + continue + + dib_py_version = str(param.get('dib_python_version', '')) + dib_py_version_env = os.environ.get('DIB_PYTHON_VERSION', '') + valid_dib_python_version = (dib_py_version == '' or + dib_py_version == dib_py_version_env) + if not valid_dib_python_version: + logger.debug("... skipping due to python version") + continue + + # True means install, false skip + if _when(param.get('when', None)) is False: + logger.debug("... skipped due to when: failures") + continue - if valid_installtype and valid_arch and valid_dib_python_version: for install in installs: + logger.debug("... installing for '%s'" % install) data[phase][install].append((pkg_name, element_name)) return data diff --git a/diskimage_builder/elements/package-installs/tests/test_package_squash.py b/diskimage_builder/elements/package-installs/tests/test_package_squash.py index 5bebb526..fa0915c7 100644 --- a/diskimage_builder/elements/package-installs/tests/test_package_squash.py +++ b/diskimage_builder/elements/package-installs/tests/test_package_squash.py @@ -98,6 +98,55 @@ class TestPackageInstall(base.BaseTestCase): self.assertThat(result, IsMatchingInstallList(expected)) + kernel_objs = { + 'linux-image-generic': [ + { + 'not-arch': 'arm64', + 'when': 'DIB_UBUNTU_KERNEL = linux-image-generic', + }, + { + 'arch': 'arm64', + 'when': ( + 'DIB_RELEASE != xenial', + 'DIB_UBUNTU_KERNEL = linux-image-generic', + ) + }, + ], + 'linux-generic-hwe-16.04': { + 'arch': 'arm64', + 'when': ( + 'DIB_RELEASE = xenial', + 'DIB_UBUNTU_KERNEL = linux-image-generic', + ) + }, + } + + def _test_kernel_objs_match(self, arch, release, expected): + with mock.patch.object(os, 'environ', + dict(ARCH=arch, + DIB_UBUNTU_KERNEL='linux-image-generic', + DIB_RELEASE=release, + **os.environ)): + result = installs_squash.collect_data( + self.final_dict, self.kernel_objs, 'test_element') + + expected = { + 'install.d': { + 'install': [(expected, 'test_element')] + } + } + self.assertThat(result, IsMatchingInstallList(expected)) + + def test_param_list_x86(self): + self._test_kernel_objs_match('x86_64', 'focal', 'linux-image-generic') + + def test_param_list_arm64_xenial(self): + self._test_kernel_objs_match('arm64', 'xenial', + 'linux-generic-hwe-16.04') + + def test_param_list_arm64_focal(self): + self._test_kernel_objs_match('arm64', 'focal', 'linux-image-generic') + @mock.patch.object(os, 'environ', dict(DIB_FEATURE='1', **os.environ)) def test_skip_when(self): '''Exercise the when flag'''