import CS libdnf-0.69.0-18.el9
This commit is contained in:
parent
0a31c76569
commit
21d4545a1c
@ -0,0 +1,206 @@
|
||||
From 26f929cdbf033a48abbc8d6fe4cf741a366d1028 Mon Sep 17 00:00:00 2001
|
||||
From: Matej Focko <mfocko@redhat.com>
|
||||
Date: Fri, 30 Jan 2026 12:28:09 +0100
|
||||
Subject: [PATCH] fix: compare RPMItem in transaction with rpmvercmp
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Previous implementation resorts to manual comparison of the EVR fields
|
||||
including the following issues:
|
||||
|
||||
• There appears to be a typo when comparing epochs:
|
||||
|
||||
} else if (epoch < 0) {
|
||||
|
||||
instead of
|
||||
|
||||
} else if (epochDif < 0) {
|
||||
|
||||
N.B. ‹epoch < 0› is unreachable
|
||||
• RPM packaging guidelines **do not** define any requirements on the
|
||||
value (and is internally represented as ‹int32_t›)
|
||||
• On the contrary Fedora packaging guidelines denote:
|
||||
|
||||
If present, it MUST consist of a positive integer.
|
||||
|
||||
• There is a manual parsing of the version fields by “chopping off” the
|
||||
parts ofversion and parsing them via ‹std::stoi›.
|
||||
|
||||
• More importantly, reported by bugs below, the release fields are
|
||||
ignored altogether.
|
||||
|
||||
Instead of manually processing the EVR, with a potential room to error,
|
||||
switch to using the ‹::rpmvercmp› from ‹rpm/rpmver.h› that should be the
|
||||
“source of truth” in this case.
|
||||
|
||||
Also cover the discovered problems with regression tests in unit tests.
|
||||
|
||||
Fixes RHEL-81778
|
||||
Fixes RHEL-81779
|
||||
Fixes RHEL-128443 (RHEL10 clone of RHEL-81779)
|
||||
|
||||
Signed-off-by: Matej Focko <mfocko@redhat.com>
|
||||
(cherry picked from commit 1bcd660168302c120b73b99238babf39f3131faa)
|
||||
---
|
||||
libdnf/transaction/RPMItem.cpp | 39 +++++++--------
|
||||
tests/libdnf/transaction/RpmItemTest.cpp | 61 ++++++++++++++++++++++++
|
||||
tests/libdnf/transaction/RpmItemTest.hpp | 2 +
|
||||
3 files changed, 80 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/libdnf/transaction/RPMItem.cpp b/libdnf/transaction/RPMItem.cpp
|
||||
index ecce789d..92c26d09 100644
|
||||
--- a/libdnf/transaction/RPMItem.cpp
|
||||
+++ b/libdnf/transaction/RPMItem.cpp
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
+#include <rpm/rpmver.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "../hy-subject.h"
|
||||
@@ -343,35 +344,29 @@ RPMItem::resolveTransactionItemReason(SQLite3Ptr conn,
|
||||
* Compare RPM packages
|
||||
* This method doesn't care about compare package names
|
||||
* \param other RPMItem to compare with
|
||||
- * \return true if other package is newer (has higher version and/or epoch)
|
||||
+ * \return true if other package is newer (has higher epoch, version, or release)
|
||||
*/
|
||||
bool
|
||||
RPMItem::operator<(const RPMItem &other) const
|
||||
{
|
||||
- // compare epochs
|
||||
- int32_t epochDif = other.getEpoch() - getEpoch();
|
||||
- if (epochDif > 0) {
|
||||
- return true;
|
||||
- } else if (epoch < 0) {
|
||||
- return false;
|
||||
+ // Compare epochs
|
||||
+ if (getEpoch() != other.getEpoch()) {
|
||||
+ return getEpoch() < other.getEpoch();
|
||||
}
|
||||
|
||||
- // compare versions
|
||||
- std::stringstream versionThis(getVersion());
|
||||
- std::stringstream versionOther(other.getVersion());
|
||||
-
|
||||
- std::string bufferThis;
|
||||
- std::string bufferOther;
|
||||
- while (std::getline(versionThis, bufferThis, '.') &&
|
||||
- std::getline(versionOther, bufferOther, '.')) {
|
||||
- int subVersionThis = std::stoi(bufferThis);
|
||||
- int subVersionOther = std::stoi(bufferOther);
|
||||
- if (subVersionThis == subVersionOther) {
|
||||
- continue;
|
||||
- }
|
||||
- return subVersionOther > subVersionThis;
|
||||
+ // Compare versions
|
||||
+ auto version = getVersion();
|
||||
+ auto otherVersion = other.getVersion();
|
||||
+ auto cmpResult = ::rpmvercmp(version.c_str(), otherVersion.c_str());
|
||||
+ if (cmpResult != 0) {
|
||||
+ return cmpResult < 0;
|
||||
}
|
||||
- return false;
|
||||
+
|
||||
+ // Compare releases
|
||||
+ auto release = getRelease();
|
||||
+ auto otherRelease = other.getRelease();
|
||||
+ cmpResult = ::rpmvercmp(release.c_str(), otherRelease.c_str());
|
||||
+ return cmpResult < 0;
|
||||
}
|
||||
|
||||
std::vector< int64_t >
|
||||
diff --git a/tests/libdnf/transaction/RpmItemTest.cpp b/tests/libdnf/transaction/RpmItemTest.cpp
|
||||
index 774c716a..503e4ec3 100644
|
||||
--- a/tests/libdnf/transaction/RpmItemTest.cpp
|
||||
+++ b/tests/libdnf/transaction/RpmItemTest.cpp
|
||||
@@ -119,3 +119,64 @@ RpmItemTest::testGetTransactionItems()
|
||||
//CPPUNIT_ASSERT(createMs.count() == 0);
|
||||
//CPPUNIT_ASSERT(readMs.count() == 0);
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * Regression test for RHEL-81778
|
||||
+ * Regression test for RHEL-81779
|
||||
+ */
|
||||
+void
|
||||
+RpmItemTest::testComparison()
|
||||
+{
|
||||
+ auto a = std::make_shared< RPMItem >(conn);
|
||||
+ a->setName("rsyslog");
|
||||
+ a->setEpoch(0);
|
||||
+ a->setVersion("8.2102.0");
|
||||
+ a->setRelease("1.el9");
|
||||
+ a->setArch("aarch64");
|
||||
+
|
||||
+ auto b = std::make_shared< RPMItem >(conn);
|
||||
+ b->setName("rsyslog");
|
||||
+ b->setEpoch(0);
|
||||
+ b->setVersion("8.2102.0");
|
||||
+ b->setRelease("5.el9");
|
||||
+ b->setArch("aarch64");
|
||||
+
|
||||
+ // rsyslog-8.2102.0-1.el9.aarch64 < rsyslog-8.2102.0-5.el9.aarch64
|
||||
+ CPPUNIT_ASSERT(*a < *b);
|
||||
+ CPPUNIT_ASSERT(!(*b < *a));
|
||||
+
|
||||
+ a->setRelease("2.el9");
|
||||
+ b->setRelease("1.el9");
|
||||
+
|
||||
+ // rsyslog-8.2102.0-1.el9.aarch64 < rsyslog-8.2102.0-2.el9.aarch64
|
||||
+ CPPUNIT_ASSERT(*b < *a);
|
||||
+ CPPUNIT_ASSERT(!(*a < *b));
|
||||
+
|
||||
+ b->setRelease("10.el9");
|
||||
+
|
||||
+ // rsyslog-8.2102.0-2.el9.aarch64 < rsyslog-8.2102.0-10.el9.aarch64
|
||||
+ CPPUNIT_ASSERT(*a < *b);
|
||||
+ CPPUNIT_ASSERT(!(*b < *a));
|
||||
+
|
||||
+ // Cover fixed comparison of epochs (previously falling through to version
|
||||
+ // comparison when left side being newer)
|
||||
+ {
|
||||
+ auto a = std::make_shared< RPMItem >(conn);
|
||||
+ a->setName("rsyslog");
|
||||
+ a->setEpoch(0);
|
||||
+ a->setVersion("8.2102.0");
|
||||
+ a->setRelease("1.el9");
|
||||
+ a->setArch("aarch64");
|
||||
+
|
||||
+ auto b = std::make_shared< RPMItem >(conn);
|
||||
+ b->setName("rsyslog");
|
||||
+ b->setEpoch(3);
|
||||
+ b->setVersion("8.2101.0");
|
||||
+ b->setRelease("1.el9");
|
||||
+ b->setArch("aarch64");
|
||||
+
|
||||
+ // rsyslog-0:8.2102.0-1.el9.aarch64 < rsyslog-3:8.2101.0-1.el9.aarch64
|
||||
+ CPPUNIT_ASSERT(*a < *b);
|
||||
+ CPPUNIT_ASSERT(!(*b < *a));
|
||||
+ }
|
||||
+}
|
||||
diff --git a/tests/libdnf/transaction/RpmItemTest.hpp b/tests/libdnf/transaction/RpmItemTest.hpp
|
||||
index 59cc6c59..bb4cd930 100644
|
||||
--- a/tests/libdnf/transaction/RpmItemTest.hpp
|
||||
+++ b/tests/libdnf/transaction/RpmItemTest.hpp
|
||||
@@ -10,6 +10,7 @@ class RpmItemTest : public CppUnit::TestCase {
|
||||
CPPUNIT_TEST(testCreate);
|
||||
CPPUNIT_TEST(testCreateDuplicates);
|
||||
CPPUNIT_TEST(testGetTransactionItems);
|
||||
+ CPPUNIT_TEST(testComparison);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -19,6 +20,7 @@ public:
|
||||
void testCreate();
|
||||
void testCreateDuplicates();
|
||||
void testGetTransactionItems();
|
||||
+ void testComparison();
|
||||
|
||||
private:
|
||||
std::shared_ptr< SQLite3 > conn;
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
From 96df64bf5f4e374adac4b1ea423cb29ae73b9f49 Mon Sep 17 00:00:00 2001
|
||||
From: Jaroslav Rohel <jrohel@redhat.com>
|
||||
Date: Mon, 7 Nov 2022 12:15:19 +0100
|
||||
Subject: [PATCH] Fix: "dnf_keyring_add_public_keys": reset GError to NULL
|
||||
(RhBug:2121222)
|
||||
|
||||
Fixes problem "PackageKit crashes if parsing multiple key files fails"
|
||||
packagekitd[1397]: GError set over the top of a previous GError or
|
||||
uninitialized memory. This indicates a bug in someone's code. You must
|
||||
ensure an error is NULL before it's set. The overwriting error message
|
||||
was: failed to parse public key for
|
||||
/etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-14-secondary
|
||||
|
||||
= changelog =
|
||||
msg: "dnf_keyring_add_public_keys": reset localError to NULL after free
|
||||
type: bugfix
|
||||
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2121222
|
||||
---
|
||||
libdnf/dnf-keyring.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/libdnf/dnf-keyring.cpp b/libdnf/dnf-keyring.cpp
|
||||
index 62a6248c..550d5ce2 100644
|
||||
--- a/libdnf/dnf-keyring.cpp
|
||||
+++ b/libdnf/dnf-keyring.cpp
|
||||
@@ -213,6 +213,7 @@ dnf_keyring_add_public_keys(rpmKeyring keyring, GError **error) try
|
||||
if (!ret) {
|
||||
g_warning("%s", localError->message);
|
||||
g_error_free(localError);
|
||||
+ localError = NULL;
|
||||
}
|
||||
} while (true);
|
||||
return TRUE;
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
From 5298228fc2ac50f2172f17ff3f821f7a1a35393d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
|
||||
Date: Fri, 9 Jan 2026 07:26:34 +0100
|
||||
Subject: [PATCH 1/5] Mark all protected packages as user installed for all
|
||||
transactions
|
||||
|
||||
Closes: https://github.com/rpm-software-management/dnf/issues/2192
|
||||
---
|
||||
libdnf/goal/Goal.cpp | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp
|
||||
index ba938e10..3543b3bd 100644
|
||||
--- a/libdnf/goal/Goal.cpp
|
||||
+++ b/libdnf/goal/Goal.cpp
|
||||
@@ -987,6 +987,15 @@ Goal::jobLength()
|
||||
bool
|
||||
Goal::run(DnfGoalActions flags)
|
||||
{
|
||||
+ // Automatically mark all protected packages as user installed.
|
||||
+ // When a protected package is installed as a dependency it can block
|
||||
+ // removal of the last package that depends on it (because the protected
|
||||
+ // package cannot be removed, not even as an unused dependency).
|
||||
+ // To prevent this and still correctly resolve dependencies of the protected
|
||||
+ // packages mark them all as user installed.
|
||||
+ if (pImpl->protectedPkgs) {
|
||||
+ userInstalled(*pImpl->protectedPkgs);
|
||||
+ }
|
||||
auto job = pImpl->constructJob(flags);
|
||||
pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | flags);
|
||||
int ret = pImpl->solve(job->getQueue(), flags);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -0,0 +1,149 @@
|
||||
From 71c3d69bf56c1fa0726b7b5a2fad20acbf8f1ba9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
|
||||
Date: Mon, 26 Jan 2026 14:07:37 +0100
|
||||
Subject: [PATCH 2/5] Add `filterUnneededExtraUserinstalled` and Python version
|
||||
to the API
|
||||
|
||||
This can be used to get unneeded packages with for example protected
|
||||
packages extra marked as userinstalled.
|
||||
---
|
||||
libdnf/sack/query.cpp | 18 +++++++++++----
|
||||
libdnf/sack/query.hpp | 1 +
|
||||
python/hawkey/query-py.cpp | 47 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 62 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libdnf/sack/query.cpp b/libdnf/sack/query.cpp
|
||||
index 6eecfa50..8dce7082 100644
|
||||
--- a/libdnf/sack/query.cpp
|
||||
+++ b/libdnf/sack/query.cpp
|
||||
@@ -830,7 +830,7 @@ private:
|
||||
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);
|
||||
+ int filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove, PackageSet *extra_userinstalled);
|
||||
void obsoletesByPriority(Pool * pool, Solvable * candidate, Map * m, const Map * target, int obsprovides);
|
||||
|
||||
bool isGlob(const std::vector<const char *> &matches) const;
|
||||
@@ -2245,7 +2245,7 @@ Query::Impl::filterDataiterator(const Filter & f, Map *m)
|
||||
}
|
||||
|
||||
int
|
||||
-Query::Impl::filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove)
|
||||
+Query::Impl::filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove, PackageSet *extra_userinstalled)
|
||||
{
|
||||
apply();
|
||||
Goal goal(sack);
|
||||
@@ -2260,6 +2260,10 @@ Query::Impl::filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, b
|
||||
}
|
||||
goal.userInstalled(*userInstalled);
|
||||
|
||||
+ if (extra_userinstalled != NULL) {
|
||||
+ goal.userInstalled(*extra_userinstalled);
|
||||
+ }
|
||||
+
|
||||
int ret1 = goal.run(DNF_NONE);
|
||||
if (ret1)
|
||||
return -1;
|
||||
@@ -2575,13 +2579,19 @@ Query::filterDuplicated()
|
||||
int
|
||||
Query::filterUnneeded(const Swdb &swdb, bool debug_solver)
|
||||
{
|
||||
- return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, false);
|
||||
+ return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, false, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
Query::filterSafeToRemove(const Swdb &swdb, bool debug_solver)
|
||||
{
|
||||
- return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, true);
|
||||
+ return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, true, NULL);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+Query::filterUnneededExtraUserinstalled(const Swdb &swdb, PackageSet &extra_userinstalled, bool debug_solver)
|
||||
+{
|
||||
+ return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, false, &extra_userinstalled);
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/libdnf/sack/query.hpp b/libdnf/sack/query.hpp
|
||||
index 306b24e3..a5ed7745 100644
|
||||
--- a/libdnf/sack/query.hpp
|
||||
+++ b/libdnf/sack/query.hpp
|
||||
@@ -177,6 +177,7 @@ public:
|
||||
void filterRecent(const long unsigned int recent_limit);
|
||||
void filterDuplicated();
|
||||
int filterUnneeded(const Swdb &swdb, bool debug_solver);
|
||||
+ int filterUnneededExtraUserinstalled(const Swdb &swdb, PackageSet &extra_userinstalled, bool debug_solver);
|
||||
int filterSafeToRemove(const Swdb &swdb, bool debug_solver);
|
||||
void getAdvisoryPkgs(int cmpType, std::vector<AdvisoryPkg> & advisoryPkgs);
|
||||
void filterUserInstalled(const Swdb &swdb);
|
||||
diff --git a/python/hawkey/query-py.cpp b/python/hawkey/query-py.cpp
|
||||
index 99f71bd5..1290a07a 100644
|
||||
--- a/python/hawkey/query-py.cpp
|
||||
+++ b/python/hawkey/query-py.cpp
|
||||
@@ -809,6 +809,52 @@ filter_unneeded(PyObject *self, PyObject *args, PyObject *kwds) try
|
||||
return filter_unneeded_or_safe_to_remove(self, args, kwds, false);
|
||||
} CATCH_TO_PYTHON
|
||||
|
||||
+static PyObject *
|
||||
+filter_unneeded_extra_userinstalled(PyObject *self, PyObject *args, PyObject *kwds) try
|
||||
+{
|
||||
+ const char *kwlist[] = {"swdb", "extra_userinstalled", "debug_solver", NULL};
|
||||
+ PyObject *pySwdb;
|
||||
+ PyObject *extra_userinstalled;
|
||||
+ PyObject *debug_solver = NULL;
|
||||
+
|
||||
+ if (!PyArg_ParseTupleAndKeywords(
|
||||
+ args, kwds, "OO|O!", (char **)kwlist, &pySwdb, &extra_userinstalled, &PyBool_Type, &debug_solver)) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ UniquePtrPyObject thisPySwdb(PyObject_GetAttrString(pySwdb, "this"));
|
||||
+ auto swigSwdb = reinterpret_cast< SwdbSwigPyObject * >(thisPySwdb.get());
|
||||
+ if (swigSwdb == nullptr) {
|
||||
+ PyErr_SetString(PyExc_SystemError, "Unable to parse SwigPyObject");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ libdnf::Swdb *swdb = swigSwdb->ptr;
|
||||
+ if (swdb == NULL) {
|
||||
+ PyErr_SetString(PyExc_SystemError, "Unable to parse swig object");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ HyQuery query = ((_QueryObject *) self)->query;
|
||||
+ auto extra_userinstalled_pset = pyseq_to_packageset(extra_userinstalled, query->getSack());
|
||||
+ if (!extra_userinstalled_pset) {
|
||||
+ PyErr_SetString(PyExc_SystemError, "Unable to parse SwigPyObject: extra_userinstalled PackageSet");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ std::unique_ptr<libdnf::Query> self_query_copy(new libdnf::Query(*query));
|
||||
+ gboolean c_debug_solver = debug_solver != NULL && PyObject_IsTrue(debug_solver);
|
||||
+
|
||||
+ int ret = self_query_copy->filterUnneededExtraUserinstalled(*swdb, *extra_userinstalled_pset, c_debug_solver);
|
||||
+ if (ret == -1) {
|
||||
+ PyErr_SetString(PyExc_SystemError, "Unable to provide query with unneded filter");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ PyObject *final_query = queryToPyObject(self_query_copy.release(), ((_QueryObject *) self)->sack,
|
||||
+ Py_TYPE(self));
|
||||
+ return final_query;
|
||||
+} CATCH_TO_PYTHON
|
||||
+
|
||||
static PyObject *
|
||||
q_add(_QueryObject *self, PyObject *list) try
|
||||
{
|
||||
@@ -1071,6 +1117,7 @@ static struct PyMethodDef query_methods[] = {
|
||||
{"_nevra", (PyCFunction)add_nevra_or_other_filter, METH_VARARGS, NULL},
|
||||
{"_recent", (PyCFunction)add_filter_recent, METH_VARARGS, NULL},
|
||||
{"_unneeded", (PyCFunction)filter_unneeded, METH_KEYWORDS|METH_VARARGS, NULL},
|
||||
+ {"_unneeded_extra_userinstalled", (PyCFunction)filter_unneeded_extra_userinstalled, METH_KEYWORDS|METH_VARARGS, NULL},
|
||||
{"_safe_to_remove", (PyCFunction)filter_safe_to_remove, METH_KEYWORDS|METH_VARARGS, NULL},
|
||||
{NULL} /* sentinel */
|
||||
};
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 61066041c2d4e816bc5f4443876af7d9b15d03ec Mon Sep 17 00:00:00 2001
|
||||
From: Evan Goode <mail@evangoo.de>
|
||||
Date: Tue, 27 Jan 2026 13:00:50 -0500
|
||||
Subject: [PATCH 4/5] Describe all problems even when there are protected
|
||||
removals
|
||||
|
||||
Previously, if a transaction involved removal (or dependency break) of a
|
||||
protected package, only the protected package problem would be described
|
||||
by `describeProblemRules`. Information about excluded or versionlocked
|
||||
packages would be missing.
|
||||
|
||||
For: RHEL-115194
|
||||
---
|
||||
libdnf/goal/Goal.cpp | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp
|
||||
index 3543b3bd..fb7bd343 100644
|
||||
--- a/libdnf/goal/Goal.cpp
|
||||
+++ b/libdnf/goal/Goal.cpp
|
||||
@@ -1108,7 +1108,6 @@ Goal::describeProblemRules(unsigned i, bool pkgs)
|
||||
auto problem = pImpl->describeProtectedRemoval();
|
||||
if (!problem.empty()) {
|
||||
output.push_back(std::move(problem));
|
||||
- return output;
|
||||
}
|
||||
auto solv = pImpl->solv;
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
From 5f5dbd01e93d1ec830d5d071051d1a98d2357227 Mon Sep 17 00:00:00 2001
|
||||
From: Evan Goode <mail@evangoo.de>
|
||||
Date: Tue, 27 Jan 2026 13:19:14 -0500
|
||||
Subject: [PATCH 5/5] Clearer error for protected package broken dependencies
|
||||
|
||||
The error message now distinguishes removal of a protected package from
|
||||
breaking dependencies of protected packages.
|
||||
---
|
||||
libdnf/goal/Goal.cpp | 17 +++++++++++------
|
||||
1 file changed, 11 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp
|
||||
index fb7bd343..5ae86db5 100644
|
||||
--- a/libdnf/goal/Goal.cpp
|
||||
+++ b/libdnf/goal/Goal.cpp
|
||||
@@ -1697,11 +1697,11 @@ Goal::Impl::protectedInRemovals()
|
||||
std::string
|
||||
Goal::Impl::describeProtectedRemoval()
|
||||
{
|
||||
- std::string message(_("The operation would result in removing"
|
||||
- " the following protected packages: "));
|
||||
Pool * pool = solv->pool;
|
||||
|
||||
if (removalOfProtected && removalOfProtected->size()) {
|
||||
+ const std::string removal_message(_("The operation would result in removing "
|
||||
+ "the following protected packages: "));
|
||||
Id id = -1;
|
||||
std::vector<const char *> names;
|
||||
while((id = removalOfProtected->next(id)) != -1) {
|
||||
@@ -1711,9 +1711,13 @@ Goal::Impl::describeProtectedRemoval()
|
||||
if (names.empty()) {
|
||||
return {};
|
||||
}
|
||||
- return message + std::accumulate(std::next(names.begin()), names.end(),
|
||||
- std::string(names[0]), [](std::string a, std::string b) { return a + ", " + b; });
|
||||
+ return removal_message +
|
||||
+ std::accumulate(std::next(names.begin()), names.end(), std::string(names[0]),
|
||||
+ [](std::string a, std::string b) { return a + ", " + b; });
|
||||
}
|
||||
+
|
||||
+ const std::string broken_dependency_message(_("The operation would result in broken "
|
||||
+ "dependencies for the following protected packages: "));
|
||||
auto pset = brokenDependencyAllPkgs(DNF_PACKAGE_STATE_INSTALLED);
|
||||
Id id = -1;
|
||||
Id protected_kernel = protectedRunningKernel();
|
||||
@@ -1726,8 +1730,9 @@ Goal::Impl::describeProtectedRemoval()
|
||||
}
|
||||
if (names.empty())
|
||||
return {};
|
||||
- return message + std::accumulate(std::next(names.begin()), names.end(), std::string(names[0]),
|
||||
- [](std::string a, std::string b) { return a + ", " + b; });
|
||||
+ return broken_dependency_message +
|
||||
+ std::accumulate(std::next(names.begin()), names.end(), std::string(names[0]),
|
||||
+ [](std::string a, std::string b) { return a + ", " + b; });
|
||||
}
|
||||
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
From ac1121bc58f779838713c0b0a39b6cc929d141c3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
|
||||
Date: Tue, 10 Feb 2026 13:04:42 +0100
|
||||
Subject: [PATCH] Goal: set protected as userinstalled only for the temporary
|
||||
job
|
||||
|
||||
This way the goal's `staging` is not affected.
|
||||
---
|
||||
libdnf/goal/Goal.cpp | 25 ++++++++++++++++---------
|
||||
1 file changed, 16 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp
|
||||
index 5ae86db5..7766b976 100644
|
||||
--- a/libdnf/goal/Goal.cpp
|
||||
+++ b/libdnf/goal/Goal.cpp
|
||||
@@ -987,15 +987,6 @@ Goal::jobLength()
|
||||
bool
|
||||
Goal::run(DnfGoalActions flags)
|
||||
{
|
||||
- // Automatically mark all protected packages as user installed.
|
||||
- // When a protected package is installed as a dependency it can block
|
||||
- // removal of the last package that depends on it (because the protected
|
||||
- // package cannot be removed, not even as an unused dependency).
|
||||
- // To prevent this and still correctly resolve dependencies of the protected
|
||||
- // packages mark them all as user installed.
|
||||
- if (pImpl->protectedPkgs) {
|
||||
- userInstalled(*pImpl->protectedPkgs);
|
||||
- }
|
||||
auto job = pImpl->constructJob(flags);
|
||||
pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | flags);
|
||||
int ret = pImpl->solve(job->getQueue(), flags);
|
||||
@@ -1401,6 +1392,22 @@ Goal::Impl::constructJob(DnfGoalActions flags)
|
||||
|
||||
allowUninstallAllButProtected(job->getQueue(), flags);
|
||||
|
||||
+ // Automatically mark all protected packages as user installed.
|
||||
+ // When a protected package is installed as a dependency it can block
|
||||
+ // removal of the last package that depends on it (because the protected
|
||||
+ // package cannot be removed, not even as an unused dependency).
|
||||
+ // To prevent this and still correctly resolve dependencies of the protected
|
||||
+ // packages mark them all as user installed.
|
||||
+ if (protectedPkgs) {
|
||||
+ Id id = -1;
|
||||
+ while (true) {
|
||||
+ id = protectedPkgs->next(id);
|
||||
+ if (id == -1)
|
||||
+ break;
|
||||
+ queue_push2(job->getQueue(), SOLVER_SOLVABLE|SOLVER_USERINSTALLED, id);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (flags & DNF_VERIFY)
|
||||
job->pushBack(SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0);
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
Name: libdnf
|
||||
Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version}
|
||||
Release: 16%{?dist}
|
||||
Release: 18%{?dist}
|
||||
Summary: Library providing simplified C and Python API to libsolv
|
||||
License: LGPLv2+
|
||||
URL: https://github.com/rpm-software-management/libdnf
|
||||
@ -96,6 +96,13 @@ Patch30: 0030-C-API-Detect-releasever_major-releasever_minor-from-.patch
|
||||
Patch31: 0031-C-API-Use-releasever_-major-minor-from-context-inste.patch
|
||||
Patch32: 0032-C-API-support-shell-style-variable-substitution.patch
|
||||
Patch33: 0033-C-API-test-shell-style-variable-expressions.patch
|
||||
Patch34: 0034-fix-compare-RPMItem-in-transaction-with-rpmvercmp.patch
|
||||
Patch35: 0035-Fix-dnf_keyring_add_public_keys-reset-GError-to-NULL.patch
|
||||
Patch36: 0036-Mark-all-protected-packages-as-user-installed-for-al.patch
|
||||
Patch37: 0037-Add-filterUnneededExtraUserinstalled-and-Python-vers.patch
|
||||
Patch38: 0038-Describe-all-problems-even-when-there-are-protected-.patch
|
||||
Patch39: 0039-Clearer-error-for-protected-package-broken-dependenc.patch
|
||||
Patch40: 0040-Goal-set-protected-as-userinstalled-only-for-the-tem.patch
|
||||
|
||||
|
||||
BuildRequires: cmake
|
||||
@ -345,6 +352,16 @@ popd
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Mon Feb 09 2026 Ales Matej <amatej@redhat.com> - 0.69.0-18
|
||||
- Fix a crash when parsing multiple key files fails (RHEL-145618)
|
||||
- Mark all protected packages as user installed for all transactions (RHEL-76112)
|
||||
- Add `filterUnneededExtraUserinstalled` and Python version to the API
|
||||
- Describe all problems even when there are protected removals (RHEL-115194)
|
||||
- Clearer error for protected package broken dependencies
|
||||
|
||||
* Tue Feb 03 2026 Matej Focko <mfocko@redhat.com> - 0.69.0-17
|
||||
- Fix comparison of RPM items in the transaction (RHEL-81779)
|
||||
|
||||
* Mon Jun 30 2025 Evan Goode <egoode@redhat.com> - 0.69.0-16
|
||||
- Introduce $releasever_major, $releasever_minor variables, shell-style
|
||||
variable substitution (RHEL-95006)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user