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

deploy: Add a spinner #848

Merged
merged 3 commits into from
Nov 5, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 49 additions & 24 deletions lib/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ use ostree_ext::oci_spec::image::{Descriptor, Digest};
use ostree_ext::ostree::Deployment;
use ostree_ext::ostree::{self, Sysroot};
use ostree_ext::sysroot::SysrootLock;
use ostree_ext::tokio_util::spawn_blocking_cancellable_flatten;

use crate::spec::ImageReference;
use crate::spec::{BootOrder, HostSpec};
use crate::status::labels_of_config;
use crate::store::Storage;
use crate::utils::async_task_with_spinner;

// TODO use https://github.com/ostreedev/ostree-rs-ext/pull/493/commits/afc1837ff383681b947de30c0cefc70080a4f87a
const BASE_IMAGE_PREFIX: &str = "ostree/container/baseimage/bootc";
Expand Down Expand Up @@ -211,12 +213,14 @@ async fn handle_layer_progress_print(
let elapsed = end.duration_since(start);
let persec = total_read as f64 / elapsed.as_secs_f64();
let persec = indicatif::HumanBytes(persec as u64);
println!(
if let Err(e) = bar.println(&format!(
"Fetched layers: {} in {} ({}/s)",
indicatif::HumanBytes(total_read),
indicatif::HumanDuration(elapsed),
persec,
);
)) {
tracing::warn!("writing to stdout: {e}");
}
}

/// Wrapper for pulling a container image, wiring up status output.
Expand Down Expand Up @@ -373,8 +377,6 @@ async fn deploy(
image: &ImageState,
origin: &glib::KeyFile,
) -> Result<Deployment> {
let stateroot = Some(stateroot);
let mut opts = ostree::SysrootDeployTreeOpts::default();
// Compute the kernel argument overrides. In practice today this API is always expecting
// a merge deployment. The kargs code also always looks at the booted root (which
// is a distinct minor issue, but not super important as right now the install path
Expand All @@ -384,26 +386,49 @@ async fn deploy(
} else {
None
};
// Because the C API expects a Vec<&str>, we need to generate a new Vec<>
// that borrows.
let override_kargs = override_kargs
.as_deref()
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<_>>());
if let Some(kargs) = override_kargs.as_deref() {
opts.override_kernel_argv = Some(&kargs);
}
// Copy to move into thread
let cancellable = gio::Cancellable::NONE;
return sysroot
.stage_tree_with_options(
stateroot,
image.ostree_commit.as_str(),
Some(origin),
merge_deployment,
&opts,
cancellable,
)
.map_err(Into::into);
// Clone all the things to move to worker thread
let sysroot_clone = sysroot.sysroot.clone();
// ostree::Deployment is incorrently !Send 😢 so convert it to an integer
let merge_deployment = merge_deployment.map(|d| d.index() as usize);
let stateroot = stateroot.to_string();
let ostree_commit = image.ostree_commit.to_string();
// GKeyFile also isn't Send! So we serialize that as a string...
let origin_data = origin.to_data();
let r = async_task_with_spinner(
"Deploying",
spawn_blocking_cancellable_flatten(move |cancellable| -> Result<_> {
let sysroot = sysroot_clone;
let stateroot = Some(stateroot);
let mut opts = ostree::SysrootDeployTreeOpts::default();

// Because the C API expects a Vec<&str>, we need to generate a new Vec<>
// that borrows.
let override_kargs = override_kargs
.as_deref()
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<_>>());
if let Some(kargs) = override_kargs.as_deref() {
opts.override_kernel_argv = Some(&kargs);
}
let deployments = sysroot.deployments();
let merge_deployment = merge_deployment.map(|m| &deployments[m]);
let origin = glib::KeyFile::new();
origin.load_from_data(&origin_data, glib::KeyFileFlags::NONE)?;
let d = sysroot.stage_tree_with_options(
stateroot.as_deref(),
&ostree_commit,
Some(&origin),
merge_deployment,
&opts,
Some(cancellable),
)?;
Ok(d.index())
}),
)
.await?;
// SAFETY: We must have a staged deployment
let staged = sysroot.staged_deployment().unwrap();
assert_eq!(staged.index(), r);
cgwalters marked this conversation as resolved.
Show resolved Hide resolved
Ok(staged)
}

#[context("Generating origin")]
Expand Down
12 changes: 10 additions & 2 deletions lib/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::time::Duration;

use anyhow::{Context, Result};
use cap_std_ext::cap_std::fs::Dir;
use indicatif::HumanDuration;
use libsystemd::logging::journal_print;
use ostree::glib;
use ostree_ext::container::SignatureSource;
use ostree_ext::ostree;
Expand Down Expand Up @@ -119,6 +121,7 @@ pub(crate) async fn async_task_with_spinner<F, T>(msg: &str, f: F) -> T
where
F: Future<Output = T>,
{
let start_time = std::time::Instant::now();
let pb = indicatif::ProgressBar::new_spinner();
let style = indicatif::ProgressStyle::default_bar();
pb.set_style(style.template("{spinner} {msg}").unwrap());
Expand All @@ -131,10 +134,15 @@ where
std::io::stdout().flush().unwrap();
}
let r = f.await;
let elapsed = HumanDuration(start_time.elapsed());
let _ = journal_print(
libsystemd::logging::Priority::Info,
&format!("completed task in {elapsed}: {msg}"),
);
if pb.is_hidden() {
println!("done");
println!("done ({elapsed})");
} else {
pb.finish_with_message(format!("{msg}: done"));
pb.finish_with_message(format!("{msg}: done ({elapsed})"));
}
r
}
Expand Down