From 342f429d5640648c2fa1f3c9ccc5cf0a1aeab61c Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Tue, 30 Apr 2024 14:35:16 +0200 Subject: [PATCH 1/4] base: Add repository to solver problem messages Information about the repository is important for debugging, especially for systems where packages may originate from different repositories. --- libdnf5/base/solver_problems.cpp | 98 +++++++++++++++++++------------- libdnf5/base/transaction.cpp | 67 +++++++++++++++------- 2 files changed, 105 insertions(+), 60 deletions(-) diff --git a/libdnf5/base/solver_problems.cpp b/libdnf5/base/solver_problems.cpp index 423647123..63407ab1f 100644 --- a/libdnf5/base/solver_problems.cpp +++ b/libdnf5/base/solver_problems.cpp @@ -39,7 +39,7 @@ namespace { // TODO(jmracek) Translation must be done later. After setting the locale. static const std::map PKG_PROBLEMS_DICT = { {ProblemRules::RULE_DISTUPGRADE, M_("{} does not belong to a distupgrade repository")}, - {ProblemRules::RULE_INFARCH, M_("{} has inferior architecture")}, + {ProblemRules::RULE_INFARCH, M_("{0} from {1} has inferior architecture")}, {ProblemRules::RULE_UPDATE, M_("problem with installed package ")}, {ProblemRules::RULE_JOB, M_("conflicting requests")}, {ProblemRules::RULE_JOB_UNSUPPORTED, M_("unsupported request")}, @@ -49,19 +49,21 @@ static const std::map PKG_PROBLEMS_DICT = { {ProblemRules::RULE_PKG, M_("some dependency problem")}, {ProblemRules::RULE_BEST_1, M_("cannot install the best update candidate for package {}")}, {ProblemRules::RULE_BEST_2, M_("cannot install the best candidate for the job")}, - {ProblemRules::RULE_PKG_NOT_INSTALLABLE_1, M_("package {} is filtered out by modular filtering")}, - {ProblemRules::RULE_PKG_NOT_INSTALLABLE_2, M_("package {} does not have a compatible architecture")}, - {ProblemRules::RULE_PKG_NOT_INSTALLABLE_3, M_("package {} is not installable")}, - {ProblemRules::RULE_PKG_NOT_INSTALLABLE_4, M_("package {} is filtered out by exclude filtering")}, - {ProblemRules::RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides {0} needed by {1}")}, - {ProblemRules::RULE_PKG_SAME_NAME, M_("cannot install both {0} and {1}")}, - {ProblemRules::RULE_PKG_CONFLICTS, M_("package {0} conflicts with {1} provided by {2}")}, - {ProblemRules::RULE_PKG_OBSOLETES, M_("package {0} obsoletes {1} provided by {2}")}, - {ProblemRules::RULE_PKG_INSTALLED_OBSOLETES, M_("installed package {0} obsoletes {1} provided by {2}")}, - {ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES, M_("package {0} implicitly obsoletes {1} provided by {2}")}, - {ProblemRules::RULE_PKG_REQUIRES, M_("package {1} requires {0}, but none of the providers can be installed")}, - {ProblemRules::RULE_PKG_SELF_CONFLICT, M_("package {1} conflicts with {0} provided by itself")}, - {ProblemRules::RULE_YUMOBS, M_("both package {0} and {2} obsolete {1}")}, + {ProblemRules::RULE_PKG_NOT_INSTALLABLE_1, M_("package {0} from {1} is filtered out by modular filtering")}, + {ProblemRules::RULE_PKG_NOT_INSTALLABLE_2, M_("package {0} from {1} does not have a compatible architecture")}, + {ProblemRules::RULE_PKG_NOT_INSTALLABLE_3, M_("package {0} from {1} is not installable")}, + {ProblemRules::RULE_PKG_NOT_INSTALLABLE_4, M_("package {0} from {1} is filtered out by exclude filtering")}, + {ProblemRules::RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides {0} needed by {1} from {2}")}, + {ProblemRules::RULE_PKG_SAME_NAME, M_("cannot install both {0} from {1} and {2} from {3}")}, + {ProblemRules::RULE_PKG_CONFLICTS, M_("package {0} from {1} conflicts with {2} provided by {3} from {4}")}, + {ProblemRules::RULE_PKG_OBSOLETES, M_("package {0} from {1} obsoletes {2} provided by {3} from {4}")}, + {ProblemRules::RULE_PKG_INSTALLED_OBSOLETES, M_("installed package {0} obsoletes {1} provided by {2} from {3}")}, + {ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES, + M_("package {0} from {1} implicitly obsoletes {2} provided by {3} from {4}")}, + {ProblemRules::RULE_PKG_REQUIRES, + M_("package {1} from {2} requires {0}, but none of the providers can be installed")}, + {ProblemRules::RULE_PKG_SELF_CONFLICT, M_("package {0} from {1} conflicts with {2} provided by itself")}, + {ProblemRules::RULE_YUMOBS, M_("both package {0} from {1} and {3} from {4} obsolete {2}")}, {ProblemRules::RULE_PKG_REMOVAL_OF_PROTECTED, M_("The operation would result in removing" " the following protected packages: {}")}, @@ -179,17 +181,24 @@ SolverProblems::~SolverProblems() = default; std::string SolverProblems::problem_to_string(const std::pair> & raw) { switch (raw.first) { + case ProblemRules::RULE_JOB: + case ProblemRules::RULE_JOB_UNSUPPORTED: + case ProblemRules::RULE_PKG: + case ProblemRules::RULE_BEST_2: + case ProblemRules::RULE_MODULE_JOB: + case ProblemRules::RULE_MODULE_JOB_UNSUPPORTED: + case ProblemRules::RULE_MODULE_PKG: + case ProblemRules::RULE_MODULE_BEST_2: + if (raw.second.size() != 0) { + throw std::invalid_argument("Incorrect number of elements for a problem rule"); + } + return TM_(PKG_PROBLEMS_DICT.at(raw.first), 1); case ProblemRules::RULE_DISTUPGRADE: - case ProblemRules::RULE_INFARCH: case ProblemRules::RULE_UPDATE: case ProblemRules::RULE_JOB_NOTHING_PROVIDES_DEP: case ProblemRules::RULE_JOB_UNKNOWN_PACKAGE: case ProblemRules::RULE_JOB_PROVIDED_BY_SYSTEM: case ProblemRules::RULE_BEST_1: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_1: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_2: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_3: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_4: case ProblemRules::RULE_MODULE_DISTUPGRADE: case ProblemRules::RULE_MODULE_INFARCH: case ProblemRules::RULE_MODULE_UPDATE: @@ -205,22 +214,11 @@ std::string SolverProblems::problem_to_string(const std::pair>>> SolverProblems::get_problems() const { return p_impl->problems; diff --git a/libdnf5/base/transaction.cpp b/libdnf5/base/transaction.cpp index e03b016bc..7fa1557cb 100644 --- a/libdnf5/base/transaction.cpp +++ b/libdnf5/base/transaction.cpp @@ -464,12 +464,17 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ std::vector elements; ProblemRules tmp_rule = rule; switch (rule) { - case ProblemRules::RULE_DISTUPGRADE: case ProblemRules::RULE_INFARCH: + case ProblemRules::RULE_PKG_NOT_INSTALLABLE_2: + case ProblemRules::RULE_PKG_NOT_INSTALLABLE_3: { + auto * src_solvable = pool.id2solvable(source); + elements.push_back(pool.solvable2str(src_solvable)); + elements.push_back(src_solvable->repo->name); + break; + } + case ProblemRules::RULE_DISTUPGRADE: case ProblemRules::RULE_UPDATE: case ProblemRules::RULE_BEST_1: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_2: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_3: elements.push_back(pool.solvid2str(source)); break; case ProblemRules::RULE_JOB: @@ -483,47 +488,69 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ elements.push_back(pool.dep2str(dep)); break; case ProblemRules::RULE_PKG_NOT_INSTALLABLE_1: - case ProblemRules::RULE_PKG_NOT_INSTALLABLE_4: + case ProblemRules::RULE_PKG_NOT_INSTALLABLE_4: { if (false) { // TODO (jmracek) (modularExclude && modularExclude->has(source)) } else { tmp_rule = ProblemRules::RULE_PKG_NOT_INSTALLABLE_4; } - elements.push_back(pool.solvid2str(source)); + auto * src_solvable = pool.id2solvable(source); + elements.push_back(pool.solvable2str(src_solvable)); + elements.push_back(src_solvable->repo->name); break; - case ProblemRules::RULE_PKG_SELF_CONFLICT: + } + case ProblemRules::RULE_PKG_SELF_CONFLICT: { skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); + auto * src_solvable = pool.id2solvable(source); + elements.push_back(pool.solvable2str(src_solvable)); + elements.push_back(src_solvable->repo->name); elements.push_back(pool.dep2str(dep)); - elements.push_back(pool.solvid2str(source)); break; + } case ProblemRules::RULE_PKG_NOTHING_PROVIDES_DEP: - case ProblemRules::RULE_PKG_REQUIRES: + case ProblemRules::RULE_PKG_REQUIRES: { skip_broken.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); + auto * src_solvable = pool.id2solvable(source); elements.push_back(pool.dep2str(dep)); - elements.push_back(pool.solvid2str(source)); + elements.push_back(pool.solvable2str(src_solvable)); + elements.push_back(src_solvable->repo->name); break; - case ProblemRules::RULE_PKG_SAME_NAME: + } + case ProblemRules::RULE_PKG_SAME_NAME: { skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(target))); - elements.push_back(pool.solvid2str(source)); - elements.push_back(pool.solvid2str(target)); - std::sort(elements.begin(), elements.end()); + auto * src_solvable = pool.id2solvable(source); + elements.push_back(pool.solvable2str(src_solvable)); + elements.push_back(src_solvable->repo->name); + auto * tgt_solvable = pool.id2solvable(target); + elements.push_back(pool.solvable2str(tgt_solvable)); + elements.push_back(tgt_solvable->repo->name); break; + } case ProblemRules::RULE_PKG_CONFLICTS: skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(target))); - elements.push_back(pool.solvid2str(source)); - elements.push_back(pool.dep2str(dep)); - elements.push_back(pool.solvid2str(target)); - break; + [[fallthrough]]; case ProblemRules::RULE_PKG_OBSOLETES: - case ProblemRules::RULE_PKG_INSTALLED_OBSOLETES: case ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES: - case ProblemRules::RULE_YUMOBS: + case ProblemRules::RULE_YUMOBS: { + auto * src_solvable = pool.id2solvable(source); + elements.push_back(pool.solvable2str(src_solvable)); + elements.push_back(src_solvable->repo->name); + elements.push_back(pool.dep2str(dep)); + auto * tgt_solvable = pool.id2solvable(target); + elements.push_back(pool.solvable2str(tgt_solvable)); + elements.push_back(tgt_solvable->repo->name); + break; + } + case ProblemRules::RULE_PKG_INSTALLED_OBSOLETES: { elements.push_back(pool.solvid2str(source)); elements.push_back(pool.dep2str(dep)); - elements.push_back(pool.solvid2str(target)); + auto * tgt_solvable = pool.id2solvable(target); + elements.push_back(pool.solvable2str(tgt_solvable)); + elements.push_back(tgt_solvable->repo->name); break; + } case ProblemRules::RULE_UNKNOWN: elements.push_back(description); break; From 2029f3d4834bc7d1251625f9c8b990611619e1a8 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Thu, 2 May 2024 11:27:05 +0200 Subject: [PATCH 2/4] base: Deduplicate solver problem messages Do not include the "pkgA conflicts with pkgB" message in case the "pkgB conflicts with pkgA" message is already present. --- libdnf5/base/transaction.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libdnf5/base/transaction.cpp b/libdnf5/base/transaction.cpp index 7fa1557cb..23928cdf7 100644 --- a/libdnf5/base/transaction.cpp +++ b/libdnf5/base/transaction.cpp @@ -458,6 +458,7 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ solver_problems.clear(); for (auto & problem : goal_solver_problems) { + std::set> current_conflicting_rules; std::vector>> problem_output; for (auto & [rule, source, dep, target, description] : problem) { @@ -528,8 +529,13 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ break; } case ProblemRules::RULE_PKG_CONFLICTS: + if (current_conflicting_rules.contains(std::pair(target, source))) { + // do not add pkgA conflicts with pkgB rule if pkgB conflicts with PkgA rule is already present + continue; + } skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(target))); + current_conflicting_rules.emplace(source, target); [[fallthrough]]; case ProblemRules::RULE_PKG_OBSOLETES: case ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES: From e88c6e02774d47b0807618e20908751b755f684b Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Thu, 2 May 2024 12:51:00 +0200 Subject: [PATCH 3/4] base: Remove trailing space from RULE_UPDATE message --- libdnf5/base/solver_problems.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdnf5/base/solver_problems.cpp b/libdnf5/base/solver_problems.cpp index 63407ab1f..078f13df1 100644 --- a/libdnf5/base/solver_problems.cpp +++ b/libdnf5/base/solver_problems.cpp @@ -40,7 +40,7 @@ namespace { static const std::map PKG_PROBLEMS_DICT = { {ProblemRules::RULE_DISTUPGRADE, M_("{} does not belong to a distupgrade repository")}, {ProblemRules::RULE_INFARCH, M_("{0} from {1} has inferior architecture")}, - {ProblemRules::RULE_UPDATE, M_("problem with installed package ")}, + {ProblemRules::RULE_UPDATE, M_("problem with installed package")}, {ProblemRules::RULE_JOB, M_("conflicting requests")}, {ProblemRules::RULE_JOB_UNSUPPORTED, M_("unsupported request")}, {ProblemRules::RULE_JOB_NOTHING_PROVIDES_DEP, M_("nothing provides requested {}")}, From cc76aad0744293160f3631941771dc865cebca82 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Wed, 22 May 2024 15:26:16 +0200 Subject: [PATCH 4/4] base: Enhance installed pkgs solver problems reporting Instead of cryptic "PkgA from @System" is used more user friendli expression "installed package PkgA". --- include/libdnf5/base/goal_elements.hpp | 2 ++ libdnf5/base/solver_problems.cpp | 8 ++++++++ libdnf5/base/transaction.cpp | 20 +++++++++++++++++++- libdnf5/rpm/solv/goal_private.cpp | 24 ++++++++++++++++++------ 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/include/libdnf5/base/goal_elements.hpp b/include/libdnf5/base/goal_elements.hpp index 790ce18f2..4c65d0471 100644 --- a/include/libdnf5/base/goal_elements.hpp +++ b/include/libdnf5/base/goal_elements.hpp @@ -86,6 +86,8 @@ enum class ProblemRules { RULE_MODULE_PKG_SELF_CONFLICT, RULE_MODULE_YUMOBS, RULE_MODULE_UNKNOWN, + RULE_PKG_INSTALLED_CONFLICTS, + RULE_PKG_INSTALLED_REQUIRES, }; /// Define a type of information, hint, or problem gathered during libdnf5::Goal::resolve() diff --git a/libdnf5/base/solver_problems.cpp b/libdnf5/base/solver_problems.cpp index 078f13df1..8b0ee9b7d 100644 --- a/libdnf5/base/solver_problems.cpp +++ b/libdnf5/base/solver_problems.cpp @@ -56,12 +56,16 @@ static const std::map PKG_PROBLEMS_DICT = { {ProblemRules::RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides {0} needed by {1} from {2}")}, {ProblemRules::RULE_PKG_SAME_NAME, M_("cannot install both {0} from {1} and {2} from {3}")}, {ProblemRules::RULE_PKG_CONFLICTS, M_("package {0} from {1} conflicts with {2} provided by {3} from {4}")}, + {ProblemRules::RULE_PKG_INSTALLED_CONFLICTS, + M_("installed package {0} conflicts with {1} provided by {2} from {3}")}, {ProblemRules::RULE_PKG_OBSOLETES, M_("package {0} from {1} obsoletes {2} provided by {3} from {4}")}, {ProblemRules::RULE_PKG_INSTALLED_OBSOLETES, M_("installed package {0} obsoletes {1} provided by {2} from {3}")}, {ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES, M_("package {0} from {1} implicitly obsoletes {2} provided by {3} from {4}")}, {ProblemRules::RULE_PKG_REQUIRES, M_("package {1} from {2} requires {0}, but none of the providers can be installed")}, + {ProblemRules::RULE_PKG_INSTALLED_REQUIRES, + M_("installed package {1} requires {0}, but none of the providers can be installed")}, {ProblemRules::RULE_PKG_SELF_CONFLICT, M_("package {0} from {1} conflicts with {2} provided by itself")}, {ProblemRules::RULE_YUMOBS, M_("both package {0} from {1} and {3} from {4} obsolete {2}")}, {ProblemRules::RULE_PKG_REMOVAL_OF_PROTECTED, @@ -223,6 +227,7 @@ std::string SolverProblems::problem_to_string(const std::pair Transaction::get_gpg_signature_problems() const noexcep void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_goal) { auto & pool = get_rpm_pool(base); + auto * installed_repo = pool->installed; libdnf5::rpm::PackageQuery skip_broken(base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); libdnf5::rpm::PackageQuery skip_conflict(base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); @@ -464,6 +465,7 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ for (auto & [rule, source, dep, target, description] : problem) { std::vector elements; ProblemRules tmp_rule = rule; + bool installed_conflicts = false; switch (rule) { case ProblemRules::RULE_INFARCH: case ProblemRules::RULE_PKG_NOT_INSTALLABLE_2: @@ -508,6 +510,10 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ elements.push_back(pool.dep2str(dep)); break; } + case ProblemRules::RULE_PKG_INSTALLED_REQUIRES: + elements.push_back(pool.dep2str(dep)); + elements.push_back(pool.solvid2str(source)); + break; case ProblemRules::RULE_PKG_NOTHING_PROVIDES_DEP: case ProblemRules::RULE_PKG_REQUIRES: { skip_broken.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); @@ -528,6 +534,9 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ elements.push_back(tgt_solvable->repo->name); break; } + case ProblemRules::RULE_PKG_INSTALLED_CONFLICTS: + installed_conflicts = true; + [[fallthrough]]; case ProblemRules::RULE_PKG_CONFLICTS: if (current_conflicting_rules.contains(std::pair(target, source))) { // do not add pkgA conflicts with pkgB rule if pkgB conflicts with PkgA rule is already present @@ -536,13 +545,22 @@ void Transaction::Impl::process_solver_problems(rpm::solv::GoalPrivate & solved_ skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(source))); skip_conflict.add(libdnf5::rpm::Package(base, libdnf5::rpm::PackageId(target))); current_conflicting_rules.emplace(source, target); + if (installed_conflicts) { + // RULE_PKG_INSTALLED_CONFLICTS expects the first(source) + // element to be an installed package + if (pool.id2solvable(source)->repo != installed_repo) { + std::swap(source, target); + } + } [[fallthrough]]; case ProblemRules::RULE_PKG_OBSOLETES: case ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES: case ProblemRules::RULE_YUMOBS: { auto * src_solvable = pool.id2solvable(source); elements.push_back(pool.solvable2str(src_solvable)); - elements.push_back(src_solvable->repo->name); + if (!installed_conflicts) { + elements.push_back(src_solvable->repo->name); + } elements.push_back(pool.dep2str(dep)); auto * tgt_solvable = pool.id2solvable(target); elements.push_back(pool.solvable2str(tgt_solvable)); diff --git a/libdnf5/rpm/solv/goal_private.cpp b/libdnf5/rpm/solv/goal_private.cpp index 99ece390e..3a8c16fa5 100644 --- a/libdnf5/rpm/solv/goal_private.cpp +++ b/libdnf5/rpm/solv/goal_private.cpp @@ -484,6 +484,7 @@ void GoalPrivate::write_debugdata(const std::filesystem::path & abs_dest_dir) { std::vector>> GoalPrivate::get_problems() { auto & pool = get_rpm_pool(); + auto * installed_repo = pool->installed; libdnf_assert_goal_resolved(); @@ -564,9 +565,15 @@ std::vector>> Goal case SOLVER_RULE_PKG_SAME_NAME: rule = ProblemRules::RULE_PKG_SAME_NAME; break; - case SOLVER_RULE_PKG_CONFLICTS: - rule = ProblemRules::RULE_PKG_CONFLICTS; - break; + case SOLVER_RULE_PKG_CONFLICTS: { + Solvable * src_solvable = pool.id2solvable(source); + Solvable * tgt_solvable = pool.id2solvable(target); + if (src_solvable->repo == installed_repo || tgt_solvable->repo == installed_repo) { + rule = ProblemRules::RULE_PKG_INSTALLED_CONFLICTS; + } else { + rule = ProblemRules::RULE_PKG_CONFLICTS; + } + } break; case SOLVER_RULE_PKG_OBSOLETES: rule = ProblemRules::RULE_PKG_OBSOLETES; break; @@ -576,9 +583,14 @@ std::vector>> Goal case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES: rule = ProblemRules::RULE_PKG_IMPLICIT_OBSOLETES; break; - case SOLVER_RULE_PKG_REQUIRES: - rule = ProblemRules::RULE_PKG_REQUIRES; - break; + case SOLVER_RULE_PKG_REQUIRES: { + Solvable * solvable = pool.id2solvable(source); + if (solvable->repo == installed_repo) { + rule = ProblemRules::RULE_PKG_INSTALLED_REQUIRES; + } else { + rule = ProblemRules::RULE_PKG_REQUIRES; + } + } break; case SOLVER_RULE_PKG_SELF_CONFLICT: rule = ProblemRules::RULE_PKG_SELF_CONFLICT; break;