From cfba6821beab9a30f2f15830c3c317110dbf2469 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Fri, 2 Sep 2022 13:07:46 -0700 Subject: [PATCH] Group transactions: fail on missing non-optional packages If any default or mandatory package listed in a group does not exist, `raise dnf.exceptions.MarkingErrors`. This is a small change with a big impact and a lot of history. In the early days, dnf treated both 'package doesn't exist' and 'package exists but is not installable' as fatal errors. Shortly after Fedora and RHEL switched from yum to dnf, this was changed, because historically yum had not behaved this way, and our existing comps definitions had lots of missing packages; conditional and arch-specific comps entries also were not properly handled by all tools, so cleaning up comps was not possible. dnf was switched for a while to treat neither as fatal, which turned out to be too permissive, so eventually we gave it the same behaviour yum used to have, in #1038. These days, conditional and arch-specific comps entries work. I have just cleaned up Fedora's comps file for Rawhide, so there should be no 'missing' mandatory or default packages in any group: https://pagure.io/fedora-comps/pull-request/767 I don't know if RHEL's or CentOS's comps have been cleaned up, but if not, this presents an excellent opportunity to do it. Links to the history here: https://bugzilla.redhat.com/show_bug.cgi?id=1292892 https://bugzilla.redhat.com/show_bug.cgi?id=1427365 https://bugzilla.redhat.com/show_bug.cgi?id=1461539 https://github.com/rpm-software-management/dnf/pull/1038 Signed-off-by: Adam Williamson --- dnf/base.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/dnf/base.py b/dnf/base.py index 154eb4e37b..56b4fd8cec 100644 --- a/dnf/base.py +++ b/dnf/base.py @@ -1690,12 +1690,15 @@ def trans_remove(query, remove_query, comps_pkg): return remove_query remove_query = self.sack.query().filterm(empty=True) - attr_fn = ((trans.install, functools.partial(trans_install, strict=True)), - (trans.install_opt, functools.partial(trans_install, strict=False)), - (trans.upgrade, trans_upgrade), - (trans.remove, trans_remove)) - - for (attr, fn) in attr_fn: + attr_fn_mf = ( + (trans.install, functools.partial(trans_install, strict=True), True), + (trans.install_opt, functools.partial(trans_install, strict=False), False), + (trans.upgrade, trans_upgrade, True), + (trans.remove, trans_remove, True) + ) + + missing_fatals = [] + for (attr, fn, missing_fatal) in attr_fn_mf: for comps_pkg in attr: query_args = {'name': comps_pkg.name} if (comps_pkg.basearchonly): @@ -1706,11 +1709,17 @@ def trans_remove(query, remove_query, comps_pkg): package_string = comps_pkg.name if comps_pkg.basearchonly: package_string += '.' + basearch - logger.warning(_('No match for group package "{}"').format(package_string)) + msg = _('No match for group package "{}"').format(package_string) + if missing_fatal: + missing_fatals.append(package_string) + else: + logger.warning(msg) continue remove_query = fn(q, remove_query, comps_pkg) self._goal.group_members.add(comps_pkg.name) + if missing_fatals: + raise dnf.exceptions.MarkingErrors(no_match_pkg_specs=missing_fatals) self._remove_if_unneeded(remove_query) def _build_comps_solver(self):