@@ -302,9 +302,20 @@ impl RustwideBuilder {
302
302
. build ( & self . toolchain , & krate, self . prepare_sandbox ( & limits) )
303
303
. run ( |build| {
304
304
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" ) ?;
305
308
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
+ ) ?;
308
319
if !res. result . successful {
309
320
bail ! ( "failed to build dummy crate for {}" , rustc_version) ;
310
321
}
@@ -431,6 +442,7 @@ impl RustwideBuilder {
431
442
}
432
443
433
444
let limits = self . get_limits ( name) ?;
445
+
434
446
#[ cfg( target_os = "linux" ) ]
435
447
if !self . config . disable_memory_limit {
436
448
use anyhow:: Context ;
@@ -509,21 +521,50 @@ impl RustwideBuilder {
509
521
default_target,
510
522
other_targets,
511
523
} = 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 ( ) ;
514
547
515
548
{
516
549
let _span = info_span ! ( "fetch_build_std_dependencies" ) . entered ( ) ;
517
550
// 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
+ } ) ?;
519
556
}
520
557
521
558
let mut has_docs = false ;
522
559
let mut successful_targets = Vec :: new ( ) ;
523
560
561
+ let deadline = Instant :: now ( )
562
+ . checked_add ( limits. timeout ( ) )
563
+ . context ( "deadline is not representable" ) ?;
564
+
524
565
// Perform an initial build
525
566
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 ) ?;
527
568
528
569
// If the build fails with the lockfile given, try using only the dependencies listed in Cargo.toml.
529
570
let cargo_lock = build. host_source_dir ( ) . join ( "Cargo.lock" ) ;
@@ -545,7 +586,7 @@ impl RustwideBuilder {
545
586
. run_capture ( ) ?;
546
587
}
547
588
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 ) ?;
549
590
}
550
591
551
592
if res. result . successful {
@@ -572,8 +613,7 @@ impl RustwideBuilder {
572
613
successful_targets. push ( res. target . clone ( ) ) ;
573
614
574
615
// 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 {
577
617
debug ! ( "building package {} {} for {}" , name, version, target) ;
578
618
let target_res = self . build_target (
579
619
target,
@@ -583,6 +623,7 @@ impl RustwideBuilder {
583
623
& mut successful_targets,
584
624
& metadata,
585
625
collect_metrics,
626
+ deadline,
586
627
) ?;
587
628
target_build_logs. insert ( target, target_res. build_log ) ;
588
629
}
@@ -758,6 +799,7 @@ impl RustwideBuilder {
758
799
successful_targets : & mut Vec < String > ,
759
800
metadata : & Metadata ,
760
801
collect_metrics : bool ,
802
+ deadline : Instant ,
761
803
) -> Result < FullBuildResult > {
762
804
let target_res = self . execute_build (
763
805
target,
@@ -767,6 +809,7 @@ impl RustwideBuilder {
767
809
metadata,
768
810
false ,
769
811
collect_metrics,
812
+ deadline,
770
813
) ?;
771
814
if target_res. result . successful {
772
815
// Cargo is not giving any error and not generating documentation of some crates
@@ -787,7 +830,7 @@ impl RustwideBuilder {
787
830
target : & str ,
788
831
build : & Build ,
789
832
metadata : & Metadata ,
790
- limits : & Limits ,
833
+ deadline : Instant ,
791
834
) -> Result < Option < DocCoverage > > {
792
835
let rustdoc_flags = vec ! [
793
836
"--output-format" . to_string( ) ,
@@ -810,7 +853,7 @@ impl RustwideBuilder {
810
853
items_with_examples : 0 ,
811
854
} ;
812
855
813
- self . prepare_command ( build, target, metadata, limits , rustdoc_flags, false ) ?
856
+ self . prepare_command ( build, target, metadata, rustdoc_flags, false , deadline ) ?
814
857
. process_lines ( & mut |line, _| {
815
858
if line. starts_with ( '{' ) && line. ends_with ( '}' ) {
816
859
let parsed = match serde_json:: from_str :: < HashMap < String , FileCoverage > > ( line) {
@@ -848,6 +891,7 @@ impl RustwideBuilder {
848
891
metadata : & Metadata ,
849
892
create_essential_files : bool ,
850
893
collect_metrics : bool ,
894
+ deadline : Instant ,
851
895
) -> Result < FullBuildResult > {
852
896
let cargo_metadata = CargoMetadata :: load_from_rustwide (
853
897
& self . workspace ,
@@ -874,7 +918,7 @@ impl RustwideBuilder {
874
918
// we have to run coverage before the doc-build because currently it
875
919
// deletes the doc-target folder.
876
920
// 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 ) {
878
922
Ok ( cov) => cov,
879
923
Err ( err) => {
880
924
info ! ( "error when trying to get coverage: {}" , err) ;
@@ -890,9 +934,9 @@ impl RustwideBuilder {
890
934
build,
891
935
target,
892
936
metadata,
893
- limits,
894
937
rustdoc_flags,
895
938
collect_metrics,
939
+ deadline,
896
940
)
897
941
. and_then ( |command| command. run ( ) . map_err ( Error :: from) )
898
942
. is_ok ( )
@@ -949,10 +993,14 @@ impl RustwideBuilder {
949
993
build : & ' ws Build ,
950
994
target : & str ,
951
995
metadata : & Metadata ,
952
- limits : & Limits ,
953
996
mut rustdoc_flags_extras : Vec < String > ,
954
997
collect_metrics : bool ,
998
+ deadline : Instant ,
955
999
) -> Result < Command < ' ws , ' pl > > {
1000
+ let timeout = deadline
1001
+ . checked_duration_since ( Instant :: now ( ) )
1002
+ . context ( "exceeded deadline" ) ?;
1003
+
956
1004
// Add docs.rs specific arguments
957
1005
let mut cargo_args = vec ! [
958
1006
"--offline" . into( ) ,
@@ -1000,20 +1048,7 @@ impl RustwideBuilder {
1000
1048
rustdoc_flags_extras. extend ( UNCONDITIONAL_ARGS . iter ( ) . map ( |& s| s. to_owned ( ) ) ) ;
1001
1049
let mut cargo_args = metadata. cargo_args ( & cargo_args, & rustdoc_flags_extras) ;
1002
1050
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 ) ;
1017
1052
1018
1053
for ( key, val) in metadata. environment_variables ( ) {
1019
1054
command = command. env ( key, val) ;
@@ -1117,6 +1152,7 @@ mod tests {
1117
1152
use std:: iter;
1118
1153
1119
1154
use super :: * ;
1155
+ use crate :: db:: Overrides ;
1120
1156
use crate :: db:: types:: Feature ;
1121
1157
use crate :: registry_api:: ReleaseData ;
1122
1158
use crate :: storage:: CompressionAlgorithm ;
@@ -1741,6 +1777,61 @@ mod tests {
1741
1777
} ) ;
1742
1778
}
1743
1779
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
+
1744
1835
#[ test]
1745
1836
#[ ignore]
1746
1837
fn test_implicit_features_for_optional_dependencies ( ) {
0 commit comments