--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::fmt;
+use std::path::PathBuf;
+
+use errors;
+use errors::emitter::ColorConfig;
+use getopts;
+use rustc::lint::Level;
+use rustc::session::early_error;
+use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
+use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
+ get_cmd_lint_options};
+use rustc::session::search_paths::SearchPaths;
+use rustc_driver;
+use rustc_target::spec::TargetTriple;
+use syntax::edition::Edition;
+
+use core::new_handler;
+use externalfiles::ExternalHtml;
+use html;
+use html::markdown::IdMap;
+use opts;
+use passes::{self, DefaultPassOption};
+use theme;
+
+/// Configuration options for rustdoc.
+#[derive(Clone)]
+pub struct Options {
+ // Basic options / Options passed directly to rustc
+
+ /// The crate root or Markdown file to load.
+ pub input: PathBuf,
+ /// The name of the crate being documented.
+ pub crate_name: Option<String>,
+ /// How to format errors and warnings.
+ pub error_format: ErrorOutputType,
+ /// Library search paths to hand to the compiler.
+ pub libs: SearchPaths,
+ /// The list of external crates to link against.
+ pub externs: Externs,
+ /// List of `cfg` flags to hand to the compiler. Always includes `rustdoc`.
+ pub cfgs: Vec<String>,
+ /// Codegen options to hand to the compiler.
+ pub codegen_options: CodegenOptions,
+ /// Debugging (`-Z`) options to pass to the compiler.
+ pub debugging_options: DebuggingOptions,
+ /// The target used to compile the crate against.
+ pub target: Option<TargetTriple>,
+ /// Edition used when reading the crate. Defaults to "2015". Also used by default when
+ /// compiling doctests from the crate.
+ pub edition: Edition,
+ /// The path to the sysroot. Used during the compilation process.
+ pub maybe_sysroot: Option<PathBuf>,
+ /// Linker to use when building doctests.
+ pub linker: Option<PathBuf>,
+ /// Lint information passed over the command-line.
+ pub lint_opts: Vec<(String, Level)>,
+ /// Whether to ask rustc to describe the lints it knows. Practically speaking, this will not be
+ /// used, since we abort if we have no input file, but it's included for completeness.
+ pub describe_lints: bool,
+ /// What level to cap lints at.
+ pub lint_cap: Option<Level>,
+
+ // Options specific to running doctests
+
+ /// Whether we should run doctests instead of generating docs.
+ pub should_test: bool,
+ /// List of arguments to pass to the test harness, if running tests.
+ pub test_args: Vec<String>,
+
+ // Options that affect the documentation process
+
+ /// The selected default set of passes to use.
+ ///
+ /// Be aware: This option can come both from the CLI and from crate attributes!
+ pub default_passes: DefaultPassOption,
+ /// Any passes manually selected by the user.
+ ///
+ /// Be aware: This option can come both from the CLI and from crate attributes!
+ pub manual_passes: Vec<String>,
+ /// Whether to display warnings during doc generation or while gathering doctests. By default,
+ /// all non-rustdoc-specific lints are allowed when generating docs.
+ pub display_warnings: bool,
+
+ // Options that alter generated documentation pages
+
+ /// Crate version to note on the sidebar of generated docs.
+ pub crate_version: Option<String>,
+ /// Collected options specific to outputting final pages.
+ pub render_options: RenderOptions,
+}
+
+impl fmt::Debug for Options {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ struct FmtExterns<'a>(&'a Externs);
+
+ impl<'a> fmt::Debug for FmtExterns<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_map()
+ .entries(self.0.iter())
+ .finish()
+ }
+ }
+
+ f.debug_struct("Options")
+ .field("input", &self.input)
+ .field("crate_name", &self.crate_name)
+ .field("error_format", &self.error_format)
+ .field("libs", &self.libs)
+ .field("externs", &FmtExterns(&self.externs))
+ .field("cfgs", &self.cfgs)
+ .field("codegen_options", &"...")
+ .field("debugging_options", &"...")
+ .field("target", &self.target)
+ .field("edition", &self.edition)
+ .field("maybe_sysroot", &self.maybe_sysroot)
+ .field("linker", &self.linker)
+ .field("lint_opts", &self.lint_opts)
+ .field("describe_lints", &self.describe_lints)
+ .field("lint_cap", &self.lint_cap)
+ .field("should_test", &self.should_test)
+ .field("test_args", &self.test_args)
+ .field("default_passes", &self.default_passes)
+ .field("manual_passes", &self.manual_passes)
+ .field("display_warnings", &self.display_warnings)
+ .field("crate_version", &self.crate_version)
+ .field("render_options", &self.render_options)
+ .finish()
+ }
+}
+
+/// Configuration options for the HTML page-creation process.
+#[derive(Clone, Debug)]
+pub struct RenderOptions {
+ /// Output directory to generate docs into. Defaults to `doc`.
+ pub output: PathBuf,
+ /// External files to insert into generated pages.
+ pub external_html: ExternalHtml,
+ /// A pre-populated `IdMap` with the default headings and any headings added by Markdown files
+ /// processed by `external_html`.
+ pub id_map: IdMap,
+ /// If present, playground URL to use in the "Run" button added to code samples.
+ ///
+ /// Be aware: This option can come both from the CLI and from crate attributes!
+ pub playground_url: Option<String>,
+ /// Whether to sort modules alphabetically on a module page instead of using declaration order.
+ /// `true` by default.
+ ///
+ /// FIXME(misdreavus): the flag name is `--sort-modules-by-appearance` but the meaning is
+ /// inverted once read
+ pub sort_modules_alphabetically: bool,
+ /// List of themes to extend the docs with. Original argument name is included to assist in
+ /// displaying errors if it fails a theme check.
+ pub themes: Vec<PathBuf>,
+ /// If present, CSS file that contains rules to add to the default CSS.
+ pub extension_css: Option<PathBuf>,
+ /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`.
+ pub extern_html_root_urls: BTreeMap<String, String>,
+ /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
+ pub resource_suffix: String,
+ /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
+ /// default.
+ ///
+ /// FIXME(misdreavus): the flag name is `--disable-minification` but the meaning is inverted
+ /// once read
+ pub enable_minification: bool,
+ /// Whether to create an index page in the root of the output directory. If this is true but
+ /// `enable_index_page` is None, generate a static listing of crates instead.
+ pub enable_index_page: bool,
+ /// A file to use as the index page at the root of the output directory. Overrides
+ /// `enable_index_page` to be true if set.
+ pub index_page: Option<PathBuf>,
+
+ // Options specific to reading standalone Markdown files
+
+ /// Whether to generate a table of contents on the output file when reading a standalone
+ /// Markdown file.
+ pub markdown_no_toc: bool,
+ /// Additional CSS files to link in pages generated from standlone Markdown files.
+ pub markdown_css: Vec<String>,
+ /// If present, playground URL to use in the "Run" button added to code samples generated from
+ /// standalone Markdown files. If not present, `playground_url` is used.
+ pub markdown_playground_url: Option<String>,
+}
+
+impl Options {
+ /// Parses the given command-line for options. If an error message or other early-return has
+ /// been printed, returns `Err` with the exit code.
+ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, isize> {
+ // Check for unstable options.
+ nightly_options::check_nightly_options(&matches, &opts());
+
+ if matches.opt_present("h") || matches.opt_present("help") {
+ ::usage("rustdoc");
+ return Err(0);
+ } else if matches.opt_present("version") {
+ rustc_driver::version("rustdoc", &matches);
+ return Err(0);
+ }
+
+ if matches.opt_strs("passes") == ["list"] {
+ println!("Available passes for running rustdoc:");
+ for pass in passes::PASSES {
+ println!("{:>20} - {}", pass.name(), pass.description());
+ }
+ println!("\nDefault passes for rustdoc:");
+ for &name in passes::DEFAULT_PASSES {
+ println!("{:>20}", name);
+ }
+ println!("\nPasses run with `--document-private-items`:");
+ for &name in passes::DEFAULT_PRIVATE_PASSES {
+ println!("{:>20}", name);
+ }
+ return Err(0);
+ }
+
+ let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
+ Some("auto") => ColorConfig::Auto,
+ Some("always") => ColorConfig::Always,
+ Some("never") => ColorConfig::Never,
+ None => ColorConfig::Auto,
+ Some(arg) => {
+ early_error(ErrorOutputType::default(),
+ &format!("argument for --color must be `auto`, `always` or `never` \
+ (instead was `{}`)", arg));
+ }
+ };
+ let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+ Some("human") => ErrorOutputType::HumanReadable(color),
+ Some("json") => ErrorOutputType::Json(false),
+ Some("pretty-json") => ErrorOutputType::Json(true),
+ Some("short") => ErrorOutputType::Short(color),
+ None => ErrorOutputType::HumanReadable(color),
+ Some(arg) => {
+ early_error(ErrorOutputType::default(),
+ &format!("argument for --error-format must be `human`, `json` or \
+ `short` (instead was `{}`)", arg));
+ }
+ };
+
+ let codegen_options = build_codegen_options(matches, error_format);
+ let debugging_options = build_debugging_options(matches, error_format);
+
+ let diag = new_handler(error_format,
+ None,
+ debugging_options.treat_err_as_bug,
+ debugging_options.ui_testing);
+
+ // check for deprecated options
+ check_deprecated_options(&matches, &diag);
+
+ let to_check = matches.opt_strs("theme-checker");
+ if !to_check.is_empty() {
+ let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
+ let mut errors = 0;
+
+ println!("rustdoc: [theme-checker] Starting tests!");
+ for theme_file in to_check.iter() {
+ print!(" - Checking \"{}\"...", theme_file);
+ let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
+ if !differences.is_empty() || !success {
+ println!(" FAILED");
+ errors += 1;
+ if !differences.is_empty() {
+ println!("{}", differences.join("\n"));
+ }
+ } else {
+ println!(" OK");
+ }
+ }
+ if errors != 0 {
+ return Err(1);
+ }
+ return Err(0);
+ }
+
+ if matches.free.is_empty() {
+ diag.struct_err("missing file operand").emit();
+ return Err(1);
+ }
+ if matches.free.len() > 1 {
+ diag.struct_err("too many file operands").emit();
+ return Err(1);
+ }
+ let input = PathBuf::from(&matches.free[0]);
+
+ let mut libs = SearchPaths::new();
+ for s in &matches.opt_strs("L") {
+ libs.add_path(s, error_format);
+ }
+ let externs = match parse_externs(&matches) {
+ Ok(ex) => ex,
+ Err(err) => {
+ diag.struct_err(&err).emit();
+ return Err(1);
+ }
+ };
+ let extern_html_root_urls = match parse_extern_html_roots(&matches) {
+ Ok(ex) => ex,
+ Err(err) => {
+ diag.struct_err(err).emit();
+ return Err(1);
+ }
+ };
+
+ let test_args = matches.opt_strs("test-args");
+ let test_args: Vec<String> = test_args.iter()
+ .flat_map(|s| s.split_whitespace())
+ .map(|s| s.to_string())
+ .collect();
+
+ let should_test = matches.opt_present("test");
+
+ let output = matches.opt_str("o")
+ .map(|s| PathBuf::from(&s))
+ .unwrap_or_else(|| PathBuf::from("doc"));
+ let mut cfgs = matches.opt_strs("cfg");
+ cfgs.push("rustdoc".to_string());
+
+ let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));
+
+ if let Some(ref p) = extension_css {
+ if !p.is_file() {
+ diag.struct_err("option --extend-css argument must be a file").emit();
+ return Err(1);
+ }
+ }
+
+ let mut themes = Vec::new();
+ if matches.opt_present("themes") {
+ let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
+
+ for (theme_file, theme_s) in matches.opt_strs("themes")
+ .iter()
+ .map(|s| (PathBuf::from(&s), s.to_owned())) {
+ if !theme_file.is_file() {
+ diag.struct_err("option --themes arguments must all be files").emit();
+ return Err(1);
+ }
+ let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
+ if !success || !ret.is_empty() {
+ diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
+ .help("check what's wrong with the --theme-checker option")
+ .emit();
+ return Err(1);
+ }
+ themes.push(theme_file);
+ }
+ }
+
+ let mut id_map = html::markdown::IdMap::new();
+ id_map.populate(html::render::initial_ids());
+ let external_html = match ExternalHtml::load(
+ &matches.opt_strs("html-in-header"),
+ &matches.opt_strs("html-before-content"),
+ &matches.opt_strs("html-after-content"),
+ &matches.opt_strs("markdown-before-content"),
+ &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
+ Some(eh) => eh,
+ None => return Err(3),
+ };
+
+ let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
+ let edition = match edition.parse() {
+ Ok(e) => e,
+ Err(_) => {
+ diag.struct_err("could not parse edition").emit();
+ return Err(1);
+ }
+ };
+
+ match matches.opt_str("r").as_ref().map(|s| &**s) {
+ Some("rust") | None => {}
+ Some(s) => {
+ diag.struct_err(&format!("unknown input format: {}", s)).emit();
+ return Err(1);
+ }
+ }
+
+ match matches.opt_str("w").as_ref().map(|s| &**s) {
+ Some("html") | None => {}
+ Some(s) => {
+ diag.struct_err(&format!("unknown output format: {}", s)).emit();
+ return Err(1);
+ }
+ }
+
+ let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
+ if let Some(ref index_page) = index_page {
+ if !index_page.is_file() {
+ diag.struct_err("option `--index-page` argument must be a file").emit();
+ return Err(1);
+ }
+ }
+
+ let target = matches.opt_str("target").map(|target| {
+ if target.ends_with(".json") {
+ TargetTriple::TargetPath(PathBuf::from(target))
+ } else {
+ TargetTriple::TargetTriple(target)
+ }
+ });
+
+ let default_passes = if matches.opt_present("no-defaults") {
+ passes::DefaultPassOption::None
+ } else if matches.opt_present("document-private-items") {
+ passes::DefaultPassOption::Private
+ } else {
+ passes::DefaultPassOption::Default
+ };
+ let manual_passes = matches.opt_strs("passes");
+
+ let crate_name = matches.opt_str("crate-name");
+ let playground_url = matches.opt_str("playground-url");
+ let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
+ let display_warnings = matches.opt_present("display-warnings");
+ let linker = matches.opt_str("linker").map(PathBuf::from);
+ let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
+ let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
+ let enable_minification = !matches.opt_present("disable-minification");
+ let markdown_no_toc = matches.opt_present("markdown-no-toc");
+ let markdown_css = matches.opt_strs("markdown-css");
+ let markdown_playground_url = matches.opt_str("markdown-playground-url");
+ let crate_version = matches.opt_str("crate-version");
+ let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
+
+ let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+
+ Ok(Options {
+ input,
+ crate_name,
+ error_format,
+ libs,
+ externs,
+ cfgs,
+ codegen_options,
+ debugging_options,
+ target,
+ edition,
+ maybe_sysroot,
+ linker,
+ lint_opts,
+ describe_lints,
+ lint_cap,
+ should_test,
+ test_args,
+ default_passes,
+ manual_passes,
+ display_warnings,
+ crate_version,
+ render_options: RenderOptions {
+ output,
+ external_html,
+ id_map,
+ playground_url,
+ sort_modules_alphabetically,
+ themes,
+ extension_css,
+ extern_html_root_urls,
+ resource_suffix,
+ enable_minification,
+ enable_index_page,
+ index_page,
+ markdown_no_toc,
+ markdown_css,
+ markdown_playground_url,
+ }
+ })
+ }
+
+ /// Returns whether the file given as `self.input` is a Markdown file.
+ pub fn markdown_input(&self) -> bool {
+ self.input.extension()
+ .map_or(false, |e| e == "md" || e == "markdown")
+ }
+}
+
+/// Prints deprecation warnings for deprecated options
+fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
+ let deprecated_flags = [
+ "input-format",
+ "output-format",
+ "no-defaults",
+ "passes",
+ ];
+
+ for flag in deprecated_flags.into_iter() {
+ if matches.opt_present(flag) {
+ let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
+ flag));
+ err.warn("please see https://github.com/rust-lang/rust/issues/44136");
+
+ if *flag == "no-defaults" {
+ err.help("you may want to use --document-private-items");
+ }
+
+ err.emit();
+ }
+ }
+
+ let removed_flags = [
+ "plugins",
+ "plugin-path",
+ ];
+
+ for &flag in removed_flags.iter() {
+ if matches.opt_present(flag) {
+ diag.struct_warn(&format!("the '{}' flag no longer functions", flag))
+ .warn("see CVE-2018-1000622")
+ .emit();
+ }
+ }
+}
+
+/// Extracts `--extern-html-root-url` arguments from `matches` and returns a map of crate names to
+/// the given URLs. If an `--extern-html-root-url` argument was ill-formed, returns an error
+/// describing the issue.
+fn parse_extern_html_roots(
+ matches: &getopts::Matches,
+) -> Result<BTreeMap<String, String>, &'static str> {
+ let mut externs = BTreeMap::new();
+ for arg in &matches.opt_strs("extern-html-root-url") {
+ let mut parts = arg.splitn(2, '=');
+ let name = parts.next().ok_or("--extern-html-root-url must not be empty")?;
+ let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?;
+ externs.insert(name.to_string(), url.to_string());
+ }
+
+ Ok(externs)
+}
+
+/// Extracts `--extern CRATE=PATH` arguments from `matches` and
+/// returns a map mapping crate names to their paths or else an
+/// error message.
+// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
+fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
+ let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
+ for arg in &matches.opt_strs("extern") {
+ let mut parts = arg.splitn(2, '=');
+ let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
+ let location = parts.next().map(|s| s.to_string());
+ if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
+ return Err("the `-Z unstable-options` flag must also be passed to \
+ enable `--extern crate_name` without `=path`".to_string());
+ }
+ let name = name.to_string();
+ externs.entry(name).or_default().insert(location);
+ }
+ Ok(Externs::new(externs))
+}
use syntax::ast::{self, Ident, NodeId};
use syntax::source_map;
-use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
use syntax::json::JsonEmitter;
use syntax::ptr::P;
use rustc_data_structures::sync::{self, Lrc};
use std::rc::Rc;
use std::sync::Arc;
-use std::path::PathBuf;
use visit_ast::RustdocVisitor;
+use config::{Options as RustdocOptions, RenderOptions};
use clean;
use clean::{get_path_for_type, Clean, MAX_DEF_ID, AttributesExt};
use html::render::RenderInfo;
)
}
-pub fn run_core(search_paths: SearchPaths,
- cfgs: Vec<String>,
- externs: config::Externs,
- input: Input,
- triple: Option<TargetTriple>,
- maybe_sysroot: Option<PathBuf>,
- allow_warnings: bool,
- crate_name: Option<String>,
- force_unstable_if_unmarked: bool,
- edition: Edition,
- cg: CodegenOptions,
- error_format: ErrorOutputType,
- cmd_lints: Vec<(String, lint::Level)>,
- lint_cap: Option<lint::Level>,
- describe_lints: bool,
- mut manual_passes: Vec<String>,
- mut default_passes: passes::DefaultPassOption,
- treat_err_as_bug: bool,
- ui_testing: bool,
-) -> (clean::Crate, RenderInfo, Vec<String>) {
+pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions, Vec<String>) {
// Parse, resolve, and typecheck the given crate.
- let cpath = match input {
- Input::File(ref p) => Some(p.clone()),
- _ => None
- };
+ let RustdocOptions {
+ input,
+ crate_name,
+ error_format,
+ libs,
+ externs,
+ cfgs,
+ codegen_options,
+ debugging_options,
+ target,
+ edition,
+ maybe_sysroot,
+ lint_opts,
+ describe_lints,
+ lint_cap,
+ mut default_passes,
+ mut manual_passes,
+ display_warnings,
+ render_options,
+ ..
+ } = options;
+
+ let cpath = Some(input.clone());
+ let input = Input::File(input);
let intra_link_resolution_failure_name = lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE.name;
let warnings_lint_name = lint::builtin::WARNINGS.name;
missing_docs.to_owned(),
missing_doc_example.to_owned()];
- whitelisted_lints.extend(cmd_lints.iter().map(|(lint, _)| lint).cloned());
+ whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
let lints = lint::builtin::HardwiredLints.get_lints()
.into_iter()
Some((lint.name_lower(), lint::Allow))
}
})
- .chain(cmd_lints.into_iter())
+ .chain(lint_opts.into_iter())
.collect::<Vec<_>>();
let host_triple = TargetTriple::from_triple(config::host_triple());
// plays with error output here!
let sessopts = config::Options {
maybe_sysroot,
- search_paths,
+ search_paths: libs,
crate_types: vec![config::CrateType::Rlib],
- lint_opts: if !allow_warnings {
+ lint_opts: if !display_warnings {
lints
} else {
vec![]
},
lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)),
- cg,
+ cg: codegen_options,
externs,
- target_triple: triple.unwrap_or(host_triple),
+ target_triple: target.unwrap_or(host_triple),
// Ensure that rustdoc works even if rustc is feature-staged
unstable_features: UnstableFeatures::Allow,
actually_rustdoc: true,
- debugging_opts: config::DebuggingOptions {
- force_unstable_if_unmarked,
- treat_err_as_bug,
- ui_testing,
- ..config::basic_debugging_options()
- },
+ debugging_opts: debugging_options.clone(),
error_format,
edition,
describe_lints,
let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()));
let diagnostic_handler = new_handler(error_format,
Some(source_map.clone()),
- treat_err_as_bug,
- ui_testing);
+ debugging_options.treat_err_as_bug,
+ debugging_options.ui_testing);
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, source_map,
ctxt.sess().abort_if_errors();
- (krate, ctxt.renderinfo.into_inner(), passes)
+ (krate, ctxt.renderinfo.into_inner(), render_options, passes)
}), &sess)
})
}
use html::markdown::{IdMap, ErrorCodes, Markdown};
use std::cell::RefCell;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct ExternalHtml {
/// Content that will be included inline in the <head> section of a
/// rendered Markdown file or generated documentation
links
}
-#[derive(Default)]
+#[derive(Clone, Default, Debug)]
pub struct IdMap {
map: FxHashMap<String, usize>,
}
use std::sync::Arc;
use std::rc::Rc;
-use externalfiles::ExternalHtml;
-
use errors;
-use getopts;
-
use serialize::json::{ToJson, Json, as_json};
use syntax::ast;
use syntax::ext::base::MacroKind;
use rustc_data_structures::flock;
use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
+use config::RenderOptions;
use doctree;
use fold::DocFolder;
use html::escape::Escape;
/// The map used to ensure all generated 'id=' attributes are unique.
id_map: Rc<RefCell<IdMap>>,
pub shared: Arc<SharedContext>,
- pub enable_index_page: bool,
- pub index_page: Option<PathBuf>,
}
struct SharedContext {
/// Generates the documentation for `crate` into the directory `dst`
pub fn run(mut krate: clean::Crate,
- extern_urls: BTreeMap<String, String>,
- external_html: &ExternalHtml,
- playground_url: Option<String>,
- dst: PathBuf,
- resource_suffix: String,
+ options: RenderOptions,
passes: FxHashSet<String>,
- css_file_extension: Option<PathBuf>,
renderinfo: RenderInfo,
- sort_modules_alphabetically: bool,
- themes: Vec<PathBuf>,
- enable_minification: bool,
- id_map: IdMap,
- enable_index_page: bool,
- index_page: Option<PathBuf>,
- matches: &getopts::Matches,
- diag: &errors::Handler,
-) -> Result<(), Error> {
+ diag: &errors::Handler) -> Result<(), Error> {
+ // need to save a copy of the options for rendering the index page
+ let md_opts = options.clone();
+ let RenderOptions {
+ output,
+ external_html,
+ id_map,
+ playground_url,
+ sort_modules_alphabetically,
+ themes,
+ extension_css,
+ extern_html_root_urls,
+ resource_suffix,
+ ..
+ } = options;
+
let src_root = match krate.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
layout: layout::Layout {
logo: String::new(),
favicon: String::new(),
- external_html: external_html.clone(),
+ external_html,
krate: krate.name.clone(),
},
- css_file_extension,
+ css_file_extension: extension_css,
created_dirs: Default::default(),
sort_modules_alphabetically,
themes,
}
}
}
+ let dst = output;
try_err!(fs::create_dir_all(&dst), &dst);
krate = render_sources(&dst, &mut scx, krate)?;
let cx = Context {
codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
id_map: Rc::new(RefCell::new(id_map)),
shared: Arc::new(scx),
- enable_index_page,
- index_page,
};
// Crawl the crate to build various caches used for the output
},
_ => PathBuf::new(),
};
- let extern_url = extern_urls.get(&e.name).map(|u| &**u);
+ let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
cache.extern_locations.insert(n, (e.name.clone(), src_root,
extern_location(e, extern_url, &cx.dst)));
CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
- write_shared(&cx, &krate, &*cache, index, enable_minification, matches, diag)?;
+ write_shared(&cx, &krate, &*cache, index, &md_opts, diag)?;
// And finally render the whole crate's documentation
cx.krate(krate)
krate: &clean::Crate,
cache: &Cache,
search_index: String,
- enable_minification: bool,
- matches: &getopts::Matches,
+ options: &RenderOptions,
diag: &errors::Handler,
) -> Result<(), Error> {
// Write out the shared files. Note that these are shared among all rustdoc
write_minify(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
include_str!("static/rustdoc.css"),
- enable_minification)?;
+ options.enable_minification)?;
write_minify(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
include_str!("static/settings.css"),
- enable_minification)?;
+ options.enable_minification)?;
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles.
include_bytes!("static/wheel.svg"))?;
write_minify(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
include_str!("static/themes/light.css"),
- enable_minification)?;
+ options.enable_minification)?;
themes.insert("light".to_owned());
write_minify(cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)),
include_str!("static/themes/dark.css"),
- enable_minification)?;
+ options.enable_minification)?;
themes.insert("dark".to_owned());
let mut themes: Vec<&String> = themes.iter().collect();
write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
include_str!("static/main.js"),
- enable_minification)?;
+ options.enable_minification)?;
write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
include_str!("static/settings.js"),
- enable_minification)?;
+ options.enable_minification)?;
{
let mut data = format!("var resourcesSuffix = \"{}\";\n",
data.push_str(include_str!("static/storage.js"));
write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
&data,
- enable_minification)?;
+ options.enable_minification)?;
}
if let Some(ref css) = cx.shared.css_file_extension {
let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix));
- if !enable_minification {
+ if !options.enable_minification {
try_err!(fs::copy(css, out), css);
} else {
let mut f = try_err!(File::open(css), css);
let mut buffer = String::with_capacity(1000);
try_err!(f.read_to_string(&mut buffer), css);
- write_minify(out, &buffer, enable_minification)?;
+ write_minify(out, &buffer, options.enable_minification)?;
}
}
write_minify(cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)),
include_str!("static/normalize.css"),
- enable_minification)?;
+ options.enable_minification)?;
write(cx.dst.join("FiraSans-Regular.woff"),
include_bytes!("static/FiraSans-Regular.woff"))?;
write(cx.dst.join("FiraSans-Medium.woff"),
let mut w = try_err!(File::create(&dst), &dst);
try_err!(writeln!(&mut w, "var N = null;var searchIndex = {{}};"), &dst);
for index in &all_indexes {
- try_err!(write_minify_replacer(&mut w, &*index, enable_minification,
+ try_err!(write_minify_replacer(&mut w, &*index, options.enable_minification,
&[(minifier::js::Keyword::Null, "N")]),
&dst);
}
try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst);
- if cx.enable_index_page == true {
- if let Some(ref index_page) = cx.index_page {
- ::markdown::render(index_page,
- cx.dst.clone(),
- &matches, &(*cx.shared).layout.external_html,
- !matches.opt_present("markdown-no-toc"),
- diag);
+ if options.enable_index_page {
+ if let Some(index_page) = options.index_page.clone() {
+ let mut md_opts = options.clone();
+ md_opts.output = cx.dst.clone();
+ md_opts.external_html = (*cx.shared).layout.external_html.clone();
+
+ ::markdown::render(index_page, md_opts, diag);
} else {
let dst = cx.dst.join("index.html");
let mut w = BufWriter::new(try_err!(File::create(&dst), &dst));
extern crate serialize as rustc_serialize; // used by deriving
-use errors::ColorConfig;
-
-use std::collections::{BTreeMap, BTreeSet};
use std::default::Default;
use std::env;
use std::panic;
-use std::path::{Path, PathBuf};
use std::process;
use std::sync::mpsc::channel;
-use syntax::edition::Edition;
-use externalfiles::ExternalHtml;
use rustc::session::{early_warn, early_error};
-use rustc::session::search_paths::SearchPaths;
-use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions};
-use rustc::session::config::{nightly_options, build_codegen_options};
-use rustc_target::spec::TargetTriple;
-use rustc::session::config::get_cmd_lint_options;
+use rustc::session::config::{ErrorOutputType, RustcOptGroup};
#[macro_use]
mod externalfiles;
mod clean;
+mod config;
mod core;
mod doctree;
mod fold;
struct Output {
krate: clean::Crate,
renderinfo: html::render::RenderInfo,
+ renderopts: config::RenderOptions,
passes: Vec<String>,
}
early_error(ErrorOutputType::default(), &err.to_string());
}
};
- // Check for unstable options.
- nightly_options::check_nightly_options(&matches, &opts());
-
- if matches.opt_present("h") || matches.opt_present("help") {
- usage("rustdoc");
- return 0;
- } else if matches.opt_present("version") {
- rustc_driver::version("rustdoc", &matches);
- return 0;
- }
-
- if matches.opt_strs("passes") == ["list"] {
- println!("Available passes for running rustdoc:");
- for pass in passes::PASSES {
- println!("{:>20} - {}", pass.name(), pass.description());
- }
- println!("\nDefault passes for rustdoc:");
- for &name in passes::DEFAULT_PASSES {
- println!("{:>20}", name);
- }
- println!("\nPasses run with `--document-private-items`:");
- for &name in passes::DEFAULT_PRIVATE_PASSES {
- println!("{:>20}", name);
- }
- return 0;
- }
-
- let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
- Some("auto") => ColorConfig::Auto,
- Some("always") => ColorConfig::Always,
- Some("never") => ColorConfig::Never,
- None => ColorConfig::Auto,
- Some(arg) => {
- early_error(ErrorOutputType::default(),
- &format!("argument for --color must be `auto`, `always` or `never` \
- (instead was `{}`)", arg));
- }
+ let options = match config::Options::from_matches(&matches) {
+ Ok(opts) => opts,
+ Err(code) => return code,
};
- let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
- Some("human") => ErrorOutputType::HumanReadable(color),
- Some("json") => ErrorOutputType::Json(false),
- Some("pretty-json") => ErrorOutputType::Json(true),
- Some("short") => ErrorOutputType::Short(color),
- None => ErrorOutputType::HumanReadable(color),
- Some(arg) => {
- early_error(ErrorOutputType::default(),
- &format!("argument for --error-format must be `human`, `json` or \
- `short` (instead was `{}`)", arg));
- }
- };
- let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
- *x == "treat-err-as-bug"
- });
- let ui_testing = matches.opt_strs("Z").iter().any(|x| {
- *x == "ui-testing"
- });
-
- let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
-
- // check for deprecated options
- check_deprecated_options(&matches, &diag);
-
- let to_check = matches.opt_strs("theme-checker");
- if !to_check.is_empty() {
- let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
- let mut errors = 0;
-
- println!("rustdoc: [theme-checker] Starting tests!");
- for theme_file in to_check.iter() {
- print!(" - Checking \"{}\"...", theme_file);
- let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
- if !differences.is_empty() || !success {
- println!(" FAILED");
- errors += 1;
- if !differences.is_empty() {
- println!("{}", differences.join("\n"));
- }
- } else {
- println!(" OK");
- }
- }
- if errors != 0 {
- return 1;
- }
- return 0;
- }
-
- if matches.free.is_empty() {
- diag.struct_err("missing file operand").emit();
- return 1;
- }
- if matches.free.len() > 1 {
- diag.struct_err("too many file operands").emit();
- return 1;
- }
- let input = matches.free[0].clone();
-
- let mut libs = SearchPaths::new();
- for s in &matches.opt_strs("L") {
- libs.add_path(s, error_format);
- }
- let externs = match parse_externs(&matches) {
- Ok(ex) => ex,
- Err(err) => {
- diag.struct_err(&err).emit();
- return 1;
- }
- };
- let extern_urls = match parse_extern_html_roots(&matches) {
- Ok(ex) => ex,
- Err(err) => {
- diag.struct_err(err).emit();
- return 1;
- }
- };
-
- let test_args = matches.opt_strs("test-args");
- let test_args: Vec<String> = test_args.iter()
- .flat_map(|s| s.split_whitespace())
- .map(|s| s.to_string())
- .collect();
-
- let should_test = matches.opt_present("test");
- let markdown_input = Path::new(&input).extension()
- .map_or(false, |e| e == "md" || e == "markdown");
-
- let output = matches.opt_str("o").map(|s| PathBuf::from(&s));
- let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
- let mut cfgs = matches.opt_strs("cfg");
- cfgs.push("rustdoc".to_string());
-
- if let Some(ref p) = css_file_extension {
- if !p.is_file() {
- diag.struct_err("option --extend-css argument must be a file").emit();
- return 1;
- }
- }
-
- let mut themes = Vec::new();
- if matches.opt_present("themes") {
- let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
-
- for (theme_file, theme_s) in matches.opt_strs("themes")
- .iter()
- .map(|s| (PathBuf::from(&s), s.to_owned())) {
- if !theme_file.is_file() {
- diag.struct_err("option --themes arguments must all be files").emit();
- return 1;
- }
- let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
- if !success || !ret.is_empty() {
- diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
- .help("check what's wrong with the --theme-checker option")
- .emit();
- return 1;
- }
- themes.push(theme_file);
- }
- }
-
- let mut id_map = html::markdown::IdMap::new();
- id_map.populate(html::render::initial_ids());
- let external_html = match ExternalHtml::load(
- &matches.opt_strs("html-in-header"),
- &matches.opt_strs("html-before-content"),
- &matches.opt_strs("html-after-content"),
- &matches.opt_strs("markdown-before-content"),
- &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
- Some(eh) => eh,
- None => return 3,
- };
- let crate_name = matches.opt_str("crate-name");
- let playground_url = matches.opt_str("playground-url");
- let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let display_warnings = matches.opt_present("display-warnings");
- let linker = matches.opt_str("linker").map(PathBuf::from);
- let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
- let resource_suffix = matches.opt_str("resource-suffix");
- let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
- let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
- let enable_minification = !matches.opt_present("disable-minification");
-
- let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
- let edition = match edition.parse() {
- Ok(e) => e,
- Err(_) => {
- diag.struct_err("could not parse edition").emit();
- return 1;
- }
- };
- if let Some(ref index_page) = index_page {
- if !index_page.is_file() {
- diag.struct_err("option `--index-page` argument must be a file").emit();
- return 1;
- }
- }
- let cg = build_codegen_options(&matches, ErrorOutputType::default());
+ let diag = core::new_handler(options.error_format,
+ None,
+ options.debugging_options.treat_err_as_bug,
+ options.debugging_options.ui_testing);
- match (should_test, markdown_input) {
- (true, true) => {
- return markdown::test(&input, cfgs, libs, externs, test_args, maybe_sysroot,
- display_warnings, linker, edition, cg, &diag)
- }
- (true, false) => {
- return test::run(Path::new(&input), cfgs, libs, externs, test_args, crate_name,
- maybe_sysroot, display_warnings, linker, edition, cg)
- }
- (false, true) => return markdown::render(Path::new(&input),
- output.unwrap_or(PathBuf::from("doc")),
- &matches, &external_html,
- !matches.opt_present("markdown-no-toc"), &diag),
+ match (options.should_test, options.markdown_input()) {
+ (true, true) => return markdown::test(options, &diag),
+ (true, false) => return test::run(options),
+ (false, true) => return markdown::render(options.input, options.render_options, &diag),
(false, false) => {}
}
- let output_format = matches.opt_str("w");
-
- let res = acquire_input(PathBuf::from(input), externs, edition, cg, matches, error_format,
- move |out, matches| {
- let Output { krate, passes, renderinfo } = out;
- let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
+ // need to move these items separately because we lose them by the time the closure is called,
+ // but we can't crates the Handler ahead of time because it's not Send
+ let diag_opts = (options.error_format,
+ options.debugging_options.treat_err_as_bug,
+ options.debugging_options.ui_testing);
+ rust_input(options, move |out| {
+ let Output { krate, passes, renderinfo, renderopts } = out;
info!("going to format");
- match output_format.as_ref().map(|s| &**s) {
- Some("html") | None => {
- html::render::run(krate, extern_urls, &external_html, playground_url,
- output.unwrap_or(PathBuf::from("doc")),
- resource_suffix.unwrap_or(String::new()),
- passes.into_iter().collect(),
- css_file_extension,
- renderinfo,
- sort_modules_alphabetically,
- themes,
- enable_minification, id_map,
- enable_index_page, index_page,
- &matches,
- &diag)
- .expect("failed to generate documentation");
- 0
- }
- Some(s) => {
- diag.struct_err(&format!("unknown output format: {}", s)).emit();
- 1
- }
- }
- });
- res.unwrap_or_else(|s| {
- diag.struct_err(&format!("input error: {}", s)).emit();
- 1
+ let (error_format, treat_err_as_bug, ui_testing) = diag_opts;
+ let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
+ html::render::run(krate, renderopts, passes.into_iter().collect(), renderinfo, &diag)
+ .expect("failed to generate documentation");
+ 0
})
}
-/// Looks inside the command line arguments to extract the relevant input format
-/// and files and then generates the necessary rustdoc output for formatting.
-fn acquire_input<R, F>(input: PathBuf,
- externs: Externs,
- edition: Edition,
- cg: CodegenOptions,
- matches: getopts::Matches,
- error_format: ErrorOutputType,
- f: F)
- -> Result<R, String>
-where R: 'static + Send, F: 'static + Send + FnOnce(Output, &getopts::Matches) -> R {
- match matches.opt_str("r").as_ref().map(|s| &**s) {
- Some("rust") => Ok(rust_input(input, externs, edition, cg, matches, error_format, f)),
- Some(s) => Err(format!("unknown input format: {}", s)),
- None => Ok(rust_input(input, externs, edition, cg, matches, error_format, f))
- }
-}
-
-/// Extracts `--extern CRATE=PATH` arguments from `matches` and
-/// returns a map mapping crate names to their paths or else an
-/// error message.
-// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
-fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
- let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
- for arg in &matches.opt_strs("extern") {
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
- let location = parts.next().map(|s| s.to_string());
- if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
- return Err("the `-Z unstable-options` flag must also be passed to \
- enable `--extern crate_name` without `=path`".to_string());
- }
- let name = name.to_string();
- externs.entry(name).or_default().insert(location);
- }
- Ok(Externs::new(externs))
-}
-
-/// Extracts `--extern-html-root-url` arguments from `matches` and returns a map of crate names to
-/// the given URLs. If an `--extern-html-root-url` argument was ill-formed, returns an error
-/// describing the issue.
-fn parse_extern_html_roots(matches: &getopts::Matches)
- -> Result<BTreeMap<String, String>, &'static str>
-{
- let mut externs = BTreeMap::new();
- for arg in &matches.opt_strs("extern-html-root-url") {
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().ok_or("--extern-html-root-url must not be empty")?;
- let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?;
- externs.insert(name.to_string(), url.to_string());
- }
-
- Ok(externs)
-}
-
/// Interprets the input file as a rust source file, passing it through the
/// compiler all the way through the analysis passes. The rustdoc output is then
/// generated from the cleaned AST of the crate.
///
/// This form of input will run all of the plug/cleaning passes
-fn rust_input<R, F>(cratefile: PathBuf,
- externs: Externs,
- edition: Edition,
- cg: CodegenOptions,
- matches: getopts::Matches,
- error_format: ErrorOutputType,
- f: F) -> R
+fn rust_input<R, F>(options: config::Options, f: F) -> R
where R: 'static + Send,
- F: 'static + Send + FnOnce(Output, &getopts::Matches) -> R
+ F: 'static + Send + FnOnce(Output) -> R
{
- let default_passes = if matches.opt_present("no-defaults") {
- passes::DefaultPassOption::None
- } else if matches.opt_present("document-private-items") {
- passes::DefaultPassOption::Private
- } else {
- passes::DefaultPassOption::Default
- };
-
- let manual_passes = matches.opt_strs("passes");
- let plugins = matches.opt_strs("plugins");
-
// First, parse the crate and extract all relevant information.
- let mut paths = SearchPaths::new();
- for s in &matches.opt_strs("L") {
- paths.add_path(s, ErrorOutputType::default());
- }
- let mut cfgs = matches.opt_strs("cfg");
- cfgs.push("rustdoc".to_string());
- let triple = matches.opt_str("target").map(|target| {
- if target.ends_with(".json") {
- TargetTriple::TargetPath(PathBuf::from(target))
- } else {
- TargetTriple::TargetTriple(target)
- }
- });
- let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let crate_name = matches.opt_str("crate-name");
- let crate_version = matches.opt_str("crate-version");
- let plugin_path = matches.opt_str("plugin-path");
-
info!("starting to run rustc");
- let display_warnings = matches.opt_present("display-warnings");
-
- let force_unstable_if_unmarked = matches.opt_strs("Z").iter().any(|x| {
- *x == "force-unstable-if-unmarked"
- });
- let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
- *x == "treat-err-as-bug"
- });
- let ui_testing = matches.opt_strs("Z").iter().any(|x| {
- *x == "ui-testing"
- });
-
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(&matches, error_format);
let (tx, rx) = channel();
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
- use rustc::session::config::Input;
-
- let (mut krate, renderinfo, passes) =
- core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
- display_warnings, crate_name.clone(),
- force_unstable_if_unmarked, edition, cg, error_format,
- lint_opts, lint_cap, describe_lints, manual_passes, default_passes,
- treat_err_as_bug, ui_testing);
+ let crate_name = options.crate_name.clone();
+ let crate_version = options.crate_version.clone();
+ let (mut krate, renderinfo, renderopts, passes) = core::run_core(options);
info!("finished with rustc");
krate.version = crate_version;
- if !plugins.is_empty() {
- eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622");
- }
-
- if !plugin_path.is_none() {
- eprintln!("WARNING: --plugin-path no longer functions; see CVE-2018-1000622");
- }
-
info!("Executing passes");
for pass in &passes {
krate = pass(krate);
}
- tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes },
- &matches)).unwrap();
+ tx.send(f(Output {
+ krate: krate,
+ renderinfo: renderinfo,
+ renderopts,
+ passes: passes
+ })).unwrap();
}));
match result {
Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)),
}
}
-
-/// Prints deprecation warnings for deprecated options
-fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
- let deprecated_flags = [
- "input-format",
- "output-format",
- "no-defaults",
- "passes",
- ];
-
- for flag in deprecated_flags.into_iter() {
- if matches.opt_present(flag) {
- let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
- flag));
- err.warn("please see https://github.com/rust-lang/rust/issues/44136");
-
- if *flag == "no-defaults" {
- err.help("you may want to use --document-private-items");
- }
-
- err.emit();
- }
- }
-}
use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
-use std::path::{PathBuf, Path};
+use std::path::PathBuf;
use std::cell::RefCell;
use errors;
-use getopts;
use testing;
-use rustc::session::search_paths::SearchPaths;
-use rustc::session::config::{Externs, CodegenOptions};
use syntax::source_map::DUMMY_SP;
use syntax::feature_gate::UnstableFeatures;
-use syntax::edition::Edition;
-use externalfiles::{ExternalHtml, LoadStringError, load_string};
+use externalfiles::{LoadStringError, load_string};
+use config::{Options, RenderOptions};
use html::escape::Escape;
use html::markdown;
use html::markdown::{ErrorCodes, IdMap, Markdown, MarkdownWithToc, find_testable_code};
/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
-pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
- external_html: &ExternalHtml, include_toc: bool, diag: &errors::Handler) -> isize {
+pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> isize {
+ let mut output = options.output;
output.push(input.file_stem().unwrap());
output.set_extension("html");
let mut css = String::new();
- for name in &matches.opt_strs("markdown-css") {
+ for name in &options.markdown_css {
let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
css.push_str(&s)
}
- let input_str = match load_string(input, diag) {
+ let input_str = match load_string(&input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
};
- if let Some(playground) = matches.opt_str("markdown-playground-url").or(
- matches.opt_str("playground-url")) {
+ let playground_url = options.markdown_playground_url
+ .or(options.playground_url);
+ if let Some(playground) = playground_url {
markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
}
let mut ids = IdMap::new();
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
- let text = if include_toc {
+ let text = if !options.markdown_no_toc {
MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string()
} else {
Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string()
</html>"#,
title = Escape(title),
css = css,
- in_header = external_html.in_header,
- before_content = external_html.before_content,
+ in_header = options.external_html.in_header,
+ before_content = options.external_html.before_content,
text = text,
- after_content = external_html.after_content,
+ after_content = options.external_html.after_content,
);
match err {
}
/// Run any tests/code examples in the markdown file `input`.
-pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
- mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
- display_warnings: bool, linker: Option<PathBuf>, edition: Edition,
- cg: CodegenOptions, diag: &errors::Handler) -> isize {
- let input_str = match load_string(input, diag) {
+pub fn test(mut options: Options, diag: &errors::Handler) -> isize {
+ let input_str = match load_string(&options.input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
- opts.display_warnings = display_warnings;
- let mut collector = Collector::new(input.to_owned(), cfgs, libs, cg, externs,
- true, opts, maybe_sysroot, None,
- Some(PathBuf::from(input)),
- linker, edition);
+ opts.display_warnings = options.display_warnings;
+ let mut collector = Collector::new(options.input.display().to_string(), options.cfgs,
+ options.libs, options.codegen_options, options.externs,
+ true, opts, options.maybe_sysroot, None,
+ Some(options.input),
+ options.linker, options.edition);
collector.set_position(DUMMY_SP);
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let res = find_testable_code(&input_str, &mut collector, codes);
if let Err(err) = res {
diag.span_warn(DUMMY_SP, &err.to_string());
}
- test_args.insert(0, "rustdoctest".to_string());
- testing::test_main(&test_args, collector.tests,
- testing::Options::new().display_output(display_warnings));
+ options.test_args.insert(0, "rustdoctest".to_string());
+ testing::test_main(&options.test_args, collector.tests,
+ testing::Options::new().display_output(options.display_warnings));
0
}
use std::ffi::OsString;
use std::io::prelude::*;
use std::io;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
use std::panic::{self, AssertUnwindSafe};
use std::process::Command;
use std::str;
use errors::emitter::ColorConfig;
use clean::Attributes;
+use config::Options;
use html::markdown::{self, ErrorCodes, LangString};
#[derive(Clone, Default)]
pub attrs: Vec<String>,
}
-pub fn run(input_path: &Path,
- cfgs: Vec<String>,
- libs: SearchPaths,
- externs: Externs,
- mut test_args: Vec<String>,
- crate_name: Option<String>,
- maybe_sysroot: Option<PathBuf>,
- display_warnings: bool,
- linker: Option<PathBuf>,
- edition: Edition,
- cg: CodegenOptions)
- -> isize {
- let input = config::Input::File(input_path.to_owned());
+pub fn run(mut options: Options) -> isize {
+ let input = config::Input::File(options.input.clone());
let sessopts = config::Options {
- maybe_sysroot: maybe_sysroot.clone().or_else(
+ maybe_sysroot: options.maybe_sysroot.clone().or_else(
|| Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
- search_paths: libs.clone(),
+ search_paths: options.libs.clone(),
crate_types: vec![config::CrateType::Dylib],
- cg: cg.clone(),
- externs: externs.clone(),
+ cg: options.codegen_options.clone(),
+ externs: options.externs.clone(),
unstable_features: UnstableFeatures::from_environment(),
lint_cap: Some(::rustc::lint::Level::Allow),
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions {
..config::basic_debugging_options()
},
- edition,
+ edition: options.edition,
..config::Options::default()
};
driver::spawn_thread_pool(sessopts, |sessopts| {
Some(source_map.clone()));
let mut sess = session::build_session_(
- sessopts, Some(input_path.to_owned()), handler, source_map.clone(),
+ sessopts, Some(options.input), handler, source_map.clone(),
);
let codegen_backend = rustc_driver::get_codegen_backend(&sess);
let cstore = CStore::new(codegen_backend.metadata_loader());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+ let mut cfg = config::build_configuration(&sess,
+ config::parse_cfgspecs(options.cfgs.clone()));
target_features::add_configuration(&mut cfg, &sess, &*codegen_backend);
sess.parse_sess.config = cfg;
).expect("phase_2_configure_and_expand aborted in rustdoc!")
};
- let crate_name = crate_name.unwrap_or_else(|| {
+ let crate_name = options.crate_name.unwrap_or_else(|| {
::rustc_codegen_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
});
let mut opts = scrape_test_config(hir_forest.krate());
- opts.display_warnings |= display_warnings;
+ opts.display_warnings |= options.display_warnings;
let mut collector = Collector::new(
crate_name,
- cfgs,
- libs,
- cg,
- externs,
+ options.cfgs,
+ options.libs,
+ options.codegen_options,
+ options.externs,
false,
opts,
- maybe_sysroot,
+ options.maybe_sysroot,
Some(source_map),
- None,
- linker,
- edition
+ None,
+ options.linker,
+ options.edition
);
{
});
}
- test_args.insert(0, "rustdoctest".to_string());
+ options.test_args.insert(0, "rustdoctest".to_string());
- testing::test_main(&test_args,
+ testing::test_main(&options.test_args,
collector.tests.into_iter().collect(),
- testing::Options::new().display_output(display_warnings));
+ testing::Options::new().display_output(options.display_warnings));
0
})
}
3 | no
| ^^ not found in this scope
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- $DIR/failed-doctest-output.rs - SomeStruct (line 21) stdout ----
thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
note: Run with `RUST_BACKTRACE=1` for a backtrace.
-', librustdoc/test.rs:367:17
+', librustdoc/test.rs:358:17
failures: