From 75ed6761f2012b61c14e0093db6af4e0240489ea Mon Sep 17 00:00:00 2001 From: Jaroslav Rohel Date: Sun, 14 May 2023 18:21:01 +0200 Subject: [PATCH] Backport patch: Add repoid to solver error messages Resolves: rhbz#2179413 --- ...-Add-repoid-to-solver-error-messages.patch | 316 ++++++++++++++++++ libdnf.spec | 6 +- 2 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 0002-Add-repoid-to-solver-error-messages.patch diff --git a/0002-Add-repoid-to-solver-error-messages.patch b/0002-Add-repoid-to-solver-error-messages.patch new file mode 100644 index 0000000..8b89140 --- /dev/null +++ b/0002-Add-repoid-to-solver-error-messages.patch @@ -0,0 +1,316 @@ +From 659bc22f36c7bf21d86ceb298a1eaaccd5a2a880 Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek +Date: Fri, 24 Mar 2023 13:22:41 +0100 +Subject: [PATCH] Split modular packages to to repositories according their + origin + +It will help to provide information about repository origin to libsolv +modular error messages. +--- + libdnf/module/ModulePackageContainer.cpp | 42 ++++++++++++++---------- + 1 file changed, 24 insertions(+), 18 deletions(-) + +diff --git a/libdnf/module/ModulePackageContainer.cpp b/libdnf/module/ModulePackageContainer.cpp +index ccfa249d..4879130f 100644 +--- a/libdnf/module/ModulePackageContainer.cpp ++++ b/libdnf/module/ModulePackageContainer.cpp +@@ -286,13 +286,6 @@ ModulePackageContainer::ModulePackageContainer(bool allArch, std::string install + pImpl->persistDir = dir; + } + +- Pool * pool = dnf_sack_get_pool(pImpl->moduleSack); +- HyRepo hrepo = hy_repo_create("available"); +- auto repoImpl = libdnf::repoGetImpl(hrepo); +- LibsolvRepo *repo = repo_create(pool, "available"); +- repo->appdata = hrepo; +- repoImpl->libsolvRepo = repo; +- repoImpl->needs_internalizing = 1; + pImpl->installRoot = installRoot; + g_autofree gchar * path = g_build_filename(pImpl->installRoot.c_str(), + "/etc/dnf/modules.d", NULL); +@@ -375,23 +368,36 @@ ModulePackageContainer::add(const std::string &fileContent, const std::string & + md.addMetadataFromString(fileContent, 0); + md.resolveAddedMetadata(); + ++ LibsolvRepo * repo = nullptr; + LibsolvRepo * r; + Id id; + ++ // Search whether available repo was already created + FOR_REPOS(id, r) { +- if (strcmp(r->name, "available") == 0) { +- g_autofree gchar * path = g_build_filename(pImpl->installRoot.c_str(), +- "/etc/dnf/modules.d", NULL); +- auto packages = md.getAllModulePackages(pImpl->moduleSack, r, repoID, pImpl->modulesV2); +- for(auto const& modulePackagePtr: packages) { +- std::unique_ptr modulePackage(modulePackagePtr); +- pImpl->modules.insert(std::make_pair(modulePackage->getId(), std::move(modulePackage))); +- pImpl->persistor->insert(modulePackagePtr->getName(), path); +- } +- +- return; ++ if (strcmp(r->name, repoID.c_str()) == 0) { ++ repo = r; + } + } ++ ++ // If not created yet, create it ++ if (!repo) { ++ Pool * pool = dnf_sack_get_pool(pImpl->moduleSack); ++ HyRepo hrepo = hy_repo_create(repoID.c_str()); ++ auto repoImpl = libdnf::repoGetImpl(hrepo); ++ repo = repo_create(pool, repoID.c_str()); ++ repo->appdata = hrepo; ++ repoImpl->libsolvRepo = repo; ++ repoImpl->needs_internalizing = 1; ++ } ++ ++ // add all modules to repository and pass ownership to module container ++ g_autofree gchar * path = g_build_filename(pImpl->installRoot.c_str(), "/etc/dnf/modules.d", NULL); ++ auto packages = md.getAllModulePackages(pImpl->moduleSack, r, repoID, pImpl->modulesV2); ++ for(auto const& modulePackagePtr: packages) { ++ std::unique_ptr modulePackage(modulePackagePtr); ++ pImpl->modules.insert(std::make_pair(modulePackage->getId(), std::move(modulePackage))); ++ pImpl->persistor->insert(modulePackagePtr->getName(), path); ++ } + } + + Id +-- +2.40.1 + + +From e86bc9082e226c7b784c820e9820537cd71afaa0 Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek +Date: Tue, 21 Mar 2023 11:28:43 +0100 +Subject: [PATCH] Add repoid to solver errors for RPMs (RhBug:2179413) + +Repoid is very useful to find a source of the issue. It tells which +repositories contains problematic packages. + +https://bugzilla.redhat.com/show_bug.cgi?id=2179413 +--- + libdnf/goal/Goal.cpp | 101 +++++++++++++---------- + libdnf/module/ModulePackageContainer.cpp | 2 +- + tests/hawkey/test_goal.cpp | 14 ++-- + 3 files changed, 64 insertions(+), 53 deletions(-) + +diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp +index ebe2fbd1..7def8371 100644 +--- a/libdnf/goal/Goal.cpp ++++ b/libdnf/goal/Goal.cpp +@@ -87,8 +87,8 @@ enum {RULE_DISTUPGRADE=1, RULE_INFARCH, RULE_UPDATE, RULE_JOB, RULE_JOB_UNSUPPOR + }; + + static const std::map PKG_PROBLEMS_DICT = { +- {RULE_DISTUPGRADE, M_(" does not belong to a distupgrade repository")}, +- {RULE_INFARCH, M_(" has inferior architecture")}, ++ {RULE_DISTUPGRADE, M_("%s from %s does not belong to a distupgrade repository")}, ++ {RULE_INFARCH, M_("%s from %s has inferior architecture")}, + {RULE_UPDATE, M_("problem with installed package ")}, + {RULE_JOB, M_("conflicting requests")}, + {RULE_JOB_UNSUPPORTED, M_("unsupported request")}, +@@ -98,24 +98,24 @@ static const std::map PKG_PROBLEMS_DICT = { + {RULE_PKG, M_("some dependency problem")}, + {RULE_BEST_1, M_("cannot install the best update candidate for package ")}, + {RULE_BEST_2, M_("cannot install the best candidate for the job")}, +- {RULE_PKG_NOT_INSTALLABLE_1, M_("package %s is filtered out by modular filtering")}, +- {RULE_PKG_NOT_INSTALLABLE_2, M_("package %s does not have a compatible architecture")}, +- {RULE_PKG_NOT_INSTALLABLE_3, M_("package %s is not installable")}, +- {RULE_PKG_NOT_INSTALLABLE_4, M_("package %s is filtered out by exclude filtering")}, +- {RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides %s needed by %s")}, +- {RULE_PKG_SAME_NAME, M_("cannot install both %s and %s")}, +- {RULE_PKG_CONFLICTS, M_("package %s conflicts with %s provided by %s")}, +- {RULE_PKG_OBSOLETES, M_("package %s obsoletes %s provided by %s")}, +- {RULE_PKG_INSTALLED_OBSOLETES, M_("installed package %s obsoletes %s provided by %s")}, +- {RULE_PKG_IMPLICIT_OBSOLETES, M_("package %s implicitly obsoletes %s provided by %s")}, +- {RULE_PKG_REQUIRES, M_("package %s requires %s, but none of the providers can be installed")}, +- {RULE_PKG_SELF_CONFLICT, M_("package %s conflicts with %s provided by itself")}, +- {RULE_YUMOBS, M_("both package %s and %s obsolete %s")} ++ {RULE_PKG_NOT_INSTALLABLE_1, M_("package %s from %s is filtered out by modular filtering")}, ++ {RULE_PKG_NOT_INSTALLABLE_2, M_("package %s from %s does not have a compatible architecture")}, ++ {RULE_PKG_NOT_INSTALLABLE_3, M_("package %s from %s is not installable")}, ++ {RULE_PKG_NOT_INSTALLABLE_4, M_("package %s from %s is filtered out by exclude filtering")}, ++ {RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides %s needed by %s from %s")}, ++ {RULE_PKG_SAME_NAME, M_("cannot install both %s from %s and %s from %s")}, ++ {RULE_PKG_CONFLICTS, M_("package %s from %s conflicts with %s provided by %s from %s")}, ++ {RULE_PKG_OBSOLETES, M_("package %s from %s obsoletes %s provided by %s from %s")}, ++ {RULE_PKG_INSTALLED_OBSOLETES, M_("installed package %s obsoletes %s provided by %s from %s")}, ++ {RULE_PKG_IMPLICIT_OBSOLETES, M_("package %s from %s implicitly obsoletes %s provided by %s from %s")}, ++ {RULE_PKG_REQUIRES, M_("package %s from %s requires %s, but none of the providers can be installed")}, ++ {RULE_PKG_SELF_CONFLICT, M_("package %s from %s conflicts with %s provided by itself")}, ++ {RULE_YUMOBS, M_("both package %s from %s and %s from %s obsolete %s")} + }; + + static const std::map MODULE_PROBLEMS_DICT = { +- {RULE_DISTUPGRADE, M_(" does not belong to a distupgrade repository")}, +- {RULE_INFARCH, M_(" has inferior architecture")}, ++ {RULE_DISTUPGRADE, M_("%s from %s does not belong to a distupgrade repository")}, ++ {RULE_INFARCH, M_("%s from %s has inferior architecture")}, + {RULE_UPDATE, M_("problem with installed module ")}, + {RULE_JOB, M_("conflicting requests")}, + {RULE_JOB_UNSUPPORTED, M_("unsupported request")}, +@@ -125,19 +125,19 @@ static const std::map MODULE_PROBLEMS_DICT = { + {RULE_PKG, M_("some dependency problem")}, + {RULE_BEST_1, M_("cannot install the best update candidate for module ")}, + {RULE_BEST_2, M_("cannot install the best candidate for the job")}, +- {RULE_PKG_NOT_INSTALLABLE_1, M_("module %s is disabled")}, +- {RULE_PKG_NOT_INSTALLABLE_2, M_("module %s does not have a compatible architecture")}, +- {RULE_PKG_NOT_INSTALLABLE_3, M_("module %s is not installable")}, +- {RULE_PKG_NOT_INSTALLABLE_4, M_("module %s is disabled")}, +- {RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides %s needed by module %s")}, +- {RULE_PKG_SAME_NAME, M_("cannot install both modules %s and %s")}, +- {RULE_PKG_CONFLICTS, M_("module %s conflicts with %s provided by %s")}, +- {RULE_PKG_OBSOLETES, M_("module %s obsoletes %s provided by %s")}, +- {RULE_PKG_INSTALLED_OBSOLETES, M_("installed module %s obsoletes %s provided by %s")}, +- {RULE_PKG_IMPLICIT_OBSOLETES, M_("module %s implicitly obsoletes %s provided by %s")}, +- {RULE_PKG_REQUIRES, M_("module %s requires %s, but none of the providers can be installed")}, +- {RULE_PKG_SELF_CONFLICT, M_("module %s conflicts with %s provided by itself")}, +- {RULE_YUMOBS, M_("both module %s and %s obsolete %s")} ++ {RULE_PKG_NOT_INSTALLABLE_1, M_("module %s from %s is disabled")}, ++ {RULE_PKG_NOT_INSTALLABLE_2, M_("module %s from %s does not have a compatible architecture")}, ++ {RULE_PKG_NOT_INSTALLABLE_3, M_("module %s from %s is not installable")}, ++ {RULE_PKG_NOT_INSTALLABLE_4, M_("module %s from %s is disabled")}, ++ {RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides %s needed by module %s from %s")}, ++ {RULE_PKG_SAME_NAME, M_("cannot install both modules %s from %s and %s from %s")}, ++ {RULE_PKG_CONFLICTS, M_("module %s from %s conflicts with %s provided by %s from %s")}, ++ {RULE_PKG_OBSOLETES, M_("module %s from %s obsoletes %s provided by %s from %s")}, ++ {RULE_PKG_INSTALLED_OBSOLETES, M_("installed module %s obsoletes %s provided by %s from %s")}, ++ {RULE_PKG_IMPLICIT_OBSOLETES, M_("module %s from %s implicitly obsoletes %s provided by %s from %s")}, ++ {RULE_PKG_REQUIRES, M_("module %s from %s requires %s, but none of the providers can be installed")}, ++ {RULE_PKG_SELF_CONFLICT, M_("module %s from %s conflicts with %s provided by itself")}, ++ {RULE_YUMOBS, M_("both module %s from %s and %s from %s obsolete %s")} + }; + + static std::string +@@ -151,9 +151,11 @@ libdnf_problemruleinfo2str(libdnf::PackageSet * modularExclude, Solver *solv, So + Solvable *ss; + switch (type) { + case SOLVER_RULE_DISTUPGRADE: +- return solvid2str(pool, source) + TM_(problemDict.at(RULE_DISTUPGRADE), 1); ++ return tfm::format(TM_(problemDict.at(RULE_DISTUPGRADE), 1), solvid2str(pool, source).c_str(), ++ pool_id2solvable(pool, source)->repo->name); + case SOLVER_RULE_INFARCH: +- return solvid2str(pool, source) + TM_(problemDict.at(RULE_INFARCH), 1); ++ return tfm::format(TM_(problemDict.at(RULE_DISTUPGRADE), 1), solvid2str(pool, source).c_str(), ++ pool_id2solvable(pool, source)->repo->name); + case SOLVER_RULE_UPDATE: + return std::string(TM_(problemDict.at(RULE_UPDATE), 1)) + solvid2str(pool, source); + case SOLVER_RULE_JOB: +@@ -176,44 +178,53 @@ libdnf_problemruleinfo2str(libdnf::PackageSet * modularExclude, Solver *solv, So + ss = pool->solvables + source; + if (pool_disabled_solvable(pool, ss)) { + if (modularExclude && modularExclude->has(source)) { +- return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_1), 1), solvid2str(pool, source).c_str()); ++ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_1), 1), ++ solvid2str(pool, source).c_str(), pool_id2solvable(pool, source)->repo->name); + } else { +- return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_4), 1), solvid2str(pool, source).c_str()); ++ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_4), 1), ++ solvid2str(pool, source).c_str(), pool_id2solvable(pool, source)->repo->name); + } + } + if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC && + pool->id2arch && (ss->arch > pool->lastarch || !pool->id2arch[ss->arch])) +- return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_2), 1), solvid2str(pool, source).c_str()); +- return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_3), 1), solvid2str(pool, source).c_str()); ++ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_2), 1), solvid2str(pool, source).c_str(), ++ pool_id2solvable(pool, source)->repo->name); ++ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_3), 1), solvid2str(pool, source).c_str(), ++ pool_id2solvable(pool, source)->repo->name); + case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP: + return tfm::format(TM_(problemDict.at(RULE_PKG_NOTHING_PROVIDES_DEP), 1), pool_dep2str(pool, dep), +- solvid2str(pool, source).c_str()); ++ solvid2str(pool, source).c_str(), pool_id2solvable(pool, source)->repo->name); + case SOLVER_RULE_PKG_SAME_NAME: + return tfm::format(TM_(problemDict.at(RULE_PKG_SAME_NAME), 1), solvid2str(pool, source).c_str(), +- solvid2str(pool, target).c_str()); ++ pool_id2solvable(pool, source)->repo->name, solvid2str(pool, target).c_str(), ++ pool_id2solvable(pool, target)->repo->name); + case SOLVER_RULE_PKG_CONFLICTS: + return tfm::format(TM_(problemDict.at(RULE_PKG_CONFLICTS), 1), solvid2str(pool, source).c_str(), +- pool_dep2str(pool, dep), solvid2str(pool, target).c_str()); ++ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep), ++ solvid2str(pool, target).c_str(), pool_id2solvable(pool, target)->repo->name); + case SOLVER_RULE_PKG_OBSOLETES: + return tfm::format(TM_(problemDict.at(RULE_PKG_OBSOLETES), 1), solvid2str(pool, source).c_str(), +- pool_dep2str(pool, dep), solvid2str(pool, target).c_str()); ++ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep), ++ solvid2str(pool, target).c_str(), pool_id2solvable(pool, target)->repo->name); + case SOLVER_RULE_PKG_INSTALLED_OBSOLETES: + return tfm::format(TM_(problemDict.at(RULE_PKG_INSTALLED_OBSOLETES), 1), + solvid2str(pool, source).c_str(), pool_dep2str(pool, dep), +- solvid2str(pool, target).c_str()); ++ solvid2str(pool, target).c_str(), pool_id2solvable(pool, target)->repo->name); + case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES: + return tfm::format(TM_(problemDict.at(RULE_PKG_IMPLICIT_OBSOLETES), 1), + solvid2str(pool, source).c_str(), pool_dep2str(pool, dep), +- solvid2str(pool, target).c_str()); ++ pool_id2solvable(pool, source)->repo->name, solvid2str(pool, target).c_str(), ++ pool_id2solvable(pool, target)->repo->name); + case SOLVER_RULE_PKG_REQUIRES: + return tfm::format(TM_(problemDict.at(RULE_PKG_REQUIRES), 1), solvid2str(pool, source).c_str(), +- pool_dep2str(pool, dep)); ++ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep)); + case SOLVER_RULE_PKG_SELF_CONFLICT: + return tfm::format(TM_(problemDict.at(RULE_PKG_SELF_CONFLICT), 1), solvid2str(pool, source).c_str(), +- pool_dep2str(pool, dep)); ++ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep)); + case SOLVER_RULE_YUMOBS: + return tfm::format(TM_(problemDict.at(RULE_YUMOBS), 1), solvid2str(pool, source).c_str(), +- solvid2str(pool, target).c_str(), pool_dep2str(pool, dep)); ++ pool_id2solvable(pool, source)->repo->name, solvid2str(pool, target).c_str(), ++ pool_id2solvable(pool, target)->repo->name, pool_dep2str(pool, dep)); + default: + return solver_problemruleinfo2str(solv, type, source, target, dep); + } +diff --git a/libdnf/module/ModulePackageContainer.cpp b/libdnf/module/ModulePackageContainer.cpp +index 4879130f..e4140748 100644 +--- a/libdnf/module/ModulePackageContainer.cpp ++++ b/libdnf/module/ModulePackageContainer.cpp +@@ -392,7 +392,7 @@ ModulePackageContainer::add(const std::string &fileContent, const std::string & + + // add all modules to repository and pass ownership to module container + g_autofree gchar * path = g_build_filename(pImpl->installRoot.c_str(), "/etc/dnf/modules.d", NULL); +- auto packages = md.getAllModulePackages(pImpl->moduleSack, r, repoID, pImpl->modulesV2); ++ auto packages = md.getAllModulePackages(pImpl->moduleSack, repo, repoID, pImpl->modulesV2); + for(auto const& modulePackagePtr: packages) { + std::unique_ptr modulePackage(modulePackagePtr); + pImpl->modules.insert(std::make_pair(modulePackage->getId(), std::move(modulePackage))); +diff --git a/tests/hawkey/test_goal.cpp b/tests/hawkey/test_goal.cpp +index f22e1c80..b2d7af9f 100644 +--- a/tests/hawkey/test_goal.cpp ++++ b/tests/hawkey/test_goal.cpp +@@ -593,11 +593,11 @@ START_TEST(test_goal_describe_problem_rules) + auto problems = goal->describeProblemRules(0, true); + const char *expected[] = { + "conflicting requests", +- "nothing provides goodbye needed by hello-1-1.noarch" ++ "nothing provides goodbye needed by hello-1-1.noarch from main" + }; +- fail_unless(problems.size() == 2); +- fail_unless(problems[0] == expected[0]); +- fail_unless(problems[1] == expected[1]); ++ ck_assert_int_eq(problems.size(), 2); ++ ck_assert_str_eq(problems[0].c_str(), expected[0]); ++ ck_assert_str_eq(problems[1].c_str(), expected[1]); + + g_object_unref(pkg); + hy_goal_free(goal); +@@ -860,10 +860,10 @@ START_TEST(test_goal_lock) + + auto problems = goal->describeProblemRules(0, true); + const char *expected[] = { +- "package bloop-ext-2.0-1.noarch requires bloop = 2.0-1, but none of the providers can be installed", +- "cannot install both bloop-2.0-1.noarch and bloop-1.0-1.noarch", ++ "package bloop-ext-2.0-1.noarch from updates requires bloop = 2.0-1, but none of the providers can be installed", ++ "cannot install both bloop-2.0-1.noarch from updates and bloop-1.0-1.noarch from @System", + "conflicting requests", +- "package bloop-ext-1.0-1.noarch is filtered out by exclude filtering" ++ "package bloop-ext-1.0-1.noarch from updates is filtered out by exclude filtering" + }; + ck_assert_int_eq(problems.size(), 4); + ck_assert_str_eq(problems[0].c_str(), expected[0]); +-- +2.40.1 + diff --git a/libdnf.spec b/libdnf.spec index ac114b4..5364f91 100644 --- a/libdnf.spec +++ b/libdnf.spec @@ -56,12 +56,13 @@ Name: libdnf Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version} -Release: 2%{?dist} +Release: 3%{?dist} Summary: Library providing simplified C and Python API to libsolv License: LGPLv2+ URL: https://github.com/rpm-software-management/libdnf Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz Patch1: 0001-Allow-change-of-arch-during-security-updates-with-no.patch +Patch2: 0002-Add-repoid-to-solver-error-messages.patch BuildRequires: cmake @@ -306,6 +307,9 @@ popd %endif %changelog +* Sun May 14 2023 Jaroslav Rohel - 0.69.0-3 +- Add repoid to solver error messages (RhBug:2179409,2179413) + * Mon Oct 31 2022 Nicola Sella - 0.69.0-2 - Allow change of arch during security updates with noarch