Incorporated Budziq's feedback

This commit is contained in:
Michael Bryan 2017-08-31 18:00:21 +08:00
parent 98a8ce934b
commit f8cec4cef3
4 changed files with 79 additions and 64 deletions

View File

@ -44,7 +44,7 @@ ws = { version = "0.7", optional = true}
error-chain = "0.11" error-chain = "0.11"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "0.2.1" pretty_assertions = "0.2"
[features] [features]
default = ["output", "watch", "serve"] default = ["output", "watch", "serve"]

View File

@ -24,9 +24,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
None => book, None => book,
}; };
if args.is_present("create") { book.create_missing = args.is_present("create");
book.create_missing = true;
}
if args.is_present("curly-quotes") { if args.is_present("curly-quotes") {
book = book.with_curly_quotes(true); book = book.with_curly_quotes(true);

View File

@ -13,7 +13,7 @@ use std::process::Command;
use tempdir::TempDir; use tempdir::TempDir;
use {theme, utils}; use {theme, utils};
use renderer::{Renderer, HtmlHandlebars}; use renderer::{HtmlHandlebars, Renderer};
use preprocess; use preprocess;
use errors::*; use errors::*;
@ -23,7 +23,10 @@ use config::htmlconfig::HtmlConfig;
use config::jsonconfig::JsonConfig; use config::jsonconfig::JsonConfig;
/// A helper for managing the `Book`, its configuration, and the rendering const STUB_SUMMARY_CONTENTS: &'static str = "# Summary\n\n- [Chapter 1](./chapter_1.md)]";
const STUB_CHAPTER_1: &'static str = "# Chapter 1\n";
/// A helper for managing the `Book`, its configuration, and the rendering
/// process. /// process.
pub struct MDBook { pub struct MDBook {
config: BookConfig, config: BookConfig,
@ -67,7 +70,6 @@ impl MDBook {
/// [`set_dest()`](#method.set_dest) /// [`set_dest()`](#method.set_dest)
pub fn new<P: Into<PathBuf>>(root: P) -> MDBook { pub fn new<P: Into<PathBuf>>(root: P) -> MDBook {
let root = root.into(); let root = root.into();
if !root.exists() || !root.is_dir() { if !root.exists() || !root.is_dir() {
warn!("{:?} No directory with that name", root); warn!("{:?} No directory with that name", root);
@ -114,8 +116,10 @@ impl MDBook {
/// ``` /// ```
pub fn iter(&self) -> BookItems { pub fn iter(&self) -> BookItems {
self.content.as_ref().expect("Trying to iterate over a book before it is loaded. This is a bug") self.content
.iter() .as_ref()
.expect("Trying to iterate over a book before it is loaded. This is a bug")
.iter()
} }
/// `init()` creates some boilerplate files and directories /// `init()` creates some boilerplate files and directories
@ -132,64 +136,73 @@ impl MDBook {
/// It uses the paths given as source and output directories /// It uses the paths given as source and output directories
/// and adds a `SUMMARY.md` and a /// and adds a `SUMMARY.md` and a
/// `chapter_1.md` to the source directory. /// `chapter_1.md` to the source directory.
pub fn init(&mut self) -> Result<()> { pub fn init(&mut self) -> Result<()> {
debug!("[fn]: init"); debug!("[fn]: init");
{ self.create_book_directories()?;
let root = self.config.get_root(); self.create_stub_files()?;
let dest = self.get_destination();
let src = self.config.get_source();
let necessary_folders = &[root, dest, src]; self.parse_summary()
.chain_err(|| "Couldn't parse the SUMMARY.md file")?;
for folder in necessary_folders {
if !folder.exists() {
fs::create_dir_all(folder)?;
debug!("{} created", folder.display());
}
}
let summary = src.join("SUMMARY.md"); debug!("[*]: init done");
Ok(())
}
if !summary.exists() { fn create_book_directories(&self) -> Result<()> {
debug!("[*]: Creating SUMMARY.md"); debug!("[*] Creating directories");
let mut f = File::create(&summary)?; let root = self.config.get_root();
let dest = self.get_destination();
let src = self.config.get_source();
writeln!(f, "# Summary")?; let necessary_folders = &[root, dest, src];
writeln!(f)?;
writeln!(f, "- [Chapter 1](./chapter_1.md)")?;
}
let ch_1 = src.join("chapter_1.md"); for folder in necessary_folders {
if !ch_1.exists() { if !folder.exists() {
debug!("[*] Creating {}", ch_1.display()); fs::create_dir_all(folder)?;
debug!("{} created", folder.display());
let mut f = File::create(&ch_1)?;
writeln!(f, "# Chapter 1")?;
} }
} }
// parse SUMMARY.md and load the newly created files into memory Ok(())
self.parse_summary().chain_err(|| "Couldn't parse the SUMMARY.md file")?; }
fn create_stub_files(&self) -> Result<()> {
debug!("[*] Creating stub files");
let src = self.config.get_source();
let summary = src.join("SUMMARY.md");
if !summary.exists() {
debug!("[*]: Creating SUMMARY.md");
let mut f = File::create(&summary)?;
writeln!(f, "{}", STUB_SUMMARY_CONTENTS)?;
}
let ch_1 = src.join("chapter_1.md");
if !ch_1.exists() {
debug!("[*] Creating {}", ch_1.display());
let mut f = File::create(&ch_1)?;
writeln!(f, "{}", STUB_CHAPTER_1)?;
}
debug!("[*]: init done");
Ok(()) Ok(())
} }
pub fn create_gitignore(&self) { pub fn create_gitignore(&self) {
let gitignore = self.get_gitignore(); let gitignore = self.get_gitignore();
let destination = self.config.get_html_config() let destination = self.config.get_html_config().get_destination();
.get_destination();
// Check that the gitignore does not extist and that the destination path begins with the root path // Check that the gitignore does not exist and that the destination path
// We assume tha if it does begin with the root path it is contained within. This assumption // begins with the root path
// will not hold true for paths containing double dots to go back up e.g. `root/../destination` // We assume tha if it does begin with the root path it is contained within.
// This assumption
// will not hold true for paths containing double dots to go back up e.g.
// `root/../destination`
if !gitignore.exists() && destination.starts_with(self.config.get_root()) { if !gitignore.exists() && destination.starts_with(self.config.get_root()) {
let relative = destination let relative = destination
.strip_prefix(self.config.get_root()) .strip_prefix(self.config.get_root())
.expect("Could not strip the root prefix, path is not relative to root") .expect("Could not strip the root prefix, path is not relative to root")
@ -223,7 +236,6 @@ impl MDBook {
self.renderer.render(self) self.renderer.render(self)
} }
pub fn get_gitignore(&self) -> PathBuf { pub fn get_gitignore(&self) -> PathBuf {
self.config.get_root().join(".gitignore") self.config.get_root().join(".gitignore")
} }
@ -265,8 +277,7 @@ 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() let path = self.get_destination().join(filename);
.join(filename);
utils::fs::create_file(&path)? utils::fs::create_file(&path)?
.write_all(content) .write_all(content)
@ -279,7 +290,6 @@ impl MDBook {
/// The root directory is the one specified when creating a new `MDBook` /// The root directory is the one specified when creating a new `MDBook`
pub fn read_config(mut self) -> Result<Self> { pub fn read_config(mut self) -> Result<Self> {
let toml = self.get_root().join("book.toml"); let toml = self.get_root().join("book.toml");
let json = self.get_root().join("book.json"); let json = self.get_root().join("book.json");
@ -335,31 +345,33 @@ impl MDBook {
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
// read in the chapters // read in the chapters
self.parse_summary().chain_err(|| "Couldn't parse summary")?; self.parse_summary().chain_err(|| "Couldn't parse summary")?;
let library_args: Vec<&str> = (0..library_paths.len()).map(|_| "-L") let library_args: Vec<&str> = (0..library_paths.len())
.zip(library_paths.into_iter()) .map(|_| "-L")
.flat_map(|x| vec![x.0, x.1]) .zip(library_paths.into_iter())
.collect(); .flat_map(|x| vec![x.0, x.1])
.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 != PathBuf::new() { if ch.path != PathBuf::new() {
let path = self.get_source().join(&ch.path); let path = self.get_source().join(&ch.path);
let base = path.parent().ok_or_else( let base = path.parent()
|| 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)?;
println!("[*]: Testing file: {:?}", path); println!("[*]: Testing file: {:?}", path);
//write preprocessed file to tempdir // write preprocessed file to tempdir
let path = temp_dir.path().join(&ch.path); let path = temp_dir.path().join(&ch.path);
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").arg(&path).arg("--test").args(&library_args).output()?; let output = Command::new("rustdoc")
.arg(&path)
.arg("--test")
.args(&library_args)
.output()?;
if !output.status.success() { if !output.status.success() {
bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(), output)); bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(), output));
@ -377,15 +389,15 @@ impl MDBook {
pub fn with_destination<T: Into<PathBuf>>(mut self, destination: T) -> Self { pub fn with_destination<T: Into<PathBuf>>(mut self, destination: T) -> Self {
let root = self.config.get_root().to_owned(); let root = self.config.get_root().to_owned();
self.config.get_mut_html_config() self.config
.get_mut_html_config()
.set_destination(&root, &destination.into()); .set_destination(&root, &destination.into());
self self
} }
pub fn get_destination(&self) -> &Path { pub fn get_destination(&self) -> &Path {
self.config.get_html_config() self.config.get_html_config().get_destination()
.get_destination()
} }
pub fn with_source<T: Into<PathBuf>>(mut self, source: T) -> Self { pub fn with_source<T: Into<PathBuf>>(mut self, source: T) -> Self {

View File

@ -322,6 +322,11 @@ impl<'a> SummaryParser<'a> {
let section_number = self.push_numbered_section(SummaryItem::Link(it)); let section_number = self.push_numbered_section(SummaryItem::Link(it));
trace!("[*] Section number is {}", section_number); trace!("[*] Section number is {}", section_number);
}, },
Event::End(Tag::Rule) => {
debug!("[*] Found a numbered chapter separator");
self.summary.numbered_chapters.push(SummaryItem::Separator);
self.state = State::NumberedChapters(0);
},
Event::Start(Tag::List(_)) => { Event::Start(Tag::List(_)) => {
if let State::NumberedChapters(n) = self.state { if let State::NumberedChapters(n) = self.state {
self.state = State::NumberedChapters(n + 1); self.state = State::NumberedChapters(n + 1);