diff --git a/dnf5/commands/group/group_install.cpp b/dnf5/commands/group/group_install.cpp index a8cfd0383..d64f59f2c 100644 --- a/dnf5/commands/group/group_install.cpp +++ b/dnf5/commands/group/group_install.cpp @@ -61,7 +61,7 @@ void GroupInstallCommand::run() { libdnf5::GoalJobSettings settings; if (no_packages->get_value()) { - settings.group_no_packages = true; + settings.set_group_no_packages(true); } if (with_optional->get_value()) { auto group_package_types = libdnf5::comps::package_type_from_string( diff --git a/dnf5/commands/group/group_remove.cpp b/dnf5/commands/group/group_remove.cpp index 5938ca0b3..623d74e81 100644 --- a/dnf5/commands/group/group_remove.cpp +++ b/dnf5/commands/group/group_remove.cpp @@ -52,7 +52,7 @@ void GroupRemoveCommand::run() { libdnf5::GoalJobSettings settings; if (no_packages->get_value()) { - settings.group_no_packages = true; + settings.set_group_no_packages(true); } for (const auto & spec : group_specs->get_value()) { goal->add_group_remove(spec, libdnf5::transaction::TransactionItemReason::USER, settings); diff --git a/dnf5daemon-server/services/goal/goal.cpp b/dnf5daemon-server/services/goal/goal.cpp index 1cf5dac16..a0ecbb70b 100644 --- a/dnf5daemon-server/services/goal/goal.cpp +++ b/dnf5daemon-server/services/goal/goal.cpp @@ -172,7 +172,7 @@ sdbus::MethodReply Goal::get_transaction_problems(sdbus::MethodCall & call) { goal_resolve_log_item["problem"] = static_cast(log.get_problem()); if (log.get_job_settings()) { dnfdaemon::KeyValueMap goal_job_settings; - goal_job_settings["to_repo_ids"] = log.get_job_settings()->to_repo_ids; + goal_job_settings["to_repo_ids"] = log.get_job_settings()->get_to_repo_ids(); goal_resolve_log_item["goal_job_settings"] = goal_job_settings; } if (log.get_spec()) { diff --git a/dnf5daemon-server/services/rpm/rpm.cpp b/dnf5daemon-server/services/rpm/rpm.cpp index f95a4db9c..064b959f3 100644 --- a/dnf5daemon-server/services/rpm/rpm.cpp +++ b/dnf5daemon-server/services/rpm/rpm.cpp @@ -311,7 +311,7 @@ sdbus::MethodReply Rpm::downgrade(sdbus::MethodCall & call) { // fill the goal auto & goal = session.get_goal(); libdnf5::GoalJobSettings setting; - setting.to_repo_ids = repo_ids; + setting.set_to_repo_ids(repo_ids); for (const auto & spec : specs) { goal.add_downgrade(spec, setting); } @@ -347,9 +347,9 @@ sdbus::MethodReply Rpm::install(sdbus::MethodCall & call) { // fill the goal auto & goal = session.get_goal(); libdnf5::GoalJobSettings setting; - setting.skip_broken = skip_broken; - setting.skip_unavailable = skip_unavailable; - setting.to_repo_ids = repo_ids; + setting.set_skip_broken(skip_broken); + setting.set_skip_unavailable(skip_unavailable); + setting.set_to_repo_ids(repo_ids); for (const auto & spec : specs) { goal.add_install(spec, setting); @@ -371,7 +371,7 @@ sdbus::MethodReply Rpm::upgrade(sdbus::MethodCall & call) { // fill the goal auto & goal = session.get_goal(); libdnf5::GoalJobSettings setting; - setting.to_repo_ids = repo_ids; + setting.set_to_repo_ids(repo_ids); if (specs.empty()) { goal.add_rpm_upgrade(setting); } else { @@ -396,7 +396,7 @@ sdbus::MethodReply Rpm::reinstall(sdbus::MethodCall & call) { // fill the goal auto & goal = session.get_goal(); libdnf5::GoalJobSettings setting; - setting.to_repo_ids = repo_ids; + setting.set_to_repo_ids(repo_ids); for (const auto & spec : specs) { goal.add_reinstall(spec, setting); } diff --git a/include/libdnf5/base/goal_elements.hpp b/include/libdnf5/base/goal_elements.hpp index af62038c3..f76fb6a87 100644 --- a/include/libdnf5/base/goal_elements.hpp +++ b/include/libdnf5/base/goal_elements.hpp @@ -199,46 +199,85 @@ struct ResolveSpecSettings { struct GoalJobSettings : public ResolveSpecSettings { public: + GoalJobSettings(); + ~GoalJobSettings(); + + GoalJobSettings(const GoalJobSettings & src); + GoalJobSettings(GoalJobSettings && src) noexcept; + GoalJobSettings & operator=(const GoalJobSettings & src); + GoalJobSettings & operator=(GoalJobSettings && src) noexcept; + /// Return used value for skip_broken - GoalUsedSetting get_used_skip_broken() const { return used_skip_broken; }; + GoalUsedSetting get_used_skip_broken() const; /// Return used value for skip_unavailable - GoalUsedSetting get_used_skip_unavailable() const { return used_skip_unavailable; }; + GoalUsedSetting get_used_skip_unavailable() const; /// Return used value for best - GoalUsedSetting get_used_best() const { return used_best; }; + GoalUsedSetting get_used_best() const; /// Return used value for clean_requirements_on_remove - GoalUsedSetting get_used_clean_requirements_on_remove() const { return used_clean_requirements_on_remove; }; + GoalUsedSetting get_used_clean_requirements_on_remove() const; - /// Optionally assign AdvisoryQuery that is used to filter goal target packages (used for upgrade and install) - void set_advisory_filter(const libdnf5::advisory::AdvisoryQuery & filter) { advisory_filter = filter; }; - const libdnf5::advisory::AdvisoryQuery * get_advisory_filter() const { - return advisory_filter ? &advisory_filter.value() : nullptr; - } + /// Optionally set AdvisoryQuery that is used to filter packages (used for upgrade). + /// Upgrades considers only packages that resolve some advisory in specified AdvisoryQuery. + /// + /// By default is is empty and no packages are filtered. + void set_advisory_filter(const libdnf5::advisory::AdvisoryQuery & filter); + const libdnf5::advisory::AdvisoryQuery * get_advisory_filter() const; - // Which types of group packages are going to be installed with the group. - // If not set, default is taken from ConfigMain.group_package_types - void set_group_package_types(const libdnf5::comps::PackageType type) { group_package_types = type; } - const libdnf5::comps::PackageType * get_group_package_types() const { - return group_package_types ? &group_package_types.value() : nullptr; - } + /// Which types of group packages are going to be installed with the group. + /// + /// Default is taken from ConfigMain.group_package_types + void set_group_package_types(libdnf5::comps::PackageType type); + const libdnf5::comps::PackageType * get_group_package_types() const; /// If set to true, group operations (install / remove / upgrade) will only work /// with the group itself, but will not add to the transaction any packages. - bool group_no_packages{false}; - - /// Set whether hints should be reported - bool report_hint{true}; - /// Set skip_broken, AUTO means that it is handled according to the default behavior - GoalSetting skip_broken{GoalSetting::AUTO}; - /// Set skip_unavailable, AUTO means that it is handled according to the default behavior - GoalSetting skip_unavailable{GoalSetting::AUTO}; - /// Set best, AUTO means that it is handled according to the default behavior - GoalSetting best{GoalSetting::AUTO}; - /// Set clean_requirements_on_remove, AUTO means that it is handled according to the default behavior - GoalSetting clean_requirements_on_remove{GoalSetting::AUTO}; - /// Define which installed packages should be modified according to repoid from which they were installed - std::vector from_repo_ids; - /// Reduce candidates for the operation according repository ids - std::vector to_repo_ids; + /// + /// Default: false + void set_group_no_packages(bool group_no_packages); + bool get_group_no_packages() const; + + /// Set whether to report packages providing alternatives (``alternative-for(..)`` provide) and packages + /// with different letter capitalization when no matches are found. + /// + /// Default: true + void set_report_hint(bool report_hint); + bool get_report_hint() const; + + /// Resolve any dependency problems by removing packages that are causing problems from the transaction. + /// + /// By default the value is taken from ``skip_broken`` configuration option. + void set_skip_broken(GoalSetting skip_broken); + GoalSetting get_skip_broken() const; + + /// Allow skipping packages that are unavailable. + /// + /// By default the value is taken from a configuration option ``skip_unavailable`` except for remove action + /// which defaults to true. + void set_skip_unavailable(GoalSetting skip_unavailable); + GoalSetting get_skip_unavailable() const; + + /// Try the best available package versions in transactions. + /// + /// By default the value is taken from ``best`` configuration option. + void set_best(GoalSetting best); + GoalSetting get_best() const; + + /// Remove dependencies that are no longer used during ``dnf remove``. + /// + /// By default the value is false except for remove action which defaults to value from + /// clean_requirements_on_remove configuration option. + void set_clean_requirements_on_remove(GoalSetting clean_requirements_on_remove); + GoalSetting get_clean_requirements_on_remove() const; + + /// Not implemented yet + void set_from_repo_ids(std::vector from_repo_ids); + std::vector get_from_repo_ids() const; + + /// Limit available packages to specified repositories. + /// + /// Empty by default. + void set_to_repo_ids(std::vector to_repo_ids); + std::vector get_to_repo_ids() const; private: friend class Goal; @@ -294,13 +333,8 @@ struct GoalJobSettings : public ResolveSpecSettings { /// @exception libdnf5::AssertionError When a different value already stored or when invalid value libdnf5::comps::PackageType resolve_group_package_types(const libdnf5::ConfigMain & cfg_main); - GoalUsedSetting used_skip_broken{GoalUsedSetting::UNUSED}; - GoalUsedSetting used_skip_unavailable{GoalUsedSetting::UNUSED}; - GoalUsedSetting used_best{GoalUsedSetting::UNUSED}; - GoalUsedSetting used_clean_requirements_on_remove{GoalUsedSetting::UNUSED}; - std::optional used_group_package_types{std::nullopt}; - std::optional advisory_filter{std::nullopt}; - std::optional group_package_types{std::nullopt}; + class Impl; + std::unique_ptr p_impl; }; diff --git a/libdnf5/base/goal.cpp b/libdnf5/base/goal.cpp index a028c3b6b..02c05f38e 100644 --- a/libdnf5/base/goal.cpp +++ b/libdnf5/base/goal.cpp @@ -369,13 +369,13 @@ void Goal::Impl::add_spec(GoalAction action, const std::string & spec, const Goa std::string group_spec = spec.substr(1); auto group_settings = libdnf5::GoalJobSettings(settings); // for compatibility reasons '@group-spec' can mean also environment - group_settings.group_search_environments = true; + group_settings.set_group_search_environments(true); // support for kickstart environmental groups syntax - '@^environment-spec' if (group_spec.starts_with("^")) { group_spec = group_spec.substr(1); - group_settings.group_search_groups = false; + group_settings.set_group_search_groups(false); } else { - group_settings.group_search_groups = true; + group_settings.set_group_search_groups(true); } group_specs.push_back( std::make_tuple(action, libdnf5::transaction::TransactionItemReason::USER, group_spec, group_settings)); @@ -508,9 +508,9 @@ GoalProblem Goal::Impl::add_specs_to_goal(base::Transaction & transaction) { rpm::PackageQuery query(base); // Apply advisory filters - if (settings.advisory_filter.has_value()) { + if (settings.get_advisory_filter() != nullptr) { filter_candidates_for_advisory_upgrade( - base, query, settings.advisory_filter.value(), cfg_main.get_obsoletes_option().get_value()); + base, query, *settings.get_advisory_filter(), cfg_main.get_obsoletes_option().get_value()); } // Make the smallest possible upgrade @@ -609,13 +609,13 @@ GoalProblem Goal::Impl::add_transaction_replay_specs_to_goal(base::Transaction & for (const auto & package_replay : serialized_transaction->first.packages) { libdnf5::GoalJobSettings settings_per_package = settings; - settings_per_package.clean_requirements_on_remove = libdnf5::GoalSetting::SET_FALSE; + settings_per_package.set_clean_requirements_on_remove(libdnf5::GoalSetting::SET_FALSE); if (!package_replay.repo_id.empty()) { repo::RepoQuery enabled_repos(base); enabled_repos.filter_enabled(true); enabled_repos.filter_id(package_replay.repo_id); if (!enabled_repos.empty()) { - settings_per_package.to_repo_ids = {package_replay.repo_id}; + settings_per_package.set_to_repo_ids({package_replay.repo_id}); } } @@ -653,16 +653,16 @@ GoalProblem Goal::Impl::add_transaction_replay_specs_to_goal(base::Transaction & for (const auto & group_replay : serialized_transaction->first.groups) { libdnf5::GoalJobSettings settings_per_group = settings; - settings_per_group.group_no_packages = true; - settings_per_group.group_search_groups = true; - settings_per_group.group_search_environments = false; + settings_per_group.set_group_no_packages(true); + settings_per_group.set_group_search_groups(true); + settings_per_group.set_group_search_environments(false); if (!group_replay.repo_id.empty()) { repo::RepoQuery enabled_repos(base); enabled_repos.filter_enabled(true); enabled_repos.filter_id(group_replay.repo_id); if (!enabled_repos.empty()) { //TODO(amatej): add ci test where we limit a group to repo - settings_per_group.to_repo_ids = {group_replay.repo_id}; + settings_per_group.set_to_repo_ids({group_replay.repo_id}); } } @@ -687,15 +687,15 @@ GoalProblem Goal::Impl::add_transaction_replay_specs_to_goal(base::Transaction & //TODO(amatej): add environment_no_groups to avoid handling groups twice // (once from the environment automatically and once from the replay) //settings_per_environment.environment_no_groups = true; - settings_per_environment.group_search_groups = false; - settings_per_environment.group_search_environments = true; + settings_per_environment.set_group_search_groups(false); + settings_per_environment.set_group_search_environments(true); if (!env_replay.repo_id.empty()) { repo::RepoQuery enabled_repos(base); enabled_repos.filter_enabled(true); enabled_repos.filter_id(env_replay.repo_id); if (!enabled_repos.empty()) { //TODO(amatej): add ci test where we limit an env to a repo - settings_per_environment.to_repo_ids = {env_replay.repo_id}; + settings_per_environment.set_to_repo_ids({env_replay.repo_id}); } } @@ -738,7 +738,7 @@ GoalProblem Goal::Impl::resolve_group_specs(std::vector & specs, base for (auto & [action, reason, spec, settings] : specs) { // For the REMOVE action, skip_unavailable defaults to true, ensuring // that the removal of a not-installed group is not treated as an error. - bool skip_unavailable = (action == GoalAction::REMOVE && settings.skip_unavailable == GoalSetting::AUTO) + bool skip_unavailable = (action == GoalAction::REMOVE && settings.get_skip_unavailable() == GoalSetting::AUTO) ? true : settings.resolve_skip_unavailable(cfg_main); auto log_level = skip_unavailable ? libdnf5::Logger::Level::WARNING : libdnf5::Logger::Level::ERROR; @@ -757,19 +757,19 @@ GoalProblem Goal::Impl::resolve_group_specs(std::vector & specs, base } sack::QueryCmp cmp = settings.get_ignore_case() ? sack::QueryCmp::IGLOB : sack::QueryCmp::GLOB; bool spec_resolved{false}; - if (settings.group_search_groups) { + if (settings.get_group_search_groups()) { comps::GroupQuery group_query(base, true); comps::GroupQuery spec_groups_query(base_groups_query); // for REMOVE / UPGRADE actions take only installed groups into account // for INSTALL only available groups spec_groups_query.filter_installed(action != GoalAction::INSTALL && action != GoalAction::INSTALL_BY_COMPS); - if (settings.group_with_id) { + if (settings.get_group_with_id()) { comps::GroupQuery group_query_id(spec_groups_query); group_query_id.filter_groupid(spec, cmp); group_query |= group_query_id; } // TODO(mblaha): reconsider usefulness of searching groups by names - if (settings.group_with_name) { + if (settings.get_group_with_name()) { comps::GroupQuery group_query_name(spec_groups_query); group_query_name.filter_name(spec, cmp); group_query |= group_query_name; @@ -779,17 +779,17 @@ GoalProblem Goal::Impl::resolve_group_specs(std::vector & specs, base spec_resolved = true; } } - if (settings.group_search_environments) { + if (settings.get_group_search_environments()) { comps::EnvironmentQuery environment_query(base, true); comps::EnvironmentQuery spec_environments_query(base_environments_query); spec_environments_query.filter_installed(action != GoalAction::INSTALL); - if (settings.group_with_id) { + if (settings.get_group_with_id()) { comps::EnvironmentQuery environment_query_id(spec_environments_query); environment_query_id.filter_environmentid(spec, cmp); environment_query |= environment_query_id; } // TODO(mblaha): reconsider usefulness of searching groups by names - if (settings.group_with_name) { + if (settings.get_group_with_name()) { comps::EnvironmentQuery environment_query_name(spec_environments_query); environment_query_name.filter_name(spec, cmp); environment_query |= environment_query_name; @@ -881,7 +881,7 @@ std::pair Goal::Impl::add_install_to_goal( // The correct evaluation of rich dependencies can be only performed by solver. // There are some limitations - solver is unable to handle when operation is limited to packages from the // particular repository and multilib_policy `all`. - if (libdnf5::rpm::Reldep::is_rich_dependency(spec) && settings.to_repo_ids.empty()) { + if (libdnf5::rpm::Reldep::is_rich_dependency(spec) && settings.get_to_repo_ids().empty()) { add_provide_install_to_goal(spec, settings); return {GoalProblem::NO_PROBLEM, result_queue}; } @@ -905,8 +905,8 @@ std::pair Goal::Impl::add_install_to_goal( bool skip_broken = settings.resolve_skip_broken(cfg_main); if (multilib_policy == "all" || utils::is_glob_pattern(nevra_pair.second.get_arch().c_str())) { - if (!settings.to_repo_ids.empty()) { - query.filter_repo_id(settings.to_repo_ids, sack::QueryCmp::GLOB); + if (!settings.get_to_repo_ids().empty()) { + query.filter_repo_id(settings.get_to_repo_ids(), sack::QueryCmp::GLOB); if (query.empty()) { transaction.p_impl->add_resolve_log( action, @@ -922,8 +922,8 @@ std::pair Goal::Impl::add_install_to_goal( } // Apply advisory filters - if (settings.advisory_filter.has_value()) { - query.filter_advisories(settings.advisory_filter.value(), libdnf5::sack::QueryCmp::EQ); + if (settings.get_advisory_filter() != nullptr) { + query.filter_advisories(*settings.get_advisory_filter(), libdnf5::sack::QueryCmp::EQ); } /// >> @@ -994,8 +994,8 @@ std::pair Goal::Impl::add_install_to_goal( (nevra_pair.second.get_name().empty() && (!nevra_pair.second.get_epoch().empty() || !nevra_pair.second.get_version().empty() || !nevra_pair.second.get_release().empty() || !nevra_pair.second.get_arch().empty()))) { - if (!settings.to_repo_ids.empty()) { - query.filter_repo_id(settings.to_repo_ids, sack::QueryCmp::GLOB); + if (!settings.get_to_repo_ids().empty()) { + query.filter_repo_id(settings.get_to_repo_ids(), sack::QueryCmp::GLOB); if (query.empty()) { transaction.p_impl->add_resolve_log( action, @@ -1011,8 +1011,8 @@ std::pair Goal::Impl::add_install_to_goal( } // Apply advisory filters - if (settings.advisory_filter.has_value()) { - query.filter_advisories(settings.advisory_filter.value(), libdnf5::sack::QueryCmp::EQ); + if (settings.get_advisory_filter() != nullptr) { + query.filter_advisories(*settings.get_advisory_filter(), libdnf5::sack::QueryCmp::EQ); } rpm::PackageQuery available(query); @@ -1070,8 +1070,8 @@ std::pair Goal::Impl::add_install_to_goal( if (add_obsoletes) { add_obsoletes_to_data(base_query, query); } - if (!settings.to_repo_ids.empty()) { - query.filter_repo_id(settings.to_repo_ids, sack::QueryCmp::GLOB); + if (!settings.get_to_repo_ids().empty()) { + query.filter_repo_id(settings.get_to_repo_ids(), sack::QueryCmp::GLOB); if (query.empty()) { transaction.p_impl->add_resolve_log( action, @@ -1087,8 +1087,8 @@ std::pair Goal::Impl::add_install_to_goal( } // Apply advisory filters - if (settings.advisory_filter.has_value()) { - query.filter_advisories(settings.advisory_filter.value(), libdnf5::sack::QueryCmp::EQ); + if (settings.get_advisory_filter() != nullptr) { + query.filter_advisories(*settings.get_advisory_filter(), libdnf5::sack::QueryCmp::EQ); } solv_map_to_id_queue(result_queue, *query.p_impl); rpm_goal.add_install(result_queue, skip_broken, best, clean_requirements_on_remove); @@ -1200,8 +1200,8 @@ GoalProblem Goal::Impl::add_reinstall_to_goal( // TODO(jmracek) Implement filtering from_repo_ids - if (!settings.to_repo_ids.empty()) { - relevant_available.filter_repo_id(settings.to_repo_ids, sack::QueryCmp::GLOB); + if (!settings.get_to_repo_ids().empty()) { + relevant_available.filter_repo_id(settings.get_to_repo_ids(), sack::QueryCmp::GLOB); if (relevant_available.empty()) { transaction.p_impl->add_resolve_log( GoalAction::REINSTALL, @@ -1469,7 +1469,7 @@ GoalProblem Goal::Impl::add_remove_to_goal( if (!nevra_pair.first) { auto & cfg_main = base->get_config(); bool skip_unavailable = - settings.skip_unavailable == GoalSetting::AUTO ? true : settings.resolve_skip_unavailable(cfg_main); + settings.get_skip_unavailable() == GoalSetting::AUTO ? true : settings.resolve_skip_unavailable(cfg_main); auto problem = transaction.p_impl->report_not_found( GoalAction::REMOVE, spec, @@ -1478,7 +1478,7 @@ GoalProblem Goal::Impl::add_remove_to_goal( return skip_unavailable ? GoalProblem::NO_PROBLEM : problem; } - if (!settings.from_repo_ids.empty()) { + if (!settings.get_from_repo_ids().empty()) { // TODO(jmracek) keep only packages installed from repo_id -requires swdb if (query.empty()) { // TODO(jmracek) no solution for the spec => mark result - not from repository @@ -1574,8 +1574,8 @@ GoalProblem Goal::Impl::add_up_down_distrosync_to_goal( query |= obsoletes_query; } } - if (!settings.to_repo_ids.empty()) { - query.filter_repo_id(settings.to_repo_ids, sack::QueryCmp::GLOB); + if (!settings.get_to_repo_ids().empty()) { + query.filter_repo_id(settings.get_to_repo_ids(), sack::QueryCmp::GLOB); if (query.empty()) { transaction.p_impl->add_resolve_log( action, @@ -1591,8 +1591,8 @@ GoalProblem Goal::Impl::add_up_down_distrosync_to_goal( } // Apply advisory filters - if (settings.advisory_filter.has_value()) { - filter_candidates_for_advisory_upgrade(base, query, settings.advisory_filter.value(), obsoletes); + if (settings.get_advisory_filter() != nullptr) { + filter_candidates_for_advisory_upgrade(base, query, *settings.get_advisory_filter(), obsoletes); } if (minimal) { @@ -1759,7 +1759,7 @@ void Goal::Impl::add_group_install_to_goal( auto allowed_package_types = settings.resolve_group_package_types(cfg_main); for (auto group : group_query) { rpm_goal.add_group(group, transaction::TransactionItemAction::INSTALL, reason, allowed_package_types); - if (settings.group_no_packages) { + if (settings.get_group_no_packages()) { continue; } std::vector packages; @@ -1797,7 +1797,7 @@ void Goal::Impl::add_group_remove_to_goal( for (auto & [spec, reason, group_query, settings] : groups_to_remove) { for (const auto & group : group_query) { rpm_goal.add_group(group, transaction::TransactionItemAction::REMOVE, reason, {}); - if (settings.group_no_packages) { + if (settings.get_group_no_packages()) { continue; } // get all packages installed by the group @@ -1871,7 +1871,7 @@ void Goal::Impl::add_group_upgrade_to_goal( installed_group.get_reason(), allowed_package_types); - if (settings.group_no_packages) { + if (settings.get_group_no_packages()) { continue; } @@ -1929,8 +1929,8 @@ void Goal::Impl::add_environment_install_to_goal( auto & cfg_main = base->get_config(); bool with_optional = any(settings.resolve_group_package_types(cfg_main) & libdnf5::comps::PackageType::OPTIONAL); auto group_settings = libdnf5::GoalJobSettings(settings); - group_settings.group_search_environments = false; - group_settings.group_search_groups = true; + group_settings.set_group_search_environments(false); + group_settings.set_group_search_groups(true); std::vector env_group_specs; for (auto environment : environment_query) { rpm_goal.add_environment(environment, transaction::TransactionItemAction::INSTALL, with_optional); @@ -1971,8 +1971,8 @@ void Goal::Impl::add_environment_remove_to_goal( // groups that are candidates for removal std::vector remove_group_specs; auto group_settings = libdnf5::GoalJobSettings(); - group_settings.group_search_environments = false; - group_settings.group_search_groups = true; + group_settings.set_group_search_environments(false); + group_settings.set_group_search_groups(true); for (auto & [spec, environment_query, settings] : environments_to_remove) { for (const auto & environment : environment_query) { rpm_goal.add_environment(environment, transaction::TransactionItemAction::REMOVE, {}); @@ -2022,8 +2022,8 @@ void Goal::Impl::add_environment_upgrade_to_goal( std::vector env_group_specs; auto group_settings = libdnf5::GoalJobSettings(settings); - group_settings.group_search_environments = false; - group_settings.group_search_groups = true; + group_settings.set_group_search_environments(false); + group_settings.set_group_search_groups(true); for (auto installed_environment : environment_query) { auto environment_id = installed_environment.get_environmentid(); diff --git a/libdnf5/base/goal_elements.cpp b/libdnf5/base/goal_elements.cpp index b3a81f239..f92852be0 100644 --- a/libdnf5/base/goal_elements.cpp +++ b/libdnf5/base/goal_elements.cpp @@ -127,9 +127,69 @@ bool ResolveSpecSettings::get_group_search_environments() const { return p_impl->group_search_environments; } +class GoalJobSettings::Impl { + friend GoalJobSettings; + /// If set to true, group operations (install / remove / upgrade) will only work + /// with the group itself, but will not add to the transaction any packages. + bool group_no_packages{false}; + + /// Set whether hints should be reported + bool report_hint{true}; + + /// Set skip_broken, AUTO means that it is handled according to the default behavior + /// If set resolve depsolve problems by removing packages that are causing them from the transaction. + GoalSetting skip_broken{GoalSetting::AUTO}; + + ///// Set skip_unavailable, AUTO means that it is handled according to the default behavior + ///// If set and some packages stored in the transaction are not available on the target system, + ///// skip them instead of erroring out. + GoalSetting skip_unavailable{GoalSetting::AUTO}; + + ///// Set best, AUTO means that it is handled according to the default behavior + GoalSetting best{GoalSetting::AUTO}; + + ///// Set clean_requirements_on_remove, AUTO means that it is handled according to the default behavior + GoalSetting clean_requirements_on_remove{GoalSetting::AUTO}; + + ///// Define which installed packages should be modified according to repoid from which they were installed + std::vector from_repo_ids; + ///// Reduce candidates for the operation according repository ids + std::vector to_repo_ids; + + GoalUsedSetting used_skip_broken{GoalUsedSetting::UNUSED}; + GoalUsedSetting used_skip_unavailable{GoalUsedSetting::UNUSED}; + GoalUsedSetting used_best{GoalUsedSetting::UNUSED}; + GoalUsedSetting used_clean_requirements_on_remove{GoalUsedSetting::UNUSED}; + std::optional used_group_package_types{std::nullopt}; + std::optional advisory_filter{std::nullopt}; + std::optional group_package_types{std::nullopt}; +}; + +GoalJobSettings::~GoalJobSettings() = default; +GoalJobSettings::GoalJobSettings() : p_impl(std::make_unique()) {} +GoalJobSettings::GoalJobSettings(const GoalJobSettings & src) + : ResolveSpecSettings(src), + p_impl(new Impl(*src.p_impl)) {} +GoalJobSettings::GoalJobSettings(GoalJobSettings && src) noexcept = default; + +GoalJobSettings & GoalJobSettings::operator=(const GoalJobSettings & src) { + ResolveSpecSettings::operator=(src); + if (this != &src) { + if (p_impl) { + *p_impl = *src.p_impl; + } else { + p_impl = std::make_unique(*src.p_impl); + } + } + + return *this; +} +GoalJobSettings & GoalJobSettings::operator=(GoalJobSettings && src) noexcept = default; + + bool GoalJobSettings::resolve_skip_broken(const libdnf5::ConfigMain & cfg_main) { auto resolved = GoalUsedSetting::UNUSED; - switch (skip_broken) { + switch (p_impl->skip_broken) { case GoalSetting::AUTO: { bool skip_broken = cfg_main.get_skip_broken_option().get_value(); resolved = skip_broken ? GoalUsedSetting::USED_TRUE : GoalUsedSetting::USED_FALSE; @@ -143,16 +203,16 @@ bool GoalJobSettings::resolve_skip_broken(const libdnf5::ConfigMain & cfg_main) } libdnf_assert( - used_skip_broken == GoalUsedSetting::UNUSED || resolved == used_skip_broken, + p_impl->used_skip_broken == GoalUsedSetting::UNUSED || resolved == p_impl->used_skip_broken, "\"skip_broken\" is already set to a different value"); - used_skip_broken = resolved; + p_impl->used_skip_broken = resolved; return resolved == GoalUsedSetting::USED_TRUE; } bool GoalJobSettings::resolve_skip_unavailable(const libdnf5::ConfigMain & cfg_main) { auto resolved = GoalUsedSetting::UNUSED; - switch (skip_unavailable) { + switch (p_impl->skip_unavailable) { case GoalSetting::AUTO: { bool skip_unavailable = cfg_main.get_skip_unavailable_option().get_value(); resolved = skip_unavailable ? GoalUsedSetting::USED_TRUE : GoalUsedSetting::USED_FALSE; @@ -166,29 +226,29 @@ bool GoalJobSettings::resolve_skip_unavailable(const libdnf5::ConfigMain & cfg_m } libdnf_assert( - used_skip_unavailable == GoalUsedSetting::UNUSED || resolved == used_skip_unavailable, + p_impl->used_skip_unavailable == GoalUsedSetting::UNUSED || resolved == p_impl->used_skip_unavailable, "\"skip_unavailable\" is already set to a different value"); - used_skip_unavailable = resolved; + p_impl->used_skip_unavailable = resolved; return resolved == GoalUsedSetting::USED_TRUE; } bool GoalJobSettings::resolve_skip_broken() { - bool skip_broken_bool = skip_broken == GoalSetting::SET_TRUE; + bool skip_broken_bool = p_impl->skip_broken == GoalSetting::SET_TRUE; auto resolved = skip_broken_bool ? GoalUsedSetting::USED_TRUE : GoalUsedSetting::USED_FALSE; libdnf_assert( - used_skip_broken == GoalUsedSetting::UNUSED || resolved == used_skip_broken, + p_impl->used_skip_broken == GoalUsedSetting::UNUSED || resolved == p_impl->used_skip_broken, "Used value for 'used_skip_broken' already set"); - used_skip_broken = resolved; + p_impl->used_skip_broken = resolved; return skip_broken_bool; } bool GoalJobSettings::resolve_best(const libdnf5::ConfigMain & cfg_main) { auto resolved = GoalUsedSetting::UNUSED; - switch (best) { + switch (p_impl->best) { case GoalSetting::AUTO: { bool best = cfg_main.get_best_option().get_value(); resolved = best ? GoalUsedSetting::USED_TRUE : GoalUsedSetting::USED_FALSE; @@ -202,15 +262,16 @@ bool GoalJobSettings::resolve_best(const libdnf5::ConfigMain & cfg_main) { } libdnf_assert( - used_best == GoalUsedSetting::UNUSED || resolved == used_best, "'best' is already set to a different value"); + p_impl->used_best == GoalUsedSetting::UNUSED || resolved == p_impl->used_best, + "'best' is already set to a different value"); - used_best = resolved; + p_impl->used_best = resolved; return resolved == GoalUsedSetting::USED_TRUE; } bool GoalJobSettings::resolve_clean_requirements_on_remove(const libdnf5::ConfigMain & cfg_main) { auto resolved = GoalUsedSetting::UNUSED; - switch (clean_requirements_on_remove) { + switch (p_impl->clean_requirements_on_remove) { case GoalSetting::AUTO: { bool clean_requirements_on_remove = cfg_main.get_clean_requirements_on_remove_option().get_value(); resolved = clean_requirements_on_remove ? GoalUsedSetting::USED_TRUE : GoalUsedSetting::USED_FALSE; @@ -224,38 +285,40 @@ bool GoalJobSettings::resolve_clean_requirements_on_remove(const libdnf5::Config } libdnf_assert( - used_clean_requirements_on_remove == GoalUsedSetting::UNUSED || resolved == used_clean_requirements_on_remove, + p_impl->used_clean_requirements_on_remove == GoalUsedSetting::UNUSED || + resolved == p_impl->used_clean_requirements_on_remove, "'clean_requirements_on_remove' is already set to a different value"); - used_clean_requirements_on_remove = resolved; + p_impl->used_clean_requirements_on_remove = resolved; return resolved == GoalUsedSetting::USED_TRUE; } bool GoalJobSettings::resolve_clean_requirements_on_remove() { - bool on_remove = clean_requirements_on_remove == GoalSetting::SET_TRUE; + bool on_remove = p_impl->clean_requirements_on_remove == GoalSetting::SET_TRUE; auto resolved = on_remove ? GoalUsedSetting::USED_TRUE : GoalUsedSetting::USED_FALSE; libdnf_assert( - used_clean_requirements_on_remove == GoalUsedSetting::UNUSED || resolved == used_clean_requirements_on_remove, + p_impl->used_clean_requirements_on_remove == GoalUsedSetting::UNUSED || + resolved == p_impl->used_clean_requirements_on_remove, "Used value for 'used_clean_requirements_on_remove' already set"); - used_clean_requirements_on_remove = resolved; + p_impl->used_clean_requirements_on_remove = resolved; return on_remove; } libdnf5::comps::PackageType GoalJobSettings::resolve_group_package_types(const libdnf5::ConfigMain & cfg_main) { - auto resolved = group_package_types; + auto resolved = p_impl->group_package_types; if (!resolved) { resolved = libdnf5::comps::package_type_from_string(cfg_main.get_group_package_types_option().get_value()); } libdnf_assert( - !used_group_package_types || used_group_package_types == resolved, + !p_impl->used_group_package_types || p_impl->used_group_package_types == resolved, "Used value for 'used_group_package_types' already set"); - used_group_package_types = resolved; + p_impl->used_group_package_types = resolved; - return *used_group_package_types; + return *p_impl->used_group_package_types; } std::string goal_action_to_string(GoalAction action) { @@ -300,4 +363,88 @@ std::string goal_action_to_string(GoalAction action) { return ""; } + +void GoalJobSettings::set_report_hint(bool report_hint) { + p_impl->report_hint = report_hint; +} +bool GoalJobSettings::get_report_hint() const { + return p_impl->report_hint; +} + +void GoalJobSettings::set_skip_broken(GoalSetting skip_broken) { + p_impl->skip_broken = skip_broken; +} +GoalSetting GoalJobSettings::get_skip_broken() const { + return p_impl->skip_broken; +} + +void GoalJobSettings::set_skip_unavailable(GoalSetting skip_unavailable) { + p_impl->skip_unavailable = skip_unavailable; +} +GoalSetting GoalJobSettings::get_skip_unavailable() const { + return p_impl->skip_unavailable; +} + +void GoalJobSettings::set_best(GoalSetting best) { + p_impl->best = best; +} +GoalSetting GoalJobSettings::get_best() const { + return p_impl->best; +} + +void GoalJobSettings::set_clean_requirements_on_remove(GoalSetting clean_requirements_on_remove) { + p_impl->clean_requirements_on_remove = clean_requirements_on_remove; +} +GoalSetting GoalJobSettings::get_clean_requirements_on_remove() const { + return p_impl->clean_requirements_on_remove; +} + +void GoalJobSettings::set_from_repo_ids(std::vector from_repo_ids) { + p_impl->from_repo_ids = std::move(from_repo_ids); +} +std::vector GoalJobSettings::get_from_repo_ids() const { + return p_impl->from_repo_ids; +} + +void GoalJobSettings::set_to_repo_ids(std::vector to_repo_ids) { + p_impl->to_repo_ids = std::move(to_repo_ids); +} +std::vector GoalJobSettings::get_to_repo_ids() const { + return p_impl->to_repo_ids; +} + +void GoalJobSettings::set_group_no_packages(bool group_no_packages) { + p_impl->group_no_packages = group_no_packages; +} +bool GoalJobSettings::get_group_no_packages() const { + return p_impl->group_no_packages; +} + +void GoalJobSettings::set_advisory_filter(const libdnf5::advisory::AdvisoryQuery & filter) { + p_impl->advisory_filter = filter; +}; +const libdnf5::advisory::AdvisoryQuery * GoalJobSettings::get_advisory_filter() const { + return p_impl->advisory_filter ? &p_impl->advisory_filter.value() : nullptr; +} + +void GoalJobSettings::set_group_package_types(const libdnf5::comps::PackageType type) { + p_impl->group_package_types = type; +} +const libdnf5::comps::PackageType * GoalJobSettings::get_group_package_types() const { + return p_impl->group_package_types ? &p_impl->group_package_types.value() : nullptr; +} + +GoalUsedSetting GoalJobSettings::get_used_skip_broken() const { + return p_impl->used_skip_broken; +}; +GoalUsedSetting GoalJobSettings::get_used_skip_unavailable() const { + return p_impl->used_skip_unavailable; +}; +GoalUsedSetting GoalJobSettings::get_used_best() const { + return p_impl->used_best; +}; +GoalUsedSetting GoalJobSettings::get_used_clean_requirements_on_remove() const { + return p_impl->used_clean_requirements_on_remove; +}; + } // namespace libdnf5 diff --git a/libdnf5/base/log_event.cpp b/libdnf5/base/log_event.cpp index 62273c4b3..298b49a6e 100644 --- a/libdnf5/base/log_event.cpp +++ b/libdnf5/base/log_event.cpp @@ -102,7 +102,7 @@ std::string LogEvent::to_string( return ret.append(utils::sformat( _("No match for argument '{0}' in repositories '{1}'"), *spec, - utils::string::join(settings->to_repo_ids, ", "))); + utils::string::join(settings->get_to_repo_ids(), ", "))); case GoalProblem::NOT_INSTALLED: return ret.append(utils::sformat(_("Packages for argument '{}' available, but not installed."), *spec)); case GoalProblem::NOT_INSTALLED_FOR_ARCHITECTURE: diff --git a/libdnf5/base/transaction.cpp b/libdnf5/base/transaction.cpp index 29d8c01c0..34060c914 100644 --- a/libdnf5/base/transaction.cpp +++ b/libdnf5/base/transaction.cpp @@ -182,7 +182,7 @@ GoalProblem Transaction::Impl::report_not_found( pkg_spec, {}, log_level); - if (settings.report_hint) { + if (settings.get_report_hint()) { rpm::PackageQuery hints(base); if (action == GoalAction::REMOVE) { hints.filter_installed();