Switch from log to tracing

This switches to using the tracing crate instead of log. Tracing
provides a lot of nice features which we can take advantage of moving
forward.

This also adjusts the output fairly significantly. This includes:

- Switched the environment variable from RUST_LOG to MDBOOK_LOG.
- Dropped the timestamp. I experimented with various different time
  displays, but ultimately decided to omit it for now. I don't think
  I've ever found it to be useful, and it takes up a very significant
  amount of space. It could potentially be useful for basic profiling,
  but I think there are other, better mechanisms for that. We could
  consider leveraging tracing itself for doing some basic profiling
  (like using something like tracing-chrome).
- Dropped the target unless MDBOOK_LOG is set. The target tends to be
  pretty noisy, and doesn't really convey much information unless you
  are debugging or otherwise trying to adjust the log output.
- Added color.
- Slightly reworked the way the error cause trace is displayed.
- Slightly changed the way html5ever filtering is done, as well as add
  handlebars to the list since they both are very noisy. You can
  override this now by explicitly listing them as targets.

I still expect that mdbook will eventually change how it displays things
to the console, possibly switching away from tracing and printing things
itself. However, that is a larger project for the future.
This commit is contained in:
Eric Huss 2025-09-12 06:13:45 -07:00
parent 787882069e
commit 3e673ce424
46 changed files with 320 additions and 292 deletions

166
Cargo.lock generated
View file

@ -559,29 +559,6 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "env_filter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@ -1132,30 +1109,6 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.77" version = "0.3.77"
@ -1186,6 +1139,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.174" version = "0.2.174"
@ -1291,6 +1250,15 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.8.4" version = "0.8.4"
@ -1306,11 +1274,9 @@ dependencies = [
"chrono", "chrono",
"clap", "clap",
"clap_complete", "clap_complete",
"env_logger",
"futures-util", "futures-util",
"glob", "glob",
"ignore", "ignore",
"log",
"mdbook-core", "mdbook-core",
"mdbook-driver", "mdbook-driver",
"mdbook-html", "mdbook-html",
@ -1331,6 +1297,8 @@ dependencies = [
"tokio", "tokio",
"toml", "toml",
"tower-http", "tower-http",
"tracing",
"tracing-subscriber",
"walkdir", "walkdir",
] ]
@ -1339,12 +1307,12 @@ name = "mdbook-core"
version = "0.5.0-alpha.1" version = "0.5.0-alpha.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"log",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",
"tempfile", "tempfile",
"toml", "toml",
"tracing",
] ]
[[package]] [[package]]
@ -1353,7 +1321,6 @@ version = "0.5.0-alpha.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap",
"log",
"mdbook-core", "mdbook-core",
"mdbook-html", "mdbook-html",
"mdbook-markdown", "mdbook-markdown",
@ -1367,6 +1334,7 @@ dependencies = [
"tempfile", "tempfile",
"toml", "toml",
"topological-sort", "topological-sort",
"tracing",
] ]
[[package]] [[package]]
@ -1379,7 +1347,6 @@ dependencies = [
"font-awesome-as-a-crate", "font-awesome-as-a-crate",
"handlebars", "handlebars",
"hex", "hex",
"log",
"mdbook-core", "mdbook-core",
"mdbook-markdown", "mdbook-markdown",
"mdbook-renderer", "mdbook-renderer",
@ -1391,15 +1358,16 @@ dependencies = [
"sha2", "sha2",
"tempfile", "tempfile",
"toml", "toml",
"tracing",
] ]
[[package]] [[package]]
name = "mdbook-markdown" name = "mdbook-markdown"
version = "0.5.0-alpha.1" version = "0.5.0-alpha.1"
dependencies = [ dependencies = [
"log",
"pulldown-cmark", "pulldown-cmark",
"regex", "regex",
"tracing",
] ]
[[package]] [[package]]
@ -1437,11 +1405,11 @@ name = "mdbook-summary"
version = "0.5.0-alpha.1" version = "0.5.0-alpha.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"log",
"mdbook-core", "mdbook-core",
"memchr", "memchr",
"pulldown-cmark", "pulldown-cmark",
"serde", "serde",
"tracing",
] ]
[[package]] [[package]]
@ -1544,6 +1512,15 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
[[package]]
name = "nu-ansi-term"
version = "0.50.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
dependencies = [
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "num-modular" name = "num-modular"
version = "0.6.1" version = "0.6.1"
@ -1781,21 +1758,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]] [[package]]
name = "potential_utf" name = "potential_utf"
version = "0.1.2" version = "0.1.2"
@ -2126,6 +2088,15 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
@ -2333,6 +2304,15 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "thread_local"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "tinystr" name = "tinystr"
version = "0.8.1" version = "0.8.1"
@ -2504,9 +2484,21 @@ checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [ dependencies = [
"log", "log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes",
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-attributes"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.34" version = "0.1.34"
@ -2514,6 +2506,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
] ]
[[package]] [[package]]
@ -2598,6 +2620,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.5" version = "0.9.5"

View file

@ -32,7 +32,6 @@ chrono = { version = "0.4.41", default-features = false, features = ["clock"] }
clap = { version = "4.5.41", features = ["cargo", "wrap_help"] } clap = { version = "4.5.41", features = ["cargo", "wrap_help"] }
clap_complete = "4.5.55" clap_complete = "4.5.55"
elasticlunr-rs = "3.0.2" elasticlunr-rs = "3.0.2"
env_logger = "0.11.8"
font-awesome-as-a-crate = "0.3.0" font-awesome-as-a-crate = "0.3.0"
futures-util = "0.3.31" futures-util = "0.3.31"
glob = "0.3.3" glob = "0.3.3"
@ -40,7 +39,6 @@ handlebars = "6.3.2"
hex = "0.4.3" hex = "0.4.3"
indexmap = "2.10.0" indexmap = "2.10.0"
ignore = "0.4.23" ignore = "0.4.23"
log = "0.4.27"
mdbook-core = { path = "crates/mdbook-core" } mdbook-core = { path = "crates/mdbook-core" }
mdbook-driver = { path = "crates/mdbook-driver" } mdbook-driver = { path = "crates/mdbook-driver" }
mdbook-html = { path = "crates/mdbook-html" } mdbook-html = { path = "crates/mdbook-html" }
@ -68,6 +66,8 @@ tokio = "1.46.1"
toml = "0.9.2" toml = "0.9.2"
topological-sort = "0.2.2" topological-sort = "0.2.2"
tower-http = "0.6.6" tower-http = "0.6.6"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
walkdir = "2.5.0" walkdir = "2.5.0"
[package] [package]
@ -93,8 +93,6 @@ anyhow.workspace = true
chrono.workspace = true chrono.workspace = true
clap.workspace = true clap.workspace = true
clap_complete.workspace = true clap_complete.workspace = true
env_logger.workspace = true
log.workspace = true
mdbook-core.workspace = true mdbook-core.workspace = true
mdbook-driver.workspace = true mdbook-driver.workspace = true
mdbook-html.workspace = true mdbook-html.workspace = true
@ -104,6 +102,8 @@ mdbook-renderer.workspace = true
mdbook-summary.workspace = true mdbook-summary.workspace = true
opener.workspace = true opener.workspace = true
toml.workspace = true toml.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
# Watch feature # Watch feature
ignore = { workspace = true, optional = true } ignore = { workspace = true, optional = true }

View file

@ -9,11 +9,11 @@ rust-version.workspace = true
[dependencies] [dependencies]
anyhow.workspace = true anyhow.workspace = true
log.workspace = true
regex.workspace = true regex.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
toml.workspace = true toml.workspace = true
tracing.workspace = true
[dev-dependencies] [dev-dependencies]
tempfile.workspace = true tempfile.workspace = true

View file

@ -46,7 +46,6 @@
use crate::utils::TomlExt; use crate::utils::TomlExt;
use crate::utils::log_backtrace; use crate::utils::log_backtrace;
use anyhow::{Context, Error, Result, bail}; use anyhow::{Context, Error, Result, bail};
use log::{debug, trace};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::env; use std::env;
@ -56,6 +55,7 @@ use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use toml::Value; use toml::Value;
use toml::value::Table; use toml::value::Table;
use tracing::{debug, trace};
/// The overall configuration object for MDBook, essentially an in-memory /// The overall configuration object for MDBook, essentially an in-memory
/// representation of `book.toml`. /// representation of `book.toml`.
@ -162,6 +162,10 @@ impl Config {
env::vars().filter_map(|(key, value)| parse_env(&key).map(|index| (index, value))); env::vars().filter_map(|(key, value)| parse_env(&key).map(|index| (index, value)));
for (key, value) in overrides { for (key, value) in overrides {
if key == "log" {
// MDBOOK_LOG is used to control logging.
continue;
}
trace!("{} => {}", key, value); trace!("{} => {}", key, value);
let parsed_value = serde_json::from_str(&value) let parsed_value = serde_json::from_str(&value)
.unwrap_or_else(|_| serde_json::Value::String(value.to_string())); .unwrap_or_else(|_| serde_json::Value::String(value.to_string()));

View file

@ -1,10 +1,10 @@
//! Filesystem utilities and helpers. //! Filesystem utilities and helpers.
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::{debug, trace};
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::Write; use std::io::Write;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use tracing::{debug, trace};
/// Naively replaces any path separator with a forward-slash '/' /// Naively replaces any path separator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String { pub fn normalize_path(path: &str) -> String {

View file

@ -1,11 +1,12 @@
//! Various helpers and utilities. //! Various helpers and utilities.
use anyhow::Error; use anyhow::Error;
use log::error;
use regex::Regex; use regex::Regex;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Write;
use std::sync::LazyLock; use std::sync::LazyLock;
use tracing::error;
pub mod fs; pub mod fs;
mod string; mod string;
@ -79,11 +80,13 @@ pub fn unique_id_from_content(content: &str, id_counter: &mut HashMap<String, us
/// Prints a "backtrace" of some `Error`. /// Prints a "backtrace" of some `Error`.
pub fn log_backtrace(e: &Error) { pub fn log_backtrace(e: &Error) {
error!("Error: {}", e); let mut message = format!("{e}");
for cause in e.chain().skip(1) { for cause in e.chain().skip(1) {
error!("\tCaused By: {}", cause); write!(message, "\n\tCaused by: {cause}").unwrap();
} }
error!("{message}");
} }
/// Escape `<` and `>` for HTML. /// Escape `<` and `>` for HTML.

View file

@ -10,7 +10,6 @@ rust-version.workspace = true
[dependencies] [dependencies]
anyhow.workspace = true anyhow.workspace = true
indexmap.workspace = true indexmap.workspace = true
log.workspace = true
mdbook-core.workspace = true mdbook-core.workspace = true
mdbook-html.workspace = true mdbook-html.workspace = true
mdbook-markdown.workspace = true mdbook-markdown.workspace = true
@ -24,6 +23,7 @@ shlex.workspace = true
tempfile.workspace = true tempfile.workspace = true
toml.workspace = true toml.workspace = true
topological-sort.workspace = true topological-sort.workspace = true
tracing.workspace = true
[lints] [lints]
workspace = true workspace = true

View file

@ -1,10 +1,10 @@
use anyhow::{Context, Result, ensure}; use anyhow::{Context, Result, ensure};
use log::{debug, trace, warn};
use mdbook_core::book::Book; use mdbook_core::book::Book;
use mdbook_preprocessor::{Preprocessor, PreprocessorContext}; use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::{Child, Stdio}; use std::process::{Child, Stdio};
use tracing::{debug, trace, warn};
/// A custom preprocessor which will shell out to a 3rd-party program. /// A custom preprocessor which will shell out to a 3rd-party program.
/// ///

View file

@ -1,9 +1,9 @@
use anyhow::Result; use anyhow::Result;
use log::warn;
use mdbook_core::book::{Book, BookItem}; use mdbook_core::book::{Book, BookItem};
use mdbook_preprocessor::{Preprocessor, PreprocessorContext}; use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
use regex::Regex; use regex::Regex;
use std::{path::Path, sync::LazyLock}; use std::{path::Path, sync::LazyLock};
use tracing::warn;
/// A preprocessor for converting file name `README.md` to `index.md` since /// A preprocessor for converting file name `README.md` to `index.md` since
/// `README.md` is the de facto index file in markdown-based documentation. /// `README.md` is the de facto index file in markdown-based documentation.

View file

@ -1,5 +1,4 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::{error, warn};
use mdbook_core::book::{Book, BookItem}; use mdbook_core::book::{Book, BookItem};
use mdbook_core::utils::{ use mdbook_core::utils::{
take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines, take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines,
@ -11,6 +10,7 @@ use std::fs;
use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeTo}; use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeTo};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::LazyLock; use std::sync::LazyLock;
use tracing::{error, warn};
const ESCAPE_CHAR: char = '\\'; const ESCAPE_CHAR: char = '\\';
const MAX_LINK_NESTED_DEPTH: usize = 10; const MAX_LINK_NESTED_DEPTH: usize = 10;

View file

@ -1,9 +1,9 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::trace;
use mdbook_core::book::BookItem; use mdbook_core::book::BookItem;
use mdbook_core::utils; use mdbook_core::utils;
use mdbook_renderer::{RenderContext, Renderer}; use mdbook_renderer::{RenderContext, Renderer};
use std::fs; use std::fs;
use tracing::trace;
/// A renderer to output the Markdown after the preprocessors have run. Mostly useful /// A renderer to output the Markdown after the preprocessors have run. Mostly useful
/// when debugging preprocessors. /// when debugging preprocessors.

View file

@ -3,10 +3,10 @@
//! The HTML renderer can be found in the [`mdbook_html`] crate. //! The HTML renderer can be found in the [`mdbook_html`] crate.
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use log::{error, info, trace, warn};
use mdbook_renderer::{RenderContext, Renderer}; use mdbook_renderer::{RenderContext, Renderer};
use std::fs; use std::fs;
use std::process::Stdio; use std::process::Stdio;
use tracing::{error, info, trace, warn};
pub use self::markdown_renderer::MarkdownRenderer; pub use self::markdown_renderer::MarkdownRenderer;
@ -30,7 +30,7 @@ mod markdown_renderer;
/// whatever it wants, to avoid spamming users it is recommended to avoid /// whatever it wants, to avoid spamming users it is recommended to avoid
/// unnecessary output. /// unnecessary output.
/// ///
/// To help choose the appropriate output level, the `RUST_LOG` environment /// To help choose the appropriate output level, the `MDBOOK_LOG` environment
/// variable will be passed through to the subprocess, if set. /// variable will be passed through to the subprocess, if set.
/// ///
/// If the subprocess wishes to indicate that rendering failed, it should exit /// If the subprocess wishes to indicate that rendering failed, it should exit

View file

@ -6,10 +6,10 @@ use std::path::PathBuf;
use super::MDBook; use super::MDBook;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::{debug, error, info, trace};
use mdbook_core::config::Config; use mdbook_core::config::Config;
use mdbook_core::utils::fs::write_file; use mdbook_core::utils::fs::write_file;
use mdbook_html::theme; use mdbook_html::theme;
use tracing::{debug, error, info, trace};
/// A helper for setting up a new book and its directory structure. /// A helper for setting up a new book and its directory structure.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]

View file

@ -65,12 +65,12 @@ mod load;
mod mdbook; mod mdbook;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use log::{error, warn};
pub use mdbook::MDBook; pub use mdbook::MDBook;
pub use mdbook_core::{book, config, errors}; pub use mdbook_core::{book, config, errors};
use shlex::Shlex; use shlex::Shlex;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use tracing::{error, warn};
/// Creates a [`Command`] for command renderers and preprocessors. /// Creates a [`Command`] for command renderers and preprocessors.
fn compose_command(cmd: &str, root: &Path) -> Result<Command> { fn compose_command(cmd: &str, root: &Path) -> Result<Command> {

View file

@ -1,5 +1,4 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::debug;
use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::book::{Book, BookItem, Chapter};
use mdbook_core::config::BuildConfig; use mdbook_core::config::BuildConfig;
use mdbook_core::utils::bracket_escape; use mdbook_core::utils::bracket_escape;
@ -7,6 +6,7 @@ use mdbook_summary::{Link, Summary, SummaryItem, parse_summary};
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
use tracing::debug;
/// Load a book into memory from its `src/` directory. /// Load a book into memory from its `src/` directory.
pub(crate) fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -> Result<Book> { pub(crate) fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -> Result<Book> {

View file

@ -6,7 +6,6 @@ use crate::init::BookBuilder;
use crate::load::{load_book, load_book_from_disk}; use crate::load::{load_book, load_book_from_disk};
use anyhow::{Context, Error, Result, bail}; use anyhow::{Context, Error, Result, bail};
use indexmap::IndexMap; use indexmap::IndexMap;
use log::{debug, error, info, log_enabled, trace, warn};
use mdbook_core::book::{Book, BookItem, BookItems}; use mdbook_core::book::{Book, BookItem, BookItems};
use mdbook_core::config::{Config, RustEdition}; use mdbook_core::config::{Config, RustEdition};
use mdbook_core::utils; use mdbook_core::utils;
@ -21,6 +20,7 @@ use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use tempfile::Builder as TempFileBuilder; use tempfile::Builder as TempFileBuilder;
use topological_sort::TopologicalSort; use topological_sort::TopologicalSort;
use tracing::{debug, error, info, trace, warn};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -58,7 +58,7 @@ impl MDBook {
config.update_from_env(); config.update_from_env();
if log_enabled!(log::Level::Trace) { if tracing::enabled!(tracing::Level::TRACE) {
for line in format!("Config: {config:#?}").lines() { for line in format!("Config: {config:#?}").lines() {
trace!("{}", line); trace!("{}", line);
} }

View file

@ -14,7 +14,6 @@ elasticlunr-rs = { workspace = true, optional = true }
font-awesome-as-a-crate.workspace = true font-awesome-as-a-crate.workspace = true
handlebars.workspace = true handlebars.workspace = true
hex.workspace = true hex.workspace = true
log.workspace = true
mdbook-core.workspace = true mdbook-core.workspace = true
mdbook-markdown.workspace = true mdbook-markdown.workspace = true
mdbook-renderer.workspace = true mdbook-renderer.workspace = true
@ -23,6 +22,7 @@ regex.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
sha2.workspace = true sha2.workspace = true
tracing.workspace = true
[dev-dependencies] [dev-dependencies]
pretty_assertions.workspace = true pretty_assertions.workspace = true

View file

@ -3,7 +3,6 @@ use super::static_files::StaticFiles;
use crate::theme::Theme; use crate::theme::Theme;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use handlebars::Handlebars; use handlebars::Handlebars;
use log::{debug, info, trace, warn};
use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::book::{Book, BookItem, Chapter};
use mdbook_core::config::{BookConfig, Code, Config, HtmlConfig, Playground, RustEdition}; use mdbook_core::config::{BookConfig, Code, Config, HtmlConfig, Playground, RustEdition};
use mdbook_core::utils; use mdbook_core::utils;
@ -18,6 +17,8 @@ use std::collections::HashMap;
use std::fs::{self, File}; use std::fs::{self, File};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::LazyLock; use std::sync::LazyLock;
use tracing::error;
use tracing::{debug, info, trace, warn};
/// The HTML renderer for mdBook. /// The HTML renderer for mdBook.
#[derive(Default)] #[derive(Default)]
@ -286,7 +287,7 @@ impl HtmlHandlebars {
return Ok(()); return Ok(());
} }
log::debug!("Emitting redirects"); debug!("Emitting redirects");
let redirects = combine_fragment_redirects(redirects); let redirects = combine_fragment_redirects(redirects);
for (original, (dest, fragment_map)) in redirects { for (original, (dest, fragment_map)) in redirects {
@ -306,7 +307,7 @@ impl HtmlHandlebars {
destination." destination."
); );
} }
log::debug!("Redirecting \"{}\"\"{}\"", original, dest); debug!("Redirecting \"{}\"\"{}\"", original, dest);
self.emit_redirect(handlebars, &filename, &dest, &fragment_map)?; self.emit_redirect(handlebars, &filename, &dest, &fragment_map)?;
} }
@ -1034,7 +1035,7 @@ fn combine_fragment_redirects(redirects: &HashMap<String, String>) -> CombinedRe
if let Some((source_path, source_fragment)) = original.rsplit_once('#') { if let Some((source_path, source_fragment)) = original.rsplit_once('#') {
let e = combined.entry(source_path.to_string()).or_default(); let e = combined.entry(source_path.to_string()).or_default();
if let Some(old) = e.1.insert(format!("#{source_fragment}"), new.clone()) { if let Some(old) = e.1.insert(format!("#{source_fragment}"), new.clone()) {
log::error!( error!(
"internal error: found duplicate fragment redirect \ "internal error: found duplicate fragment redirect \
{old} for {source_path}#{source_fragment}" {old} for {source_path}#{source_fragment}"
); );

View file

@ -2,8 +2,8 @@ use font_awesome_as_a_crate as fa;
use handlebars::{ use handlebars::{
Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason, Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason,
}; };
use log::trace;
use std::str::FromStr; use std::str::FromStr;
use tracing::trace;
pub(crate) fn fa_helper( pub(crate) fn fa_helper(
h: &Helper<'_>, h: &Helper<'_>,

View file

@ -2,7 +2,6 @@ use super::static_files::StaticFiles;
use crate::theme::searcher; use crate::theme::searcher;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use elasticlunr::{Index, IndexBuilder}; use elasticlunr::{Index, IndexBuilder};
use log::{debug, warn};
use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::book::{Book, BookItem, Chapter};
use mdbook_core::config::{Search, SearchChapterSettings}; use mdbook_core::config::{Search, SearchChapterSettings};
use mdbook_core::utils; use mdbook_core::utils;
@ -14,6 +13,7 @@ use std::borrow::Cow;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::LazyLock; use std::sync::LazyLock;
use tracing::{debug, warn};
const MAX_WORD_LENGTH_TO_INDEX: usize = 80; const MAX_WORD_LENGTH_TO_INDEX: usize = 80;

View file

@ -3,7 +3,6 @@
use super::helpers::resources::ResourceHelper; use super::helpers::resources::ResourceHelper;
use crate::theme::{self, Theme, playground_editor}; use crate::theme::{self, Theme, playground_editor};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::debug;
use mdbook_core::config::HtmlConfig; use mdbook_core::config::HtmlConfig;
use mdbook_core::utils; use mdbook_core::utils;
use std::borrow::Cow; use std::borrow::Cow;
@ -11,6 +10,7 @@ use std::collections::HashMap;
use std::fs::{self, File}; use std::fs::{self, File};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::LazyLock; use std::sync::LazyLock;
use tracing::debug;
/// Map static files to their final names and contents. /// Map static files to their final names and contents.
/// ///

View file

@ -1,10 +1,10 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use anyhow::Result; use anyhow::Result;
use log::warn;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tracing::{info, warn};
pub mod fonts; pub mod fonts;
pub mod playground_editor; pub mod playground_editor;
@ -133,7 +133,7 @@ impl Theme {
if entry.file_name() == "fonts.css" { if entry.file_name() == "fonts.css" {
None None
} else if entry.file_type().ok()?.is_dir() { } else if entry.file_type().ok()?.is_dir() {
log::info!("skipping font directory {:?}", entry.path()); info!("skipping font directory {:?}", entry.path());
None None
} else { } else {
Some(entry.path()) Some(entry.path())

View file

@ -8,9 +8,9 @@ repository.workspace = true
rust-version.workspace = true rust-version.workspace = true
[dependencies] [dependencies]
log.workspace = true
pulldown-cmark.workspace = true pulldown-cmark.workspace = true
regex.workspace = true regex.workspace = true
tracing.workspace = true
[lints] [lints]
workspace = true workspace = true

View file

@ -15,6 +15,7 @@ use std::collections::HashMap;
use std::fmt::Write; use std::fmt::Write;
use std::path::Path; use std::path::Path;
use std::sync::LazyLock; use std::sync::LazyLock;
use tracing::warn;
#[doc(inline)] #[doc(inline)]
pub use pulldown_cmark; pub use pulldown_cmark;
@ -126,7 +127,7 @@ pub fn render_markdown(text: &str, options: &HtmlRenderOptions<'_>) -> String {
Event::Start(Tag::FootnoteDefinition(name)) => { Event::Start(Tag::FootnoteDefinition(name)) => {
prev_was_footnote = false; prev_was_footnote = false;
if !in_footnote.is_empty() { if !in_footnote.is_empty() {
log::warn!( warn!(
"internal bug: nested footnote not expected in {:?}", "internal bug: nested footnote not expected in {:?}",
options.path options.path
); );
@ -139,7 +140,7 @@ pub fn render_markdown(text: &str, options: &HtmlRenderOptions<'_>) -> String {
let name = std::mem::take(&mut in_footnote_name); let name = std::mem::take(&mut in_footnote_name);
if footnote_defs.contains_key(&name) { if footnote_defs.contains_key(&name) {
log::warn!( warn!(
"footnote `{name}` in {} defined multiple times - \ "footnote `{name}` in {} defined multiple times - \
not updating to new definition", not updating to new definition",
options.path.display() options.path.display()
@ -212,7 +213,7 @@ fn add_footnote_defs(
// Remove unused. // Remove unused.
defs.retain(|(name, _)| { defs.retain(|(name, _)| {
if !numbers.contains_key(name) { if !numbers.contains_key(name) {
log::warn!( warn!(
"footnote `{name}` in `{}` is defined but not referenced", "footnote `{name}` in `{}` is defined but not referenced",
options.path.display() options.path.display()
); );

View file

@ -9,11 +9,11 @@ rust-version.workspace = true
[dependencies] [dependencies]
anyhow.workspace = true anyhow.workspace = true
log.workspace = true
mdbook-core.workspace = true mdbook-core.workspace = true
memchr.workspace = true memchr.workspace = true
pulldown-cmark.workspace = true pulldown-cmark.workspace = true
serde.workspace = true serde.workspace = true
tracing.workspace = true
[lints] [lints]
workspace = true workspace = true

View file

@ -5,7 +5,6 @@
//! file structure for [mdBook](https://rust-lang.github.io/mdBook/). //! file structure for [mdBook](https://rust-lang.github.io/mdBook/).
use anyhow::{Context, Error, Result, bail}; use anyhow::{Context, Error, Result, bail};
use log::{debug, trace, warn};
pub use mdbook_core::book::SectionNumber; pub use mdbook_core::book::SectionNumber;
use memchr::Memchr; use memchr::Memchr;
use pulldown_cmark::{DefaultBrokenLinkCallback, Event, HeadingLevel, Tag, TagEnd}; use pulldown_cmark::{DefaultBrokenLinkCallback, Event, HeadingLevel, Tag, TagEnd};
@ -13,6 +12,7 @@ use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::Display; use std::fmt::Display;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tracing::{debug, trace, warn};
/// Parse the text from a `SUMMARY.md` file into a sort of "recipe" to be /// Parse the text from a `SUMMARY.md` file into a sort of "recipe" to be
/// used when loading a book from disk. /// used when loading a book from disk.

View file

@ -317,7 +317,7 @@ the "rule of silence" and only generate output when necessary (e.g. an error in
generation or a warning). generation or a warning).
All environment variables are passed through to the backend, allowing you to use All environment variables are passed through to the backend, allowing you to use
the usual `RUST_LOG` to control logging verbosity. the usual `MDBOOK_LOG` to control logging verbosity.
## Wrapping up ## Wrapping up

View file

@ -2,6 +2,7 @@ use super::command_prelude::*;
use crate::{get_book_dir, open}; use crate::{get_book_dir, open};
use anyhow::Result; use anyhow::Result;
use mdbook_driver::MDBook; use mdbook_driver::MDBook;
use tracing::error;
// Create clap subcommand arguments // Create clap subcommand arguments
pub fn make_subcommand() -> Command { pub fn make_subcommand() -> Command {

View file

@ -6,6 +6,7 @@ use mdbook_driver::MDBook;
use std::io; use std::io;
use std::io::Write; use std::io::Write;
use std::process::Command; use std::process::Command;
use tracing::debug;
// Create clap subcommand arguments // Create clap subcommand arguments
pub fn make_subcommand() -> ClapCommand { pub fn make_subcommand() -> ClapCommand {

View file

@ -15,6 +15,7 @@ use std::net::{SocketAddr, ToSocketAddrs};
use std::path::PathBuf; use std::path::PathBuf;
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tower_http::services::{ServeDir, ServeFile}; use tower_http::services::{ServeDir, ServeFile};
use tracing::{error, info, trace};
/// The HTTP endpoint for the websocket used to trigger reloads when a file changes. /// The HTTP endpoint for the websocket used to trigger reloads when a file changes.
const LIVE_RELOAD_ENDPOINT: &str = "__livereload"; const LIVE_RELOAD_ENDPOINT: &str = "__livereload";

View file

@ -3,6 +3,7 @@ use crate::{get_book_dir, open};
use anyhow::Result; use anyhow::Result;
use mdbook_driver::MDBook; use mdbook_driver::MDBook;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tracing::error;
mod native; mod native;
mod poller; mod poller;

View file

@ -6,6 +6,7 @@ use std::path::{Path, PathBuf};
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use tracing::{error, info, warn};
pub fn rebuild_on_change( pub fn rebuild_on_change(
book_dir: &Path, book_dir: &Path,
@ -71,7 +72,7 @@ pub fn rebuild_on_change(
.filter_map(|event| match event { .filter_map(|event| match event {
Ok(events) => Some(events), Ok(events) => Some(events),
Err(error) => { Err(error) => {
log::warn!("error while watching for changes: {error}"); warn!("error while watching for changes: {error}");
None None
} }
}) })

View file

@ -11,6 +11,7 @@ use std::collections::HashMap;
use std::fs::FileType; use std::fs::FileType;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::{Duration, Instant, SystemTime}; use std::time::{Duration, Instant, SystemTime};
use tracing::{debug, error, info, trace, warn};
use walkdir::WalkDir; use walkdir::WalkDir;
/// Calls the closure when a book source file is changed, blocking indefinitely. /// Calls the closure when a book source file is changed, blocking indefinitely.

View file

@ -4,20 +4,15 @@
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
#[macro_use]
extern crate log;
use anyhow::anyhow; use anyhow::anyhow;
use chrono::Local;
use clap::{Arg, ArgMatches, Command}; use clap::{Arg, ArgMatches, Command};
use clap_complete::Shell; use clap_complete::Shell;
use env_logger::Builder;
use log::LevelFilter;
use mdbook_core::utils; use mdbook_core::utils;
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use tracing::{error, info};
mod cmd; mod cmd;
@ -99,29 +94,36 @@ fn create_clap_command() -> Command {
} }
fn init_logger() { fn init_logger() {
let mut builder = Builder::new(); let filter = tracing_subscriber::EnvFilter::builder()
.with_env_var("MDBOOK_LOG")
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
.from_env_lossy();
let log_env = std::env::var("MDBOOK_LOG");
// Silence some particularly noisy dependencies unless the user
// specifically asks for them.
let silence_unless_specified = |filter: tracing_subscriber::EnvFilter, target| {
if !log_env.as_ref().map_or(false, |s| {
s.split(',').any(|directive| directive.starts_with(target))
}) {
filter.add_directive(format!("{target}=warn").parse().unwrap())
} else {
filter
}
};
let filter = silence_unless_specified(filter, "handlebars");
let filter = silence_unless_specified(filter, "html5ever");
builder.format(|formatter, record| { // Don't show the target by default, since it generally isn't useful
writeln!( // unless you are overriding the level.
formatter, let with_target = log_env.is_ok();
"{} [{}] ({}): {}",
Local::now().format("%Y-%m-%d %H:%M:%S"),
record.level(),
record.target(),
record.args()
)
});
if let Ok(var) = env::var("RUST_LOG") { tracing_subscriber::fmt()
builder.parse_filters(&var); .without_time()
} else { .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr()))
// if no RUST_LOG provided, default to logging at the Info level .with_writer(std::io::stderr)
builder.filter(None, LevelFilter::Info); .with_env_filter(filter)
// Filter extraneous html5ever not-implemented messages .with_target(with_target)
builder.filter(Some("html5ever"), LevelFilter::Error); .init();
}
builder.init();
} }
fn get_book_dir(args: &ArgMatches) -> PathBuf { fn get_book_dir(args: &ArgMatches) -> PathBuf {

View file

@ -360,7 +360,7 @@ impl BookCommand {
/// Use this to debug a command. /// Use this to debug a command.
/// ///
/// Pass the value that you would normally pass to `RUST_LOG`, and this /// Pass the value that you would normally pass to `MDBOOK_LOG`, and this
/// will enable logging, print the command that runs and its output. /// will enable logging, print the command that runs and its output.
/// ///
/// This will fail if you use it in CI. /// This will fail if you use it in CI.
@ -378,7 +378,7 @@ impl BookCommand {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_mdbook")); let mut cmd = Command::new(env!("CARGO_BIN_EXE_mdbook"));
cmd.current_dir(&self.dir) cmd.current_dir(&self.dir)
.args(&self.args) .args(&self.args)
.env_remove("RUST_LOG") .env_remove("MDBOOK_LOG")
// Don't read the system git config which is out of our control. // Don't read the system git config which is out of our control.
.env("GIT_CONFIG_NOSYSTEM", "1") .env("GIT_CONFIG_NOSYSTEM", "1")
.env("GIT_CONFIG_GLOBAL", &self.dir) .env("GIT_CONFIG_GLOBAL", &self.dir)
@ -389,7 +389,7 @@ impl BookCommand {
.env_remove("GIT_COMMITTER_NAME"); .env_remove("GIT_COMMITTER_NAME");
if let Some(debug) = &self.debug { if let Some(debug) = &self.debug {
cmd.env("RUST_LOG", debug); cmd.env("MDBOOK_LOG", debug);
} }
for (k, v) in &self.env { for (k, v) in &self.env {
@ -479,23 +479,9 @@ static LITERAL_REDACTIONS: &[(&str, &str)] = &[
("[EXE]", std::env::consts::EXE_SUFFIX), ("[EXE]", std::env::consts::EXE_SUFFIX),
]; ];
/// This makes it easier to write regex replacements that are guaranteed to only
/// get compiled once
macro_rules! regex {
($re:literal $(,)?) => {{
static RE: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
RE.get_or_init(|| regex::Regex::new($re).unwrap())
}};
}
fn assert(root: &Path) -> snapbox::Assert { fn assert(root: &Path) -> snapbox::Assert {
let mut subs = snapbox::Redactions::new(); let mut subs = snapbox::Redactions::new();
subs.insert("[ROOT]", root.to_path_buf()).unwrap(); subs.insert("[ROOT]", root.to_path_buf()).unwrap();
subs.insert(
"[TIMESTAMP]",
regex!(r"(?m)(?<redacted>20\d\d-\d{2}-\d{2} \d{2}:\d{2}:\d{2})"),
)
.unwrap();
subs.insert("[VERSION]", mdbook_core::MDBOOK_VERSION) subs.insert("[VERSION]", mdbook_core::MDBOOK_VERSION)
.unwrap(); .unwrap();

View file

@ -10,9 +10,9 @@ use crate::prelude::*;
fn basic_build() { fn basic_build() {
BookTest::from_dir("build/basic_build").run("build", |cmd| { BookTest::from_dir("build/basic_build").run("build", |cmd| {
cmd.expect_stderr(str![[r#" cmd.expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}); });
@ -24,8 +24,8 @@ fn basic_build() {
fn failure_on_missing_file() { fn failure_on_missing_file() {
BookTest::from_dir("build/missing_file").run("build", |cmd| { BookTest::from_dir("build/missing_file").run("build", |cmd| {
cmd.expect_failure().expect_stderr(str![[r#" cmd.expect_failure().expect_stderr(str![[r#"
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Chapter file not found, ./chapter_1.md ERROR Chapter file not found, ./chapter_1.md
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [NOT_FOUND] [TAB]Caused by: [NOT_FOUND]
"#]]); "#]]);
}); });
@ -46,10 +46,10 @@ fn create_missing() {
fn no_reserved_filename() { fn no_reserved_filename() {
BookTest::from_dir("build/no_reserved_filename").run("build", |cmd| { BookTest::from_dir("build/no_reserved_filename").run("build", |cmd| {
cmd.expect_failure().expect_stderr(str![[r#" cmd.expect_failure().expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed ERROR Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: print.md is reserved for internal use [TAB]Caused by: print.md is reserved for internal use
"#]]); "#]]);
}); });
@ -77,9 +77,9 @@ fn dest_dir_relative_path() {
cmd.args(&["--dest-dir", "foo", ".."]) cmd.args(&["--dest-dir", "foo", ".."])
.current_dir(&current_dir) .current_dir(&current_dir)
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/work/foo` INFO HTML book written to `[ROOT]/work/foo`
"#]]); "#]]);
}); });

View file

@ -120,8 +120,8 @@ fn bad_config_top_level() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file ERROR Invalid configuration file
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 1, column 1 [TAB]Caused by: TOML parse error at line 1, column 1
| |
1 | foo = 123 1 | foo = 123
| ^^^ | ^^^
@ -145,8 +145,8 @@ fn bad_config_top_level_table() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file ERROR Invalid configuration file
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 1, column 2 [TAB]Caused by: TOML parse error at line 1, column 2
| |
1 | [other] 1 | [other]
| ^^^^^ | ^^^^^
@ -171,8 +171,8 @@ fn bad_config_in_book_table() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file ERROR Invalid configuration file
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 3, column 1 [TAB]Caused by: TOML parse error at line 3, column 1
| |
3 | foo = 123 3 | foo = 123
| ^^^ | ^^^
@ -196,8 +196,8 @@ fn bad_config_in_rust_table() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file ERROR Invalid configuration file
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 2, column 1 [TAB]Caused by: TOML parse error at line 2, column 1
| |
2 | title = "bad-config" 2 | title = "bad-config"
| ^^^^^ | ^^^^^

View file

@ -45,10 +45,10 @@ fn recursive_include() {
BookTest::from_dir("includes/all_includes") BookTest::from_dir("includes/all_includes")
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stderr(str![[r#" cmd.expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [ERROR] (mdbook_driver::builtin_preprocessors::links): Stack depth exceeded in recursive.md. Check for cyclic includes ERROR Stack depth exceeded in recursive.md. Check for cyclic includes
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}) })

View file

@ -19,7 +19,7 @@ All done, no errors...
"#]]) "#]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::init): Creating a new book with stub content INFO Creating a new book with stub content
"#]]); "#]]);
}) })
@ -84,7 +84,7 @@ All done, no errors...
"#]]) "#]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::init): Creating a new book with stub content INFO Creating a new book with stub content
"#]]); "#]]);
}) })
@ -115,7 +115,7 @@ All done, no errors...
"#]]) "#]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::init): Creating a new book with stub content INFO Creating a new book with stub content
"#]]) "#]])
.args(&["--title", "Example title"]); .args(&["--title", "Example title"]);

View file

@ -20,13 +20,13 @@ fn footnotes() {
BookTest::from_dir("markdown/footnotes") BookTest::from_dir("markdown/footnotes")
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stderr(str![[r#" cmd.expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [WARN] (mdbook_markdown): footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition WARN footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition
[TIMESTAMP] [WARN] (mdbook_markdown): footnote `unused` in `footnotes.md` is defined but not referenced WARN footnote `unused` in `footnotes.md` is defined but not referenced
[TIMESTAMP] [WARN] (mdbook_markdown): footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition WARN footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition
[TIMESTAMP] [WARN] (mdbook_markdown): footnote `unused` in `footnotes.md` is defined but not referenced WARN footnote `unused` in `footnotes.md` is defined but not referenced
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}) })

View file

@ -49,9 +49,9 @@ fn runs_preprocessors() {
fn nop_preprocessor() { fn nop_preprocessor() {
BookTest::from_dir("preprocessor/nop_preprocessor").run("build", |cmd| { BookTest::from_dir("preprocessor/nop_preprocessor").run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}); });
@ -60,17 +60,16 @@ fn nop_preprocessor() {
// Failing preprocessor generates an error. // Failing preprocessor generates an error.
#[test] #[test]
fn failing_preprocessor() { fn failing_preprocessor() {
BookTest::from_dir("preprocessor/failing_preprocessor") BookTest::from_dir("preprocessor/failing_preprocessor").run("build", |cmd| {
.run("build", |cmd| { cmd.expect_failure()
cmd.expect_failure() .expect_stdout(str![[""]])
.expect_stdout(str![[""]]) .expect_stderr(str![[r#"
.expect_stderr(str![[r#" INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started
Boom!!1! Boom!!1!
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: The "nop-preprocessor" preprocessor exited unsuccessfully with [EXIT_STATUS]: 1 status ERROR The "nop-preprocessor" preprocessor exited unsuccessfully with [EXIT_STATUS]: 1 status
"#]]); "#]]);
}); });
} }
fn example() -> CmdPreprocessor { fn example() -> CmdPreprocessor {
@ -128,9 +127,9 @@ fn relative_command_path() {
) )
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stdout(str![""]).expect_stderr(str![[r#" cmd.expect_stdout(str![""]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}) })
@ -143,9 +142,9 @@ fn relative_command_path() {
cmd.current_dir(cmd.dir.join("src")) cmd.current_dir(cmd.dir.join("src"))
.expect_stdout(str![""]) .expect_stdout(str![""])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/src/../book` INFO HTML book written to `[ROOT]/src/../book`
"#]]); "#]]);
}) })
@ -160,10 +159,10 @@ fn missing_preprocessor() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [ERROR] (mdbook_driver): The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` preprocessor installed? If you want to ignore this error when the `missing` preprocessor is not installed, set `optional = true` in the `[preprocessor.missing]` section of the book.toml configuration file. ERROR The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` preprocessor installed? If you want to ignore this error when the `missing` preprocessor is not installed, set `optional = true` in the `[preprocessor.missing]` section of the book.toml configuration file.
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Unable to run the preprocessor `missing` ERROR Unable to run the preprocessor `missing`
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [NOT_FOUND] [TAB]Caused by: [NOT_FOUND]
"#]]); "#]]);
}); });
@ -174,10 +173,10 @@ fn missing_preprocessor() {
fn missing_optional_not_fatal() { fn missing_optional_not_fatal() {
BookTest::from_dir("preprocessor/missing_optional_not_fatal").run("build", |cmd| { BookTest::from_dir("preprocessor/missing_optional_not_fatal").run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [WARN] (mdbook_driver): The command `trduyvbhijnorgevfuhn` for preprocessor `missing` was not found, but is marked as optional. WARN The command `trduyvbhijnorgevfuhn` for preprocessor `missing` was not found, but is marked as optional.
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}); });
@ -239,14 +238,14 @@ fn extension_compatibility() {
// that the built book is identical with the preprocessor enabled. // that the built book is identical with the preprocessor enabled.
test.run("build", |cmd| { test.run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [WARN] (mdbook_driver): The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional. WARN The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional.
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book/html` INFO HTML book written to `[ROOT]/book/html`
[TIMESTAMP] [WARN] (mdbook_driver): The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional. WARN The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional.
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the my-renderer backend INFO Running the my-renderer backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "my-renderer" renderer INFO Invoking the "my-renderer" renderer
[TIMESTAMP] [WARN] (mdbook_driver): The command `./my-renderer` for backend `my-renderer` was not found, but is marked as optional. WARN The command `./my-renderer` for backend `my-renderer` was not found, but is marked as optional.
"#]]); "#]]);
}); });
@ -441,11 +440,11 @@ fn extension_compatibility() {
) )
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book/html` INFO HTML book written to `[ROOT]/book/html`
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the my-renderer backend INFO Running the my-renderer backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "my-renderer" renderer INFO Invoking the "my-renderer" renderer
"#]]); "#]]);
}) })

View file

@ -22,11 +22,11 @@ fn redirects_are_emitted_correctly() {
fn redirect_removed_with_fragments_only() { fn redirect_removed_with_fragments_only() {
BookTest::from_dir("redirects/redirect_removed_with_fragments_only").run("build", |cmd| { BookTest::from_dir("redirects/redirect_removed_with_fragments_only").run("build", |cmd| {
cmd.expect_failure().expect_stderr(str![[r#" cmd.expect_failure().expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed ERROR Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: Unable to emit redirects [TAB]Caused by: Unable to emit redirects
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: redirect entry for `old-file.html` only has source paths with `#` fragments [TAB]Caused by: redirect entry for `old-file.html` only has source paths with `#` fragments
There must be an entry without the `#` fragment to determine the default destination. There must be an entry without the `#` fragment to determine the default destination.
"#]]); "#]]);
@ -38,10 +38,10 @@ There must be an entry without the `#` fragment to determine the default destina
fn redirect_existing_page() { fn redirect_existing_page() {
BookTest::from_dir("redirects/redirect_existing_page").run("build", |cmd| { BookTest::from_dir("redirects/redirect_existing_page").run("build", |cmd| {
cmd.expect_failure().expect_stderr(str![[r#" cmd.expect_failure().expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed ERROR Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: redirect found for existing chapter at `/chapter_1.html` [TAB]Caused by: redirect found for existing chapter at `/chapter_1.html`
Either delete the redirect or remove the chapter. Either delete the redirect or remove the chapter.
"#]]); "#]]);

View file

@ -64,12 +64,12 @@ fn failing_command() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the failing backend INFO Running the failing backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "failing" renderer INFO Invoking the "failing" renderer
[TIMESTAMP] [ERROR] (mdbook_driver::builtin_renderers): Renderer exited with non-zero return code. ERROR Renderer exited with non-zero return code.
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed ERROR Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: The "failing" renderer failed [TAB]Caused by: The "failing" renderer failed
"#]]); "#]]);
}); });
@ -82,13 +82,13 @@ fn missing_renderer() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the missing backend INFO Running the missing backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "missing" renderer INFO Invoking the "missing" renderer
[TIMESTAMP] [ERROR] (mdbook_driver): The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` backend installed? If you want to ignore this error when the `missing` backend is not installed, set `optional = true` in the `[output.missing]` section of the book.toml configuration file. ERROR The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` backend installed? If you want to ignore this error when the `missing` backend is not installed, set `optional = true` in the `[output.missing]` section of the book.toml configuration file.
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed ERROR Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: Unable to run the backend `missing` [TAB]Caused by: Unable to run the backend `missing`
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [NOT_FOUND] [TAB]Caused by: [NOT_FOUND]
"#]]); "#]]);
}); });
@ -99,10 +99,10 @@ fn missing_renderer() {
fn missing_optional_not_fatal() { fn missing_optional_not_fatal() {
BookTest::from_dir("renderer/missing_optional_not_fatal").run("build", |cmd| { BookTest::from_dir("renderer/missing_optional_not_fatal").run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the missing backend INFO Running the missing backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "missing" renderer INFO Invoking the "missing" renderer
[TIMESTAMP] [WARN] (mdbook_driver): The command `trduyvbhijnorgevfuhn` for backend `missing` was not found, but is marked as optional. WARN The command `trduyvbhijnorgevfuhn` for backend `missing` was not found, but is marked as optional.
"#]]); "#]]);
}); });
@ -131,9 +131,9 @@ Hello World!
"#]]) "#]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the arguments backend INFO Running the arguments backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "arguments" renderer INFO Invoking the "arguments" renderer
"#]]); "#]]);
}); });
@ -156,9 +156,9 @@ fn backends_receive_render_context_via_stdin() {
) )
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the cat-to-file backend INFO Running the cat-to-file backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "cat-to-file" renderer INFO Invoking the "cat-to-file" renderer
"#]]); "#]]);
}) })
@ -233,9 +233,9 @@ fn relative_command_path() {
) )
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the myrenderer backend INFO Running the myrenderer backend
[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "myrenderer" renderer INFO Invoking the "myrenderer" renderer
"#]]); "#]]);
}) })

View file

@ -126,10 +126,10 @@ fn with_no_source_path() {
fn chapter_settings_validation_error() { fn chapter_settings_validation_error() {
BookTest::from_dir("search/chapter_settings_validation_error").run("build", |cmd| { BookTest::from_dir("search/chapter_settings_validation_error").run("build", |cmd| {
cmd.expect_failure().expect_stderr(str![[r#" cmd.expect_failure().expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed ERROR Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [output.html.search.chapter] key `does-not-exist` does not match any chapter paths [TAB]Caused by: [output.html.search.chapter] key `does-not-exist` does not match any chapter paths
"#]]); "#]]);
}); });

View file

@ -7,9 +7,9 @@ use crate::prelude::*;
fn passing_tests() { fn passing_tests() {
BookTest::from_dir("test/passing_tests").run("test", |cmd| { BookTest::from_dir("test/passing_tests").run("test", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Intro': "intro.md" INFO Testing chapter 'Intro': "intro.md"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 1': "passing1.md" INFO Testing chapter 'Passing 1': "passing1.md"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 2': "passing2.md" INFO Testing chapter 'Passing 2': "passing2.md"
"#]]); "#]]);
}); });
@ -27,8 +27,8 @@ fn failing_tests() {
// still includes a little bit of output, so if that is a problem, // still includes a little bit of output, so if that is a problem,
// add more redactions. // add more redactions.
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Failing Tests': "failing.md" INFO Testing chapter 'Failing Tests': "failing.md"
[TIMESTAMP] [ERROR] (mdbook_driver::mdbook): rustdoc returned an error: ERROR rustdoc returned an error:
--- stdout --- stdout
@ -38,8 +38,8 @@ test failing.md - Failing_Tests (line 3) ... FAILED
thread [..] panicked at failing.md:3:1: thread [..] panicked at failing.md:3:1:
fail fail
... ...
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Failing Include': "failing_include.md" INFO Testing chapter 'Failing Include': "failing_include.md"
[TIMESTAMP] [ERROR] (mdbook_driver::mdbook): rustdoc returned an error: ERROR rustdoc returned an error:
--- stdout --- stdout
... ...
@ -48,7 +48,7 @@ test failing_include.md - Failing_Include (line 3) ... FAILED
thread [..] panicked at failing_include.md:3:1: thread [..] panicked at failing_include.md:3:1:
failing! failing!
... ...
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: One or more tests failed ERROR One or more tests failed
"#]]); "#]]);
}); });
@ -62,14 +62,14 @@ fn test_individual_chapter() {
cmd.args(&["Passing 1"]) cmd.args(&["Passing 1"])
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 1': "passing1.md" INFO Testing chapter 'Passing 1': "passing1.md"
"#]]); "#]]);
}) })
// Can also be a source path. // Can also be a source path.
.run("test -c passing2.md", |cmd| { .run("test -c passing2.md", |cmd| {
cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 2': "passing2.md" INFO Testing chapter 'Passing 2': "passing2.md"
"#]]); "#]]);
}); });
@ -82,7 +82,7 @@ fn chapter_not_found() {
cmd.expect_failure() cmd.expect_failure()
.expect_stdout(str![[""]]) .expect_stdout(str![[""]])
.expect_stderr(str![[r#" .expect_stderr(str![[r#"
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Chapter not found: bogus ERROR Chapter not found: bogus
"#]]); "#]]);
}); });

View file

@ -5,14 +5,12 @@ use crate::prelude::*;
// Checks what happens if the theme directory is missing. // Checks what happens if the theme directory is missing.
#[test] #[test]
fn missing_theme() { fn missing_theme() {
BookTest::from_dir("theme/missing_theme") BookTest::from_dir("theme/missing_theme").run("build", |cmd| {
.run("build", |cmd| { cmd.expect_failure().expect_stderr(str![[r#"
cmd.expect_failure() INFO Book building has started
.expect_stderr(str![[r#" INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started ERROR Rendering failed
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend [TAB]Caused by: theme dir [ROOT]/./non-existent-directory does not exist
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: theme dir [ROOT]/./non-existent-directory does not exist
"#]]); "#]]);
}); });
@ -24,9 +22,9 @@ fn empty_theme() {
BookTest::from_dir("theme/empty_theme").run("build", |cmd| { BookTest::from_dir("theme/empty_theme").run("build", |cmd| {
std::fs::create_dir(cmd.dir.join("theme")).unwrap(); std::fs::create_dir(cmd.dir.join("theme")).unwrap();
cmd.expect_stderr(str![[r#" cmd.expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}); });
@ -147,9 +145,9 @@ fn empty_fonts_css() {
BookTest::from_dir("theme/empty_fonts_css") BookTest::from_dir("theme/empty_fonts_css")
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stderr(str![[r#" cmd.expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}) })
@ -163,9 +161,9 @@ fn custom_fonts_css() {
BookTest::from_dir("theme/custom_fonts_css") BookTest::from_dir("theme/custom_fonts_css")
.run("build", |cmd| { .run("build", |cmd| {
cmd.expect_stderr(str![[r#" cmd.expect_stderr(str![[r#"
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started INFO Book building has started
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend INFO Running the html backend
[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` INFO HTML book written to `[ROOT]/book`
"#]]); "#]]);
}) })