From 27ca04b173964f7f62944b4526ed66b97305c5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 9 Aug 2020 00:00:00 +0000 Subject: [PATCH] Document build dependencies and dev dependencies Add a new `--deps` option to cargo doc, which allows to select what kinds of dependencies should be documented: build dependencies, dev dependencies, or normal dependencies. Multiple kinds of dependencies can be specified, e.g., `cargo doc --deps=dev,normal`. When `--deps` options is used, the default behaviour of documenting normal dependencies is suppressed unless asked for explicitly with `--deps=normal`. The `--deps` option also conflicts with `--no-deps`. --- src/bin/cargo/commands/doc.rs | 48 ++++++++++++-- src/bin/cargo/commands/rustdoc.rs | 2 +- src/cargo/core/compiler/build_config.rs | 16 ++++- src/cargo/core/compiler/mod.rs | 2 +- src/cargo/core/compiler/unit_dependencies.rs | 35 ++++++++-- src/cargo/util/command_prelude.rs | 2 +- tests/testsuite/doc.rs | 68 +++++++++++++++++++- 7 files changed, 155 insertions(+), 18 deletions(-) diff --git a/src/bin/cargo/commands/doc.rs b/src/bin/cargo/commands/doc.rs index d82dc0ec3f6..2a75d369da3 100644 --- a/src/bin/cargo/commands/doc.rs +++ b/src/bin/cargo/commands/doc.rs @@ -16,6 +16,17 @@ pub fn cli() -> App { "Exclude packages from the build", ) .arg(opt("no-deps", "Don't build documentation for dependencies")) + .arg( + opt( + "deps", + "Build documentation for given kinds of dependencies", + ) + .takes_value(true) + .multiple(true) + .require_delimiter(true) + .possible_values(&["all", "build", "dev", "normal"]) + .conflicts_with("no-deps"), + ) .arg(opt("document-private-items", "Document private items")) .arg_jobs() .arg_targets_lib_bin( @@ -36,11 +47,38 @@ pub fn cli() -> App { pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let ws = args.workspace(config)?; - let mode = CompileMode::Doc { - deps: !args.is_present("no-deps"), - }; - let mut compile_opts = - args.compile_options(config, mode, Some(&ws), ProfileChecking::Checked)?; + + let mut deps_mode = DocDepsMode::default(); + if let Some(deps) = args.values_of("deps") { + config.cli_unstable().fail_if_stable_opt("--deps", 8608)?; + + // Disable documenting of transitive dependencies. + deps_mode.deps = false; + for dep in deps { + match dep { + "all" => { + deps_mode.build = true; + deps_mode.normal = true; + deps_mode.dev = true; + } + "build" => deps_mode.build = true, + "normal" => deps_mode.normal = true, + "dev" => deps_mode.dev = true, + _ => unreachable!(), + } + } + } else { + let no_deps = args.is_present("no-deps"); + deps_mode.deps = !no_deps; + deps_mode.normal = !no_deps; + } + + let mut compile_opts = args.compile_options( + config, + CompileMode::Doc(deps_mode), + Some(&ws), + ProfileChecking::Checked, + )?; compile_opts.rustdoc_document_private_items = args.is_present("document-private-items"); let doc_opts = DocOptions { diff --git a/src/bin/cargo/commands/rustdoc.rs b/src/bin/cargo/commands/rustdoc.rs index f67f6ba985b..5775ec173a2 100644 --- a/src/bin/cargo/commands/rustdoc.rs +++ b/src/bin/cargo/commands/rustdoc.rs @@ -41,7 +41,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let ws = args.workspace(config)?; let mut compile_opts = args.compile_options_for_single_package( config, - CompileMode::Doc { deps: false }, + CompileMode::Doc(DocDepsMode::default()), Some(&ws), ProfileChecking::Checked, )?; diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index d0f5431a47e..f75d78f0f68 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -139,14 +139,26 @@ pub enum CompileMode { /// allows some de-duping of Units to occur. Bench, /// A target that will be documented with `rustdoc`. - /// If `deps` is true, then it will also document all dependencies. - Doc { deps: bool }, + Doc(DocDepsMode), /// A target that will be tested with `rustdoc`. Doctest, /// A marker for Units that represent the execution of a `build.rs` script. RunCustomBuild, } +/// Describes what kinds of dependencies should be documented. +#[derive(Clone, Copy, Default, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)] +pub struct DocDepsMode { + /// Document build dependencies. + pub build: bool, + /// Document development dependencies. + pub dev: bool, + /// Document normal dependencies. + pub normal: bool, + /// Whether to document dependencies of other crates being documented. + pub deps: bool, +} + impl ser::Serialize for CompileMode { fn serialize(&self, s: S) -> Result where diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 79d8c47abed..4079250b715 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -31,7 +31,7 @@ use anyhow::Error; use lazycell::LazyCell; use log::debug; -pub use self::build_config::{BuildConfig, CompileMode, MessageFormat}; +pub use self::build_config::{BuildConfig, CompileMode, DocDepsMode, MessageFormat}; pub use self::build_context::{BuildContext, FileFlavor, FileType, RustcTargetData, TargetInfo}; use self::build_plan::BuildPlan; pub use self::compilation::{Compilation, Doctest}; diff --git a/src/cargo/core/compiler/unit_dependencies.rs b/src/cargo/core/compiler/unit_dependencies.rs index 8ebe21b9002..daf20a6b4fc 100644 --- a/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/cargo/core/compiler/unit_dependencies.rs @@ -17,7 +17,7 @@ use crate::core::compiler::unit_graph::{UnitDep, UnitGraph}; use crate::core::compiler::UnitInterner; -use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit}; +use crate::core::compiler::{CompileKind, CompileMode, DocDepsMode, RustcTargetData, Unit}; use crate::core::dependency::DepKind; use crate::core::profiles::{Profile, Profiles, UnitFor}; use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures}; @@ -404,14 +404,23 @@ fn compute_deps_custom_build( /// Returns the dependencies necessary to document a package. fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult> { + let deps_mode = match unit.mode { + CompileMode::Doc(deps_mode) => deps_mode, + _ => unreachable!(), + }; + let target_data = state.target_data; let deps = state .resolve() .deps(unit.pkg.package_id()) .filter(|&(_id, deps)| { - deps.iter().any(|dep| match dep.kind() { - DepKind::Normal => target_data.dep_platform_activated(dep, unit.kind), - _ => false, + deps.iter().any(|dep| { + let required = match dep.kind() { + DepKind::Normal => true, + DepKind::Build => deps_mode.build, + DepKind::Development => deps_mode.dev, + }; + required && target_data.dep_platform_activated(dep, unit.kind) }) }); @@ -419,7 +428,7 @@ fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult lib, @@ -441,7 +450,14 @@ fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult deps_mode.normal, + DepKind::Build => deps_mode.build, + DepKind::Development => deps_mode.dev, + }); + + if should_document { // Document this lib as well. let doc_unit_dep = new_unit_dep( state, @@ -450,7 +466,12 @@ fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult Project { + project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies] + num = { path = "num" } + + [build-dependencies] + baz = { path = "baz" } + + [dev-dependencies] + dev = { path = "dev" } + "#, + ) + .file("src/lib.rs", "pub fn foo() {}") + .file("num/Cargo.toml", &basic_manifest("num", "1.0.0")) + .file("num/src/lib.rs", "") + .file("baz/Cargo.toml", &basic_manifest("baz", "1.0.0")) + .file("baz/src/lib.rs", "") + .file("dev/Cargo.toml", &basic_manifest("dev", "1.0.0")) + .file("dev/src/lib.rs", "") + .build() +} + +#[cargo_test] +fn doc_deps_dev() { + build_doc_project() + .cargo("doc -Zunstable-options --deps=dev") + .masquerade_as_nightly_cargo() + .with_stderr_contains("[..] Documenting dev v1.0.0 ([..])") + .with_stderr_contains("[..] Documenting foo v0.0.1 ([..])") + .with_stderr_does_not_contain("[..] Documenting baz v1.0.0 ([..])") + .with_stderr_does_not_contain("[..] Documenting num v1.0.0 ([..])") + .run(); +} + +#[cargo_test] +fn doc_deps_build_normal() { + build_doc_project() + .cargo("doc -Zunstable-options --deps=build,normal") + .masquerade_as_nightly_cargo() + .with_stderr_contains("[..] Documenting baz v1.0.0 ([..])") + .with_stderr_contains("[..] Documenting foo v0.0.1 ([..])") + .with_stderr_contains("[..] Documenting num v1.0.0 ([..])") + .with_stderr_does_not_contain("[..] Documenting dev v1.0.0 ([..])") + .run(); +} + +#[cargo_test] +fn doc_deps_all() { + build_doc_project() + .cargo("doc -Zunstable-options --deps=all") + .masquerade_as_nightly_cargo() + .with_stderr_contains("[..] Documenting baz v1.0.0 ([..])") + .with_stderr_contains("[..] Documenting dev v1.0.0 ([..])") + .with_stderr_contains("[..] Documenting foo v0.0.1 ([..])") + .with_stderr_contains("[..] Documenting num v1.0.0 ([..])") + .run(); +}