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