@@ -10,6 +10,7 @@ use std::{cmp, env};
1010use anstyle:: Style ;
1111use anyhow:: { Context , Result , anyhow} ;
1212use clap_cargo:: style:: { CONTEXT , ERROR , UPDATE_ADDED , UPDATE_UNCHANGED , UPDATE_UPGRADED } ;
13+ use futures_util:: future:: join_all;
1314use git_testament:: { git_testament, render_testament} ;
1415use tracing:: { error, info, warn} ;
1516use tracing_subscriber:: { EnvFilter , Registry , reload:: Handle } ;
@@ -213,11 +214,26 @@ fn show_channel_updates(
213214
214215pub ( crate ) async fn update_all_channels ( cfg : & Cfg < ' _ > , force_update : bool ) -> Result < ExitCode > {
215216 let profile = cfg. get_profile ( ) ?;
217+ let channels = cfg. list_channels ( ) ?;
218+
219+ // Run a pre-check to determine which channels have updates available.
220+ let channels_with_manifests = join_all ( channels. into_iter ( ) . map ( |( desc, d) | async move {
221+ // Prefetch errors are intentionally discarded; a failed prefetch falls
222+ // back to the normal update path, where errors are properly propagated.
223+ let manifest = d. fetch_dist_manifest ( ) . await . unwrap_or ( None ) ;
224+ ( desc, d, manifest)
225+ } ) )
226+ . await ;
227+
216228 let mut toolchains = Vec :: new ( ) ;
217- for ( desc, distributable) in cfg. list_channels ( ) ? {
218- let options = DistOptions :: new ( & [ ] , & [ ] , & desc, profile, force_update, cfg) ?
219- . for_update ( & distributable, false ) ;
220- let result = InstallMethod :: Dist ( options) . install ( None ) . await ;
229+ for ( desc, distributable, manifest) in channels_with_manifests {
230+ let result = if force_update || manifest. is_some ( ) {
231+ let options = DistOptions :: new ( & [ ] , & [ ] , & desc, profile, force_update, cfg) ?
232+ . for_update ( & distributable, false ) ;
233+ InstallMethod :: Dist ( options) . install ( manifest) . await
234+ } else {
235+ Ok ( UpdateStatus :: Unchanged )
236+ } ;
221237
222238 if let Err ( e) = & result {
223239 error ! ( "{e}" ) ;
0 commit comments