@@ -20,7 +20,7 @@ use rustwide::toolchain::ToolchainError;
2020use rustwide:: { Build , Crate , Toolchain , Workspace , WorkspaceBuilder } ;
2121use serde_json:: Value ;
2222use std:: borrow:: Cow ;
23- use std:: collections:: HashSet ;
23+ use std:: collections:: { HashMap , HashSet } ;
2424use std:: path:: Path ;
2525use std:: sync:: Arc ;
2626
@@ -69,84 +69,6 @@ const ESSENTIAL_FILES_UNVERSIONED: &[&str] = &[
6969const DUMMY_CRATE_NAME : & str = "empty-library" ;
7070const DUMMY_CRATE_VERSION : & str = "1.0.0" ;
7171
72- // This macro exists because of lifetimes issues surrounding the `Command::process_lines` method:
73- // it expects a mutable reference to a closure, in which we capture a variable in order to store
74- // the JSON output. Unfortunately, we *need* to create the command in the same scope level otherwise
75- // rustc becomes very grumpy about the fact that the variable needs to be static because it is
76- // captured in a mutably referenced closure.
77- //
78- // So either you create a function with a callback in which you pass the `Command` as an argument,
79- // or you create a function returning a `Command`, it's very unhappy in both cases.
80- //
81- // TODO: make `Command::process_lines` take the closure by value rather than a mutable reference.
82- macro_rules! config_command {
83- ( $obj: ident, $build: expr, $target: expr, $metadata: expr, $limits: expr, $rustdoc_flags_extras: expr, $( $extra: tt) +) => { {
84- let mut cargo_args = vec![ "doc" , "--lib" , "--no-deps" ] ;
85- if $target != HOST_TARGET {
86- // If the explicit target is not a tier one target, we need to install it.
87- if !TARGETS . contains( & $target) {
88- // This is a no-op if the target is already installed.
89- $obj. toolchain. add_target( & $obj. workspace, $target) ?;
90- }
91- cargo_args. push( "--target" ) ;
92- cargo_args. push( $target) ;
93- } ;
94-
95- let tmp;
96- if let Some ( cpu_limit) = $obj. cpu_limit {
97- tmp = format!( "-j{}" , cpu_limit) ;
98- cargo_args. push( & tmp) ;
99- }
100-
101- let tmp;
102- if let Some ( features) = & $metadata. features {
103- cargo_args. push( "--features" ) ;
104- tmp = features. join( " " ) ;
105- cargo_args. push( & tmp) ;
106- }
107- if $metadata. all_features {
108- cargo_args. push( "--all-features" ) ;
109- }
110- if $metadata. no_default_features {
111- cargo_args. push( "--no-default-features" ) ;
112- }
113-
114- let mut rustdoc_flags = vec![
115- "-Z" . to_string( ) ,
116- "unstable-options" . to_string( ) ,
117- "--static-root-path" . to_string( ) ,
118- "/" . to_string( ) ,
119- "--cap-lints" . to_string( ) ,
120- "warn" . to_string( ) ,
121- ] ;
122-
123- if let Some ( package_rustdoc_args) = & $metadata. rustdoc_args {
124- rustdoc_flags. append( & mut package_rustdoc_args. clone( ) ) ;
125- }
126-
127- rustdoc_flags. extend( $rustdoc_flags_extras) ;
128-
129- $build
130- . cargo( )
131- . timeout( Some ( $limits. timeout( ) ) )
132- . no_output_timeout( None )
133- . env(
134- "RUSTFLAGS" ,
135- $metadata
136- . rustc_args
137- . as_ref( )
138- . map( |args| args. join( " " ) )
139- . unwrap_or_default( ) ,
140- )
141- . env( "RUSTDOCFLAGS" , rustdoc_flags. join( " " ) )
142- // For docs.rs detection from build script:
143- // https://github.com/rust-lang/docs.rs/issues/147
144- . env( "DOCS_RS" , "1" )
145- . args( & cargo_args)
146- $( $extra) +
147- } }
148- }
149-
15072pub struct RustwideBuilder {
15173 workspace : Workspace ,
15274 toolchain : Toolchain ,
@@ -558,41 +480,46 @@ impl RustwideBuilder {
558480 metadata : & Metadata ,
559481 limits : & Limits ,
560482 ) -> Result < Option < DocCoverage > > {
561- let mut doc_coverage_json = None ;
562-
563483 let rustdoc_flags = vec ! [
564484 "--output-format" . to_string( ) ,
565485 "json" . to_string( ) ,
566486 "--show-coverage" . to_string( ) ,
567487 ] ;
568- config_command ! ( self , build, target, metadata, limits, rustdoc_flags,
488+
489+ #[ derive( serde:: Deserialize ) ]
490+ struct FileCoverage {
491+ total : i32 ,
492+ with_docs : i32 ,
493+ }
494+
495+ let mut coverage = DocCoverage {
496+ total_items : 0 ,
497+ documented_items : 0 ,
498+ } ;
499+
500+ self . prepare_command ( build, target, metadata, limits, rustdoc_flags) ?
569501 . process_lines ( & mut |line, _| {
570502 if line. starts_with ( '{' ) && line. ends_with ( '}' ) {
571- doc_coverage_json = Some ( line. to_owned( ) ) ;
503+ let parsed = match serde_json:: from_str :: < HashMap < String , FileCoverage > > ( line) {
504+ Ok ( parsed) => parsed,
505+ Err ( _) => return ,
506+ } ;
507+ for file in parsed. values ( ) {
508+ coverage. total_items += file. total ;
509+ coverage. documented_items += file. with_docs ;
510+ }
572511 }
573512 } )
574513 . log_output ( false )
575514 . run ( ) ?;
576- ) ;
577-
578- if let Some ( json) = doc_coverage_json {
579- if let Ok ( Value :: Object ( m) ) = serde_json:: from_str ( & json) {
580- let ( mut total_items, mut documented_items) = ( 0 , 0 ) ;
581- for entry in m. values ( ) {
582- if let Some ( Value :: Number ( n) ) = entry. get ( "total" ) {
583- total_items += n. as_i64 ( ) . unwrap_or ( 0 ) as i32 ;
584- }
585- if let Some ( Value :: Number ( n) ) = entry. get ( "with_docs" ) {
586- documented_items += n. as_i64 ( ) . unwrap_or ( 0 ) as i32 ;
587- }
588- }
589- return Ok ( Some ( DocCoverage {
590- total_items,
591- documented_items,
592- } ) ) ;
593- }
594- }
595- Ok ( None )
515+
516+ Ok (
517+ if coverage. total_items == 0 && coverage. documented_items == 0 {
518+ None
519+ } else {
520+ Some ( coverage)
521+ } ,
522+ )
596523 }
597524
598525 fn execute_build (
@@ -627,12 +554,9 @@ impl RustwideBuilder {
627554 storage. set_max_size ( limits. max_log_size ( ) ) ;
628555
629556 let successful = logging:: capture ( & storage, || {
630- let wrap = || {
631- config_command ! ( self , build, target, metadata, limits, rustdoc_flags,
632- . run( )
633- )
634- } ;
635- wrap ( ) . is_ok ( )
557+ self . prepare_command ( build, target, metadata, limits, rustdoc_flags)
558+ . and_then ( |command| command. run ( ) . map_err ( failure:: Error :: from) )
559+ . is_ok ( )
636560 } ) ;
637561 let doc_coverage = if successful {
638562 self . get_coverage ( target, build, metadata, limits) ?
@@ -665,6 +589,80 @@ impl RustwideBuilder {
665589 } )
666590 }
667591
592+ fn prepare_command < ' ws , ' pl > (
593+ & self ,
594+ build : & ' ws Build ,
595+ target : & str ,
596+ metadata : & Metadata ,
597+ limits : & Limits ,
598+ rustdoc_flags_extras : Vec < String > ,
599+ ) -> Result < Command < ' ws , ' pl > > {
600+ let mut cargo_args = vec ! [ "doc" , "--lib" , "--no-deps" ] ;
601+ if target != HOST_TARGET {
602+ // If the explicit target is not a tier one target, we need to install it.
603+ if !TARGETS . contains ( & target) {
604+ // This is a no-op if the target is already installed.
605+ self . toolchain . add_target ( & self . workspace , target) ?;
606+ }
607+ cargo_args. push ( "--target" ) ;
608+ cargo_args. push ( target) ;
609+ } ;
610+
611+ let tmp;
612+ if let Some ( cpu_limit) = self . cpu_limit {
613+ tmp = format ! ( "-j{}" , cpu_limit) ;
614+ cargo_args. push ( & tmp) ;
615+ }
616+
617+ let tmp;
618+ if let Some ( features) = & metadata. features {
619+ cargo_args. push ( "--features" ) ;
620+ tmp = features. join ( " " ) ;
621+ cargo_args. push ( & tmp) ;
622+ }
623+ if metadata. all_features {
624+ cargo_args. push ( "--all-features" ) ;
625+ }
626+ if metadata. no_default_features {
627+ cargo_args. push ( "--no-default-features" ) ;
628+ }
629+
630+ let mut rustdoc_flags = vec ! [
631+ "-Z" . to_string( ) ,
632+ "unstable-options" . to_string( ) ,
633+ "--static-root-path" . to_string( ) ,
634+ "/" . to_string( ) ,
635+ "--cap-lints" . to_string( ) ,
636+ "warn" . to_string( ) ,
637+ ] ;
638+
639+ if let Some ( package_rustdoc_args) = & metadata. rustdoc_args {
640+ rustdoc_flags. append ( & mut package_rustdoc_args. clone ( ) ) ;
641+ }
642+
643+ rustdoc_flags. extend ( rustdoc_flags_extras) ;
644+
645+ let command = build
646+ . cargo ( )
647+ . timeout ( Some ( limits. timeout ( ) ) )
648+ . no_output_timeout ( None )
649+ . env (
650+ "RUSTFLAGS" ,
651+ metadata
652+ . rustc_args
653+ . as_ref ( )
654+ . map ( |args| args. join ( " " ) )
655+ . unwrap_or_default ( ) ,
656+ )
657+ . env ( "RUSTDOCFLAGS" , rustdoc_flags. join ( " " ) )
658+ // For docs.rs detection from build script:
659+ // https://github.com/rust-lang/docs.rs/issues/147
660+ . env ( "DOCS_RS" , "1" )
661+ . args ( & cargo_args) ;
662+
663+ Ok ( command)
664+ }
665+
668666 fn copy_docs (
669667 & self ,
670668 target_dir : & Path ,
0 commit comments