Add cargo rustdoc for passing arbitrary flags to rustdoc

This commit is contained in:
Manish Goregaokar 2015-09-09 14:16:43 +05:30 committed by Alex Crichton
parent b01770c7ad
commit 4816a2a5d8
15 changed files with 305 additions and 0 deletions

View file

@ -84,6 +84,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
extra_rustdoc_args: Vec::new(),
target_rustc_args: None,
},
};

View file

@ -81,6 +81,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
extra_rustdoc_args: Vec::new(),
target_rustc_args: None,
};

View file

@ -81,6 +81,7 @@ macro_rules! each_subcommand{ ($mac:ident) => ({
$mac!(read_manifest);
$mac!(run);
$mac!(rustc);
$mac!(rustdoc);
$mac!(search);
$mac!(test);
$mac!(uninstall);

View file

@ -70,6 +70,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
deps: !options.flag_no_deps,
},
target_rustc_args: None,
extra_rustdoc_args: Vec::new(),
},
};

View file

@ -80,6 +80,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
bins: &bins, examples: &examples,
}
},
extra_rustdoc_args: Vec::new(),
target_rustc_args: None,
};

View file

@ -84,6 +84,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
extra_rustdoc_args: Vec::new(),
target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]),
};

89
src/bin/rustdoc.rs Normal file
View file

@ -0,0 +1,89 @@
use cargo::ops;
use cargo::util::{CliResult, CliError, Config};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
#[derive(RustcDecodable)]
struct Options {
arg_opts: Vec<String>,
flag_target: Option<String>,
flag_features: Vec<String>,
flag_jobs: Option<u32>,
flag_manifest_path: Option<String>,
flag_no_default_features: bool,
flag_no_deps: bool,
flag_open: bool,
flag_verbose: bool,
flag_release: bool,
flag_quiet: bool,
flag_color: Option<String>,
flag_package: Option<String>,
}
pub const USAGE: &'static str = "
Build a package's documentation, using specified custom flags.
Usage:
cargo rustdoc [options] [--] [<opts>...]
Options:
-h, --help Print this message
--open Opens the docs in a browser after the operation
-p SPEC, --package SPEC Package to document
--no-deps Don't build documentation for dependencies
-j N, --jobs N The number of jobs to run in parallel
--release Build artifacts in release mode, with optimizations
--features FEATURES Space-separated list of features to also build
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to document
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.
The specified target for the current package (or package specified by SPEC if
provided) will be documented along with all of its dependencies. The specified
<opts>... will all be passed to the final rustdoc invocation, not any of the
dependencies. Note that rustdoc will still unconditionally receive
arguments such as -L, --extern, and --crate-type, and the specified <opts>...
will simply be added to the rustdoc invocation.
If the --package argument is given, then SPEC is a package id specification
which indicates which package should be documented. If it is not given, then the
current package is documented. For more information on SPEC and its format, see
the `cargo help pkgid` command.
";
pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));
try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..])));
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
let mut doc_opts = ops::DocOptions {
open_result: options.flag_open,
compile_opts: ops::CompileOptions {
config: config,
jobs: options.flag_jobs,
target: options.flag_target.as_ref().map(|t| &t[..]),
features: &options.flag_features,
no_default_features: options.flag_no_default_features,
spec: options.flag_package.as_ref().map(|s| &s[..]),
exec_engine: None,
filter: ops::CompileFilter::Everything,
release: options.flag_release,
mode: ops::CompileMode::Doc {
deps: !options.flag_no_deps,
},
extra_rustdoc_args: options.arg_opts,
target_rustc_args: None,
},
};
try!(ops::doc(&root, &mut doc_opts).map_err(|err| CliError::from_boxed(err, 101)));
Ok(None)
}

View file

@ -90,6 +90,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
extra_rustdoc_args: Vec::new(),
target_rustc_args: None,
},
};

View file

@ -112,6 +112,7 @@ pub struct Profile {
pub lto: bool,
pub codegen_units: Option<u32>, // None = use rustc default
pub rustc_args: Option<Vec<String>>,
pub rustdoc_args: Option<Vec<String>>,
pub debuginfo: bool,
pub debug_assertions: bool,
pub rpath: bool,
@ -474,6 +475,7 @@ impl Default for Profile {
lto: false,
codegen_units: None,
rustc_args: None,
rustdoc_args: None,
debuginfo: false,
debug_assertions: false,
rpath: false,

View file

@ -57,6 +57,8 @@ pub struct CompileOptions<'a> {
pub release: bool,
/// Mode for this compile.
pub mode: CompileMode,
/// Extra arguments to be passed to rustdoc (for main crate and dependencies)
pub extra_rustdoc_args: Vec<String>,
/// The specified target will be compiled with all the available arguments,
/// note that this only accounts for the *final* invocation of rustc
pub target_rustc_args: Option<&'a [String]>,
@ -145,6 +147,7 @@ pub fn compile_pkg<'a>(root_package: &Package,
let CompileOptions { config, jobs, target, spec, features,
no_default_features, release, mode,
ref filter, ref exec_engine,
ref extra_rustdoc_args,
ref target_rustc_args } = *options;
let target = target.map(|s| s.to_string());
@ -223,6 +226,24 @@ pub fn compile_pkg<'a>(root_package: &Package,
}
let mut ret = {
let mut target_with_rustdoc = None;
if !extra_rustdoc_args.is_empty() {
let mut target_with_rustdoc_inner = Vec::new();
for &(target, profile) in &targets {
if profile.doc {
let mut profile = profile.clone();
profile.rustdoc_args = Some(extra_rustdoc_args.clone());
target_with_rustdoc_inner.push((target, profile));
}
}
target_with_rustdoc = Some(target_with_rustdoc_inner);
};
let targets = target_with_rustdoc.as_ref().map_or(targets,
|o| o.into_iter()
.map(|&(t, ref p)| (t, p))
.collect());
let ret = {
let _p = profile::start("compiling");
let mut build_config = try!(scrape_build_config(config, jobs, target));
build_config.exec_engine = exec_engine.clone();

View file

@ -220,6 +220,7 @@ fn run_verify(config: &Config, pkg: &Package, tar: &Path)
exec_engine: None,
release: false,
mode: ops::CompileMode::Build,
extra_rustdoc_args: Vec::new(),
target_rustc_args: None,
}));

View file

@ -395,6 +395,10 @@ fn rustdoc(cx: &mut Context, unit: &Unit) -> CargoResult<Work> {
}
}
if let Some(ref args) = profile.rustdoc_args {
rustdoc.args(args);
}
try!(build_deps_args(&mut rustdoc, cx, unit));
if unit.pkg.has_custom_build() {
@ -448,6 +452,7 @@ fn build_base_args(cx: &Context,
let Profile {
opt_level, lto, codegen_units, ref rustc_args, debuginfo,
debug_assertions, rpath, test, doc: _doc, run_custom_build,
rustdoc_args: _,
} = *unit.profile;
assert!(!run_custom_build);

View file

@ -941,6 +941,7 @@ fn build_profiles(profiles: &Option<TomlProfiles>) -> Profiles {
lto: lto.unwrap_or(profile.lto),
codegen_units: codegen_units,
rustc_args: None,
rustdoc_args: None,
debuginfo: debug.unwrap_or(profile.debuginfo),
debug_assertions: debug_assertions.unwrap_or(profile.debug_assertions),
rpath: rpath.unwrap_or(profile.rpath),

178
tests/test_cargo_rustdoc.rs Normal file
View file

@ -0,0 +1,178 @@
use std::path::MAIN_SEPARATOR as SEP;
use support::{execs, project};
use support::{COMPILING, RUNNING};
use hamcrest::{assert_that};
fn setup() {
}
test!(rustdoc_simple {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", r#" "#);
assert_that(p.cargo_process("rustdoc").arg("-v"),
execs()
.with_status(0)
.with_stdout(format!("\
{compiling} foo v0.0.1 ({url})
{running} `rustdoc src{sep}lib.rs --crate-name foo \
-o {dir}{sep}target{sep}doc \
-L dependency={dir}{sep}target{sep}debug \
-L dependency={dir}{sep}target{sep}debug{sep}deps`
",
running = RUNNING, compiling = COMPILING, sep = SEP,
dir = p.root().display(), url = p.url())));
});
test!(rustdoc_args {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", r#" "#);
assert_that(p.cargo_process("rustdoc").arg("-v").arg("--").arg("--no-defaults"),
execs()
.with_status(0)
.with_stdout(format!("\
{compiling} foo v0.0.1 ({url})
{running} `rustdoc src{sep}lib.rs --crate-name foo \
-o {dir}{sep}target{sep}doc \
--no-defaults \
-L dependency={dir}{sep}target{sep}debug \
-L dependency={dir}{sep}target{sep}debug{sep}deps`
",
running = RUNNING, compiling = COMPILING, sep = SEP,
dir = p.root().display(), url = p.url())));
});
test!(rustdoc_foo_with_bar_dependency {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
"#)
.file("src/lib.rs", r#"
extern crate bar;
pub fn foo() {}
"#);
let bar = project("bar")
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", r#"
pub fn baz() {}
"#);
bar.build();
assert_that(foo.cargo_process("rustdoc").arg("-v").arg("--").arg("--no-defaults"),
execs()
.with_status(0)
.with_stdout(format!("\
{compiling} bar v0.0.1 ({url})
{running} `rustc {bar_dir}{sep}src{sep}lib.rs [..]`
{running} `rustdoc {bar_dir}{sep}src{sep}lib.rs --crate-name bar \
-o {dir}{sep}target{sep}doc \
-L dependency={dir}{sep}target{sep}debug{sep}deps \
-L dependency={dir}{sep}target{sep}debug{sep}deps`
{compiling} foo v0.0.1 ({url})
{running} `rustdoc src{sep}lib.rs --crate-name foo \
-o {dir}{sep}target{sep}doc \
--no-defaults \
-L dependency={dir}{sep}target{sep}debug \
-L dependency={dir}{sep}target{sep}debug{sep}deps \
--extern [..]`
",
running = RUNNING, compiling = COMPILING, sep = SEP,
dir = foo.root().display(), url = foo.url(),
bar_dir = bar.root().display())));
});
test!(rustdoc_only_bar_dependency {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
"#)
.file("src/main.rs", r#"
extern crate bar;
fn main() {
bar::baz()
}
"#);
let bar = project("bar")
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", r#"
pub fn baz() {}
"#);
bar.build();
assert_that(foo.cargo_process("rustdoc").arg("-v").arg("-p").arg("bar")
.arg("--").arg("--no-defaults"),
execs()
.with_status(0)
.with_stdout(format!("\
{compiling} bar v0.0.1 ({url})
{running} `rustdoc {bar_dir}{sep}src{sep}lib.rs --crate-name bar \
-o {dir}{sep}target{sep}doc \
--no-defaults \
-L dependency={dir}{sep}target{sep}debug{sep}deps \
-L dependency={dir}{sep}target{sep}debug{sep}deps`
",
running = RUNNING, compiling = COMPILING, sep = SEP,
dir = foo.root().display(), url = foo.url(),
bar_dir = bar.root().display())));
});
test!(rustdoc_same_name_err {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("src/lib.rs", r#" "#);
assert_that(p.cargo_process("rustdoc").arg("-v")
.arg("--").arg("--no-defaults"),
execs()
.with_status(101)
.with_stderr("Cannot document a package where a library and a \
binary have the same name. Consider renaming one \
or marking the target as `doc = false`"));
});

View file

@ -57,6 +57,7 @@ mod test_cargo_read_manifest;
mod test_cargo_registry;
mod test_cargo_run;
mod test_cargo_rustc;
mod test_cargo_rustdoc;
mod test_cargo_search;
mod test_cargo_test;
mod test_cargo_tool_paths;