Skip to content

Commit 07593a0

Browse files
authored
Merge pull request #848 from cgwalters/spinner-deploy
deploy: Add a spinner
2 parents 5a89d94 + daeafea commit 07593a0

File tree

2 files changed

+59
-26
lines changed

2 files changed

+59
-26
lines changed

lib/src/deploy.rs

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ use ostree_ext::oci_spec::image::{Descriptor, Digest};
1919
use ostree_ext::ostree::Deployment;
2020
use ostree_ext::ostree::{self, Sysroot};
2121
use ostree_ext::sysroot::SysrootLock;
22+
use ostree_ext::tokio_util::spawn_blocking_cancellable_flatten;
2223

2324
use crate::spec::ImageReference;
2425
use crate::spec::{BootOrder, HostSpec};
2526
use crate::status::labels_of_config;
2627
use crate::store::Storage;
28+
use crate::utils::async_task_with_spinner;
2729

2830
// TODO use https://github.com/ostreedev/ostree-rs-ext/pull/493/commits/afc1837ff383681b947de30c0cefc70080a4f87a
2931
const BASE_IMAGE_PREFIX: &str = "ostree/container/baseimage/bootc";
@@ -211,12 +213,14 @@ async fn handle_layer_progress_print(
211213
let elapsed = end.duration_since(start);
212214
let persec = total_read as f64 / elapsed.as_secs_f64();
213215
let persec = indicatif::HumanBytes(persec as u64);
214-
println!(
216+
if let Err(e) = bar.println(&format!(
215217
"Fetched layers: {} in {} ({}/s)",
216218
indicatif::HumanBytes(total_read),
217219
indicatif::HumanDuration(elapsed),
218220
persec,
219-
);
221+
)) {
222+
tracing::warn!("writing to stdout: {e}");
223+
}
220224
}
221225

222226
/// Wrapper for pulling a container image, wiring up status output.
@@ -373,8 +377,6 @@ async fn deploy(
373377
image: &ImageState,
374378
origin: &glib::KeyFile,
375379
) -> Result<Deployment> {
376-
let stateroot = Some(stateroot);
377-
let mut opts = ostree::SysrootDeployTreeOpts::default();
378380
// Compute the kernel argument overrides. In practice today this API is always expecting
379381
// a merge deployment. The kargs code also always looks at the booted root (which
380382
// is a distinct minor issue, but not super important as right now the install path
@@ -384,26 +386,49 @@ async fn deploy(
384386
} else {
385387
None
386388
};
387-
// Because the C API expects a Vec<&str>, we need to generate a new Vec<>
388-
// that borrows.
389-
let override_kargs = override_kargs
390-
.as_deref()
391-
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<_>>());
392-
if let Some(kargs) = override_kargs.as_deref() {
393-
opts.override_kernel_argv = Some(&kargs);
394-
}
395-
// Copy to move into thread
396-
let cancellable = gio::Cancellable::NONE;
397-
return sysroot
398-
.stage_tree_with_options(
399-
stateroot,
400-
image.ostree_commit.as_str(),
401-
Some(origin),
402-
merge_deployment,
403-
&opts,
404-
cancellable,
405-
)
406-
.map_err(Into::into);
389+
// Clone all the things to move to worker thread
390+
let sysroot_clone = sysroot.sysroot.clone();
391+
// ostree::Deployment is incorrently !Send 😢 so convert it to an integer
392+
let merge_deployment = merge_deployment.map(|d| d.index() as usize);
393+
let stateroot = stateroot.to_string();
394+
let ostree_commit = image.ostree_commit.to_string();
395+
// GKeyFile also isn't Send! So we serialize that as a string...
396+
let origin_data = origin.to_data();
397+
let r = async_task_with_spinner(
398+
"Deploying",
399+
spawn_blocking_cancellable_flatten(move |cancellable| -> Result<_> {
400+
let sysroot = sysroot_clone;
401+
let stateroot = Some(stateroot);
402+
let mut opts = ostree::SysrootDeployTreeOpts::default();
403+
404+
// Because the C API expects a Vec<&str>, we need to generate a new Vec<>
405+
// that borrows.
406+
let override_kargs = override_kargs
407+
.as_deref()
408+
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<_>>());
409+
if let Some(kargs) = override_kargs.as_deref() {
410+
opts.override_kernel_argv = Some(&kargs);
411+
}
412+
let deployments = sysroot.deployments();
413+
let merge_deployment = merge_deployment.map(|m| &deployments[m]);
414+
let origin = glib::KeyFile::new();
415+
origin.load_from_data(&origin_data, glib::KeyFileFlags::NONE)?;
416+
let d = sysroot.stage_tree_with_options(
417+
stateroot.as_deref(),
418+
&ostree_commit,
419+
Some(&origin),
420+
merge_deployment,
421+
&opts,
422+
Some(cancellable),
423+
)?;
424+
Ok(d.index())
425+
}),
426+
)
427+
.await?;
428+
// SAFETY: We must have a staged deployment
429+
let staged = sysroot.staged_deployment().unwrap();
430+
assert_eq!(staged.index(), r);
431+
Ok(staged)
407432
}
408433

409434
#[context("Generating origin")]

lib/src/utils.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use std::time::Duration;
66

77
use anyhow::{Context, Result};
88
use cap_std_ext::cap_std::fs::Dir;
9+
use indicatif::HumanDuration;
10+
use libsystemd::logging::journal_print;
911
use ostree::glib;
1012
use ostree_ext::container::SignatureSource;
1113
use ostree_ext::ostree;
@@ -119,6 +121,7 @@ pub(crate) async fn async_task_with_spinner<F, T>(msg: &str, f: F) -> T
119121
where
120122
F: Future<Output = T>,
121123
{
124+
let start_time = std::time::Instant::now();
122125
let pb = indicatif::ProgressBar::new_spinner();
123126
let style = indicatif::ProgressStyle::default_bar();
124127
pb.set_style(style.template("{spinner} {msg}").unwrap());
@@ -131,10 +134,15 @@ where
131134
std::io::stdout().flush().unwrap();
132135
}
133136
let r = f.await;
137+
let elapsed = HumanDuration(start_time.elapsed());
138+
let _ = journal_print(
139+
libsystemd::logging::Priority::Info,
140+
&format!("completed task in {elapsed}: {msg}"),
141+
);
134142
if pb.is_hidden() {
135-
println!("done");
143+
println!("done ({elapsed})");
136144
} else {
137-
pb.finish_with_message(format!("{msg}: done"));
145+
pb.finish_with_message(format!("{msg}: done ({elapsed})"));
138146
}
139147
r
140148
}

0 commit comments

Comments
 (0)