From 2ad341a01c68ca3c5006d48839934d79afb7a440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Sedl=C3=A1=C5=99?= Date: Mon, 15 May 2023 09:53:38 +0200 Subject: [PATCH] gather: Always get latest packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If lookaside contains an older version of a package, but with a different arch, the depsolver doesn't notice that and prefers the lookaside version. This is not correct. The latest package should be used no matter if there are different arches available. The filtering in DNF doesn't ensure this, so we have to build it ourselves. To limit the performance impact, only run this filtering when there actually are some lookaside repos configured. JIRA: RHELCMP-11728 Signed-off-by: Lubomír Sedlář --- pungi/gather_dnf.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/pungi/gather_dnf.py b/pungi/gather_dnf.py index 86652723..9c90ef3e 100644 --- a/pungi/gather_dnf.py +++ b/pungi/gather_dnf.py @@ -15,12 +15,14 @@ from enum import Enum -from itertools import count +from functools import cmp_to_key +from itertools import count, groupby import logging import os import re from kobo.rpmlib import parse_nvra +import rpm import pungi.common import pungi.dnf_wrapper @@ -246,9 +248,36 @@ class Gather(GatherBase): # from lookaside. This can be achieved by removing any package that is # also in lookaside from the list. lookaside_pkgs = set() - for pkg in package_list: - if pkg.repoid in self.opts.lookaside_repos: - lookaside_pkgs.add("{0.name}-{0.evr}".format(pkg)) + + if self.opts.lookaside_repos: + # We called `latest()` to get the highest version packages only. + # However, that is per name and architecture. If a package switches + # from arched to noarch or the other way, it is possible that the + # package_list contains different versions in main repos and in + # lookaside repos. + # We need to manually filter the latest version. + def vercmp(x, y): + return rpm.labelCompare(x[1], y[1]) + + # Annotate the packages with their version. + versioned_packages = [ + (pkg, (str(pkg.epoch) or "0", pkg.version, pkg.release)) + for pkg in package_list + ] + # Sort the packages newest first. + sorted_packages = sorted( + versioned_packages, key=cmp_to_key(vercmp), reverse=True + ) + # Group packages by version, take the first group and discard the + # version info from the tuple. + package_list = list( + x[0] for x in next(groupby(sorted_packages, key=lambda x: x[1]))[1] + ) + + # Now we can decide what is used from lookaside. + for pkg in package_list: + if pkg.repoid in self.opts.lookaside_repos: + lookaside_pkgs.add("{0.name}-{0.evr}".format(pkg)) if self.opts.greedy_method == "all": return list(package_list)