Auto merge of #129337 - EtomicBomb:rfc, r=notriddle · rust-lang/rust@f827364 (original) (raw)

`@@ -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,

`

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,

`

``

301

`+

/// Where to write crate-info

`

``

302

`+

pub(crate) parts_out_dir: Option,

`

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,

`

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, 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

`+

}

`