diff --git a/.gitignore b/.gitignore index d101600..5aef53c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/libdnf-0.39.1.tar.gz +SOURCES/libdnf-0.48.0.tar.gz diff --git a/.libdnf.metadata b/.libdnf.metadata index 4bef024..b596b13 100644 --- a/.libdnf.metadata +++ b/.libdnf.metadata @@ -1 +1 @@ -a74a37b029439749298705ff3c1ccfbd0f0fd821 SOURCES/libdnf-0.39.1.tar.gz +452c2195741b627bd97b0be11cd4a4dc4118e330 SOURCES/libdnf-0.48.0.tar.gz diff --git a/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch b/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch new file mode 100644 index 0000000..079524d --- /dev/null +++ b/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch @@ -0,0 +1,244 @@ +From a96d701f7f55ff475e11ac9cda63b81c31c54e7a Mon Sep 17 00:00:00 2001 +From: Daniel Mach +Date: Wed, 6 May 2020 08:34:46 +0200 +Subject: [PATCH] history: Fix dnf history rollback when a package was removed + (RhBug:1683134) + +--- + libdnf/transaction/MergedTransaction.cpp | 25 +++- + .../transaction/MergedTransactionTest.cpp | 120 ++++++++++++++++-- + .../transaction/MergedTransactionTest.hpp | 6 +- + 3 files changed, 137 insertions(+), 14 deletions(-) + +diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp +index a7c06ffa9..a8d878cb5 100644 +--- a/libdnf/transaction/MergedTransaction.cpp ++++ b/libdnf/transaction/MergedTransaction.cpp +@@ -19,6 +19,7 @@ + */ + + #include "MergedTransaction.hpp" ++#include + #include + + namespace libdnf { +@@ -171,6 +172,21 @@ MergedTransaction::getConsoleOutput() + return output; + } + ++ ++static bool transaction_item_sort_function(const std::shared_ptr lhs, const std::shared_ptr rhs) { ++ if (lhs->isForwardAction() && rhs->isForwardAction()) { ++ return false; ++ } ++ if (lhs->isBackwardAction() && rhs->isBackwardAction()) { ++ return false; ++ } ++ if (lhs->isBackwardAction()) { ++ return true; ++ } ++ return false; ++} ++ ++ + /** + * Get list of transaction items involved in the merged transaction + * Actions are merged using following rules: +@@ -203,6 +219,9 @@ MergedTransaction::getItems() + // iterate over transaction + for (auto t : transactions) { + auto transItems = t->getItems(); ++ // sort transaction items by their action type - forward/backward ++ // this fixes behavior of the merging algorithm in several edge cases ++ std::sort(transItems.begin(), transItems.end(), transaction_item_sort_function); + // iterate over transaction items + for (auto transItem : transItems) { + // get item and its type +@@ -383,10 +402,6 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT + auto firstState = previousItemPair.first->getAction(); + auto newState = mTransItem->getAction(); + +- if (firstState == TransactionItemAction::INSTALL && mTransItem->isBackwardAction()) { +- return; +- } +- + switch (firstState) { + case TransactionItemAction::REMOVE: + case TransactionItemAction::OBSOLETED: +@@ -399,6 +414,8 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT + // Install -> Remove = (nothing) + itemPairMap.erase(name); + break; ++ } else if (mTransItem->isBackwardAction()) { ++ break; + } + // altered -> transfer install to the altered package + mTransItem->setAction(TransactionItemAction::INSTALL); +diff --git a/tests/libdnf/transaction/MergedTransactionTest.cpp b/tests/libdnf/transaction/MergedTransactionTest.cpp +index 90ad182cf..52507700b 100644 +--- a/tests/libdnf/transaction/MergedTransactionTest.cpp ++++ b/tests/libdnf/transaction/MergedTransactionTest.cpp +@@ -700,7 +700,7 @@ MergedTransactionTest::test_downgrade() + } + + void +-MergedTransactionTest::test_install_downgrade() ++MergedTransactionTest::test_install_downgrade_upgrade_remove() + { + auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn); + trans1->addItem( +@@ -724,19 +724,123 @@ MergedTransactionTest::test_install_downgrade() + TransactionItemReason::USER + ); + ++ auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn); ++ trans3->addItem( ++ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"), ++ "repo2", ++ TransactionItemAction::UPGRADED, ++ TransactionItemReason::USER ++ ); ++ trans3->addItem( ++ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"), ++ "repo1", ++ TransactionItemAction::UPGRADE, ++ TransactionItemReason::USER ++ ); ++ ++ auto trans4 = std::make_shared< libdnf::swdb_private::Transaction >(conn); ++ trans4->addItem( ++ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"), ++ "repo1", ++ TransactionItemAction::REMOVE, ++ TransactionItemReason::USER ++ ); ++ + MergedTransaction merged(trans1); ++ ++ // test merging trans1, trans2 + merged.merge(trans2); ++ auto items2 = merged.getItems(); ++ CPPUNIT_ASSERT_EQUAL(1, (int)items2.size()); ++ auto item2 = items2.at(0); ++ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item2->getItem()->toStr()); ++ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item2->getRepoid()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item2->getAction()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason()); + +- auto items = merged.getItems(); +- CPPUNIT_ASSERT_EQUAL(1, (int)items.size()); ++ // test merging trans1, trans2, trans3 ++ merged.merge(trans3); ++ auto items3 = merged.getItems(); ++ CPPUNIT_ASSERT_EQUAL(1, (int)items3.size()); ++ auto item3 = items3.at(0); ++ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr()); ++ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item3->getAction()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason()); + +- auto item = items.at(0); +- CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item->getItem()->toStr()); +- CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item->getRepoid()); +- CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item->getAction()); +- CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason()); ++ // test merging trans1, trans2, trans3, trans4 ++ merged.merge(trans4); ++ auto items4 = merged.getItems(); ++ CPPUNIT_ASSERT_EQUAL(0, (int)items4.size()); ++ // trans4 removes the package, empty output is expected + } + ++ ++void ++MergedTransactionTest::test_downgrade_upgrade_remove() ++{ ++ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn); ++ trans1->addItem( ++ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"), ++ "repo2", ++ TransactionItemAction::DOWNGRADE, ++ TransactionItemReason::USER ++ ); ++ trans1->addItem( ++ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"), ++ "repo1", ++ TransactionItemAction::DOWNGRADED, ++ TransactionItemReason::USER ++ ); ++ ++ // items are in reversed order than in test_install_downgrade_upgrade_remove() ++ // fixing this required ordering transaction items by forward/backward action ++ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn); ++ trans2->addItem( ++ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"), ++ "repo1", ++ TransactionItemAction::UPGRADE, ++ TransactionItemReason::USER ++ ); ++ trans2->addItem( ++ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"), ++ "repo2", ++ TransactionItemAction::UPGRADED, ++ TransactionItemReason::USER ++ ); ++ ++ auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn); ++ trans3->addItem( ++ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"), ++ "repo1", ++ TransactionItemAction::REMOVE, ++ TransactionItemReason::USER ++ ); ++ ++ MergedTransaction merged(trans1); ++ ++ // test merging trans1, trans2 ++ merged.merge(trans2); ++ auto items2 = merged.getItems(); ++ CPPUNIT_ASSERT_EQUAL(1, (int)items2.size()); ++ auto item2 = items2.at(0); ++ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item2->getItem()->toStr()); ++ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item2->getRepoid()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item2->getAction()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason()); ++ ++ // test merging trans1, trans2, trans3 ++ merged.merge(trans3); ++ auto items3 = merged.getItems(); ++ CPPUNIT_ASSERT_EQUAL(1, (int)items3.size()); ++ auto item3 = items3.at(0); ++ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr()); ++ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REMOVE, item3->getAction()); ++ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason()); ++} ++ ++ + void + MergedTransactionTest::test_multilib_identity() + { +diff --git a/tests/libdnf/transaction/MergedTransactionTest.hpp b/tests/libdnf/transaction/MergedTransactionTest.hpp +index 9f1ed660a..77585e865 100644 +--- a/tests/libdnf/transaction/MergedTransactionTest.hpp ++++ b/tests/libdnf/transaction/MergedTransactionTest.hpp +@@ -26,7 +26,8 @@ class MergedTransactionTest : public CppUnit::TestCase { + CPPUNIT_TEST(test_add_obsoleted_obsoleted); + + CPPUNIT_TEST(test_downgrade); +- CPPUNIT_TEST(test_install_downgrade); ++ CPPUNIT_TEST(test_install_downgrade_upgrade_remove); ++ CPPUNIT_TEST(test_downgrade_upgrade_remove); + + CPPUNIT_TEST(test_multilib_identity); + +@@ -56,7 +57,8 @@ class MergedTransactionTest : public CppUnit::TestCase { + // END: tests ported from DNF unit tests + + void test_downgrade(); +- void test_install_downgrade(); ++ void test_install_downgrade_upgrade_remove(); ++ void test_downgrade_upgrade_remove(); + + void test_multilib_identity(); + private: diff --git a/SOURCES/0001-user-agent-Drop-the-whitelist.patch b/SOURCES/0001-user-agent-Drop-the-whitelist.patch deleted file mode 100644 index f897cb6..0000000 --- a/SOURCES/0001-user-agent-Drop-the-whitelist.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 1dffef87fc2f07763f64eeabc1ea891e68d23541 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Tue, 26 Nov 2019 13:05:49 +0100 -Subject: [PATCH] [user-agent] Drop the whitelist - - - Stop checking os-release(5) data against a hard-coded whitelist and - just use them as they are, to avoid a maintenance burden in the - future (see [1] for details) - - - Clean up the getUserAgent() function a bit - -Note that, by removing the whitelist, there's a risk of leaking a -"unique" value from the os-release file now, but a rather small one. - -[1] https://github.com/rpm-software-management/libdnf/pull/851 ---- - libdnf/utils/os-release.cpp | 58 ++++++++++++++++++++-------------------------------------- - libdnf/utils/os-release.hpp | 7 ++----- - 2 files changed, 22 insertions(+), 43 deletions(-) - -diff --git a/libdnf/utils/os-release.cpp b/libdnf/utils/os-release.cpp -index 57be110..1d8a95b 100644 ---- a/libdnf/utils/os-release.cpp -+++ b/libdnf/utils/os-release.cpp -@@ -36,17 +36,8 @@ - namespace libdnf { - - // sorted by precedence (see os-release(5) for details) --static const std::array paths = {"/etc/os-release", "/usr/lib/os-release"}; --// whitelists used for sanity-checking the os-release data when constructing a --// User-Agent string (to avoid reporting rare systems or platforms that could --// be tracked) --static const std::map> distros = { -- // taken from the {fedora,generic}-release.spec files -- { "Fedora", { "cinnamon", "cloud", "container", "coreos", "generic", "iot", -- "kde", "matecompiz", "server", "silverblue", "snappy", "soas", -- "workstation", "xfce" } }, --}; --std::array canons = { "Linux" }; -+static const std::array -+paths = {"/etc/os-release", "/usr/lib/os-release"}; - - std::map getOsReleaseData() - { -@@ -118,47 +109,38 @@ std::string getUserAgent(const std::map & osReleaseDat - { - std::ostringstream oss; - auto logger(Log::getLogger()); -- std::string msg = "os-release: falling back to basic User-Agent"; - -- // start with the basic libdnf string - oss << USER_AGENT; -+ std::string fallback = oss.str(); - -- // mandatory OS data (bail out if missing or unknown) - if (!osReleaseData.count("NAME") || !osReleaseData.count("VERSION_ID")) { -- logger->debug(tfm::format("%s: missing NAME or VERSION_ID", msg)); -- return oss.str(); -+ logger->debug(tfm::format( -+ "User-Agent: falling back to '%s': missing NAME or VERSION_ID", -+ fallback -+ )); -+ return fallback; - } - std::string name = osReleaseData.at("NAME"); - std::string version = osReleaseData.at("VERSION_ID"); -- if (!distros.count(name)) { -- logger->debug(tfm::format("%s: distro %s not whitelisted", msg, name)); -- return oss.str(); -- } -+ std::string variant = "generic"; -+ if (osReleaseData.count("VARIANT_ID")) -+ variant = osReleaseData.at("VARIANT_ID"); - -- // mandatory platform data from RPM (bail out if missing or unknown) - std::string canon = getCanonOs(); - std::string arch = getBaseArch(); -- if (canon.empty() || arch.empty() -- || std::find(canons.begin(), canons.end(), canon) == canons.end()) { -- logger->debug(tfm::format("%s: could not detect canonical OS or basearch", msg)); -- return oss.str(); -- } -- -- // optional OS data (use fallback values if missing or unknown) -- std::string variant = "generic"; -- auto list = distros.at(name); -- if (osReleaseData.count("VARIANT_ID")) { -- std::string value = osReleaseData.at("VARIANT_ID"); -- if (std::find(list.begin(), list.end(), value) != list.end()) -- variant = value; -+ if (canon.empty() || arch.empty()) { -+ logger->debug(tfm::format( -+ "User-Agent: falling back to '%s': could not detect OS or basearch", -+ fallback -+ )); -+ return fallback; - } - -- // good to go! -- oss << " (" << name << " " << version << "; " << variant << "; " -- << canon << "." << arch << ")"; -+ oss << " (" << name << " " << version << "; " << variant << "; " << canon -+ << "." << arch << ")"; - - std::string result = oss.str(); -- logger->debug(tfm::format("os-release: User-Agent constructed: %s", result)); -+ logger->debug(tfm::format("User-Agent: constructed: '%s'", result)); - return result; - } - -diff --git a/libdnf/utils/os-release.hpp b/libdnf/utils/os-release.hpp -index ef4d14f..e7b24a7 100644 ---- a/libdnf/utils/os-release.hpp -+++ b/libdnf/utils/os-release.hpp -@@ -50,11 +50,8 @@ getOsReleaseData(); - * libdnf (NAME VERSION_ID; VARIANT_ID; OS.BASEARCH) - * - * where NAME, VERSION_ID and VARIANT_ID are OS identifiers read from the -- * passed os-release data, and OS and BASEARCH (if found) are the canonical OS -- * name and base architecture, respectively, detected using RPM. -- * -- * Note that the OS part (enclosed in parentheses) will only be included for -- * whitelisted values. -+ * passed os-release data, and OS and BASEARCH are the canonical OS name and -+ * base architecture, respectively, detected using RPM. - * - * @param osReleaseData a map containing os-release data (will be loaded from - * disk if not specified) --- -libgit2 0.28.2 - diff --git a/SPECS/libdnf.spec b/SPECS/libdnf.spec index 2ccbcb6..65f8aac 100644 --- a/SPECS/libdnf.spec +++ b/SPECS/libdnf.spec @@ -1,8 +1,11 @@ %global libsolv_version 0.7.7 -%global libmodulemd_version 1.6.1 -%global librepo_version 1.11.0 -%global dnf_conflict 4.2.13 +%global libmodulemd_version 2.5.0 +%global librepo_version 1.12.0 +%global dnf_conflict 4.2.23 %global swig_version 3.0.12 +%global libdnf_major_version 0 +%global libdnf_minor_version 48 +%global libdnf_micro_version 0 # set sphinx package name according to distro %global requires_python2_sphinx python2-sphinx @@ -43,18 +46,20 @@ %bcond_without zchunk %endif +%bcond_with sanitizers + %global _cmake_opts \\\ -DENABLE_RHSM_SUPPORT=%{?with_rhsm:ON}%{!?with_rhsm:OFF} \\\ %{nil} Name: libdnf -Version: 0.39.1 +Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version} Release: 2%{?dist} Summary: Library providing simplified C and Python API to libsolv License: LGPLv2+ URL: https://github.com/rpm-software-management/libdnf Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz -Patch1: 0001-user-agent-Drop-the-whitelist.patch +Patch1: 0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch BuildRequires: cmake BuildRequires: gcc @@ -78,11 +83,17 @@ BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(json-c) BuildRequires: pkgconfig(cppunit) BuildRequires: pkgconfig(libcrypto) -BuildRequires: pkgconfig(modulemd) >= %{libmodulemd_version} +BuildRequires: pkgconfig(modulemd-2.0) >= %{libmodulemd_version} BuildRequires: pkgconfig(smartcols) BuildRequires: gettext BuildRequires: gpgme-devel +%if %{with sanitizers} +BuildRequires: libasan-static +BuildRequires: liblsan-static +BuildRequires: libubsan-static +%endif + Requires: libmodulemd%{?_isa} >= %{libmodulemd_version} Requires: libsolv%{?_isa} >= %{libsolv_version} Requires: librepo%{?_isa} >= %{librepo_version} @@ -125,7 +136,8 @@ BuildRequires: swig >= %{swig_version} %description -n python2-%{name} Python 2 bindings for the libdnf library. -%endif # with python2 +%endif +# endif with python2 %if %{with python3} %package -n python3-%{name} @@ -159,7 +171,8 @@ Conflicts: python-dnf < %{dnf_conflict} %description -n python2-hawkey Python 2 bindings for the hawkey library. -%endif # with python2 +%endif +# endif with python2 %if %{with python3} %package -n python3-hawkey @@ -183,7 +196,7 @@ Python 3 bindings for the hawkey library. %autosetup -p1 %if %{with python2} mkdir build-py2 -%endif # with python2 +%endif %if %{with python3} mkdir build-py3 %endif @@ -196,10 +209,12 @@ pushd build-py2 %define _cmake_builddir build-py2 %define __builddir build-py2 %endif - %cmake -DPYTHON_DESIRED:FILEPATH=%{__python2} -DWITH_MAN=OFF ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} + %cmake -DPYTHON_DESIRED:FILEPATH=%{__python2} -DWITH_MAN=OFF ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version} \ + -DWITH_SANITIZERS=%{?with_sanitizers:ON}%{!?with_sanitizers:OFF} %make_build popd -%endif # with python2 +%endif +# endif with python2 %if %{with python3} pushd build-py3 @@ -208,7 +223,8 @@ pushd build-py3 %define _cmake_builddir build-py3 %define __builddir build-py3 %endif - %cmake -DPYTHON_DESIRED:FILEPATH=%{__python3} -DWITH_GIR=0 -DWITH_MAN=0 -Dgtkdoc=0 ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} + %cmake -DPYTHON_DESIRED:FILEPATH=%{__python3} -DWITH_GIR=0 -DWITH_MAN=0 -Dgtkdoc=0 ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version} \ + -DWITH_SANITIZERS=%{?with_sanitizers:ON}%{!?with_sanitizers:OFF} %make_build popd %endif @@ -218,7 +234,7 @@ popd pushd build-py2 make ARGS="-V" test popd -%endif # with python2 +%endif %if %{with python3} # If we didn't run the general tests yet, do it now. %if %{without python2} @@ -240,7 +256,7 @@ popd pushd build-py2 %make_install popd -%endif # with python2 +%endif %if %{with python3} pushd build-py3 %make_install @@ -273,7 +289,7 @@ popd %if %{with python2} %files -n python2-%{name} %{python2_sitearch}/%{name}/ -%endif # with python2 +%endif %if %{with python3} %files -n python3-%{name} @@ -283,7 +299,7 @@ popd %if %{with python2} %files -n python2-hawkey %{python2_sitearch}/hawkey/ -%endif # with python2 +%endif %if %{with python3} %files -n python3-hawkey @@ -291,6 +307,80 @@ popd %endif %changelog +* Wed Jun 10 2020 Ales Matej - 0.48.0-2 +- [history] Fix dnf history rollback when a package was removed (RhBug:1683134) + +* Wed Jun 03 2020 Nicola Sella - 0.48.0-1 +- Update to 0.48.0 +- swdb: Catch only SQLite3 exceptions and simplify the messages +- MergedTransaction list multiple comments (RhBug:1773679) +- Modify CMake to pull *.po files from weblate +- Optimize DependencyContainer creation from an existing queue +- fix a memory leak in dnf_package_get_requires() +- Fix memory leaks on g_build_filename() +- Fix memory leak in dnf_context_setup() +- Add `hy_goal_favor` and `hy_goal_disfavor` +- Define a cleanup function for `DnfPackageSet` +- dnf-repo: fix dnf_repo_get_public_keys double-free +- Do not cache RPMDB +- Use single-quotes around string literals used in SQL statements +- SQLite3: Do not close the database if it wasn't opened (RhBug:1761976) +- Don't create a new history DB connection for in-memory DB +- transaction/Swdb: Use a single logger variable in constructor +- utils: Add a safe version of pathExists() +- swdb: Handle the case when pathExists() fails on e.g. permission +- Repo: prepend "file://" if a local path is used as baseurl +- Move urlEncode() to utils +- utils: Add 'exclude' argument to urlEncode() +- Encode package URL for downloading through librepo (RhBug:1817130) +- Replace std::runtime_error with libdnf::RepoError +- Fixes and error handling improvements of the File class +- [context] Use ConfigRepo for gpgkey and baseurl (RhBug:1807864) +- [context] support "priority" option in .repo config file (RhBug:1797265) + +* Fri Apr 03 2020 Ales Matej - 0.47.0-1 +- Update to 0.47.0 +- Allow excluding packages with "excludepkgs" and globs +- Make parsing of reldeps more strict (RhBug:1788107) +- Add expanding solvable provides for dependency matching (RhBug:1534123) +- DnfRepo: fix module_hotfixes keyfile priority level +- Add custom exceptions to libdnf interface +- Port to libmodulemd-2 API (RhBug:1693683) +- Add prereq_ignoreinst & regular_requires properties for pkg (RhBug:1543449) +- Reset active modules when no module enabled or default (RhBug:1767351) +- Add comment option to transaction (RhBug:1773679) +- Baseurl is not exclusive with mirrorlist/metalink (RhBug:1775184) +- Add new function to reset all modules in C API (dnf_context_reset_all_modules) +- Handle situation when an unprivileged user cannot create history database (RhBug:1634385) +- Add query filter: latest by priority +- Add setter for running kernel protection setting +- Add DNF_NO_PROTECTED flag to allow empty list of protected packages +- Config options: only first empty value clears existing (RhBug:1788154) +- [conf] Set useful default colors when color is enabled +- [context] Use installonly_limit from global config (RhBug:1256108) +- [context] Add API to get/set "install_weak_deps" +- [context] Adds support for includepkgs in repository configuration. +- [context] Adds support for excludepkgs, exclude, includepkgs, and disable_excludes in main configuration. +- [context] Added function dnf_transaction_set_dont_solve_goal +- [context] Added functions dnf_context_get/set_config_file_path +- [context] Respect "plugins" global conf value +- [context] Add API to disable/enable plugins +- [context] Create new repo instead of reusing old one (RhBug:1795004) +- [context] Error when main config file can't be opened (RhBug:1794864) +- [context] Add function function dnf_context_is_set_config_file_path +- [context] Support repositories defined in main configuration file + +* Tue Feb 18 2020 Ales Matej - 0.39.1-5 +- Fix filtering of packages by advisory (RhBug:1770125) + +* Fri Jan 31 2020 Marek Blaha - 0.39.1-4 +- [translations] Update translations from zanata (RhBug:1754965) + +* Mon Jan 13 2020 Ales Matej - 0.39.1-3 +- Add two new query filters: obsoletes_by_priority, upgrades_by_priority (RhBug:1769466) +- [context] Add wildcard support in dnf_context_repo_set_data (RhBug:1781420) +- Remove killGpgAgent function (RhBug:1781601) + * Thu Dec 12 2019 Pavla Kratochvilova - 0.39.1-2 - [user-agent] Stop checking os-release(5) data against a hard-coded whitelist (RhBug:1777255)