Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libdnf for openSUSE:Factory checked in at 2021-11-06 18:13:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libdnf (Old) and /work/SRC/openSUSE:Factory/.libdnf.new.1890 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libdnf" Sat Nov 6 18:13:19 2021 rev:27 rq:929010 version:0.65.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libdnf/libdnf.changes 2021-08-31 19:55:05.629907559 +0200 +++ /work/SRC/openSUSE:Factory/.libdnf.new.1890/libdnf.changes 2021-11-06 18:13:35.516746005 +0100 @@ -1,0 +2,12 @@ +Wed Nov 3 11:11:08 UTC 2021 - Neal Gompa <ngomp...@gmail.com> + +- Update to 0.65.0 + + Add support for excluding packages to be installed as weak dependencies + + Add support for autodetecting packages to be excluded from being installed as weak dependencies + + Turn off strict validation of modulemd documents (rh#2004853, rh#2007166, rh#2007167) + + Implement logic for demodularization of modular rpms (rh#1805260) + + DnfContext: fix handling of default module profiles + + ModuleMetadata: gracefully handle modules with no defaults + + Remove failovermethod config option (rh#1961083) + +------------------------------------------------------------------- Old: ---- libdnf-0.63.1.tar.gz New: ---- libdnf-0.65.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libdnf.spec ++++++ --- /var/tmp/diff_new_pack.TZot2J/_old 2021-11-06 18:13:37.604747099 +0100 +++ /var/tmp/diff_new_pack.TZot2J/_new 2021-11-06 18:13:37.604747099 +0100 @@ -2,7 +2,7 @@ # spec file for package libdnf # # Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. -# Copyright (c) 2020-2021 Neal Gompa <ngomp...@gmail.com>. +# Copyright (c) 2021 Neal Gompa <ngomp...@gmail.com>. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,9 +17,9 @@ # -%global libsolv_version 0.7.17 -%global libmodulemd_version 2.12.0 -%global librepo_version 1.13.0 +%global libsolv_version 0.7.20 +%global libmodulemd_version 2.13.0 +%global librepo_version 1.13.1 %global dnf_conflict 4.3.0 %global swig_version 3.0.12 @@ -34,7 +34,7 @@ %define devname %{name}-devel Name: libdnf -Version: 0.63.1 +Version: 0.65.0 Release: 0 Summary: Library providing C and Python APIs atop libsolv License: LGPL-2.1-or-later ++++++ libdnf-0.63.1.tar.gz -> libdnf-0.65.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/VERSION.cmake new/libdnf-0.65.0/VERSION.cmake --- old/libdnf-0.63.1/VERSION.cmake 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/VERSION.cmake 2021-10-21 08:19:17.000000000 +0200 @@ -1,6 +1,6 @@ set (DEFAULT_LIBDNF_MAJOR_VERSION 0) -set (DEFAULT_LIBDNF_MINOR_VERSION 63) -set (DEFAULT_LIBDNF_MICRO_VERSION 1) +set (DEFAULT_LIBDNF_MINOR_VERSION 65) +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.63.1/docs/release_notes.rst new/libdnf-0.65.0/docs/release_notes.rst --- old/libdnf-0.63.1/docs/release_notes.rst 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/docs/release_notes.rst 2021-10-21 08:19:17.000000000 +0200 @@ -20,6 +20,37 @@ ###################### ==================== +0.65.0 Release Notes +==================== + +- New features: + - Add support for excluding packages to be installed as weak dependencies + - Add support for autodetecting packages to be excluded from being installed as weak dependencies + +- Bug fixes: + - Turn off strict validation of modulemd documents (RhBug:2004853,2007166,2007167) + +Bugs fixed in 0.65.0: + +* :rhbug:`2004853` +* :rhbug:`2007166` +* :rhbug:`2007167` + +==================== +0.64.0 Release Notes +==================== + +- Implement logic for demodularization of modular rpms (RhBug:1805260) +- DnfContext: fix handling of default module profiles +- ModuleMetadata: gracefully handle modules with no defaults +- Remove failovermethod config option (RhBug:1961083) + +Bugs fixed in 0.64.0: + +* :rhbug:`1961083` +* :rhbug:`1805260` + +==================== 0.63.1 Release Notes ==================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/conf/ConfigMain.cpp new/libdnf-0.65.0/libdnf/conf/ConfigMain.cpp --- old/libdnf-0.63.1/libdnf/conf/ConfigMain.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/conf/ConfigMain.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -298,6 +298,8 @@ OptionBool fastestmirror{false}; OptionStringList excludepkgs{std::vector<std::string>{}}; OptionStringList includepkgs{std::vector<std::string>{}}; + OptionStringList exclude_from_weak{std::vector<std::string>{}}; + OptionBool exclude_from_weak_autodetect{true}; OptionString proxy{""}; OptionString proxy_username{nullptr}; OptionString proxy_password{nullptr}; @@ -475,7 +477,13 @@ optionTListAppend(includepkgs, priority, value); }, nullptr, true ); + owner.optBinds().add("exclude_from_weak", exclude_from_weak, + [&](Option::Priority priority, const std::string & value){ + optionTListAppend(exclude_from_weak, priority, value); + }, nullptr, true + ); + owner.optBinds().add("exclude_from_weak_autodetect", exclude_from_weak_autodetect); owner.optBinds().add("proxy", proxy); owner.optBinds().add("proxy_username", proxy_username); owner.optBinds().add("proxy_password", proxy_password); @@ -601,6 +609,8 @@ OptionBool & ConfigMain::fastestmirror() { return pImpl->fastestmirror; } OptionStringList & ConfigMain::excludepkgs() { return pImpl->excludepkgs; } OptionStringList & ConfigMain::includepkgs() { return pImpl->includepkgs; } +OptionStringList & ConfigMain::exclude_from_weak() { return pImpl->exclude_from_weak; } +OptionBool & ConfigMain::exclude_from_weak_autodetect() { return pImpl->exclude_from_weak_autodetect; } OptionString & ConfigMain::proxy() { return pImpl->proxy; } OptionString & ConfigMain::proxy_username() { return pImpl->proxy_username; } OptionString & ConfigMain::proxy_password() { return pImpl->proxy_password; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/conf/ConfigMain.hpp new/libdnf-0.65.0/libdnf/conf/ConfigMain.hpp --- old/libdnf-0.63.1/libdnf/conf/ConfigMain.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/conf/ConfigMain.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -137,6 +137,8 @@ OptionBool & fastestmirror(); OptionStringList & excludepkgs(); OptionStringList & includepkgs(); + OptionStringList & exclude_from_weak(); + OptionBool & exclude_from_weak_autodetect(); OptionString & proxy(); OptionString & proxy_username(); OptionString & proxy_password(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/conf/ConfigRepo.cpp new/libdnf-0.65.0/libdnf/conf/ConfigRepo.cpp --- old/libdnf-0.63.1/libdnf/conf/ConfigRepo.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/conf/ConfigRepo.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -79,7 +79,6 @@ OptionString enabled_metadata{""}; OptionChild<OptionString> user_agent{mainConfig.user_agent()}; OptionChild<OptionBool> countme{mainConfig.countme()}; - OptionEnum<std::string> failovermethod{"priority", {"priority", "roundrobin"}}; OptionChild<OptionBool> sslverifystatus{mainConfig.sslverifystatus()}; }; @@ -230,7 +229,6 @@ OptionString & ConfigRepo::enabled_metadata() { return pImpl->enabled_metadata; } OptionChild<OptionString> & ConfigRepo::user_agent() { return pImpl->user_agent; } OptionChild<OptionBool> & ConfigRepo::countme() { return pImpl->countme; } -OptionEnum<std::string> & ConfigRepo::failovermethod() { return pImpl->failovermethod; } OptionChild<OptionBool> & ConfigRepo::sslverifystatus() { return pImpl->sslverifystatus; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/conf/ConfigRepo.hpp new/libdnf-0.65.0/libdnf/conf/ConfigRepo.hpp --- old/libdnf-0.63.1/libdnf/conf/ConfigRepo.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/conf/ConfigRepo.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -95,7 +95,6 @@ OptionChild<OptionString> & user_agent(); OptionChild<OptionBool> & countme(); // yum compatibility options - OptionEnum<std::string> & failovermethod(); OptionChild<OptionBool> & sslverifystatus(); private: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/config.h new/libdnf-0.65.0/libdnf/config.h --- old/libdnf-0.63.1/libdnf/config.h 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/config.h 2021-10-21 08:19:17.000000000 +0200 @@ -18,16 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef __APPLE__ -#include <stdint.h> -#else -#include <bits/wordsize.h> -#endif +#include <limits.h> -#if __WORDSIZE == 32 -#include "config-32.h" -#elif __WORDSIZE == 64 +#if (ULONG_MAX == 0xffffffffffffffff) #include "config-64.h" +#elif (ULONG_MAX == 0xffffffff) +#include "config-32.h" #else #error "Unknown word size" #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-context.cpp new/libdnf-0.65.0/libdnf/dnf-context.cpp --- old/libdnf-0.63.1/libdnf/dnf-context.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-context.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -3075,6 +3075,10 @@ return ret; } +/* This is subtly different from the C++ version above: it passes NULL as the + * modular container to `dnf_sack_filter_modules_v2` which has the effect of + * throwing away all transient modular changes and reloading from disk. This is + * used by dnf_context_reset_all_modules(). */ static gboolean recompute_modular_filtering(DnfContext * context, DnfSack * sack, GError ** error) { @@ -3098,6 +3102,7 @@ return TRUE; } +/* See header docstring; you likely want dnf_context_module_reset instead. */ gboolean dnf_context_reset_modules(DnfContext * context, DnfSack * sack, const char ** module_names, GError ** error) try { @@ -3525,7 +3530,15 @@ throw std::runtime_error(tfm::format(_("No profile found matching '%s'"), nsvcap_obj->getProfile().c_str())); } } else { - profiles.push_back(latest->getDefaultProfile()); + // This queries the distro-level modulemd-defaults. + auto default_profiles = container->getDefaultProfiles(latest->getName(), latest->getStream()); + for (auto & profileName : default_profiles) { + auto matching = latest->getProfiles(profileName); + profiles.insert(profiles.begin(), matching.begin(), matching.end()); + } + if (profiles.empty()) { + throw std::runtime_error("No default profile found for " + latest->getFullIdentifier()); + } } g_autoptr(GPtrArray) pkgnames = g_ptr_array_new_with_free_func (g_free); @@ -3665,6 +3678,59 @@ } CATCH_TO_GERROR(FALSE) gboolean +dnf_context_module_disable_all(DnfContext * context, 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; + auto container = dnf_sack_get_module_container(sack); + if (!container) { + return TRUE; + } + + auto all_modules = container->getModulePackages(); + for (auto & module: all_modules) { + container->disable(module->getName()); + } + + 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); + + std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages; + 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())); + } + + auto errors = report_problems(messages); + if (!errors.empty()) { + std::string final_errmsg (_("Problems appeared for module disable request:")); + for (const auto &errmsg : errors) { + final_errmsg += "\n - " + errmsg; + } + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, final_errmsg.c_str()); + return FALSE; + } + return TRUE; +} 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); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-context.h new/libdnf-0.65.0/libdnf/dnf-context.h --- old/libdnf-0.63.1/libdnf/dnf-context.h 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-context.h 2021-10-21 08:19:17.000000000 +0200 @@ -280,13 +280,41 @@ DnfPluginError *error); /// String must be dealocated by g_free() gchar * dnf_context_get_module_report (DnfContext * context); + +/** + * dnf_context_reset_modules: + * @context: DnfContext + * @sack: DnfSack + * @module_names: Names of modules to reset + * @error: Error + * + * Reset modules, commit modular changes, and recalculate module filtration. + * Note you likely want to use dnf_context_module_reset instead which matches + * the behaviour of other modular APIs to not commit modular changes to disk + * until dnf_context_run(). Returns FALSE when an error is set. + * + * Since: 0.38.1 + **/ gboolean dnf_context_reset_modules (DnfContext * context, DnfSack * sack, const char ** module_names, GError ** error); + +/** + * dnf_context_reset_all_modules: + * @context: DnfContext + * @sack: DnfSack + * @error: Error + * + * Reset all modules and recalculate module filtration. + * Returns FALSE when an error is set. + * + * Since: 0.46.2 + **/ gboolean dnf_context_reset_all_modules (DnfContext * context, DnfSack * sack, GError ** error); + /** * dnf_context_module_enable: * @context: DnfContext @@ -325,7 +353,7 @@ * @module_specs: Module specs that should be enabled * @error: Error * - * Disable mudules, recalculate module filtration, but do not commit modular changes. + * Disable 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. * @@ -334,6 +362,22 @@ gboolean dnf_context_module_disable (DnfContext * context, const char ** module_specs, GError ** error); + +/** + * dnf_context_module_disable_all: + * @context: DnfContext + * @module_specs: Module specs that should be enabled + * @error: Error + * + * Disable all 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.64.0 + **/ +gboolean dnf_context_module_disable_all (DnfContext * context, + GError ** error); + /** * dnf_context_module_reset: * @context: DnfContext diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-goal.cpp new/libdnf-0.65.0/libdnf/dnf-goal.cpp --- old/libdnf-0.63.1/libdnf/dnf-goal.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-goal.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -48,6 +48,26 @@ #include <vector> +static void set_excludes_from_weak_to_goal(HyGoal goal) +{ + DnfSack * sack = hy_goal_get_sack(goal); + + goal->reset_exclude_from_weak(); + + const auto & exclude_from_weak_autodetect = libdnf::getGlobalMainConfig().exclude_from_weak_autodetect().getValue(); + if (exclude_from_weak_autodetect) { + goal->exclude_from_weak_autodetect(); + } + + const auto & exclude_from_weak = libdnf::getGlobalMainConfig().exclude_from_weak().getValue(); + + for (auto & exclude : exclude_from_weak) { + libdnf::Query query(sack); + auto ret = query.filterSubject(exclude.c_str(), nullptr, false, true, false, false); + goal->add_exclude_from_weak(*query.getResultPset()); + } +} + /** * dnf_goal_depsolve: * @goal: a #HyGoal. @@ -80,6 +100,8 @@ auto pkgset = *query.runSet(); goal->addProtected(pkgset); + set_excludes_from_weak_to_goal(goal); + rc = hy_goal_run_flags(goal, flags); if (rc) { string = g_string_new(_("Could not depsolve transaction; ")); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-reldep.cpp new/libdnf-0.65.0/libdnf/dnf-reldep.cpp --- old/libdnf-0.63.1/libdnf/dnf-reldep.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-reldep.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -60,6 +60,24 @@ return reldep->getId(); } +const char * +dnf_reldep_get_name(DnfReldep * reldep) +{ + return reldep->getName(); +} + +const char * +dnf_reldep_get_relation(DnfReldep * reldep) +{ + return reldep->getRelation(); +} + +const char * +dnf_reldep_get_version(DnfReldep * reldep) +{ + return reldep->getVersion(); +} + void dnf_reldep_free(DnfReldep *reldep) { delete reldep; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-reldep.h new/libdnf-0.65.0/libdnf/dnf-reldep.h --- old/libdnf-0.63.1/libdnf/dnf-reldep.h 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-reldep.h 2021-10-21 08:19:17.000000000 +0200 @@ -31,6 +31,9 @@ DnfReldep *dnf_reldep_new(DnfSack *sack, const char *name, int cmp_type, const char *evr); const char *dnf_reldep_to_string(DnfReldep *reldep); Id dnf_reldep_get_id(DnfReldep *reldep); +const char * dnf_reldep_get_name(DnfReldep * reldep); +const char * dnf_reldep_get_relation(DnfReldep * reldep); +const char * dnf_reldep_get_version(DnfReldep * reldep); void dnf_reldep_free(DnfReldep *reldep); #ifdef __cplusplus diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-repo.cpp new/libdnf-0.65.0/libdnf/dnf-repo.cpp --- old/libdnf-0.63.1/libdnf/dnf-repo.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-repo.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -1966,9 +1966,12 @@ g_free(updatedata.last_mirror_failure_message); g_free(updatedata.last_mirror_url); dnf_state_release_locks(state); - lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSCB, NULL); - lr_handle_setopt(priv->repo_handle, NULL, LRO_HMFCB, NULL); - lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSDATA, 0xdeadbeef); + if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSCB, NULL)) + g_debug("Failed to reset LRO_PROGRESSCB to NULL"); + if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_HMFCB, NULL)) + g_debug("Failed to reset LRO_HMFCB to NULL"); + if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSDATA, 0xdeadbeef)) + g_debug("Failed to set LRO_PROGRESSDATA to 0xdeadbeef"); return ret; } CATCH_TO_GERROR(FALSE) @@ -2296,8 +2299,10 @@ ret = TRUE; out: - lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSCB, NULL); - lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSDATA, 0xdeadbeef); + if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSCB, NULL)) + g_debug("Failed to reset LRO_PROGRESSCB to NULL"); + if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSDATA, 0xdeadbeef)) + g_debug("Failed to set LRO_PROGRESSDATA to 0xdeadbeef"); g_free(global_data.last_mirror_failure_message); g_free(global_data.last_mirror_url); g_slist_free_full(package_targets, (GDestroyNotify)lr_packagetarget_free); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-sack.cpp new/libdnf-0.65.0/libdnf/dnf-sack.cpp --- old/libdnf-0.63.1/libdnf/dnf-sack.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-sack.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -2308,47 +2308,107 @@ } } -static std::tuple<std::vector<std::string>, std::vector<std::string>> -collectNevraForInclusionExclusion(libdnf::ModulePackageContainer &modulePackageContainer) +/// @return std::map<name:stream.arch, std::vector<std::string>> +static std::map<std::string, std::vector<std::string>> getDemodularizedRpms( + libdnf::ModulePackageContainer & moduleContainer, const std::vector<libdnf::ModulePackage *> & allPackages) { + std::map<std::string, std::vector<std::string>> ret; + auto latest = moduleContainer.getLatestModules(allPackages, true); + for (auto modulePackage : latest) { + auto demodularized = modulePackage->getDemodularizedRpms(); + if (demodularized.empty()) { + continue; + } + std::string packageID{modulePackage->getNameStream()}; + packageID.append("."); + packageID.append(modulePackage->getArch()); + auto & data = ret[packageID]; + data.insert(data.end(), demodularized.begin(), demodularized.end()); + } + return ret; +} + +/// Return <includeNEVRAs>, <excludeNEVRAs>, <names>, <srcNames>, <name dependency container> +static std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, libdnf::DependencyContainer> +collectNevraForInclusionExclusion(DnfSack *sack, libdnf::ModulePackageContainer &modulePackageContainer) +{ + auto allPackages = modulePackageContainer.getModulePackages(); + auto demodularizedNames = getDemodularizedRpms(modulePackageContainer, allPackages); + std::vector<std::string> includeNEVRAs; std::vector<std::string> excludeNEVRAs; + std::vector<std::string> names; + std::vector<std::string> srcNames; + libdnf::DependencyContainer nameDependencies{sack}; + libdnf::Nevra nevra; // TODO: turn into std::vector<const char *> to prevent unnecessary conversion? - for (const auto &module : modulePackageContainer.getModulePackages()) { + for (const auto & module : allPackages) { auto artifacts = module->getArtifacts(); // TODO use Goal::listInstalls() to not requires filtering out Platform if (modulePackageContainer.isModuleActive(module->getId())) { + std::string packageID{module->getNameStream()}; + packageID.append("."); + packageID.append(module->getArch()); + auto it = demodularizedNames.find(packageID); + if (it == demodularizedNames.end()) { + for (const auto &rpm : artifacts) { + if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) { + auto arch = nevra.getArch(); + // source packages do not provide anything and must not cause excluding binary packages + if (arch == "src" || arch == "nosrc") { + srcNames.push_back(nevra.getName()); + } else { + names.push_back(nevra.getName()); + nameDependencies.addReldep(nevra.getName().c_str()); + } + } + } + } else { + for (const auto &rpm : artifacts) { + if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) { + bool found = false; + for ( auto & demodularized : it->second) { + if (nevra.getName() == demodularized) { + found = true; + break; + } + } + if (found) { + continue; + } + auto arch = nevra.getArch(); + // source packages do not provide anything and must not cause excluding binary packages + if (arch == "src" || arch == "nosrc") { + srcNames.push_back(nevra.getName()); + } else { + names.push_back(nevra.getName()); + nameDependencies.addReldep(nevra.getName().c_str()); + } + } + } + } copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(includeNEVRAs)); } else { copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(excludeNEVRAs)); } } - return std::tuple<std::vector<std::string>, - std::vector<std::string>>{includeNEVRAs, excludeNEVRAs}; + return std::make_tuple(std::move(includeNEVRAs), std::move(excludeNEVRAs), std::move(names), std::move(srcNames), + std::move(nameDependencies)); } -static void -setModuleExcludes(DnfSack *sack, const char ** hotfixRepos, - const std::vector<std::string> &includeNEVRAs, const std::vector<std::string> &excludeNEVRAs) +void +setModuleExcludes(DnfSack * sack, const char ** hotfixRepos, libdnf::ModulePackageContainer & modulePackageContainer) { dnf_sack_set_module_excludes(sack, nullptr); - std::vector<std::string> names; - std::vector<std::string> srcNames; - libdnf::DependencyContainer nameDependencies{sack}; - libdnf::Nevra nevra; - for (const auto &rpm : includeNEVRAs) { - if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) { - auto arch = nevra.getArch(); - // source packages do not provide anything and must not cause excluding binary packages - if (arch == "src" || arch == "nosrc") { - srcNames.push_back(nevra.getName()); - } else { - names.push_back(nevra.getName()); - nameDependencies.addReldep(nevra.getName().c_str()); - } - } - } + + auto data = collectNevraForInclusionExclusion(sack, modulePackageContainer); + + auto & includeNEVRAs = std::get<0>(data); + auto & excludeNEVRAs = std::get<1>(data); + auto & names = std::get<2>(data); + auto & srcNames = std::get<3>(data); + auto & nameDependencies = std::get<4>(data); std::vector<const char *> namesCString(names.size() + 1); std::vector<const char *> srcNamesCString(srcNames.size() + 1); @@ -2471,9 +2531,8 @@ moduleContainer->applyObsoletes(); } auto ret = moduleContainer->resolveActiveModulePackages(debugSolver); - auto nevraTuple = collectNevraForInclusionExclusion(*moduleContainer); - setModuleExcludes(sack, hotfixRepos, std::get<0>(nevraTuple), std::get<1>(nevraTuple)); + setModuleExcludes(sack, hotfixRepos, *moduleContainer); return ret; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/dnf-transaction.cpp new/libdnf-0.65.0/libdnf/dnf-transaction.cpp --- old/libdnf-0.63.1/libdnf/dnf-transaction.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/dnf-transaction.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -1523,8 +1523,6 @@ /* this section done */ ret = dnf_state_done(state, error); - if (!ret) - goto out; out: dnf_transaction_reset(transaction); dnf_state_release_locks(state); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/goal/Goal-private.hpp new/libdnf-0.65.0/libdnf/goal/Goal-private.hpp --- old/libdnf-0.63.1/libdnf/goal/Goal-private.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/goal/Goal-private.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -23,6 +23,7 @@ #include "Goal.hpp" #include "IdQueue.hpp" +#include "../sack/packageset.hpp" namespace libdnf { @@ -37,6 +38,7 @@ DnfSack *sack; Queue staging; + PackageSet exclude_from_weak; Solver *solv{nullptr}; ::Transaction *trans{nullptr}; DnfGoalActions actions{DNF_NONE}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/goal/Goal.cpp new/libdnf-0.65.0/libdnf/goal/Goal.cpp --- old/libdnf-0.63.1/libdnf/goal/Goal.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/goal/Goal.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -635,7 +635,7 @@ Goal::Goal(const Goal & goal_src) : pImpl(new Impl(*goal_src.pImpl)) {} Goal::Impl::Impl(const Goal::Impl & goal_src) -: sack(goal_src.sack) +: sack(goal_src.sack), exclude_from_weak(goal_src.exclude_from_weak) { queue_init_clone(&staging, const_cast<Queue *>(&goal_src.staging)); @@ -649,7 +649,7 @@ } Goal::Impl::Impl(DnfSack *sack) -: sack(sack) +: sack(sack), exclude_from_weak(sack) { queue_init(&staging); } @@ -794,6 +794,92 @@ } void +Goal::add_exclude_from_weak(const DnfPackageSet & pset) +{ + pImpl->exclude_from_weak += pset; +} + +void +Goal::add_exclude_from_weak(DnfPackage *pkg) +{ + // ensure that the map has a corrent size before set to prevent memory corruption + map_grow(pImpl->exclude_from_weak.getMap(), dnf_sack_get_pool(pImpl->sack)->nsolvables); + pImpl->exclude_from_weak.set(pkg); +} + +void +Goal::reset_exclude_from_weak() +{ + pImpl->exclude_from_weak.clear(); +} + +void +Goal::exclude_from_weak_autodetect() +{ + Query installed_query(pImpl->sack, Query::ExcludeFlags::IGNORE_EXCLUDES); + installed_query.installed(); + if (installed_query.empty()) { + return; + } + Query base_query(pImpl->sack); + base_query.apply(); + auto * installed_pset = installed_query.getResultPset(); + Id installed_id = -1; + + std::vector<const char *> installed_names; + installed_names.reserve(installed_pset->size() + 1); + + // Iterate over installed packages to detect unmet weak deps + while ((installed_id = installed_pset->next(installed_id)) != -1) { + g_autoptr(DnfPackage) pkg = dnf_package_new(pImpl->sack, installed_id); + installed_names.push_back(dnf_package_get_name(pkg)); + std::unique_ptr<libdnf::DependencyContainer> recommends(dnf_package_get_recommends(pkg)); + for (int i = 0; i < recommends->count(); ++i) { + Query query(base_query); + std::unique_ptr<libdnf::Dependency> dep(recommends->getPtr(i)); + const char * version = dep->getVersion(); + // There can be installed provider in different version or upgraded packed can recommend a different version + // Ignore version and search only by reldep name + if (version && strlen(version) > 0) { + query.addFilter(HY_PKG_PROVIDES, HY_EQ, dep->getName()); + } else { + query.addFilter(HY_PKG_PROVIDES, dep.get()); + } + // No providers of recommend => continue + if (query.empty()) { + continue; + } + Query test_installed(query); + test_installed.installed(); + // when there is not installed any provider of recommend, exclude it + if (test_installed.empty()) { + add_exclude_from_weak(*query.getResultPset()); + } + } + } + + // Invesigate supplements of only available packages with a different name to installed packages + installed_names.push_back(nullptr); + base_query.addFilter(HY_PKG_NAME, HY_NEQ, installed_names.data()); + auto * available_pset = base_query.getResultPset(); + *available_pset -= *installed_pset; + Id available_id = -1; + while ((available_id = available_pset->next(available_id)) != -1) { + g_autoptr(DnfPackage) pkg = dnf_package_new(pImpl->sack, available_id); + std::unique_ptr<libdnf::DependencyContainer> supplements(dnf_package_get_supplements(pkg)); + if (supplements->count() == 0) { + continue; + } + Query query(installed_query); + query.addFilter(HY_PKG_PROVIDES, supplements.get()); + // When supplemented package already installed, exclude_from_weak available package + if (!query.empty()) { + add_exclude_from_weak(pkg); + } + } +} + +void Goal::disfavor(DnfPackage *pkg) { queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_DISFAVOR, dnf_package_get_id(pkg)); @@ -1261,6 +1347,12 @@ elements[i] |= SOLVER_FORCEBEST; } + // Add weak excludes to the job + Id id = -1; + while ((id = exclude_from_weak.next(id)) != -1) { + job->pushBack(SOLVER_SOLVABLE|SOLVER_EXCLUDEFROMWEAK, id); + } + /* turn off implicit obsoletes for installonly packages */ for (int i = 0; i < (int) dnf_sack_get_installonly(sack)->count; i++) job->pushBack(SOLVER_MULTIVERSION|SOLVER_SOLVABLE_PROVIDES, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/goal/Goal.hpp new/libdnf-0.65.0/libdnf/goal/Goal.hpp --- old/libdnf-0.63.1/libdnf/goal/Goal.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/goal/Goal.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -76,6 +76,10 @@ void install(DnfPackage *new_pkg, bool optional); void lock(DnfPackage *new_pkg); void favor(DnfPackage *new_pkg); + void add_exclude_from_weak(const DnfPackageSet & pset); + void add_exclude_from_weak(DnfPackage *pkg); + void reset_exclude_from_weak(); + void exclude_from_weak_autodetect(); void disfavor(DnfPackage *new_pkg); /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/module/ModulePackage.cpp new/libdnf-0.65.0/libdnf/module/ModulePackage.cpp --- old/libdnf-0.63.1/libdnf/module/ModulePackage.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/module/ModulePackage.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -418,6 +418,24 @@ return result_rpms; } +/** + * @brief Return sorted list of RPM names that are demodularized. + * + * @return std::vector<std::string> + */ +std::vector<std::string> ModulePackage::getDemodularizedRpms() const +{ + std::vector<std::string> result_rpms; + char ** rpms = modulemd_module_stream_v2_get_demodularized_rpms((ModulemdModuleStreamV2 *) mdStream); + + for (char **iter = rpms; iter && *iter; iter++) { + result_rpms.emplace_back(std::string(*iter)); + } + + g_strfreev(rpms); + return result_rpms; +} + std::vector<ModuleProfile> ModulePackage::getProfiles(const std::string &name) const { @@ -442,6 +460,19 @@ return result_profiles; } +/* @brief Return default profiles as defined in the modulemd itself. + * + * Note this is probably not the function you want. You likely want to use + * ModulePackageContainer::getDefaultProfiles() instead, which sources the + * distro-level modulemd-defaults. + * + * Also, this function returns the first default profile, but instead we want it + * to return all default profiles. So supporting this properly in the future + * would require a new ModulePackage::getDefaultProfiles() which returns an + * std::vec<ModuleProfile> instead. + * + * @return ModuleProfile + */ ModuleProfile ModulePackage::getDefaultProfile() const { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/module/ModulePackage.hpp new/libdnf-0.65.0/libdnf/module/ModulePackage.hpp --- old/libdnf-0.63.1/libdnf/module/ModulePackage.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/module/ModulePackage.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -59,6 +59,10 @@ std::string getDescription() const; std::vector<std::string> getArtifacts() const; + + /// Return sorted list of RPM names that are demodularized. + std::vector<std::string> getDemodularizedRpms() const; + bool operator==(const ModulePackage &r) const; /** * @brief Return profiles matched by name (which is possibly a globby pattern). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/module/ModulePackageContainer.cpp new/libdnf-0.65.0/libdnf/module/ModulePackageContainer.cpp --- old/libdnf-0.63.1/libdnf/module/ModulePackageContainer.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/module/ModulePackageContainer.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -859,7 +859,7 @@ if (!latest) { latest = module; } else { - if (module->getVersion() > latest->getVersion()) { + if (module->getVersionNum() > latest->getVersionNum()) { latest = module; } } @@ -1051,13 +1051,15 @@ if (modulePackages.empty()) { return {}; } - auto & packageFirst = modulePackages[0]; + std::vector<std::vector<std::vector<ModulePackage *>>> output; auto sack = pImpl->moduleSack; std::sort(modulePackages.begin(), modulePackages.end(), [sack](const ModulePackage * first, const ModulePackage * second) {return modulePackageLatestPerRepoSorter(sack, first, second);}); auto vectorSize = modulePackages.size(); + + auto & packageFirst = modulePackages[0]; output.push_back( std::vector<std::vector<ModulePackage *>>{std::vector<ModulePackage *> {packageFirst}}); int repoIndex = 0; @@ -1099,6 +1101,35 @@ return output; } +std::vector<ModulePackage *> +ModulePackageContainer::getLatestModules(const std::vector<ModulePackage *> modulePackages, bool activeOnly) +{ + // Because modular sovables uses as name combination of module $name:$stream:$context, we can use to get the lates + // Query + std::vector<ModulePackage *> latestModules; + Query query(pImpl->moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES); + if (activeOnly) { + // When no active module return + if (!pImpl->activatedModules) { + return latestModules; + } + query.addFilter(HY_PKG, HY_EQ, pImpl->activatedModules.get()); + } + + PackageSet inputModulePackages(pImpl->moduleSack); + for (auto modulePackage : modulePackages) { + inputModulePackages.set(modulePackage->getId()); + } + query.addFilter(HY_PKG, HY_EQ, &inputModulePackages); + query.addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, 1); + auto set = query.runSet(); + + Id moduleId = -1; + while ((moduleId = set->next(moduleId)) != -1) { + latestModules.push_back(pImpl->modules.at(moduleId).get()); + } + return latestModules; +} std::pair<std::vector<std::vector<std::string>>, ModulePackageContainer::ModuleErrorType> ModulePackageContainer::resolveActiveModulePackages(bool debugSolver) @@ -1753,8 +1784,6 @@ if (pImpl->activatedModules) { std::vector<ModulePackage *> latest = pImpl->getLatestActiveEnabledModules(); - auto begin = fileNames.begin(); - auto end = fileNames.end(); if (g_mkdir_with_parents(pImpl->persistDir.c_str(), 0755) == -1) { const char * errTxt = strerror(errno); auto logger(Log::getLogger()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/module/ModulePackageContainer.hpp new/libdnf-0.65.0/libdnf/module/ModulePackageContainer.hpp --- old/libdnf-0.63.1/libdnf/module/ModulePackageContainer.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/module/ModulePackageContainer.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -134,6 +134,16 @@ std::vector<ModulePackage *> getModulePackages(); std::vector<std::vector<std::vector<ModulePackage *>>> getLatestModulesPerRepo( ModuleState moduleFilter, std::vector<ModulePackage *> modulePackages); + + /** + * @brief Return all latest ModulePackages for each module Name, stream, context and architecture. In case of + * multiple latest packages, all will be returned. When activeOnly is true, it returns only the latest active + * packages. + * + * @return std::vector<ModulePackage *> + */ + std::vector<ModulePackage *> getLatestModules(const std::vector<ModulePackage *> modulePackages, bool activeOnly); + ModulePackage * getLatestModule(std::vector<ModulePackage *> modulePackages, bool activeOnly); std::vector<ModulePackage *> requiresModuleEnablement(const libdnf::PackageSet & packages); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/module/modulemd/ModuleMetadata.cpp new/libdnf-0.65.0/libdnf/module/modulemd/ModuleMetadata.cpp --- old/libdnf-0.63.1/libdnf/module/modulemd/ModuleMetadata.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/module/modulemd/ModuleMetadata.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -78,7 +78,7 @@ g_autoptr(GPtrArray) failures = NULL; ModulemdModuleIndex * mi = modulemd_module_index_new(); - gboolean success = modulemd_module_index_update_from_string(mi, yaml.c_str(), TRUE, &failures, &error); + gboolean success = modulemd_module_index_update_from_string(mi, yaml.c_str(), FALSE, &failures, &error); if(!success){ ModuleMetadata::reportFailures(failures); } @@ -181,6 +181,8 @@ ModulemdModule * myModule = modulemd_module_index_get_module(resultingModuleIndex, moduleName.c_str()); ModulemdDefaultsV1 * myDefaults = (ModulemdDefaultsV1 *) modulemd_module_get_defaults(myModule); + if (!myDefaults) + return output; char ** list = modulemd_defaults_v1_get_default_profiles_for_stream_as_strv(myDefaults, moduleStream.c_str(), NULL); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/repo/Repo.cpp new/libdnf-0.65.0/libdnf/repo/Repo.cpp --- old/libdnf-0.63.1/libdnf/repo/Repo.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/repo/Repo.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -704,7 +704,11 @@ // set GPG home dir char tmpdir[] = "/tmp/tmpdir.XXXXXX"; - mkdtemp(tmpdir); + if (!mkdtemp(tmpdir)) { + const char * errTxt = strerror(errno); + throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"), + tmpdir, errTxt)); + } Finalizer tmpDirRemover([&tmpdir](){ dnf_remove_recursive(tmpdir, NULL); }); @@ -894,8 +898,14 @@ } struct stat sb; - if (stat(gpgDir.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) - mkdir(gpgDir.c_str(), 0777); + if (stat(gpgDir.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) { + int res = mkdir(gpgDir.c_str(), 0777); + if (res != 0 && errno != EEXIST) { + auto msg = tfm::format(_("Failed to create directory \"%s\": %d - %s"), + gpgDir, errno, strerror(errno)); + throw RepoError(msg); + } + } gpgme_ctx_t ctx; gpgme_new(&ctx); @@ -1147,7 +1157,11 @@ { auto logger(Log::getLogger()); char tmpdir[] = "/tmp/tmpdir.XXXXXX"; - mkdtemp(tmpdir); + if (!mkdtemp(tmpdir)) { + const char * errTxt = strerror(errno); + throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"), + tmpdir, errTxt)); + } Finalizer tmpDirRemover([&tmpdir](){ dnf_remove_recursive(tmpdir, NULL); }); @@ -1217,7 +1231,11 @@ auto logger(Log::getLogger()); LrYumRepo *yum_repo; char tmpdir[] = "/tmp/tmpdir.XXXXXX"; - mkdtemp(tmpdir); + if (!mkdtemp(tmpdir)) { + const char * errTxt = strerror(errno); + throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"), + tmpdir, errTxt)); + } Finalizer tmpDirRemover([&tmpdir](){ dnf_remove_recursive(tmpdir, NULL); }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/repo/solvable/DependencyContainer.cpp new/libdnf-0.65.0/libdnf/repo/solvable/DependencyContainer.cpp --- old/libdnf-0.63.1/libdnf/repo/solvable/DependencyContainer.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/repo/solvable/DependencyContainer.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -32,9 +32,15 @@ DependencyContainer::DependencyContainer(const DependencyContainer &src) : sack(src.sack) { - queue_init_clone(&this->queue, &queue); + queue_init_clone(&queue, &src.queue); } +DependencyContainer::DependencyContainer(DependencyContainer &&src) + : sack(src.sack) +{ + queue_init(&queue); + std::swap(queue, src.queue); +} DependencyContainer::DependencyContainer(DnfSack *sack) : sack(sack) @@ -57,10 +63,22 @@ queue_free(&queue); } +DependencyContainer &DependencyContainer::operator=(const DependencyContainer &src) +{ + if (this != &src) { + sack = src.sack; + queue_free(&queue); + queue_init_clone(&queue, &src.queue); + } + return *this; +} + DependencyContainer &DependencyContainer::operator=(DependencyContainer &&src) noexcept { - sack = src.sack; - queue_init_clone(&queue, &src.queue); + if (this != &src) { + sack = src.sack; + std::swap(queue, src.queue); + } return *this; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/repo/solvable/DependencyContainer.hpp new/libdnf-0.65.0/libdnf/repo/solvable/DependencyContainer.hpp --- old/libdnf-0.63.1/libdnf/repo/solvable/DependencyContainer.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/repo/solvable/DependencyContainer.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -34,11 +34,13 @@ { public: DependencyContainer(const DependencyContainer &src); + DependencyContainer(DependencyContainer &&src); explicit DependencyContainer(DnfSack *sack); DependencyContainer(DnfSack *sack, const Queue &queue); DependencyContainer(DnfSack *sack, Queue &&queue); ~DependencyContainer(); + DependencyContainer &operator=(const DependencyContainer &src); DependencyContainer &operator=(DependencyContainer &&src) noexcept; bool operator==(const DependencyContainer &r) const; bool operator!=(const DependencyContainer &r) const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/sack/query.hpp new/libdnf-0.65.0/libdnf/sack/query.hpp --- old/libdnf-0.63.1/libdnf/sack/query.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/sack/query.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -26,6 +26,7 @@ #include "../hy-types.h" #include "../hy-query.h" #include "../hy-subject.h" +#include "../nevra.hpp" #include "../repo/solvable/Dependency.hpp" #include "../repo/solvable/DependencyContainer.hpp" #include "../transaction/Swdb.hpp" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/utils/crypto/sha1.cpp new/libdnf-0.65.0/libdnf/utils/crypto/sha1.cpp --- old/libdnf-0.63.1/libdnf/utils/crypto/sha1.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/utils/crypto/sha1.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -8,14 +8,15 @@ SHA1Hash::SHA1Hash() { - SHA1_Init(&ctx); + md_ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(md_ctx, EVP_sha1(), NULL); } void SHA1Hash::update(const char * data) { - SHA1_Update(&ctx, (unsigned char *)data, strlen(data)); + EVP_DigestUpdate(md_ctx, data, strlen(data)); } @@ -23,12 +24,13 @@ SHA1Hash::hexdigest() { unsigned char md[digestLength]; - SHA1_Final(md, &ctx); + EVP_DigestFinal_ex(md_ctx, md, NULL); std::stringstream ss; for(int i=0; i<digestLength; i++) { ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(md[i]); } + EVP_MD_CTX_free(md_ctx); return ss.str(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/utils/crypto/sha1.hpp new/libdnf-0.65.0/libdnf/utils/crypto/sha1.hpp --- old/libdnf-0.63.1/libdnf/utils/crypto/sha1.hpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/utils/crypto/sha1.hpp 2021-10-21 08:19:17.000000000 +0200 @@ -1,5 +1,6 @@ #include <string> #include <openssl/sha.h> +#include <openssl/evp.h> /* @@ -20,5 +21,5 @@ static constexpr int digestLength = SHA_DIGEST_LENGTH; private: - SHA_CTX ctx; + EVP_MD_CTX *md_ctx; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/utils/filesystem.cpp new/libdnf-0.65.0/libdnf/utils/filesystem.cpp --- old/libdnf-0.63.1/libdnf/utils/filesystem.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/utils/filesystem.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -24,6 +24,8 @@ #include <cerrno> #include <cstring> +#include "bgettext/bgettext-lib.h" +#include "tinyformat/tinyformat.hpp" #include "filesystem.hpp" #include "../error.hpp" @@ -72,7 +74,12 @@ previous = position; // create directory if necessary if (!pathExists(directory.c_str())) { - mkdir(directory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + int res = mkdir(directory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (res != 0 && errno != EEXIST) { + auto msg = tfm::format(_("Failed to create directory \"%s\": %d - %s"), + directory, errno, strerror(errno)); + throw Error(msg); + } } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/utils/os-release.cpp new/libdnf-0.65.0/libdnf/utils/os-release.cpp --- old/libdnf-0.63.1/libdnf/utils/os-release.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/utils/os-release.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -80,12 +80,10 @@ static void initLibRpm() { - static bool libRpmInitiated{false}; - if (libRpmInitiated) return; - if (rpmReadConfigFiles(NULL, NULL) != 0) { - throw std::runtime_error("failed to read rpm config files\n"); - } - libRpmInitiated = true; + // call dnf_context_globals_init to ensure this only happens once + g_autoptr(GError) local_error = NULL; + if (!dnf_context_globals_init(&local_error)) + throw std::runtime_error(local_error->message); } static std::string getBaseArch() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf/utils/utils.cpp new/libdnf-0.65.0/libdnf/utils/utils.cpp --- old/libdnf-0.63.1/libdnf/utils/utils.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf/utils/utils.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -301,7 +301,7 @@ fclose(inFile); } -void checksum(const char * type, const char * inPath, const char * checksum_valid, bool * valid_out, gchar ** calculated_out) +static void checksum(const char * type, const char * inPath, const char * checksum_valid, bool * valid_out, gchar ** calculated_out) { GError * errP{nullptr}; gboolean valid; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/libdnf.spec new/libdnf-0.65.0/libdnf.spec --- old/libdnf-0.63.1/libdnf.spec 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/libdnf.spec 2021-10-21 08:19:17.000000000 +0200 @@ -1,11 +1,11 @@ -%global libsolv_version 0.7.17 -%global libmodulemd_version 2.11.2-2 +%global libsolv_version 0.7.20 +%global libmodulemd_version 2.13.0 %global librepo_version 1.13.1 %global dnf_conflict 4.3.0 %global swig_version 3.0.12 %global libdnf_major_version 0 -%global libdnf_minor_version 63 -%global libdnf_micro_version 1 +%global libdnf_minor_version 65 +%global libdnf_micro_version 0 %define __cmake_in_source_build 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/po/CMakeLists.txt new/libdnf-0.65.0/po/CMakeLists.txt --- old/libdnf-0.63.1/po/CMakeLists.txt 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/po/CMakeLists.txt 2021-10-21 08:19:17.000000000 +0200 @@ -38,6 +38,14 @@ ) endif() +add_custom_target(gettext-pot + COMMENT "Generating fresh dnf.pot file from sources" + + COMMAND find . -iname '*.[ch]' -o -iname '*.[ch]pp' | + xargs xgettext -F --from-code=UTF-8 --keyword=_ --keyword=M_ --keyword=P_:1,2 --keyword=MP_:1,2 --keyword=C_:1c,2 --keyword=MC_:1c,2 --keyword=CP_:1c,2,3 --keyword=MCP_:1c,2,3 -c --output=${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pot + + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) IF (GETTEXT_FOUND) # this process unfortunately reformats .po files so copy them diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/python/hawkey/goal-py.cpp new/libdnf-0.65.0/python/hawkey/goal-py.cpp --- old/libdnf-0.63.1/python/hawkey/goal-py.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/python/hawkey/goal-py.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -376,6 +376,33 @@ } CATCH_TO_PYTHON static PyObject * +add_exclude_from_weak(_GoalObject *self, PyObject *seq) try +{ + HyGoal goal = self->goal; + auto pset = pyseq_to_packageset(seq, hy_goal_get_sack(goal)); + if (!pset) + return NULL; + goal->add_exclude_from_weak(*(pset.get())); + Py_RETURN_NONE; +} CATCH_TO_PYTHON + +static PyObject * +reset_exclude_from_weak(_GoalObject *self, PyObject *unused) try +{ + HyGoal goal = self->goal; + goal->reset_exclude_from_weak(); + Py_RETURN_NONE; +} CATCH_TO_PYTHON + +static PyObject * +exclude_from_weak_autodetect(_GoalObject *self, PyObject *unused) try +{ + HyGoal goal = self->goal; + goal->exclude_from_weak_autodetect(); + Py_RETURN_NONE; +} CATCH_TO_PYTHON + +static PyObject * run(_GoalObject *self, PyObject *args, PyObject *kwds) try { int flags = 0; @@ -597,6 +624,9 @@ NULL}, {"add_protected", (PyCFunction)add_protected, METH_O, NULL}, + {"add_exclude_from_weak", (PyCFunction)add_exclude_from_weak, METH_O, NULL}, + {"reset_exclude_from_weak", (PyCFunction)reset_exclude_from_weak, METH_NOARGS, NULL}, + {"exclude_from_weak_autodetect", (PyCFunction)exclude_from_weak_autodetect, METH_NOARGS, NULL}, {"distupgrade_all", (PyCFunction)distupgrade_all, METH_NOARGS, NULL}, {"distupgrade", (PyCFunction)distupgrade, METH_VARARGS | METH_KEYWORDS, NULL}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/python/hawkey/reldep-py.cpp new/libdnf-0.65.0/python/hawkey/reldep-py.cpp --- old/libdnf-0.63.1/python/hawkey/reldep-py.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/python/hawkey/reldep-py.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -220,6 +220,26 @@ return result; } CATCH_TO_PYTHON +static PyObject * +get_str(_ReldepObject *self, void *closure) try +{ + const char *(*func)(DnfReldep*); + const char *cstr; + + func = (const char *(*)(DnfReldep*))closure; + cstr = func(self->reldep); + if (cstr == NULL) + Py_RETURN_NONE; + return PyUnicode_FromString(cstr); +} CATCH_TO_PYTHON + +static PyGetSetDef reldep_getsetters[] = { + {(char*)"name", (getter)get_str, NULL, NULL, (void *)dnf_reldep_get_name}, + {(char*)"relation", (getter)get_str, NULL, NULL, (void *)dnf_reldep_get_relation}, + {(char*)"version", (getter)get_str, NULL, NULL, (void *)dnf_reldep_get_version}, + {NULL} /* sentinel */ +}; + PyTypeObject reldep_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_hawkey.Reldep", /*tp_name*/ @@ -250,7 +270,7 @@ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + reldep_getsetters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/tests/hawkey/test_iutil.cpp new/libdnf-0.65.0/tests/hawkey/test_iutil.cpp --- old/libdnf-0.63.1/tests/hawkey/test_iutil.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/tests/hawkey/test_iutil.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -79,11 +79,13 @@ /* the taken checksum are not zeros anymore */ fail_if(checksum_cmp(cs1, cs2) == 0); fail_if(checksum_cmp(cs1_sum, cs2_sum) == 0); + fp = NULL; /* append something */ fail_if((fp = fopen(new_file, "a")) == NULL); fail_unless(fwrite("X", 1, 1, fp) == 1); fclose(fp); + fp = NULL; /* take the second checksums */ fail_if((fp = fopen(new_file, "r")) == NULL); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/tests/libdnf/module/ContextTest.cpp new/libdnf-0.65.0/tests/libdnf/module/ContextTest.cpp --- old/libdnf-0.63.1/tests/libdnf/module/ContextTest.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/tests/libdnf/module/ContextTest.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -146,13 +146,6 @@ g_assert(strstr(error->message, "Unable to resolve argument 'httpd:nonexistent'")); g_clear_pointer(&error, g_error_free); - // try to install without default profile - module_specs[0] = "httpd"; - g_assert(!dnf_context_module_install(context, module_specs, &error)); - g_assert(error); - g_assert(strstr(error->message, "No default profile found")); - g_clear_pointer(&error, g_error_free); - // try to install non-existent profile module_specs[0] = "httpd:2.4/nonexistent"; g_assert(!dnf_context_module_install(context, module_specs, &error)); @@ -160,7 +153,22 @@ g_assert(strstr(error->message, "No profile found matching 'nonexistent'")); g_clear_pointer(&error, g_error_free); - module_specs[0] = "httpd:2.4/default"; + // disable all modules + g_assert(dnf_context_module_disable_all(context, &error)); + g_assert_no_error(error); + + // installing a modular package should fail + g_assert(!dnf_context_install(context, "httpd-2.4.25-8.x86_64", &error)); + g_assert(error); + g_assert(strstr(error->message, "No package matches 'httpd-2.4.25-8.x86_64'")); + g_clear_pointer(&error, g_error_free); + + // reset all modules + g_assert(dnf_context_reset_all_modules(context, sack, &error)); + g_assert_no_error(error); + + // enable and install default profile from modulemd-defaults + module_specs[0] = "httpd:2.4"; g_assert(dnf_context_module_install(context, module_specs, &error)); g_assert_no_error(error); HyGoal goal = dnf_context_get_goal(context); @@ -170,6 +178,13 @@ g_assert(pkgs); g_assert(pkglist_has_nevra(pkgs, "httpd-2.4.25-8.x86_64")); g_assert(pkglist_has_nevra(pkgs, "libnghttp2-1.21.1-1.x86_64")); + + // Verify we can install the default stream from modulemd-defaults. + // This would fail with EnableMultipleStreamsException if it didn't match + // the 2.4 stream since we enabled the 2.4 stream just above. + module_specs[0] = "httpd"; + g_assert(dnf_context_module_install(context, module_specs, &error)); + g_assert_no_error(error); } void ContextTest::sackHas(DnfSack * sack, libdnf::ModulePackage * pkg) const diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdnf-0.63.1/tests/libdnf/module/ModulePackageContainerTest.cpp new/libdnf-0.65.0/tests/libdnf/module/ModulePackageContainerTest.cpp --- old/libdnf-0.63.1/tests/libdnf/module/ModulePackageContainerTest.cpp 2021-06-14 15:09:48.000000000 +0200 +++ new/libdnf-0.65.0/tests/libdnf/module/ModulePackageContainerTest.cpp 2021-10-21 08:19:17.000000000 +0200 @@ -17,7 +17,7 @@ char *retptr = mkdtemp(tmpdir); CPPUNIT_ASSERT(retptr); char * etc_target = g_strjoin(NULL, tmpdir, "/etc", NULL); - dnf_copy_recursive(TESTDATADIR "/modules/etc", etc_target, &error); + CPPUNIT_ASSERT(dnf_copy_recursive(TESTDATADIR "/modules/etc", etc_target, &error)); g_assert_no_error(error); g_free(etc_target);