diff --git a/.gitignore b/.gitignore
index 5aef53c..ce72cd2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/libdnf-0.48.0.tar.gz
+SOURCES/libdnf-0.55.0.tar.gz
diff --git a/.libdnf.metadata b/.libdnf.metadata
index b596b13..85f3501 100644
--- a/.libdnf.metadata
+++ b/.libdnf.metadata
@@ -1 +1 @@
-452c2195741b627bd97b0be11cd4a4dc4118e330 SOURCES/libdnf-0.48.0.tar.gz
+5d997c2c7113cd50af986ada5ff10a62853f1943 SOURCES/libdnf-0.55.0.tar.gz
diff --git a/SOURCES/0001-Better-msgs-if-basecachedir-or-proxy-password-isn-t-set-RhBug-1888946.patch b/SOURCES/0001-Better-msgs-if-basecachedir-or-proxy-password-isn-t-set-RhBug-1888946.patch
new file mode 100644
index 0000000..7666421
--- /dev/null
+++ b/SOURCES/0001-Better-msgs-if-basecachedir-or-proxy-password-isn-t-set-RhBug-1888946.patch
@@ -0,0 +1,87 @@
+From 2353dfbcb49a16bd37115915517417678fe49b19 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Fri, 13 Nov 2020 09:55:23 +0100
+Subject: [PATCH] Better msgs if "basecachedir" or "proxy_password" isn't set
+ (RhBug:1888946)
+
+Generates more specific error messages:
+- repo '%s': 'basecachedir' is not set
+- repo '%s': 'proxy_username' is set but not 'proxy_password'
+- 'proxy_username' is set but not 'proxy_password'
+instead of generic "GetValue(): Value not set"
+---
+ libdnf/repo/Repo.cpp | 24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/libdnf/repo/Repo.cpp b/libdnf/repo/Repo.cpp
+index d7c137d75..34539e1ee 100644
+--- a/libdnf/repo/Repo.cpp
++++ b/libdnf/repo/Repo.cpp
+@@ -484,8 +484,12 @@ std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitLocal()
+     handleSetOpt(h.get(), LRO_LOCAL, 1L);
+ #ifdef LRO_SUPPORTS_CACHEDIR
+     /* If zchunk is enabled, set librepo cache dir */
+-    if (conf->getMasterConfig().zchunk().getValue())
++    if (conf->getMasterConfig().zchunk().getValue()) {
++        if (conf->basecachedir().empty()) {
++            throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
++        }
+         handleSetOpt(h.get(), LRO_CACHEDIR, conf->basecachedir().getValue().c_str());
++    }
+ #endif
+     return h;
+ }
+@@ -526,6 +530,9 @@ std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitRemote(const char *destdir)
+                 handleSetOpt(h.get(), LRO_METALINKURL, tmp.c_str());
+         }
+         handleSetOpt(h.get(), LRO_FASTESTMIRROR, conf->fastestmirror().getValue() ? 1L : 0L);
++        if (conf->basecachedir().empty()) {
++            throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
++        }
+         auto fastestMirrorCacheDir = conf->basecachedir().getValue();
+         if (fastestMirrorCacheDir.back() != '/')
+             fastestMirrorCacheDir.push_back('/');
+@@ -569,8 +576,12 @@ std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitRemote(const char *destdir)
+ 
+ #ifdef LRO_SUPPORTS_CACHEDIR
+     /* If zchunk is enabled, set librepo cache dir */
+-    if (conf->getMasterConfig().zchunk().getValue())
++    if (conf->getMasterConfig().zchunk().getValue()) {
++        if (conf->basecachedir().empty()) {
++            throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
++        }
+         handleSetOpt(h.get(), LRO_CACHEDIR, conf->basecachedir().getValue().c_str());
++    }
+ #endif
+ 
+     auto minrate = conf->minrate().getValue();
+@@ -610,6 +621,9 @@ std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitRemote(const char *destdir)
+     if (!conf->proxy_username().empty()) {
+         userpwd = conf->proxy_username().getValue();
+         if (!userpwd.empty()) {
++            if (conf->proxy_password().empty()) {
++                throw RepoError(tfm::format(_("repo '%s': 'proxy_username' is set but not 'proxy_password'"), id));
++            }
+             userpwd = formatUserPassString(userpwd, conf->proxy_password().getValue(), true);
+             handleSetOpt(h.get(), LRO_PROXYUSERPWD, userpwd.c_str());
+         }
+@@ -1346,6 +1360,9 @@ std::string Repo::Impl::getHash() const
+ 
+ std::string Repo::Impl::getCachedir() const
+ {
++    if (conf->basecachedir().empty()) {
++        throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
++    }
+     auto repodir(conf->basecachedir().getValue());
+     if (repodir.back() != '/')
+         repodir.push_back('/');
+@@ -1690,6 +1707,9 @@ static LrHandle * newHandle(ConfigMain * conf)
+         if (!conf->proxy_username().empty()) {
+             auto userpwd = conf->proxy_username().getValue();
+             if (!userpwd.empty()) {
++                if (conf->proxy_password().empty()) {
++                    throw RepoError(_("'proxy_username' is set but not 'proxy_password'"));
++                }
+                 userpwd = formatUserPassString(userpwd, conf->proxy_password().getValue(), true);
+                 handleSetOpt(h, LRO_PROXYUSERPWD, userpwd.c_str());
+             }
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
deleted file mode 100644
index 079524d..0000000
--- a/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch
+++ /dev/null
@@ -1,244 +0,0 @@
-From a96d701f7f55ff475e11ac9cda63b81c31c54e7a Mon Sep 17 00:00:00 2001
-From: Daniel Mach <dmach@redhat.com>
-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 <algorithm>
- #include <vector>
- 
- namespace libdnf {
-@@ -171,6 +172,21 @@ MergedTransaction::getConsoleOutput()
-     return output;
- }
- 
-+
-+static bool transaction_item_sort_function(const std::shared_ptr<TransactionItemBase> lhs, const std::shared_ptr<TransactionItemBase> 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/0002-modules-Add-special-handling-for-src-artifacts-RhBug-1809314.patch b/SOURCES/0002-modules-Add-special-handling-for-src-artifacts-RhBug-1809314.patch
new file mode 100644
index 0000000..a16d544
--- /dev/null
+++ b/SOURCES/0002-modules-Add-special-handling-for-src-artifacts-RhBug-1809314.patch
@@ -0,0 +1,73 @@
+From 71db968178e5d8cd4c01ed36fa940c2a95f3e494 Mon Sep 17 00:00:00 2001
+From: Jaroslav Mracek <jmracek@redhat.com>
+Date: Mon, 9 Nov 2020 18:10:37 +0100
+Subject: [PATCH] [modules] Add special handling for src artifacts
+ (RhBug:1809314)
+
+Source packages are special because they cannot be installed and provide
+nothing, therefore they should be handled by a different way than binary
+packages. Source rpm should not trigger a removal of binary packages.
+---
+ libdnf/dnf-sack.cpp | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/libdnf/dnf-sack.cpp b/libdnf/dnf-sack.cpp
+index 9fd2c72d1..d44e1d86d 100644
+--- a/libdnf/dnf-sack.cpp
++++ b/libdnf/dnf-sack.cpp
+@@ -2335,20 +2335,29 @@ setModuleExcludes(DnfSack *sack, const char ** hotfixRepos,
+ {
+     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)) {
+-            names.push_back(nevra.getName());
+-            nameDependencies.addReldep(nevra.getName().c_str());
++            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());
++            }
+         }
+     }
+ 
+     std::vector<const char *> namesCString(names.size() + 1);
++    std::vector<const char *> srcNamesCString(srcNames.size() + 1);
+     std::vector<const char *> excludeNEVRAsCString(excludeNEVRAs.size() + 1);
+     std::vector<const char *> includeNEVRAsCString(includeNEVRAs.size() + 1);
+ 
+     transform(names.begin(), names.end(), namesCString.begin(), std::mem_fn(&std::string::c_str));
++    transform(srcNames.begin(), srcNames.end(), srcNamesCString.begin(), std::mem_fn(&std::string::c_str));
+     transform(excludeNEVRAs.begin(), excludeNEVRAs.end(), excludeNEVRAsCString.begin(),
+               std::mem_fn(&std::string::c_str));
+     transform(includeNEVRAs.begin(), includeNEVRAs.end(), includeNEVRAsCString.begin(),
+@@ -2363,6 +2372,7 @@ setModuleExcludes(DnfSack *sack, const char ** hotfixRepos,
+     libdnf::Query excludeQuery{keepPackages};
+     libdnf::Query excludeProvidesQuery{keepPackages};
+     libdnf::Query excludeNamesQuery(keepPackages);
++    libdnf::Query excludeSrcNamesQuery(keepPackages);
+     includeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, includeNEVRAsCString.data());
+ 
+     excludeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, excludeNEVRAsCString.data());
+@@ -2372,8 +2382,14 @@ setModuleExcludes(DnfSack *sack, const char ** hotfixRepos,
+     excludeProvidesQuery.addFilter(HY_PKG_PROVIDES, &nameDependencies);
+     excludeProvidesQuery.queryDifference(includeQuery);
+ 
+-    // Requred to filtrate out source packages and packages with incompatible architectures
++    // Search for source packages with same names as included source artifacts
++    excludeSrcNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, srcNamesCString.data());
++    const char * srcArchs[] = {"src", "nosrc", nullptr};
++    excludeSrcNamesQuery.addFilter(HY_PKG_ARCH, HY_EQ, srcArchs);
++
++    // Required to filtrate out source packages and packages with incompatible architectures
+     excludeNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, namesCString.data());
++    excludeNamesQuery.queryUnion(excludeSrcNamesQuery);
+     excludeNamesQuery.queryDifference(includeQuery);
+ 
+     dnf_sack_set_module_excludes(sack, excludeQuery.getResultPset());
diff --git a/SOURCES/0003-Avoid-multilib-file-conflict-in-config.h-RhBug-1918818.patch b/SOURCES/0003-Avoid-multilib-file-conflict-in-config.h-RhBug-1918818.patch
new file mode 100644
index 0000000..ae93fb0
--- /dev/null
+++ b/SOURCES/0003-Avoid-multilib-file-conflict-in-config.h-RhBug-1918818.patch
@@ -0,0 +1,101 @@
+From 3f6adc99506f065d0858e4d9d46055be9d070634 Mon Sep 17 00:00:00 2001
+From: Nicola Sella <nsella@redhat.com>
+Date: Fri, 22 Jan 2021 16:07:37 +0100
+Subject: [PATCH] Avoid multilib file conflict in config.h (RhBug:1918818)
+
+=changelog=
+msg: Avoid multilib file conflicts in config.h
+resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1918818
+---
+ .gitignore                             |  2 +-
+ libdnf/CMakeLists.txt                  |  8 ++++++-
+ libdnf/{config.h.in => config-64.h.in} |  6 +++---
+ libdnf/config.h                        | 29 ++++++++++++++++++++++++++
+ 4 files changed, 40 insertions(+), 5 deletions(-)
+ rename libdnf/{config.h.in => config-64.h.in} (87%)
+ create mode 100644 libdnf/config.h
+
+diff --git a/.gitignore b/.gitignore
+index e17a9b9bb..0a63bdae7 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -5,4 +5,4 @@
+ build
+ *.pyc
+ data/tests/modules/yum.repos.d/test.repo
+-libdnf/config.h
++libdnf/config-64.h
+diff --git a/libdnf/CMakeLists.txt b/libdnf/CMakeLists.txt
+index e82aac11e..25f33d7b0 100644
+--- a/libdnf/CMakeLists.txt
++++ b/libdnf/CMakeLists.txt
+@@ -35,7 +35,13 @@ set(LIBDNF_SRCS
+ include_directories(transaction)
+ add_subdirectory("transaction")
+ 
+-configure_file("config.h.in" ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
++if(CMAKE_SIZEOF_VOID_P EQUAL 8)
++    set(MULTILIB_ARCH "64")
++    configure_file("config-64.h.in" ${CMAKE_CURRENT_SOURCE_DIR}/config-64.h)
++elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
++    set(MULTILIB_ARCH "32")
++    configure_file("config-64.h.in" ${CMAKE_CURRENT_SOURCE_DIR}/config-32.h)
++endif()
+ configure_file("dnf-version.h.in"  ${CMAKE_CURRENT_SOURCE_DIR}/dnf-version.h)
+ configure_file("libdnf.pc.in" ${CMAKE_CURRENT_BINARY_DIR}/libdnf.pc @ONLY)
+ 
+diff --git a/libdnf/config.h.in b/libdnf/config-64.h.in
+similarity index 87%
+rename from libdnf/config.h.in
+rename to libdnf/config-64.h.in
+index 77974f757..e2329fe71 100644
+--- a/libdnf/config.h.in
++++ b/libdnf/config-64.h.in
+@@ -18,9 +18,9 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+  */
+ 
+-#ifndef _LIBDNF_CONFIG_H_
+-#define _LIBDNF_CONFIG_H_
++#ifndef _LIBDNF_CONFIG_@MULTILIB_ARCH@_H_
++#define _LIBDNF_CONFIG_@MULTILIB_ARCH@_H_
+ 
+ #define DEFAULT_PLUGINS_DIRECTORY "@CMAKE_INSTALL_FULL_LIBDIR@/libdnf/plugins/"
+ 
+-#endif // _LIBDNF_CONFIG_H_
++#endif // _LIBDNF_CONFIG_@MULTILIB_ARCH@_H_
+diff --git a/libdnf/config.h b/libdnf/config.h
+new file mode 100644
+index 000000000..16121f6f5
+--- /dev/null
++++ b/libdnf/config.h
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2018 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 <bits/wordsize.h>
++
++#if __WORDSIZE == 32
++#include "config-32.h"
++#elif __WORDSIZE == 64
++#include "config-64.h"
++#else
++#error "Unknown word size"
++#endif
diff --git a/SOURCES/0004-context-improve-retrieving-repository-configuration.patch b/SOURCES/0004-context-improve-retrieving-repository-configuration.patch
new file mode 100644
index 0000000..79bdeff
--- /dev/null
+++ b/SOURCES/0004-context-improve-retrieving-repository-configuration.patch
@@ -0,0 +1,1136 @@
+From be8449aa177473a834a5b2c401a8a3fcc61522b4 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Wed, 2 Dec 2020 08:00:07 +0100
+Subject: [PATCH 1/9] Option: Add reset() method
+
+The method resets the option to its initial state.
+Can be used, for example, before reloading the configuration in daemon
+mode (PackageKit).
+---
+ libdnf/conf/Option.hpp           |  2 ++
+ libdnf/conf/OptionBool.hpp       |  9 ++++++++-
+ libdnf/conf/OptionChild.hpp      | 14 ++++++++++++++
+ libdnf/conf/OptionEnum.hpp       | 15 +++++++++++++++
+ libdnf/conf/OptionNumber.hpp     | 10 +++++++++-
+ libdnf/conf/OptionString.cpp     | 11 ++++++++---
+ libdnf/conf/OptionString.hpp     |  8 ++++++++
+ libdnf/conf/OptionStringList.hpp |  9 ++++++++-
+ 8 files changed, 72 insertions(+), 6 deletions(-)
+
+diff --git a/libdnf/conf/Option.hpp b/libdnf/conf/Option.hpp
+index e9a9dfc84..849871fe7 100644
+--- a/libdnf/conf/Option.hpp
++++ b/libdnf/conf/Option.hpp
+@@ -62,6 +62,8 @@ class Option {
+     virtual void set(Priority priority, const std::string & value) = 0;
+     virtual std::string getValueString() const = 0;
+     virtual bool empty() const noexcept;
++    /// Resets the option to its initial state.
++    virtual void reset() = 0;
+     virtual ~Option() = default;
+ 
+ protected:
+diff --git a/libdnf/conf/OptionBool.hpp b/libdnf/conf/OptionBool.hpp
+index c27ab0b79..a5e647807 100644
+--- a/libdnf/conf/OptionBool.hpp
++++ b/libdnf/conf/OptionBool.hpp
+@@ -47,6 +47,7 @@ class OptionBool : public Option {
+     std::string getValueString() const override;
+     const char * const * getTrueValues() const noexcept;
+     const char * const * getFalseValues() const noexcept;
++    void reset() override;
+ 
+ protected:
+     const char * const * const trueValues;
+@@ -84,7 +85,13 @@ inline const char * const * OptionBool::getTrueValues() const noexcept
+ 
+ inline const char * const * OptionBool::getFalseValues() const noexcept
+ {
+-    return falseValues ? falseValues : defFalseValues; 
++    return falseValues ? falseValues : defFalseValues;
++}
++
++inline void OptionBool::reset()
++{
++    value = defaultValue;
++    priority = Priority::DEFAULT;
+ }
+ 
+ }
+diff --git a/libdnf/conf/OptionChild.hpp b/libdnf/conf/OptionChild.hpp
+index 5d1503cb6..3056345f9 100644
+--- a/libdnf/conf/OptionChild.hpp
++++ b/libdnf/conf/OptionChild.hpp
+@@ -39,6 +39,7 @@ class OptionChild : public Option {
+     const typename ParentOptionType::ValueType getDefaultValue() const;
+     std::string getValueString() const override;
+     bool empty() const noexcept override;
++    void reset() override;
+ 
+ private:
+     const ParentOptionType * parent;
+@@ -56,6 +57,7 @@ class OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typenam
+     const std::string & getDefaultValue() const;
+     std::string getValueString() const override;
+     bool empty() const noexcept override;
++    void reset() override;
+ 
+ private:
+     const ParentOptionType * parent;
+@@ -119,6 +121,12 @@ inline bool OptionChild<ParentOptionType, Enable>::empty() const noexcept
+     return priority == Priority::EMPTY && parent->empty();
+ }
+ 
++template <class ParentOptionType, class Enable>
++inline void OptionChild<ParentOptionType, Enable>::reset()
++{
++    priority = Priority::EMPTY;
++}
++
+ template <class ParentOptionType>
+ inline OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::OptionChild(const ParentOptionType & parent)
+ : parent(&parent) {}
+@@ -171,6 +179,12 @@ inline bool OptionChild<ParentOptionType, typename std::enable_if<std::is_same<t
+     return priority == Priority::EMPTY && parent->empty();
+ }
+ 
++template <class ParentOptionType>
++inline void OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::reset()
++{
++    priority = Priority::EMPTY;
++}
++
+ }
+ 
+ #endif
+diff --git a/libdnf/conf/OptionEnum.hpp b/libdnf/conf/OptionEnum.hpp
+index c63156cb3..d2f710f20 100644
+--- a/libdnf/conf/OptionEnum.hpp
++++ b/libdnf/conf/OptionEnum.hpp
+@@ -49,6 +49,7 @@ class OptionEnum : public Option {
+     T getDefaultValue() const;
+     std::string toString(ValueType value) const;
+     std::string getValueString() const override;
++    void reset() override;
+ 
+ protected:
+     FromStringFunc fromStringUser;
+@@ -74,6 +75,7 @@ class OptionEnum<std::string> : public Option {
+     const std::string & getValue() const;
+     const std::string & getDefaultValue() const;
+     std::string getValueString() const override;
++    void reset() override;
+ 
+ protected:
+     FromStringFunc fromStringUser;
+@@ -88,6 +90,13 @@ inline OptionEnum<T> * OptionEnum<T>::clone() const
+     return new OptionEnum<T>(*this);
+ }
+ 
++template <typename T>
++inline void OptionEnum<T>::reset()
++{
++    value = defaultValue;
++    priority = Priority::DEFAULT;
++}
++
+ inline OptionEnum<std::string> * OptionEnum<std::string>::clone() const
+ {
+     return new OptionEnum<std::string>(*this);
+@@ -108,6 +117,12 @@ inline std::string OptionEnum<std::string>::getValueString() const
+     return value;
+ }
+ 
++inline void OptionEnum<std::string>::reset()
++{
++    value = defaultValue;
++    priority = Priority::DEFAULT;
++}
++
+ }
+ 
+ #endif
+diff --git a/libdnf/conf/OptionNumber.hpp b/libdnf/conf/OptionNumber.hpp
+index 98988fd50..f7a7b3d6e 100644
+--- a/libdnf/conf/OptionNumber.hpp
++++ b/libdnf/conf/OptionNumber.hpp
+@@ -50,6 +50,7 @@ class OptionNumber : public Option {
+     T getDefaultValue() const;
+     std::string toString(ValueType value) const;
+     std::string getValueString() const override;
++    void reset() override;
+ 
+ protected:
+     FromStringFunc fromStringUser;
+@@ -80,7 +81,14 @@ inline T OptionNumber<T>::getDefaultValue() const
+ template <typename T>
+ inline std::string OptionNumber<T>::getValueString() const
+ {
+-    return toString(value); 
++    return toString(value);
++}
++
++template <typename T>
++inline void OptionNumber<T>::reset()
++{
++    value = defaultValue;
++    priority = Priority::DEFAULT;
+ }
+ 
+ extern template class OptionNumber<std::int32_t>;
+diff --git a/libdnf/conf/OptionString.cpp b/libdnf/conf/OptionString.cpp
+index d27194f7a..b42e6c633 100644
+--- a/libdnf/conf/OptionString.cpp
++++ b/libdnf/conf/OptionString.cpp
+@@ -27,18 +27,21 @@
+ namespace libdnf {
+ 
+ OptionString::OptionString(const std::string & defaultValue)
+-: Option(Priority::DEFAULT), defaultValue(defaultValue), value(defaultValue) {}
++: Option(Priority::DEFAULT), initPriority(Priority::DEFAULT), defaultValue(defaultValue), value(defaultValue) {}
+ 
+ OptionString::OptionString(const char * defaultValue)
+ {
+     if (defaultValue) {
+         this->value = this->defaultValue = defaultValue;
+-        this->priority = Priority::DEFAULT;
++        this->initPriority = this->priority = Priority::DEFAULT;
++    } else {
++        this->initPriority = Priority::EMPTY;
+     }
+ }
+ 
+ OptionString::OptionString(const std::string & defaultValue, const std::string & regex, bool icase)
+-: Option(Priority::DEFAULT), regex(regex), icase(icase), defaultValue(defaultValue), value(defaultValue) { test(defaultValue); }
++: Option(Priority::DEFAULT), initPriority(Priority::DEFAULT), regex(regex), icase(icase)
++, defaultValue(defaultValue), value(defaultValue) { test(defaultValue); }
+ 
+ OptionString::OptionString(const char * defaultValue, const std::string & regex, bool icase)
+ : regex(regex), icase(icase)
+@@ -48,6 +51,8 @@ OptionString::OptionString(const char * defaultValue, const std::string & regex,
+         test(this->defaultValue);
+         this->value = this->defaultValue;
+         this->priority = Priority::DEFAULT;
++    } else {
++        this->initPriority = Priority::EMPTY;
+     }
+ }
+ 
+diff --git a/libdnf/conf/OptionString.hpp b/libdnf/conf/OptionString.hpp
+index 2e26305c4..03fef8bcf 100644
+--- a/libdnf/conf/OptionString.hpp
++++ b/libdnf/conf/OptionString.hpp
+@@ -42,8 +42,10 @@ class OptionString : public Option {
+     const std::string & getValue() const;
+     const std::string & getDefaultValue() const noexcept;
+     std::string getValueString() const override;
++    void reset() override;
+ 
+ protected:
++    Priority initPriority;
+     std::string regex;
+     bool icase;
+     std::string defaultValue;
+@@ -70,6 +72,12 @@ inline std::string OptionString::fromString(const std::string & value) const
+     return value;
+ }
+ 
++inline void OptionString::reset()
++{
++    value = defaultValue;
++    priority = initPriority;
++}
++
+ }
+ 
+ #endif
+diff --git a/libdnf/conf/OptionStringList.hpp b/libdnf/conf/OptionStringList.hpp
+index 942e56b16..20debaa8c 100644
+--- a/libdnf/conf/OptionStringList.hpp
++++ b/libdnf/conf/OptionStringList.hpp
+@@ -45,6 +45,7 @@ class OptionStringList : public Option {
+     const ValueType & getDefaultValue() const;
+     std::string toString(const ValueType & value) const;
+     std::string getValueString() const override;
++    void reset() override;
+ 
+ protected:
+     std::string regex;
+@@ -70,7 +71,13 @@ inline const OptionStringList::ValueType & OptionStringList::getDefaultValue() c
+ 
+ inline std::string OptionStringList::getValueString() const
+ {
+-    return toString(value); 
++    return toString(value);
++}
++
++inline void OptionStringList::reset()
++{
++    value = defaultValue;
++    priority = Priority::DEFAULT;
+ }
+ 
+ }
+
+From 372a000414875f323147cd342dd8b4c8c7ebe260 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Tue, 1 Dec 2020 08:29:53 +0100
+Subject: [PATCH 2/9] Add OptionBinds::getOption() method
+
+Sometime we want direct access to the underlying Option.
+E.g. we want to get its original value (not just a string representation)
+or find out the Option type.
+---
+ libdnf/conf/OptionBinds.cpp | 9 +++++++++
+ libdnf/conf/OptionBinds.hpp | 2 ++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/libdnf/conf/OptionBinds.cpp b/libdnf/conf/OptionBinds.cpp
+index f7c67540b..ab53518a3 100644
+--- a/libdnf/conf/OptionBinds.cpp
++++ b/libdnf/conf/OptionBinds.cpp
+@@ -66,6 +66,15 @@ bool OptionBinds::Item::getAddValue() const
+     return addValue;
+ }
+ 
++const Option & OptionBinds::Item::getOption() const
++{
++    return *option;
++}
++
++Option & OptionBinds::Item::getOption()
++{
++    return *option;
++}
+ 
+ // =========== OptionBinds class ===============
+ 
+diff --git a/libdnf/conf/OptionBinds.hpp b/libdnf/conf/OptionBinds.hpp
+index 715c37e26..515120b93 100644
+--- a/libdnf/conf/OptionBinds.hpp
++++ b/libdnf/conf/OptionBinds.hpp
+@@ -55,6 +55,8 @@ class OptionBinds {
+         void newString(Option::Priority priority, const std::string & value);
+         std::string getValueString() const;
+         bool getAddValue() const;
++        const Option & getOption() const;
++        Option & getOption();
+ 
+     private:
+         friend class OptionBinds;
+
+From 3a686c378978c90538a6ac5d9826d52ce7c8daf6 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Tue, 1 Dec 2020 08:37:14 +0100
+Subject: [PATCH 3/9] [context] Add dnf_repo_conf_from_gkeyfile() and
+ dnf_repo_conf_reset()
+
+dnf_repo_conf_from_gkeyfile():
+The function reloads repository configuration from GKeyFile.
+
+dnf_repo_conf_reset():
+Resets repository configuration options previously readed from repository
+configuration file to initial state.
+---
+ libdnf/dnf-repo.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 64 insertions(+)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index 00f4bbf7b..9f283df55 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -936,6 +936,70 @@ dnf_repo_get_boolean(GKeyFile *keyfile,
+     return false;
+ }
+ 
++/* Resets repository configuration options previously readed from repository
++ * configuration file to initial state. */
++static void
++dnf_repo_conf_reset(libdnf::ConfigRepo &config)
++{
++    for (auto & item : config.optBinds()) {
++        auto & itemOption = item.second;
++        if (itemOption.getPriority() == libdnf::Option::Priority::REPOCONFIG) {
++            itemOption.getOption().reset();
++        }
++    }
++}
++
++/* Loads repository configuration from GKeyFile */
++static void
++dnf_repo_conf_from_gkeyfile(libdnf::ConfigRepo &config, const char *repoId, GKeyFile *gkeyFile)
++{
++    // Reset to the initial state before reloading the configuration.
++    dnf_repo_conf_reset(config);
++
++    g_auto(GStrv) keys = g_key_file_get_keys(gkeyFile, repoId, NULL, NULL);
++    for (auto it = keys; *it != NULL; ++it) {
++        auto key = *it;
++        g_autofree gchar *str = g_key_file_get_value(gkeyFile, repoId, key, NULL);
++        if (str) {
++            try {
++                auto & optionItem = config.optBinds().at(key);
++
++                if (dynamic_cast<libdnf::OptionStringList*>(&optionItem.getOption()) ||
++                    dynamic_cast<libdnf::OptionChild<libdnf::OptionStringList>*>(&optionItem.getOption())
++                ) {
++
++                    // reload list option from gKeyFile using g_key_file_get_string_list()
++                    // g_key_file_get_value () is problematic for multiline lists
++                    g_auto(GStrv) list = g_key_file_get_string_list(gkeyFile, repoId, key, NULL, NULL);
++                    if (list) {
++                        // list can be ['value1', 'value2, value3'] therefore we first join
++                        // to have 'value1, value2, value3'
++                        g_autofree gchar * tmp_strval = g_strjoinv(",", list);
++                        try {
++                            optionItem.newString(libdnf::Option::Priority::REPOCONFIG, tmp_strval);
++                        } catch (const std::exception & ex) {
++                            g_debug("Invalid configuration value: %s = %s in %s; %s", key, str, repoId, ex.what());
++                        }
++                    }
++
++                } else {
++
++                    // process other (non list) options
++                    try {
++                        optionItem.newString(libdnf::Option::Priority::REPOCONFIG, str);
++                    } catch (const std::exception & ex) {
++                        g_debug("Invalid configuration value: %s = %s in %s; %s", key, str, repoId, ex.what());
++                    }
++
++                }
++
++            } catch (const std::exception &) {
++                g_debug("Unknown configuration option: %s = %s in %s", key, str, repoId);
++            }
++        }
++    }
++}
++
+ /* Initialize (or potentially reset) repo & LrHandle from keyfile values. */
+ static gboolean
+ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+
+From 5f1c06a66fcdb2c2340c11c07c5ba0ea3abf4b77 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Wed, 2 Dec 2020 11:37:26 +0100
+Subject: [PATCH 4/9] [context] Use dnf_repo_conf_from_gkeyfile() for repo
+ configuration reload
+
+The dnf_repo_set_key_file_data() uses dnf_repo_conf_from_gkeyfile() now.
+All occurrences of the direct use 'repo->getConfig()->.*set' and
+newString() were removed.
+---
+ libdnf/dnf-repo.cpp | 121 +++++++++-----------------------------------
+ 1 file changed, 25 insertions(+), 96 deletions(-)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index 9f283df55..2837580f7 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -1006,7 +1006,6 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+ {
+     DnfRepoPrivate *priv = GET_PRIVATE(repo);
+     guint cost;
+-    gboolean module_hotfixes = false;
+     g_autofree gchar *metadata_expire_str = NULL;
+     g_autofree gchar *mirrorlist = NULL;
+     g_autofree gchar *mirrorlisturl = NULL;
+@@ -1016,48 +1015,28 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     g_autofree gchar *usr = NULL;
+     g_autofree gchar *usr_pwd = NULL;
+     g_autofree gchar *usr_pwd_proxy = NULL;
+-    g_auto(GStrv) baseurls;
+ 
+     auto repoId = priv->repo->getId().c_str();
+     g_debug("setting keyfile data for %s", repoId);
+ 
+-    /* skip_if_unavailable is optional */
+-    if (g_key_file_has_key(priv->keyfile, repoId, "skip_if_unavailable", NULL)) {
+-        bool skip = dnf_repo_get_boolean(priv->keyfile, repoId, "skip_if_unavailable");
+-        priv->repo->getConfig()->skip_if_unavailable().set(libdnf::Option::Priority::REPOCONFIG, skip);
+-    }
++    auto conf = priv->repo->getConfig();
+ 
+-    /* priority is optional */
+-    g_autofree gchar * priority_str = g_key_file_get_string(priv->keyfile, repoId, "priority", NULL);
+-    if (priority_str) {
+-        priv->repo->getConfig()->priority().set(libdnf::Option::Priority::REPOCONFIG, priority_str);
+-    }
++    // Reload repository configuration from keyfile.
++    dnf_repo_conf_from_gkeyfile(*conf, repoId, priv->keyfile);
+ 
+     /* cost is optional */
+     cost = g_key_file_get_integer(priv->keyfile, repoId, "cost", NULL);
+     if (cost != 0)
+         dnf_repo_set_cost(repo, cost);
+ 
+-    module_hotfixes = g_key_file_get_boolean(priv->keyfile, repoId, "module_hotfixes", NULL);
+-    priv->repo->getConfig()->module_hotfixes().set(libdnf::Option::Priority::REPOCONFIG, module_hotfixes);
+-
+     /* baseurl is optional; if missing, unset it */
+-    baseurls = g_key_file_get_string_list(priv->keyfile, repoId, "baseurl", NULL, NULL);
+-    if (baseurls) {
+-        // baseruls can be ['value1', 'value2, value3'] therefore we first join to have 'value1, value2, value3'
+-        g_autofree gchar * tmp_strval = g_strjoinv(",", baseurls);
+-
+-        auto & bindBaseurls = priv->repo->getConfig()->optBinds().at("baseurl");
+-        bindBaseurls.newString(libdnf::Option::Priority::REPOCONFIG, tmp_strval);
+-
+-        auto & repoBaseurls = priv->repo->getConfig()->baseurl();
+-        if (!repoBaseurls.getValue().empty()){
+-            auto len = repoBaseurls.getValue().size();
+-            g_strfreev(baseurls);
+-            baseurls = g_new0(char *, len + 1);
+-            for (size_t i = 0; i < len; ++i) {
+-                baseurls[i] = g_strdup(repoBaseurls.getValue()[i].c_str());
+-            }
++    g_auto(GStrv) baseurls = NULL;
++    auto & repoBaseurls = conf->baseurl().getValue();
++    if (!repoBaseurls.empty()){
++        auto len = repoBaseurls.size();
++        baseurls = g_new0(char *, len + 1);
++        for (size_t i = 0; i < len; ++i) {
++            baseurls[i] = g_strdup(repoBaseurls[i].c_str());
+         }
+     }
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_URLS, baseurls))
+@@ -1093,18 +1072,6 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_METALINKURL, metalinkurl))
+         return FALSE;
+ 
+-    /* needed in order for addCountmeFlag() to use the same persistdir as DNF
+-     * would */
+-    if (metalinkurl)
+-        priv->repo->getConfig()->metalink().set(libdnf::Option::Priority::REPOCONFIG, metalinkurl);
+-    if (mirrorlisturl)
+-        priv->repo->getConfig()->mirrorlist().set(libdnf::Option::Priority::REPOCONFIG, mirrorlisturl);
+-
+-    if (g_key_file_has_key(priv->keyfile, repoId, "countme", NULL)) {
+-        bool countme = dnf_repo_get_boolean(priv->keyfile, repoId, "countme");
+-        priv->repo->getConfig()->countme().set(libdnf::Option::Priority::REPOCONFIG, countme);
+-    }
+-
+     /* file:// */
+     if (baseurls != NULL && baseurls[0] != NULL &&
+         mirrorlisturl == NULL && metalinkurl == NULL) {
+@@ -1150,42 +1117,20 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+         dnf_repo_set_location_tmp(repo, tmp->str);
+     }
+ 
+-    /* gpgkey is optional for gpgcheck=1, but required for repo_gpgcheck=1 */
++    // Sync priv->gpgkeys
+     g_strfreev(priv->gpgkeys);
+-    priv->gpgkeys = NULL;
+-
+-    g_auto(GStrv) gpgkeys;
+-    gpgkeys = g_key_file_get_string_list(priv->keyfile, repoId, "gpgkey", NULL, NULL);
+-
+-    if (gpgkeys) {
+-        // gpgkeys can be ['value1', 'value2, value3'] therefore we first join to have 'value1, value2, value3'
+-        g_autofree gchar * tmp_strval = g_strjoinv(",", gpgkeys);
+-
+-        auto & bindGpgkeys = priv->repo->getConfig()->optBinds().at("gpgkey");
+-        bindGpgkeys.newString(libdnf::Option::Priority::REPOCONFIG, tmp_strval);
+-
+-        auto & repoGpgkeys = priv->repo->getConfig()->gpgkey();
+-        if (!repoGpgkeys.getValue().empty()){
+-            auto len = repoGpgkeys.getValue().size();
+-            priv->gpgkeys = g_new0(char *, len + 1);
+-            for (size_t i = 0; i < len; ++i) {
+-                priv->gpgkeys[i] = g_strdup(repoGpgkeys.getValue()[i].c_str());
+-            }
+-        } else {
+-            /* Canonicalize the empty list to NULL for ease of checking elsewhere */
+-            g_strfreev(static_cast<gchar **>(g_steal_pointer(&priv->gpgkeys)));
++    auto & repoGpgkeys = conf->gpgkey().getValue();
++    if (!repoGpgkeys.empty()){
++        auto len = repoGpgkeys.size();
++        priv->gpgkeys = g_new0(char *, len + 1);
++        for (size_t i = 0; i < len; ++i) {
++            priv->gpgkeys[i] = g_strdup(repoGpgkeys[i].c_str());
+         }
++    } else {
++        priv->gpgkeys = NULL;
+     }
+ 
+-    if (g_key_file_has_key(priv->keyfile, repoId, "gpgcheck", NULL)) {
+-        auto gpgcheck_pkgs = dnf_repo_get_boolean(priv->keyfile, repoId, "gpgcheck");
+-        priv->repo->getConfig()->gpgcheck().set(libdnf::Option::Priority::REPOCONFIG, gpgcheck_pkgs);
+-    }
+-
+-    if (g_key_file_has_key(priv->keyfile, repoId, "repo_gpgcheck", NULL)) {
+-        auto gpgcheck_md = dnf_repo_get_boolean(priv->keyfile, repoId, "repo_gpgcheck");
+-        priv->repo->getConfig()->repo_gpgcheck().set(libdnf::Option::Priority::REPOCONFIG, gpgcheck_md);
+-    }
++    /* gpgkey is optional for gpgcheck=1, but required for repo_gpgcheck=1 */
+     auto gpgcheck_md = priv->repo->getConfig()->repo_gpgcheck().getValue();
+     if (gpgcheck_md && priv->gpgkeys == NULL) {
+         g_set_error_literal(error,
+@@ -1199,35 +1144,19 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_GPGCHECK, (long)gpgcheck_md))
+         return FALSE;
+ 
+-    auto & repoExcludepkgs = priv->repo->getConfig()->excludepkgs();
+-    repoExcludepkgs.set(libdnf::Option::Priority::REPOCONFIG, "");
+-
+-    auto & bindExcludepkgs = priv->repo->getConfig()->optBinds().at("excludepkgs");
+-    if (auto excludepkgs = g_key_file_get_string(priv->keyfile, repoId, "exclude", NULL)) {
+-        bindExcludepkgs.newString(libdnf::Option::Priority::REPOCONFIG, excludepkgs);
+-        g_free(excludepkgs);
+-    }
+-    if (auto excludepkgs = g_key_file_get_string(priv->keyfile, repoId, "excludepkgs", NULL)) {
+-        bindExcludepkgs.newString(libdnf::Option::Priority::REPOCONFIG, excludepkgs);
+-        g_free(excludepkgs);
+-    }
+-
++    // Sync priv->exclude_packages
+     g_strfreev(priv->exclude_packages);
+-    if (!repoExcludepkgs.getValue().empty()) {
+-        auto len = repoExcludepkgs.getValue().size();
++    auto & repoExcludepkgs = conf->excludepkgs().getValue();
++    if (!repoExcludepkgs.empty()) {
++        auto len = repoExcludepkgs.size();
+         priv->exclude_packages = g_new0(char *, len + 1);
+         for (size_t i = 0; i < len; ++i) {
+-            priv->exclude_packages[i] = g_strdup(repoExcludepkgs.getValue()[i].c_str());
++            priv->exclude_packages[i] = g_strdup(repoExcludepkgs[i].c_str());
+         }
+     } else {
+         priv->exclude_packages = NULL;
+     }
+ 
+-    if (auto includepkgs = g_key_file_get_string(priv->keyfile, repoId, "includepkgs", NULL)) {
+-        priv->repo->getConfig()->includepkgs().set(libdnf::Option::Priority::REPOCONFIG, includepkgs);
+-        g_free(includepkgs);
+-    }
+-
+     /* proxy is optional */
+     proxy = g_key_file_get_string(priv->keyfile, repoId, "proxy", NULL);
+     auto repoProxy = proxy ? (strcasecmp(proxy, "_none_") == 0 ? NULL : proxy)
+
+From c6afbb4f93eee480c68201297e9c5c7afdf05dd3 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Wed, 2 Dec 2020 13:26:51 +0100
+Subject: [PATCH 5/9] [context] Fix: "cost" and  "metadata_expire" repository
+ options
+
+Changes in dnf_repo_set_keyfile_data():
+Removed the dnf_repo_set_cost() call.
+Removed the "metadata_expire" parsing and dnf_repo_set_metadata_expire() call.
+
+The options were set earlier. The function calls were redundant and
+set the priority to the wrong RUNTIME value.
+---
+ libdnf/dnf-repo.cpp | 103 --------------------------------------------
+ 1 file changed, 103 deletions(-)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index 2837580f7..61d496750 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -816,93 +816,6 @@ dnf_repo_set_metadata_expire(DnfRepo *repo, guint metadata_expire)
+     priv->repo->getConfig()->metadata_expire().set(libdnf::Option::Priority::RUNTIME, metadata_expire);
+ }
+ 
+-/**
+- *  dnf_repo_parse_time_from_str
+- *  @expression: a expression to be parsed
+- *  @out_parsed_time: (out): return location for parsed time
+- *  @error: error item
+- *
+- *  Parse String into an integer value of seconds, or a human
+- *  readable variation specifying days, hours, minutes or seconds
+- *  until something happens. Note that due to historical president
+- *  -1 means "never", so this accepts that and allows
+- *  the word never, too.
+- *
+- *  Valid inputs: 100, 1.5m, 90s, 1.2d, 1d, 0xF, 0.1, -1, never.
+- *  Invalid inputs: -10, -0.1, 45.6Z, 1d6h, 1day, 1y.
+-
+- *  Returns: integer value in seconds
+- **/
+-
+-static gboolean
+-dnf_repo_parse_time_from_str(const gchar *expression, guint *out_parsed_time, GError **error)
+-{
+-    gint multiplier;
+-    gdouble parsed_time;
+-    gchar *endptr = NULL;
+-
+-    if (!g_strcmp0(expression, "")) {
+-        g_set_error_literal(error,
+-                            DNF_ERROR,
+-                            DNF_ERROR_FILE_INVALID,
+-                            "no metadata value specified");
+-        return FALSE;
+-    }
+-
+-    if (g_strcmp0(expression, "-1") == 0 ||
+-        g_strcmp0(expression,"never") == 0) {
+-        *out_parsed_time = G_MAXUINT;
+-        return TRUE; /* Note early return */
+-    }
+-
+-    gchar last_char = expression[ strlen(expression) - 1 ];
+-
+-    /* check if the input ends with h, m ,d ,s as units */
+-    if (g_ascii_isalpha(last_char)) {
+-        if (last_char == 'h')
+-            multiplier = 60 * 60;
+-        else if (last_char == 's')
+-            multiplier = 1;
+-        else if (last_char == 'm')
+-            multiplier = 60;
+-        else if (last_char == 'd')
+-            multiplier = 60 * 60 * 24;
+-        else {
+-            g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID,
+-                        "unknown unit %c", last_char);
+-            return FALSE;
+-        }
+-    }
+-    else
+-        multiplier = 1;
+-
+-    /* convert expression into a double*/
+-    parsed_time = g_ascii_strtod(expression, &endptr);
+-
+-    /* failed to parse */
+-    if (expression == endptr) {
+-        g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+-                    "failed to parse time: %s", expression);
+-        return FALSE;
+-    }
+-
+-    /* time can not be below zero */
+-    if (parsed_time < 0) {
+-        g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+-                    "seconds value must not be negative %s",expression );
+-        return FALSE;
+-    }
+-
+-    /* time too large */
+-    if (parsed_time > G_MAXDOUBLE || (parsed_time * multiplier) > G_MAXUINT){
+-        g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+-                    "time too large");
+-        return FALSE;
+-    }
+-
+-    *out_parsed_time = (guint) (parsed_time * multiplier);
+-    return TRUE;
+-}
+ /**
+  * dnf_repo_get_username_password_string:
+  */
+@@ -1005,8 +918,6 @@ static gboolean
+ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+ {
+     DnfRepoPrivate *priv = GET_PRIVATE(repo);
+-    guint cost;
+-    g_autofree gchar *metadata_expire_str = NULL;
+     g_autofree gchar *mirrorlist = NULL;
+     g_autofree gchar *mirrorlisturl = NULL;
+     g_autofree gchar *metalinkurl = NULL;
+@@ -1024,11 +935,6 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     // Reload repository configuration from keyfile.
+     dnf_repo_conf_from_gkeyfile(*conf, repoId, priv->keyfile);
+ 
+-    /* cost is optional */
+-    cost = g_key_file_get_integer(priv->keyfile, repoId, "cost", NULL);
+-    if (cost != 0)
+-        dnf_repo_set_cost(repo, cost);
+-
+     /* baseurl is optional; if missing, unset it */
+     g_auto(GStrv) baseurls = NULL;
+     auto & repoBaseurls = conf->baseurl().getValue();
+@@ -1042,15 +948,6 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_URLS, baseurls))
+         return FALSE;
+ 
+-    /* metadata_expire is optional, if shown, we parse the string to add the time */
+-    metadata_expire_str = g_key_file_get_string(priv->keyfile, repoId, "metadata_expire", NULL);
+-    if (metadata_expire_str) {
+-        guint metadata_expire;
+-        if (!dnf_repo_parse_time_from_str(metadata_expire_str, &metadata_expire, error))
+-            return FALSE;
+-        dnf_repo_set_metadata_expire(repo, metadata_expire);
+-    }
+-
+     /* the "mirrorlist" entry could be either a real mirrorlist, or a metalink entry */
+     mirrorlist = g_key_file_get_string(priv->keyfile, repoId, "mirrorlist", NULL);
+     if (mirrorlist) {
+
+From b11ac5204dc4c7048a7b6880813f2f9b1d8eb242 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Wed, 2 Dec 2020 13:21:35 +0100
+Subject: [PATCH 6/9] [context] Fix: username, password, proxy, proxy_username,
+ proxy_password
+
+- Uses global configuration options when they are not defined
+  in the repository configuration.
+- proxy_username and proxy_password is urlEncoded before passing to librepo.
+---
+ libdnf/dnf-repo.cpp | 78 ++++++++++++++++++++++++++-------------------
+ 1 file changed, 46 insertions(+), 32 deletions(-)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index 61d496750..005721ef6 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -817,18 +817,22 @@ dnf_repo_set_metadata_expire(DnfRepo *repo, guint metadata_expire)
+ }
+ 
+ /**
+- * dnf_repo_get_username_password_string:
+- */
+-static gchar *
+-dnf_repo_get_username_password_string(const gchar *user, const gchar *pass)
+-{
+-    if (user == NULL && pass == NULL)
+-        return NULL;
+-    if (user != NULL && pass == NULL)
+-        return g_strdup(user);
+-    if (user == NULL && pass != NULL)
+-        return g_strdup_printf(":%s", pass);
+-    return g_strdup_printf("%s:%s", user, pass);
++* @brief Format user password string
++*
++* Returns user and password in user:password form. If encode is True,
++* special characters in user and password are URL encoded.
++*
++* @param user Username
++* @param passwd Password
++* @param encode If quote is True, special characters in user and password are URL encoded.
++* @return User and password in user:password form
++*/
++static std::string formatUserPassString(const std::string & user, const std::string & passwd, bool encode)
++{
++    if (encode)
++        return libdnf::urlEncode(user) + ":" + libdnf::urlEncode(passwd);
++    else
++        return user + ":" + passwd;
+ }
+ 
+ static gboolean
+@@ -921,11 +925,8 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     g_autofree gchar *mirrorlist = NULL;
+     g_autofree gchar *mirrorlisturl = NULL;
+     g_autofree gchar *metalinkurl = NULL;
+-    g_autofree gchar *proxy = NULL;
+-    g_autofree gchar *pwd = NULL;
+-    g_autofree gchar *usr = NULL;
+-    g_autofree gchar *usr_pwd = NULL;
+-    g_autofree gchar *usr_pwd_proxy = NULL;
++    std::string tmp_str;
++    const char *tmp_cstr;
+ 
+     auto repoId = priv->repo->getId().c_str();
+     g_debug("setting keyfile data for %s", repoId);
+@@ -1054,26 +1055,39 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+         priv->exclude_packages = NULL;
+     }
+ 
+-    /* proxy is optional */
+-    proxy = g_key_file_get_string(priv->keyfile, repoId, "proxy", NULL);
+-    auto repoProxy = proxy ? (strcasecmp(proxy, "_none_") == 0 ? NULL : proxy)
+-        : dnf_context_get_http_proxy(priv->context);
+-    if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY, repoProxy))
++    tmp_str = conf->proxy().getValue();
++    tmp_cstr = tmp_str.empty() ? dnf_context_get_http_proxy(priv->context) : tmp_str.c_str();
++    if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY, tmp_cstr))
+         return FALSE;
+ 
+-    /* both parts of the proxy auth are optional */
+-    usr = g_key_file_get_string(priv->keyfile, repoId, "proxy_username", NULL);
+-    pwd = g_key_file_get_string(priv->keyfile, repoId, "proxy_password", NULL);
+-    usr_pwd_proxy = dnf_repo_get_username_password_string(usr, pwd);
+-    if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXYUSERPWD, usr_pwd_proxy))
++    // setup proxy username and password
++    tmp_cstr = NULL;
++    if (!conf->proxy_username().empty()) {
++        tmp_str = conf->proxy_username().getValue();
++        if (!tmp_str.empty()) {
++            if (conf->proxy_password().empty()) {
++                g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID,
++                            "repo '%s': 'proxy_username' is set but not 'proxy_password'", repoId);
++                return FALSE;
++            }
++            tmp_str = formatUserPassString(tmp_str, conf->proxy_password().getValue(), true);
++            tmp_cstr = tmp_str.c_str();
++        }
++    }
++    if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXYUSERPWD, tmp_cstr))
+         return FALSE;
+ 
+-    /* both parts of the HTTP auth are optional */
+-    usr = g_key_file_get_string(priv->keyfile, repoId, "username", NULL);
+-    pwd = g_key_file_get_string(priv->keyfile, repoId, "password", NULL);
+-    usr_pwd = dnf_repo_get_username_password_string(usr, pwd);
+-    if (!lr_handle_setopt(priv->repo_handle, error, LRO_USERPWD, usr_pwd))
++    // setup username and password
++    tmp_cstr = NULL;
++    tmp_str = conf->username().getValue();
++    if (!tmp_str.empty()) {
++        // TODO Use URL encoded form, needs support in librepo
++        tmp_str = formatUserPassString(tmp_str, conf->password().getValue(), false);
++        tmp_cstr = tmp_str.c_str();
++    }
++    if (!lr_handle_setopt(priv->repo_handle, error, LRO_USERPWD, tmp_cstr))
+         return FALSE;
++
+     return TRUE;
+ }
+ 
+
+From fd07b29ccaec2648cfc050122e16e4846d7ac4be Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Wed, 2 Dec 2020 13:53:45 +0100
+Subject: [PATCH 7/9] [context] Add support for options: minrate, throttle,
+ bandwidth, timeout
+
+---
+ libdnf/dnf-repo.cpp | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index 005721ef6..c6dd027be 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -1055,6 +1055,35 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+         priv->exclude_packages = NULL;
+     }
+ 
++    auto minrate = conf->minrate().getValue();
++    if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOWSPEEDLIMIT, static_cast<long>(minrate)))
++        return FALSE;
++
++    auto maxspeed = conf->throttle().getValue();
++    if (maxspeed > 0 && maxspeed <= 1)
++        maxspeed *= conf->bandwidth().getValue();
++    if (maxspeed != 0 && maxspeed < minrate) {
++        g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FILE_INVALID,
++                            "Maximum download speed is lower than minimum. "
++                            "Please change configuration of minrate or throttle");
++        return FALSE;
++    }
++    if (!lr_handle_setopt(priv->repo_handle, error, LRO_MAXSPEED, static_cast<int64_t>(maxspeed)))
++        return FALSE;
++
++    long timeout = conf->timeout().getValue();
++    if (timeout > 0) {
++        if (!lr_handle_setopt(priv->repo_handle, error, LRO_CONNECTTIMEOUT, timeout))
++            return FALSE;
++        if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOWSPEEDTIME, timeout))
++            return FALSE;
++    } else {
++        if (!lr_handle_setopt(priv->repo_handle, error, LRO_CONNECTTIMEOUT, LRO_CONNECTTIMEOUT_DEFAULT))
++            return FALSE;
++        if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOWSPEEDTIME, LRO_LOWSPEEDTIME_DEFAULT))
++            return FALSE;
++    }
++
+     tmp_str = conf->proxy().getValue();
+     tmp_cstr = tmp_str.empty() ? dnf_context_get_http_proxy(priv->context) : tmp_str.c_str();
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY, tmp_cstr))
+
+From c484de218699dff834fb32133cf502b2d0c64162 Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Thu, 3 Dec 2020 10:55:02 +0100
+Subject: [PATCH 8/9] [context] Remove g_key_file_get_string() from
+ dnf_repo_set_keyfile_data()
+
+Removes the remaining usage of g_key_file_get_string() from
+dnf_repo_set_keyfile_data(). Use the values from ConfigRepo instead.
+---
+ libdnf/dnf-repo.cpp | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index c6dd027be..c5c50d55c 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -922,9 +922,6 @@ static gboolean
+ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+ {
+     DnfRepoPrivate *priv = GET_PRIVATE(repo);
+-    g_autofree gchar *mirrorlist = NULL;
+-    g_autofree gchar *mirrorlisturl = NULL;
+-    g_autofree gchar *metalinkurl = NULL;
+     std::string tmp_str;
+     const char *tmp_cstr;
+ 
+@@ -949,20 +946,22 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_URLS, baseurls))
+         return FALSE;
+ 
++    const char *mirrorlisturl = NULL;
++    const char *metalinkurl = NULL;
++
+     /* the "mirrorlist" entry could be either a real mirrorlist, or a metalink entry */
+-    mirrorlist = g_key_file_get_string(priv->keyfile, repoId, "mirrorlist", NULL);
+-    if (mirrorlist) {
+-        if (strstr(mirrorlist, "metalink"))
+-            metalinkurl = static_cast<gchar *>(g_steal_pointer(&mirrorlist));
++    tmp_cstr = conf->mirrorlist().empty() ? NULL : conf->mirrorlist().getValue().c_str();
++    if (tmp_cstr) {
++        if (strstr(tmp_cstr, "metalink"))
++            metalinkurl = tmp_cstr;
+         else /* it really is a mirrorlist */
+-            mirrorlisturl = static_cast<gchar *>(g_steal_pointer(&mirrorlist));
++            mirrorlisturl = tmp_cstr;
+     }
+ 
+     /* let "metalink" entry override metalink-as-mirrorlist entry */
+-    if (g_key_file_has_key(priv->keyfile, repoId, "metalink", NULL)) {
+-        g_free(metalinkurl);
+-        metalinkurl = g_key_file_get_string(priv->keyfile, repoId, "metalink", NULL);
+-    }
++    tmp_cstr = conf->metalink().empty() ? NULL : conf->metalink().getValue().c_str();
++    if (tmp_cstr)
++        metalinkurl = tmp_cstr;
+ 
+     /* now set the final values (or unset them) */
+     if (!lr_handle_setopt(priv->repo_handle, error, LRO_MIRRORLISTURL, mirrorlisturl))
+
+From ce44d3dced4b800e3b7f80556fac1daf7e7fa49d Mon Sep 17 00:00:00 2001
+From: Jaroslav Rohel <jrohel@redhat.com>
+Date: Thu, 3 Dec 2020 11:43:18 +0100
+Subject: [PATCH 9/9] [context] Remove the extra gpgkey member from
+ DnfRepoPrivate
+
+The value stored in ConfigRepo can be used directly.
+---
+ libdnf/dnf-repo.cpp | 81 ++++++++++++++++++---------------------------
+ 1 file changed, 33 insertions(+), 48 deletions(-)
+
+diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
+index c5c50d55c..193999902 100644
+--- a/libdnf/dnf-repo.cpp
++++ b/libdnf/dnf-repo.cpp
+@@ -63,7 +63,6 @@
+ typedef struct
+ {
+     DnfRepoEnabled   enabled;
+-    gchar          **gpgkeys;
+     gchar          **exclude_packages;
+     gchar           *filename;      /* /etc/yum.repos.d/updates.repo */
+     gchar           *location;      /* /var/cache/PackageKit/metadata/fedora */
+@@ -97,7 +96,6 @@ dnf_repo_finalize(GObject *object)
+     DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ 
+     g_free(priv->filename);
+-    g_strfreev(priv->gpgkeys);
+     g_strfreev(priv->exclude_packages);
+     g_free(priv->location_tmp);
+     g_free(priv->location);
+@@ -225,16 +223,13 @@ gchar **
+ dnf_repo_get_public_keys(DnfRepo *repo)
+ {
+     DnfRepoPrivate *priv = GET_PRIVATE(repo);
+-    g_autoptr(GPtrArray) ret = g_ptr_array_new();
+-    for (char **iter = priv->gpgkeys; iter && *iter; iter++) {
+-        const char *key = *iter;
+-        g_autofree gchar *key_bn = g_path_get_basename(key);
+-        /* transfer ownership to ptrarray */
+-        g_ptr_array_add(ret, g_build_filename(priv->location, key_bn, NULL));
++    const auto & keys = priv->repo->getConfig()->gpgkey().getValue();
++    gchar **ret = g_new0(gchar *, keys.size() + 1);
++    for (size_t i = 0; i < keys.size(); ++i) {
++        g_autofree gchar *key_bn = g_path_get_basename(keys[i].c_str());
++        ret[i] = g_build_filename(priv->location, key_bn, NULL);
+     }
+-    g_ptr_array_add(ret, NULL);
+-    /* transfer ownership of container and elements to caller */
+-    return (gchar**)g_ptr_array_free(static_cast<GPtrArray *>(g_steal_pointer(&ret)), FALSE);
++    return ret;
+ }
+ 
+ /**
+@@ -1014,22 +1009,9 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+         dnf_repo_set_location_tmp(repo, tmp->str);
+     }
+ 
+-    // Sync priv->gpgkeys
+-    g_strfreev(priv->gpgkeys);
+-    auto & repoGpgkeys = conf->gpgkey().getValue();
+-    if (!repoGpgkeys.empty()){
+-        auto len = repoGpgkeys.size();
+-        priv->gpgkeys = g_new0(char *, len + 1);
+-        for (size_t i = 0; i < len; ++i) {
+-            priv->gpgkeys[i] = g_strdup(repoGpgkeys[i].c_str());
+-        }
+-    } else {
+-        priv->gpgkeys = NULL;
+-    }
+-
+     /* gpgkey is optional for gpgcheck=1, but required for repo_gpgcheck=1 */
+-    auto gpgcheck_md = priv->repo->getConfig()->repo_gpgcheck().getValue();
+-    if (gpgcheck_md && priv->gpgkeys == NULL) {
++    auto repo_gpgcheck = conf->repo_gpgcheck().getValue();
++    if (repo_gpgcheck && conf->gpgkey().getValue().empty()) {
+         g_set_error_literal(error,
+                             DNF_ERROR,
+                             DNF_ERROR_FILE_INVALID,
+@@ -1038,7 +1020,7 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error)
+     }
+ 
+     /* XXX: setopt() expects a long, so we need a long on the stack */
+-    if (!lr_handle_setopt(priv->repo_handle, error, LRO_GPGCHECK, (long)gpgcheck_md))
++    if (!lr_handle_setopt(priv->repo_handle, error, LRO_GPGCHECK, (long)repo_gpgcheck))
+         return FALSE;
+ 
+     // Sync priv->exclude_packages
+@@ -1750,28 +1732,31 @@ dnf_repo_update(DnfRepo *repo,
+         goto out;
+     }
+ 
+-    if (priv->gpgkeys &&
+-        (priv->repo->getConfig()->repo_gpgcheck().getValue() || priv->repo->getConfig()->gpgcheck().getValue())) {
+-        for (char **iter = priv->gpgkeys; iter && *iter; iter++) {
+-            const char *gpgkey = *iter;
+-            g_autofree char *gpgkey_name = g_path_get_basename(gpgkey);
+-            g_autofree char *key_tmp = g_build_filename(priv->location_tmp, gpgkey_name, NULL);
+-
+-            /* download and import public key */
+-            if ((g_str_has_prefix(gpgkey, "https://") ||
+-                  g_str_has_prefix(gpgkey, "file://"))) {
+-                g_debug("importing public key %s", gpgkey);
+-
+-                ret = dnf_repo_download_import_public_key(repo, gpgkey, key_tmp, error);
+-                if (!ret)
+-                    goto out;
+-            }
++    {
++        const auto & gpgkeys = priv->repo->getConfig()->gpgkey().getValue();
++        if (!gpgkeys.empty() &&
++            (priv->repo->getConfig()->repo_gpgcheck().getValue() || priv->repo->getConfig()->gpgcheck().getValue())) {
++            for (const auto & key : gpgkeys) {
++                const char *gpgkey = key.c_str();
++                g_autofree char *gpgkey_name = g_path_get_basename(gpgkey);
++                g_autofree char *key_tmp = g_build_filename(priv->location_tmp, gpgkey_name, NULL);
++
++                /* download and import public key */
++                if ((g_str_has_prefix(gpgkey, "https://") ||
++                    g_str_has_prefix(gpgkey, "file://"))) {
++                    g_debug("importing public key %s", gpgkey);
++
++                    ret = dnf_repo_download_import_public_key(repo, gpgkey, key_tmp, error);
++                    if (!ret)
++                        goto out;
++                }
+ 
+-            /* do we autoimport this into librpm? */
+-            if ((flags & DNF_REPO_UPDATE_FLAG_IMPORT_PUBKEY) > 0) {
+-                ret = dnf_repo_add_public_key(repo, key_tmp, error);
+-                if (!ret)
+-                    goto out;
++                /* do we autoimport this into librpm? */
++                if ((flags & DNF_REPO_UPDATE_FLAG_IMPORT_PUBKEY) > 0) {
++                    ret = dnf_repo_add_public_key(repo, key_tmp, error);
++                    if (!ret)
++                        goto out;
++                }
+             }
+         }
+     }
diff --git a/SOURCES/0005-Allow-loading-incomplete-cache-and-loading-ext-solv-files-without-its-repodata.patch b/SOURCES/0005-Allow-loading-incomplete-cache-and-loading-ext-solv-files-without-its-repodata.patch
new file mode 100644
index 0000000..30421d4
--- /dev/null
+++ b/SOURCES/0005-Allow-loading-incomplete-cache-and-loading-ext-solv-files-without-its-repodata.patch
@@ -0,0 +1,134 @@
+From 816d18d826dc7134e553eae28f4aaca9a27e2307 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
+Date: Mon, 2 Nov 2020 11:43:19 +0100
+Subject: [PATCH 1/2] Allow loading ext metadata even if only cache (solv) is
+ present
+
+If we have a valid (checksum matches with repomd) solv file for
+requested type of metadata allow using it even if we no longer have the
+original xml metadata.
+---
+ libdnf/dnf-sack.cpp | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/libdnf/dnf-sack.cpp b/libdnf/dnf-sack.cpp
+index 6a43f01e3..608103d18 100644
+--- a/libdnf/dnf-sack.cpp
++++ b/libdnf/dnf-sack.cpp
+@@ -371,20 +371,9 @@ load_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
+     auto repoImpl = libdnf::repoGetImpl(hrepo);
+     Repo *repo = repoImpl->libsolvRepo;
+     const char *name = repo->name;
+-    auto fn = hrepo->getMetadataPath(which_filename);
+     FILE *fp;
+     gboolean done = FALSE;
+ 
+-    /* nothing set */
+-    if (fn.empty()) {
+-        g_set_error (error,
+-                     DNF_ERROR,
+-                     DNF_ERROR_NO_CAPABILITY,
+-                     _("no %1$s string for %2$s"),
+-                     which_filename, name);
+-        return FALSE;
+-    }
+-
+     char *fn_cache =  dnf_sack_give_cache_fn(sack, name, suffix);
+     fp = fopen(fn_cache, "r");
+     assert(libdnf::repoGetImpl(hrepo)->checksum);
+@@ -416,6 +405,17 @@ load_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
+     if (done)
+         return TRUE;
+ 
++    auto fn = hrepo->getMetadataPath(which_filename);
++    /* nothing set */
++    if (fn.empty()) {
++        g_set_error (error,
++                     DNF_ERROR,
++                     DNF_ERROR_NO_CAPABILITY,
++                     _("no %1$s string for %2$s"),
++                     which_filename, name);
++        return FALSE;
++    }
++
+     fp = solv_xfopen(fn.c_str(), "r");
+     if (fp == NULL) {
+         g_set_error (error,
+
+From aa2a372158f1b264708f960f387218deea17ef2a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
+Date: Thu, 10 Dec 2020 14:21:03 +0100
+Subject: [PATCH 2/2] Extend repo loadCache method with ignoreMissing parameter
+
+This allows loading even incomplete cache of xml files, only repomd.xml
+is requried.
+
+= changelog =
+msg: Extend repo loadCache method with ignoreMissing parameter to allow
+loading incomplete xml cache (repomd.xml is required).
+type: enhancement
+resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1865803
+---
+ VERSION.cmake                | 2 +-
+ libdnf.spec                  | 2 +-
+ libdnf/repo/Repo-private.hpp | 2 +-
+ libdnf/repo/Repo.cpp         | 8 ++++++--
+ libdnf/repo/Repo.hpp         | 2 +-
+ 5 files changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/libdnf/repo/Repo-private.hpp b/libdnf/repo/Repo-private.hpp
+index 1e4ea4d20..c2ce369dc 100644
+--- a/libdnf/repo/Repo-private.hpp
++++ b/libdnf/repo/Repo-private.hpp
+@@ -111,7 +111,7 @@ class Repo::Impl {
+     ~Impl();
+ 
+     bool load();
+-    bool loadCache(bool throwExcept);
++    bool loadCache(bool throwExcept, bool ignoreMissing=false);
+     void downloadMetadata(const std::string & destdir);
+     bool isInSync();
+     void fetch(const std::string & destdir, std::unique_ptr<LrHandle> && h);
+diff --git a/libdnf/repo/Repo.cpp b/libdnf/repo/Repo.cpp
+index 34539e1ee..84702c294 100644
+--- a/libdnf/repo/Repo.cpp
++++ b/libdnf/repo/Repo.cpp
+@@ -379,7 +379,7 @@ std::string Repo::getLocalBaseurl() const
+ }
+ 
+ bool Repo::load() { return pImpl->load(); }
+-bool Repo::loadCache(bool throwExcept) { return pImpl->loadCache(throwExcept); }
++bool Repo::loadCache(bool throwExcept, bool ignoreMissing) { return pImpl->loadCache(throwExcept, ignoreMissing); }
+ void Repo::downloadMetadata(const std::string & destdir) { pImpl->downloadMetadata(destdir); }
+ bool Repo::getUseIncludes() const { return pImpl->useIncludes; }
+ void Repo::setUseIncludes(bool enabled) { pImpl->useIncludes = enabled; }
+@@ -963,11 +963,15 @@ std::unique_ptr<LrResult> Repo::Impl::lrHandlePerform(LrHandle * handle, const s
+     return result;
+ }
+ 
+-bool Repo::Impl::loadCache(bool throwExcept)
++bool Repo::Impl::loadCache(bool throwExcept, bool ignoreMissing)
+ {
+     std::unique_ptr<LrHandle> h(lrHandleInitLocal());
+     std::unique_ptr<LrResult> r;
+ 
++    if (ignoreMissing) {
++        handleSetOpt(h.get(), LRO_IGNOREMISSING, 1L);
++    }
++
+     // Fetch data
+     try {
+         r = lrHandlePerform(h.get(), getCachedir(), conf->repo_gpgcheck().getValue());
+diff --git a/libdnf/repo/Repo.hpp b/libdnf/repo/Repo.hpp
+index eeec651c3..be376f60c 100644
+--- a/libdnf/repo/Repo.hpp
++++ b/libdnf/repo/Repo.hpp
+@@ -167,7 +167,7 @@ struct Repo {
+     * @return true if fresh metadata were downloaded, false otherwise.
+     */
+     bool load();
+-    bool loadCache(bool throwExcept);
++    bool loadCache(bool throwExcept, bool ignoreMissing=false);
+     void downloadMetadata(const std::string & destdir);
+     bool getUseIncludes() const;
+     void setUseIncludes(bool enabled);
diff --git a/SOURCES/0006-Add-new-option-module-stream-switch.patch b/SOURCES/0006-Add-new-option-module-stream-switch.patch
new file mode 100644
index 0000000..1a9cfd9
--- /dev/null
+++ b/SOURCES/0006-Add-new-option-module-stream-switch.patch
@@ -0,0 +1,53 @@
+From a1c96ecae6f2052407345a66293710109323de3a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
+Date: Tue, 21 Jul 2020 15:37:05 +0200
+Subject: [PATCH] Add new option module_stream_switch
+
+= changelog =
+msg: Add new options module_stream_switch
+type: enhancement
+---
+ libdnf/conf/ConfigMain.cpp | 3 +++
+ libdnf/conf/ConfigMain.hpp | 1 +
+ 2 files changed, 4 insertions(+)
+
+diff --git a/libdnf/conf/ConfigMain.cpp b/libdnf/conf/ConfigMain.cpp
+index 1ffd3b336..abfc2082b 100644
+--- a/libdnf/conf/ConfigMain.cpp
++++ b/libdnf/conf/ConfigMain.cpp
+@@ -278,6 +278,7 @@ class ConfigMain::Impl {
+     OptionBool downloadonly{false}; // runtime only option
+     OptionBool ignorearch{false};
+     OptionString module_platform_id{nullptr};
++    OptionBool module_stream_switch{false};
+ 
+     OptionString user_agent{getUserAgent()};
+     OptionBool countme{false};
+@@ -434,6 +435,7 @@ ConfigMain::Impl::Impl(Config & owner)
+     owner.optBinds().add("comment", comment);
+     owner.optBinds().add("ignorearch", ignorearch);
+     owner.optBinds().add("module_platform_id", module_platform_id);
++    owner.optBinds().add("module_stream_switch", module_stream_switch);
+     owner.optBinds().add("user_agent", user_agent);
+     owner.optBinds().add("countme", countme);
+     owner.optBinds().add("protect_running_kernel", protect_running_kernel);
+@@ -569,6 +571,7 @@ OptionBool & ConfigMain::downloadonly() { return pImpl->downloadonly; }
+ OptionBool & ConfigMain::ignorearch() { return pImpl->ignorearch; }
+ 
+ OptionString & ConfigMain::module_platform_id() { return pImpl->module_platform_id; }
++OptionBool & ConfigMain::module_stream_switch() { return pImpl->module_stream_switch; }
+ OptionString & ConfigMain::user_agent() { return pImpl->user_agent; }
+ OptionBool & ConfigMain::countme() { return pImpl->countme; }
+ OptionBool & ConfigMain::protect_running_kernel() {return pImpl->protect_running_kernel; }
+diff --git a/libdnf/conf/ConfigMain.hpp b/libdnf/conf/ConfigMain.hpp
+index 226c74d50..835e1fc65 100644
+--- a/libdnf/conf/ConfigMain.hpp
++++ b/libdnf/conf/ConfigMain.hpp
+@@ -125,6 +125,7 @@ class ConfigMain : public Config {
+     OptionBool & ignorearch();
+ 
+     OptionString & module_platform_id();
++    OptionBool & module_stream_switch();
+     OptionString & user_agent();
+     OptionBool & countme();
+     OptionBool & protect_running_kernel();
diff --git a/SOURCES/0007-Fix-removal-step-during-modular-enable-in-context-part.patch b/SOURCES/0007-Fix-removal-step-during-modular-enable-in-context-part.patch
new file mode 100644
index 0000000..d43bfcc
--- /dev/null
+++ b/SOURCES/0007-Fix-removal-step-during-modular-enable-in-context-part.patch
@@ -0,0 +1,23 @@
+From 831d023c3c6fb4a28903cb3170efdd9f85645e1a Mon Sep 17 00:00:00 2001
+From: Jaroslav Mracek <jmracek@redhat.com>
+Date: Fri, 20 Nov 2020 16:30:17 +0100
+Subject: [PATCH] Fix removal step during modular enable in context part
+
+It resolves `free(): double free detected in tcache 2`
+---
+ libdnf/dnf-context.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libdnf/dnf-context.cpp b/libdnf/dnf-context.cpp
+index 069267119..bc4a15b68 100644
+--- a/libdnf/dnf-context.cpp
++++ b/libdnf/dnf-context.cpp
+@@ -3087,7 +3087,7 @@ static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, s
+             }
+             for (auto iter = stream_dict.begin(); iter != stream_dict.end(); ) {
+                 if (iter->first != enabledOrDefaultStream) {
+-                    stream_dict.erase(iter);
++                    stream_dict.erase(iter++);
+                 } else {
+                     ++iter;
+                 }
diff --git a/SPECS/libdnf.spec b/SPECS/libdnf.spec
index 65f8aac..0fd799b 100644
--- a/SPECS/libdnf.spec
+++ b/SPECS/libdnf.spec
@@ -1,12 +1,14 @@
 %global libsolv_version 0.7.7
 %global libmodulemd_version 2.5.0
 %global librepo_version 1.12.0
-%global dnf_conflict 4.2.23
+%global dnf_conflict 4.3.0
 %global swig_version 3.0.12
 %global libdnf_major_version 0
-%global libdnf_minor_version 48
+%global libdnf_minor_version 55
 %global libdnf_micro_version 0
 
+%define __cmake_in_source_build 1
+
 # set sphinx package name according to distro
 %global requires_python2_sphinx python2-sphinx
 %global requires_python3_sphinx python3-sphinx
@@ -54,12 +56,19 @@
 
 Name:           libdnf
 Version:        %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version}
-Release:        2%{?dist}
+Release:        6%{?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-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch
+Patch0:         0001-Better-msgs-if-basecachedir-or-proxy-password-isn-t-set-RhBug-1888946.patch
+Patch1:         0002-modules-Add-special-handling-for-src-artifacts-RhBug-1809314.patch
+Patch2:         0003-Avoid-multilib-file-conflict-in-config.h-RhBug-1918818.patch
+Patch3:         0004-context-improve-retrieving-repository-configuration.patch
+Patch4:         0005-Allow-loading-incomplete-cache-and-loading-ext-solv-files-without-its-repodata.patch
+Patch5:         0006-Add-new-option-module-stream-switch.patch
+Patch6:         0007-Fix-removal-step-during-modular-enable-in-context-part.patch
+
 
 BuildRequires:  cmake
 BuildRequires:  gcc
@@ -307,6 +316,42 @@ popd
 %endif
 
 %changelog
+* Fri Feb 12 2021 Nicola Sella <nsella@redhat.com> - 0.55.0-6
+- Fix removal step during modular enable in context part
+
+* Thu Feb 11 2021 Nicola Sella <nsella@redhat.com> - 0.55.0-5
+- Add new option module_stream_switch
+
+* Mon Feb 08 2021 Nicola Sella <nsella@redhat.com> - 0.55.0-4
+- [context] improve retrieving repository configuration
+- Allow loading incomplete cache and loading ext solv files without its repodata
+
+* Fri Jan 29 2021 Nicola Sella <nsella@redhat.com> - 0.55.0-3
+- Avoid multilib file conflict in config.h (RhBug:1918818)
+- [modules] Add special handling for src artifacts (RhBug:1809314)
+
+* Fri Jan 15 2021 Nicola Sella <nsella@redhat.com> - 0.55.0-2
+- Better msgs if "basecachedir" or "proxy_password" isn't set (RhBug:1888946)
+
+* Mon Nov 09 2020 Nicola Sella <nsella@redhat.com> - 0.55.0-1
+- 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)
+
+* Thu Aug 20 2020 Nicola Sella <nsella@redhat.com> - 0.48.0-5
+- [covscan] Handle exception in a python binding by the proper function (RhBug:1870492)
+
+* Tue Jul 28 2020 Marek Blaha <mblaha@redhat.com> - 0.48.0-4
+- Update translations (RhBug:1820548)
+
+* Fri Jul 17 2020 Nicola Sella <nsella@redhat.com> - 0.48.0-3
+- Add log file level main config option (RhBug:1802074)
+- Accept '==' as an operator in reldeps (RhBug:1847946)
+
 * Wed Jun 10 2020 Ales Matej <amatej@redhat.com> - 0.48.0-2
 - [history] Fix dnf history rollback when a package was removed (RhBug:1683134)