diff --git a/crates/ostree-ext/src/sysroot.rs b/crates/ostree-ext/src/sysroot.rs index 6ddc321e5..b6f00b7f1 100644 --- a/crates/ostree-ext/src/sysroot.rs +++ b/crates/ostree-ext/src/sysroot.rs @@ -4,6 +4,8 @@ use std::ops::Deref; use anyhow::Result; +use crate::utils::async_task_with_spinner; + /// A locked system root. #[derive(Debug)] pub struct SysrootLock { @@ -35,20 +37,17 @@ impl SysrootLock { /// immediately, a status message will be printed to standard output. /// The lock will be unlocked when this object is dropped. pub async fn new_from_sysroot(sysroot: &ostree::Sysroot) -> Result { - let mut printed = false; - loop { - if sysroot.try_lock()? { - return Ok(Self { - sysroot: sysroot.clone(), - unowned: false, - }); - } - if !printed { - eprintln!("Waiting for sysroot lock..."); - printed = true; - } - tokio::time::sleep(std::time::Duration::from_secs(3)).await; + if sysroot.try_lock()? { + return Ok(Self { + sysroot: sysroot.clone(), + unowned: false, + }); } + async_task_with_spinner("Waiting for sysroot lock...", sysroot.lock_future()).await?; + Ok(Self { + sysroot: sysroot.clone(), + unowned: false, + }) } /// This function should only be used when you have locked the sysroot diff --git a/crates/ostree-ext/src/utils.rs b/crates/ostree-ext/src/utils.rs index 8b1378917..a70cac053 100644 --- a/crates/ostree-ext/src/utils.rs +++ b/crates/ostree-ext/src/utils.rs @@ -1 +1,29 @@ +use std::{future::Future, time::Duration}; +/// Call an async task function, and write a message to stdout +/// with an automatic spinner to show that we're not blocked. +/// Note that generally the called function should not output +/// anything to stdout as this will interfere with the spinner. +pub(crate) async fn async_task_with_spinner(msg: &str, f: F) -> T +where + F: Future, +{ + let pb = indicatif::ProgressBar::new_spinner(); + let style = indicatif::ProgressStyle::default_bar(); + pb.set_style(style.template("{spinner} {msg}").unwrap()); + pb.set_message(msg.to_string()); + pb.enable_steady_tick(Duration::from_millis(150)); + let r = f.await; + pb.finish_and_clear(); + r +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_spinner() { + async_task_with_spinner("Testing...", tokio::time::sleep(Duration::from_secs(5))).await + } +}