@@ -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