diff --git a/mock/docs/site-defaults.cfg b/mock/docs/site-defaults.cfg index a9aac69bd..3fdd3b16f 100644 --- a/mock/docs/site-defaults.cfg +++ b/mock/docs/site-defaults.cfg @@ -112,6 +112,12 @@ # config_opts['dynamic_buildrequires'] = True # config_opts['dynamic_buildrequires_max_loops'] = 10 +# BuildRequires are installed in a loop until there is nothing left to install. +# This is useful for example when BuildRequires are generated by a macro, +# which is provided by another dependency. This option limits the maximum number +# of loops that are allowed to happen. +# config_opts['static_buildrequires_max_loops'] = 10 + # Allows use of external buildrequires. I.e. when dependencies are installed # from PyPI, Rubygems... # config_opts['external_buildrequires'] = False diff --git a/mock/py/mockbuild/backend.py b/mock/py/mockbuild/backend.py index 63b063c88..d21b9039a 100644 --- a/mock/py/mockbuild/backend.py +++ b/mock/py/mockbuild/backend.py @@ -281,21 +281,30 @@ def build(self, srpm, timeout, check=True, spec=None): spec = self.get_specfile_name(srpm) spec_path = os.path.join(self.buildroot.builddir, 'SPECS', spec) - rebuilt_srpm = self.rebuild_installed_srpm(spec_path, timeout) + # We need to rebuild the SRPM and install dependencies multiple + # times so that cases like #1652 are covered + max_loops = int(self.config.get('static_buildrequires_max_loops')) + for _ in range(max_loops): + packages_before = self.buildroot.all_chroot_packages() + rebuilt_srpm = self.rebuild_installed_srpm(spec_path, timeout) - # Check if we will have dynamic BuildRequires, but do not allow it - hdr = next(util.yieldSrpmHeaders((rebuilt_srpm,))) - # pylint: disable=no-member - requires = {text._to_text(req) for req in hdr[rpm.RPMTAG_REQUIRES]} - dynamic_buildreqs = 'rpmlib(DynamicBuildRequires)' in requires + # Check if we will have dynamic BuildRequires, but do not allow it + hdr = next(util.yieldSrpmHeaders((rebuilt_srpm,))) + # pylint: disable=no-member + requires = {text._to_text(req) for req in hdr[rpm.RPMTAG_REQUIRES]} + dynamic_buildreqs = 'rpmlib(DynamicBuildRequires)' in requires + + if dynamic_buildreqs and not self.config.get('dynamic_buildrequires'): + raise Error('DynamicBuildRequires are found but support is disabled.' + ' See "dynamic_buildrequires" in config_opts.') - if dynamic_buildreqs and not self.config.get('dynamic_buildrequires'): - raise Error('DynamicBuildRequires are found but support is disabled.' - ' See "dynamic_buildrequires" in config_opts.') + self.install_external(requires) + # Install the (static) BuildRequires + self.installSrpmDeps(rebuilt_srpm) + packages_after = self.buildroot.all_chroot_packages() + if packages_after == packages_before: + break - self.install_external(requires) - # install the (static) BuildRequires - self.installSrpmDeps(rebuilt_srpm) self.state.finish(buildsetup) buildsetup_finished = True diff --git a/mock/py/mockbuild/config.py b/mock/py/mockbuild/config.py index 4025c8665..f74bc927f 100644 --- a/mock/py/mockbuild/config.py +++ b/mock/py/mockbuild/config.py @@ -348,6 +348,8 @@ def setup_default_config_opts(): config_opts['dynamic_buildrequires'] = True config_opts['dynamic_buildrequires_max_loops'] = 10 + config_opts['static_buildrequires_max_loops'] = 10 + config_opts['external_buildrequires'] = False config_opts['dev_loop_count'] = 12 diff --git a/releng/release-notes-next/buildrequires-from-macro.bugfix b/releng/release-notes-next/buildrequires-from-macro.bugfix new file mode 100644 index 000000000..5500febd9 --- /dev/null +++ b/releng/release-notes-next/buildrequires-from-macro.bugfix @@ -0,0 +1,8 @@ +Make sure to install `BuildRequires` defined by macros. For example: + +``` +BuildRequires: selinux-policy +%{?selinux_requires} +``` + +This now properly installs the `selinux-policy-devel` package.