Skip to content

Commit

Permalink
Change book source root depending on language
Browse files Browse the repository at this point in the history
  • Loading branch information
Ruin0x11 committed Sep 15, 2021
1 parent e4b443c commit 24e6d6b
Show file tree
Hide file tree
Showing 15 changed files with 111 additions and 24 deletions.
29 changes: 23 additions & 6 deletions src/book/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::renderer::{CmdRenderer, HtmlHandlebars, MarkdownRenderer, RenderConte
use crate::utils;

use crate::config::{Config, RustEdition};
use crate::build_opts::BuildOpts;

/// The object used to manage and build a book.
pub struct MDBook {
Expand All @@ -38,6 +39,10 @@ pub struct MDBook {
pub config: Config,
/// A representation of the book's contents in memory.
pub book: Book,
/// Build options passed from frontend.
pub build_opts: BuildOpts,

/// List of renderers to be run on the book.
renderers: Vec<Box<dyn Renderer>>,

/// List of pre-processors to be run on the book.
Expand All @@ -47,6 +52,12 @@ pub struct MDBook {
impl MDBook {
/// Load a book from its root directory on disk.
pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
MDBook::load_with_build_opts(book_root, BuildOpts::default())
}

/// Load a book from its root directory on disk, passing in options from the
/// frontend.
pub fn load_with_build_opts<P: Into<PathBuf>>(book_root: P, build_opts: BuildOpts) -> Result<MDBook> {
let book_root = book_root.into();
let config_location = book_root.join("book.toml");

Expand Down Expand Up @@ -75,11 +86,11 @@ impl MDBook {
}
}

MDBook::load_with_config(book_root, config)
MDBook::load_with_config(book_root, config, build_opts)
}

/// Load a book from its root directory using a custom `Config`.
pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config) -> Result<MDBook> {
/// Load a book from its root directory using a custom config.
pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config, build_opts: BuildOpts) -> Result<MDBook> {
let root = book_root.into();

let src_dir = root.join(&config.book.src);
Expand All @@ -92,6 +103,7 @@ impl MDBook {
root,
config,
book,
build_opts,
renderers,
preprocessors,
})
Expand All @@ -102,6 +114,7 @@ impl MDBook {
book_root: P,
config: Config,
summary: Summary,
build_opts: BuildOpts,
) -> Result<MDBook> {
let root = book_root.into();

Expand All @@ -115,6 +128,7 @@ impl MDBook {
root,
config,
book,
build_opts,
renderers,
preprocessors,
})
Expand Down Expand Up @@ -185,6 +199,7 @@ impl MDBook {
let mut preprocessed_book = self.book.clone();
let preprocess_ctx = PreprocessorContext::new(
self.root.clone(),
self.build_opts.clone(),
self.config.clone(),
renderer.name().to_string(),
);
Expand All @@ -201,7 +216,8 @@ impl MDBook {

let mut render_context = RenderContext::new(
self.root.clone(),
preprocessed_book,
preprocessed_book.clone(),
self.build_opts.clone(),
self.config.clone(),
build_dir,
);
Expand Down Expand Up @@ -241,7 +257,7 @@ impl MDBook {

// FIXME: Is "test" the proper renderer name to use here?
let preprocess_context =
PreprocessorContext::new(self.root.clone(), self.config.clone(), "test".to_string());
PreprocessorContext::new(self.root.clone(), self.build_opts.clone(), self.config.clone(), "test".to_string());

let book = LinkPreprocessor::new().run(&preprocess_context, self.book.clone())?;
// Index Preprocessor is disabled so that chapter paths continue to point to the
Expand Down Expand Up @@ -336,7 +352,8 @@ impl MDBook {

/// Get the directory containing this book's source files.
pub fn source_dir(&self) -> PathBuf {
self.root.join(&self.config.book.src)
let src = self.config.get_localized_src_path(self.build_opts.language_ident.as_ref()).unwrap();
self.root.join(src)
}

/// Get the directory containing the theme resources for the book.
Expand Down
10 changes: 10 additions & 0 deletions src/build_opts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Build options.
/// Build options passed from the frontend to control how the book is built.
/// Separate from `Config`, which is global to all book languages.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(default, rename_all = "kebab-case")]
pub struct BuildOpts {
/// Language of the book to render.
pub language_ident: Option<String>,
}
5 changes: 3 additions & 2 deletions src/cmd/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{get_book_dir, open};
use crate::{get_book_dir, get_build_opts, open};
use clap::{App, ArgMatches, SubCommand};
use mdbook::errors::Result;
use mdbook::MDBook;
Expand All @@ -22,7 +22,8 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
// Build command implementation
pub fn execute(args: &ArgMatches) -> Result<()> {
let book_dir = get_book_dir(args);
let mut book = MDBook::load(&book_dir)?;
let opts = get_build_opts(args);
let mut book = MDBook::load_with_build_opts(&book_dir, opts)?;

if let Some(dest_dir) = args.value_of("dest-dir") {
book.config.build.build_dir = dest_dir.into();
Expand Down
5 changes: 3 additions & 2 deletions src/cmd/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::get_book_dir;
use crate::{get_book_dir, get_build_opts};
use clap::{App, Arg, ArgMatches, SubCommand};
use mdbook::errors::Result;
use mdbook::MDBook;
Expand Down Expand Up @@ -34,7 +34,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
.map(std::iter::Iterator::collect)
.unwrap_or_default();
let book_dir = get_book_dir(args);
let mut book = MDBook::load(&book_dir)?;
let build_opts = get_build_opts(args);
let mut book = MDBook::load_with_build_opts(&book_dir, build_opts)?;

if let Some(dest_dir) = args.value_of("dest-dir") {
book.config.build.build_dir = dest_dir.into();
Expand Down
30 changes: 27 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,31 @@ impl Config {
self.get(&key).and_then(Value::as_table)
}

/// Get the source directory of a localized book corresponding to language ident `index`.
pub fn get_localized_src_path<I: AsRef<str>>(&self, index: Option<I>) -> Option<PathBuf> {
match self.language.default_language() {
Some(default) => match index {
// Make sure that the language we passed was actually
// declared in the config, and return `None` if not.
Some(lang_ident) => self.language.0.get(lang_ident.as_ref()).map(|_| {
let mut buf = PathBuf::new();
buf.push(self.book.src.clone());
buf.push(lang_ident.as_ref());
buf
}),
// Use the default specified in book.toml.
None => Some(PathBuf::from(default))
}

// No default language was configured in book.toml. Preserve
// backwards compatibility by just returning `src`.
None => match index {
Some(_) => None,
None => Some(self.book.src.clone()),
}
}
}

fn from_legacy(mut table: Value) -> Config {
let mut cfg = Config::default();

Expand Down Expand Up @@ -354,7 +379,6 @@ impl<'de> Deserialize<'de> for Config {
.count();

if default_languages != 1 {
use serde::de::Error;
return Err(D::Error::custom(
"If languages are specified, exactly one must be set as 'default'"
));
Expand Down Expand Up @@ -727,10 +751,10 @@ pub struct Language {

impl LanguageConfig {
/// Returns the default language specified in the config.
pub fn default_language(&self) -> Option<&Language> {
pub fn default_language(&self) -> Option<&String> {
self.0.iter()
.find(|(_, lang)| lang.default)
.map(|(_, lang)| lang)
.map(|(lang_ident, _)| lang_ident)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ extern crate serde_json;
extern crate pretty_assertions;

pub mod book;
pub mod build_opts;
pub mod config;
pub mod preprocess;
pub mod renderer;
Expand Down
9 changes: 9 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use clap::{App, AppSettings, Arg, ArgMatches, Shell, SubCommand};
use env_logger::Builder;
use log::LevelFilter;
use mdbook::utils;
use mdbook::build_opts::BuildOpts;
use std::env;
use std::ffi::OsStr;
use std::io::Write;
Expand Down Expand Up @@ -131,6 +132,14 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf {
}
}

fn get_build_opts(args: &ArgMatches) -> BuildOpts {
let language = args.value_of("language");

BuildOpts {
language_ident: language.map(String::from)
}
}

fn open<P: AsRef<OsStr>>(path: P) {
info!("Opening web browser");
if let Err(e) = open::that(path) {
Expand Down
2 changes: 2 additions & 0 deletions src/preprocess/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ impl Preprocessor for CmdPreprocessor {
mod tests {
use super::*;
use crate::MDBook;
use crate::build_opts::BuildOpts;
use std::path::Path;

fn guide() -> MDBook {
Expand All @@ -192,6 +193,7 @@ mod tests {
let md = guide();
let ctx = PreprocessorContext::new(
md.root.clone(),
BuildOpts::default(),
md.config.clone(),
"some-renderer".to_string(),
);
Expand Down
2 changes: 1 addition & 1 deletion src/preprocess/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl Preprocessor for IndexPreprocessor {
}

fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
let source_dir = ctx.root.join(&ctx.config.book.src);
let source_dir = ctx.source_dir();
book.for_each_mut(|section: &mut BookItem| {
if let BookItem::Chapter(ref mut ch) = *section {
if let Some(ref mut path) = ch.path {
Expand Down
2 changes: 1 addition & 1 deletion src/preprocess/links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl Preprocessor for LinkPreprocessor {
}

fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
let src_dir = ctx.root.join(&ctx.config.book.src);
let src_dir = ctx.source_dir();

book.for_each_mut(|section: &mut BookItem| {
if let BookItem::Chapter(ref mut ch) = *section {
Expand Down
12 changes: 11 additions & 1 deletion src/preprocess/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod links;

use crate::book::Book;
use crate::config::Config;
use crate::build_opts::BuildOpts;
use crate::errors::*;

use std::cell::RefCell;
Expand All @@ -22,6 +23,8 @@ use std::path::PathBuf;
pub struct PreprocessorContext {
/// The location of the book directory on disk.
pub root: PathBuf,
/// The build options passed from the frontend.
pub build_opts: BuildOpts,
/// The book configuration (`book.toml`).
pub config: Config,
/// The `Renderer` this preprocessor is being used with.
Expand All @@ -36,16 +39,23 @@ pub struct PreprocessorContext {

impl PreprocessorContext {
/// Create a new `PreprocessorContext`.
pub(crate) fn new(root: PathBuf, config: Config, renderer: String) -> Self {
pub(crate) fn new(root: PathBuf, build_opts: BuildOpts, config: Config, renderer: String) -> Self {
PreprocessorContext {
root,
build_opts,
config,
renderer,
mdbook_version: crate::MDBOOK_VERSION.to_string(),
chapter_titles: RefCell::new(HashMap::new()),
__non_exhaustive: (),
}
}

/// Get the directory containing this book's source files.
pub fn source_dir(&self) -> PathBuf {
let src = self.config.get_localized_src_path(self.build_opts.language_ident.as_ref()).unwrap();
self.root.join(src)
}
}

/// An operation which is run immediately after loading a book into memory and
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/html_handlebars/hbs_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ impl Renderer for HtmlHandlebars {
fn render(&self, ctx: &RenderContext) -> Result<()> {
let book_config = &ctx.config.book;
let html_config = ctx.config.html_config().unwrap_or_default();
let src_dir = ctx.root.join(&ctx.config.book.src);
let src_dir = ctx.source_dir();
let destination = &ctx.destination;
let book = &ctx.book;
let build_dir = ctx.root.join(&ctx.config.build.build_dir);
Expand Down
9 changes: 7 additions & 2 deletions src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::process::{Command, Stdio};

use crate::book::Book;
use crate::config::Config;
use crate::build_opts::BuildOpts;
use crate::errors::*;
use toml::Value;

Expand Down Expand Up @@ -58,6 +59,8 @@ pub struct RenderContext {
pub root: PathBuf,
/// A loaded representation of the book itself.
pub book: Book,
/// The build options passed from the frontend.
pub build_opts: BuildOpts,
/// The loaded configuration file.
pub config: Config,
/// Where the renderer *must* put any build artefacts generated. To allow
Expand All @@ -72,13 +75,14 @@ pub struct RenderContext {

impl RenderContext {
/// Create a new `RenderContext`.
pub fn new<P, Q>(root: P, book: Book, config: Config, destination: Q) -> RenderContext
pub fn new<P, Q>(root: P, book: Book, build_opts: BuildOpts, config: Config, destination: Q) -> RenderContext
where
P: Into<PathBuf>,
Q: Into<PathBuf>,
{
RenderContext {
book,
build_opts,
config,
version: crate::MDBOOK_VERSION.to_string(),
root: root.into(),
Expand All @@ -90,7 +94,8 @@ impl RenderContext {

/// Get the source directory's (absolute) path on disk.
pub fn source_dir(&self) -> PathBuf {
self.root.join(&self.config.book.src)
let src = self.config.get_localized_src_path(self.build_opts.language_ident.as_ref()).unwrap();
self.root.join(src)
}

/// Load a `RenderContext` from its JSON representation.
Expand Down
7 changes: 5 additions & 2 deletions tests/build_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod dummy_book;

use crate::dummy_book::DummyBook;
use mdbook::book::Book;
use mdbook::build_opts::BuildOpts;
use mdbook::config::Config;
use mdbook::errors::*;
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
Expand Down Expand Up @@ -48,8 +49,9 @@ fn mdbook_runs_preprocessors() {

let temp = DummyBook::new().build().unwrap();
let cfg = Config::default();
let build_opts = BuildOpts::default();

let mut book = MDBook::load_with_config(temp.path(), cfg).unwrap();
let mut book = MDBook::load_with_config(temp.path(), cfg, build_opts).unwrap();
book.with_preprocessor(Spy(Arc::clone(&spy)));
book.build().unwrap();

Expand All @@ -68,8 +70,9 @@ fn mdbook_runs_renderers() {

let temp = DummyBook::new().build().unwrap();
let cfg = Config::default();
let build_opts = BuildOpts::default();

let mut book = MDBook::load_with_config(temp.path(), cfg).unwrap();
let mut book = MDBook::load_with_config(temp.path(), cfg, build_opts).unwrap();
book.with_renderer(Spy(Arc::clone(&spy)));
book.build().unwrap();

Expand Down
Loading

0 comments on commit 24e6d6b

Please sign in to comment.