Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document build dependencies and dev dependencies #8562

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions src/bin/cargo/commands/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)?;
Expand Down
16 changes: 14 additions & 2 deletions src/cargo/core/compiler/build_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
35 changes: 28 additions & 7 deletions src/cargo/core/compiler/unit_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -404,22 +404,31 @@ fn compute_deps_custom_build(

/// Returns the dependencies necessary to document a package.
fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult<Vec<UnitDep>> {
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)
})
});

// To document a library, we depend on dependencies actually being
// built. If we're documenting *all* libraries, then we also depend on
// the documentation of the library being built.
let mut ret = Vec::new();
for (id, _deps) in deps {
for (id, deps) in deps {
let dep = state.get(id);
let lib = match dep.targets().iter().find(|t| t.is_lib()) {
Some(lib) => lib,
Expand All @@ -441,7 +450,14 @@ fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult<Vec<U
mode,
)?;
ret.push(lib_unit_dep);
if let CompileMode::Doc { deps: true } = unit.mode {

let should_document = deps.iter().any(|dep| match dep.kind() {
DepKind::Normal => 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,
Expand All @@ -450,7 +466,12 @@ fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult<Vec<U
lib,
dep_unit_for,
unit.kind.for_target(lib),
unit.mode,
CompileMode::Doc(DocDepsMode {
deps: deps_mode.deps,
build: false,
dev: false,
normal: deps_mode.deps,
}),
)?;
ret.push(doc_unit_dep);
}
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use clap::{self, SubCommand};
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;

pub use crate::core::compiler::CompileMode;
pub use crate::core::compiler::{CompileMode, DocDepsMode};
pub use crate::{CliError, CliResult, Config};
pub use clap::{AppSettings, Arg, ArgMatches};

Expand Down
68 changes: 67 additions & 1 deletion tests/testsuite/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::registry::Package;
use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project};
use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project, Project};
use cargo_test_support::{is_nightly, rustc_host};
use std::fs;
use std::str;
Expand Down Expand Up @@ -1542,3 +1542,69 @@ fn crate_versions_flag_is_overridden() {
p.cargo("rustdoc -- --crate-version 2.0.3").run();
asserts(output_documentation());
}

fn build_doc_project() -> 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();
}