diff --git a/dnf5-plugins/builddep_plugin/builddep.cpp b/dnf5-plugins/builddep_plugin/builddep.cpp index b75b009b6..c843919fb 100644 --- a/dnf5-plugins/builddep_plugin/builddep.cpp +++ b/dnf5-plugins/builddep_plugin/builddep.cpp @@ -188,10 +188,11 @@ bool BuildDepCommand::add_from_pkg( auto & ctx = get_context(); libdnf5::rpm::PackageQuery pkg_query(ctx.base); - pkg_query.resolve_pkg_spec( - pkg_spec, - libdnf5::ResolveSpecSettings{.with_provides = false, .with_filenames = false, .with_binaries = false}, - false); + libdnf5::ResolveSpecSettings settings; + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); + pkg_query.resolve_pkg_spec(pkg_spec, settings, false); std::vector source_names{pkg_spec}; for (const auto & pkg : pkg_query) { @@ -273,8 +274,8 @@ void BuildDepCommand::run() { // Search only for solution in provides and files. Use buildrequire with name search might result in inconsistent // behavior with installing dependencies of RPMs libdnf5::GoalJobSettings settings; - settings.with_nevra = false; - settings.with_binaries = false; + settings.set_with_nevra(false); + settings.set_with_binaries(false); for (const auto & spec : install_specs) { if (libdnf5::rpm::Reldep::is_rich_dependency(spec)) { diff --git a/dnf5-plugins/changelog_plugin/changelog.cpp b/dnf5-plugins/changelog_plugin/changelog.cpp index 9d189c029..ef4daa5c4 100644 --- a/dnf5-plugins/changelog_plugin/changelog.cpp +++ b/dnf5-plugins/changelog_plugin/changelog.cpp @@ -141,12 +141,12 @@ void ChangelogCommand::run() { //query libdnf5::rpm::PackageQuery query(ctx.base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); - libdnf5::ResolveSpecSettings settings{ - .ignore_case = true, - .with_nevra = true, - .with_provides = false, - .with_filenames = false, - .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(true); + settings.set_with_nevra(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); if (pkgs_spec_to_show_options->size() > 0) { for (auto & pattern : *pkgs_spec_to_show_options) { libdnf5::rpm::PackageQuery package_query(full_package_query); diff --git a/dnf5-plugins/repoclosure_plugin/repoclosure.cpp b/dnf5-plugins/repoclosure_plugin/repoclosure.cpp index 3b2506079..eff66aa43 100644 --- a/dnf5-plugins/repoclosure_plugin/repoclosure.cpp +++ b/dnf5-plugins/repoclosure_plugin/repoclosure.cpp @@ -139,8 +139,11 @@ void RepoclosureCommand::run() { if (!pkg_specs.empty()) { libdnf5::rpm::PackageQuery to_check_pkgs(ctx.base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); - libdnf5::ResolveSpecSettings settings{ - .with_nevra = true, .with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_nevra(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); bool specs_resolved = true; for (const auto & spec : pkg_specs) { libdnf5::rpm::PackageQuery package_query(to_check_query); diff --git a/dnf5/commands/check-upgrade/check-upgrade.cpp b/dnf5/commands/check-upgrade/check-upgrade.cpp index c804dbd97..f53ffbc26 100644 --- a/dnf5/commands/check-upgrade/check-upgrade.cpp +++ b/dnf5/commands/check-upgrade/check-upgrade.cpp @@ -113,8 +113,11 @@ void CheckUpgradeCommand::run() { // filter by provided specs, for `check-upgrade ...` if (!pkg_specs.empty()) { upgrades_query = libdnf5::rpm::PackageQuery(ctx.base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); - libdnf5::ResolveSpecSettings settings{ - .with_nevra = true, .with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_nevra(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); for (const auto & spec : pkg_specs) { libdnf5::rpm::PackageQuery package_query(ctx.base); package_query.resolve_pkg_spec(spec, settings, true); 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/dnf5/commands/list/list.cpp b/dnf5/commands/list/list.cpp index 524afd7b9..e196da1ef 100644 --- a/dnf5/commands/list/list.cpp +++ b/dnf5/commands/list/list.cpp @@ -151,8 +151,11 @@ void ListCommand::run() { // pre-select by patterns if (!pkg_specs.empty()) { base_query = libdnf5::rpm::PackageQuery(ctx.base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); - libdnf5::ResolveSpecSettings settings{ - .with_nevra = true, .with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_nevra(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); for (const auto & spec : pkg_specs) { libdnf5::rpm::PackageQuery pkg_query(full_package_query); pkg_query.resolve_pkg_spec(spec, settings, true); diff --git a/dnf5/commands/remove/remove.cpp b/dnf5/commands/remove/remove.cpp index ca02d3176..078e6457d 100644 --- a/dnf5/commands/remove/remove.cpp +++ b/dnf5/commands/remove/remove.cpp @@ -69,10 +69,10 @@ void RemoveCommand::run() { // Limit remove spec capabity to prevent multiple matches. Remove command should not match anything after performing // a remove action with the same spec. NEVRA and filenames are the only types that have no overlaps. libdnf5::GoalJobSettings settings; - settings.with_nevra = true; - settings.with_provides = false; - settings.with_filenames = true; - settings.with_binaries = false; + settings.set_with_nevra(true); + settings.set_with_provides(false); + settings.set_with_filenames(true); + settings.set_with_binaries(false); for (const auto & spec : pkg_specs) { goal->add_remove(spec, settings); } diff --git a/dnf5/commands/repoquery/repoquery.cpp b/dnf5/commands/repoquery/repoquery.cpp index fa3f11176..ac33d5674 100644 --- a/dnf5/commands/repoquery/repoquery.cpp +++ b/dnf5/commands/repoquery/repoquery.cpp @@ -534,9 +534,9 @@ static libdnf5::rpm::PackageSet resolve_nevras_to_packges( libdnf5::Base & base, const std::vector & nevra_globs, const libdnf5::rpm::PackageQuery & base_query) { auto resolved_nevras_set = libdnf5::rpm::PackageSet(base); auto settings = libdnf5::ResolveSpecSettings(); - settings.with_provides = false; - settings.with_filenames = false; - settings.with_binaries = false; + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); for (const auto & nevra : nevra_globs) { auto tmp_query = base_query; tmp_query.resolve_pkg_spec(nevra, settings, true); @@ -566,8 +566,10 @@ void RepoqueryCommand::run() { } } - const libdnf5::ResolveSpecSettings settings{ - .ignore_case = true, .with_provides = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(true); + settings.set_with_provides(false); + settings.set_with_binaries(false); for (const auto & spec : pkg_specs) { libdnf5::rpm::PackageQuery package_query(base_query); package_query.resolve_pkg_spec(spec, settings, true); diff --git a/dnf5/context.cpp b/dnf5/context.cpp index 942e69a59..fd806a2d9 100644 --- a/dnf5/context.cpp +++ b/dnf5/context.cpp @@ -601,10 +601,12 @@ std::vector match_specs( std::set result_set; { libdnf5::rpm::PackageQuery matched_pkgs_query(base); - matched_pkgs_query.resolve_pkg_spec( - pattern + '*', - {.ignore_case = false, .with_provides = false, .with_filenames = false, .with_binaries = false}, - true); + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(false); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); + matched_pkgs_query.resolve_pkg_spec(pattern + '*', settings, true); for (const auto & package : matched_pkgs_query) { auto [it, inserted] = result_set.insert(package.get_name()); 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 5e30eb53c..064b959f3 100644 --- a/dnf5daemon-server/services/rpm/rpm.cpp +++ b/dnf5daemon-server/services/rpm/rpm.cpp @@ -73,7 +73,10 @@ std::vector get_filter_patterns(dnfdaemon::KeyValueMap options, con libdnf5::rpm::PackageQuery resolve_nevras(libdnf5::rpm::PackageQuery base_query, std::vector nevras) { libdnf5::rpm::PackageQuery result(base_query.get_base(), libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); - libdnf5::ResolveSpecSettings settings{.with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); for (const auto & nevra : nevras) { libdnf5::rpm::PackageQuery nevra_query(base_query); nevra_query.resolve_pkg_spec(nevra, settings, false); @@ -120,12 +123,12 @@ sdbus::MethodReply Rpm::list(sdbus::MethodCall & call) { libdnf5::rpm::PackageQuery result(*base, libdnf5::sack::ExcludeFlags::APPLY_EXCLUDES, true); // packages matching flags bool with_src = key_value_map_get(options, "with_src", true); - libdnf5::ResolveSpecSettings settings{ - .ignore_case = key_value_map_get(options, "icase", true), - .with_nevra = key_value_map_get(options, "with_nevra", true), - .with_provides = key_value_map_get(options, "with_provides", true), - .with_filenames = key_value_map_get(options, "with_filenames", true), - .with_binaries = key_value_map_get(options, "with_binaries", true)}; + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(key_value_map_get(options, "icase", true)); + settings.set_with_nevra(key_value_map_get(options, "with_nevra", true)); + settings.set_with_provides(key_value_map_get(options, "with_provides", true)); + settings.set_with_filenames(key_value_map_get(options, "with_filenames", true)); + settings.set_with_binaries(key_value_map_get(options, "with_binaries", true)); for (auto & pattern : patterns) { libdnf5::rpm::PackageQuery package_query(query); package_query.resolve_pkg_spec(pattern, settings, with_src); @@ -308,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); } @@ -344,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); @@ -368,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 { @@ -393,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); } @@ -416,10 +419,10 @@ sdbus::MethodReply Rpm::remove(sdbus::MethodCall & call) { // Limit remove spec capabity to prevent multiple matches. Remove command should not match anything after performing // a remove action with the same spec. NEVRA and filenames are the only types that have no overlaps. libdnf5::GoalJobSettings setting; - setting.with_nevra = true; - setting.with_provides = false; - setting.with_filenames = true; - setting.with_binaries = false; + setting.set_with_nevra(true); + setting.set_with_provides(false); + setting.set_with_filenames(true); + setting.set_with_binaries(false); for (const auto & spec : specs) { goal.add_remove(spec, setting); } diff --git a/include/libdnf5/base/goal_elements.hpp b/include/libdnf5/base/goal_elements.hpp index abd52262d..f76fb6a87 100644 --- a/include/libdnf5/base/goal_elements.hpp +++ b/include/libdnf5/base/goal_elements.hpp @@ -115,73 +115,169 @@ enum class GoalSetting { AUTO, SET_TRUE, SET_FALSE }; /// Unresolved or resolved values based on GoalSetting enum class GoalUsedSetting { UNUSED, USED_TRUE, USED_FALSE }; +/// Configure SPEC resolving. +/// Important for queries that resolve SPEC. struct ResolveSpecSettings { public: - /// Important for queries that resolve SPEC - bool ignore_case{false}; - /// Important for queries that resolve SPEC - bool with_nevra{true}; - /// Important for queries that resolve SPEC - bool with_provides{true}; - /// Important for queries that resolve SPEC - bool with_filenames{true}; - /// Important for queries that resolve SPEC + ResolveSpecSettings(); + ~ResolveSpecSettings(); + + ResolveSpecSettings(const ResolveSpecSettings & src); + ResolveSpecSettings & operator=(const ResolveSpecSettings & src); + + ResolveSpecSettings(ResolveSpecSettings && src) noexcept; + ResolveSpecSettings & operator=(ResolveSpecSettings && src) noexcept; + + /// Set whether to match case-insensitively + /// + /// Default: false + void set_ignore_case(bool ignore_case); + bool get_ignore_case() const; + + /// Set whether packages' nevras should be considered during SPEC matching + /// + /// Default: true + void set_with_nevra(bool with_nevra); + bool get_with_nevra() const; + + /// Set whether packages' provides should be considered during SPEC matching + /// + /// Default: true + void set_with_provides(bool with_provides); + bool get_with_provides() const; + + /// Set whether package's files should be considered during SPEC matching + /// It will check if SPEC starts with "/" or "*/" and if it matches any file in a package + /// + /// Default: true + void set_with_filenames(bool with_filenames); + bool get_with_filenames() const; + + /// Set whether package's binaries should be considered during SPEC matching /// It will check whether SPEC is a binary -> `/usr/(s)bin/` - bool with_binaries{true}; - /// Important for queries that resolve SPEC - std::vector nevra_forms{}; - - /// these flags are used only for group resolving - bool group_with_id{true}; - bool group_with_name{false}; - /// Historically group spec could also mean an environment. These flags + /// + /// Default: true + void set_with_binaries(bool with_binaries); + bool get_with_binaries() const; + + /// When matching packages' nevras is enabled specify allowed nevra forms. + /// + /// The default can be obtained from libdnf5::rpm::Nevra::get_default_pkg_spec_forms(). + void set_nevra_forms(std::vector nevra_forms); + std::vector get_nevra_forms() const; + + /// Set whether groups' ids should be considered during group SPEC matching + /// + /// Default: true + void set_group_with_id(bool group_with_id); + bool get_group_with_id() const; + + /// Set whether groups' names should be considered during group SPEC matching + /// + /// Default: false + void set_group_with_name(bool group_with_name); + bool get_group_with_name() const; + + /// Configure whether to search in groups when matching SPEC in group ids or names. + /// Historically group SPEC could also mean an environment. These flags /// configure in which entities the spec is searched for. - bool group_search_groups{true}; - bool group_search_environments{true}; + /// + /// Default: true + void set_group_search_groups(bool search_groups); + bool get_group_search_groups() const; + + /// Configure whether to search in environments when matching SPEC in group ids or names. + /// + /// Default: true + void set_group_search_environments(bool search_environments); + bool get_group_search_environments() const; + +private: + class Impl; + std::unique_ptr p_impl; }; 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; @@ -237,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-plugins/actions/actions.cpp b/libdnf5-plugins/actions/actions.cpp index 5929121fb..94f64455c 100644 --- a/libdnf5-plugins/actions/actions.cpp +++ b/libdnf5-plugins/actions/actions.cpp @@ -711,12 +711,12 @@ void Actions::on_transaction( std::set unique_commands_to_run; // std::set is used to detect duplicate commands - libdnf5::ResolveSpecSettings spec_settings{ - .ignore_case = false, - .with_nevra = true, - .with_provides = false, - .with_filenames = true, - .with_binaries = false}; + libdnf5::ResolveSpecSettings spec_settings; + spec_settings.set_ignore_case(false); + spec_settings.set_with_nevra(true); + spec_settings.set_with_provides(false); + spec_settings.set_with_filenames(true); + spec_settings.set_with_binaries(false); for (const auto & action : trans_actions) { if (action.pkg_filter.empty()) { // action without packages - the action is called regardless of the of number of packages in the transaction diff --git a/libdnf5/base/goal.cpp b/libdnf5/base/goal.cpp index c88dd5b99..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; @@ -755,21 +755,21 @@ GoalProblem Goal::Impl::resolve_group_specs(std::vector & specs, base ret |= GoalProblem::UNSUPPORTED_ACTION; continue; } - sack::QueryCmp cmp = settings.ignore_case ? sack::QueryCmp::IGLOB : sack::QueryCmp::GLOB; + 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) { @@ -1685,10 +1685,10 @@ GoalProblem Goal::Impl::add_up_down_distrosync_to_goal( void Goal::Impl::install_group_package(base::Transaction & transaction, libdnf5::comps::Package pkg) { auto pkg_settings = GoalJobSettings(); - pkg_settings.with_provides = false; - pkg_settings.with_filenames = false; - pkg_settings.with_binaries = false; - pkg_settings.nevra_forms.push_back(rpm::Nevra::Form::NAME); + pkg_settings.set_with_provides(false); + pkg_settings.set_with_filenames(false); + pkg_settings.set_with_binaries(false); + pkg_settings.set_nevra_forms({rpm::Nevra::Form::NAME}); // TODO(mblaha): apply pkg.basearchonly when available in comps auto pkg_name = pkg.get_name(); @@ -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; } @@ -1896,13 +1896,13 @@ void Goal::Impl::add_group_upgrade_to_goal( } auto pkg_settings = GoalJobSettings(); - pkg_settings.with_provides = false; - pkg_settings.with_filenames = false; - pkg_settings.with_binaries = false; + pkg_settings.set_with_provides(false); + pkg_settings.set_with_filenames(false); + pkg_settings.set_with_binaries(false); for (const auto & pkg_name : state_group.packages) { if (new_set.contains(pkg_name)) { // upgrade all packages installed with the group - pkg_settings.nevra_forms.push_back(rpm::Nevra::Form::NAME); + pkg_settings.set_nevra_forms({rpm::Nevra::Form::NAME}); add_up_down_distrosync_to_goal(transaction, GoalAction::UPGRADE, pkg_name, pkg_settings); } else { // remove those packages that are not part of the group any more @@ -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(); @@ -2180,8 +2180,11 @@ void Goal::Impl::add_paths_to_goal() { void Goal::Impl::set_exclude_from_weak(const std::vector & exclude_from_weak) { for (const auto & exclude_weak : exclude_from_weak) { rpm::PackageQuery weak_query(base, rpm::PackageQuery::ExcludeFlags::APPLY_EXCLUDES); - libdnf5::ResolveSpecSettings settings{ - .with_nevra = true, .with_provides = false, .with_filenames = true, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_nevra(true); + settings.set_with_provides(false); + settings.set_with_filenames(true); + settings.set_with_binaries(true); weak_query.resolve_pkg_spec(exclude_weak, settings, false); weak_query.filter_available(); rpm_goal.add_exclude_from_weak(*weak_query.p_impl); diff --git a/libdnf5/base/goal_elements.cpp b/libdnf5/base/goal_elements.cpp index 9fba1c011..f92852be0 100644 --- a/libdnf5/base/goal_elements.cpp +++ b/libdnf5/base/goal_elements.cpp @@ -24,9 +24,172 @@ along with libdnf. If not, see . namespace libdnf5 { +class ResolveSpecSettings::Impl { + friend ResolveSpecSettings; + bool ignore_case{false}; + bool with_nevra{true}; + bool with_provides{true}; + bool with_filenames{true}; + bool with_binaries{true}; + bool group_with_id{true}; + bool group_with_name{false}; + bool group_search_groups{true}; + bool group_search_environments{true}; + std::vector nevra_forms{}; +}; + +ResolveSpecSettings::~ResolveSpecSettings() = default; + +ResolveSpecSettings::ResolveSpecSettings() : p_impl(std::make_unique()) {} +ResolveSpecSettings::ResolveSpecSettings(const ResolveSpecSettings & src) : p_impl(new Impl(*src.p_impl)) {} +ResolveSpecSettings::ResolveSpecSettings(ResolveSpecSettings && src) noexcept = default; + +ResolveSpecSettings & ResolveSpecSettings::operator=(const ResolveSpecSettings & src) { + if (this != &src) { + if (p_impl) { + *p_impl = *src.p_impl; + } else { + p_impl = std::make_unique(*src.p_impl); + } + } + + return *this; +} +ResolveSpecSettings & ResolveSpecSettings::operator=(ResolveSpecSettings && src) noexcept = default; + +void ResolveSpecSettings::set_ignore_case(bool ignore_case) { + p_impl->ignore_case = ignore_case; +} +bool ResolveSpecSettings::get_ignore_case() const { + return p_impl->ignore_case; +} + +void ResolveSpecSettings::set_with_nevra(bool with_nevra) { + p_impl->with_nevra = with_nevra; +} +bool ResolveSpecSettings::get_with_nevra() const { + return p_impl->with_nevra; +} + +void ResolveSpecSettings::set_with_provides(bool with_provides) { + p_impl->with_provides = with_provides; +} +bool ResolveSpecSettings::get_with_provides() const { + return p_impl->with_provides; +} + +void ResolveSpecSettings::set_with_filenames(bool with_filenames) { + p_impl->with_filenames = with_filenames; +} +bool ResolveSpecSettings::get_with_filenames() const { + return p_impl->with_filenames; +} + +void ResolveSpecSettings::set_with_binaries(bool with_binaries) { + p_impl->with_binaries = with_binaries; +} +bool ResolveSpecSettings::get_with_binaries() const { + return p_impl->with_binaries; +} + +void ResolveSpecSettings::set_nevra_forms(std::vector nevra_forms) { + p_impl->nevra_forms = std::move(nevra_forms); +} +std::vector ResolveSpecSettings::get_nevra_forms() const { + return p_impl->nevra_forms; +} + +void ResolveSpecSettings::set_group_with_id(bool group_with_id) { + p_impl->group_with_id = group_with_id; +} +bool ResolveSpecSettings::get_group_with_id() const { + return p_impl->group_with_id; +} + +void ResolveSpecSettings::set_group_with_name(bool group_with_name) { + p_impl->group_with_name = group_with_name; +} +bool ResolveSpecSettings::get_group_with_name() const { + return p_impl->group_with_name; +} + +void ResolveSpecSettings::set_group_search_groups(bool search_groups) { + p_impl->group_search_groups = search_groups; +} +bool ResolveSpecSettings::get_group_search_groups() const { + return p_impl->group_search_groups; +} + +void ResolveSpecSettings::set_group_search_environments(bool search_environments) { + p_impl->group_search_environments = search_environments; +} +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; @@ -40,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; @@ -63,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; @@ -99,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; @@ -121,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) { @@ -197,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 94a693c97..34060c914 100644 --- a/libdnf5/base/transaction.cpp +++ b/libdnf5/base/transaction.cpp @@ -182,18 +182,18 @@ 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(); } - if (!settings.ignore_case && settings.with_nevra) { + if (!settings.get_ignore_case() && settings.get_with_nevra()) { rpm::PackageQuery icase(hints); - ResolveSpecSettings settings_copy = settings; - settings_copy.ignore_case = true; - settings_copy.with_provides = false; - settings_copy.with_filenames = false; - settings_copy.with_binaries = false; + ResolveSpecSettings settings_copy(settings); + settings_copy.set_ignore_case(true); + settings_copy.set_with_provides(false); + settings_copy.set_with_filenames(false); + settings_copy.set_with_binaries(false); auto nevra_pair_icase = icase.resolve_pkg_spec(pkg_spec, settings_copy, false); if (nevra_pair_icase.first) { add_resolve_log( diff --git a/libdnf5/rpm/package_query.cpp b/libdnf5/rpm/package_query.cpp index 56b486f40..31955aeb4 100644 --- a/libdnf5/rpm/package_query.cpp +++ b/libdnf5/rpm/package_query.cpp @@ -2546,9 +2546,9 @@ std::pair PackageQuery::resolve_pkg_spec( bool glob = libdnf5::utils::is_glob_pattern(pkg_spec.c_str()); libdnf5::sack::QueryCmp cmp = glob ? libdnf5::sack::QueryCmp::GLOB : libdnf5::sack::QueryCmp::EQ; - if (settings.with_nevra) { + if (settings.get_with_nevra()) { const std::vector & test_forms = - settings.nevra_forms.empty() ? Nevra::get_default_pkg_spec_forms() : settings.nevra_forms; + settings.get_nevra_forms().empty() ? Nevra::get_default_pkg_spec_forms() : settings.get_nevra_forms(); try { auto nevras = rpm::Nevra::parse(pkg_spec, test_forms); for (auto & nevra_obj : nevras) { @@ -2556,7 +2556,7 @@ std::pair PackageQuery::resolve_pkg_spec( *this, nevra_obj, glob, - settings.ignore_case ? (cmp | libdnf5::sack::QueryCmp::ICASE) : cmp, + settings.get_ignore_case() ? (cmp | libdnf5::sack::QueryCmp::ICASE) : cmp, filter_result, with_src); filter_result &= *p_impl; @@ -2567,14 +2567,14 @@ std::pair PackageQuery::resolve_pkg_spec( } } // When parsed nevra search failed only string with glob can match full nevra - if (settings.nevra_forms.empty() && glob) { + if (settings.get_nevra_forms().empty() && glob) { auto & sorted_solvables = sack->p_impl->get_sorted_solvables(); PQImpl::filter_nevra( *this, sorted_solvables, pkg_spec, glob, - settings.ignore_case ? (cmp | libdnf5::sack::QueryCmp::ICASE) : cmp, + settings.get_ignore_case() ? (cmp | libdnf5::sack::QueryCmp::ICASE) : cmp, filter_result); filter_result &= *p_impl; if (!filter_result.empty()) { @@ -2585,7 +2585,7 @@ std::pair PackageQuery::resolve_pkg_spec( } catch (const NevraIncorrectInputError &) { } } - if (settings.with_provides) { + if (settings.get_with_provides()) { ReldepList reldep_list(p_impl->base); PQImpl::str2reldep_internal(reldep_list, cmp, glob, pkg_spec); if (reldep_list.size() != 0) { @@ -2599,7 +2599,7 @@ std::pair PackageQuery::resolve_pkg_spec( } } auto is_file_pattern = libdnf5::utils::is_file_pattern(pkg_spec); - if (settings.with_filenames && is_file_pattern) { + if (settings.get_with_filenames() && is_file_pattern) { filter_dataiterator( *pool, SOLVABLE_FILELIST, @@ -2613,7 +2613,7 @@ std::pair PackageQuery::resolve_pkg_spec( } } // If spec is file path than it is not a binary - if (settings.with_binaries and !is_file_pattern) { + if (settings.get_with_binaries() and !is_file_pattern) { ReldepList reldep_list(p_impl->base); std::array binary_paths{"/usr/bin/", "/usr/sbin/"}; std::vector binary_paths_string; diff --git a/libdnf5/rpm/package_sack.cpp b/libdnf5/rpm/package_sack.cpp index c9ba471f9..a7cb494d3 100644 --- a/libdnf5/rpm/package_sack.cpp +++ b/libdnf5/rpm/package_sack.cpp @@ -105,12 +105,12 @@ void PackageSack::Impl::load_config_excludes_includes(bool only_main) { bool excludes_exist = false; // found packages for exclude bool includes_exist = false; // found packages for include - ResolveSpecSettings resolve_settings{ - .ignore_case = false, - .with_nevra = true, - .with_provides = false, - .with_filenames = false, - .with_binaries = false}; + ResolveSpecSettings resolve_settings; + resolve_settings.set_ignore_case(false); + resolve_settings.set_with_nevra(true); + resolve_settings.set_with_provides(false); + resolve_settings.set_with_filenames(false); + resolve_settings.set_with_binaries(false); // first evaluate repo specific includes/excludes if (!only_main) { diff --git a/test/libdnf5/rpm/test_package_query.cpp b/test/libdnf5/rpm/test_package_query.cpp index f53d4d81c..24e82ab73 100644 --- a/test/libdnf5/rpm/test_package_query.cpp +++ b/test/libdnf5/rpm/test_package_query.cpp @@ -671,7 +671,10 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // test Name.Arch PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{.with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("pkg.x86_64", settings, true); CPPUNIT_ASSERT_EQUAL(return_value.first, true); std::vector expected = {get_pkg("pkg-0:1.2-3.x86_64")}; @@ -681,8 +684,11 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // Test NA icase PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{ - .ignore_case = true, .with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("Pkg.x86_64", settings, true); CPPUNIT_ASSERT_EQUAL(return_value.first, true); std::vector expected = {get_pkg("pkg-0:1.2-3.x86_64")}; @@ -692,7 +698,9 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // Test a provide PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{.with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("pkg >= 1", settings, true); CPPUNIT_ASSERT_EQUAL(return_value.first, true); std::vector expected = {get_pkg("pkg-0:1.2-3.x86_64")}; @@ -702,7 +710,10 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // Test NEVRA glob PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{.with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("pk?-?:1.?-?.x8?_64", settings, true); CPPUNIT_ASSERT_EQUAL(return_value.first, true); std::vector expected = {get_pkg("pkg-0:1.2-3.x86_64")}; @@ -712,7 +723,10 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // Test NEVRA glob - icase == false, nothing found PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{.with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("Pk?-?:1.?-?.x8?_64", settings, true); CPPUNIT_ASSERT_EQUAL(return_value.first, false); std::vector expected = {}; @@ -722,8 +736,11 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // Test NEVRA glob - icase == true PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{ - .ignore_case = true, .with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("Pk?-?:1.?-?.x8?_64", settings, true); CPPUNIT_ASSERT_EQUAL(return_value.first, true); std::vector expected = {get_pkg("pkg-0:1.2-3.x86_64")}; @@ -733,8 +750,11 @@ void RpmPackageQueryTest::test_resolve_pkg_spec() { { // Test NEVRA icase PackageQuery query(base); - libdnf5::ResolveSpecSettings settings{ - .ignore_case = true, .with_provides = false, .with_filenames = false, .with_binaries = false}; + libdnf5::ResolveSpecSettings settings; + settings.set_ignore_case(true); + settings.set_with_provides(false); + settings.set_with_filenames(false); + settings.set_with_binaries(false); auto return_value = query.resolve_pkg_spec("Pkg-0:1.2-3.X86_64", settings, true); std::vector expected = {get_pkg("pkg-0:1.2-3.x86_64")}; CPPUNIT_ASSERT_EQUAL(expected, to_vector(query)); diff --git a/test/python3/libdnf5/rpm/test_package_query.py b/test/python3/libdnf5/rpm/test_package_query.py index d6eb2edcc..0f87c4948 100644 --- a/test/python3/libdnf5/rpm/test_package_query.py +++ b/test/python3/libdnf5/rpm/test_package_query.py @@ -124,7 +124,8 @@ def test_resolve_pkg_spec(self): # Test passing an explicit list of forms query = libdnf5.rpm.PackageQuery(self.base) settings = libdnf5.base.ResolveSpecSettings() - settings.nevra_forms.append(libdnf5.rpm.Nevra.Form_NA) + settings.set_nevra_forms( + libdnf5.rpm.VectorNevraForm(1, libdnf5.rpm.Nevra.Form_NA)) match, nevra = query.resolve_pkg_spec("pkg.x86_64", settings, True)