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 423647123..8b0ee9b7d 100644 --- a/libdnf5/base/solver_problems.cpp +++ b/libdnf5/base/solver_problems.cpp @@ -39,8 +39,8 @@ 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_UPDATE, M_("problem with installed package ")}, + {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")}, {ProblemRules::RULE_JOB_NOTHING_PROVIDES_DEP, M_("nothing provides requested {}")}, @@ -49,19 +49,25 @@ 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_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, M_("The operation would result in removing" " the following protected packages: {}")}, @@ -179,17 +185,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,35 +218,23 @@ std::string SolverProblems::problem_to_string(const std::pair>>> SolverProblems::get_problems() const { return p_impl->problems; @@ -383,10 +407,12 @@ std::vector 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); @@ -458,18 +459,25 @@ 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) { std::vector elements; ProblemRules tmp_rule = rule; + bool installed_conflicts = false; 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 +491,90 @@ 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)); + 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: + 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_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 + continue; + } 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; + 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_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)); + 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)); + 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; 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;