@@ -302,9 +302,20 @@ impl RustwideBuilder {
302302            . build ( & self . toolchain ,  & krate,  self . prepare_sandbox ( & limits) ) 
303303            . run ( |build| { 
304304                let  metadata = Metadata :: from_crate_root ( build. host_source_dir ( ) ) ?; 
305+                 let  deadline = Instant :: now ( ) 
306+                     . checked_add ( limits. timeout ( ) ) 
307+                     . context ( "deadline is not representable" ) ?; 
305308
306-                 let  res =
307-                     self . execute_build ( HOST_TARGET ,  true ,  build,  & limits,  & metadata,  true ,  false ) ?; 
309+                 let  res = self . execute_build ( 
310+                     HOST_TARGET , 
311+                     true , 
312+                     build, 
313+                     & limits, 
314+                     & metadata, 
315+                     true , 
316+                     false , 
317+                     deadline, 
318+                 ) ?; 
308319                if  !res. result . successful  { 
309320                    bail ! ( "failed to build dummy crate for {}" ,  rustc_version) ; 
310321                } 
@@ -431,6 +442,7 @@ impl RustwideBuilder {
431442        } 
432443
433444        let  limits = self . get_limits ( name) ?; 
445+ 
434446        #[ cfg( target_os = "linux" ) ]  
435447        if  !self . config . disable_memory_limit  { 
436448            use  anyhow:: Context ; 
@@ -509,21 +521,50 @@ impl RustwideBuilder {
509521                    default_target, 
510522                    other_targets, 
511523                }  = metadata. targets ( self . config . include_default_targets ) ; 
512-                 let  mut  targets = vec ! [ default_target] ; 
513-                 targets. extend ( & other_targets) ; 
524+ 
525+                 let  cargo_args = metadata. cargo_args ( & [ ] ,  & [ ] ) ; 
526+                 let  has_build_std = cargo_args. iter ( ) . any ( |arg| arg. starts_with ( "-Zbuild-std" ) ) 
527+                     || cargo_args
528+                         . windows ( 2 ) 
529+                         . any ( |args| args[ 0 ]  == "-Z"  && args[ 1 ] . starts_with ( "build-std" ) ) ; 
530+ 
531+                 let  other_targets:  Vec < _ >  = other_targets
532+                     . into_iter ( ) 
533+                     . filter ( |target| { 
534+                         // If the explicit target is not a tier one target, we need to install it. 
535+                         if  !docsrs_metadata:: DEFAULT_TARGETS . contains ( target)  && !has_build_std { 
536+                             // This is a no-op if the target is already installed. 
537+                             if  let  Err ( e)  = self . toolchain . add_target ( & self . workspace ,  target)  { 
538+                                 info ! ( "Skipping target {target} since it failed to install: {e}" ) ; 
539+                                 return  false ; 
540+                             } 
541+                         } 
542+                         true 
543+                     } ) 
544+                     // Limit the number of targets so that no one can try to build all 200000 possible targets 
545+                     . take ( limits. targets ( ) ) 
546+                     . collect ( ) ; 
514547
515548                { 
516549                    let  _span = info_span ! ( "fetch_build_std_dependencies" ) . entered ( ) ; 
517550                    // Fetch this before we enter the sandbox, so networking isn't blocked. 
518-                     build. fetch_build_std_dependencies ( & targets) ?; 
551+                     build. fetch_build_std_dependencies ( & { 
552+                         let  mut  targets = other_targets. clone ( ) ; 
553+                         targets. push ( default_target) ; 
554+                         targets
555+                     } ) ?; 
519556                } 
520557
521558                let  mut  has_docs = false ; 
522559                let  mut  successful_targets = Vec :: new ( ) ; 
523560
561+                 let  deadline = Instant :: now ( ) 
562+                     . checked_add ( limits. timeout ( ) ) 
563+                     . context ( "deadline is not representable" ) ?; 
564+ 
524565                // Perform an initial build 
525566                let  mut  res =
526-                     self . execute_build ( default_target,  true ,  build,  & limits,  & metadata,  false ,  collect_metrics) ?; 
567+                     self . execute_build ( default_target,  true ,  build,  & limits,  & metadata,  false ,  collect_metrics,  deadline ) ?; 
527568
528569                // If the build fails with the lockfile given, try using only the dependencies listed in Cargo.toml. 
529570                let  cargo_lock = build. host_source_dir ( ) . join ( "Cargo.lock" ) ; 
@@ -545,7 +586,7 @@ impl RustwideBuilder {
545586                            . run_capture ( ) ?; 
546587                    } 
547588                    res =
548-                         self . execute_build ( default_target,  true ,  build,  & limits,  & metadata,  false ,  collect_metrics) ?; 
589+                         self . execute_build ( default_target,  true ,  build,  & limits,  & metadata,  false ,  collect_metrics,  deadline ) ?; 
549590                } 
550591
551592                if  res. result . successful  { 
@@ -572,8 +613,7 @@ impl RustwideBuilder {
572613                    successful_targets. push ( res. target . clone ( ) ) ; 
573614
574615                    // Then build the documentation for all the targets 
575-                     // Limit the number of targets so that no one can try to build all 200000 possible targets 
576-                     for  target in  other_targets. into_iter ( ) . take ( limits. targets ( ) )  { 
616+                     for  target in  other_targets { 
577617                        debug ! ( "building package {} {} for {}" ,  name,  version,  target) ; 
578618                        let  target_res = self . build_target ( 
579619                            target, 
@@ -583,6 +623,7 @@ impl RustwideBuilder {
583623                            & mut  successful_targets, 
584624                            & metadata, 
585625                            collect_metrics, 
626+                             deadline, 
586627                        ) ?; 
587628                        target_build_logs. insert ( target,  target_res. build_log ) ; 
588629                    } 
@@ -758,6 +799,7 @@ impl RustwideBuilder {
758799        successful_targets :  & mut  Vec < String > , 
759800        metadata :  & Metadata , 
760801        collect_metrics :  bool , 
802+         deadline :  Instant , 
761803    )  -> Result < FullBuildResult >  { 
762804        let  target_res = self . execute_build ( 
763805            target, 
@@ -767,6 +809,7 @@ impl RustwideBuilder {
767809            metadata, 
768810            false , 
769811            collect_metrics, 
812+             deadline, 
770813        ) ?; 
771814        if  target_res. result . successful  { 
772815            // Cargo is not giving any error and not generating documentation of some crates 
@@ -787,7 +830,7 @@ impl RustwideBuilder {
787830        target :  & str , 
788831        build :  & Build , 
789832        metadata :  & Metadata , 
790-         limits :   & Limits , 
833+         deadline :   Instant , 
791834    )  -> Result < Option < DocCoverage > >  { 
792835        let  rustdoc_flags = vec ! [ 
793836            "--output-format" . to_string( ) , 
@@ -810,7 +853,7 @@ impl RustwideBuilder {
810853            items_with_examples :  0 , 
811854        } ; 
812855
813-         self . prepare_command ( build,  target,  metadata,  limits ,   rustdoc_flags,  false ) ?
856+         self . prepare_command ( build,  target,  metadata,  rustdoc_flags,  false ,  deadline ) ?
814857            . process_lines ( & mut  |line,  _| { 
815858                if  line. starts_with ( '{' )  && line. ends_with ( '}' )  { 
816859                    let  parsed = match  serde_json:: from_str :: < HashMap < String ,  FileCoverage > > ( line)  { 
@@ -848,6 +891,7 @@ impl RustwideBuilder {
848891        metadata :  & Metadata , 
849892        create_essential_files :  bool , 
850893        collect_metrics :  bool , 
894+         deadline :  Instant , 
851895    )  -> Result < FullBuildResult >  { 
852896        let  cargo_metadata = CargoMetadata :: load_from_rustwide ( 
853897            & self . workspace , 
@@ -874,7 +918,7 @@ impl RustwideBuilder {
874918        // we have to run coverage before the doc-build because currently it 
875919        // deletes the doc-target folder. 
876920        // https://github.com/rust-lang/cargo/issues/9447 
877-         let  doc_coverage = match  self . get_coverage ( target,  build,  metadata,  limits )  { 
921+         let  doc_coverage = match  self . get_coverage ( target,  build,  metadata,  deadline )  { 
878922            Ok ( cov)  => cov, 
879923            Err ( err)  => { 
880924                info ! ( "error when trying to get coverage: {}" ,  err) ; 
@@ -890,9 +934,9 @@ impl RustwideBuilder {
890934                    build, 
891935                    target, 
892936                    metadata, 
893-                     limits, 
894937                    rustdoc_flags, 
895938                    collect_metrics, 
939+                     deadline, 
896940                ) 
897941                . and_then ( |command| command. run ( ) . map_err ( Error :: from) ) 
898942                . is_ok ( ) 
@@ -949,10 +993,14 @@ impl RustwideBuilder {
949993        build :  & ' ws  Build , 
950994        target :  & str , 
951995        metadata :  & Metadata , 
952-         limits :  & Limits , 
953996        mut  rustdoc_flags_extras :  Vec < String > , 
954997        collect_metrics :  bool , 
998+         deadline :  Instant , 
955999    )  -> Result < Command < ' ws ,  ' pl > >  { 
1000+         let  timeout = deadline
1001+             . checked_duration_since ( Instant :: now ( ) ) 
1002+             . context ( "exceeded deadline" ) ?; 
1003+ 
9561004        // Add docs.rs specific arguments 
9571005        let  mut  cargo_args = vec ! [ 
9581006            "--offline" . into( ) , 
@@ -1000,20 +1048,7 @@ impl RustwideBuilder {
10001048        rustdoc_flags_extras. extend ( UNCONDITIONAL_ARGS . iter ( ) . map ( |& s| s. to_owned ( ) ) ) ; 
10011049        let  mut  cargo_args = metadata. cargo_args ( & cargo_args,  & rustdoc_flags_extras) ; 
10021050
1003-         // If the explicit target is not a tier one target, we need to install it. 
1004-         let  has_build_std = cargo_args. windows ( 2 ) . any ( |args| { 
1005-             args[ 0 ] . starts_with ( "-Zbuild-std" ) 
1006-                 || ( args[ 0 ]  == "-Z"  && args[ 1 ] . starts_with ( "build-std" ) ) 
1007-         } )  || cargo_args. last ( ) . unwrap ( ) . starts_with ( "-Zbuild-std" ) ; 
1008-         if  !docsrs_metadata:: DEFAULT_TARGETS . contains ( & target)  && !has_build_std { 
1009-             // This is a no-op if the target is already installed. 
1010-             self . toolchain . add_target ( & self . workspace ,  target) ?; 
1011-         } 
1012- 
1013-         let  mut  command = build
1014-             . cargo ( ) 
1015-             . timeout ( Some ( limits. timeout ( ) ) ) 
1016-             . no_output_timeout ( None ) ; 
1051+         let  mut  command = build. cargo ( ) . timeout ( Some ( timeout) ) . no_output_timeout ( None ) ; 
10171052
10181053        for  ( key,  val)  in  metadata. environment_variables ( )  { 
10191054            command = command. env ( key,  val) ; 
@@ -1117,6 +1152,7 @@ mod tests {
11171152    use  std:: iter; 
11181153
11191154    use  super :: * ; 
1155+     use  crate :: db:: Overrides ; 
11201156    use  crate :: db:: types:: Feature ; 
11211157    use  crate :: registry_api:: ReleaseData ; 
11221158    use  crate :: storage:: CompressionAlgorithm ; 
@@ -1741,6 +1777,61 @@ mod tests {
17411777        } ) ; 
17421778    } 
17431779
1780+     #[ test]  
1781+     #[ ignore]  
1782+     fn  test_timeout_skips_some_targets ( )  { 
1783+         wrapper ( |env| { 
1784+             let  crate_ = "bs58" ; 
1785+             let  version = "0.5.0" ; 
1786+             let  mut  builder = RustwideBuilder :: init ( env) . unwrap ( ) ; 
1787+             let  get_targets =
1788+                 || -> i32  { 
1789+                     env. runtime ( ) . block_on ( async  { 
1790+                         sqlx:: query!( 
1791+                         "SELECT json_array_length(releases.doc_targets) as length FROM releases;" , 
1792+                     ) 
1793+                     . fetch_one ( & mut  * env. async_db ( ) . await . async_conn ( ) . await ) 
1794+                     . await . unwrap ( ) 
1795+                     . length . unwrap ( ) 
1796+                     } ) 
1797+                 } ; 
1798+ 
1799+             // Build once to time it and count how many targets are built 
1800+             let  start = Instant :: now ( ) ; 
1801+             assert ! ( 
1802+                 builder
1803+                     . build_package( crate_,  version,  PackageKind :: CratesIo ,  false ) ?
1804+                     . successful
1805+             ) ; 
1806+             let  timeout = start. elapsed ( )  / 2 ; 
1807+             let  original_targets = get_targets ( ) ; 
1808+ 
1809+             // Build again with half the time and count how many targets are built 
1810+             env. runtime ( ) . block_on ( async  { 
1811+                 Overrides :: save ( 
1812+                     & mut  * env. async_db ( ) . await . async_conn ( ) . await , 
1813+                     crate_, 
1814+                     Overrides  { 
1815+                         memory :  None , 
1816+                         targets :  Some ( original_targets as  usize ) , 
1817+                         timeout :  Some ( timeout) , 
1818+                     } , 
1819+                 ) 
1820+                 . await 
1821+             } ) ?; 
1822+             assert ! ( 
1823+                 builder
1824+                     . build_package( crate_,  version,  PackageKind :: CratesIo ,  false ) ?
1825+                     . successful
1826+             ) ; 
1827+             let  new_targets = get_targets ( ) ; 
1828+ 
1829+             assert ! ( new_targets < original_targets) ; 
1830+ 
1831+             Ok ( ( ) ) 
1832+         } ) ; 
1833+     } 
1834+ 
17441835    #[ test]  
17451836    #[ ignore]  
17461837    fn  test_implicit_features_for_optional_dependencies ( )  { 
0 commit comments