Skip to content
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
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/agama-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ indicatif= "0.17.3"
async-std = { version ="1.12.0", features = ["attributes"] }
thiserror = "1.0.39"
convert_case = "0.6.0"
console = "0.15.7"

[[bin]]
name = "agama"
Expand Down
10 changes: 6 additions & 4 deletions rust/agama-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod progress;
use crate::error::CliError;
use agama_lib::error::ServiceError;
use agama_lib::manager::ManagerClient;
use agama_lib::progress::build_progress_monitor;
use agama_lib::progress::ProgressMonitor;
use async_std::task::{self, block_on};
use commands::Commands;
use config::run as run_config_cmd;
Expand Down Expand Up @@ -53,9 +53,11 @@ async fn install(manager: &ManagerClient<'_>, max_attempts: u8) -> Result<(), Bo
if !manager.can_install().await? {
return Err(Box::new(CliError::ValidationError));
}

// Display the progress (if needed) and makes sure that the manager is ready
manager.wait().await?;

let progress = task::spawn(async { show_progress().await });
// Try to start the installation up to max_attempts times.
let mut attempts = 1;
loop {
Expand All @@ -75,15 +77,15 @@ async fn install(manager: &ManagerClient<'_>, max_attempts: u8) -> Result<(), Bo
attempts += 1;
sleep(Duration::from_secs(1));
}
println!("The installation process has started.");
let _ = progress.await;
Ok(())
}

async fn show_progress() -> Result<(), ServiceError> {
// wait 1 second to give other task chance to start, so progress can display something
task::sleep(Duration::from_secs(1)).await;
let conn = agama_lib::connection().await?;
let mut monitor = build_progress_monitor(conn).await.unwrap();
let mut monitor = ProgressMonitor::new(conn).await.unwrap();
let presenter = InstallerProgress::new();
monitor
.run(presenter)
Expand All @@ -96,7 +98,7 @@ async fn wait_for_services(manager: &ManagerClient<'_>) -> Result<(), Box<dyn Er
let services = manager.busy_services().await?;
// TODO: having it optional
if !services.is_empty() {
eprintln!("There are busy services {services:?}. Waiting for them.");
eprintln!("The Agama service is busy. Waiting for it to be available...");
show_progress().await?
}
Ok(())
Expand Down
67 changes: 43 additions & 24 deletions rust/agama-cli/src/progress.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,61 @@
use agama_lib::progress::{Progress, ProgressPresenter};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use console::style;
use indicatif::{ProgressBar, ProgressStyle};
use std::time::Duration;

/// Reports the installer progress through the terminal
pub struct InstallerProgress {
progress: MultiProgress,
bars: Vec<ProgressBar>,
bar: Option<ProgressBar>,
}

impl InstallerProgress {
pub fn new() -> Self {
let progress = MultiProgress::new();
Self {
progress,
bars: vec![],
}
Self { bar: None }
}

fn update_bar(&mut self, progress: &Progress) {
let bar = self.bar.get_or_insert_with(|| {
let style = ProgressStyle::with_template("{spinner:.green} {msg}").unwrap();
let bar = ProgressBar::new(0).with_style(style);
bar.enable_steady_tick(Duration::from_millis(120));
bar
});
bar.set_length(progress.max_steps.into());
bar.set_position(progress.current_step.into());
bar.set_message(progress.current_title.to_owned());
}
}

impl ProgressPresenter for InstallerProgress {
fn start(&mut self, progress: &[Progress]) {
let style =
ProgressStyle::with_template("{bar:40.green/white} {pos:>3}/{len:3} {msg}").unwrap();
for info in progress.iter() {
let bar = self.progress.add(ProgressBar::new(info.max_steps.into()));
bar.set_style(style.clone());
self.bars.push(bar);
fn start(&mut self, progress: &Progress) {
if !progress.finished {
self.update_main(&progress);
}
}

fn update(&mut self, progress: &[Progress]) {
for (i, info) in progress.iter().enumerate() {
let bar = &self.bars.get(i).unwrap();
if info.finished {
bar.finish_with_message("Done");
} else {
bar.set_length(info.max_steps.into());
bar.set_position(info.current_step.into());
bar.set_message(info.current_title.to_owned());
fn update_main(&mut self, progress: &Progress) {
let counter = format!("[{}/{}]", &progress.current_step, &progress.max_steps);

println!(
"{} {}",
style(&counter).bold().green(),
&progress.current_title
);
}

fn update_detail(&mut self, progress: &Progress) {
if progress.finished {
if let Some(bar) = self.bar.take() {
bar.finish_and_clear();
}
} else {
self.update_bar(&progress);
}
}

fn finish(&mut self) {
if let Some(bar) = self.bar.take() {
bar.finish_and_clear();
}
}
}
Loading