Skip to content

Commit

Permalink
Rollup merge of rust-lang#68791 - mark-i-m:proper-linkcheck, r=ehuss,…
Browse files Browse the repository at this point in the history
…JohnTitor

implement proper linkchecker hardening

r? @JohnTitor

This implements proper linkcheck filtering... we might need to fiddle with a bit to adjust what is or isn't filtered, but this seems to work reasonable locally.
  • Loading branch information
Dylan-DPC authored Feb 6, 2020
2 parents 2d8f638 + 5e086c8 commit 4ce157d
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3067,6 +3067,7 @@ name = "rustbook"
version = "0.1.0"
dependencies = [
"clap",
"codespan",
"codespan-reporting",
"failure",
"mdbook",
Expand Down
2 changes: 1 addition & 1 deletion src/doc/rustc-guide
3 changes: 2 additions & 1 deletion src/tools/rustbook/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }


Expand Down
72 changes: 59 additions & 13 deletions src/tools/rustbook/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)'";
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -73,14 +78,55 @@ fn main() {
}

#[cfg(feature = "linkcheck")]
pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> {
pub fn linkcheck(
args: &ArgMatches<'_>,
) -> Result<(Vec<codespan_reporting::diagnostic::Diagnostic>, 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
Expand Down

0 comments on commit 4ce157d

Please sign in to comment.