]>
Commit | Line | Data |
---|---|---|
48663c56 | 1 | use std::collections::BTreeMap; |
ba9703b0 | 2 | use std::convert::TryFrom; |
60c5eb7d | 3 | use std::ffi::OsStr; |
a1dfa0c6 XL |
4 | use std::fmt; |
5 | use std::path::PathBuf; | |
6 | ||
ba9703b0 XL |
7 | use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType}; |
8 | use rustc_session::config::{ | |
60c5eb7d XL |
9 | build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple, |
10 | nightly_options, | |
11 | }; | |
ba9703b0 XL |
12 | use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; |
13 | use rustc_session::getopts; | |
14 | use rustc_session::lint::Level; | |
15 | use rustc_session::search_paths::SearchPath; | |
dfeec247 | 16 | use rustc_span::edition::{Edition, DEFAULT_EDITION}; |
a1dfa0c6 | 17 | use rustc_target::spec::TargetTriple; |
a1dfa0c6 | 18 | |
9fa01778 XL |
19 | use crate::core::new_handler; |
20 | use crate::externalfiles::ExternalHtml; | |
21 | use crate::html; | |
60c5eb7d XL |
22 | use crate::html::markdown::IdMap; |
23 | use crate::html::static_files; | |
9fa01778 | 24 | use crate::opts; |
60c5eb7d | 25 | use crate::passes::{self, Condition, DefaultPassOption}; |
9fa01778 | 26 | use crate::theme; |
a1dfa0c6 | 27 | |
ba9703b0 XL |
28 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
29 | pub enum OutputFormat { | |
30 | Json, | |
31 | Html, | |
32 | } | |
33 | ||
34 | impl OutputFormat { | |
35 | pub fn is_json(&self) -> bool { | |
36 | match self { | |
37 | OutputFormat::Json => true, | |
38 | _ => false, | |
39 | } | |
40 | } | |
41 | } | |
42 | ||
43 | impl TryFrom<&str> for OutputFormat { | |
44 | type Error = String; | |
45 | ||
46 | fn try_from(value: &str) -> Result<Self, Self::Error> { | |
47 | match value { | |
48 | "json" => Ok(OutputFormat::Json), | |
49 | "html" => Ok(OutputFormat::Html), | |
50 | _ => Err(format!("unknown output format `{}`", value)), | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
a1dfa0c6 XL |
55 | /// Configuration options for rustdoc. |
56 | #[derive(Clone)] | |
57 | pub struct Options { | |
58 | // Basic options / Options passed directly to rustc | |
a1dfa0c6 XL |
59 | /// The crate root or Markdown file to load. |
60 | pub input: PathBuf, | |
61 | /// The name of the crate being documented. | |
62 | pub crate_name: Option<String>, | |
e1599b0c XL |
63 | /// Whether or not this is a proc-macro crate |
64 | pub proc_macro_crate: bool, | |
a1dfa0c6 XL |
65 | /// How to format errors and warnings. |
66 | pub error_format: ErrorOutputType, | |
67 | /// Library search paths to hand to the compiler. | |
0731742a | 68 | pub libs: Vec<SearchPath>, |
e1599b0c XL |
69 | /// Library search paths strings to hand to the compiler. |
70 | pub lib_strs: Vec<String>, | |
a1dfa0c6 XL |
71 | /// The list of external crates to link against. |
72 | pub externs: Externs, | |
e1599b0c XL |
73 | /// The list of external crates strings to link against. |
74 | pub extern_strs: Vec<String>, | |
a1dfa0c6 XL |
75 | /// List of `cfg` flags to hand to the compiler. Always includes `rustdoc`. |
76 | pub cfgs: Vec<String>, | |
77 | /// Codegen options to hand to the compiler. | |
78 | pub codegen_options: CodegenOptions, | |
e1599b0c XL |
79 | /// Codegen options strings to hand to the compiler. |
80 | pub codegen_options_strs: Vec<String>, | |
a1dfa0c6 XL |
81 | /// Debugging (`-Z`) options to pass to the compiler. |
82 | pub debugging_options: DebuggingOptions, | |
e74abb32 XL |
83 | /// Debugging (`-Z`) options strings to pass to the compiler. |
84 | pub debugging_options_strs: Vec<String>, | |
a1dfa0c6 | 85 | /// The target used to compile the crate against. |
e1599b0c | 86 | pub target: TargetTriple, |
a1dfa0c6 XL |
87 | /// Edition used when reading the crate. Defaults to "2015". Also used by default when |
88 | /// compiling doctests from the crate. | |
89 | pub edition: Edition, | |
90 | /// The path to the sysroot. Used during the compilation process. | |
91 | pub maybe_sysroot: Option<PathBuf>, | |
a1dfa0c6 XL |
92 | /// Lint information passed over the command-line. |
93 | pub lint_opts: Vec<(String, Level)>, | |
94 | /// Whether to ask rustc to describe the lints it knows. Practically speaking, this will not be | |
95 | /// used, since we abort if we have no input file, but it's included for completeness. | |
96 | pub describe_lints: bool, | |
97 | /// What level to cap lints at. | |
98 | pub lint_cap: Option<Level>, | |
99 | ||
100 | // Options specific to running doctests | |
a1dfa0c6 XL |
101 | /// Whether we should run doctests instead of generating docs. |
102 | pub should_test: bool, | |
103 | /// List of arguments to pass to the test harness, if running tests. | |
104 | pub test_args: Vec<String>, | |
9fa01778 XL |
105 | /// Optional path to persist the doctest executables to, defaults to a |
106 | /// temporary directory if not set. | |
107 | pub persist_doctests: Option<PathBuf>, | |
e1599b0c XL |
108 | /// Runtool to run doctests with |
109 | pub runtool: Option<String>, | |
110 | /// Arguments to pass to the runtool | |
111 | pub runtool_args: Vec<String>, | |
112 | /// Whether to allow ignoring doctests on a per-target basis | |
113 | /// For example, using ignore-foo to ignore running the doctest on any target that | |
114 | /// contains "foo" as a substring | |
115 | pub enable_per_target_ignores: bool, | |
116 | ||
117 | /// The path to a rustc-like binary to build tests with. If not set, we | |
118 | /// default to loading from $sysroot/bin/rustc. | |
119 | pub test_builder: Option<PathBuf>, | |
a1dfa0c6 XL |
120 | |
121 | // Options that affect the documentation process | |
a1dfa0c6 XL |
122 | /// The selected default set of passes to use. |
123 | /// | |
124 | /// Be aware: This option can come both from the CLI and from crate attributes! | |
125 | pub default_passes: DefaultPassOption, | |
126 | /// Any passes manually selected by the user. | |
127 | /// | |
128 | /// Be aware: This option can come both from the CLI and from crate attributes! | |
129 | pub manual_passes: Vec<String>, | |
130 | /// Whether to display warnings during doc generation or while gathering doctests. By default, | |
131 | /// all non-rustdoc-specific lints are allowed when generating docs. | |
132 | pub display_warnings: bool, | |
532ac7d7 XL |
133 | /// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items |
134 | /// with and without documentation. | |
135 | pub show_coverage: bool, | |
a1dfa0c6 XL |
136 | |
137 | // Options that alter generated documentation pages | |
a1dfa0c6 XL |
138 | /// Crate version to note on the sidebar of generated docs. |
139 | pub crate_version: Option<String>, | |
140 | /// Collected options specific to outputting final pages. | |
141 | pub render_options: RenderOptions, | |
ba9703b0 XL |
142 | /// Output format rendering (used only for "show-coverage" option for the moment) |
143 | pub output_format: Option<OutputFormat>, | |
a1dfa0c6 XL |
144 | } |
145 | ||
146 | impl fmt::Debug for Options { | |
9fa01778 | 147 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
a1dfa0c6 XL |
148 | struct FmtExterns<'a>(&'a Externs); |
149 | ||
150 | impl<'a> fmt::Debug for FmtExterns<'a> { | |
9fa01778 | 151 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
60c5eb7d | 152 | f.debug_map().entries(self.0.iter()).finish() |
a1dfa0c6 XL |
153 | } |
154 | } | |
155 | ||
156 | f.debug_struct("Options") | |
157 | .field("input", &self.input) | |
158 | .field("crate_name", &self.crate_name) | |
e1599b0c | 159 | .field("proc_macro_crate", &self.proc_macro_crate) |
a1dfa0c6 XL |
160 | .field("error_format", &self.error_format) |
161 | .field("libs", &self.libs) | |
162 | .field("externs", &FmtExterns(&self.externs)) | |
163 | .field("cfgs", &self.cfgs) | |
164 | .field("codegen_options", &"...") | |
165 | .field("debugging_options", &"...") | |
166 | .field("target", &self.target) | |
167 | .field("edition", &self.edition) | |
168 | .field("maybe_sysroot", &self.maybe_sysroot) | |
a1dfa0c6 XL |
169 | .field("lint_opts", &self.lint_opts) |
170 | .field("describe_lints", &self.describe_lints) | |
171 | .field("lint_cap", &self.lint_cap) | |
172 | .field("should_test", &self.should_test) | |
173 | .field("test_args", &self.test_args) | |
9fa01778 | 174 | .field("persist_doctests", &self.persist_doctests) |
a1dfa0c6 XL |
175 | .field("default_passes", &self.default_passes) |
176 | .field("manual_passes", &self.manual_passes) | |
177 | .field("display_warnings", &self.display_warnings) | |
532ac7d7 | 178 | .field("show_coverage", &self.show_coverage) |
a1dfa0c6 XL |
179 | .field("crate_version", &self.crate_version) |
180 | .field("render_options", &self.render_options) | |
e1599b0c XL |
181 | .field("runtool", &self.runtool) |
182 | .field("runtool_args", &self.runtool_args) | |
183 | .field("enable-per-target-ignores", &self.enable_per_target_ignores) | |
a1dfa0c6 XL |
184 | .finish() |
185 | } | |
186 | } | |
187 | ||
188 | /// Configuration options for the HTML page-creation process. | |
189 | #[derive(Clone, Debug)] | |
190 | pub struct RenderOptions { | |
191 | /// Output directory to generate docs into. Defaults to `doc`. | |
192 | pub output: PathBuf, | |
193 | /// External files to insert into generated pages. | |
194 | pub external_html: ExternalHtml, | |
195 | /// A pre-populated `IdMap` with the default headings and any headings added by Markdown files | |
196 | /// processed by `external_html`. | |
197 | pub id_map: IdMap, | |
198 | /// If present, playground URL to use in the "Run" button added to code samples. | |
199 | /// | |
200 | /// Be aware: This option can come both from the CLI and from crate attributes! | |
201 | pub playground_url: Option<String>, | |
202 | /// Whether to sort modules alphabetically on a module page instead of using declaration order. | |
203 | /// `true` by default. | |
9fa01778 XL |
204 | // |
205 | // FIXME(misdreavus): the flag name is `--sort-modules-by-appearance` but the meaning is | |
206 | // inverted once read. | |
a1dfa0c6 XL |
207 | pub sort_modules_alphabetically: bool, |
208 | /// List of themes to extend the docs with. Original argument name is included to assist in | |
209 | /// displaying errors if it fails a theme check. | |
210 | pub themes: Vec<PathBuf>, | |
211 | /// If present, CSS file that contains rules to add to the default CSS. | |
212 | pub extension_css: Option<PathBuf>, | |
213 | /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`. | |
214 | pub extern_html_root_urls: BTreeMap<String, String>, | |
215 | /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages. | |
216 | pub resource_suffix: String, | |
217 | /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by | |
218 | /// default. | |
9fa01778 XL |
219 | // |
220 | // FIXME(misdreavus): the flag name is `--disable-minification` but the meaning is inverted | |
221 | // once read. | |
a1dfa0c6 XL |
222 | pub enable_minification: bool, |
223 | /// Whether to create an index page in the root of the output directory. If this is true but | |
224 | /// `enable_index_page` is None, generate a static listing of crates instead. | |
225 | pub enable_index_page: bool, | |
226 | /// A file to use as the index page at the root of the output directory. Overrides | |
227 | /// `enable_index_page` to be true if set. | |
228 | pub index_page: Option<PathBuf>, | |
0731742a XL |
229 | /// An optional path to use as the location of static files. If not set, uses combinations of |
230 | /// `../` to reach the documentation root. | |
231 | pub static_root_path: Option<String>, | |
a1dfa0c6 XL |
232 | |
233 | // Options specific to reading standalone Markdown files | |
a1dfa0c6 XL |
234 | /// Whether to generate a table of contents on the output file when reading a standalone |
235 | /// Markdown file. | |
236 | pub markdown_no_toc: bool, | |
237 | /// Additional CSS files to link in pages generated from standalone Markdown files. | |
238 | pub markdown_css: Vec<String>, | |
239 | /// If present, playground URL to use in the "Run" button added to code samples generated from | |
240 | /// standalone Markdown files. If not present, `playground_url` is used. | |
241 | pub markdown_playground_url: Option<String>, | |
0731742a XL |
242 | /// If false, the `select` element to have search filtering by crates on rendered docs |
243 | /// won't be generated. | |
244 | pub generate_search_filter: bool, | |
f035d41b XL |
245 | /// Document items that have lower than `pub` visibility. |
246 | pub document_private: bool, | |
247 | /// Document items that have `doc(hidden)`. | |
248 | pub document_hidden: bool, | |
a1dfa0c6 XL |
249 | } |
250 | ||
251 | impl Options { | |
252 | /// Parses the given command-line for options. If an error message or other early-return has | |
253 | /// been printed, returns `Err` with the exit code. | |
532ac7d7 | 254 | pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> { |
a1dfa0c6 XL |
255 | // Check for unstable options. |
256 | nightly_options::check_nightly_options(&matches, &opts()); | |
257 | ||
258 | if matches.opt_present("h") || matches.opt_present("help") { | |
9fa01778 | 259 | crate::usage("rustdoc"); |
a1dfa0c6 XL |
260 | return Err(0); |
261 | } else if matches.opt_present("version") { | |
262 | rustc_driver::version("rustdoc", &matches); | |
263 | return Err(0); | |
264 | } | |
265 | ||
266 | if matches.opt_strs("passes") == ["list"] { | |
267 | println!("Available passes for running rustdoc:"); | |
268 | for pass in passes::PASSES { | |
532ac7d7 | 269 | println!("{:>20} - {}", pass.name, pass.description); |
a1dfa0c6 XL |
270 | } |
271 | println!("\nDefault passes for rustdoc:"); | |
60c5eb7d XL |
272 | for p in passes::DEFAULT_PASSES { |
273 | print!("{:>20}", p.pass.name); | |
274 | println_condition(p.condition); | |
a1dfa0c6 | 275 | } |
532ac7d7 XL |
276 | |
277 | if nightly_options::is_nightly_build() { | |
278 | println!("\nPasses run with `--show-coverage`:"); | |
60c5eb7d XL |
279 | for p in passes::COVERAGE_PASSES { |
280 | print!("{:>20}", p.pass.name); | |
281 | println_condition(p.condition); | |
532ac7d7 | 282 | } |
60c5eb7d XL |
283 | } |
284 | ||
285 | fn println_condition(condition: Condition) { | |
286 | use Condition::*; | |
287 | match condition { | |
288 | Always => println!(), | |
289 | WhenDocumentPrivate => println!(" (when --document-private-items)"), | |
290 | WhenNotDocumentPrivate => println!(" (when not --document-private-items)"), | |
291 | WhenNotDocumentHidden => println!(" (when not --document-hidden-items)"), | |
532ac7d7 XL |
292 | } |
293 | } | |
294 | ||
a1dfa0c6 XL |
295 | return Err(0); |
296 | } | |
297 | ||
ba9703b0 XL |
298 | let color = config::parse_color(&matches); |
299 | let (json_rendered, _artifacts) = config::parse_json(&matches); | |
300 | let error_format = config::parse_error_format(&matches, color, json_rendered); | |
a1dfa0c6 XL |
301 | |
302 | let codegen_options = build_codegen_options(matches, error_format); | |
303 | let debugging_options = build_debugging_options(matches, error_format); | |
304 | ||
dfeec247 | 305 | let diag = new_handler(error_format, None, &debugging_options); |
a1dfa0c6 XL |
306 | |
307 | // check for deprecated options | |
308 | check_deprecated_options(&matches, &diag); | |
309 | ||
60c5eb7d | 310 | let to_check = matches.opt_strs("check-theme"); |
a1dfa0c6 XL |
311 | if !to_check.is_empty() { |
312 | let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); | |
313 | let mut errors = 0; | |
314 | ||
60c5eb7d | 315 | println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)"); |
a1dfa0c6 XL |
316 | for theme_file in to_check.iter() { |
317 | print!(" - Checking \"{}\"...", theme_file); | |
318 | let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag); | |
319 | if !differences.is_empty() || !success { | |
320 | println!(" FAILED"); | |
321 | errors += 1; | |
322 | if !differences.is_empty() { | |
323 | println!("{}", differences.join("\n")); | |
324 | } | |
325 | } else { | |
326 | println!(" OK"); | |
327 | } | |
328 | } | |
329 | if errors != 0 { | |
330 | return Err(1); | |
331 | } | |
332 | return Err(0); | |
333 | } | |
334 | ||
335 | if matches.free.is_empty() { | |
336 | diag.struct_err("missing file operand").emit(); | |
337 | return Err(1); | |
338 | } | |
339 | if matches.free.len() > 1 { | |
340 | diag.struct_err("too many file operands").emit(); | |
341 | return Err(1); | |
342 | } | |
343 | let input = PathBuf::from(&matches.free[0]); | |
344 | ||
60c5eb7d XL |
345 | let libs = matches |
346 | .opt_strs("L") | |
347 | .iter() | |
0731742a XL |
348 | .map(|s| SearchPath::from_cli_opt(s, error_format)) |
349 | .collect(); | |
60c5eb7d | 350 | let externs = parse_externs(&matches, &debugging_options, error_format); |
a1dfa0c6 XL |
351 | let extern_html_root_urls = match parse_extern_html_roots(&matches) { |
352 | Ok(ex) => ex, | |
353 | Err(err) => { | |
354 | diag.struct_err(err).emit(); | |
355 | return Err(1); | |
356 | } | |
357 | }; | |
358 | ||
359 | let test_args = matches.opt_strs("test-args"); | |
60c5eb7d XL |
360 | let test_args: Vec<String> = |
361 | test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect(); | |
a1dfa0c6 XL |
362 | |
363 | let should_test = matches.opt_present("test"); | |
364 | ||
60c5eb7d XL |
365 | let output = |
366 | matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc")); | |
e74abb32 | 367 | let cfgs = matches.opt_strs("cfg"); |
a1dfa0c6 XL |
368 | |
369 | let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); | |
370 | ||
371 | if let Some(ref p) = extension_css { | |
372 | if !p.is_file() { | |
373 | diag.struct_err("option --extend-css argument must be a file").emit(); | |
374 | return Err(1); | |
375 | } | |
376 | } | |
377 | ||
378 | let mut themes = Vec::new(); | |
60c5eb7d | 379 | if matches.opt_present("theme") { |
a1dfa0c6 XL |
380 | let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); |
381 | ||
60c5eb7d XL |
382 | for (theme_file, theme_s) in |
383 | matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned())) | |
384 | { | |
a1dfa0c6 | 385 | if !theme_file.is_file() { |
60c5eb7d XL |
386 | diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)) |
387 | .help("arguments to --theme must be files") | |
388 | .emit(); | |
389 | return Err(1); | |
390 | } | |
391 | if theme_file.extension() != Some(OsStr::new("css")) { | |
392 | diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)).emit(); | |
a1dfa0c6 XL |
393 | return Err(1); |
394 | } | |
395 | let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag); | |
60c5eb7d XL |
396 | if !success { |
397 | diag.struct_err(&format!("error loading theme file: \"{}\"", theme_s)).emit(); | |
a1dfa0c6 | 398 | return Err(1); |
60c5eb7d XL |
399 | } else if !ret.is_empty() { |
400 | diag.struct_warn(&format!( | |
401 | "theme file \"{}\" is missing CSS rules from the \ | |
402 | default theme", | |
403 | theme_s | |
404 | )) | |
405 | .warn("the theme may appear incorrect when loaded") | |
406 | .help(&format!( | |
407 | "to see what rules are missing, call `rustdoc \ | |
408 | --check-theme \"{}\"`", | |
409 | theme_s | |
410 | )) | |
411 | .emit(); | |
a1dfa0c6 XL |
412 | } |
413 | themes.push(theme_file); | |
414 | } | |
415 | } | |
416 | ||
48663c56 XL |
417 | let edition = if let Some(e) = matches.opt_str("edition") { |
418 | match e.parse() { | |
419 | Ok(e) => e, | |
420 | Err(_) => { | |
421 | diag.struct_err("could not parse edition").emit(); | |
422 | return Err(1); | |
423 | } | |
424 | } | |
425 | } else { | |
426 | DEFAULT_EDITION | |
427 | }; | |
428 | ||
a1dfa0c6 XL |
429 | let mut id_map = html::markdown::IdMap::new(); |
430 | id_map.populate(html::render::initial_ids()); | |
431 | let external_html = match ExternalHtml::load( | |
60c5eb7d XL |
432 | &matches.opt_strs("html-in-header"), |
433 | &matches.opt_strs("html-before-content"), | |
434 | &matches.opt_strs("html-after-content"), | |
435 | &matches.opt_strs("markdown-before-content"), | |
436 | &matches.opt_strs("markdown-after-content"), | |
437 | &diag, | |
438 | &mut id_map, | |
439 | edition, | |
440 | &None, | |
441 | ) { | |
a1dfa0c6 XL |
442 | Some(eh) => eh, |
443 | None => return Err(3), | |
444 | }; | |
445 | ||
f9f354fc | 446 | match matches.opt_str("r").as_deref() { |
a1dfa0c6 XL |
447 | Some("rust") | None => {} |
448 | Some(s) => { | |
449 | diag.struct_err(&format!("unknown input format: {}", s)).emit(); | |
450 | return Err(1); | |
451 | } | |
452 | } | |
453 | ||
a1dfa0c6 XL |
454 | let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s)); |
455 | if let Some(ref index_page) = index_page { | |
456 | if !index_page.is_file() { | |
457 | diag.struct_err("option `--index-page` argument must be a file").emit(); | |
458 | return Err(1); | |
459 | } | |
460 | } | |
461 | ||
60c5eb7d XL |
462 | let target = |
463 | matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| { | |
464 | if target.ends_with(".json") { | |
465 | TargetTriple::TargetPath(PathBuf::from(target)) | |
466 | } else { | |
467 | TargetTriple::TargetTriple(target) | |
468 | } | |
469 | }); | |
a1dfa0c6 | 470 | |
532ac7d7 | 471 | let show_coverage = matches.opt_present("show-coverage"); |
532ac7d7 | 472 | |
a1dfa0c6 XL |
473 | let default_passes = if matches.opt_present("no-defaults") { |
474 | passes::DefaultPassOption::None | |
532ac7d7 XL |
475 | } else if show_coverage { |
476 | passes::DefaultPassOption::Coverage | |
a1dfa0c6 XL |
477 | } else { |
478 | passes::DefaultPassOption::Default | |
479 | }; | |
480 | let manual_passes = matches.opt_strs("passes"); | |
481 | ||
e1599b0c XL |
482 | let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { |
483 | Ok(types) => types, | |
60c5eb7d | 484 | Err(e) => { |
e1599b0c XL |
485 | diag.struct_err(&format!("unknown crate type: {}", e)).emit(); |
486 | return Err(1); | |
487 | } | |
488 | }; | |
489 | ||
ba9703b0 XL |
490 | let output_format = match matches.opt_str("output-format") { |
491 | Some(s) => match OutputFormat::try_from(s.as_str()) { | |
492 | Ok(o) => { | |
493 | if o.is_json() && !show_coverage { | |
494 | diag.struct_err("json output format isn't supported for doc generation") | |
495 | .emit(); | |
496 | return Err(1); | |
497 | } else if !o.is_json() && show_coverage { | |
498 | diag.struct_err( | |
499 | "html output format isn't supported for the --show-coverage option", | |
500 | ) | |
501 | .emit(); | |
502 | return Err(1); | |
503 | } | |
504 | Some(o) | |
505 | } | |
506 | Err(e) => { | |
507 | diag.struct_err(&e).emit(); | |
508 | return Err(1); | |
509 | } | |
510 | }, | |
511 | None => None, | |
512 | }; | |
a1dfa0c6 | 513 | let crate_name = matches.opt_str("crate-name"); |
e1599b0c | 514 | let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); |
a1dfa0c6 XL |
515 | let playground_url = matches.opt_str("playground-url"); |
516 | let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); | |
517 | let display_warnings = matches.opt_present("display-warnings"); | |
a1dfa0c6 XL |
518 | let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance"); |
519 | let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default(); | |
520 | let enable_minification = !matches.opt_present("disable-minification"); | |
521 | let markdown_no_toc = matches.opt_present("markdown-no-toc"); | |
522 | let markdown_css = matches.opt_strs("markdown-css"); | |
523 | let markdown_playground_url = matches.opt_str("markdown-playground-url"); | |
524 | let crate_version = matches.opt_str("crate-version"); | |
525 | let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some(); | |
0731742a XL |
526 | let static_root_path = matches.opt_str("static-root-path"); |
527 | let generate_search_filter = !matches.opt_present("disable-per-crate-search"); | |
9fa01778 | 528 | let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); |
e1599b0c XL |
529 | let test_builder = matches.opt_str("test-builder").map(PathBuf::from); |
530 | let codegen_options_strs = matches.opt_strs("C"); | |
e74abb32 | 531 | let debugging_options_strs = matches.opt_strs("Z"); |
e1599b0c XL |
532 | let lib_strs = matches.opt_strs("L"); |
533 | let extern_strs = matches.opt_strs("extern"); | |
534 | let runtool = matches.opt_str("runtool"); | |
535 | let runtool_args = matches.opt_strs("runtool-arg"); | |
536 | let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); | |
60c5eb7d XL |
537 | let document_private = matches.opt_present("document-private-items"); |
538 | let document_hidden = matches.opt_present("document-hidden-items"); | |
a1dfa0c6 XL |
539 | |
540 | let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); | |
541 | ||
542 | Ok(Options { | |
543 | input, | |
544 | crate_name, | |
e1599b0c | 545 | proc_macro_crate, |
a1dfa0c6 XL |
546 | error_format, |
547 | libs, | |
e1599b0c | 548 | lib_strs, |
a1dfa0c6 | 549 | externs, |
e1599b0c | 550 | extern_strs, |
a1dfa0c6 XL |
551 | cfgs, |
552 | codegen_options, | |
e1599b0c | 553 | codegen_options_strs, |
a1dfa0c6 | 554 | debugging_options, |
e74abb32 | 555 | debugging_options_strs, |
a1dfa0c6 XL |
556 | target, |
557 | edition, | |
558 | maybe_sysroot, | |
a1dfa0c6 XL |
559 | lint_opts, |
560 | describe_lints, | |
561 | lint_cap, | |
562 | should_test, | |
563 | test_args, | |
564 | default_passes, | |
565 | manual_passes, | |
566 | display_warnings, | |
532ac7d7 | 567 | show_coverage, |
a1dfa0c6 | 568 | crate_version, |
9fa01778 | 569 | persist_doctests, |
e1599b0c XL |
570 | runtool, |
571 | runtool_args, | |
572 | enable_per_target_ignores, | |
573 | test_builder, | |
a1dfa0c6 XL |
574 | render_options: RenderOptions { |
575 | output, | |
576 | external_html, | |
577 | id_map, | |
578 | playground_url, | |
579 | sort_modules_alphabetically, | |
580 | themes, | |
581 | extension_css, | |
582 | extern_html_root_urls, | |
583 | resource_suffix, | |
584 | enable_minification, | |
585 | enable_index_page, | |
586 | index_page, | |
0731742a | 587 | static_root_path, |
a1dfa0c6 XL |
588 | markdown_no_toc, |
589 | markdown_css, | |
590 | markdown_playground_url, | |
0731742a | 591 | generate_search_filter, |
f035d41b XL |
592 | document_private, |
593 | document_hidden, | |
60c5eb7d | 594 | }, |
ba9703b0 | 595 | output_format, |
a1dfa0c6 XL |
596 | }) |
597 | } | |
598 | ||
9fa01778 | 599 | /// Returns `true` if the file given as `self.input` is a Markdown file. |
a1dfa0c6 | 600 | pub fn markdown_input(&self) -> bool { |
60c5eb7d | 601 | self.input.extension().map_or(false, |e| e == "md" || e == "markdown") |
a1dfa0c6 XL |
602 | } |
603 | } | |
604 | ||
605 | /// Prints deprecation warnings for deprecated options | |
dfeec247 | 606 | fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Handler) { |
60c5eb7d | 607 | let deprecated_flags = ["input-format", "output-format", "no-defaults", "passes"]; |
a1dfa0c6 | 608 | |
48663c56 | 609 | for flag in deprecated_flags.iter() { |
a1dfa0c6 | 610 | if matches.opt_present(flag) { |
ba9703b0 XL |
611 | if *flag == "output-format" && matches.opt_present("show-coverage") { |
612 | continue; | |
613 | } | |
60c5eb7d XL |
614 | let mut err = |
615 | diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag)); | |
74b04a01 XL |
616 | err.warn( |
617 | "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \ | |
618 | for more information", | |
619 | ); | |
a1dfa0c6 XL |
620 | |
621 | if *flag == "no-defaults" { | |
622 | err.help("you may want to use --document-private-items"); | |
623 | } | |
624 | ||
625 | err.emit(); | |
626 | } | |
627 | } | |
628 | ||
60c5eb7d | 629 | let removed_flags = ["plugins", "plugin-path"]; |
a1dfa0c6 XL |
630 | |
631 | for &flag in removed_flags.iter() { | |
632 | if matches.opt_present(flag) { | |
633 | diag.struct_warn(&format!("the '{}' flag no longer functions", flag)) | |
634 | .warn("see CVE-2018-1000622") | |
635 | .emit(); | |
636 | } | |
637 | } | |
638 | } | |
639 | ||
640 | /// Extracts `--extern-html-root-url` arguments from `matches` and returns a map of crate names to | |
641 | /// the given URLs. If an `--extern-html-root-url` argument was ill-formed, returns an error | |
642 | /// describing the issue. | |
643 | fn parse_extern_html_roots( | |
644 | matches: &getopts::Matches, | |
645 | ) -> Result<BTreeMap<String, String>, &'static str> { | |
646 | let mut externs = BTreeMap::new(); | |
647 | for arg in &matches.opt_strs("extern-html-root-url") { | |
648 | let mut parts = arg.splitn(2, '='); | |
649 | let name = parts.next().ok_or("--extern-html-root-url must not be empty")?; | |
650 | let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?; | |
651 | externs.insert(name.to_string(), url.to_string()); | |
652 | } | |
653 | ||
654 | Ok(externs) | |
655 | } |