From f3f246c6f3b93de59c430ca42b52d90e9467fd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= Date: Tue, 29 Nov 2022 10:28:07 +0100 Subject: [PATCH] PackageQuery: Add filter_duplicates() method --- include/libdnf/rpm/package_query.hpp | 3 ++ libdnf/rpm/package_query.cpp | 62 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/include/libdnf/rpm/package_query.hpp b/include/libdnf/rpm/package_query.hpp index 73c33268b..038b2d20e 100644 --- a/include/libdnf/rpm/package_query.hpp +++ b/include/libdnf/rpm/package_query.hpp @@ -594,6 +594,9 @@ class PackageQuery : public PackageSet { void swap(PackageQuery & other) noexcept; + /// Filter packages to keep only duplicates of installed packages. Packages are duplicate if they have the same `name` and `arch` but different `evr`. + void filter_duplicates(); + private: friend libdnf::Goal; class PQImpl; diff --git a/libdnf/rpm/package_query.cpp b/libdnf/rpm/package_query.cpp index 733732227..705bebcae 100644 --- a/libdnf/rpm/package_query.cpp +++ b/libdnf/rpm/package_query.cpp @@ -2148,6 +2148,30 @@ static void add_n_first_to_map( } } +static void add_duplicates_to_map( + libdnf::solv::Pool & pool, + libdnf::solv::SolvMap & result, + libdnf::solv::IdQueue & samename, + int start_block, + int stop_block) { + Solvable * s_first = nullptr; + Solvable * s_second = nullptr; + for (int pos_first = start_block; pos_first < stop_block; ++pos_first) { + Id id_first = samename[pos_first]; + s_first = pool.id2solvable(id_first); + for (int pos_second = start_block; pos_second < stop_block; ++pos_second) { + Id id_second = samename[pos_second]; + s_second = pool.id2solvable(id_second); + if ((s_first->evr == s_second->evr) && (s_first->arch != s_second->arch)) { + continue; + } + + result.add_unsafe(id_first); + result.add_unsafe(id_second); + } + } +} + static int latest_cmp(const Id * ap, const Id * bp, libdnf::solv::RpmPool * pool) { Solvable * sa = pool->id2solvable(*ap); Solvable * sb = pool->id2solvable(*bp); @@ -2349,4 +2373,42 @@ void PackageQuery::swap(PackageQuery & other) noexcept { p_pq_impl.swap(other.p_pq_impl); } +void PackageQuery::filter_duplicates() { + auto & pool = get_rpm_pool(p_impl->base); + + filter_installed(); + + libdnf::solv::IdQueue samename; + for (Id candidate_id : *p_impl) { + samename.push_back(candidate_id); + } + samename.sort(latest_cmp, &pool); + + p_impl->clear(); + // Create blocks per name, arch + Solvable * highest = nullptr; + int start_block = -1; + int i; + for (i = 0; i < samename.size(); ++i) { + Solvable * considered = pool.id2solvable(samename[i]); + if (!highest || highest->name != considered->name || highest->arch != considered->arch) { + /* start of a new block */ + if (start_block == -1) { + highest = considered; + start_block = i; + continue; + } + if (start_block != i - 1) { + add_duplicates_to_map(pool, *p_impl, samename, start_block, i); + } + highest = considered; + start_block = i; + } + } + if (start_block != i - 1) { // Add last block to the map if it is bigger than 1 (has duplicates) + add_duplicates_to_map(pool, *p_impl, samename, start_block, i); + } +} + + } // namespace libdnf::rpm