]> git.lizzy.rs Git - rust.git/blob - src/tools/rustbook/src/main.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / src / tools / rustbook / src / main.rs
1 use clap::crate_version;
2
3 use std::env;
4 use std::path::{Path, PathBuf};
5
6 use clap::{arg, ArgMatches, Command};
7
8 use mdbook::errors::Result as Result3;
9 use mdbook::MDBook;
10
11 fn main() {
12     let crate_version = concat!("v", crate_version!());
13     env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
14     let d_arg = arg!(-d --"dest-dir" <DEST_DIR>
15 "The output directory for your book\n(Defaults to ./book when omitted)")
16     .required(false)
17     .value_parser(clap::value_parser!(PathBuf));
18
19     let dir_arg = arg!([dir] "Root directory for the book\n\
20                               (Defaults to the current directory when omitted)")
21     .value_parser(clap::value_parser!(PathBuf));
22
23     let matches = Command::new("rustbook")
24         .about("Build a book with mdBook")
25         .author("Steve Klabnik <steve@steveklabnik.com>")
26         .version(crate_version)
27         .subcommand_required(true)
28         .arg_required_else_help(true)
29         .subcommand(
30             Command::new("build")
31                 .about("Build the book from the markdown files")
32                 .arg(d_arg)
33                 .arg(&dir_arg),
34         )
35         .subcommand(
36             Command::new("test")
37                 .about("Tests that a book's Rust code samples compile")
38                 .arg(dir_arg),
39         )
40         .get_matches();
41
42     // Check which subcomamnd the user ran...
43     match matches.subcommand() {
44         Some(("build", sub_matches)) => {
45             if let Err(e) = build(sub_matches) {
46                 handle_error(e);
47             }
48         }
49         Some(("test", sub_matches)) => {
50             if let Err(e) = test(sub_matches) {
51                 handle_error(e);
52             }
53         }
54         _ => unreachable!(),
55     };
56 }
57
58 // Build command implementation
59 pub fn build(args: &ArgMatches) -> Result3<()> {
60     let book_dir = get_book_dir(args);
61     let mut book = load_book(&book_dir)?;
62
63     // Set this to allow us to catch bugs in advance.
64     book.config.build.create_missing = false;
65
66     if let Some(dest_dir) = args.get_one::<PathBuf>("dest-dir") {
67         book.config.build.build_dir = dest_dir.into();
68     }
69
70     book.build()?;
71
72     Ok(())
73 }
74
75 fn test(args: &ArgMatches) -> Result3<()> {
76     let book_dir = get_book_dir(args);
77     let mut book = load_book(&book_dir)?;
78     book.test(vec![])
79 }
80
81 fn get_book_dir(args: &ArgMatches) -> PathBuf {
82     if let Some(p) = args.get_one::<PathBuf>("dir") {
83         // Check if path is relative from current dir, or absolute...
84         if p.is_relative() { env::current_dir().unwrap().join(p) } else { p.to_path_buf() }
85     } else {
86         env::current_dir().unwrap()
87     }
88 }
89
90 fn load_book(book_dir: &Path) -> Result3<MDBook> {
91     let mut book = MDBook::load(book_dir)?;
92     book.config.set("output.html.input-404", "").unwrap();
93     Ok(book)
94 }
95
96 fn handle_error(error: mdbook::errors::Error) -> ! {
97     eprintln!("Error: {}", error);
98
99     for cause in error.chain().skip(1) {
100         eprintln!("\tCaused By: {}", cause);
101     }
102
103     ::std::process::exit(101);
104 }