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
48 changes: 33 additions & 15 deletions rust/agama-cli/src/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@
// find current contact information at www.suse.com.

use agama_lib::monitor::MonitorClient;
use agama_utils::api;
use console::style;
use agama_utils::api::{self, Scope};
use indicatif::{ProgressBar, ProgressStyle};
use std::time::Duration;
use std::{collections::HashMap, time::Duration};

/// Displays the progress on the terminal.
#[derive(Debug)]
pub struct ProgressMonitor {
monitor: MonitorClient,
bar: Option<ProgressBar>,
current_step: u32,
running: bool,
stop_on_idle: bool,
}
Expand All @@ -40,8 +38,6 @@ impl ProgressMonitor {
pub fn new(monitor: MonitorClient) -> Self {
Self {
monitor,
bar: None,
current_step: 0,
running: true,
stop_on_idle: true,
}
Expand All @@ -57,41 +53,63 @@ impl ProgressMonitor {
pub async fn run(&mut self) -> anyhow::Result<()> {
let mut updates = self.monitor.subscribe();
let status = self.monitor.get_status().await?;
self.update(status).await;
self.update(&status).await;
if !self.running {
return Ok(());
}

let multibar = indicatif::MultiProgress::new();
let mut bars: HashMap<Scope, ProgressBar> = HashMap::new();
multibar.println("Installaton Tasks:")?;
loop {
if let Ok(status) = updates.recv().await {
if !self.update(status).await {
if !self.update(&status).await {
return Ok(());
}

let mut active_scopes = vec![];
for progress in status.progresses {
active_scopes.push(progress.scope);
let bar = bars.entry(progress.scope).or_insert_with(|| {
let style = ProgressStyle::with_template("{spinner:.green} {msg}").unwrap();
let new_bar = ProgressBar::new(progress.size as u64).with_style(style);
new_bar.enable_steady_tick(Duration::from_millis(120));
multibar.add(new_bar)
});
bar.set_message(progress.step);
bar.set_position(progress.index as u64);
}
// and finish all that no longer have progress
let mut to_remove = vec![];
for (scope, bar) in &bars {
if !active_scopes.contains(&scope) {
bar.finish_with_message("done");
to_remove.push(scope.clone());
}
}
for scope in to_remove {
bars.remove(&scope);
}
}
}
}

/// Updates the progress.
///
/// It returns true if the monitor should continue.
async fn update(&mut self, status: api::Status) -> bool {
async fn update(&mut self, status: &api::Status) -> bool {
if status.progresses.is_empty() && self.running {
self.finish();
if self.stop_on_idle {
return false;
}
}

// TODO: adapt to multi progresses

true
}

/// Stops the representation.
fn finish(&mut self) {
self.running = false;
if let Some(bar) = self.bar.take() {
bar.finish_with_message("Done");
}
}
}
2 changes: 1 addition & 1 deletion rust/agama-lib/src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub enum MonitorError {
/// It allows connecting to the Agama monitor to get the status or listen for changes.
///
/// It can be cloned and moved between threads.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct MonitorClient {
commands: mpsc::Sender<MonitorCommand>,
pub updates: broadcast::Sender<api::Status>,
Expand Down
15 changes: 4 additions & 11 deletions rust/agama-software/src/callbacks/commit_download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,10 @@ impl Callback for CommitDownload {
.progress
.cast(progress::message::NextWithStep::new(Scope::Software, &msg));
} else {
let labels = [gettext("Ok")];
let actions = [("Ok", labels[0].as_str())];
let question =
QuestionSpec::new(&error_details, "software.package_error.preload_error")
.with_actions(&actions)
.with_data(&[
("package", file_str),
("error_code", error.to_string().as_str()),
]);
// answer can be only OK so ignore it
let _ = ask_software_question(&self.questions, question);
// just log that download failed as libzypp will automatically use next mirror
// so we should not bother user. But also do not update progress otherwise it will
// mess us steps.
tracing::info!("preload failed with {:?}", error_details);
}
}
}
4 changes: 2 additions & 2 deletions rust/agama-utils/src/api/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
// find current contact information at www.suse.com.

use crate::api::{l10n, network, software};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Clone, Debug, Serialize, utoipa::ToSchema)]
#[derive(Clone, Debug, Deserialize, Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct Proposal {
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
8 changes: 4 additions & 4 deletions rust/agama-utils/src/api/software/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Represents the reason why a pattern is selected.
#[derive(Clone, Copy, Debug, PartialEq, Serialize, utoipa::ToSchema)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub enum SelectedBy {
/// The pattern was selected by the user.
Expand All @@ -34,7 +34,7 @@ pub enum SelectedBy {
}

/// Software proposal information.
#[derive(Clone, Debug, Serialize, utoipa::ToSchema)]
#[derive(Clone, Debug, Deserialize, Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct SoftwareProposal {
/// Space required for installation in KiB.
Expand All @@ -45,7 +45,7 @@ pub struct SoftwareProposal {
}

/// Describes what Agama proposes for the target system.
#[derive(Clone, Default, Debug, Serialize, utoipa::ToSchema)]
#[derive(Clone, Default, Debug, Deserialize, Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct Proposal {
/// Software specific proposal
Expand Down
Loading