Hello community, here is the log from the commit of package libdnf for openSUSE:Factory checked in at 2020-12-02 13:57:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libdnf (Old) and /work/SRC/openSUSE:Factory/.libdnf.new.5913 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libdnf" Wed Dec 2 13:57:18 2020 rev:19 rq:851721 version:0.55.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libdnf/libdnf.changes 2020-10-28 09:58:42.719158598 +0100 +++ /work/SRC/openSUSE:Factory/.libdnf.new.5913/libdnf.changes 2020-12-02 13:57:20.897745938 +0100 @@ -1,0 +2,17 @@ +Sun Nov 29 22:14:35 UTC 2020 - Neal Gompa <ngomp...@gmail.com> + +- Update to version 0.55.0 + + Add vendor to dnf API (rh#1876561) + + Add formatting function for solver error + + Add error types in ModulePackageContainer + + Implement module enable for context part + + Improve string formatting for translation + + Remove redundant printf and change logging info to notice (rh#1827424) + + Add allow_vendor_change option (rh#1788371) (rh#1788371) +- Backport patches from upstream + + Patch: 0001-Support-allow_vendor_change-setting-in-dnf-context-A.patch + + Patch: 0001-context-dnf_keyring_add_public_keys-not-generate-err.patch +- Add patch to turn off changing vendors by default + + Patch: libdnf-0.55.0-Switch-allow_vendor_change-off.patch + +------------------------------------------------------------------- Old: ---- libdnf-0.54.2.tar.gz New: ---- 0001-Support-allow_vendor_change-setting-in-dnf-context-A.patch 0001-context-dnf_keyring_add_public_keys-not-generate-err.patch libdnf-0.55.0-Switch-allow_vendor_change-off.patch libdnf-0.55.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libdnf.spec ++++++ --- /var/tmp/diff_new_pack.VdjYrO/_old 2020-12-02 13:57:21.541746616 +0100 +++ /var/tmp/diff_new_pack.VdjYrO/_new 2020-12-02 13:57:21.545746620 +0100 @@ -33,7 +33,7 @@ %define devname %{name}-devel Name: libdnf -Version: 0.54.2 +Version: 0.55.0 Release: 0 Summary: Library providing C and Python APIs atop libsolv License: LGPL-2.1-or-later @@ -42,12 +42,16 @@ Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz # Backports from upstream +Patch0001: 0001-Support-allow_vendor_change-setting-in-dnf-context-A.patch +Patch0002: 0001-context-dnf_keyring_add_public_keys-not-generate-err.patch # openSUSE specific fixes ## Fix libdnf build with static libsolvext Patch1000: libdnf-0.48.0-with-static-libsolvext.patch ## Switch default reposdir to /etc/dnf/repos.d Patch1001: libdnf-0.54.2-Switch-default-reposdir-to-etc-dnf-repos.d.patch +## Switch allow_vendor_change off by default +Patch1002: libdnf-0.55.0-Switch-allow_vendor_change-off.patch BuildRequires: cmake BuildRequires: gcc ++++++ 0001-Support-allow_vendor_change-setting-in-dnf-context-A.patch ++++++ From 690243af4f5113368ce905e750577926bfe94977 Mon Sep 17 00:00:00 2001 From: Neal Gompa <ngomp...@gmail.com> Date: Wed, 18 Nov 2020 08:03:28 -0500 Subject: [PATCH] Support allow_vendor_change setting in dnf context API = changelog = msg: Support allow_vendor_change setting in dnf context API type: enhancement --- libdnf/dnf-context.cpp | 33 +++++++++++++++++++++++++++++++++ libdnf/dnf-context.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/libdnf/dnf-context.cpp b/libdnf/dnf-context.cpp index 33e7eb6d..06926711 100644 --- a/libdnf/dnf-context.cpp +++ b/libdnf/dnf-context.cpp @@ -932,6 +932,22 @@ dnf_context_get_install_weak_deps() return mainConf.install_weak_deps().getValue(); } +/** + * dnf_context_get_allow_vendor_change: + * + * Gets allow_vendor_change global configuration value. + * + * Returns: %TRUE if changing vendors in a transaction is allowed + * + * Since: 0.55.2 + */ +gboolean +dnf_context_get_allow_vendor_change() +{ + auto & mainConf = libdnf::getGlobalMainConfig(); + return mainConf.allow_vendor_change().getValue(); +} + /** * dnf_context_get_check_disk_space: * @context: a #DnfContext instance. @@ -1409,6 +1425,20 @@ dnf_context_set_install_weak_deps(gboolean enabled) mainConf.install_weak_deps().set(libdnf::Option::Priority::RUNTIME, enabled); } +/** + * dnf_context_set_allow_vendor_change: + * + * Sets allow_vendor_change global configuration value. + * + * Since: 0.55.2 + */ +void +dnf_context_set_allow_vendor_change(gboolean vendorchange) +{ + auto & mainConf = libdnf::getGlobalMainConfig(); + mainConf.allow_vendor_change().set(libdnf::Option::Priority::RUNTIME, vendorchange); +} + /** * dnf_context_set_cache_only: * @context: a #DnfContext instance. @@ -1725,12 +1755,15 @@ dnf_context_setup_sack_with_flags(DnfContext *context, DnfContextPrivate *priv = GET_PRIVATE(context); gboolean ret; g_autofree gchar *solv_dir_real = nullptr; + gboolean vendorchange; /* create empty sack */ solv_dir_real = dnf_realpath(priv->solv_dir); + vendorchange = dnf_context_get_allow_vendor_change(); priv->sack = dnf_sack_new(); dnf_sack_set_cachedir(priv->sack, solv_dir_real); dnf_sack_set_rootdir(priv->sack, priv->install_root); + dnf_sack_set_allow_vendor_change(priv->sack, vendorchange); if (priv->arch) { if(!dnf_sack_set_arch(priv->sack, priv->arch, error)) { return FALSE; diff --git a/libdnf/dnf-context.h b/libdnf/dnf-context.h index f5dfb0b3..71e12ebd 100644 --- a/libdnf/dnf-context.h +++ b/libdnf/dnf-context.h @@ -132,6 +132,7 @@ const gchar **dnf_context_get_native_arches (DnfContext *context const gchar **dnf_context_get_installonly_pkgs (DnfContext *context); gboolean dnf_context_get_best (void); gboolean dnf_context_get_install_weak_deps (void); +gboolean dnf_context_get_allow_vendor_change (void); gboolean dnf_context_get_cache_only (DnfContext *context); gboolean dnf_context_get_check_disk_space (DnfContext *context); gboolean dnf_context_get_check_transaction (DnfContext *context); @@ -185,6 +186,7 @@ void dnf_context_set_source_root (DnfContext *context const gchar *source_root); void dnf_context_set_best (gboolean best); void dnf_context_set_install_weak_deps (gboolean enabled); +void dnf_context_set_allow_vendor_change (gboolean vendorchange); void dnf_context_set_cache_only (DnfContext *context, gboolean cache_only); void dnf_context_set_check_disk_space (DnfContext *context, -- 2.28.0 ++++++ 0001-context-dnf_keyring_add_public_keys-not-generate-err.patch ++++++ From 35f2062c8508326221a6d807ece3feec766349fb Mon Sep 17 00:00:00 2001 From: Jaroslav Rohel <jro...@redhat.com> Date: Wed, 25 Nov 2020 15:41:59 +0100 Subject: [PATCH] [context] dnf_keyring_add_public_keys(): not generate error if dir problem The function adds all public keys from "/etc/pki/rpm-gpg" (installed public keys) to the RPM keyring. Before patch: Empty directory was ignored. But if the directory could not be opened (does not exist, it is a file, another error ...) an error has occurred. Changes: A non-existent directory is ignored too. If the path exists but cannot be opened by the process as a directory, warning is reported. Closes: #1097 Approved by: Conan-Kudo --- libdnf/dnf-keyring.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libdnf/dnf-keyring.cpp b/libdnf/dnf-keyring.cpp index 6797b119..eec58c69 100644 --- a/libdnf/dnf-keyring.cpp +++ b/libdnf/dnf-keyring.cpp @@ -189,11 +189,17 @@ dnf_keyring_add_public_keys(rpmKeyring keyring, GError **error) try const gchar *gpg_dir = "/etc/pki/rpm-gpg"; gboolean ret = TRUE; g_autoptr(GDir) dir = NULL; + GError *localError = NULL; /* search all the public key files */ - dir = g_dir_open(gpg_dir, 0, error); - if (dir == NULL) - return FALSE; + dir = g_dir_open(gpg_dir, 0, &localError); + if (dir == NULL) { + if (localError->domain != G_FILE_ERROR || localError->code != G_FILE_ERROR_NOENT) { + g_warning("%s", localError->message); + } + g_error_free(localError); + return TRUE; + } do { const gchar *filename; g_autofree gchar *path_tmp = NULL; @@ -201,7 +207,6 @@ dnf_keyring_add_public_keys(rpmKeyring keyring, GError **error) try if (filename == NULL) break; path_tmp = g_build_filename(gpg_dir, filename, NULL); - GError *localError = NULL; ret = dnf_keyring_add_public_key(keyring, path_tmp, &localError); if (!ret) { g_warning("%s", localError->message); -- 2.28.0 ++++++ libdnf-0.55.0-Switch-allow_vendor_change-off.patch ++++++ From 6a67b1a671f5778b014d8652321a193715cf952c Mon Sep 17 00:00:00 2001 From: Neal Gompa <ngomp...@gmail.com> Date: Sun, 29 Nov 2020 18:46:15 -0500 Subject: [PATCH] Switch allow_vendor_change off by default This is consistent with how SUSE distributions expect package management to work. --- libdnf/conf/ConfigMain.cpp | 2 +- libdnf/dnf-sack.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libdnf/conf/ConfigMain.cpp b/libdnf/conf/ConfigMain.cpp index 1ffd3b33..c451015d 100644 --- a/libdnf/conf/ConfigMain.cpp +++ b/libdnf/conf/ConfigMain.cpp @@ -216,7 +216,7 @@ class ConfigMain::Impl { OptionBool obsoletes{true}; OptionBool showdupesfromrepos{false}; OptionBool exit_on_lock{false}; - OptionBool allow_vendor_change{true}; + OptionBool allow_vendor_change{false}; OptionSeconds metadata_timer_sync{60 * 60 * 3}; // 3 hours OptionStringList disable_excludes{std::vector<std::string>{}}; OptionEnum<std::string> multilib_policy{"best", {"best", "all"}}; // :api diff --git a/libdnf/dnf-sack.cpp b/libdnf/dnf-sack.cpp index 9fd2c72d..e0b53b60 100644 --- a/libdnf/dnf-sack.cpp +++ b/libdnf/dnf-sack.cpp @@ -190,7 +190,7 @@ dnf_sack_init(DnfSack *sack) priv->running_kernel_fn = running_kernel; priv->considered_uptodate = TRUE; priv->cmdline_repo = NULL; - priv->allow_vendor_change = TRUE; + priv->allow_vendor_change = FALSE; queue_init(&priv->installonly); /* logging up after this*/ -- 2.28.0 ++++++ libdnf-0.54.2.tar.gz -> libdnf-0.55.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/VERSION.cmake new/libdnf-0.55.0/VERSION.cmake --- old/libdnf-0.54.2/VERSION.cmake 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/VERSION.cmake 2020-11-09 15:42:13.000000000 +0100 @@ -1,6 +1,6 @@ set (DEFAULT_LIBDNF_MAJOR_VERSION 0) -set (DEFAULT_LIBDNF_MINOR_VERSION 54) -set (DEFAULT_LIBDNF_MICRO_VERSION 2) +set (DEFAULT_LIBDNF_MINOR_VERSION 55) +set (DEFAULT_LIBDNF_MICRO_VERSION 0) if(DEFINED LIBDNF_MAJOR_VERSION) if(NOT ${DEFAULT_LIBDNF_MAJOR_VERSION} STREQUAL ${LIBDNF_MAJOR_VERSION}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/docs/release_notes.rst new/libdnf-0.55.0/docs/release_notes.rst --- old/libdnf-0.54.2/docs/release_notes.rst 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/docs/release_notes.rst 2020-11-09 15:42:13.000000000 +0100 @@ -20,6 +20,19 @@ ###################### ==================== +0.55.0 Release Notes +==================== + +- Add vendor to dnf API (RhBug:1876561) +- Add formatting function for solver error +- Add error types in ModulePackageContainer +- Implement module enable for context part +- Improve string formatting for translation +- Remove redundant printf and change logging info to notice (RhBug:1827424) +- Add allow_vendor_change option (RhBug:1788371) (RhBug:1788371) + + +==================== 0.54.2 Release Notes ==================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/conf/ConfigMain.cpp new/libdnf-0.55.0/libdnf/conf/ConfigMain.cpp --- old/libdnf-0.54.2/libdnf/conf/ConfigMain.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/conf/ConfigMain.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -216,6 +216,7 @@ OptionBool obsoletes{true}; OptionBool showdupesfromrepos{false}; OptionBool exit_on_lock{false}; + OptionBool allow_vendor_change{true}; OptionSeconds metadata_timer_sync{60 * 60 * 3}; // 3 hours OptionStringList disable_excludes{std::vector<std::string>{}}; OptionEnum<std::string> multilib_policy{"best", {"best", "all"}}; // :api @@ -399,6 +400,7 @@ owner.optBinds().add("obsoletes", obsoletes); owner.optBinds().add("showdupesfromrepos", showdupesfromrepos); owner.optBinds().add("exit_on_lock", exit_on_lock); + owner.optBinds().add("allow_vendor_change", allow_vendor_change); owner.optBinds().add("metadata_timer_sync", metadata_timer_sync); owner.optBinds().add("disable_excludes", disable_excludes); owner.optBinds().add("multilib_policy", multilib_policy); @@ -531,6 +533,7 @@ OptionBool & ConfigMain::obsoletes() { return pImpl->obsoletes; } OptionBool & ConfigMain::showdupesfromrepos() { return pImpl->showdupesfromrepos; } OptionBool & ConfigMain::exit_on_lock() { return pImpl->exit_on_lock; } +OptionBool & ConfigMain::allow_vendor_change() { return pImpl->allow_vendor_change; } OptionSeconds & ConfigMain::metadata_timer_sync() { return pImpl->metadata_timer_sync; } OptionStringList & ConfigMain::disable_excludes() { return pImpl->disable_excludes; } OptionEnum<std::string> & ConfigMain::multilib_policy() { return pImpl->multilib_policy; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/conf/ConfigMain.hpp new/libdnf-0.55.0/libdnf/conf/ConfigMain.hpp --- old/libdnf-0.54.2/libdnf/conf/ConfigMain.hpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/conf/ConfigMain.hpp 2020-11-09 15:42:13.000000000 +0100 @@ -89,6 +89,7 @@ OptionBool & obsoletes(); OptionBool & showdupesfromrepos(); OptionBool & exit_on_lock(); + OptionBool & allow_vendor_change(); OptionSeconds & metadata_timer_sync(); OptionStringList & disable_excludes(); OptionEnum<std::string> & multilib_policy(); // :api diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/dnf-context.cpp new/libdnf-0.55.0/libdnf/dnf-context.cpp --- old/libdnf-0.54.2/libdnf/dnf-context.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/dnf-context.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -35,6 +35,9 @@ #include "dnf-context.hpp" #include "libdnf/conf/ConfigParser.hpp" #include "conf/Option.hpp" +#include "bgettext/bgettext-lib.h" +#include "tinyformat/tinyformat.hpp" +#include "goal/Goal.hpp" #include <memory> #include <set> @@ -74,6 +77,7 @@ #include "dnf-repo.hpp" #include "goal/Goal.hpp" #include "plugin/plugin-private.hpp" +#include "utils/GLibLogger.hpp" #include "utils/os-release.hpp" @@ -185,6 +189,7 @@ SIGNAL_LAST }; +static libdnf::GLibLogger glibLogger(G_LOG_DOMAIN); static std::string pluginsDir = DEFAULT_PLUGINS_DIRECTORY; static std::unique_ptr<std::string> configFilePath; static std::set<std::string> pluginsEnabled; @@ -332,6 +337,8 @@ { DnfContextPrivate *priv = GET_PRIVATE(context); + libdnf::Log::setLogger(&glibLogger); + priv->install_root = g_strdup("/"); priv->check_disk_space = TRUE; priv->check_transaction = TRUE; @@ -2880,6 +2887,26 @@ return priv->plugins->hook(id, hookData, error); } +gchar * +dnf_context_get_module_report(DnfContext * context) +{ + DnfContextPrivate *priv = GET_PRIVATE (context); + + /* create sack and add sources */ + if (priv->sack == nullptr) { + return nullptr; + } + auto container = dnf_sack_get_module_container(priv->sack); + if (container == nullptr) { + return nullptr; + } + auto report = container->getReport(); + if (report.empty()) { + return nullptr; + } + return g_strdup(report.c_str()); +} + DnfContext * pluginGetContext(DnfPluginInitData * data) { @@ -2896,6 +2923,20 @@ return (static_cast<PluginHookContextInitData *>(data)->context); } +static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> +recompute_modular_filtering(libdnf::ModulePackageContainer * moduleContainer, DnfSack * sack, std::vector<const char *> & hotfixRepos) +{ + auto solver_errors = dnf_sack_filter_modules_v2( + sack, moduleContainer, hotfixRepos.data(), nullptr, nullptr, true, false); + if (solver_errors.second == libdnf::ModulePackageContainer::ModuleErrorType::NO_ERROR) { + return {}; + } + auto formated_problem = libdnf::Goal::formatAllProblemRules(solver_errors.first); + std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> ret; + ret.emplace_back(std::make_tuple(solver_errors.second, std::move(formated_problem), std::string())); + return ret; +} + static gboolean recompute_modular_filtering(DnfContext * context, DnfSack * sack, GError ** error) { @@ -2959,11 +3000,391 @@ for (auto & name: names) { container->reset(name); } - container->save(); - container->updateFailSafeData(); + //container->save(); + //container->updateFailSafeData(); return recompute_modular_filtering(context, sack, error); } CATCH_TO_GERROR(FALSE) +/// module dict { name : {stream : [modules] } +static std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>> create_module_dict( + const std::vector<libdnf::ModulePackage *> & modules) +{ + std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>> data; + for (auto * module : modules) { + data[module->getName()][module->getStream()].push_back(module); + } + return data; +} + +/// Modify module_dict => Keep only single relevant stream +/// If more streams it keeps enabled or default stream +static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> modify_module_dict_and_enable_stream(std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>> & module_dict, libdnf::ModulePackageContainer & container, bool enable) +{ + std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages; + for (auto module_dict_iter : module_dict) { + auto & name = module_dict_iter.first; + auto & stream_dict = module_dict_iter.second; + auto moduleState = container.getModuleState(name); + if (stream_dict.size() > 1) { + if (moduleState != libdnf::ModulePackageContainer::ModuleState::ENABLED + && moduleState != libdnf::ModulePackageContainer::ModuleState::DEFAULT) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_ENABLE_MULTIPLE_STREAMS, + tfm::format(_("Cannot enable more streams from module '%s' at the same time"), name), name)); + return messages; + } + const auto enabledOrDefaultStream = moduleState == libdnf::ModulePackageContainer::ModuleState::ENABLED ? + container.getEnabledStream(name) : container.getDefaultStream(name); + auto modules_iter = stream_dict.find(enabledOrDefaultStream); + if (modules_iter == stream_dict.end()) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_ENABLE_MULTIPLE_STREAMS, + tfm::format(_("Cannot enable more streams from module '%s' at the same time"), name), name)); + return messages;; + } + if (enable) { + try { + container.enable(name, modules_iter->first); + } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE, + tfm::format(_("Cannot enable module '%1$s' stream '%2$s': State of module already modified"), + name, modules_iter->first), name)); + } + } + for (auto iter = stream_dict.begin(); iter != stream_dict.end(); ) { + if (iter->first != enabledOrDefaultStream) { + stream_dict.erase(iter); + } else { + ++iter; + } + } + } else if (enable) { + for (auto iter : stream_dict) { + try { + container.enable(name, iter.first); + } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE, + tfm::format(_("Cannot enable module '%1$s' stream '%2$s': State of module already modified"), + name, iter.first), name)); + } + } + } + if (stream_dict.size() != 1) { + throw std::runtime_error("modify_module_dict_and_enable_stream() did not modify output correctly!!!"); + } + } + return messages; +} + +static std::pair<std::unique_ptr<libdnf::Nsvcap>, std::vector< libdnf::ModulePackage*>> resolve_module_spec(const std::string & module_spec, libdnf::ModulePackageContainer & container) +{ + std::unique_ptr<libdnf::Nsvcap> nsvcapObj(new libdnf::Nsvcap); + for (std::size_t i = 0; HY_MODULE_FORMS_MOST_SPEC[i] != _HY_MODULE_FORM_STOP_; ++i) { + if (nsvcapObj->parse(module_spec.c_str(), HY_MODULE_FORMS_MOST_SPEC[i])) { + auto result_modules = container.query(nsvcapObj->getName(), + nsvcapObj->getStream(), + nsvcapObj->getVersion(), + nsvcapObj->getContext(), + nsvcapObj->getArch()); + if (!result_modules.empty()) { + return std::make_pair(std::move(nsvcapObj), std::move(result_modules)); + } + } + } + return {}; +} + +static bool +report_problems(const std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> & messages) +{ + libdnf::ModulePackageContainer::ModuleErrorType typeMessage; + std::string report; + std::string argument; + auto logger(libdnf::Log::getLogger()); + bool return_error = false; + for (auto & message : messages) { + std::tie(typeMessage, report, argument) = message; + switch (typeMessage) { + case libdnf::ModulePackageContainer::ModuleErrorType::NO_ERROR: + break; + case libdnf::ModulePackageContainer::ModuleErrorType::INFO: + logger->notice(report); + break; + case libdnf::ModulePackageContainer::ModuleErrorType::ERROR_IN_DEFAULTS: + logger->warning(tfm::format(_("Modular dependency problem with Defaults: %s"), report.c_str())); + break; + case libdnf::ModulePackageContainer::ModuleErrorType::ERROR: + logger->error(tfm::format(_("Modular dependency problem: %s"), report.c_str())); + return_error = true; + break; + case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULES: + logger->error(report); + return_error = true; + break; + case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC: + logger->error(report); + return_error = true; + break; + case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_ENABLE_MULTIPLE_STREAMS: + logger->error(report); + return_error = true; + break; + case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE: + logger->error(report); + return_error = true; + break; + } + } + return return_error; +} + +static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> +modules_reset_or_disable(libdnf::ModulePackageContainer & container, const char ** module_specs, bool reset) +{ + std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages; + + for (const char ** specs = module_specs; *specs != NULL; ++specs) { + auto resolved_spec = resolve_module_spec(*specs, container); + if (!resolved_spec.first) { + messages.emplace_back( + std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC, + tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs)); + continue; + } + if (!resolved_spec.first->getStream().empty() || !resolved_spec.first->getProfile().empty() || + !resolved_spec.first->getVersion().empty() || !resolved_spec.first->getContext().empty()) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::INFO, + tfm::format(_("Only module name is required. Ignoring unneeded information in argument: '%s'"), *specs), + *specs)); + } + std::unordered_set<std::string> names; + for (auto * module : resolved_spec.second) { + names.insert(std::move(module->getName())); + } + for (auto & name : names) { + if (reset) { + try { + container.reset(name); + } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE, + tfm::format(_("Cannot reset module '%s': State of module already modified"), name), name)); + messages.emplace_back( + std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC, + tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs)); + } + } else { + try { + container.disable(name); + } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE, + tfm::format(_("Cannot disable module '%s': State of module already modified"), name), name)); + messages.emplace_back( + std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC, + tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs)); + } + } + } + } + + return messages; +} + +gboolean +dnf_context_module_enable(DnfContext * context, const char ** module_specs, GError ** error) try +{ + DnfContextPrivate *priv = GET_PRIVATE (context); + + /* create sack and add sources */ + if (priv->sack == nullptr) { + dnf_state_reset (priv->state); + if (!dnf_context_setup_sack(context, priv->state, error)) { + return FALSE; + } + } + + DnfSack * sack = priv->sack; + assert(sack); + assert(module_specs); + + auto container = dnf_sack_get_module_container(sack); + if (!container) { + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("No modular data available")); + return FALSE; + } + std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages; + + std::vector<std::pair<const char *, std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>>>> all_resolved_module_dicts; + for (const char ** specs = module_specs; *specs != NULL; ++specs) { + auto resolved_spec = resolve_module_spec(*specs, *container); + if (!resolved_spec.first) { + messages.emplace_back( + std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC, + tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs)); + continue; + } + if (!resolved_spec.first->getProfile().empty() || !resolved_spec.first->getVersion().empty() || + !resolved_spec.first->getContext().empty()) { + messages.emplace_back(std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::INFO, + tfm::format(_("Ignoring unneeded information in argument: '%s'"), *specs), + *specs)); + } + auto module_dict = create_module_dict(resolved_spec.second); + auto message = modify_module_dict_and_enable_stream(module_dict, *container, true); + if (!message.empty()) { + messages.insert( + messages.end(),std::make_move_iterator(message.begin()), std::make_move_iterator(message.end())); + messages.emplace_back( + std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC, + tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs)); + } else { + all_resolved_module_dicts.emplace_back(make_pair(*specs, std::move(module_dict))); + } + } + + std::vector<const char *> hotfixRepos; + // don't filter RPMs from repos with the 'module_hotfixes' flag set + for (unsigned int i = 0; i < priv->repos->len; i++) { + auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i)); + if (dnf_repo_get_module_hotfixes(repo)) { + hotfixRepos.push_back(dnf_repo_get_id(repo)); + } + } + hotfixRepos.push_back(nullptr); + auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos); + if (!solver_error.empty()) { + messages.insert( + messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end())); + } + for (auto & pair : all_resolved_module_dicts) { + for (auto module_dict_iter : pair.second) { + for (auto & stream_dict_iter : module_dict_iter.second) { + try { + container->enableDependencyTree(stream_dict_iter.second); + } catch (const libdnf::ModulePackageContainer::EnableMultipleStreamsException & exception) { + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE, + tfm::format(_("Problem during enablement of dependency tree for moduele '%1$s' stream '%2$s': %3$s"), + module_dict_iter.first, stream_dict_iter.first, exception.what()), pair.first)); + messages.emplace_back(std::make_tuple( + libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC, + tfm::format(_("Unable to resolve argument '%s'"), pair.first), pair.first)); + } + } + } + } + bool return_error = report_problems(messages); + + if (return_error) { + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("Problems appeared for module enable request")); + return FALSE; + } + return TRUE; +} CATCH_TO_GERROR(FALSE) + +static gboolean +context_modules_reset_or_disable(DnfContext * context, const char ** module_specs, GError ** error, bool reset) +{ + DnfContextPrivate *priv = GET_PRIVATE (context); + + /* create sack and add sources */ + if (priv->sack == nullptr) { + dnf_state_reset (priv->state); + if (!dnf_context_setup_sack(context, priv->state, error)) { + return FALSE; + } + } + + DnfSack * sack = priv->sack; + assert(module_specs); + + auto container = dnf_sack_get_module_container(sack); + if (!container) { + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("No modular data available")); + return FALSE; + } + std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages; + + auto disable_errors = modules_reset_or_disable(*container, module_specs, reset); + if (!disable_errors.empty()) { + messages.insert( + messages.end(), + std::make_move_iterator(disable_errors.begin()), + std::make_move_iterator(disable_errors.end())); + } + + std::vector<const char *> hotfixRepos; + // don't filter RPMs from repos with the 'module_hotfixes' flag set + for (unsigned int i = 0; i < priv->repos->len; i++) { + auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i)); + if (dnf_repo_get_module_hotfixes(repo)) { + hotfixRepos.push_back(dnf_repo_get_id(repo)); + } + } + hotfixRepos.push_back(nullptr); + auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos); + if (!solver_error.empty()) { + messages.insert( + messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end())); + } + bool return_error = report_problems(messages); + + if (return_error) { + if (reset) { + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("Problems appeared for module reset request")); + } else { + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("Problems appeared for module disable request")); + } + return FALSE; + } + return TRUE; +} + + +gboolean +dnf_context_module_disable(DnfContext * context, const char ** module_specs, GError ** error) try +{ + return context_modules_reset_or_disable(context, module_specs, error, false); +} CATCH_TO_GERROR(FALSE) + +gboolean +dnf_context_module_reset(DnfContext * context, const char ** module_specs, GError ** error) try +{ + return context_modules_reset_or_disable(context, module_specs, error, true); +} CATCH_TO_GERROR(FALSE) + +gboolean +dnf_context_module_switched_check(DnfContext * context, GError ** error) try +{ + DnfContextPrivate *priv = GET_PRIVATE (context); + if (priv->sack == nullptr) { + return TRUE; + } + auto container = dnf_sack_get_module_container(priv->sack); + if (!container) { + return TRUE; + } + auto switched = container->getSwitchedStreams(); + if (switched.empty()) { + return TRUE; + } + auto logger(libdnf::Log::getLogger()); + const char * msg = _("The operation would result in switching of module '%s' stream '%s' to stream '%s'"); + for (auto item : switched) { + logger->warning(tfm::format(msg, item.first.c_str(), item.second.first.c_str(), item.second.second.c_str())); + } + const char * msg_error = _("It is not possible to switch enabled streams of a module.\n" + "It is recommended to remove all installed content from the module, and " + "reset the module using 'microdnf module reset <module_name>' command. After " + "you reset the module, you can install the other stream."); + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, msg_error); + return FALSE; +} CATCH_TO_GERROR(FALSE) + namespace libdnf { std::map<std::string, std::string> & @@ -3045,3 +3466,4 @@ } } + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/dnf-context.h new/libdnf-0.55.0/libdnf/dnf-context.h --- old/libdnf-0.54.2/libdnf/dnf-context.h 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/dnf-context.h 2020-11-09 15:42:13.000000000 +0100 @@ -271,8 +271,8 @@ PluginHookId id, DnfPluginHookData *hookData, DnfPluginError *error); - - +/// String must be dealocated by g_free() +gchar * dnf_context_get_module_report (DnfContext * context); gboolean dnf_context_reset_modules (DnfContext * context, DnfSack * sack, const char ** module_names, @@ -280,6 +280,63 @@ gboolean dnf_context_reset_all_modules (DnfContext * context, DnfSack * sack, GError ** error); +/** + * dnf_context_module_enable: + * @context: DnfContext + * @module_specs: Module specs that should be enabled + * @error: Error + * + * Enable mudules, recalculate module filtration, but do not commit modular changes. + * To commit modular changes it requires to call dnf_context_run() + * Returns FALSE when an error is set. + * + * Since: 0.55.0 + **/ +gboolean dnf_context_module_enable (DnfContext * context, + const char ** module_specs, + GError ** error); +/** + * dnf_context_module_disable: + * @context: DnfContext + * @module_specs: Module specs that should be enabled + * @error: Error + * + * Disable mudules, recalculate module filtration, but do not commit modular changes. + * To commit modular changes it requires to call dnf_context_run() + * Returns FALSE when an error is set. + * + * Since: 0.55.0 + **/ +gboolean dnf_context_module_disable (DnfContext * context, + const char ** module_specs, + GError ** error); +/** + * dnf_context_module_reset: + * @context: DnfContext + * @module_specs: Module specs that should be enabled + * @error: Error + * + * Reset modules, recalculate module filtration, but do not commit modular changes. + * To commit modular changes it requires to call dnf_context_run() + * Returns FALSE when an error is set. + * + * Since: 0.55.0 + **/ +gboolean dnf_context_module_reset (DnfContext * context, + const char ** module_specs, + GError ** error); +/** + * dnf_context_module_switched_check: + * @context: DnfContext + * @error: Error + * + * Ceck if any module is switched and return FALSE and sets an error + * Returns FALSE when an error is set. + * + * Since: 0.55.0 + **/ +gboolean dnf_context_module_switched_check (DnfContext * context, + GError ** error); G_END_DECLS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/dnf-sack.cpp new/libdnf-0.55.0/libdnf/dnf-sack.cpp --- old/libdnf-0.54.2/libdnf/dnf-sack.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/dnf-sack.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -107,6 +107,7 @@ gboolean have_set_arch; gboolean all_arch; gboolean provides_ready; + gboolean allow_vendor_change; gchar *cache_dir; char *arch; dnf_sack_running_kernel_fn_t running_kernel_fn; @@ -189,6 +190,7 @@ priv->running_kernel_fn = running_kernel; priv->considered_uptodate = TRUE; priv->cmdline_repo = NULL; + priv->allow_vendor_change = TRUE; queue_init(&priv->installonly); /* logging up after this*/ @@ -843,6 +845,46 @@ return priv->all_arch; } +/* + * dnf_sack_set_allow_vendor_change: + * @sack: a #DnfSack instance. + * @allow_vendor_change is a boolean. + * + * Sets the value of allow vendor change to use for + * SOLVER_FLAG_ALLOW_VENDORCHANGE flag + * + * Returns: Nothing. + * + * Since: 0.54.3 + * + * */ +void +dnf_sack_set_allow_vendor_change(DnfSack *sack, gboolean allow_vendor_change) +{ + DnfSackPrivate *priv = GET_PRIVATE(sack); + priv->allow_vendor_change = allow_vendor_change; +} + +/* + * dnf_sack_get_allow_vendor_change: + * @sack: a #DnfSack instance. + * @allow_vendor_change is a boolean. + * + * Gets the value of allow vendor change to use for + * SOLVER_FLAG_ALLOW_VENDORCHANGE flag + * + * Returns: True if flag set to 1, False if set to 0 + * + * Since: 0.54.3 + * + * */ +gboolean +dnf_sack_get_allow_vendor_change(DnfSack *sack) +{ + DnfSackPrivate *priv = GET_PRIVATE(sack); + return priv->allow_vendor_change; +} + /** * dnf_sack_get_arch * @sack: a #DnfSack instance. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/dnf-sack.h new/libdnf-0.55.0/libdnf/dnf-sack.h --- old/libdnf-0.54.2/libdnf/dnf-sack.h 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/dnf-sack.h 2020-11-09 15:42:13.000000000 +0100 @@ -96,6 +96,9 @@ void dnf_sack_set_all_arch (DnfSack *sack, gboolean all_arch); gboolean dnf_sack_get_all_arch (DnfSack *sack); +void dnf_sack_set_allow_vendor_change(DnfSack *sack, + gboolean allow_vendor_change); +gboolean dnf_sack_get_allow_vendor_change(DnfSack *sack); void dnf_sack_set_rootdir (DnfSack *sack, const gchar *value); gboolean dnf_sack_setup (DnfSack *sack, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/dnf-transaction.cpp new/libdnf-0.55.0/libdnf/dnf-transaction.cpp --- old/libdnf-0.54.2/libdnf/dnf-transaction.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/dnf-transaction.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -1466,14 +1466,16 @@ /* hmm, nothing was done... */ if (priv->step != DNF_TRANSACTION_STEP_WRITING) { - ret = FALSE; - g_set_error(error, - DNF_ERROR, - DNF_ERROR_INTERNAL_ERROR, - _("Transaction did not go to writing phase, " - "but returned no error(%i)"), - priv->step); - goto out; + if (priv->install->len > 0 || priv->remove->len > 0) { + ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("Transaction did not go to writing phase, " + "but returned no error(%i)"), + priv->step); + goto out; + } } /* this section done */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/goal/Goal.cpp new/libdnf-0.55.0/libdnf/goal/Goal.cpp --- old/libdnf-0.54.2/libdnf/goal/Goal.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/goal/Goal.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -1167,6 +1167,49 @@ return pset; } +static std::string string_join(const std::vector<std::string> & src, const std::string & delim) +{ + if (src.empty()) { + return {}; + } + std::string output(*src.begin()); + for (auto iter = std::next(src.begin()); iter != src.end(); ++iter) { + output.append(delim); + output.append(*iter); + } + return output; +} + +std::string +Goal::formatAllProblemRules(const std::vector<std::vector<std::string>> & problems) +{ + if (problems.empty()) { + return {}; + } + bool single_problems = problems.size() == 1; + std::string output; + + if (single_problems) { + output.append(_("Problem: ")); + output.append(string_join(*problems.begin(), "\n - ")); + return output; + } + + const char * problem_prefix = _("Problem %d: "); + + output.append(tfm::format(problem_prefix, 1)); + output.append(string_join(*problems.begin(), "\n - ")); + + int index = 2; + for (auto iter = std::next(problems.begin()); iter != problems.end(); ++iter) { + output.append("\n "); + output.append(tfm::format(problem_prefix, index)); + output.append(string_join(*iter, "\n - ")); + ++index; + } + return output; +} + void Goal::Impl::allowUninstallAllButProtected(Queue *job, DnfGoalActions flags) { @@ -1224,8 +1267,11 @@ solver_free(solv); solv = solvNew; - /* no vendor locking */ - solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1); + /* vendor locking */ + int vendor = dnf_sack_get_allow_vendor_change(sack) ? 1 : 0; + solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, vendor); + solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE, vendor); + /* don't erase packages that are no longer in repo during distupgrade */ solver_set_flag(solv, SOLVER_FLAG_KEEP_ORPHANS, 1); /* no arch change for forcebest */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/goal/Goal.hpp new/libdnf-0.55.0/libdnf/goal/Goal.hpp --- old/libdnf-0.54.2/libdnf/goal/Goal.hpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/goal/Goal.hpp 2020-11-09 15:42:13.000000000 +0100 @@ -143,6 +143,8 @@ PackageSet listDowngrades(); PackageSet listObsoletedByPackage(DnfPackage * pkg); + /// Concentrate all problems into a string + static std::string formatAllProblemRules(const std::vector<std::vector<std::string>> & problems); private: friend Query; class Impl; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/hy-package.cpp new/libdnf-0.55.0/libdnf/hy-package.cpp --- old/libdnf-0.54.2/libdnf/hy-package.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/hy-package.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -419,6 +419,23 @@ } /** + * dnf_package_get_vendor: + * @pkg: a #DnfPackage instance. + * + * Gets the name for the package. + * + * Returns: a string, or %NULL + * + * Since: 0.54.4 + */ +const char * +dnf_package_get_vendor(DnfPackage *pkg) +{ + Pool *pool = dnf_package_get_pool(pkg); + return pool_id2str(pool, get_solvable(pkg)->vendor); +} + +/** * dnf_package_get_packager: * @pkg: a #DnfPackage instance. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/hy-package.h new/libdnf-0.55.0/libdnf/hy-package.h --- old/libdnf-0.54.2/libdnf/hy-package.h 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/hy-package.h 2020-11-09 15:42:13.000000000 +0100 @@ -62,6 +62,7 @@ Id dnf_package_get_id (DnfPackage *pkg); const char *dnf_package_get_name (DnfPackage *pkg); +const char *dnf_package_get_vendor (DnfPackage *pkg); const char *dnf_package_get_arch (DnfPackage *pkg); const unsigned char *dnf_package_get_chksum(DnfPackage *pkg, int *type); const char *dnf_package_get_description(DnfPackage *pkg); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/module/ModulePackageContainer.cpp new/libdnf-0.55.0/libdnf/module/ModulePackageContainer.cpp --- old/libdnf-0.54.2/libdnf/module/ModulePackageContainer.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/module/ModulePackageContainer.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -607,7 +607,8 @@ { if (modules.empty()) { activatedModules.reset(); - return {}; + return std::make_pair(std::vector<std::vector<std::string>>(), + ModulePackageContainer::ModuleErrorType::NO_ERROR); } dnf_sack_recompute_considered(moduleSack); dnf_sack_make_provides_ready(moduleSack); @@ -822,9 +823,40 @@ ModulePackageContainer::getReport() { std::string report; + + auto installedProfiles = getInstalledProfiles(); + if (!installedProfiles.empty()) { + report += _("Installing module profiles:\n"); + for (auto & item: installedProfiles) { + for (auto & profile:item.second) { + report += " "; + report += item.first; + report += ":"; + report += profile; + report += "\n"; + } + } + report += "\n"; + } + + auto removedProfiles = getRemovedProfiles(); + if (!removedProfiles.empty()) { + report += _("Disabling module profiles:\n"); + for (auto & item: removedProfiles) { + for (auto & profile:item.second) { + report += " "; + report += item.first; + report += ":"; + report += profile; + report += "\n"; + } + } + report += "\n"; + } + auto enabled = getEnabledStreams(); if (!enabled.empty()) { - report += "Module Enabling:\n"; + report += _("Enabling module streams:\n"); for (auto & item: enabled) { report += " "; report += item.first; @@ -834,20 +866,11 @@ } report += "\n"; } - auto disabled = getDisabledModules(); - if (!disabled.empty()) { - report += "Module Disabling:\n"; - for (auto & name: disabled) { - report += " "; - report += name; - report += "\n"; - } - report += "\n"; - } + auto switchedStreams = getSwitchedStreams(); if (!switchedStreams.empty()) { std::string switchedReport; - switchedReport += "Module Switched Streams:\n"; + switchedReport += _("Switching module streams:\n"); for (auto & item: switchedStreams) { switchedReport += " "; switchedReport += item.first; @@ -862,31 +885,25 @@ report += switchedReport; report += "\n"; } - auto installedProfiles = getInstalledProfiles(); - if (!installedProfiles.empty()) { - report += "Module Installing Profiles:\n"; - for (auto & item: installedProfiles) { - for (auto & profile:item.second) { - report += " "; - report += item.first; - report += ":"; - report += profile; - report += "\n"; - } + + auto disabled = getDisabledModules(); + if (!disabled.empty()) { + report += _("Disabling modules:\n"); + for (auto & name: disabled) { + report += " "; + report += name; + report += "\n"; } report += "\n"; } - auto removedProfiles = getRemovedProfiles(); - if (!removedProfiles.empty()) { - report += "Module Removing Profiles:\n"; - for (auto & item: removedProfiles) { - for (auto & profile:item.second) { - report += " "; - report += item.first; - report += ":"; - report += profile; - report += "\n"; - } + + auto reset = getResetModules(); + if (!reset.empty()) { + report += _("Resetting modules:\n"); + for (auto & name: reset) { + report += " "; + report += name; + report += "\n"; } report += "\n"; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/module/ModulePackageContainer.hpp new/libdnf-0.55.0/libdnf/module/ModulePackageContainer.hpp --- old/libdnf-0.54.2/libdnf/module/ModulePackageContainer.hpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/module/ModulePackageContainer.hpp 2020-11-09 15:42:13.000000000 +0100 @@ -47,9 +47,16 @@ enum class ModuleErrorType { NO_ERROR = 0, + INFO, + /// Error in module defaults detected during resovement of module dependencies ERROR_IN_DEFAULTS, + /// Error detected during resovement of module dependencies ERROR, - CANNOT_RESOLVE_MODULES + /// Error detected during resovement of module dependencies - Unexpected error!!! + CANNOT_RESOLVE_MODULES, + CANNOT_RESOLVE_MODULE_SPEC, + CANNOT_ENABLE_MULTIPLE_STREAMS, + CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE }; struct Exception : public std::runtime_error diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/sack/query.cpp new/libdnf-0.55.0/libdnf/sack/query.cpp --- old/libdnf-0.54.2/libdnf/sack/query.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/sack/query.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -2143,6 +2143,7 @@ return; Pool *pool = dnf_sack_get_pool(sack); + repo_internalize_all_trigger(pool); Map m; if (!result) initResult(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/utils/CMakeLists.txt new/libdnf-0.55.0/libdnf/utils/CMakeLists.txt --- old/libdnf-0.54.2/libdnf/utils/CMakeLists.txt 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf/utils/CMakeLists.txt 2020-11-09 15:42:13.000000000 +0100 @@ -13,6 +13,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/File.cpp ${CMAKE_CURRENT_SOURCE_DIR}/CompressedFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/logger.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/GLibLogger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/os-release.cpp PARENT_SCOPE ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/utils/GLibLogger.cpp new/libdnf-0.55.0/libdnf/utils/GLibLogger.cpp --- old/libdnf-0.54.2/libdnf/utils/GLibLogger.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libdnf-0.55.0/libdnf/utils/GLibLogger.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <GLibLogger.hpp> + +#include <glib.h> + +namespace libdnf { + +static inline void write_g_log(const std::string & domain, Logger::Level level, const std::string & message) +{ + GLogLevelFlags gLogLevel; + switch (level) { + // In GLib, the "G_LOG_LEVEL_ERROR" is more severe than "G_LOG_LEVEL_CRITICAL". + // In fact, the "G_LOG_LEVEL_ERROR" is always fatal. We won't use it now. + case Logger::Level::CRITICAL: + gLogLevel = G_LOG_LEVEL_CRITICAL; + break; + case Logger::Level::ERROR: + gLogLevel = G_LOG_LEVEL_CRITICAL; + break; + + case Logger::Level::WARNING: + gLogLevel = G_LOG_LEVEL_WARNING; + break; + case Logger::Level::NOTICE: + gLogLevel = G_LOG_LEVEL_MESSAGE; + break; + case Logger::Level::INFO: + gLogLevel = G_LOG_LEVEL_INFO; + break; + case Logger::Level::DEBUG: + case Logger::Level::TRACE: + default: + gLogLevel = G_LOG_LEVEL_DEBUG; + break; + } + g_log(domain.c_str(), gLogLevel, "%s", message.c_str()); +} + +void GLibLogger::write(int /*source*/, Level level, const std::string & message) +{ + write_g_log(domain, level, message); +} + +void GLibLogger::write(int /*source*/, time_t /*time*/, pid_t /*pid*/, Level level, const std::string & message) +{ + write_g_log(domain, level, message); +} + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf/utils/GLibLogger.hpp new/libdnf-0.55.0/libdnf/utils/GLibLogger.hpp --- old/libdnf-0.54.2/libdnf/utils/GLibLogger.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libdnf-0.55.0/libdnf/utils/GLibLogger.hpp 2020-11-09 15:42:13.000000000 +0100 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _GLIB_LOGGER_HPP_ +#define _GLIB_LOGGER_HPP_ + +#include <logger.hpp> + +namespace libdnf { + +class GLibLogger : public Logger { +public: + explicit GLibLogger(std::string domain) : domain(domain) {} + void write(int source, Level level, const std::string & message) override; + void write(int source, time_t time, pid_t pid, Level level, const std::string & message) override; + +private: + std::string domain; +}; + +} + +#endif // _GLIB_LOGGER_HPP_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/libdnf.spec new/libdnf-0.55.0/libdnf.spec --- old/libdnf-0.54.2/libdnf.spec 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/libdnf.spec 2020-11-09 15:42:13.000000000 +0100 @@ -1,13 +1,11 @@ -%define __cmake_in_source_build 1 - %global libsolv_version 0.7.7 %global libmodulemd_version 2.5.0 %global librepo_version 1.12.0 %global dnf_conflict 4.3.0 %global swig_version 3.0.12 %global libdnf_major_version 0 -%global libdnf_minor_version 54 -%global libdnf_micro_version 2 +%global libdnf_minor_version 55 +%global libdnf_micro_version 0 %define __cmake_in_source_build 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/python/hawkey/package-py.cpp new/libdnf-0.55.0/python/hawkey/package-py.cpp --- old/libdnf-0.54.2/python/hawkey/package-py.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/python/hawkey/package-py.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -302,6 +302,7 @@ {(char*)"release", (getter)get_str, NULL, NULL, (void *)dnf_package_get_release}, {(char*)"name", (getter)get_str, NULL, NULL, (void *)dnf_package_get_name}, + {(char*)"vendor", (getter)get_str, NULL, NULL, (void *)dnf_package_get_vendor}, {(char*)"arch", (getter)get_str, NULL, NULL, (void *)dnf_package_get_arch}, {(char*)"hdr_chksum", (getter)get_chksum, NULL, NULL, (void *)dnf_package_get_hdr_chksum}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/python/hawkey/sack-py.cpp new/libdnf-0.55.0/python/hawkey/sack-py.cpp --- old/libdnf-0.54.2/python/hawkey/sack-py.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/python/hawkey/sack-py.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -415,10 +415,22 @@ Py_RETURN_NONE; } CATCH_TO_PYTHON +static int +set_allow_vendor_change(_SackObject *self, PyObject *obj, void *unused) try +{ + gboolean vendor = PyObject_IsTrue(obj); + if (PyErr_Occurred()) + return -1; + dnf_sack_set_allow_vendor_change(self->sack, vendor); + return 0; +} CATCH_TO_PYTHON_INT + static PyGetSetDef sack_getsetters[] = { {(char*)"cache_dir", (getter)get_cache_dir, NULL, NULL, NULL}, {(char*)"installonly", NULL, (setter)set_installonly, NULL, NULL}, {(char*)"installonly_limit", NULL, (setter)set_installonly_limit, NULL, NULL}, + {(char*)"allow_vendor_change", NULL, + (setter)set_allow_vendor_change, NULL, NULL}, {(char*)"_moduleContainer", (getter)get_module_container, (setter)set_module_container, NULL, NULL}, {NULL} /* sentinel */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/tests/hawkey/CMakeLists.txt new/libdnf-0.55.0/tests/hawkey/CMakeLists.txt --- old/libdnf-0.54.2/tests/hawkey/CMakeLists.txt 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/tests/hawkey/CMakeLists.txt 2020-11-09 15:42:13.000000000 +0100 @@ -28,7 +28,7 @@ set_target_properties(test_hawkey_main PROPERTIES COMPILE_FLAGS -fPIC) target_link_libraries(test_hawkey_main libdnf - ${CHECK_LIBRARIES} + ${CHECK_LDFLAGS} ${SOLV_LIBRARY} ${SOLVEXT_LIBRARY} ${RPMDB_LIBRARY} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.54.2/tests/hawkey/test_package.cpp new/libdnf-0.55.0/tests/hawkey/test_package.cpp --- old/libdnf-0.54.2/tests/hawkey/test_package.cpp 2020-10-06 14:52:22.000000000 +0200 +++ new/libdnf-0.55.0/tests/hawkey/test_package.cpp 2020-11-09 15:42:13.000000000 +0100 @@ -91,6 +91,18 @@ } END_TEST +START_TEST(test_vendor) +{ + DnfSack *sack = test_globals.sack; + DnfPackage *pkg = by_name_repo(sack, "foolish-grin", "vendor"); + fail_if(pkg == NULL); + const char *vendor = dnf_package_get_vendor(pkg); + + ck_assert_str_eq(vendor, "PerfectlyLoud"); + g_object_unref(pkg); +} +END_TEST + START_TEST(test_no_sourcerpm) { DnfSack *sack = test_globals.sack; @@ -379,5 +391,10 @@ tcase_add_test(tc, test_get_files_cmdline); suite_add_tcase(s, tc); + tc = tcase_create("Vendor"); + tcase_add_unchecked_fixture(tc, fixture_with_vendor, teardown); + tcase_add_test(tc, test_vendor); + suite_add_tcase(s, tc); + return s; } _______________________________________________ openSUSE Commits mailing list -- commit@lists.opensuse.org To unsubscribe, email commit-le...@lists.opensuse.org List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette List Archives: https://lists.opensuse.org/archives/list/commit@lists.opensuse.org