@@ -22,7 +22,7 @@ mod unit;
22
22
pub mod unit_dependencies;
23
23
pub mod unit_graph;
24
24
25
- use std:: collections:: HashSet ;
25
+ use std:: collections:: { HashMap , HashSet } ;
26
26
use std:: env;
27
27
use std:: ffi:: { OsStr , OsString } ;
28
28
use std:: fs:: { self , File } ;
@@ -55,7 +55,7 @@ use crate::core::compiler::future_incompat::FutureIncompatReport;
55
55
pub use crate :: core:: compiler:: unit:: { Unit , UnitInterner } ;
56
56
use crate :: core:: manifest:: TargetSourcePath ;
57
57
use crate :: core:: profiles:: { PanicStrategy , Profile , Strip } ;
58
- use crate :: core:: { Feature , PackageId , Target } ;
58
+ use crate :: core:: { Feature , PackageId , Target , Verbosity } ;
59
59
use crate :: util:: errors:: { CargoResult , VerboseError } ;
60
60
use crate :: util:: interning:: InternedString ;
61
61
use crate :: util:: machine_message:: { self , Message } ;
@@ -654,13 +654,16 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
654
654
rustdoc. arg ( "-C" ) . arg ( format ! ( "metadata={}" , metadata) ) ;
655
655
656
656
let scrape_output_path = |unit : & Unit | -> CargoResult < PathBuf > {
657
- let output_dir = cx. files ( ) . deps_dir ( unit) ;
658
- Ok ( output_dir. join ( format ! ( "{}.examples" , unit. buildkey( ) ) ) )
657
+ cx. outputs ( unit) . map ( |outputs| outputs[ 0 ] . path . clone ( ) )
659
658
} ;
660
659
661
660
if unit. mode . is_doc_scrape ( ) {
662
661
debug_assert ! ( cx. bcx. scrape_units. contains( unit) ) ;
663
662
663
+ if unit. target . is_test ( ) {
664
+ rustdoc. arg ( "--scrape-tests" ) ;
665
+ }
666
+
664
667
rustdoc. arg ( "-Zunstable-options" ) ;
665
668
666
669
rustdoc
@@ -678,18 +681,23 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
678
681
rustdoc. arg ( "--scrape-examples-target-crate" ) . arg ( name) ;
679
682
}
680
683
}
681
- } else if cx. bcx . scrape_units . len ( ) > 0 && cx. bcx . ws . unit_needs_doc_scrape ( unit) {
682
- // We only pass scraped examples to packages in the workspace
683
- // since examples are only coming from reverse-dependencies of workspace packages
684
+ }
684
685
686
+ let should_include_scrape_units = unit. mode . is_doc ( )
687
+ && cx. bcx . scrape_units . len ( ) > 0
688
+ && cx. bcx . ws . unit_needs_doc_scrape ( unit) ;
689
+ let scrape_outputs = if should_include_scrape_units {
685
690
rustdoc. arg ( "-Zunstable-options" ) ;
686
-
687
- for scrape_unit in & cx. bcx . scrape_units {
688
- rustdoc
689
- . arg ( "--with-examples" )
690
- . arg ( scrape_output_path ( scrape_unit) ?) ;
691
- }
692
- }
691
+ Some (
692
+ cx. bcx
693
+ . scrape_units
694
+ . iter ( )
695
+ . map ( |unit| Ok ( ( cx. files ( ) . metadata ( unit) , scrape_output_path ( unit) ?) ) )
696
+ . collect :: < CargoResult < HashMap < _ , _ > > > ( ) ?,
697
+ )
698
+ } else {
699
+ None
700
+ } ;
693
701
694
702
build_deps_args ( & mut rustdoc, cx, unit) ?;
695
703
rustdoc:: add_root_urls ( cx, unit, & mut rustdoc) ?;
@@ -700,19 +708,45 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
700
708
append_crate_version_flag ( unit, & mut rustdoc) ;
701
709
}
702
710
711
+ let target_desc = unit. target . description_named ( ) ;
703
712
let name = unit. pkg . name ( ) . to_string ( ) ;
704
713
let build_script_outputs = Arc :: clone ( & cx. build_script_outputs ) ;
705
714
let package_id = unit. pkg . package_id ( ) ;
706
715
let manifest_path = PathBuf :: from ( unit. pkg . manifest_path ( ) ) ;
716
+ let relative_manifest_path = manifest_path
717
+ . strip_prefix ( cx. bcx . ws . root ( ) )
718
+ . unwrap_or ( & manifest_path)
719
+ . to_owned ( ) ;
707
720
let target = Target :: clone ( & unit. target ) ;
708
721
let mut output_options = OutputOptions :: new ( cx, unit) ;
709
722
let script_metadata = cx. find_build_script_metadata ( unit) ;
723
+ let failed_scrape_units = Arc :: clone ( & cx. failed_scrape_units ) ;
724
+ let hide_diagnostics_for_scrape_unit = unit. mode . is_doc_scrape ( )
725
+ && unit. target . doc_scrape_examples ( ) . is_unset ( )
726
+ && !matches ! ( cx. bcx. config. shell( ) . verbosity( ) , Verbosity :: Verbose ) ;
727
+ if hide_diagnostics_for_scrape_unit {
728
+ output_options. show_diagnostics = false ;
729
+ }
710
730
Ok ( Work :: new ( move |state| {
711
731
add_custom_flags (
712
732
& mut rustdoc,
713
733
& build_script_outputs. lock ( ) . unwrap ( ) ,
714
734
script_metadata,
715
735
) ?;
736
+
737
+ // Add the output of scraped examples to the rustdoc command.
738
+ // This action must happen after the unit's dependencies have finished,
739
+ // because some of those deps may be Docscrape units which have failed.
740
+ // So we dynamically determine which `--with-examples` flags to pass here.
741
+ if let Some ( scrape_outputs) = scrape_outputs {
742
+ let failed_scrape_units = failed_scrape_units. lock ( ) . unwrap ( ) ;
743
+ for ( metadata, output_path) in & scrape_outputs {
744
+ if !failed_scrape_units. contains ( metadata) {
745
+ rustdoc. arg ( "--with-examples" ) . arg ( output_path) ;
746
+ }
747
+ }
748
+ }
749
+
716
750
let crate_dir = doc_dir. join ( & crate_name) ;
717
751
if crate_dir. exists ( ) {
718
752
// Remove output from a previous build. This ensures that stale
@@ -722,7 +756,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
722
756
}
723
757
state. running ( & rustdoc) ;
724
758
725
- rustdoc
759
+ let result = rustdoc
726
760
. exec_with_streaming (
727
761
& mut |line| on_stdout_line ( state, line, package_id, & target) ,
728
762
& mut |line| {
@@ -737,7 +771,23 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
737
771
} ,
738
772
false ,
739
773
)
740
- . with_context ( || format ! ( "could not document `{}`" , name) ) ?;
774
+ . with_context ( || format ! ( "could not document `{}`" , name) ) ;
775
+
776
+ if let Err ( e) = result {
777
+ if hide_diagnostics_for_scrape_unit {
778
+ let diag = format ! (
779
+ "\
780
+ failed to scan {target_desc} in package `{name}` for example code usage
781
+ Try running with `--verbose` to see the error message.
782
+ If this example should not be scanned, consider adding `doc-scrape-examples = false` to the `[[example]]` definition in {}" ,
783
+ relative_manifest_path. display( )
784
+ ) ;
785
+ state. warning ( diag) ?;
786
+ }
787
+
788
+ return Err ( e) ;
789
+ }
790
+
741
791
Ok ( ( ) )
742
792
} ) )
743
793
}
0 commit comments