diff --git a/crates/cli/src/commands/install.rs b/crates/cli/src/commands/install.rs index b9671bd07..29bc44a11 100644 --- a/crates/cli/src/commands/install.rs +++ b/crates/cli/src/commands/install.rs @@ -4,7 +4,7 @@ use crate::session::ProtoSession; use crate::shell::{self, Export}; use crate::telemetry::{track_usage, Metric}; use clap::{Args, ValueEnum}; -use indicatif::{MultiProgress, ProgressBar}; +use indicatif::ProgressBar; use miette::IntoDiagnostic; use proto_core::flow::install::{InstallOptions, InstallPhase}; use proto_core::{Id, PinType, Tool, UnresolvedVersionSpec, VersionSpec}; @@ -208,6 +208,8 @@ pub async fn do_install( ))); } + print_progress_state(&pb); + if args.id.is_some() { pb.finish_and_clear(); } else { @@ -215,8 +217,6 @@ pub async fn do_install( } }; - pb.set_message(format!("Installing {name} {version}")); - // Disable version caching and always use the latest when installing tool.disable_caching(); @@ -305,6 +305,8 @@ pub async fn do_install( } _ => {} }; + + print_progress_state(&pb3); }); let installed = tool @@ -423,25 +425,30 @@ pub async fn install_all(session: &ProtoSession) -> AppResult { .fold(0, |acc, id| if id.len() > acc { id.len() } else { acc }); // Then install each tool in parallel! - let mpb = MultiProgress::new(); + let mpb = create_multi_progress_bar(); + let pbs = create_progress_bar_style(); let mut set = JoinSet::new(); for mut tool in tools { if let Some(version) = versions.remove(&tool.id) { let pb = mpb.add(ProgressBar::new(0)); - pb.set_style(create_progress_bar_style()); + pb.set_style(pbs.clone()); + // Defer writing content till the thread starts, + // otherwise the progress bars fail to render correctly set.spawn(async move { sleep(Duration::from_millis(25)).await; - // Defer writing content till the thread starts, - // otherwise the progress bars fail to render correctly pb.set_prefix(color::id(format!( "{}{}", " ".repeat(longest_id - tool.id.len()), tool.id ))); + pb.set_message(format!("Installing {} {}", tool.get_name(), version)); + + print_progress_state(&pb); + do_install( &mut tool, InstallArgs { @@ -455,6 +462,8 @@ pub async fn install_all(session: &ProtoSession) -> AppResult { } } + let total = set.len(); + while let Some(result) = set.join_next().await { match result.into_diagnostic() { Err(error) | Ok(Err(error)) => { @@ -467,6 +476,11 @@ pub async fn install_all(session: &ProtoSession) -> AppResult { }; } + // When no TTY, we should display something to the user! + if mpb.is_hidden() { + println!("Successfully installed {} tools!", total); + } + Ok(()) } diff --git a/crates/cli/src/commands/run.rs b/crates/cli/src/commands/run.rs index 69e29ef0a..d700e36a8 100644 --- a/crates/cli/src/commands/run.rs +++ b/crates/cli/src/commands/run.rs @@ -189,7 +189,12 @@ pub async fn run(session: ProtoSession, args: RunArgs) -> AppResult { ..Default::default() }; - do_install(&mut tool, install_args, create_progress_bar("Installing")).await?; + do_install( + &mut tool, + install_args, + create_progress_bar(format!("Installing {resolved_version}")), + ) + .await?; println!( "{} {} has been installed, continuing execution...", diff --git a/crates/cli/src/helpers.rs b/crates/cli/src/helpers.rs index 7b76197a8..1eb5c0861 100644 --- a/crates/cli/src/helpers.rs +++ b/crates/cli/src/helpers.rs @@ -2,11 +2,11 @@ use dialoguer::{ console::{style, Style}, theme::ColorfulTheme, }; -use indicatif::{ProgressBar, ProgressStyle}; +use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle}; use miette::IntoDiagnostic; use starbase_styles::color::{self, Color}; use starbase_utils::env::bool_var; -use std::time::Duration; +use std::{io::IsTerminal, time::Duration}; use tracing::debug; pub fn create_theme() -> ColorfulTheme { @@ -90,8 +90,20 @@ pub fn create_progress_spinner_style() -> ProgressStyle { .unwrap() } +fn is_hidden_progress() -> bool { + bool_var("PROTO_NO_PROGRESS") || !std::io::stderr().is_terminal() +} + +pub fn create_multi_progress_bar() -> MultiProgress { + if is_hidden_progress() { + MultiProgress::with_draw_target(ProgressDrawTarget::hidden()) + } else { + MultiProgress::new() + } +} + pub fn create_progress_bar>(start: S) -> ProgressBar { - let pb = if bool_var("PROTO_NO_PROGRESS") { + let pb = if is_hidden_progress() { ProgressBar::hidden() } else { ProgressBar::new(0) @@ -101,11 +113,14 @@ pub fn create_progress_bar>(start: S) -> ProgressBar { pb.set_message(start.as_ref().to_owned()); pb.set_position(0); pb.set_length(100); + + print_progress_state(&pb); + pb } pub fn create_progress_spinner>(start: S) -> ProgressBar { - let pb = if bool_var("PROTO_NO_PROGRESS") { + let pb = if is_hidden_progress() { ProgressBar::hidden() } else { ProgressBar::new_spinner() @@ -114,9 +129,23 @@ pub fn create_progress_spinner>(start: S) -> ProgressBar { pb.set_style(create_progress_spinner_style()); pb.set_message(start.as_ref().to_owned()); pb.enable_steady_tick(Duration::from_millis(100)); + + print_progress_state(&pb); + pb } +// When not a TTY, we should display something to the user! +pub fn print_progress_state(pb: &ProgressBar) { + if pb.is_hidden() { + let message = pb.message(); + + if !message.is_empty() { + println!("{}", format!("{} {message}", pb.prefix()).trim()); + } + } +} + pub async fn fetch_latest_version() -> miette::Result { let version = reqwest::get("https://raw.githubusercontent.com/moonrepo/proto/master/version") .await