@@ -7,10 +7,10 @@ use std::collections::HashMap;
77use std:: io:: { stdin, stdout, Write } ;
88
99use clap:: { ArgMatches , Clap , FromArgMatches } ;
10- use futures_util:: future:: { join_all, try_join_all } ;
11- use tokio:: try_join ;
10+ use futures_util:: future:: join_all;
11+ use tokio:: join ;
1212
13- use crate as deploy;
13+ use crate :: { self as deploy, CmdOverrides , DeployDefs } ;
1414use crate :: push:: { PushProfileData , PushProfileError } ;
1515
1616use self :: deploy:: { DeployFlake , ParseFlakeError } ;
@@ -600,25 +600,111 @@ async fn run_deploy(
600600 }
601601 } ) ;
602602
603- try_join ! (
603+ async fn deploy_profiles_to_host < ' a > ( ( host, profiles) : ( & str , Vec < & ' a PushProfileData < ' a > > ) ) -> Result < ( ) , ( String , String , PushProfileError ) > {
604+ for profile in & profiles {
605+ deploy:: push:: build_profile ( profile) . await . map_err ( |e| ( host. to_string ( ) , profile. deploy_data . profile_name . to_string ( ) , e) ) ?;
606+ } ;
607+ Ok ( ( ) )
608+ }
609+
610+ let ( remote_results, local_results) = join ! (
611+ // remote builds can be run asynchronously (per host)
612+ join_all( remote_build_map. into_iter( ) . map( deploy_profiles_to_host) ) ,
613+
604614 // remote builds can be run asynchronously (per host)
605- try_join_all( remote_build_map. into_iter( ) . map( deploy_profiles_to_host) ) ,
606- async {
615+ async move {
616+ let mut build_results = Vec :: new( ) ;
617+ let mut push_futures = Vec :: new( ) ;
618+
607619 // run local builds synchronously to prevent hardware deadlocks
608- for data in & local_builds {
609- deploy:: push:: build_profile( data) . await . unwrap( ) ;
620+ for data in local_builds {
621+ let res = deploy:: push:: build_profile( & data) . await ;
622+ if res. is_ok( ) {
623+ // unfortunately, all of this is necessary to please the borrow checker
624+ // since deploy_data is a nested struct of references, the spawned process
625+ // could outlive the scope of this function where the references' values are
626+ // defined
627+ let node_name = data. deploy_data. node_name. to_string( ) ;
628+ let node = data. deploy_data. node. clone( ) ;
629+ let profile_name = data. deploy_data. profile_name. to_string( ) ;
630+ let profile = data. deploy_data. profile. clone( ) ;
631+ let cmd_overrides = data. deploy_data. cmd_overrides. clone( ) ;
632+ let merged_settings = data. deploy_data. merged_settings. clone( ) ;
633+ let debug_logs = data. deploy_data. debug_logs. clone( ) ;
634+ let log_dir = data. deploy_data. log_dir. map( |x| x. to_string( ) ) ;
635+ let extra_build_args: Vec <String > = data. extra_build_args. iter( ) . cloned( ) . collect( ) ;
636+ let result_path = data. result_path. map( |x| x. to_string( ) ) ;
637+ let keep_result = data. keep_result. clone( ) ;
638+ let deploy_defs = data. deploy_defs. clone( ) ;
639+ let repo = data. repo. to_string( ) ;
640+ let check_sigs = data. check_sigs. clone( ) ;
641+
642+ let handle = tokio:: spawn( async move {
643+ let deploy_data = deploy:: DeployData {
644+ node_name: & node_name,
645+ node: & node,
646+ profile_name: & profile_name,
647+ profile: & profile,
648+ cmd_overrides: & cmd_overrides,
649+ merged_settings,
650+ debug_logs,
651+ log_dir: log_dir. as_deref( )
652+ } ;
653+
654+ let data = PushProfileData {
655+ check_sigs,
656+ repo: & repo,
657+ deploy_data: & deploy_data,
658+ deploy_defs: & deploy_defs,
659+ keep_result,
660+ result_path: result_path. as_deref( ) ,
661+ extra_build_args: & extra_build_args,
662+ supports_flakes: true ,
663+ } ;
664+
665+ deploy:: push:: push_profile( & data) . await
666+ } ) ;
667+ push_futures. push( handle) ;
668+ }
669+ build_results. push( res) ;
610670 }
611671
612- // push all profiles asynchronously
613- join_all( local_builds. into_iter( ) . map( |data| async {
614- let data = data;
615- deploy:: push:: push_profile( & data) . await
616- } ) ) . await ;
672+ let push_results = join_all( push_futures) . await ;
617673
618- Ok ( ( ) )
674+ ( build_results , push_results )
619675 }
620- ) ? ;
676+ ) ;
621677
678+ for result in local_results. 0 {
679+ match result {
680+ Err ( e) => {
681+ error ! ( "failed building profile locally: {:?}" , e) ;
682+ return Err ( RunDeployError :: PushProfile ( e) ) ;
683+ } ,
684+ _ => ( ) ,
685+ }
686+ }
687+
688+ for result in local_results. 1 {
689+ match result {
690+ Err ( e) => panic ! ( "failed to join future: {}, please open a bug report" , e) ,
691+ Ok ( Err ( e) ) => {
692+ error ! ( "failed pushing profile: {:?}" , e) ;
693+ return Err ( RunDeployError :: PushProfile ( e) ) ;
694+ } ,
695+ _ => ( ) ,
696+ }
697+ }
698+
699+ for result in remote_results {
700+ match result {
701+ Err ( ( host, profile, e) ) => {
702+ error ! ( "failed building profile {} on host {}: {:?}" , profile, host, e) ;
703+ return Err ( RunDeployError :: PushProfile ( e) ) ;
704+ } ,
705+ _ => ( ) ,
706+ }
707+ }
622708
623709 let mut succeeded: Vec < ( & deploy:: DeployData , & deploy:: DeployDefs ) > = vec ! [ ] ;
624710
@@ -750,9 +836,3 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> {
750836 Ok ( ( ) )
751837}
752838
753- async fn deploy_profiles_to_host < ' a > ( ( _host, profiles) : ( & str , Vec < & ' a PushProfileData < ' a > > ) ) -> Result < ( ) , PushProfileError > {
754- for profile in & profiles {
755- deploy:: push:: build_profile ( profile) . await ?;
756- } ;
757- Ok ( ( ) )
758- }
0 commit comments