Skip to content

Commit

Permalink
Move offline from dnf5 to libdnf5
Browse files Browse the repository at this point in the history
We will need to share the code also with dnf5daemon-server to support
offline upgrades using D-Bus API.
  • Loading branch information
m-blaha committed May 30, 2024
1 parent 1b7b9e3 commit 76abaa4
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 137 deletions.
33 changes: 17 additions & 16 deletions dnf5/commands/offline/offline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include <libdnf5/base/goal.hpp>
#include <libdnf5/conf/const.hpp>
#include <libdnf5/conf/option_path.hpp>
#include <libdnf5/transaction/offline.hpp>
#include <libdnf5/utils/bgettext/bgettext-lib.h>
#include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
#include <sys/wait.h>
Expand All @@ -45,7 +46,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

using namespace libdnf5::cli;

const std::string & ID_TO_IDENTIFY_BOOTS = dnf5::offline::OFFLINE_STARTED_ID;
const std::string & ID_TO_IDENTIFY_BOOTS = libdnf5::offline::OFFLINE_STARTED_ID;

const std::string SYSTEMD_DESTINATION_NAME{"org.freedesktop.systemd1"};
const std::string SYSTEMD_OBJECT_PATH{"/org/freedesktop/systemd1"};
Expand Down Expand Up @@ -207,12 +208,12 @@ void OfflineSubcommand::configure() {
magic_symlink = "/system-update";

const std::filesystem::path installroot = ctx.get_base().get_config().get_installroot_option().get_value();
datadir = installroot / dnf5::offline::DEFAULT_DATADIR.relative_path();
datadir = installroot / libdnf5::offline::DEFAULT_DATADIR.relative_path();
std::filesystem::create_directories(datadir);
state = std::make_optional<dnf5::offline::OfflineTransactionState>(datadir / "offline-transaction-state.toml");
state = std::make_optional<libdnf5::offline::OfflineTransactionState>(datadir / "offline-transaction-state.toml");
}

void check_state(const dnf5::offline::OfflineTransactionState & state) {
void check_state(const libdnf5::offline::OfflineTransactionState & state) {
const auto & read_exception = state.get_read_exception();
if (read_exception != nullptr) {
try {
Expand Down Expand Up @@ -296,8 +297,8 @@ void OfflineRebootCommand::run() {

check_state(*state);

if (state->get_data().status != dnf5::offline::STATUS_DOWNLOAD_COMPLETE &&
state->get_data().status != dnf5::offline::STATUS_READY) {
if (state->get_data().status != libdnf5::offline::STATUS_DOWNLOAD_COMPLETE &&
state->get_data().status != libdnf5::offline::STATUS_READY) {
throw libdnf5::cli::CommandExitError(1, M_("System is not ready for offline transaction."));
}
if (!std::filesystem::is_directory(get_datadir())) {
Expand Down Expand Up @@ -350,14 +351,14 @@ void OfflineRebootCommand::run() {
std::filesystem::create_symlink(get_datadir(), get_magic_symlink());
}

state->get_data().status = dnf5::offline::STATUS_READY;
state->get_data().status = libdnf5::offline::STATUS_READY;
state->get_data().poweroff_after = poweroff_after->get_value();
state->write();

dnf5::offline::log_status(
ctx,
"Rebooting to perform offline transaction.",
dnf5::offline::REBOOT_REQUESTED_ID,
libdnf5::offline::REBOOT_REQUESTED_ID,
system_releasever,
target_releasever);

Expand Down Expand Up @@ -427,7 +428,7 @@ void OfflineExecuteCommand::run() {
dnf5::offline::log_status(
ctx,
"Starting offline transaction. This will take a while.",
dnf5::offline::OFFLINE_STARTED_ID,
libdnf5::offline::OFFLINE_STARTED_ID,
system_releasever,
target_releasever);

Expand All @@ -438,15 +439,15 @@ void OfflineExecuteCommand::run() {

std::filesystem::remove(get_magic_symlink());

if (state->get_data().status != dnf5::offline::STATUS_READY) {
if (state->get_data().status != libdnf5::offline::STATUS_READY) {
throw libdnf5::cli::CommandExitError(1, M_("Use `dnf5 offline reboot` to begin the transaction."));
}

state->get_data().status = dnf5::offline::STATUS_TRANSACTION_INCOMPLETE;
state->get_data().status = libdnf5::offline::STATUS_TRANSACTION_INCOMPLETE;
state->write();

const auto & installroot = ctx.get_base().get_config().get_installroot_option().get_value();
const auto & datadir = installroot / dnf5::offline::DEFAULT_DATADIR.relative_path();
const auto & datadir = installroot / libdnf5::offline::DEFAULT_DATADIR.relative_path();
std::filesystem::create_directories(datadir);
const auto & transaction_json_path = datadir / "transaction.json";

Expand Down Expand Up @@ -514,7 +515,7 @@ void OfflineExecuteCommand::run() {

plymouth.message(_(transaction_complete_message.c_str()));
dnf5::offline::log_status(
ctx, transaction_complete_message, dnf5::offline::OFFLINE_FINISHED_ID, system_releasever, target_releasever);
ctx, transaction_complete_message, libdnf5::offline::OFFLINE_FINISHED_ID, system_releasever, target_releasever);

// If the transaction succeeded, remove downloaded data
clean_datadir(ctx, get_datadir());
Expand Down Expand Up @@ -674,13 +675,13 @@ void OfflineStatusCommand::run() {
check_state(*state);

const auto & status = state->get_data().status;
if (status == offline::STATUS_DOWNLOAD_INCOMPLETE) {
if (status == libdnf5::offline::STATUS_DOWNLOAD_INCOMPLETE) {
std::cout << no_transaction_message << std::endl;
} else if (status == offline::STATUS_DOWNLOAD_COMPLETE || status == offline::STATUS_READY) {
} else if (status == libdnf5::offline::STATUS_DOWNLOAD_COMPLETE || status == libdnf5::offline::STATUS_READY) {
std::cout << _("An offline transaction was initiated by the following command:") << std::endl
<< "\t" << state->get_data().cmd_line << std::endl
<< _("Run `dnf5 offline reboot` to reboot and perform the offline transaction.") << std::endl;
} else if (status == offline::STATUS_TRANSACTION_INCOMPLETE) {
} else if (status == libdnf5::offline::STATUS_TRANSACTION_INCOMPLETE) {
std::cout << _("An offline transaction was started, but it did not finish. Run `dnf5 offline log` for more "
"information. The command that initiated the transaction was:")
<< std::endl
Expand Down
4 changes: 2 additions & 2 deletions dnf5/commands/offline/offline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#define DNF5_COMMANDS_OFFLINE_HPP

#include <dnf5/context.hpp>
#include <dnf5/offline.hpp>
#include <libdnf5/conf/const.hpp>
#include <libdnf5/conf/option_bool.hpp>
#include <libdnf5/conf/option_number.hpp>
#include <libdnf5/transaction/offline.hpp>

const std::filesystem::path PATH_TO_PLYMOUTH{"/usr/bin/plymouth"};
const std::filesystem::path PATH_TO_JOURNALCTL{"/usr/bin/journalctl"};
Expand All @@ -48,7 +48,7 @@ class OfflineSubcommand : public Command {
protected:
std::filesystem::path get_magic_symlink() const { return magic_symlink; };
std::filesystem::path get_datadir() const { return datadir; };
std::optional<dnf5::offline::OfflineTransactionState> state;
std::optional<libdnf5::offline::OfflineTransactionState> state;

private:
std::filesystem::path magic_symlink;
Expand Down
4 changes: 2 additions & 2 deletions dnf5/commands/system-upgrade/system-upgrade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#define DNF5_COMMANDS_SYSTEM_UPGRADE_HPP

#include <dnf5/context.hpp>
#include <dnf5/offline.hpp>
#include <libdnf5/transaction/offline.hpp>

namespace dnf5 {

Expand All @@ -43,7 +43,7 @@ class SystemUpgradeDownloadCommand : public Command {

private:
libdnf5::OptionBool * no_downgrade{nullptr};
std::filesystem::path datadir{dnf5::offline::DEFAULT_DATADIR};
std::filesystem::path datadir{libdnf5::offline::DEFAULT_DATADIR};
std::string target_releasever;
std::string system_releasever;
};
Expand Down
16 changes: 8 additions & 8 deletions dnf5/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

#include "dnf5/context.hpp"

#include "dnf5/offline.hpp"
#include "download_callbacks.hpp"
#include "plugins.hpp"
#include "utils/string.hpp"
Expand All @@ -37,6 +36,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include <libdnf5/rpm/package_query.hpp>
#include <libdnf5/rpm/package_set.hpp>
#include <libdnf5/rpm/rpm_signature.hpp>
#include <libdnf5/transaction/offline.hpp>
#include <libdnf5/utils/bgettext/bgettext-lib.h>
#include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
#include <libdnf5/utils/fs/file.hpp>
Expand Down Expand Up @@ -309,18 +309,18 @@ void Context::Impl::load_repos(bool load_system) {

void Context::Impl::store_offline(libdnf5::base::Transaction & transaction) {
const auto & installroot = base.get_config().get_installroot_option().get_value();
const auto & offline_datadir = installroot / dnf5::offline::DEFAULT_DATADIR.relative_path();
const auto & offline_datadir = installroot / libdnf5::offline::DEFAULT_DATADIR.relative_path();
std::filesystem::create_directories(offline_datadir);

constexpr const char * packages_in_trans_dir{"./packages"};
const auto & packages_location = offline_datadir / packages_in_trans_dir;
constexpr const char * comps_in_trans_dir{"./comps"};
const auto & comps_location = offline_datadir / comps_in_trans_dir;

const std::filesystem::path state_path{offline_datadir / dnf5::offline::TRANSACTION_STATE_FILENAME};
dnf5::offline::OfflineTransactionState state{state_path};
const std::filesystem::path state_path{offline_datadir / libdnf5::offline::TRANSACTION_STATE_FILENAME};
libdnf5::offline::OfflineTransactionState state{state_path};

if (state.get_data().status != dnf5::offline::STATUS_DOWNLOAD_INCOMPLETE) {
if (state.get_data().status != libdnf5::offline::STATUS_DOWNLOAD_INCOMPLETE) {
std::cout << "There is already an offline transaction queued, initiated by the following command:" << std::endl
<< "\t" << state.get_data().cmd_line << std::endl
<< "Continuing will cancel the old offline transaction and replace it with this one." << std::endl;
Expand All @@ -329,7 +329,7 @@ void Context::Impl::store_offline(libdnf5::base::Transaction & transaction) {
}
}

state.get_data().status = dnf5::offline::STATUS_DOWNLOAD_INCOMPLETE;
state.get_data().status = libdnf5::offline::STATUS_DOWNLOAD_INCOMPLETE;
state.write();

// First, serialize the transaction
Expand Down Expand Up @@ -369,7 +369,7 @@ void Context::Impl::store_offline(libdnf5::base::Transaction & transaction) {

// Download and transaction test complete. Fill out entries in offline
// transaction state file.
state.get_data().status = dnf5::offline::STATUS_DOWNLOAD_COMPLETE;
state.get_data().status = libdnf5::offline::STATUS_DOWNLOAD_COMPLETE;
state.get_data().cachedir = base.get_config().get_cachedir_option().get_value();

std::vector<std::string> command_vector;
Expand Down Expand Up @@ -424,7 +424,7 @@ void Context::Impl::download_and_run(libdnf5::base::Transaction & transaction) {

if (should_store_offline) {
const auto & installroot = base.get_config().get_installroot_option().get_value();
const auto & offline_datadir = installroot / dnf5::offline::DEFAULT_DATADIR.relative_path();
const auto & offline_datadir = installroot / libdnf5::offline::DEFAULT_DATADIR.relative_path();
std::filesystem::create_directories(offline_datadir);

base.get_config().get_destdir_option().set(offline_datadir / "packages");
Expand Down
66 changes: 2 additions & 64 deletions dnf5/include/dnf5/offline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,61 +20,11 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#ifndef DNF5_OFFLINE_HPP
#define DNF5_OFFLINE_HPP

#include "dnf5/version.hpp"

#include <dnf5/context.hpp>
#include <libdnf5/conf/const.hpp>
#include <libdnf5/conf/option_bool.hpp>
#include <libdnf5/conf/option_number.hpp>
#include <toml.hpp>

namespace dnf5::offline {

// Unique identifiers used to mark and identify system-upgrade boots in
// journald logs. These are the same as they are in `dnf4 system-upgrade`, so
// `dnf5 offline log` will find offline transactions performed by DNF 4 and
// vice-versa.
const std::string REBOOT_REQUESTED_ID{"9348174c5cc74001a71ef26bd79d302e"};
const std::string OFFLINE_STARTED_ID{"3e0a5636d16b4ca4bbe5321d06c6aa62"};
const std::string OFFLINE_FINISHED_ID{"8cec00a1566f4d3594f116450395f06c"};

const std::string STATUS_DOWNLOAD_INCOMPLETE{"download-incomplete"};
const std::string STATUS_DOWNLOAD_COMPLETE{"download-complete"};
const std::string STATUS_READY{"ready"};
const std::string STATUS_TRANSACTION_INCOMPLETE{"transaction-incomplete"};

const int STATE_VERSION = 1;
const std::string STATE_HEADER{"offline-transaction-state"};
#include <string>

const std::filesystem::path DEFAULT_DATADIR{std::filesystem::path(libdnf5::SYSTEM_STATE_DIR) / "offline"};
const std::filesystem::path TRANSACTION_STATE_FILENAME{"offline-transaction-state.toml"};

struct OfflineTransactionStateData {
int state_version = STATE_VERSION;
std::string status = STATUS_DOWNLOAD_INCOMPLETE;
std::string cachedir;
std::string target_releasever;
std::string system_releasever;
std::string verb;
std::string cmd_line;
bool poweroff_after = false;
std::string module_platform_id;
};

class OfflineTransactionState {
public:
void write();
OfflineTransactionState(std::filesystem::path path);
OfflineTransactionStateData & get_data();
const std::exception_ptr & get_read_exception() const;
std::filesystem::path get_path() const;

private:
void read();
std::exception_ptr read_exception;
std::filesystem::path path;
OfflineTransactionStateData data;
};
namespace dnf5::offline {

void log_status(
Context & context,
Expand All @@ -85,16 +35,4 @@ void log_status(

} // namespace dnf5::offline

TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(
dnf5::offline::OfflineTransactionStateData,
state_version,
status,
cachedir,
target_releasever,
system_releasever,
verb,
cmd_line,
poweroff_after,
module_platform_id)

#endif // DNF5_OFFLINE_HPP
45 changes: 0 additions & 45 deletions dnf5/offline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,57 +19,12 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

#include "dnf5/offline.hpp"

#include "libdnf5/common/exception.hpp"

#include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
#include <libdnf5/utils/fs/file.hpp>

#ifdef WITH_SYSTEMD
#include <systemd/sd-journal.h>
#endif

namespace dnf5::offline {

OfflineTransactionState::OfflineTransactionState(std::filesystem::path path) : path(std::move(path)) {
read();
}

OfflineTransactionStateData & OfflineTransactionState::get_data() {
return data;
}

const std::exception_ptr & OfflineTransactionState::get_read_exception() const {
return read_exception;
}

std::filesystem::path OfflineTransactionState::get_path() const {
return path;
}


void OfflineTransactionState::read() {
try {
const std::ifstream file{path};
if (!file.good()) {
throw libdnf5::FileSystemError(errno, path, M_("error reading offline state file"));
}
const auto & value = toml::parse(path);
data = toml::find<OfflineTransactionStateData>(value, STATE_HEADER);
if (data.state_version != STATE_VERSION) {
throw libdnf5::RuntimeError(M_("incompatible version of state data"));
}
} catch (const std::exception & ex) {
read_exception = std::current_exception();
data = OfflineTransactionStateData{};
}
}

void OfflineTransactionState::write() {
auto file = libdnf5::utils::fs::File(path, "w");
file.write(toml::format(toml::value{{STATE_HEADER, data}}));
file.close();
}

void log_status(
Context & context,
const std::string & message,
Expand Down
Loading

0 comments on commit 76abaa4

Please sign in to comment.