From 20dde998128f0f4df6bf2ce99c497b9223e0a710 Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Mon, 29 Jan 2024 14:19:41 -0800 Subject: [PATCH] ltmpl: Handle installing provides with resolve_pkg_spec Previously the installpkg command used filter_match to select packages, which works great most of the time. It fails when the package is only available as a provide. This happened recently with wget moving to wget2-wget, causing builds to fail because it couldn't find wget. This changes installpkg to use the resolve_pkg_spec function, which as it happens also support globs and version comparison operators. DNF doesn't like the `==` operator, but I have retained support for it by translating it to a single `=`. I have dropped support for `=>` and `=<` since they are never used and are and odd way to specify `>=` and `>=` which of course still work. --- src/pylorax/ltmpl.py | 57 ++++++++++++++----------------------- tests/pylorax/test_ltmpl.py | 2 -- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/pylorax/ltmpl.py b/src/pylorax/ltmpl.py index 93bb6d8ba..0cd76cd7c 100644 --- a/src/pylorax/ltmpl.py +++ b/src/pylorax/ltmpl.py @@ -43,11 +43,6 @@ import libdnf5 as dnf5 from libdnf5.base import GoalProblem_NO_PROBLEM as NO_PROBLEM from libdnf5.common import QueryCmp_EQ as EQ -from libdnf5.common import QueryCmp_GT as GT -from libdnf5.common import QueryCmp_LT as LT -from libdnf5.common import QueryCmp_GTE as GTE -from libdnf5.common import QueryCmp_LTE as LTE -from libdnf5.common import QueryCmp_GLOB as GLOB action_is_inbound = dnf5.base.transaction.transaction_item_action_is_inbound @@ -210,14 +205,11 @@ def _pkgver(self, pkg_spec): """ query = dnf5.rpm.PackageQuery(self.dbo) - # Always return the highest of the filtered results - if not any(g for g in ['=', '<', '>', '!'] if g in pkg_spec): - # glob? - if any(g for g in ['*', '?', '[', ']'] if g in pkg_spec): - query.filter_name([pkg_spec], GLOB) - else: - query.filter_name([pkg_spec], EQ) - else: + # Use default settings - https://dnf5.readthedocs.io/en/latest/api/c%2B%2B/libdnf5_goal_elements.html#goal-structures-and-enums + settings = dnf5.base.ResolveSpecSettings() + + # Does it contain comparison operators? + if any(g for g in ['=', '<', '>', '!'] if g in pkg_spec): pcv = re.split(r'([!<>=]+)', pkg_spec) if not pcv[0]: raise RuntimeError("Missing package name") @@ -226,30 +218,22 @@ def _pkgver(self, pkg_spec): if len(pcv) != 3: raise RuntimeError("Too many comparisons") - query.filter_name([pcv[0]], EQ) - - # Parse the comparison operators - cmp_map = { - "=": EQ, - "==": EQ, - ">": GT, - ">=": GTE, - "=>": GTE, - "<": LT, - "<=": LTE, - "=<": LTE, - } - if pcv[1] in cmp_map: - if ":" not in pcv[2]: - # Filter wants an epoch, assume 0 for unversioned compares - query.filter_evr(["0:"+pcv[2]], cmp_map[pcv[1]]) - else: - query.filter_evr([pcv[2]], cmp_map[pcv[1]]) - elif pcv[1] in ["<>", "!="]: + # These are not supported, but dnf5 doesn't raise any errors, just returns no results + if pcv[1] in ("!=", "<>"): raise RuntimeError(f"libdnf5 does not support using '{pcv[1]}' to compare versions") - else: + if pcv[1] in ("<<", ">>"): raise RuntimeError(f"Unknown comparison '{pcv[1]}' operator") + # It wants a single '=' not double... + if pcv[1] == "==": + pcv[1] = "=" + + # DNF wants spaces which we can't support in the template, rebuild the spec + # with them. + pkg_spec = " ".join(pcv) + + query.resolve_pkg_spec(pkg_spec, settings, False) + # Filter out other arches, list should include basearch and noarch query.filter_arch(self._filter_arches) @@ -262,6 +246,7 @@ def _pkgver(self, pkg_spec): query.filter_priority() return list(query) + def installpkg(self, *pkgs): ''' installpkg [--required|--optional] [--except PKGGLOB [--except PKGGLOB ...]] PKGGLOB [PKGGLOB ...] @@ -345,8 +330,8 @@ def installpkg(self, *pkgs): for exclude in excludes: pkgobjs = [p for p in pkgobjs if not fnmatch.fnmatch(p.get_name(), exclude)] - # If the request is a glob, expand it in the log - if any(g for g in ['*','?','.'] if g in pkg): + # If the request is a glob or returns more than one package, expand it in the log + if len(pkgobjs) > 1 or any(g for g in ['*','?','.'] if g in pkg): logger.info("installpkg: %s expands to %s", pkg, ",".join(p.get_nevra() for p in pkgobjs)) for p in pkgobjs: diff --git a/tests/pylorax/test_ltmpl.py b/tests/pylorax/test_ltmpl.py index 4fecf7549..6518be6ba 100644 --- a/tests/pylorax/test_ltmpl.py +++ b/tests/pylorax/test_ltmpl.py @@ -204,9 +204,7 @@ def test_00_pkgver(self): ("fake-milhouse>1.0.0-4", "fake-milhouse-1.3.0-1"), ("fake-milhouse>=1.3.0", "fake-milhouse-1.3.0-1"), ("fake-milhouse>=1.0.7-1", "fake-milhouse-1.3.0-1"), - ("fake-milhouse=>1.0.0-4", "fake-milhouse-1.3.0-1"), ("fake-milhouse<=1.0.0-4", "fake-milhouse-1.0.0-4"), - ("fake-milhouse=<1.0.7-1", "fake-milhouse-1.0.7-1"), ("fake-milhouse<1.3.0", "fake-milhouse-1.0.7-1"), ("fake-milhouse<1.3.0-1", "fake-milhouse-1.0.7-1"), ("fake-milhouse<1.0.7-1", "fake-milhouse-1.0.0-4"),