@@ -6,11 +6,15 @@ use std::{
66 path:: { Path , PathBuf } ,
77 process:: ExitStatus ,
88 str:: FromStr ,
9+ time:: Duration ,
910} ;
1011
1112use anyhow:: { Context , Error , Result , anyhow} ;
1213use clap:: { Args , CommandFactory , Parser , Subcommand , ValueEnum , builder:: PossibleValue } ;
1314use clap_complete:: Shell ;
15+ use console:: style;
16+ use futures_util:: stream:: StreamExt ;
17+ use indicatif:: { MultiProgress , ProgressBar , ProgressDrawTarget , ProgressStyle } ;
1418use itertools:: Itertools ;
1519use tracing:: { info, trace, warn} ;
1620use tracing_subscriber:: { EnvFilter , Registry , reload:: Handle } ;
@@ -34,7 +38,7 @@ use crate::{
3438 install:: { InstallMethod , UpdateStatus } ,
3539 process:: {
3640 Process ,
37- terminalsource:: { self , ColorableTerminal } ,
41+ terminalsource:: { self , ColorChoice , ColorableTerminal } ,
3842 } ,
3943 toolchain:: {
4044 CustomToolchainName , DistributableToolchain , LocalToolchainName ,
@@ -792,45 +796,99 @@ async fn default_(
792796}
793797
794798async fn check_updates ( cfg : & Cfg < ' _ > , opts : CheckOpts ) -> Result < utils:: ExitCode > {
799+ let t = cfg. process . stdout ( ) . terminal ( cfg. process ) ;
800+ let is_a_tty = t. is_a_tty ( ) ;
801+ let use_colors = matches ! ( t. color_choice( ) , ColorChoice :: Auto | ColorChoice :: Always ) ;
795802 let mut update_available = false ;
796-
797- let mut t = cfg. process . stdout ( ) . terminal ( cfg. process ) ;
798803 let channels = cfg. list_channels ( ) ?;
799-
800- for channel in channels {
801- let ( name, distributable) = channel;
802- let current_version = distributable. show_version ( ) ?;
803- let dist_version = distributable. show_dist_version ( ) . await ?;
804- let _ = t. attr ( terminalsource:: Attr :: Bold ) ;
805- write ! ( t. lock( ) , "{name} - " ) ?;
806- match ( current_version, dist_version) {
807- ( None , None ) => {
808- let _ = t. fg ( terminalsource:: Color :: Red ) ;
809- writeln ! ( t. lock( ) , "Cannot identify installed or update versions" ) ?;
810- }
811- ( Some ( cv) , None ) => {
812- let _ = t. fg ( terminalsource:: Color :: Green ) ;
813- write ! ( t. lock( ) , "Up to date" ) ?;
814- let _ = t. reset ( ) ;
815- writeln ! ( t. lock( ) , " : {cv}" ) ?;
804+ let num_channels = channels. len ( ) ;
805+ // Ensure that `.buffered()` is never called with 0 as this will cause a hang.
806+ // See: https://github.com/rust-lang/futures-rs/pull/1194#discussion_r209501774
807+ if num_channels > 0 {
808+ let multi_progress_bars = if is_a_tty {
809+ MultiProgress :: with_draw_target ( ProgressDrawTarget :: term_like ( Box :: new ( t) ) )
810+ } else {
811+ MultiProgress :: with_draw_target ( ProgressDrawTarget :: hidden ( ) )
812+ } ;
813+ let channels = tokio_stream:: iter ( channels. into_iter ( ) ) . map ( |( name, distributable) | {
814+ let pb = multi_progress_bars. add ( ProgressBar :: new ( 1 ) ) ;
815+ pb. set_style (
816+ ProgressStyle :: with_template ( "{msg:.bold} - Checking... {spinner:.green}" )
817+ . unwrap ( )
818+ . tick_chars ( "⠁⠂⠄⡀⢀⠠⠐⠈ " ) ,
819+ ) ;
820+ pb. set_message ( format ! ( "{name}" ) ) ;
821+ pb. enable_steady_tick ( Duration :: from_millis ( 100 ) ) ;
822+ async move {
823+ let current_version = distributable. show_version ( ) ?;
824+ let dist_version = distributable. show_dist_version ( ) . await ?;
825+ let mut update_a = false ;
826+
827+ let mut styled_name = style ( format ! ( "{name} - " ) ) ;
828+ if use_colors {
829+ styled_name = styled_name. bold ( ) ;
830+ }
831+ let message = match ( current_version, dist_version) {
832+ ( None , None ) => {
833+ let mut m = style ( "Cannot identify installed or update versions" ) ;
834+ if use_colors {
835+ m = m. red ( ) . bold ( ) ;
836+ }
837+ format ! ( "{styled_name}{m}" )
838+ }
839+ ( Some ( cv) , None ) => {
840+ let mut m = style ( "Up to date" ) ;
841+ if use_colors {
842+ m = m. green ( ) . bold ( ) ;
843+ }
844+ format ! ( "{styled_name}{m} : {cv}" )
845+ }
846+ ( Some ( cv) , Some ( dv) ) => {
847+ let mut m = style ( "Update available" ) ;
848+ if use_colors {
849+ m = m. yellow ( ) . bold ( ) ;
850+ }
851+ update_a = true ;
852+ format ! ( "{styled_name}{m} : {cv} -> {dv}" )
853+ }
854+ ( None , Some ( dv) ) => {
855+ let mut m = style ( "Update available" ) ;
856+ if use_colors {
857+ m = m. yellow ( ) . bold ( ) ;
858+ }
859+ update_a = true ;
860+ format ! ( "{styled_name}{m} : (Unknown version) -> {dv}" )
861+ }
862+ } ;
863+ pb. set_style ( ProgressStyle :: with_template ( message. as_str ( ) ) . unwrap ( ) ) ;
864+ pb. finish ( ) ;
865+ Ok :: < ( bool , String ) , Error > ( ( update_a, message) )
816866 }
817- ( Some ( cv) , Some ( dv) ) => {
867+ } ) ;
868+
869+ // If we are running in a TTY, we can use `buffer_unordered` since
870+ // displaying the output in the correct order is already handled by
871+ // `indicatif`.
872+ let channels = if is_a_tty {
873+ channels
874+ . buffer_unordered ( num_channels)
875+ . collect :: < Vec < _ > > ( )
876+ . await
877+ } else {
878+ channels. buffered ( num_channels) . collect :: < Vec < _ > > ( ) . await
879+ } ;
880+
881+ let t = cfg. process . stdout ( ) . terminal ( cfg. process ) ;
882+ for result in channels {
883+ let ( update_a, message) = result?;
884+ if update_a {
818885 update_available = true ;
819- let _ = t. fg ( terminalsource:: Color :: Yellow ) ;
820- write ! ( t. lock( ) , "Update available" ) ?;
821- let _ = t. reset ( ) ;
822- writeln ! ( t. lock( ) , " : {cv} -> {dv}" ) ?;
823886 }
824- ( None , Some ( dv) ) => {
825- update_available = true ;
826- let _ = t. fg ( terminalsource:: Color :: Yellow ) ;
827- write ! ( t. lock( ) , "Update available" ) ?;
828- let _ = t. reset ( ) ;
829- writeln ! ( t. lock( ) , " : (Unknown version) -> {dv}" ) ?;
887+ if !is_a_tty {
888+ writeln ! ( t. lock( ) , "{message}" ) ?;
830889 }
831890 }
832891 }
833-
834892 let self_update_mode = cfg. get_self_update_mode ( ) ?;
835893 // Priority: no-self-update feature > self_update_mode > no-self-update args.
836894 // Check for update only if rustup does **not** have the no-self-update feature,
0 commit comments