]> git.proxmox.com Git - rustc.git/blob - src/tools/rustbook/src/main.rs
New upstream version 1.39.0+dfsg1
[rustc.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::{App, AppSettings, ArgMatches, SubCommand};
7
8 use mdbook::errors::Result as Result3;
9 use mdbook::MDBook;
10
11 #[cfg(feature = "linkcheck")]
12 use failure::Error;
13 #[cfg(feature = "linkcheck")]
14 use mdbook::renderer::RenderContext;
15 #[cfg(feature = "linkcheck")]
16 use mdbook_linkcheck::{self, errors::BrokenLinks};
17
18 fn main() {
19 let d_message = "-d, --dest-dir=[dest-dir]
20 'The output directory for your book{n}(Defaults to ./book when omitted)'";
21 let dir_message = "[dir]
22 'A directory for your book{n}(Defaults to Current Directory when omitted)'";
23
24 let matches = App::new("rustbook")
25 .about("Build a book with mdBook")
26 .author("Steve Klabnik <steve@steveklabnik.com>")
27 .version(&*format!("v{}", crate_version!()))
28 .setting(AppSettings::SubcommandRequired)
29 .subcommand(
30 SubCommand::with_name("build")
31 .about("Build the book from the markdown files")
32 .arg_from_usage(d_message)
33 .arg_from_usage(dir_message),
34 )
35 .subcommand(
36 SubCommand::with_name("linkcheck")
37 .about("Run linkcheck with mdBook 3")
38 .arg_from_usage(dir_message),
39 )
40 .get_matches();
41
42 // Check which subcomamnd the user ran...
43 match matches.subcommand() {
44 ("build", Some(sub_matches)) => {
45 if let Err(e) = build(sub_matches) {
46 eprintln!("Error: {}", e);
47
48 for cause in e.iter().skip(1) {
49 eprintln!("\tCaused By: {}", cause);
50 }
51
52 ::std::process::exit(101);
53 }
54 }
55 ("linkcheck", Some(sub_matches)) => {
56 #[cfg(feature = "linkcheck")]
57 {
58 if let Err(err) = linkcheck(sub_matches) {
59 eprintln!("Error: {}", err);
60
61 // HACK: ignore timeouts
62 let actually_broken = err
63 .downcast::<BrokenLinks>()
64 .map(|broken_links| {
65 broken_links
66 .links()
67 .iter()
68 .inspect(|cause| eprintln!("\tCaused By: {}", cause))
69 .fold(false, |already_broken, cause| {
70 already_broken || !format!("{}", cause).contains("timed out")
71 })
72 })
73 .unwrap_or(false);
74
75 if actually_broken {
76 std::process::exit(101);
77 } else {
78 std::process::exit(0);
79 }
80 }
81 }
82
83 #[cfg(not(feature = "linkcheck"))]
84 {
85 // This avoids the `unused_binding` lint.
86 println!(
87 "mdbook-linkcheck is disabled, but arguments were passed: {:?}",
88 sub_matches
89 );
90 }
91 }
92 (_, _) => unreachable!(),
93 };
94 }
95
96 #[cfg(feature = "linkcheck")]
97 pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> {
98 let book_dir = get_book_dir(args);
99 let book = MDBook::load(&book_dir).unwrap();
100 let cfg = book.config;
101 let render_ctx = RenderContext::new(&book_dir, book.book, cfg, &book_dir);
102
103 mdbook_linkcheck::check_links(&render_ctx)
104 }
105
106 // Build command implementation
107 pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
108 let book_dir = get_book_dir(args);
109 let mut book = MDBook::load(&book_dir)?;
110
111 // Set this to allow us to catch bugs in advance.
112 book.config.build.create_missing = false;
113
114 if let Some(dest_dir) = args.value_of("dest-dir") {
115 book.config.build.build_dir = PathBuf::from(dest_dir);
116 }
117
118 book.build()?;
119
120 Ok(())
121 }
122
123 fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
124 if let Some(dir) = args.value_of("dir") {
125 // Check if path is relative from current dir, or absolute...
126 let p = Path::new(dir);
127 if p.is_relative() {
128 env::current_dir().unwrap().join(dir)
129 } else {
130 p.to_path_buf()
131 }
132 } else {
133 env::current_dir().unwrap()
134 }
135 }