diff --git a/rust/agama-cli/src/error.rs b/rust/agama-cli/src/error.rs index c439563b9b..e6a418a9a9 100644 --- a/rust/agama-cli/src/error.rs +++ b/rust/agama-cli/src/error.rs @@ -6,4 +6,6 @@ pub enum CliError { InvalidKeyName(String), #[error("Cannot perform the installation as the settings are not valid")] ValidationError, + #[error("Could not start the installation")] + InstallationError, } diff --git a/rust/agama-cli/src/main.rs b/rust/agama-cli/src/main.rs index bb94c02e7e..c96c97c3f1 100644 --- a/rust/agama-cli/src/main.rs +++ b/rust/agama-cli/src/main.rs @@ -18,6 +18,7 @@ use printers::Format; use profile::run as run_profile_cmd; use progress::InstallerProgress; use std::error::Error; +use std::thread::sleep; use std::time::Duration; #[derive(Parser)] @@ -39,17 +40,43 @@ async fn probe() -> Result<(), Box> { Ok(probe.await?) } -async fn install(manager: &ManagerClient<'_>) -> Result<(), Box> { +/// Starts the installation process +/// +/// Before starting, it makes sure that the manager is idle. +/// +/// * `manager`: the manager client. +async fn install(manager: &ManagerClient<'_>, max_attempts: u8) -> Result<(), Box> { + if manager.is_busy().await { + println!("Agama's manager is busy. Waiting until it is ready..."); + } + if !manager.can_install().await? { - // TODO: add some hints what is wrong or add dedicated command for it? - eprintln!("There are issues with configuration. Cannot install."); return Err(Box::new(CliError::ValidationError)); } - let another_manager = build_manager().await?; - let install = task::spawn(async move { another_manager.install().await }); - show_progress().await?; + // Display the progress (if needed) and makes sure that the manager is ready + manager.wait().await?; - Ok(install.await?) + // Try to start the installation up to max_attempts times. + let mut attempts = 1; + loop { + match manager.install().await { + Ok(()) => break, + Err(e) => { + eprintln!( + "Could not start the installation process: {e}. Attempt {}/{}.", + attempts, max_attempts + ); + } + } + if attempts == max_attempts { + eprintln!("Giving up."); + return Err(Box::new(CliError::InstallationError)); + } + attempts += 1; + sleep(Duration::from_secs(1)); + } + println!("The installation process has started."); + Ok(()) } async fn show_progress() -> Result<(), ServiceError> { @@ -95,8 +122,7 @@ async fn run_command(cli: Cli) -> Result<(), Box> { Commands::Profile(subcommand) => Ok(run_profile_cmd(subcommand)?), Commands::Install => { let manager = build_manager().await?; - block_on(wait_for_services(&manager))?; - block_on(install(&manager)) + block_on(install(&manager, 3)) } _ => unimplemented!(), } diff --git a/rust/agama-lib/src/manager.rs b/rust/agama-lib/src/manager.rs index 6923d936ab..640fd5b533 100644 --- a/rust/agama-lib/src/manager.rs +++ b/rust/agama-lib/src/manager.rs @@ -1,14 +1,17 @@ use crate::error::ServiceError; +use crate::proxies::ServiceStatusProxy; use crate::{ progress::Progress, proxies::{ManagerProxy, ProgressProxy}, }; +use futures_util::StreamExt; use zbus::Connection; /// D-Bus client for the manager service pub struct ManagerClient<'a> { manager_proxy: ManagerProxy<'a>, progress_proxy: ProgressProxy<'a>, + status_proxy: ServiceStatusProxy<'a>, } impl<'a> ManagerClient<'a> { @@ -16,6 +19,7 @@ impl<'a> ManagerClient<'a> { Ok(Self { manager_proxy: ManagerProxy::new(&connection).await?, progress_proxy: ProgressProxy::new(&connection).await?, + status_proxy: ServiceStatusProxy::new(&connection).await?, }) } @@ -38,4 +42,29 @@ impl<'a> ManagerClient<'a> { pub async fn progress(&self) -> zbus::Result { Progress::from_proxy(&self.progress_proxy).await } + + /// Returns whether the service is busy or not + /// + /// TODO: move this code to a trait with functions related to the service status. + pub async fn is_busy(&self) -> bool { + if let Ok(status) = self.status_proxy.current().await { + return status != 0; + } + true + } + + /// Waits until the manager is idle. + pub async fn wait(&self) -> Result<(), ServiceError> { + if !self.is_busy().await { + return Ok(()); + } + + let mut s = self.status_proxy.receive_current_changed().await; + while let Some(change) = s.next().await { + if change.get().await? == 0 { + return Ok(()); + } + } + Ok(()) + } } diff --git a/rust/package/agama-cli.changes b/rust/package/agama-cli.changes index a094014c3f..fbf08d69a0 100644 --- a/rust/package/agama-cli.changes +++ b/rust/package/agama-cli.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Jul 6 09:13:47 UTC 2023 - Imobach Gonzalez Sosa + +- Improve the waiting logic and implement a retry mechanism for the + "agama install" command (bsc#1213047). + ------------------------------------------------------------------- Wed Jul 5 11:11:20 UTC 2023 - Imobach Gonzalez Sosa