Blob Blame History Raw
From b36464f01ffadab9ca49eed1a06ab480626b28c2 Mon Sep 17 00:00:00 2001
From: Jaroslav Mracek <jmracek@redhat.com>
Date: Mon, 16 Dec 2019 10:10:51 +0100
Subject: [PATCH 1/2] Add new query filter upgrades_by_priority

It returns upgrades only from repository with the lowest priority.
---
 libdnf/hy-types.h              |  3 +-
 libdnf/sack/query.cpp          | 60 ++++++++++++++++++++++++++++++++++
 python/hawkey/hawkeymodule.cpp |  1 +
 python/hawkey/query-py.cpp     |  5 ++-
 4 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/libdnf/hy-types.h b/libdnf/hy-types.h
index b34988d89..380a0d5cc 100644
--- a/libdnf/hy-types.h
+++ b/libdnf/hy-types.h
@@ -97,7 +97,8 @@ enum _hy_key_name_e {
     * @brief Use for strings of whole NEVRA (missing epoch is handled as epoch 0)
     * Allowed compare types - only HY_EQ or HY_NEQ
     */
-    HY_PKG_NEVRA_STRICT = 36
+    HY_PKG_NEVRA_STRICT = 36,
+    HY_PKG_UPGRADES_BY_PRIORITY = 37,
 };
 
 enum _hy_comparison_type_e {
diff --git a/libdnf/sack/query.cpp b/libdnf/sack/query.cpp
index eea0ce1b1..ecfd3110f 100644
--- a/libdnf/sack/query.cpp
+++ b/libdnf/sack/query.cpp
@@ -148,6 +148,13 @@ NameArchSolvableComparator(const Solvable * first, const Solvable * second)
     return first->arch < second->arch;
 }
 
+static bool
+NamePrioritySolvableKey(const Solvable * first, const Solvable * second)
+{
+    if (first->name != second->name)
+        return first->name < second->name;
+    return first->repo->priority > second->repo->priority;
+}
 
 static bool
 match_type_num(int keyname) {
@@ -158,6 +165,7 @@ match_type_num(int keyname) {
         case HY_PKG_LATEST_PER_ARCH:
         case HY_PKG_UPGRADABLE:
         case HY_PKG_UPGRADES:
+        case HY_PKG_UPGRADES_BY_PRIORITY:
         case HY_PKG_DOWNGRADABLE:
         case HY_PKG_DOWNGRADES:
             return true;
@@ -690,6 +698,7 @@ class Query::Impl {
     void filterAdvisory(const Filter & f, Map *m, int keyname);
     void filterLatest(const Filter & f, Map *m);
     void filterUpdown(const Filter & f, Map *m);
+    void filterUpdownByPriority(const Filter & f, Map *m);
     void filterUpdownAble(const Filter  &f, Map *m);
     void filterDataiterator(const Filter & f, Map *m);
     int filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove);
@@ -1732,6 +1741,54 @@ Query::Impl::filterUpdown(const Filter & f, Map *m)
     }
 }
 
+void
+Query::Impl::filterUpdownByPriority(const Filter & f, Map *m)
+{
+    Pool *pool = dnf_sack_get_pool(sack);
+    auto resultPset = result.get();
+
+    dnf_sack_make_provides_ready(sack);
+    auto repoInstalled = pool->installed;
+    if (!repoInstalled) {
+        return;
+    }
+
+    for (auto match_in : f.getMatches()) {
+        if (match_in.num == 0)
+            continue;
+        std::vector<Solvable *> upgradeCandidates;
+        upgradeCandidates.reserve(resultPset->size());
+        Id id = -1;
+        while ((id = resultPset->next(id)) != -1) {
+            Solvable *candidate = pool_id2solvable(pool, id);
+            if (candidate->repo == repoInstalled)
+                continue;
+            upgradeCandidates.push_back(candidate);
+        }
+        if (upgradeCandidates.empty()) {
+            continue;
+        }
+        std::sort(upgradeCandidates.begin(), upgradeCandidates.end(), NamePrioritySolvableKey);
+        Id name = 0;
+        int priority = 0;
+        for (auto * candidate: upgradeCandidates) {
+            if (name != candidate->name) {
+                name = candidate->name;
+                priority = candidate->repo->priority;
+                id = pool_solvable2id(pool, candidate);
+                if (what_upgrades(pool, id) > 0) {
+                    MAPSET(m, id);
+                }
+            } else if (priority == candidate->repo->priority) {
+                id = pool_solvable2id(pool, candidate);
+                if (what_upgrades(pool, id) > 0) {
+                    MAPSET(m, id);
+                }
+            }
+        }
+    }
+}
+
 void
 Query::Impl::filterUpdownAble(const Filter  &f, Map *m)
 {
@@ -1949,6 +2006,9 @@ Query::Impl::apply()
             case HY_PKG_UPGRADES:
                 filterUpdown(f, &m);
                 break;
+            case HY_PKG_UPGRADES_BY_PRIORITY:
+                filterUpdownByPriority(f, &m);
+                break;
             default:
                 filterDataiterator(f, &m);
         }
diff --git a/python/hawkey/hawkeymodule.cpp b/python/hawkey/hawkeymodule.cpp
index 0f05f46c2..4351e96e1 100644
--- a/python/hawkey/hawkeymodule.cpp
+++ b/python/hawkey/hawkeymodule.cpp
@@ -281,6 +281,7 @@ PYCOMP_MOD_INIT(_hawkey)
     PyModule_AddIntConstant(m, "PKG_SUPPLEMENTS", HY_PKG_SUPPLEMENTS);
     PyModule_AddIntConstant(m, "PKG_UPGRADABLE", HY_PKG_UPGRADABLE);
     PyModule_AddIntConstant(m, "PKG_UPGRADES", HY_PKG_UPGRADES);
+    PyModule_AddIntConstant(m, "PKG_UPGRADES_BY_PRIORITY", HY_PKG_UPGRADES_BY_PRIORITY);
     PyModule_AddIntConstant(m, "PKG_URL", HY_PKG_URL);
     PyModule_AddIntConstant(m, "PKG_VERSION", HY_PKG_VERSION);
 
diff --git a/python/hawkey/query-py.cpp b/python/hawkey/query-py.cpp
index 116ffa1b0..286e306d3 100644
--- a/python/hawkey/query-py.cpp
+++ b/python/hawkey/query-py.cpp
@@ -89,6 +89,7 @@ static const int keyname_int_matches[] = {
     HY_PKG_SUPPLEMENTS,
     HY_PKG_UPGRADABLE,
     HY_PKG_UPGRADES,
+    HY_PKG_UPGRADES_BY_PRIORITY,
     HY_PKG_URL,
     HY_PKG_VERSION
 };
@@ -128,6 +129,7 @@ static const char * const keyname_char_matches[] = {
     "supplements",
     "upgradable",
     "upgrades",
+    "upgrades_by_priority",
     "url",
     "version",
     NULL
@@ -273,7 +275,8 @@ filter_add(HyQuery query, key_t keyname, int cmp_type, PyObject *match)
         keyname == HY_PKG_LATEST_PER_ARCH ||
         keyname == HY_PKG_LATEST ||
         keyname == HY_PKG_UPGRADABLE ||
-        keyname == HY_PKG_UPGRADES) {
+        keyname == HY_PKG_UPGRADES ||
+        keyname == HY_PKG_UPGRADES_BY_PRIORITY) {
         int val;
 
         if (!PyInt_Check(match) || cmp_type != HY_EQ) {

From 4b83ae692f90d0d3cbc377c7f93bdb7e99e477ef Mon Sep 17 00:00:00 2001
From: Jaroslav Mracek <jmracek@redhat.com>
Date: Mon, 16 Dec 2019 18:34:37 +0100
Subject: [PATCH 2/2] Add new query filter obsoletes_by_priority

---
 libdnf/hy-types.h              |  1 +
 libdnf/sack/query.cpp          | 65 ++++++++++++++++++++++++++++++++++
 python/hawkey/hawkeymodule.cpp |  1 +
 python/hawkey/query-py.cpp     |  5 ++-
 4 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/libdnf/hy-types.h b/libdnf/hy-types.h
index 380a0d5cc..e96459c25 100644
--- a/libdnf/hy-types.h
+++ b/libdnf/hy-types.h
@@ -99,6 +99,7 @@ enum _hy_key_name_e {
     */
     HY_PKG_NEVRA_STRICT = 36,
     HY_PKG_UPGRADES_BY_PRIORITY = 37,
+    HY_PKG_OBSOLETES_BY_PRIORITY = 38,
 };
 
 enum _hy_comparison_type_e {
diff --git a/libdnf/sack/query.cpp b/libdnf/sack/query.cpp
index ecfd3110f..6e9e4715f 100644
--- a/libdnf/sack/query.cpp
+++ b/libdnf/sack/query.cpp
@@ -179,6 +179,7 @@ match_type_pkg(int keyname) {
     switch (keyname) {
         case HY_PKG:
         case HY_PKG_OBSOLETES:
+        case HY_PKG_OBSOLETES_BY_PRIORITY:
             return true;
         default:
             return false;
@@ -692,6 +693,7 @@ class Query::Impl {
     void filterArch(const Filter & f, Map *m);
     void filterSourcerpm(const Filter & f, Map *m);
     void filterObsoletes(const Filter & f, Map *m);
+    void filterObsoletesByPriority(const Filter & f, Map *m);
     void filterProvidesReldep(const Filter & f, Map *m);
     void filterReponame(const Filter & f, Map *m);
     void filterLocation(const Filter & f, Map *m);
@@ -702,6 +704,7 @@ class Query::Impl {
     void filterUpdownAble(const Filter  &f, Map *m);
     void filterDataiterator(const Filter & f, Map *m);
     int filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove);
+    void obsoletesByPriority(Pool * pool, Solvable * candidate, Map * m, const Map * target, int obsprovides);
 
     bool isGlob(const std::vector<const char *> &matches) const;
 };
@@ -1469,6 +1472,65 @@ Query::Impl::filterObsoletes(const Filter & f, Map *m)
     }
 }
 
+void
+Query::Impl::obsoletesByPriority(Pool * pool, Solvable * candidate, Map * m, const Map * target, int obsprovides)
+{
+    if (!candidate->repo)
+        return;
+    for (Id *r_id = candidate->repo->idarraydata + candidate->obsoletes; *r_id; ++r_id) {
+        Id r, rr;
+        FOR_PROVIDES(r, rr, *r_id) {
+            if (!MAPTST(target, r))
+                continue;
+            assert(r != SYSTEMSOLVABLE);
+            Solvable *so = pool_id2solvable(pool, r);
+            if (!obsprovides && !pool_match_nevr(pool, so, *r_id))
+                continue; /* only matching pkg names */
+            MAPSET(m, pool_solvable2id(pool, candidate));
+            break;
+        }
+    }
+}
+
+void
+Query::Impl::filterObsoletesByPriority(const Filter & f, Map *m)
+{
+    Pool *pool = dnf_sack_get_pool(sack);
+    int obsprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
+    Map *target;
+    auto resultPset = result.get();
+
+    assert(f.getMatchType() == _HY_PKG);
+    assert(f.getMatches().size() == 1);
+    target = dnf_packageset_get_map(f.getMatches()[0].pset);
+    dnf_sack_make_provides_ready(sack);
+    std::vector<Solvable *> obsoleteCandidates;
+    obsoleteCandidates.reserve(resultPset->size());
+    Id id = -1;
+    while ((id = resultPset->next(id)) != -1) {
+        Solvable *candidate = pool_id2solvable(pool, id);
+        obsoleteCandidates.push_back(candidate);
+    }
+    if (obsoleteCandidates.empty()) {
+        return;
+    }
+    std::sort(obsoleteCandidates.begin(), obsoleteCandidates.end(), NamePrioritySolvableKey);
+    Id name = 0;
+    int priority = 0;
+    for (auto * candidate: obsoleteCandidates) {
+        if (candidate->repo == pool->installed) {
+            obsoletesByPriority(pool, candidate, m, target, obsprovides);
+        }
+        if (name != candidate->name) {
+            name = candidate->name;
+            priority = candidate->repo->priority;
+            obsoletesByPriority(pool, candidate, m, target, obsprovides);
+        } else if (priority == candidate->repo->priority) {
+            obsoletesByPriority(pool, candidate, m, target, obsprovides);
+        }
+    }
+}
+
 void
 Query::Impl::filterProvidesReldep(const Filter & f, Map *m)
 {
@@ -1969,6 +2031,9 @@ Query::Impl::apply()
                     filterObsoletes(f, &m);
                 }
                 break;
+            case HY_PKG_OBSOLETES_BY_PRIORITY:
+                filterObsoletesByPriority(f, &m);
+                break;
             case HY_PKG_PROVIDES:
                 assert(f.getMatchType() == _HY_RELDEP);
                 filterProvidesReldep(f, &m);
diff --git a/python/hawkey/hawkeymodule.cpp b/python/hawkey/hawkeymodule.cpp
index 4351e96e1..82d05e2cb 100644
--- a/python/hawkey/hawkeymodule.cpp
+++ b/python/hawkey/hawkeymodule.cpp
@@ -270,6 +270,7 @@ PYCOMP_MOD_INIT(_hawkey)
     PyModule_AddIntConstant(m, "PKG_NEVRA", HY_PKG_NEVRA);
     PyModule_AddIntConstant(m, "PKG_NEVRA_STRICT", HY_PKG_NEVRA_STRICT);
     PyModule_AddIntConstant(m, "PKG_OBSOLETES", HY_PKG_OBSOLETES);
+    PyModule_AddIntConstant(m, "PKG_OBSOLETES_BY_PRIORITY", HY_PKG_OBSOLETES_BY_PRIORITY);
     PyModule_AddIntConstant(m, "PKG_PROVIDES", HY_PKG_PROVIDES);
     PyModule_AddIntConstant(m, "PKG_RECOMMENDS", HY_PKG_RECOMMENDS);
     PyModule_AddIntConstant(m, "PKG_RELEASE", HY_PKG_RELEASE);
diff --git a/python/hawkey/query-py.cpp b/python/hawkey/query-py.cpp
index 286e306d3..9178a6d0c 100644
--- a/python/hawkey/query-py.cpp
+++ b/python/hawkey/query-py.cpp
@@ -78,6 +78,7 @@ static const int keyname_int_matches[] = {
     HY_PKG_NEVRA,
     HY_PKG_NEVRA_STRICT,
     HY_PKG_OBSOLETES,
+    HY_PKG_OBSOLETES_BY_PRIORITY,
     HY_PKG_PROVIDES,
     HY_PKG_RECOMMENDS,
     HY_PKG_RELEASE,
@@ -118,6 +119,7 @@ static const char * const keyname_char_matches[] = {
     "nevra",
     "nevra_strict",
     "obsoletes",
+    "obsoletes_by_priority",
     "provides",
     "recommends",
     "release",
@@ -342,7 +344,8 @@ filter_add(HyQuery query, key_t keyname, int cmp_type, PyObject *match)
     // match is a sequence now:
     switch (keyname) {
     case HY_PKG:
-    case HY_PKG_OBSOLETES: {
+    case HY_PKG_OBSOLETES:
+    case HY_PKG_OBSOLETES_BY_PRIORITY: {
         // It could be a sequence of packages or reldep/strings. Lets try packages first.
         auto pset = pyseq_to_packageset(match, query->getSack());
         if (!pset) {