1 #![deny(rust_2018_idioms)]
3 use clap::{crate_version};
6 use std::path::{Path, PathBuf};
8 use clap::{App, ArgMatches, SubCommand, AppSettings};
10 use mdbook_1::{MDBook as MDBook1};
11 use mdbook_1::errors::{Result as Result1};
14 use mdbook::errors::{Result as Result3};
16 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
17 use mdbook::renderer::RenderContext;
19 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
20 use mdbook_linkcheck::{self, errors::BrokenLinks};
23 #[cfg(not(all(target_arch = "x86_64", target_os = "linux")))]
27 let d_message = "-d, --dest-dir=[dest-dir]
28 'The output directory for your book{n}(Defaults to ./book when omitted)'";
29 let dir_message = "[dir]
30 'A directory for your book{n}(Defaults to Current Directory when omitted)'";
31 let vers_message = "-m, --mdbook-vers=[md-version]
32 'The version of mdbook to use for your book{n}(Defaults to 1 when omitted)'";
34 let matches = App::new("rustbook")
35 .about("Build a book with mdBook")
36 .author("Steve Klabnik <steve@steveklabnik.com>")
37 .version(&*format!("v{}", crate_version!()))
38 .setting(AppSettings::SubcommandRequired)
39 .subcommand(SubCommand::with_name("build")
40 .about("Build the book from the markdown files")
41 .arg_from_usage(d_message)
42 .arg_from_usage(dir_message)
43 .arg_from_usage(vers_message))
44 .subcommand(SubCommand::with_name("linkcheck")
45 .about("Run linkcheck with mdBook 3")
46 .arg_from_usage(dir_message))
49 // Check which subcomamnd the user ran...
50 match matches.subcommand() {
51 ("build", Some(sub_matches)) => {
52 match sub_matches.value_of("mdbook-vers") {
54 if let Err(e) = build_1(sub_matches) {
55 eprintln!("Error: {}", e);
57 for cause in e.iter().skip(1) {
58 eprintln!("\tCaused By: {}", cause);
61 ::std::process::exit(101);
64 Some("2") | Some("3") => {
65 if let Err(e) = build(sub_matches) {
66 eprintln!("Error: {}", e);
68 for cause in e.iter().skip(1) {
69 eprintln!("\tCaused By: {}", cause);
72 ::std::process::exit(101);
76 panic!("Invalid mdBook version! Select '1' or '2' or '3'");
80 ("linkcheck", Some(sub_matches)) => {
81 if let Err(err) = linkcheck(sub_matches) {
82 eprintln!("Error: {}", err);
84 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
86 if let Ok(broken_links) = err.downcast::<BrokenLinks>() {
87 for cause in broken_links.links().iter() {
88 eprintln!("\tCaused By: {}", cause);
93 ::std::process::exit(101);
96 (_, _) => unreachable!(),
100 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
101 pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> {
102 let book_dir = get_book_dir(args);
103 let book = MDBook::load(&book_dir).unwrap();
104 let cfg = book.config;
105 let render_ctx = RenderContext::new(&book_dir, book.book, cfg, &book_dir);
107 mdbook_linkcheck::check_links(&render_ctx)
110 #[cfg(not(all(target_arch = "x86_64", target_os = "linux")))]
111 pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> {
112 bail!("mdbook-linkcheck only works on x86_64 linux targets.");
115 // Build command implementation
116 pub fn build_1(args: &ArgMatches<'_>) -> Result1<()> {
117 let book_dir = get_book_dir(args);
118 let mut book = MDBook1::load(&book_dir)?;
120 // Set this to allow us to catch bugs in advance.
121 book.config.build.create_missing = false;
123 if let Some(dest_dir) = args.value_of("dest-dir") {
124 book.config.build.build_dir = PathBuf::from(dest_dir);
132 // Build command implementation
133 pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
134 let book_dir = get_book_dir(args);
135 let mut book = MDBook::load(&book_dir)?;
137 // Set this to allow us to catch bugs in advance.
138 book.config.build.create_missing = false;
140 if let Some(dest_dir) = args.value_of("dest-dir") {
141 book.config.build.build_dir = PathBuf::from(dest_dir);
149 fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
150 if let Some(dir) = args.value_of("dir") {
151 // Check if path is relative from current dir, or absolute...
152 let p = Path::new(dir);
154 env::current_dir().unwrap().join(dir)
159 env::current_dir().unwrap()