diff --git a/Cargo.lock b/Cargo.lock index ec976b6901646..bbfda0fa2c846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3067,6 +3067,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap", + "codespan", "codespan-reporting", "failure", "mdbook", diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide index 92baf7293dd2d..5bd60bc51efae 160000 --- a/src/doc/rustc-guide +++ b/src/doc/rustc-guide @@ -1 +1 @@ -Subproject commit 92baf7293dd2d418d2ac4b141b0faa822075d9f7 +Subproject commit 5bd60bc51efaec04e69e2e18b59678e2af066433 diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 327de29037cc3..e6e758dccdf0a 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -6,13 +6,14 @@ license = "MIT OR Apache-2.0" edition = "2018" [features] -linkcheck = ["mdbook-linkcheck", "codespan-reporting"] +linkcheck = ["mdbook-linkcheck", "codespan-reporting", "codespan"] [dependencies] clap = "2.25.0" failure = "0.1" mdbook-linkcheck = { version = "0.5.0", optional = true } # Keep in sync with mdbook-linkcheck. +codespan = { version = "0.5", optional = true } codespan-reporting = { version = "0.5", optional = true } diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index fc28315669376..023f5aa1e284b 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -8,11 +8,6 @@ use clap::{App, AppSettings, ArgMatches, SubCommand}; use mdbook::errors::Result as Result3; use mdbook::MDBook; -#[cfg(feature = "linkcheck")] -use failure::Error; -#[cfg(feature = "linkcheck")] -use mdbook::renderer::RenderContext; - fn main() { let d_message = "-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'"; @@ -53,8 +48,18 @@ fn main() { ("linkcheck", Some(sub_matches)) => { #[cfg(feature = "linkcheck")] { - if let Err(err) = linkcheck(sub_matches) { - eprintln!("Error: {}", err); + let (diags, files) = linkcheck(sub_matches).expect("Error while linkchecking."); + if !diags.is_empty() { + let color = codespan_reporting::term::termcolor::ColorChoice::Auto; + let mut writer = + codespan_reporting::term::termcolor::StandardStream::stderr(color); + let cfg = codespan_reporting::term::Config::default(); + + for diag in diags { + codespan_reporting::term::emit(&mut writer, &cfg, &files, &diag) + .expect("Unable to emit linkcheck error."); + } + std::process::exit(101); } } @@ -73,14 +78,55 @@ fn main() { } #[cfg(feature = "linkcheck")] -pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> { +pub fn linkcheck( + args: &ArgMatches<'_>, +) -> Result<(Vec, codespan::Files), failure::Error> { + use mdbook_linkcheck::Reason; + let book_dir = get_book_dir(args); + let src_dir = book_dir.join("src"); let book = MDBook::load(&book_dir).unwrap(); - let cfg = book.config; - let render_ctx = RenderContext::new(&book_dir, book.book, cfg, &book_dir); - let cache_file = render_ctx.destination.join("cache.json"); - let color = codespan_reporting::term::termcolor::ColorChoice::Auto; - mdbook_linkcheck::run(&cache_file, color, &render_ctx) + let linkck_cfg = mdbook_linkcheck::get_config(&book.config)?; + let mut files = codespan::Files::new(); + let target_files = mdbook_linkcheck::load_files_into_memory(&book.book, &mut files); + let cache = mdbook_linkcheck::Cache::default(); + + let (links, incomplete) = mdbook_linkcheck::extract_links(target_files, &files); + + let outcome = + mdbook_linkcheck::validate(&links, &linkck_cfg, &src_dir, &cache, &files, incomplete)?; + + let mut is_real_error = false; + + for link in outcome.invalid_links.iter() { + match &link.reason { + Reason::FileNotFound | Reason::TraversesParentDirectories => { + is_real_error = true; + } + Reason::UnsuccessfulServerResponse(status) => { + if status.is_client_error() { + is_real_error = true; + } else { + eprintln!("Unsuccessful server response for link `{}`", link.link.uri); + } + } + Reason::Client(err) => { + if err.is_timeout() { + eprintln!("Timeout for link `{}`", link.link.uri); + } else if err.is_server_error() { + eprintln!("Server error for link `{}`", link.link.uri); + } else { + is_real_error = true; + } + } + } + } + + if is_real_error { + Ok((outcome.generate_diagnostics(&files, linkck_cfg.warning_policy), files)) + } else { + Ok((vec![], files)) + } } // Build command implementation