@@ -53,12 +53,18 @@ impl TryFrom<&str> for OutputFormat {
53
53
}
54
54
}
55
55
56
+ /// Either an input crate, markdown file, or nothing (--merge=finalize).
57
+ pub ( crate ) enum InputMode {
58
+ /// The `--merge=finalize` step does not need an input crate to rustdoc.
59
+ NoInputMergeFinalize ,
60
+ /// A crate or markdown file.
61
+ HasFile ( Input ) ,
62
+ }
63
+
56
64
/// Configuration options for rustdoc.
57
65
#[ derive( Clone ) ]
58
66
pub ( crate ) struct Options {
59
67
// Basic options / Options passed directly to rustc
60
- /// The crate root or Markdown file to load.
61
- pub ( crate ) input : Input ,
62
68
/// The name of the crate being documented.
63
69
pub ( crate ) crate_name : Option < String > ,
64
70
/// Whether or not this is a bin crate
@@ -179,7 +185,6 @@ impl fmt::Debug for Options {
179
185
}
180
186
181
187
f. debug_struct ( "Options" )
182
- . field ( "input" , & self . input . source_name ( ) )
183
188
. field ( "crate_name" , & self . crate_name )
184
189
. field ( "bin_crate" , & self . bin_crate )
185
190
. field ( "proc_macro_crate" , & self . proc_macro_crate )
@@ -289,6 +294,12 @@ pub(crate) struct RenderOptions {
289
294
/// This field is only used for the JSON output. If it's set to true, no file will be created
290
295
/// and content will be displayed in stdout directly.
291
296
pub ( crate ) output_to_stdout : bool ,
297
+ /// Whether we should read or write rendered cross-crate info in the doc root.
298
+ pub ( crate ) should_merge : ShouldMerge ,
299
+ /// Path to crate-info for external crates.
300
+ pub ( crate ) include_parts_dir : Vec < PathToParts > ,
301
+ /// Where to write crate-info
302
+ pub ( crate ) parts_out_dir : Option < PathToParts > ,
292
303
}
293
304
294
305
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
@@ -348,7 +359,7 @@ impl Options {
348
359
early_dcx : & mut EarlyDiagCtxt ,
349
360
matches : & getopts:: Matches ,
350
361
args : Vec < String > ,
351
- ) -> Option < ( Options , RenderOptions ) > {
362
+ ) -> Option < ( InputMode , Options , RenderOptions ) > {
352
363
// Check for unstable options.
353
364
nightly_options:: check_nightly_options ( early_dcx, matches, & opts ( ) ) ;
354
365
@@ -478,22 +489,34 @@ impl Options {
478
489
let ( lint_opts, describe_lints, lint_cap) = get_cmd_lint_options ( early_dcx, matches) ;
479
490
480
491
let input = if describe_lints {
481
- "" // dummy, this won't be used
492
+ InputMode :: HasFile ( make_input ( early_dcx , "" ) )
482
493
} else {
483
494
match matches. free . as_slice ( ) {
495
+ [ ] if matches. opt_str ( "merge" ) . as_deref ( ) == Some ( "finalize" ) => {
496
+ InputMode :: NoInputMergeFinalize
497
+ }
484
498
[ ] => dcx. fatal ( "missing file operand" ) ,
485
- [ input] => input,
499
+ [ input] => InputMode :: HasFile ( make_input ( early_dcx , input) ) ,
486
500
_ => dcx. fatal ( "too many file operands" ) ,
487
501
}
488
502
} ;
489
- let input = make_input ( early_dcx, input) ;
490
503
491
504
let externs = parse_externs ( early_dcx, matches, & unstable_opts) ;
492
505
let extern_html_root_urls = match parse_extern_html_roots ( matches) {
493
506
Ok ( ex) => ex,
494
507
Err ( err) => dcx. fatal ( err) ,
495
508
} ;
496
509
510
+ let parts_out_dir =
511
+ match matches. opt_str ( "parts-out-dir" ) . map ( |p| PathToParts :: from_flag ( p) ) . transpose ( ) {
512
+ Ok ( parts_out_dir) => parts_out_dir,
513
+ Err ( e) => dcx. fatal ( e) ,
514
+ } ;
515
+ let include_parts_dir = match parse_include_parts_dir ( matches) {
516
+ Ok ( include_parts_dir) => include_parts_dir,
517
+ Err ( e) => dcx. fatal ( e) ,
518
+ } ;
519
+
497
520
let default_settings: Vec < Vec < ( String , String ) > > = vec ! [
498
521
matches
499
522
. opt_str( "default-theme" )
@@ -735,6 +758,10 @@ impl Options {
735
758
let extern_html_root_takes_precedence =
736
759
matches. opt_present ( "extern-html-root-takes-precedence" ) ;
737
760
let html_no_source = matches. opt_present ( "html-no-source" ) ;
761
+ let should_merge = match parse_merge ( matches) {
762
+ Ok ( result) => result,
763
+ Err ( e) => dcx. fatal ( format ! ( "--merge option error: {e}" ) ) ,
764
+ } ;
738
765
739
766
if generate_link_to_definition && ( show_coverage || output_format != OutputFormat :: Html ) {
740
767
dcx. struct_warn (
@@ -751,7 +778,6 @@ impl Options {
751
778
let unstable_features =
752
779
rustc_feature:: UnstableFeatures :: from_environment ( crate_name. as_deref ( ) ) ;
753
780
let options = Options {
754
- input,
755
781
bin_crate,
756
782
proc_macro_crate,
757
783
error_format,
@@ -823,16 +849,17 @@ impl Options {
823
849
no_emit_shared : false ,
824
850
html_no_source,
825
851
output_to_stdout,
852
+ should_merge,
853
+ include_parts_dir,
854
+ parts_out_dir,
826
855
} ;
827
- Some ( ( options, render_options) )
856
+ Some ( ( input , options, render_options) )
828
857
}
858
+ }
829
859
830
- /// Returns `true` if the file given as `self.input` is a Markdown file.
831
- pub ( crate ) fn markdown_input ( & self ) -> Option < & Path > {
832
- self . input
833
- . opt_path ( )
834
- . filter ( |p| matches ! ( p. extension( ) , Some ( e) if e == "md" || e == "markdown" ) )
835
- }
860
+ /// Returns `true` if the file given as `self.input` is a Markdown file.
861
+ pub ( crate ) fn markdown_input ( input : & Input ) -> Option < & Path > {
862
+ input. opt_path ( ) . filter ( |p| matches ! ( p. extension( ) , Some ( e) if e == "md" || e == "markdown" ) )
836
863
}
837
864
838
865
fn parse_remap_path_prefix (
@@ -900,3 +927,71 @@ fn parse_extern_html_roots(
900
927
}
901
928
Ok ( externs)
902
929
}
930
+
931
+ /// Path directly to crate-info file.
932
+ ///
933
+ /// For example, `/home/user/project/target/doc.parts/<crate>/crate-info`.
934
+ #[ derive( Clone , Debug ) ]
935
+ pub ( crate ) struct PathToParts ( pub ( crate ) PathBuf ) ;
936
+
937
+ impl PathToParts {
938
+ fn from_flag ( path : String ) -> Result < PathToParts , String > {
939
+ let mut path = PathBuf :: from ( path) ;
940
+ // check here is for diagnostics
941
+ if path. exists ( ) && !path. is_dir ( ) {
942
+ Err ( format ! (
943
+ "--parts-out-dir and --include-parts-dir expect directories, found: {}" ,
944
+ path. display( ) ,
945
+ ) )
946
+ } else {
947
+ // if it doesn't exist, we'll create it. worry about that in write_shared
948
+ path. push ( "crate-info" ) ;
949
+ Ok ( PathToParts ( path) )
950
+ }
951
+ }
952
+ }
953
+
954
+ /// Reports error if --include-parts-dir / crate-info is not a file
955
+ fn parse_include_parts_dir ( m : & getopts:: Matches ) -> Result < Vec < PathToParts > , String > {
956
+ let mut ret = Vec :: new ( ) ;
957
+ for p in m. opt_strs ( "include-parts-dir" ) {
958
+ let p = PathToParts :: from_flag ( p) ?;
959
+ // this is just for diagnostic
960
+ if !p. 0 . is_file ( ) {
961
+ return Err ( format ! ( "--include-parts-dir expected {} to be a file" , p. 0 . display( ) ) ) ;
962
+ }
963
+ ret. push ( p) ;
964
+ }
965
+ Ok ( ret)
966
+ }
967
+
968
+ /// Controls merging of cross-crate information
969
+ #[ derive( Debug , Clone ) ]
970
+ pub ( crate ) struct ShouldMerge {
971
+ /// Should we append to existing cci in the doc root
972
+ pub ( crate ) read_rendered_cci : bool ,
973
+ /// Should we write cci to the doc root
974
+ pub ( crate ) write_rendered_cci : bool ,
975
+ }
976
+
977
+ /// Extracts read_rendered_cci and write_rendered_cci from command line arguments, or
978
+ /// reports an error if an invalid option was provided
979
+ fn parse_merge ( m : & getopts:: Matches ) -> Result < ShouldMerge , & ' static str > {
980
+ match m. opt_str ( "merge" ) . as_deref ( ) {
981
+ // default = read-write
982
+ None => Ok ( ShouldMerge { read_rendered_cci : true , write_rendered_cci : true } ) ,
983
+ Some ( "none" ) if m. opt_present ( "include-parts-dir" ) => {
984
+ Err ( "--include-parts-dir not allowed if --merge=none" )
985
+ }
986
+ Some ( "none" ) => Ok ( ShouldMerge { read_rendered_cci : false , write_rendered_cci : false } ) ,
987
+ Some ( "shared" ) if m. opt_present ( "parts-out-dir" ) || m. opt_present ( "include-parts-dir" ) => {
988
+ Err ( "--parts-out-dir and --include-parts-dir not allowed if --merge=shared" )
989
+ }
990
+ Some ( "shared" ) => Ok ( ShouldMerge { read_rendered_cci : true , write_rendered_cci : true } ) ,
991
+ Some ( "finalize" ) if m. opt_present ( "parts-out-dir" ) => {
992
+ Err ( "--parts-out-dir not allowed if --merge=finalize" )
993
+ }
994
+ Some ( "finalize" ) => Ok ( ShouldMerge { read_rendered_cci : false , write_rendered_cci : true } ) ,
995
+ Some ( _) => Err ( "argument to --merge must be `none`, `shared`, or `finalize`" ) ,
996
+ }
997
+ }
0 commit comments