Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of cacheonly functionality #665

Merged
merged 6 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 29 additions & 0 deletions dnf5/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include <libdnf5/logger/factory.hpp>
#include <libdnf5/logger/global_logger.hpp>
#include <libdnf5/logger/memory_buffer_logger.hpp>
#include <libdnf5/repo/repo_cache.hpp>
#include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
#include <libdnf5/version.hpp>
#include <string.h>
Expand Down Expand Up @@ -144,6 +145,34 @@ void RootCommand::set_argument_parser() {
});
global_options_group->register_argument(quiet);

auto cacheonly = parser.add_new_named_arg("cacheonly");
cacheonly->set_long_name("cacheonly");
cacheonly->set_short_name('C');
cacheonly->set_description(
"Run entirely from system cache, don't update the cache and use it even in case it is expired.");
cacheonly->set_const_value("all");
cacheonly->link_value(&config.get_cacheonly_option());
global_options_group->register_argument(cacheonly);

auto refresh = parser.add_new_named_arg("refresh");
refresh->set_long_name("refresh");
refresh->set_description("Force refreshing metadata before running the command.");
refresh->set_parse_hook_func([&ctx](
[[maybe_unused]] ArgumentParser::NamedArg * arg,
[[maybe_unused]] const char * option,
[[maybe_unused]] const char * value) {
std::filesystem::path cachedir{ctx.base.get_config().get_cachedir_option().get_value()};
std::error_code ec;
for (const auto & dir_entry : std::filesystem::directory_iterator(cachedir, ec)) {
libdnf5::repo::RepoCache cache(ctx.base.get_weak_ptr(), dir_entry.path());
cache.write_attribute(libdnf5::repo::RepoCache::ATTRIBUTE_EXPIRED);
}
return true;
});
global_options_group->register_argument(refresh);

refresh->add_conflict_argument(*cacheonly);

// --repofrompath argument
auto repofrompath = parser.add_new_named_arg("repofrompath");
repofrompath->set_long_name("repofrompath");
Expand Down
7 changes: 7 additions & 0 deletions doc/dnf5.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ Following options are applicable in the general context for any ``dnf5`` command
directly requested (e.g. as a command line arguments), and the solver may use older
versions of dependencies to meet their requirements.

``-C, --cacheonly``
| Use only cached data for working with packages and repository metadata.
| Cache won't be updated, even if it is expired.

``--comment=COMMENT``
| Add a comment to the transaction history.

Expand Down Expand Up @@ -205,6 +209,9 @@ Following options are applicable in the general context for any ``dnf5`` command
In combination with a non-interactive command, shows just the relevant content.
Suppresses messages notifying about the current state or actions of ``DNF5``.

``--refresh``
| Force refreshing metadata before running the command.

``--repo=REPO_ID,...``
| Enable just specified repositories.
| This is a list option which can be specified multiple times.
Expand Down
4 changes: 2 additions & 2 deletions include/libdnf5/conf/config_main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class ConfigMain : public Config {
const OptionBool & get_reset_nice_option() const;
OptionPath & get_system_cachedir_option();
const OptionPath & get_system_cachedir_option() const;
OptionBool & get_cacheonly_option();
const OptionBool & get_cacheonly_option() const;
OptionEnum<std::string> & get_cacheonly_option();
const OptionEnum<std::string> & get_cacheonly_option() const;
OptionBool & get_keepcache_option();
const OptionBool & get_keepcache_option() const;
OptionPath & get_logdir_option();
Expand Down
7 changes: 7 additions & 0 deletions include/libdnf5/repo/repo_errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ class RepoError : public Error {
};


class RepoCacheonlyError : public RepoError {
public:
using RepoError::RepoError;
const char * get_name() const noexcept override { return "RepoCacheonlyError"; }
};


class RepoDownloadError : public RepoError {
public:
using RepoError::RepoError;
Expand Down
6 changes: 3 additions & 3 deletions libdnf5/conf/config_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class ConfigMain::Impl {
OptionNumber<std::int32_t> recent{7, 0};
OptionBool reset_nice{true};
OptionPath system_cachedir{SYSTEM_CACHEDIR};
OptionBool cacheonly{false};
OptionEnum<std::string> cacheonly{"none", {"all", "metadata", "none"}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to document somewhere what each of these options actually does.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I guess that's an issue with all configuration options, the docs are missing so far: #309.

OptionBool keepcache{false};
OptionPath logdir{geteuid() == 0 ? "/var/log" : libdnf5::xdg::get_user_state_dir()};
OptionNumber<std::int32_t> log_size{1024 * 1024, str_to_bytes};
Expand Down Expand Up @@ -689,10 +689,10 @@ const OptionPath & ConfigMain::get_system_cachedir_option() const {
return p_impl->system_cachedir;
}

OptionBool & ConfigMain::get_cacheonly_option() {
OptionEnum<std::string> & ConfigMain::get_cacheonly_option() {
return p_impl->cacheonly;
}
const OptionBool & ConfigMain::get_cacheonly_option() const {
const OptionEnum<std::string> & ConfigMain::get_cacheonly_option() const {
return p_impl->cacheonly;
}

Expand Down
15 changes: 14 additions & 1 deletion libdnf5/repo/file_downloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "libdnf5/base/base.hpp"
#include "libdnf5/repo/download_callbacks.hpp"
#include "libdnf5/repo/repo.hpp"
#include "libdnf5/repo/repo_errors.hpp"
#include "libdnf5/utils/bgettext/bgettext-mark-domain.h"

#include <librepo/librepo.h>
Expand Down Expand Up @@ -132,11 +133,21 @@ void FileDownloader::add(const std::string & url, const std::string & destinatio
}

void FileDownloader::download() try {
if (p_impl->targets.empty()) {
return;
}

auto & config = p_impl->base->get_config();
auto & cacheonly = config.get_cacheonly_option().get_value();
if (cacheonly == "all") {
throw RepoCacheonlyError(M_("Cannot download files, cacheonly option is activated."));
}

std::vector<std::unique_ptr<LrDownloadTarget>> lr_targets;
lr_targets.reserve(p_impl->targets.size());

LibrepoHandle local_handle;
local_handle.init_remote(p_impl->base->get_config());
local_handle.init_remote(config);

auto * download_callbacks = p_impl->base->get_download_callbacks();

Expand Down Expand Up @@ -187,6 +198,8 @@ void FileDownloader::download() try {
if (!lr_download(list, p_impl->fail_fast, &err)) {
throw LibrepoError(std::unique_ptr<GError>(err));
}
} catch (const RepoCacheonlyError & e) {
throw;
} catch (const std::runtime_error & e) {
throw_with_nested(FileDownloadError(M_("Failed to download files")));
}
Expand Down
13 changes: 12 additions & 1 deletion libdnf5/repo/package_downloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "libdnf5/common/exception.hpp"
#include "libdnf5/repo/download_callbacks.hpp"
#include "libdnf5/repo/repo.hpp"
#include "libdnf5/repo/repo_errors.hpp"
#include "libdnf5/utils/bgettext/bgettext-mark-domain.h"

#include <librepo/librepo.h>
Expand Down Expand Up @@ -133,11 +134,20 @@ void PackageDownloader::download() try {
return;
}

auto & config = p_impl->base->get_config();
auto use_cache_only = config.get_cacheonly_option().get_value() == "all";

GError * err{nullptr};

std::vector<std::unique_ptr<LrPackageTarget>> lr_targets;
lr_targets.reserve(p_impl->targets.size());
for (auto & pkg_target : p_impl->targets) {
if (use_cache_only && !pkg_target.package.is_available_locally()) {
throw RepoCacheonlyError(
M_("Cannot download the \"{0}\" package, cacheonly option is activated."),
pkg_target.package.get_nevra());
}

std::filesystem::create_directory(pkg_target.destination);

if (auto * download_callbacks = pkg_target.package.get_base()->get_download_callbacks()) {
Expand Down Expand Up @@ -184,7 +194,6 @@ void PackageDownloader::download() try {
}

// Store file paths of packages we don't want to keep cached.
auto & config = p_impl->base->get_config();
auto removal_configured = !config.get_keepcache_option().get_value();
auto removal_enforced = p_impl->keep_packages.has_value() && !p_impl->keep_packages.value();
auto keep_enforced = p_impl->keep_packages.has_value() && p_impl->keep_packages.value();
Expand All @@ -207,6 +216,8 @@ void PackageDownloader::download() try {
if (!lr_download_packages(list, flags, &err)) {
throw LibrepoError(std::unique_ptr<GError>(err));
}
} catch (const RepoCacheonlyError & e) {
throw;
} catch (const std::runtime_error & e) {
throw_with_nested(PackageDownloadError(M_("Failed to download packages")));
}
Expand Down
4 changes: 4 additions & 0 deletions libdnf5/repo/repo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ Repo::Repo(const BaseWeakPtr & base, const std::string & id, Repo::Type type)
throw RepoError(M_("Invalid repository id \"{}\": unexpected character '{}'"), id, id[idx]);
}
}
auto & cacheonly = base->get_config().get_cacheonly_option().get_value();
if (cacheonly != "none") {
sync_strategy = SyncStrategy::ONLY_CACHE;
}
}

Repo::Repo(Base & base, const std::string & id, Repo::Type type) : Repo(base.get_weak_ptr(), id, type) {}
Expand Down
2 changes: 1 addition & 1 deletion test/python3/libdnf5/conf/test_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def test_set_get_by_attribute(self):
def test_writing_to_locked_option(self):
config = self.base.get_config()

option = config.get_cacheonly_option()
option = config.get_keepcache_option()
option.lock('')

self.assertRaises(RuntimeError, option.set, False)
Expand Down