diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 95530b210afd6..d5dc9a79b5acb 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -1,18 +1,19 @@ -use clap::{crate_version}; +use clap::crate_version; use std::env; use std::path::{Path, PathBuf}; -use clap::{App, ArgMatches, SubCommand, AppSettings}; +use clap::{App, AppSettings, ArgMatches, SubCommand}; +use mdbook::errors::Result as Result3; use mdbook::MDBook; -use mdbook::errors::{Result as Result3}; +#[cfg(feature = "linkcheck")] +use failure::Error; #[cfg(feature = "linkcheck")] use mdbook::renderer::RenderContext; #[cfg(feature = "linkcheck")] use mdbook_linkcheck::{self, errors::BrokenLinks}; -use failure::Error; fn main() { let d_message = "-d, --dest-dir=[dest-dir] @@ -21,18 +22,22 @@ fn main() { 'A directory for your book{n}(Defaults to Current Directory when omitted)'"; let matches = App::new("rustbook") - .about("Build a book with mdBook") - .author("Steve Klabnik ") - .version(&*format!("v{}", crate_version!())) - .setting(AppSettings::SubcommandRequired) - .subcommand(SubCommand::with_name("build") - .about("Build the book from the markdown files") - .arg_from_usage(d_message) - .arg_from_usage(dir_message)) - .subcommand(SubCommand::with_name("linkcheck") - .about("Run linkcheck with mdBook 3") - .arg_from_usage(dir_message)) - .get_matches(); + .about("Build a book with mdBook") + .author("Steve Klabnik ") + .version(&*format!("v{}", crate_version!())) + .setting(AppSettings::SubcommandRequired) + .subcommand( + SubCommand::with_name("build") + .about("Build the book from the markdown files") + .arg_from_usage(d_message) + .arg_from_usage(dir_message), + ) + .subcommand( + SubCommand::with_name("linkcheck") + .about("Run linkcheck with mdBook 3") + .arg_from_usage(dir_message), + ) + .get_matches(); // Check which subcomamnd the user ran... match matches.subcommand() { @@ -46,23 +51,44 @@ fn main() { ::std::process::exit(101); } - }, + } ("linkcheck", Some(sub_matches)) => { - if let Err(err) = linkcheck(sub_matches) { - eprintln!("Error: {}", err); - - #[cfg(feature = "linkcheck")] - { - if let Ok(broken_links) = err.downcast::() { - for cause in broken_links.links().iter() { - eprintln!("\tCaused By: {}", cause); - } + #[cfg(feature = "linkcheck")] + { + if let Err(err) = linkcheck(sub_matches) { + eprintln!("Error: {}", err); + + // HACK: ignore timeouts + let actually_broken = err + .downcast::() + .map(|broken_links| { + broken_links + .links() + .iter() + .inspect(|cause| eprintln!("\tCaused By: {}", cause)) + .fold(false, |already_broken, cause| { + already_broken || !format!("{}", cause).contains("timed out") + }) + }) + .unwrap_or(false); + + if actually_broken { + std::process::exit(101); + } else { + std::process::exit(0); } } + } - ::std::process::exit(101); + #[cfg(not(feature = "linkcheck"))] + { + // This avoids the `unused_binding` lint. + println!( + "mdbook-linkcheck is disabled, but arguments were passed: {:?}", + sub_matches + ); } - }, + } (_, _) => unreachable!(), }; } @@ -77,12 +103,6 @@ pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> { mdbook_linkcheck::check_links(&render_ctx) } -#[cfg(not(feature = "linkcheck"))] -pub fn linkcheck(_args: &ArgMatches<'_>) -> Result<(), Error> { - println!("mdbook-linkcheck is disabled."); - Ok(()) -} - // Build command implementation pub fn build(args: &ArgMatches<'_>) -> Result3<()> { let book_dir = get_book_dir(args);