@@ -3,7 +3,8 @@ use super::Metadata;
33use crate :: db:: blacklist:: is_blacklisted;
44use crate :: db:: file:: add_path_into_database;
55use crate :: db:: {
6- add_build_into_database, add_package_into_database, update_crate_data_in_database, Pool ,
6+ add_build_into_database, add_doc_coverage, add_package_into_database,
7+ update_crate_data_in_database, Pool ,
78} ;
89use crate :: docbuilder:: { crates:: crates_from_path, Limits } ;
910use crate :: error:: Result ;
@@ -428,6 +429,12 @@ impl RustwideBuilder {
428429 algs,
429430 ) ?;
430431
432+ if let ( Some ( total) , Some ( documented) ) =
433+ ( res. result . total_items , res. result . documented_items )
434+ {
435+ add_doc_coverage ( & mut conn, release_id, total, documented) ?;
436+ }
437+
431438 add_build_into_database ( & mut conn, release_id, & res. result ) ?;
432439
433440 // Some crates.io crate data is mutable, so we proactively update it during a release
@@ -469,6 +476,106 @@ impl RustwideBuilder {
469476 Ok ( ( ) )
470477 }
471478
479+ fn get_coverage (
480+ & self ,
481+ target : & str ,
482+ build : & Build ,
483+ metadata : & Metadata ,
484+ limits : & Limits ,
485+ ) -> Option < ( i32 , i32 ) > {
486+ let rustdoc_flags: Vec < String > = vec ! [
487+ "-Z" . to_string( ) ,
488+ "unstable-options" . to_string( ) ,
489+ "--static-root-path" . to_string( ) ,
490+ "/" . to_string( ) ,
491+ "--cap-lints" . to_string( ) ,
492+ "warn" . to_string( ) ,
493+ "--output-format" . to_string( ) ,
494+ "json" . to_string( ) ,
495+ "--show-coverage" . to_string( ) ,
496+ ] ;
497+
498+ let mut cargo_args = vec ! [ "doc" , "--lib" , "--no-deps" ] ;
499+ if target != HOST_TARGET {
500+ // If the explicit target is not a tier one target, we need to install it.
501+ if !TARGETS . contains ( & target) {
502+ // This is a no-op if the target is already installed.
503+ self . toolchain . add_target ( & self . workspace , target) . ok ( ) ?;
504+ }
505+ cargo_args. push ( "--target" ) ;
506+ cargo_args. push ( target) ;
507+ } ;
508+
509+ let tmp_jobs;
510+ if let Some ( cpu_limit) = self . cpu_limit {
511+ tmp_jobs = format ! ( "-j{}" , cpu_limit) ;
512+ cargo_args. push ( & tmp_jobs) ;
513+ }
514+
515+ let tmp;
516+ if let Some ( features) = & metadata. features {
517+ cargo_args. push ( "--features" ) ;
518+ tmp = features. join ( " " ) ;
519+ cargo_args. push ( & tmp) ;
520+ }
521+ if metadata. all_features {
522+ cargo_args. push ( "--all-features" ) ;
523+ }
524+ if metadata. no_default_features {
525+ cargo_args. push ( "--no-default-features" ) ;
526+ }
527+
528+ let mut storage = LogStorage :: new ( LevelFilter :: Info ) ;
529+ storage. set_max_size ( limits. max_log_size ( ) ) ;
530+
531+ let mut json = String :: new ( ) ;
532+ if build
533+ . cargo ( )
534+ . timeout ( Some ( limits. timeout ( ) ) )
535+ . no_output_timeout ( None )
536+ . env (
537+ "RUSTFLAGS" ,
538+ metadata
539+ . rustc_args
540+ . as_ref ( )
541+ . map ( |args| args. join ( " " ) )
542+ . unwrap_or_default ( ) ,
543+ )
544+ . env ( "RUSTDOCFLAGS" , rustdoc_flags. join ( " " ) )
545+ // For docs.rs detection from build script:
546+ // https://github.com/rust-lang/docs.rs/issues/147
547+ . env ( "DOCS_RS" , "1" )
548+ . args ( & cargo_args)
549+ . log_output ( false )
550+ . process_lines ( & mut |line, _| {
551+ if line. starts_with ( '{' ) && line. ends_with ( '}' ) {
552+ json = line. to_owned ( ) ;
553+ }
554+ } )
555+ . run ( )
556+ . is_ok ( )
557+ {
558+ match serde_json:: from_str ( & json) . expect ( "conversion failed..." ) {
559+ Value :: Object ( m) => {
560+ let mut total = 0 ;
561+ let mut documented = 0 ;
562+ for entry in m. values ( ) {
563+ if let Some ( Value :: Number ( n) ) = entry. get ( "total" ) {
564+ total += n. as_i64 ( ) . unwrap_or ( 0 ) as i32 ;
565+ }
566+ if let Some ( Value :: Number ( n) ) = entry. get ( "with_docs" ) {
567+ documented += n. as_i64 ( ) . unwrap_or ( 0 ) as i32 ;
568+ }
569+ }
570+ Some ( ( total, documented) )
571+ }
572+ _ => None ,
573+ }
574+ } else {
575+ None
576+ }
577+ }
578+
472579 fn execute_build (
473580 & self ,
474581 target : & str ,
@@ -556,6 +663,14 @@ impl RustwideBuilder {
556663 . run ( )
557664 . is_ok ( )
558665 } ) ;
666+ let mut total_items = None ;
667+ let mut documented_items = None ;
668+ if successful {
669+ if let Some ( ( total, documented) ) = self . get_coverage ( target, build, metadata, limits) {
670+ total_items = Some ( total) ;
671+ documented_items = Some ( documented) ;
672+ }
673+ }
559674 // If we're passed a default_target which requires a cross-compile,
560675 // cargo will put the output in `target/<target>/doc`.
561676 // However, if this is the default build, we don't want it there,
@@ -575,6 +690,8 @@ impl RustwideBuilder {
575690 rustc_version : self . rustc_version . clone ( ) ,
576691 docsrs_version : format ! ( "docsrs {}" , crate :: BUILD_VERSION ) ,
577692 successful,
693+ total_items,
694+ documented_items,
578695 } ,
579696 cargo_metadata,
580697 target : target. to_string ( ) ,
@@ -631,4 +748,7 @@ pub(crate) struct BuildResult {
631748 pub ( crate ) docsrs_version : String ,
632749 pub ( crate ) build_log : String ,
633750 pub ( crate ) successful : bool ,
751+ // The two next fields are used for the doc coverage.
752+ pub ( crate ) total_items : Option < i32 > ,
753+ pub ( crate ) documented_items : Option < i32 > ,
634754}
0 commit comments