diff --git a/mock-core-configs/etc/mock/templates/rhel-8.tpl b/mock-core-configs/etc/mock/templates/rhel-8.tpl index 29b1f5b71..c8716c52d 100644 --- a/mock-core-configs/etc/mock/templates/rhel-8.tpl +++ b/mock-core-configs/etc/mock/templates/rhel-8.tpl @@ -4,6 +4,7 @@ config_opts['extra_chroot_dirs'] = [ '/run/lock', ] config_opts['releasever'] = '8' config_opts['package_manager'] = 'dnf' config_opts['bootstrap_image'] = 'registry.access.redhat.com/ubi8/ubi' +config_opts['bootstrap_image_ready'] = True config_opts['description'] = 'RHEL 8' config_opts['dnf_install_command'] += ' subscription-manager' diff --git a/mock-core-configs/etc/mock/templates/rhel-9.tpl b/mock-core-configs/etc/mock/templates/rhel-9.tpl index b6d511ea3..04e391b69 100644 --- a/mock-core-configs/etc/mock/templates/rhel-9.tpl +++ b/mock-core-configs/etc/mock/templates/rhel-9.tpl @@ -4,6 +4,7 @@ config_opts['dist'] = 'el{{ releasever }}' # only useful for --resultdir variab config_opts['extra_chroot_dirs'] = [ '/run/lock', ] config_opts['package_manager'] = 'dnf' config_opts['bootstrap_image'] = 'registry.access.redhat.com/ubi{{ releasever }}/ubi' +config_opts['bootstrap_image_ready'] = True config_opts['description'] = 'RHEL {{ releasever }}' config_opts['dnf_install_command'] += ' subscription-manager' diff --git a/mock/docs/site-defaults.cfg b/mock/docs/site-defaults.cfg index eab167c66..a981e1321 100644 --- a/mock/docs/site-defaults.cfg +++ b/mock/docs/site-defaults.cfg @@ -143,6 +143,21 @@ #config_opts['use_bootstrap_image'] = False #config_opts['bootstrap_image'] = 'fedora:latest' +# Mock in a nutshell needs to have the selected config_opts["package_manager"] +# executable in bootstrap, and "builddep" command working. That's why Mock +# automatically installs appropriate packages (e.g. dnf5/dnf5-plugins, if +# package_manager==dnf5). If the config_opts["bootstrap_image"] though points +# to a well-prepared image (no additional packages need to be installed), we +# can set bootstrap_image_ready to True and Mock then avoids installing +# packages into the bootstrap chroot. The initial package manager operation is +# very expensive (downloading metadata, initializing caches, ...) so setting +# this to True significantly speeds the bootstrap-from-bootstrap_image +# preparation. This can also help work-around some preparation issues, see +# https://github.com/rpm-software-management/mock/issues/1088 +# "bootstrap_module_setup_commands" and "bootstrap_chroot_additional_packages" +# options invalidate the effect of this option. +#config_opts['bootstrap_image_ready'] = False + # anything you specify with 'bootstrap_*' will be copied to bootstrap config # e.g. config_opts['bootstrap_system_yum_command'] = '/usr/bin/yum-deprecated' will become # config_opts['system_yum_command'] = '/usr/bin/yum-deprecated' for bootstrap config diff --git a/mock/py/mockbuild/buildroot.py b/mock/py/mockbuild/buildroot.py index b1f2b1ba3..83047c271 100644 --- a/mock/py/mockbuild/buildroot.py +++ b/mock/py/mockbuild/buildroot.py @@ -26,6 +26,9 @@ from .podman import Podman +# pylint: disable=too-many-lines + + def noop_in_bootstrap(f): # pylint: disable=inconsistent-return-statements def wrapper(self, *args, **kwargs): @@ -420,6 +423,9 @@ def _init_pkg_management(self): # The desired package manager. pm = self.config['package_manager'] + if self.bootstrap_image_is_ready: + return + if self.is_bootstrap: update_state = f'installing {pm} tooling' cmd = self.config.get(f"{pm}_install_command") @@ -941,6 +947,43 @@ def delete(self): def uses_bootstrap_image(self): return self.is_bootstrap and self.use_bootstrap_image + @property + def bootstrap_image_is_ready(self): + """ + True if bootstrap image is in use, bootstrap_image_ready==True, and no + config_opts field is set that would invalidate the bootstrap + "readiness" state. + """ + if not self.uses_bootstrap_image: + return False + + # TODO(praiskup): Can we have heuristic for checking if extracted + # buildroot is ready? + + # All the options checked here were copied from the corresponding + # `bootstrap_` prefixed config option. + if not self.config['image_ready']: + self.root_log.info("Bootstrap image not marked ready") + return False + + # Per configuration, we think that image is ready-made (e.g. ubi8 images + # have the 'dnf builddep' command available by default). But there + # still might be reasons to do some updates. + for check_option in [ + "module_enable", "module_install", "module_setup_commands", + "chroot_additional_packages" + ]: + if self.config.get(check_option): + self.root_log.info( + f"Package management in bootstrap (from image) is going to " + f"be updated because config_opts['{check_option}'] is set." + ) + return False + + self.root_log.info("Not updating bootstrap chroot, " + "bootstrap_image_ready=True") + return True + @traceLog() def install_as_root(self, *deps): """ Becomes root user and calls self.install() """ diff --git a/mock/py/mockbuild/config.py b/mock/py/mockbuild/config.py index 636a4d00e..349b0ec95 100644 --- a/mock/py/mockbuild/config.py +++ b/mock/py/mockbuild/config.py @@ -83,6 +83,7 @@ def setup_default_config_opts(): config_opts['use_bootstrap'] = True config_opts['use_bootstrap_image'] = False config_opts['bootstrap_image'] = 'fedora:latest' + config_opts['bootstrap_image_ready'] = False config_opts['internal_dev_setup'] = True