Skip to content

Commit a5d3cb9

Browse files
committed
Exit if a preprocessor command is not found
1 parent d24c0ca commit a5d3cb9

File tree

8 files changed

+64
-17
lines changed

8 files changed

+64
-17
lines changed

examples/nop-preprocessor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! {
5757
let renderer = sub_args
5858
.get_one::<String>("renderer")
5959
.expect("Required argument");
60-
let supported = pre.supports_renderer(renderer);
60+
let supported = pre.supports_renderer(renderer, false);
6161

6262
// Signal whether the renderer is supported by exiting with 1 or 0.
6363
if supported {
@@ -99,7 +99,7 @@ mod nop_lib {
9999
Ok(book)
100100
}
101101

102-
fn supports_renderer(&self, renderer: &str) -> bool {
102+
fn supports_renderer(&self, renderer: &str, _error_on_missing_preprocessor: bool) -> bool {
103103
renderer != "not-supported"
104104
}
105105
}

src/book/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,8 @@ fn preprocessor_should_run(
605605
) -> bool {
606606
// default preprocessors should be run by default (if supported)
607607
if cfg.build.use_default_preprocessors && is_default_preprocessor(preprocessor) {
608-
return preprocessor.supports_renderer(renderer.name());
608+
return preprocessor
609+
.supports_renderer(renderer.name(), cfg.build.error_on_missing_preprocessor);
609610
}
610611

611612
let key = format!("preprocessor.{}.renderers", preprocessor.name());
@@ -618,7 +619,7 @@ fn preprocessor_should_run(
618619
.any(|name| name == renderer_name);
619620
}
620621

621-
preprocessor.supports_renderer(renderer_name)
622+
preprocessor.supports_renderer(renderer_name, cfg.build.error_on_missing_preprocessor)
622623
}
623624

624625
#[cfg(test)]
@@ -876,7 +877,7 @@ mod tests {
876877
unimplemented!()
877878
}
878879

879-
fn supports_renderer(&self, _renderer: &str) -> bool {
880+
fn supports_renderer(&self, _renderer: &str, _error_on_missing_preprocessor: bool) -> bool {
880881
self.0
881882
}
882883
}

src/cmd/init.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::get_book_dir;
22
use clap::{arg, ArgMatches, Command as ClapCommand};
3-
use mdbook::config;
43
use mdbook::errors::Result;
5-
use mdbook::MDBook;
4+
use mdbook::{Config, MDBook};
65
use std::io;
76
use std::io::Write;
87
use std::process::Command;
@@ -31,7 +30,12 @@ pub fn make_subcommand() -> ClapCommand {
3130
pub fn execute(args: &ArgMatches) -> Result<()> {
3231
let book_dir = get_book_dir(args);
3332
let mut builder = MDBook::init(&book_dir);
34-
let mut config = config::Config::default();
33+
34+
let mut config = Config::default();
35+
// We want new books to raise an error if a preprocessor is missing, but we want old books to simply emit a warning.
36+
// This is why BuildConfig::default() sets it to false and why we force it to true here
37+
config.build.error_on_missing_preprocessor = true;
38+
3539
// If flag `--theme` is present, copy theme to src
3640
if args.get_flag("theme") {
3741
let theme_dir = book_dir.join("theme");

src/config.rs

+11
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,12 @@ pub struct BuildConfig {
496496
pub use_default_preprocessors: bool,
497497
/// Extra directories to trigger rebuild when watching/serving
498498
pub extra_watch_dirs: Vec<PathBuf>,
499+
/// Should missing a preprocessor be considered an error?
500+
/// By default, the application raises a warning instead and continue generation,
501+
/// even if the book may be generated incorrectly.
502+
/// Set this flag to ̀false` to consider this an error, and exits the application
503+
/// if a preprocessor is missing.
504+
pub error_on_missing_preprocessor: bool,
499505
}
500506

501507
impl Default for BuildConfig {
@@ -505,6 +511,7 @@ impl Default for BuildConfig {
505511
create_missing: true,
506512
use_default_preprocessors: true,
507513
extra_watch_dirs: Vec::new(),
514+
error_on_missing_preprocessor: false,
508515
}
509516
}
510517
}
@@ -831,6 +838,7 @@ mod tests {
831838
build-dir = "outputs"
832839
create-missing = false
833840
use-default-preprocessors = true
841+
error-on-missing-preprocessor = false
834842
835843
[output.html]
836844
theme = "./themedir"
@@ -872,6 +880,7 @@ mod tests {
872880
create_missing: false,
873881
use_default_preprocessors: true,
874882
extra_watch_dirs: Vec::new(),
883+
error_on_missing_preprocessor: false,
875884
};
876885
let rust_should_be = RustConfig { edition: None };
877886
let playground_should_be = Playground {
@@ -1083,6 +1092,8 @@ mod tests {
10831092
create_missing: true,
10841093
use_default_preprocessors: true,
10851094
extra_watch_dirs: Vec::new(),
1095+
error_on_missing_preprocessor: false, // This flag is missing from "src" string,
1096+
// so it should be false to ensure backward compatibility
10861097
};
10871098

10881099
let html_should_be = HtmlConfig {

src/preprocess/cmd.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::{Preprocessor, PreprocessorContext};
22
use crate::book::Book;
33
use crate::errors::*;
4-
use log::{debug, trace, warn};
4+
use log::{debug, error, trace, warn};
55
use shlex::Shlex;
66
use std::io::{self, Read, Write};
77
use std::process::{Child, Command, Stdio};
@@ -134,7 +134,7 @@ impl Preprocessor for CmdPreprocessor {
134134
})
135135
}
136136

137-
fn supports_renderer(&self, renderer: &str) -> bool {
137+
fn supports_renderer(&self, renderer: &str, error_on_missing_preprocessor: bool) -> bool {
138138
debug!(
139139
"Checking if the \"{}\" preprocessor supports \"{}\"",
140140
self.name(),
@@ -164,11 +164,17 @@ impl Preprocessor for CmdPreprocessor {
164164

165165
if let Err(ref e) = outcome {
166166
if e.kind() == io::ErrorKind::NotFound {
167-
warn!(
168-
"The command wasn't found, is the \"{}\" preprocessor installed?",
169-
self.name
167+
let message = format!(
168+
"The command \"{}\" wasn't found, is the \"{}\" preprocessor installed?",
169+
self.cmd, self.name
170170
);
171-
warn!("\tCommand: {}", self.cmd);
171+
172+
if error_on_missing_preprocessor {
173+
error!("{message}");
174+
std::process::exit(1);
175+
} else {
176+
warn!("{message}");
177+
}
172178
}
173179
}
174180

src/preprocess/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ pub trait Preprocessor {
6363
/// particular renderer.
6464
///
6565
/// By default, always returns `true`.
66-
fn supports_renderer(&self, _renderer: &str) -> bool {
66+
///
67+
/// Set `error_on_missing_preprocessor` to `true` to exit the application if a preprocessor is missing,
68+
/// or to `false` to simply raise a warning and continue the generation.
69+
fn supports_renderer(&self, _renderer: &str, _error_on_missing_preprocessor: bool) -> bool {
6770
true
6871
}
6972
}

tests/testsuite/init.rs

+22
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ authors = []
3030
language = "en"
3131
src = "src"
3232
33+
[build]
34+
build-dir = "book"
35+
create-missing = true
36+
error-on-missing-preprocessor = true
37+
extra-watch-dirs = []
38+
use-default-preprocessors = true
39+
3340
"#]],
3441
)
3542
.check_file(
@@ -96,6 +103,13 @@ authors = []
96103
language = "en"
97104
src = "src"
98105
106+
[build]
107+
build-dir = "book"
108+
create-missing = true
109+
error-on-missing-preprocessor = true
110+
extra-watch-dirs = []
111+
use-default-preprocessors = true
112+
99113
"#]],
100114
);
101115
assert!(!test.dir.join(".gitignore").exists());
@@ -130,6 +144,13 @@ language = "en"
130144
src = "src"
131145
title = "Example title"
132146
147+
[build]
148+
build-dir = "book"
149+
create-missing = true
150+
error-on-missing-preprocessor = true
151+
extra-watch-dirs = []
152+
use-default-preprocessors = true
153+
133154
"#]],
134155
);
135156
assert!(!test.dir.join(".gitignore").exists());
@@ -184,6 +205,7 @@ src = "in"
184205
[build]
185206
build-dir = "out"
186207
create-missing = true
208+
error-on-missing-preprocessor = false
187209
extra-watch-dirs = []
188210
use-default-preprocessors = true
189211

tests/testsuite/preprocessor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ fn example() -> CmdPreprocessor {
8080
fn example_supports_whatever() {
8181
let cmd = example();
8282

83-
let got = cmd.supports_renderer("whatever");
83+
let got = cmd.supports_renderer("whatever", false);
8484

8585
assert_eq!(got, true);
8686
}
@@ -89,7 +89,7 @@ fn example_supports_whatever() {
8989
fn example_doesnt_support_not_supported() {
9090
let cmd = example();
9191

92-
let got = cmd.supports_renderer("not-supported");
92+
let got = cmd.supports_renderer("not-supported", false);
9393

9494
assert_eq!(got, false);
9595
}

0 commit comments

Comments
 (0)