Bind output core into Rust, use in apply-live
Originally the Rust apply-live code was exposed from Rust to C via bindgen. But when working on that, I hit the problem that our output infrastructure was C...and the "reverse direction" binding stuff was just ugly. This PR again IMO shows the value of the investment in cxx-rs because we can now seamlessly call back from the Rust side into a "C++-ish" progress API, which the C++ side is updated to use. The level of indirection here is obviously pretty silly because the main thing on the C++ output side is basically a function dispatcher, but...I didn't want to try to rework that into Rust fully yet. (But, the moment we do this whole area will get a *lot* cleaner) Anyways, in the end this makes it easy for the apply-live code to output progress to the user which was sorely needed.
This commit is contained in:
parent
c9e9269770
commit
2f6b5a654d
@ -226,6 +226,14 @@ pub mod ffi {
|
||||
fn main_print_error(msg: &str);
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("rpmostree-output.h");
|
||||
type Progress;
|
||||
|
||||
fn progress_begin_task(msg: &str) -> UniquePtr<Progress>;
|
||||
fn end(self: Pin<&mut Progress>, msg: &str);
|
||||
}
|
||||
|
||||
// rpmostree-rpm-util.h
|
||||
unsafe extern "C++" {
|
||||
include!("rpmostree-rpm-util.h");
|
||||
|
@ -445,17 +445,22 @@ pub(crate) fn transaction_apply_live(
|
||||
|
||||
// Gather the current diff of /etc - we need to avoid changing
|
||||
// any files which are locally modified.
|
||||
let task = crate::ffi::progress_begin_task("Computing /etc diff to preserve");
|
||||
let config_diff = {
|
||||
let usretc = &rootfs_dfd.sub_dir("usr/etc")?;
|
||||
let etc = &rootfs_dfd.sub_dir("etc")?;
|
||||
crate::dirdiff::diff(usretc, etc)?
|
||||
};
|
||||
println!("Computed /etc diff: {}", &config_diff);
|
||||
std::mem::drop(task);
|
||||
|
||||
// The heart of things: updating the overlayfs on /usr
|
||||
let task = crate::ffi::progress_begin_task("Updating /usr");
|
||||
apply_diff(repo, &diff, &target_commit, &openat::Dir::open("/usr")?)?;
|
||||
std::mem::drop(task);
|
||||
|
||||
// The other important bits are /etc and /var
|
||||
let task = crate::ffi::progress_begin_task("Updating /etc");
|
||||
update_etc(
|
||||
repo,
|
||||
&diff,
|
||||
@ -464,7 +469,10 @@ pub(crate) fn transaction_apply_live(
|
||||
&target_commit,
|
||||
&openat::Dir::open("/etc")?,
|
||||
)?;
|
||||
std::mem::drop(task);
|
||||
let task = crate::ffi::progress_begin_task("Running systemd-tmpfiles for /var");
|
||||
rerun_tmpfiles()?;
|
||||
std::mem::drop(task);
|
||||
|
||||
// Success! Update the recorded state.
|
||||
state.commit = target_commit.to_string();
|
||||
|
@ -192,14 +192,14 @@ pub(crate) fn console_progress_begin_percent(msg: &str) {
|
||||
|
||||
pub(crate) fn console_progress_set_message(msg: &str) {
|
||||
let mut lock = PROGRESS.lock().unwrap();
|
||||
let state = lock.as_mut().expect("progress to update");
|
||||
let state = lock.as_mut().expect("progress to set message");
|
||||
state.set_message(msg);
|
||||
}
|
||||
|
||||
pub(crate) fn console_progress_set_sub_message(msg: &str) {
|
||||
let msg = optional_str(msg);
|
||||
let mut lock = PROGRESS.lock().unwrap();
|
||||
let state = lock.as_mut().expect("progress to update");
|
||||
let state = lock.as_mut().expect("progress sub-msg update");
|
||||
state.set_sub_message(msg);
|
||||
}
|
||||
|
||||
|
@ -559,8 +559,8 @@ checkout_base_tree (RpmOstreeSysrootUpgrader *self,
|
||||
return TRUE; /* already checked out! */
|
||||
|
||||
/* let's give the user some feedback so they don't think we're blocked */
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Checking out tree %.7s", self->base_revision);
|
||||
auto msg = g_strdup_printf ("Checking out tree %.7s", self->base_revision);
|
||||
auto task = rpmostreecxx::progress_begin_task(msg);
|
||||
|
||||
int repo_dfd = ostree_repo_get_dfd (self->repo); /* borrowed */
|
||||
/* Always delete this */
|
||||
@ -1168,8 +1168,7 @@ perform_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
g_ptr_array_add (initramfs_args, g_strdup (*it));
|
||||
g_ptr_array_add (initramfs_args, NULL);
|
||||
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Generating initramfs");
|
||||
auto task = rpmostreecxx::progress_begin_task("Generating initramfs");
|
||||
|
||||
g_assert (kernel_state && kernel_path);
|
||||
|
||||
@ -1490,8 +1489,7 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
|
||||
_OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED);
|
||||
}
|
||||
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Staging deployment");
|
||||
auto task = rpmostreecxx::progress_begin_task("Staging deployment");
|
||||
if (!ostree_sysroot_stage_tree_with_options (self->sysroot, self->osname,
|
||||
target_revision, origin,
|
||||
self->cfg_merge_deployment,
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "libglnx.h"
|
||||
#include "rpmostree-rojig-core.h"
|
||||
#include "rpmostree-core.h"
|
||||
#include "rpmostree-output.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -63,6 +64,7 @@ struct _RpmOstreeContext {
|
||||
guint n_async_max;
|
||||
gboolean async_running;
|
||||
GCancellable *async_cancellable;
|
||||
std::unique_ptr<rpmostreecxx::Progress> async_progress;
|
||||
GError *async_error;
|
||||
GPtrArray *pkgs; /* All packages */
|
||||
GPtrArray *pkgs_to_download;
|
||||
|
@ -882,7 +882,8 @@ on_hifstate_percentage_changed (DnfState *hifstate,
|
||||
guint percentage,
|
||||
gpointer user_data)
|
||||
{
|
||||
rpmostree_output_progress_percent (percentage);
|
||||
auto progress = (rpmostreecxx::Progress*)user_data;
|
||||
progress->percent_update(percentage);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -1162,18 +1163,18 @@ rpmostree_context_download_metadata (RpmOstreeContext *self,
|
||||
NULL))
|
||||
{
|
||||
dnf_state_reset (hifstate);
|
||||
auto msg = g_strdup_printf ("Updating metadata for '%s'", dnf_repo_get_id (repo));
|
||||
auto progress = rpmostreecxx::progress_percent_begin(msg);
|
||||
guint progress_sigid = g_signal_connect (hifstate, "percentage-changed",
|
||||
G_CALLBACK (on_hifstate_percentage_changed),
|
||||
NULL);
|
||||
g_auto(RpmOstreeProgress) progress = { 0, };
|
||||
rpmostree_output_progress_percent_begin (&progress, "Updating metadata for '%s'",
|
||||
dnf_repo_get_id (repo));
|
||||
(void*)progress.get());
|
||||
if (!dnf_repo_update (repo, DNF_REPO_UPDATE_FLAG_FORCE, hifstate, error))
|
||||
return glnx_prefix_error (error, "Updating rpm-md repo '%s'", dnf_repo_get_id (repo));
|
||||
|
||||
did_update = TRUE;
|
||||
|
||||
g_signal_handler_disconnect (hifstate, progress_sigid);
|
||||
progress->end("");
|
||||
}
|
||||
|
||||
guint64 ts = dnf_repo_get_timestamp_generated (repo);
|
||||
@ -1188,11 +1189,10 @@ rpmostree_context_download_metadata (RpmOstreeContext *self,
|
||||
|
||||
/* The _setup_sack function among other things imports the metadata into libsolv */
|
||||
{ g_autoptr(DnfState) hifstate = dnf_state_new ();
|
||||
auto progress = rpmostreecxx::progress_percent_begin("Importing rpm-md");
|
||||
guint progress_sigid = g_signal_connect (hifstate, "percentage-changed",
|
||||
G_CALLBACK (on_hifstate_percentage_changed),
|
||||
NULL);
|
||||
g_auto(RpmOstreeProgress) progress = { 0, };
|
||||
rpmostree_output_progress_percent_begin (&progress, "Importing rpm-md");
|
||||
(void*)progress.get());
|
||||
|
||||
/* We already explictly checked the repos above; don't try to check them
|
||||
* again.
|
||||
@ -2247,8 +2247,7 @@ rpmostree_context_prepare (RpmOstreeContext *self,
|
||||
if (!recommends)
|
||||
actions = static_cast<DnfGoalActions>(static_cast<int>(actions) | DNF_IGNORE_WEAK_DEPS);
|
||||
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Resolving dependencies");
|
||||
auto task = rpmostreecxx::progress_begin_task("Resolving dependencies");
|
||||
|
||||
/* XXX: consider a --allow-uninstall switch? */
|
||||
if (!dnf_goal_depsolve (goal, actions, error) ||
|
||||
@ -2479,22 +2478,18 @@ rpmostree_download_packages (GPtrArray *packages,
|
||||
g_autoptr(GHashTable) source_to_packages = gather_source_to_packages (packages);
|
||||
GLNX_HASH_TABLE_FOREACH_KV (source_to_packages, DnfRepo*, src, GPtrArray*, src_packages)
|
||||
{
|
||||
g_autofree char *target_dir = NULL;
|
||||
glnx_unref_object DnfState *hifstate = dnf_state_new ();
|
||||
|
||||
auto msg = g_strdup_printf("Downloading from '%s'", dnf_repo_get_id(src));
|
||||
auto progress = rpmostreecxx::progress_percent_begin(msg);
|
||||
progress_sigid = g_signal_connect (hifstate, "percentage-changed",
|
||||
G_CALLBACK (on_hifstate_percentage_changed),
|
||||
NULL);
|
||||
g_auto(RpmOstreeProgress) progress = { 0, };
|
||||
rpmostree_output_progress_percent_begin (&progress, "Downloading from '%s'",
|
||||
dnf_repo_get_id (src));
|
||||
|
||||
target_dir = g_build_filename (dnf_repo_get_location (src), "/packages/", NULL);
|
||||
G_CALLBACK (on_hifstate_percentage_changed),
|
||||
(void*)progress.get());
|
||||
g_autofree char *target_dir = g_build_filename (dnf_repo_get_location (src), "/packages/", NULL);
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, target_dir, 0755, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!dnf_repo_download_packages (src, src_packages, target_dir,
|
||||
hifstate, error))
|
||||
hifstate, error))
|
||||
return FALSE;
|
||||
|
||||
g_signal_handler_disconnect (hifstate, progress_sigid);
|
||||
@ -2572,7 +2567,7 @@ on_async_import_done (GObject *obj,
|
||||
self->n_async_pkgs_imported++;
|
||||
g_assert_cmpint (self->n_async_running, >, 0);
|
||||
self->n_async_running--;
|
||||
rpmostree_output_progress_n_items (self->n_async_pkgs_imported);
|
||||
self->async_progress->nitems_update(self->n_async_pkgs_imported);
|
||||
async_imports_mainctx_iter (self);
|
||||
}
|
||||
|
||||
@ -2697,8 +2692,7 @@ rpmostree_context_import_rojig (RpmOstreeContext *self,
|
||||
self->n_async_max = g_get_num_processors ();
|
||||
self->async_cancellable = cancellable;
|
||||
|
||||
g_auto(RpmOstreeProgress) progress = { 0, };
|
||||
rpmostree_output_progress_nitems_begin (&progress, self->pkgs_to_import->len, "Importing packages");
|
||||
self->async_progress = rpmostreecxx::progress_nitems_begin(self->pkgs_to_import->len, "Importing packages");
|
||||
|
||||
/* Process imports */
|
||||
GMainContext *mainctx = g_main_context_get_thread_default ();
|
||||
@ -2717,7 +2711,8 @@ rpmostree_context_import_rojig (RpmOstreeContext *self,
|
||||
return glnx_prefix_error (error, "importing RPMs");
|
||||
}
|
||||
|
||||
rpmostree_output_progress_end (&progress);
|
||||
self->async_progress->end("");
|
||||
self->async_progress.release();
|
||||
|
||||
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
||||
return FALSE;
|
||||
@ -3448,7 +3443,7 @@ on_async_relabel_done (GObject *obj,
|
||||
data->n_changed_files += n_relabeled;
|
||||
data->n_changed_pkgs++;
|
||||
}
|
||||
rpmostree_output_progress_n_items (self->n_async_pkgs_relabeled);
|
||||
self->async_progress->nitems_update(self->n_async_pkgs_relabeled);
|
||||
if (self->n_async_pkgs_relabeled == self->pkgs_to_relabel->len)
|
||||
self->async_running = FALSE;
|
||||
}
|
||||
@ -3486,8 +3481,7 @@ relabel_if_necessary (RpmOstreeContext *self,
|
||||
|
||||
RpmOstreeAsyncRelabelData data = { self, 0, };
|
||||
const guint n_to_relabel = self->pkgs_to_relabel->len;
|
||||
g_auto(RpmOstreeProgress) progress = { 0, };
|
||||
rpmostree_output_progress_nitems_begin (&progress, n_to_relabel, "Relabeling");
|
||||
self->async_progress = rpmostreecxx::progress_nitems_begin(n_to_relabel, "Relabeling");
|
||||
for (guint i = 0; i < n_to_relabel; i++)
|
||||
{
|
||||
auto pkg = static_cast<DnfPackage *>(self->pkgs_to_relabel->pdata[i]);
|
||||
@ -3506,7 +3500,8 @@ relabel_if_necessary (RpmOstreeContext *self,
|
||||
return glnx_prefix_error (error, "relabeling");
|
||||
}
|
||||
|
||||
rpmostree_output_progress_end (&progress);
|
||||
self->async_progress->end("");
|
||||
self->async_progress.release();
|
||||
|
||||
/* Commit */
|
||||
if (!ostree_repo_commit_transaction (ostreerepo, NULL, cancellable, error))
|
||||
@ -4061,8 +4056,7 @@ process_ostree_layers (RpmOstreeContext *self,
|
||||
if (n == 0)
|
||||
return TRUE;
|
||||
|
||||
g_auto(RpmOstreeProgress) checkout_progress = { 0, };
|
||||
rpmostree_output_progress_nitems_begin (&checkout_progress, n, "Checking out ostree layers");
|
||||
auto progress = rpmostreecxx::progress_nitems_begin(n, "Checking out ostree layers");
|
||||
size_t i = 0;
|
||||
for (char **iter = layers; iter && *iter; iter++)
|
||||
{
|
||||
@ -4072,7 +4066,7 @@ process_ostree_layers (RpmOstreeContext *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
i++;
|
||||
rpmostree_output_progress_n_items (i);
|
||||
progress->nitems_update(i);
|
||||
}
|
||||
for (char **iter = override_layers; iter && *iter; iter++)
|
||||
{
|
||||
@ -4082,9 +4076,9 @@ process_ostree_layers (RpmOstreeContext *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
i++;
|
||||
rpmostree_output_progress_n_items (i);
|
||||
progress->nitems_update(i);
|
||||
}
|
||||
rpmostree_output_progress_end (&checkout_progress);
|
||||
progress->end("");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -4231,8 +4225,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
g_assert (n_rpmts_elements > 0);
|
||||
guint n_rpmts_done = 0;
|
||||
|
||||
g_auto(RpmOstreeProgress) checkout_progress = { 0, };
|
||||
rpmostree_output_progress_nitems_begin (&checkout_progress, n_rpmts_elements, "%s", progress_msg);
|
||||
auto progress = rpmostreecxx::progress_nitems_begin(n_rpmts_elements, progress_msg);
|
||||
|
||||
/* Okay so what's going on in Fedora with incestuous relationship
|
||||
* between the `filesystem`, `setup`, `libgcc` RPMs is actively
|
||||
@ -4246,7 +4239,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
*/
|
||||
if (filesystem_package)
|
||||
{
|
||||
rpmostree_output_set_sub_message ("filesystem");
|
||||
progress->set_sub_message("filesystem");
|
||||
auto c = static_cast<const char*>(g_hash_table_lookup (pkg_to_ostree_commit, filesystem_package));
|
||||
if (!checkout_package_into_root (self, filesystem_package,
|
||||
tmprootfs_dfd, ".", self->devino_cache,
|
||||
@ -4255,7 +4248,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
n_rpmts_done++;
|
||||
rpmostree_output_progress_n_items (n_rpmts_done);
|
||||
progress->nitems_update(n_rpmts_done);
|
||||
}
|
||||
|
||||
g_autoptr(GHashTable) files_skip_add = NULL;
|
||||
@ -4290,7 +4283,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
dirs_to_remove, cancellable, error))
|
||||
return FALSE;
|
||||
n_rpmts_done++;
|
||||
rpmostree_output_progress_n_items (n_rpmts_done);
|
||||
progress->nitems_update(n_rpmts_done);
|
||||
}
|
||||
g_clear_pointer (&files_skip_delete, g_hash_table_unref);
|
||||
|
||||
@ -4322,16 +4315,16 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
(pkg == setup_package) ? OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES :
|
||||
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL;
|
||||
|
||||
rpmostree_output_set_sub_message (dnf_package_get_name (pkg));
|
||||
progress->set_sub_message(dnf_package_get_name (pkg));
|
||||
if (!checkout_package_into_root (self, pkg, tmprootfs_dfd, ".", self->devino_cache,
|
||||
static_cast<const char*>(g_hash_table_lookup (pkg_to_ostree_commit, pkg)),
|
||||
files_skip_add, ovwmode, cancellable, error))
|
||||
return FALSE;
|
||||
n_rpmts_done++;
|
||||
rpmostree_output_progress_n_items (n_rpmts_done);
|
||||
progress->nitems_update(n_rpmts_done);
|
||||
}
|
||||
|
||||
rpmostree_output_progress_end (&checkout_progress);
|
||||
progress->end("");
|
||||
|
||||
/* Some packages expect to be able to make temporary files here
|
||||
* for obvious reasons, but we otherwise make `/var` read-only.
|
||||
@ -4431,8 +4424,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
* this way is that we only need to read the passwd/group files once
|
||||
* before applying the overrides, rather than after each %pre.
|
||||
*/
|
||||
{ g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Running pre scripts");
|
||||
{ auto task = rpmostreecxx::progress_begin_task("Running pre scripts");
|
||||
guint n_pre_scripts_run = 0;
|
||||
for (guint i = 0; i < n_rpmts_elements; i++)
|
||||
{
|
||||
@ -4443,13 +4435,14 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
DnfPackage *pkg = (DnfPackage*)rpmteKey (te);
|
||||
g_assert (pkg);
|
||||
|
||||
rpmostree_output_set_sub_message (dnf_package_get_name (pkg));
|
||||
task->set_sub_message(dnf_package_get_name(pkg));
|
||||
if (!run_script_sync (self, tmprootfs_dfd, &var_lib_rpm_statedir,
|
||||
pkg, RPMOSTREE_SCRIPT_PREIN,
|
||||
&n_pre_scripts_run, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
rpmostree_output_progress_end_msg (&task, "%u done", n_pre_scripts_run);
|
||||
auto msg = g_strdup_printf ("%u done", n_pre_scripts_run);
|
||||
task->end(msg);
|
||||
}
|
||||
|
||||
/* Now undo our hack above */
|
||||
@ -4492,8 +4485,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
}
|
||||
|
||||
{
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Running post scripts");
|
||||
auto task = rpmostreecxx::progress_begin_task("Running post scripts");
|
||||
guint n_post_scripts_run = 0;
|
||||
|
||||
/* %post */
|
||||
@ -4506,7 +4498,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
auto pkg = (DnfPackage *)(rpmteKey (te));
|
||||
g_assert (pkg);
|
||||
|
||||
rpmostree_output_set_sub_message (dnf_package_get_name (pkg));
|
||||
task->set_sub_message(dnf_package_get_name(pkg));
|
||||
if (!apply_rpmfi_overrides (self, tmprootfs_dfd, pkg, passwdents, groupents,
|
||||
cancellable, error))
|
||||
return glnx_prefix_error (error, "While applying overrides for pkg %s",
|
||||
@ -4524,8 +4516,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Running posttrans scripts");
|
||||
auto task = rpmostreecxx::progress_begin_task("Running posttrans scripts");
|
||||
guint n_posttrans_scripts_run = 0;
|
||||
|
||||
/* %posttrans */
|
||||
@ -4538,7 +4529,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
auto pkg = (DnfPackage *)(rpmteKey (te));
|
||||
g_assert (pkg);
|
||||
|
||||
rpmostree_output_set_sub_message (dnf_package_get_name (pkg));
|
||||
task->set_sub_message(dnf_package_get_name(pkg));
|
||||
if (!run_script_sync (self, tmprootfs_dfd, &var_lib_rpm_statedir,
|
||||
pkg, RPMOSTREE_SCRIPT_POSTTRANS,
|
||||
&n_posttrans_scripts_run, cancellable, error))
|
||||
@ -4550,7 +4541,8 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
&n_posttrans_scripts_run, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
rpmostree_output_progress_end_msg (&task, "%u done", n_posttrans_scripts_run);
|
||||
auto msg = g_strdup_printf ("%u done", n_posttrans_scripts_run);
|
||||
task->end(msg);
|
||||
}
|
||||
|
||||
/* We want this to be the first error message if something went wrong
|
||||
@ -4596,8 +4588,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
|
||||
g_clear_pointer (&ordering_ts, rpmtsFree);
|
||||
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Writing rpmdb");
|
||||
auto task = rpmostreecxx::progress_begin_task("Writing rpmdb");
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (tmprootfs_dfd, RPMOSTREE_RPMDB_LOCATION, 0755, cancellable, error))
|
||||
return FALSE;
|
||||
@ -4689,7 +4680,7 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rpmostree_output_progress_end (&task);
|
||||
task->end("");
|
||||
|
||||
/* And finally revert the _dbpath setting because libsolv relies on it as well
|
||||
* to find the rpmdb and RPM macros are global state. */
|
||||
@ -4717,8 +4708,7 @@ rpmostree_context_commit (RpmOstreeContext *self,
|
||||
g_autoptr(OstreeRepoCommitModifier) commit_modifier = NULL;
|
||||
g_autofree char *ret_commit_checksum = NULL;
|
||||
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Writing OSTree commit");
|
||||
auto task = rpmostreecxx::progress_begin_task("Writing OSTree commit");
|
||||
|
||||
g_auto(RpmOstreeRepoAutoTransaction) txn = { 0, };
|
||||
if (!rpmostree_repo_auto_transaction_start (&txn, self->ostreerepo, FALSE, cancellable, error))
|
||||
|
@ -20,8 +20,10 @@
|
||||
|
||||
#include <ostree.h>
|
||||
#include <libglnx.h>
|
||||
#include <memory>
|
||||
|
||||
#include "rpmostree-output.h"
|
||||
#include "rpmostree-util.h"
|
||||
#include "rpmostree-rust.h"
|
||||
#include "rpmostree-cxxrs.h"
|
||||
|
||||
@ -60,13 +62,13 @@ rpmostree_output_default_handler (RpmOstreeOutputType type,
|
||||
case RPMOSTREE_OUTPUT_PROGRESS_SUB_MESSAGE:
|
||||
{
|
||||
auto msg = static_cast<const char *>(data);
|
||||
rpmostreecxx::console_progress_set_sub_message (rust::Str(msg ?: ""));
|
||||
rpmostreecxx::console_progress_set_sub_message (util::ruststr_or_empty(msg));
|
||||
}
|
||||
break;
|
||||
case RPMOSTREE_OUTPUT_PROGRESS_END:
|
||||
{
|
||||
auto end = static_cast<RpmOstreeOutputProgressEnd *>(data);
|
||||
rpmostreecxx::console_progress_end (rust::Str(end->msg ?: ""));
|
||||
rpmostreecxx::console_progress_end (util::ruststr_or_empty(end->msg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -90,6 +92,9 @@ rpmostree_output_set_callback (void (*cb)(RpmOstreeOutputType, void*, void*),
|
||||
char *s = g_strdup_vprintf (format, args); \
|
||||
va_end (args); s; })
|
||||
|
||||
// For a lot of originally-C code it's just convenient to
|
||||
// use this global C-style format API and not have to deal
|
||||
// with a progress reference.
|
||||
void
|
||||
rpmostree_output_message (const char *format, ...)
|
||||
{
|
||||
@ -98,69 +103,91 @@ rpmostree_output_message (const char *format, ...)
|
||||
active_cb (RPMOSTREE_OUTPUT_MESSAGE, &task, active_cb_opaque);
|
||||
}
|
||||
|
||||
namespace rpmostreecxx {
|
||||
|
||||
void
|
||||
rpmostree_output_task_begin (RpmOstreeProgress *taskp, const char *format, ...)
|
||||
output_message (const rust::Str msg)
|
||||
{
|
||||
g_assert (taskp && !taskp->initialized);
|
||||
taskp->initialized = TRUE;
|
||||
taskp->type = RPMOSTREE_PROGRESS_TASK;
|
||||
g_autofree char *msg = strdup_vprintf (format);
|
||||
RpmOstreeOutputProgressBegin begin = { msg, false, 0 };
|
||||
auto msg_c = std::string(msg);
|
||||
RpmOstreeOutputMessage task = { msg_c.c_str() };
|
||||
active_cb (RPMOSTREE_OUTPUT_MESSAGE, &task, active_cb_opaque);
|
||||
}
|
||||
|
||||
// Begin a task (that can't easily be "nitems" or percentage).
|
||||
// This will render as a spinner.
|
||||
std::unique_ptr<Progress>
|
||||
progress_begin_task(const rust::Str msg) noexcept
|
||||
{
|
||||
auto msg_c = std::string(msg);
|
||||
RpmOstreeOutputProgressBegin begin = { msg_c.c_str(), false, 0 };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_BEGIN, &begin, active_cb_opaque);
|
||||
return std::make_unique<Progress>(ProgressType::TASK);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_output_set_sub_message (const char *sub_message)
|
||||
// Output a string. Note that this should not be called when
|
||||
// a "task" is active.
|
||||
void
|
||||
Progress::message(const rust::Str msg)
|
||||
{
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_SUB_MESSAGE, (void*)sub_message, active_cb_opaque);
|
||||
auto msg_c = std::string(msg);
|
||||
RpmOstreeOutputMessage task = { msg_c.c_str() };
|
||||
active_cb (RPMOSTREE_OUTPUT_MESSAGE, &task, active_cb_opaque);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_output_progress_end_msg (RpmOstreeProgress *taskp, const char *format, ...)
|
||||
// When working on a task/percent/nitems, often we want to display a particular
|
||||
// item (such as a package).
|
||||
void
|
||||
Progress::set_sub_message(const rust::Str msg)
|
||||
{
|
||||
g_assert (taskp);
|
||||
if (!taskp->initialized)
|
||||
return;
|
||||
taskp->initialized = false;
|
||||
g_autofree char *final_msg = format ? strdup_vprintf (format) : NULL;
|
||||
g_autofree char *msg_c = util::ruststr_dup_c_optempty(msg);
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_SUB_MESSAGE, (void*)msg_c, active_cb_opaque);
|
||||
}
|
||||
|
||||
// Start working on a 0-n task.
|
||||
std::unique_ptr<Progress>
|
||||
progress_nitems_begin(guint n, const rust::Str msg) noexcept
|
||||
{
|
||||
auto msg_c = std::string(msg);
|
||||
RpmOstreeOutputProgressBegin begin = { msg_c.c_str(), false, n };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_BEGIN, &begin, active_cb_opaque);
|
||||
return std::make_unique<Progress>(ProgressType::N_ITEMS);
|
||||
}
|
||||
|
||||
// Update the nitems counter.
|
||||
void
|
||||
Progress::nitems_update(guint n)
|
||||
{
|
||||
RpmOstreeOutputProgressUpdate progress = { n };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_UPDATE, &progress, active_cb_opaque);
|
||||
}
|
||||
|
||||
// Start a percentage task.
|
||||
std::unique_ptr<Progress>
|
||||
progress_percent_begin(const rust::Str msg) noexcept
|
||||
{
|
||||
auto msg_c = std::string(msg);
|
||||
RpmOstreeOutputProgressBegin begin = { msg_c.c_str(), true, 0 };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_BEGIN, &begin, active_cb_opaque);
|
||||
return std::make_unique<Progress>(ProgressType::PERCENT);
|
||||
}
|
||||
|
||||
// Update the percentage.
|
||||
void
|
||||
Progress::percent_update(guint n)
|
||||
{
|
||||
RpmOstreeOutputProgressUpdate progress = { (guint)n };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_UPDATE, &progress, active_cb_opaque);
|
||||
}
|
||||
|
||||
// End the current task.
|
||||
void
|
||||
Progress::end(const rust::Str msg)
|
||||
{
|
||||
g_assert (!this->ended);
|
||||
g_autofree char *final_msg = util::ruststr_dup_c_optempty(msg);
|
||||
RpmOstreeOutputProgressEnd done = { final_msg };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_END, &done, active_cb_opaque);
|
||||
this->ended = true;
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_output_progress_percent (int percentage)
|
||||
{
|
||||
RpmOstreeOutputProgressUpdate progress = { (guint)percentage };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_UPDATE, &progress, active_cb_opaque);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_output_progress_nitems_begin (RpmOstreeProgress *taskp,
|
||||
guint n, const char *format, ...)
|
||||
{
|
||||
g_assert (taskp && !taskp->initialized);
|
||||
taskp->initialized = TRUE;
|
||||
taskp->type = RPMOSTREE_PROGRESS_N_ITEMS;
|
||||
g_autofree char *msg = strdup_vprintf (format);
|
||||
RpmOstreeOutputProgressBegin begin = { msg, false, n };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_BEGIN, &begin, active_cb_opaque);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_output_progress_percent_begin (RpmOstreeProgress *taskp,
|
||||
const char *format, ...)
|
||||
{
|
||||
g_assert (taskp && !taskp->initialized);
|
||||
taskp->initialized = TRUE;
|
||||
taskp->type = RPMOSTREE_PROGRESS_PERCENT;
|
||||
g_autofree char *msg = strdup_vprintf (format);
|
||||
RpmOstreeOutputProgressBegin begin = { msg, true, 0 };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_BEGIN, &begin, active_cb_opaque);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_output_progress_n_items (guint current)
|
||||
{
|
||||
RpmOstreeOutputProgressUpdate progress = { current };
|
||||
active_cb (RPMOSTREE_OUTPUT_PROGRESS_UPDATE, &progress, active_cb_opaque);
|
||||
}
|
||||
} /* namespace */
|
||||
|
@ -19,7 +19,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <memory>
|
||||
#include "rust/cxx.h"
|
||||
|
||||
// C++ APIs here
|
||||
namespace rpmostreecxx {
|
||||
|
||||
enum class ProgressType {
|
||||
TASK,
|
||||
N_ITEMS,
|
||||
PERCENT,
|
||||
};
|
||||
|
||||
void output_message (rust::Str msg);
|
||||
|
||||
struct Progress {
|
||||
public:
|
||||
void set_sub_message(rust::Str msg);
|
||||
void message (rust::Str msg);
|
||||
void nitems_update(guint n);
|
||||
void percent_update(guint n);
|
||||
|
||||
void end(rust::Str msg);
|
||||
~Progress() {
|
||||
if (!this->ended)
|
||||
this->end("");
|
||||
}
|
||||
Progress(ProgressType t) {
|
||||
ptype = t;
|
||||
ended = false;
|
||||
}
|
||||
ProgressType ptype;
|
||||
bool ended;
|
||||
};
|
||||
|
||||
std::unique_ptr<Progress> progress_begin_task(rust::Str msg) noexcept;
|
||||
std::unique_ptr<Progress> progress_nitems_begin(guint n, rust::Str msg) noexcept;
|
||||
std::unique_ptr<Progress> progress_percent_begin(rust::Str msg) noexcept;
|
||||
}
|
||||
|
||||
// C APIs
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
@ -30,12 +69,6 @@ typedef enum {
|
||||
RPMOSTREE_OUTPUT_PROGRESS_END,
|
||||
} RpmOstreeOutputType;
|
||||
|
||||
typedef enum {
|
||||
RPMOSTREE_PROGRESS_TASK,
|
||||
RPMOSTREE_PROGRESS_N_ITEMS,
|
||||
RPMOSTREE_PROGRESS_PERCENT,
|
||||
} RpmOstreeProgressType;
|
||||
|
||||
void
|
||||
rpmostree_output_default_handler (RpmOstreeOutputType type, void *data, void *opaque);
|
||||
|
||||
@ -49,27 +82,6 @@ typedef struct {
|
||||
void
|
||||
rpmostree_output_message (const char *format, ...) G_GNUC_PRINTF (1,2);
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
RpmOstreeProgressType type;
|
||||
} RpmOstreeProgress;
|
||||
void rpmostree_output_task_begin (RpmOstreeProgress *prog, const char *format, ...) G_GNUC_PRINTF (2,3);
|
||||
|
||||
void rpmostree_output_set_sub_message (const char *sub_message);
|
||||
|
||||
void rpmostree_output_progress_nitems_begin (RpmOstreeProgress *prog, guint n, const char *format, ...) G_GNUC_PRINTF (3,4);
|
||||
void rpmostree_output_progress_n_items (guint i);
|
||||
|
||||
void rpmostree_output_progress_percent_begin (RpmOstreeProgress *prog, const char *format, ...) G_GNUC_PRINTF (2,3);
|
||||
void rpmostree_output_progress_percent (int percentage);
|
||||
|
||||
void rpmostree_output_progress_end_msg (RpmOstreeProgress *prog, const char *format, ...) G_GNUC_PRINTF (2,3);
|
||||
static inline void rpmostree_output_progress_end (RpmOstreeProgress *task)
|
||||
{
|
||||
rpmostree_output_progress_end_msg (task, NULL);
|
||||
}
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (RpmOstreeProgress, rpmostree_output_progress_end)
|
||||
|
||||
/* For implementers of the output backend. If percent is TRUE, then n is
|
||||
* ignored. If n is zero, then it is taken to be an indefinite task. Otherwise,
|
||||
* n is used for n_items.
|
||||
|
@ -1823,6 +1823,7 @@ struct CommitThreadData {
|
||||
off_t n_bytes;
|
||||
off_t n_processed;
|
||||
gint percent; /* atomic */
|
||||
std::unique_ptr<rpmostreecxx::Progress> progress;
|
||||
OstreeRepo *repo;
|
||||
int rootfs_fd;
|
||||
OstreeMutableTree *mtree;
|
||||
@ -1968,7 +1969,7 @@ on_progress_timeout (gpointer datap)
|
||||
const gint percent = g_atomic_int_get (&data->percent);
|
||||
|
||||
/* clamp to 100 if it somehow goes over (XXX: bad counting?) */
|
||||
rpmostree_output_progress_percent (MIN(percent, 100));
|
||||
data->progress->percent_update(MIN(percent, 100));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -2038,8 +2039,7 @@ rpmostree_compose_commit (int rootfs_fd,
|
||||
{
|
||||
g_autoptr(GThread) commit_thread = g_thread_new ("commit", write_dfd_thread, &tdata);
|
||||
|
||||
g_auto(RpmOstreeProgress) commit_progress = { 0, };
|
||||
rpmostree_output_progress_percent_begin (&commit_progress, "Committing");
|
||||
tdata.progress = rpmostreecxx::progress_percent_begin("Committing");
|
||||
|
||||
g_autoptr(GSource) progress_src = g_timeout_source_new_seconds (1);
|
||||
g_source_set_callback (progress_src, on_progress_timeout, &tdata, NULL);
|
||||
@ -2051,7 +2051,7 @@ rpmostree_compose_commit (int rootfs_fd,
|
||||
g_source_destroy (progress_src);
|
||||
g_thread_join (util::move_nullify (commit_thread));
|
||||
|
||||
rpmostree_output_progress_percent (100);
|
||||
tdata.progress->percent_update(100);
|
||||
}
|
||||
|
||||
if (!tdata.success)
|
||||
|
@ -673,8 +673,7 @@ rpmostree_migrate_pkgcache_repo (OstreeRepo *repo,
|
||||
{
|
||||
if (S_ISDIR (stbuf.st_mode))
|
||||
{
|
||||
g_auto(RpmOstreeProgress) task = { 0, };
|
||||
rpmostree_output_task_begin (&task, "Migrating pkgcache");
|
||||
auto task = rpmostreecxx::progress_begin_task("Migrating pkgcache");
|
||||
|
||||
g_autoptr(OstreeRepo) pkgcache = ostree_repo_open_at (repo_dfd,
|
||||
RPMOSTREE_OLD_PKGCACHE_DIR,
|
||||
@ -686,7 +685,8 @@ rpmostree_migrate_pkgcache_repo (OstreeRepo *repo,
|
||||
if (!do_pkgcache_migration (repo, pkgcache, &n_migrated, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
rpmostree_output_progress_end_msg (&task, "%u done", n_migrated);
|
||||
auto msg = g_strdup_printf("%u done", n_migrated);
|
||||
task->end(msg);
|
||||
if (n_migrated > 0)
|
||||
sd_journal_print (LOG_INFO, "migrated %u cached package%s to system repo",
|
||||
n_migrated, _NS(n_migrated));
|
||||
|
@ -70,6 +70,27 @@ throw_gerror (GError *&error)
|
||||
error = NULL;
|
||||
throw std::runtime_error (s);
|
||||
}
|
||||
|
||||
// Duplicate a non-empty Rust Str to a NUL-terminated C string.
|
||||
// The empty string is converted to a NULL pointer.
|
||||
// This method should be viewed as a workaround for the lack
|
||||
// of Option<> binding in cxx-rs.
|
||||
static inline char *
|
||||
ruststr_dup_c_optempty(const rust::Str s) {
|
||||
if (s.length() > 0)
|
||||
return g_strndup(s.data(), s.length());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return a Rust string pointer from a possibly-NULL C string.
|
||||
// The NULL C string is converted to the empty string.
|
||||
// This method should be viewed as a workaround for the lack
|
||||
// of Option<> binding in cxx-rs.
|
||||
static inline rust::Str
|
||||
ruststr_or_empty (const char *c_str) {
|
||||
return rust::Str(c_str ?: "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace rpmostreecxx {
|
||||
|
Loading…
Reference in New Issue
Block a user