Made sure the dummy book can build

This commit is contained in:
Michael Bryan 2017-11-18 22:07:08 +08:00
parent 8b21da9950
commit 21498631b3
No known key found for this signature in database
GPG Key ID: E9C602B0D9A998DC
7 changed files with 57 additions and 64 deletions

View File

@ -1,3 +1,4 @@
[book]
title = "mdBook Documentation" title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust" description = "Create book from markdown files. Like Gitbook but implemented in Rust"
author = "Mathieu David" author = "Mathieu David"

View File

@ -3,7 +3,6 @@ use std::io::Write;
use clap::{App, ArgMatches, SubCommand}; use clap::{App, ArgMatches, SubCommand};
use mdbook::MDBook; use mdbook::MDBook;
use mdbook::errors::Result; use mdbook::errors::Result;
use mdbook::config::Config;
use get_book_dir; use get_book_dir;
// Create clap subcommand arguments // Create clap subcommand arguments

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::Read;
use super::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem}; use super::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
use errors::*; use errors::*;
@ -14,9 +14,8 @@ pub fn load_book<P: AsRef<Path>>(src_dir: P) -> Result<Book> {
let summary_md = src_dir.join("SUMMARY.md"); let summary_md = src_dir.join("SUMMARY.md");
let mut summary_content = String::new(); let mut summary_content = String::new();
File::open(summary_md) File::open(summary_md).chain_err(|| "Couldn't open SUMMARY.md")?
.chain_err(|| "Couldn't open SUMMARY.md")? .read_to_string(&mut summary_content)?;
.read_to_string(&mut summary_content)?;
let summary = parse_summary(&summary_content).chain_err(|| "Summary parsing failed")?; let summary = parse_summary(&summary_content).chain_err(|| "Summary parsing failed")?;
@ -111,10 +110,7 @@ fn load_book_from_disk<P: AsRef<Path>>(summary: &Summary, src_dir: P) -> Result<
fn load_summary_item<P: AsRef<Path>>(item: &SummaryItem, src_dir: P) -> Result<BookItem> { fn load_summary_item<P: AsRef<Path>>(item: &SummaryItem, src_dir: P) -> Result<BookItem> {
match *item { match *item {
SummaryItem::Separator => Ok(BookItem::Separator), SummaryItem::Separator => Ok(BookItem::Separator),
SummaryItem::Link(ref link) => { SummaryItem::Link(ref link) => load_chapter(link, src_dir).map(|c| BookItem::Chapter(c)),
let file = src_dir.as_ref().join(&link.location);
load_chapter(link, src_dir).map(|c| BookItem::Chapter(c))
},
} }
} }
@ -128,22 +124,22 @@ fn load_chapter<P: AsRef<Path>>(link: &Link, src_dir: P) -> Result<Chapter> {
src_dir.join(&link.location) src_dir.join(&link.location)
}; };
let mut f = File::open(&location).chain_err(|| format!("Chapter file not found, {}", link.location.display()))?; let mut f = File::open(&location).chain_err(|| {
format!("Chapter file not found, {}", link.location.display())
})?;
let mut content = String::new(); let mut content = String::new();
f.read_to_string(&mut content)?; f.read_to_string(&mut content)?;
let stripped = location let stripped = location.strip_prefix(&src_dir)
.strip_prefix(&src_dir) .expect("Chapters are always inside a book");
.expect("Chapters are always inside a book");
let mut ch = Chapter::new(&link.name, content, stripped); let mut ch = Chapter::new(&link.name, content, stripped);
ch.number = link.number.clone(); ch.number = link.number.clone();
let sub_items = link.nested_items let sub_items = link.nested_items.iter()
.iter() .map(|i| load_summary_item(i, src_dir))
.map(|i| load_summary_item(i, src_dir)) .collect::<Result<Vec<_>>>()?;
.collect::<Result<Vec<_>>>()?;
ch.sub_items = sub_items; ch.sub_items = sub_items;
@ -195,14 +191,14 @@ mod tests {
use super::*; use super::*;
use tempdir::TempDir; use tempdir::TempDir;
use std::io::Write; use std::io::Write;
use std::fs;
const DUMMY_SRC: &'static str = " const DUMMY_SRC: &'static str = "
# Dummy Chapter # Dummy Chapter
this is some dummy text. this is some dummy text.
And here is some more text. And here is some \
more text.
"; ";
/// Create a dummy `Link` in a temporary directory. /// Create a dummy `Link` in a temporary directory.
@ -210,10 +206,9 @@ And here is some more text.
let temp = TempDir::new("book").unwrap(); let temp = TempDir::new("book").unwrap();
let chapter_path = temp.path().join("chapter_1.md"); let chapter_path = temp.path().join("chapter_1.md");
File::create(&chapter_path) File::create(&chapter_path).unwrap()
.unwrap() .write(DUMMY_SRC.as_bytes())
.write(DUMMY_SRC.as_bytes()) .unwrap();
.unwrap();
let link = Link::new("Chapter 1", chapter_path); let link = Link::new("Chapter 1", chapter_path);
@ -226,10 +221,9 @@ And here is some more text.
let second_path = temp_dir.path().join("second.md"); let second_path = temp_dir.path().join("second.md");
File::create(&second_path) File::create(&second_path).unwrap()
.unwrap() .write_all("Hello World!".as_bytes())
.write_all("Hello World!".as_bytes()) .unwrap();
.unwrap();
let mut second = Link::new("Nested Chapter 1", &second_path); let mut second = Link::new("Nested Chapter 1", &second_path);
@ -339,9 +333,17 @@ And here is some more text.
number: None, number: None,
path: PathBuf::from("Chapter_1/index.md"), path: PathBuf::from("Chapter_1/index.md"),
sub_items: vec![ sub_items: vec![
BookItem::Chapter(Chapter::new("Hello World", String::new(), "Chapter_1/hello.md")), BookItem::Chapter(Chapter::new(
"Hello World",
String::new(),
"Chapter_1/hello.md",
)),
BookItem::Separator, BookItem::Separator,
BookItem::Chapter(Chapter::new("Goodbye World", String::new(), "Chapter_1/goodbye.md")), BookItem::Chapter(Chapter::new(
"Goodbye World",
String::new(),
"Chapter_1/goodbye.md",
)),
], ],
}), }),
BookItem::Separator, BookItem::Separator,
@ -354,12 +356,11 @@ And here is some more text.
assert_eq!(got.len(), 5); assert_eq!(got.len(), 5);
// checking the chapter names are in the order should be sufficient here... // checking the chapter names are in the order should be sufficient here...
let chapter_names: Vec<String> = got.into_iter() let chapter_names: Vec<String> = got.into_iter().filter_map(|i| match *i {
.filter_map(|i| match *i { BookItem::Chapter(ref ch) => Some(ch.name.clone()),
BookItem::Chapter(ref ch) => Some(ch.name.clone()), _ => None,
_ => None, })
}) .collect();
.collect();
let should_be: Vec<_> = vec![ let should_be: Vec<_> = vec![
String::from("Chapter 1"), String::from("Chapter 1"),
String::from("Hello World"), String::from("Hello World"),

View File

@ -6,12 +6,11 @@ pub use self::book::{Book, BookItem, BookItems, Chapter};
pub use self::init::BookBuilder; pub use self::init::BookBuilder;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::Write; use std::io::Write;
use std::process::Command; use std::process::Command;
use tempdir::TempDir; use tempdir::TempDir;
use {theme, utils}; use utils;
use renderer::{HtmlHandlebars, Renderer}; use renderer::{HtmlHandlebars, Renderer};
use preprocess; use preprocess;
use errors::*; use errors::*;
@ -104,17 +103,14 @@ impl MDBook {
BookBuilder::new(book_root) BookBuilder::new(book_root)
} }
/// The `build()` method is the one where everything happens. /// Tells the renderer to build our book and put it in the build directory.
/// First it parses `SUMMARY.md` to construct the book's structure
/// in the form of a `Vec<BookItem>` and then calls `render()`
/// method of the current renderer.
///
/// It is the renderer who generates all the output files.
pub fn build(&mut self) -> Result<()> { pub fn build(&mut self) -> Result<()> {
debug!("[fn]: build"); debug!("[fn]: build");
// Clean output directory let dest = self.get_destination();
utils::fs::remove_dir_content(&self.get_destination())?; if dest.exists() {
utils::fs::remove_dir_content(&dest).chain_err(|| "Unable to clear output directory")?;
}
self.renderer.render(self) self.renderer.render(self)
} }
@ -122,9 +118,8 @@ impl MDBook {
pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> { pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
let path = self.get_destination().join(filename); let path = self.get_destination().join(filename);
utils::fs::create_file(&path)? utils::fs::create_file(&path)?.write_all(content)
.write_all(content) .map_err(|e| e.into())
.map_err(|e| e.into())
} }
/// Parses the `book.json` file (if it exists) to extract /// Parses the `book.json` file (if it exists) to extract
@ -175,18 +170,16 @@ impl MDBook {
} }
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
let library_args: Vec<&str> = (0..library_paths.len()) let library_args: Vec<&str> = (0..library_paths.len()).map(|_| "-L")
.map(|_| "-L") .zip(library_paths.into_iter())
.zip(library_paths.into_iter()) .flat_map(|x| vec![x.0, x.1])
.flat_map(|x| vec![x.0, x.1]) .collect();
.collect();
let temp_dir = TempDir::new("mdbook")?; let temp_dir = TempDir::new("mdbook")?;
for item in self.iter() { for item in self.iter() {
if let BookItem::Chapter(ref ch) = *item { if let BookItem::Chapter(ref ch) = *item {
if !ch.path.as_os_str().is_empty() { if !ch.path.as_os_str().is_empty() {
let path = self.get_source().join(&ch.path); let path = self.get_source().join(&ch.path);
let base = path.parent() let base = path.parent().ok_or_else(|| String::from("Invalid bookitem path!"))?;
.ok_or_else(|| String::from("Invalid bookitem path!"))?;
let content = utils::fs::file_to_string(&path)?; let content = utils::fs::file_to_string(&path)?;
// Parse and expand links // Parse and expand links
let content = preprocess::links::replace_all(&content, base)?; let content = preprocess::links::replace_all(&content, base)?;
@ -197,11 +190,10 @@ impl MDBook {
let mut tmpf = utils::fs::create_file(&path)?; let mut tmpf = utils::fs::create_file(&path)?;
tmpf.write_all(content.as_bytes())?; tmpf.write_all(content.as_bytes())?;
let output = Command::new("rustdoc") let output = Command::new("rustdoc").arg(&path)
.arg(&path) .arg("--test")
.arg("--test") .args(&library_args)
.args(&library_args) .output()?;
.output()?;
if !output.status.success() { if !output.status.success() {
bail!(ErrorKind::Subprocess( bail!(ErrorKind::Subprocess(

View File

@ -370,8 +370,9 @@ impl<'a> SummaryParser<'a> {
} }
} }
}, },
Event::End(Tag::Item) => { /* Ignore */ },
other => { other => {
trace!("[*] skipping unexpected token: {:?}", other); trace!("[*] ignoring token: {:?}", other);
}, },
} }

View File

@ -4,7 +4,6 @@
- [First Chapter](./first/index.md) - [First Chapter](./first/index.md)
- [Nested Chapter](./first/nested.md) - [Nested Chapter](./first/nested.md)
---
- [Second Chapter](./second.md) - [Second Chapter](./second.md)
[Conclusion](./conclusion.md) [Conclusion](./conclusion.md)

View File

@ -18,7 +18,7 @@ fn base_mdbook_init_should_create_default_content() {
assert!(!temp.path().join(file).exists()); assert!(!temp.path().join(file).exists());
} }
let md = MDBook::init(temp.path()).build().unwrap(); MDBook::init(temp.path()).build().unwrap();
for file in &created_files { for file in &created_files {
let target = temp.path().join(file); let target = temp.path().join(file);