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

Update books. #69115

Merged
merged 1 commit into from
Feb 14, 2020
Merged
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
82 changes: 58 additions & 24 deletions src/bootstrap/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1264,28 +1264,75 @@ impl Step for Compiletest {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct DocTest {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct BookTest {
compiler: Compiler,
path: &'static str,
path: PathBuf,
name: &'static str,
is_ext_doc: bool,
}

impl Step for DocTest {
impl Step for BookTest {
type Output = ();
const ONLY_HOSTS: bool = true;

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
}

/// Runs `rustdoc --test` for all documentation in `src/doc`.
/// Runs the documentation tests for a book in `src/doc`.
///
/// This will run all tests in our markdown documentation (e.g., the book)
/// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
/// `compiler`.
/// This uses the `rustdoc` that sits next to `compiler`.
fn run(self, builder: &Builder<'_>) {
// External docs are different from local because:
// - Some books need pre-processing by mdbook before being tested.
// - They need to save their state to toolstate.
// - They are only tested on the "checktools" builders.
//
// The local docs are tested by default, and we don't want to pay the
// cost of building mdbook, so they use `rustdoc --test` directly.
// Also, the unstable book is special because SUMMARY.md is generated,
// so it is easier to just run `rustdoc` on its files.
if self.is_ext_doc {
self.run_ext_doc(builder);
} else {
self.run_local_doc(builder);
}
}
}

impl BookTest {
/// This runs the equivalent of `mdbook test` (via the rustbook wrapper)
/// which in turn runs `rustdoc --test` on each file in the book.
fn run_ext_doc(self, builder: &Builder<'_>) {
let compiler = self.compiler;

builder.ensure(compile::Std { compiler, target: compiler.host });

// mdbook just executes a binary named "rustdoc", so we need to update
// PATH so that it points to our rustdoc.
let mut rustdoc_path = builder.rustdoc(compiler);
rustdoc_path.pop();
let old_path = env::var_os("PATH").unwrap_or_default();
let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path)))
.expect("could not add rustdoc to PATH");

let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
let path = builder.src.join(&self.path);
rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
builder.add_rust_test_threads(&mut rustbook_cmd);
builder.info(&format!("Testing rustbook {}", self.path.display()));
let _time = util::timeit(&builder);
let toolstate = if try_run(builder, &mut rustbook_cmd) {
ToolState::TestPass
} else {
ToolState::TestFail
};
builder.save_toolstate(self.name, toolstate);
}

/// This runs `rustdoc --test` on all `.md` files in the path.
fn run_local_doc(self, builder: &Builder<'_>) {
let compiler = self.compiler;

builder.ensure(compile::Std { compiler, target: compiler.host });
Expand All @@ -1294,7 +1341,6 @@ impl Step for DocTest {
// tests for all files that end in `*.md`
let mut stack = vec![builder.src.join(self.path)];
let _time = util::timeit(&builder);

let mut files = Vec::new();
while let Some(p) = stack.pop() {
if p.is_dir() {
Expand All @@ -1306,25 +1352,13 @@ impl Step for DocTest {
continue;
}

// The nostarch directory in the book is for no starch, and so isn't
// guaranteed to builder. We don't care if it doesn't build, so skip it.
if p.to_str().map_or(false, |p| p.contains("nostarch")) {
continue;
}

files.push(p);
}

files.sort();

let mut toolstate = ToolState::TestPass;
for file in files {
if !markdown_test(builder, compiler, &file) {
toolstate = ToolState::TestFail;
}
}
if self.is_ext_doc {
builder.save_toolstate(self.name, toolstate);
markdown_test(builder, compiler, &file);
}
}
}
Expand Down Expand Up @@ -1353,9 +1387,9 @@ macro_rules! test_book {
}

fn run(self, builder: &Builder<'_>) {
builder.ensure(DocTest {
builder.ensure(BookTest {
compiler: self.compiler,
path: $path,
path: PathBuf::from($path),
name: $book_name,
is_ext_doc: !$default,
});
Expand Down
2 changes: 1 addition & 1 deletion src/doc/book
Submodule book updated 1993 files
4 changes: 4 additions & 0 deletions src/doc/rustdoc/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[book]
authors = ["The Rust Project Developers"]
src = "src"
title = "The rustdoc book"
34 changes: 27 additions & 7 deletions src/tools/rustbook/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ fn main() {
.arg_from_usage(d_message)
.arg_from_usage(dir_message),
)
.subcommand(
SubCommand::with_name("test")
.about("Tests that a book's Rust code samples compile")
.arg_from_usage(dir_message),
)
.subcommand(
SubCommand::with_name("linkcheck")
.about("Run linkcheck with mdBook 3")
Expand All @@ -36,13 +41,12 @@ fn main() {
match matches.subcommand() {
("build", Some(sub_matches)) => {
if let Err(e) = build(sub_matches) {
eprintln!("Error: {}", e);

for cause in e.iter().skip(1) {
eprintln!("\tCaused By: {}", cause);
}

::std::process::exit(101);
handle_error(e);
}
}
("test", Some(sub_matches)) => {
if let Err(e) = test(sub_matches) {
handle_error(e);
}
}
("linkcheck", Some(sub_matches)) => {
Expand Down Expand Up @@ -146,6 +150,12 @@ pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
Ok(())
}

fn test(args: &ArgMatches<'_>) -> Result3<()> {
let book_dir = get_book_dir(args);
let mut book = MDBook::load(&book_dir)?;
book.test(vec![])
}

fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
if let Some(dir) = args.value_of("dir") {
// Check if path is relative from current dir, or absolute...
Expand All @@ -155,3 +165,13 @@ fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
env::current_dir().unwrap()
}
}

fn handle_error(error: mdbook::errors::Error) -> ! {
eprintln!("Error: {}", error);

for cause in error.iter().skip(1) {
eprintln!("\tCaused By: {}", cause);
}

::std::process::exit(101);
}
1 change: 1 addition & 0 deletions src/tools/tidy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ fn filter_dirs(path: &Path) -> bool {
"src/tools/rls",
"src/tools/rust-installer",
"src/tools/rustfmt",
"src/doc/book",
// Filter RLS output directories
"target/rls",
];
Expand Down