@@ -6,11 +6,15 @@ use std::{
6
6
path:: { Path , PathBuf } ,
7
7
process:: ExitStatus ,
8
8
str:: FromStr ,
9
+ time:: Duration ,
9
10
} ;
10
11
11
12
use anyhow:: { Context , Error , Result , anyhow} ;
12
13
use clap:: { Args , CommandFactory , Parser , Subcommand , ValueEnum , builder:: PossibleValue } ;
13
14
use clap_complete:: Shell ;
15
+ use console:: style;
16
+ use futures_util:: stream:: StreamExt ;
17
+ use indicatif:: { MultiProgress , ProgressBar , ProgressDrawTarget , ProgressStyle } ;
14
18
use itertools:: Itertools ;
15
19
use tracing:: { info, trace, warn} ;
16
20
use tracing_subscriber:: { EnvFilter , Registry , reload:: Handle } ;
@@ -34,7 +38,7 @@ use crate::{
34
38
install:: { InstallMethod , UpdateStatus } ,
35
39
process:: {
36
40
Process ,
37
- terminalsource:: { self , ColorableTerminal } ,
41
+ terminalsource:: { self , ColorChoice , ColorableTerminal } ,
38
42
} ,
39
43
toolchain:: {
40
44
CustomToolchainName , DistributableToolchain , LocalToolchainName ,
@@ -792,45 +796,99 @@ async fn default_(
792
796
}
793
797
794
798
async 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 ) ;
795
802
let mut update_available = false ;
796
-
797
- let mut t = cfg. process . stdout ( ) . terminal ( cfg. process ) ;
798
803
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) )
816
866
}
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 {
818
885
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}" ) ?;
823
886
}
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}" ) ?;
830
889
}
831
890
}
832
891
}
833
-
834
892
let self_update_mode = cfg. get_self_update_mode ( ) ?;
835
893
// Priority: no-self-update feature > self_update_mode > no-self-update args.
836
894
// Check for update only if rustup does **not** have the no-self-update feature,
0 commit comments