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