Skip to content

Commit 3638b41

Browse files
committed
deploy: Add a spinner
First, this operation was absolutely not asynchronous and we need to spawn it in a helper thread on general principle. Doing that is unfortunately VERY hacky because we need to clone a lot of things and especially there's an ergonomics hit here since `Deployment` is incorrectly `!Send`. But the main motivation is this operation can be slow sometimes, so let's show progress output so the admin knows we're not blocked. Closes: #842 Signed-off-by: Colin Walters <[email protected]>
1 parent 7f64565 commit 3638b41

File tree

1 file changed

+45
-22
lines changed

1 file changed

+45
-22
lines changed

lib/src/deploy.rs

Lines changed: 45 additions & 22 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";
@@ -375,8 +377,6 @@ async fn deploy(
375377
image: &ImageState,
376378
origin: &glib::KeyFile,
377379
) -> Result<Deployment> {
378-
let stateroot = Some(stateroot);
379-
let mut opts = ostree::SysrootDeployTreeOpts::default();
380380
// Compute the kernel argument overrides. In practice today this API is always expecting
381381
// a merge deployment. The kargs code also always looks at the booted root (which
382382
// is a distinct minor issue, but not super important as right now the install path
@@ -386,26 +386,49 @@ async fn deploy(
386386
} else {
387387
None
388388
};
389-
// Because the C API expects a Vec<&str>, we need to generate a new Vec<>
390-
// that borrows.
391-
let override_kargs = override_kargs
392-
.as_deref()
393-
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<_>>());
394-
if let Some(kargs) = override_kargs.as_deref() {
395-
opts.override_kernel_argv = Some(&kargs);
396-
}
397-
// Copy to move into thread
398-
let cancellable = gio::Cancellable::NONE;
399-
return sysroot
400-
.stage_tree_with_options(
401-
stateroot,
402-
image.ostree_commit.as_str(),
403-
Some(origin),
404-
merge_deployment,
405-
&opts,
406-
cancellable,
407-
)
408-
.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)
409432
}
410433

411434
#[context("Generating origin")]

0 commit comments

Comments
 (0)