Added a flag to create missing files

This commit is contained in:
Michael Bryan 2017-08-28 03:09:47 +08:00
parent b530b673c9
commit af8a5483b8
3 changed files with 46 additions and 19 deletions

View File

@ -2,14 +2,14 @@ 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; use std::io::{Read, Write};
use super::summary::{parse_summary, Summary, Link, SummaryItem, SectionNumber}; use super::summary::{parse_summary, Summary, Link, SummaryItem, SectionNumber};
use errors::*; use errors::*;
/// Load a book into memory from its `src/` directory. /// Load a book into memory from its `src/` directory.
pub fn load_book<P: AsRef<Path>>(src_dir: P) -> Result<Book> { pub fn load_book<P: AsRef<Path>>(src_dir: P, create_if_not_present: bool) -> Result<Book> {
let src_dir = src_dir.as_ref(); let src_dir = src_dir.as_ref();
let summary_md = src_dir.join("SUMMARY.md"); let summary_md = src_dir.join("SUMMARY.md");
@ -18,11 +18,9 @@ pub fn load_book<P: AsRef<Path>>(src_dir: P) -> Result<Book> {
.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( let summary = parse_summary(&summary_content).chain_err(|| "Summary parsing failed")?;
|| "Summary parsing failed",
)?;
load_book_from_disk(&summary, src_dir) load_book_from_disk(&summary, src_dir, create_if_not_present)
} }
@ -88,7 +86,7 @@ impl Chapter {
/// ///
/// You need to pass in the book's source directory because all the links in /// You need to pass in the book's source directory because all the links in
/// `SUMMARY.md` give the chapter locations relative to it. /// `SUMMARY.md` give the chapter locations relative to it.
fn load_book_from_disk<P: AsRef<Path>>(summary: &Summary, src_dir: P) -> Result<Book> { fn load_book_from_disk<P: AsRef<Path>>(summary: &Summary, src_dir: P, create_if_not_present: bool) -> Result<Book> {
debug!("[*] Loading the book from disk"); debug!("[*] Loading the book from disk");
let src_dir = src_dir.as_ref(); let src_dir = src_dir.as_ref();
@ -98,18 +96,29 @@ fn load_book_from_disk<P: AsRef<Path>>(summary: &Summary, src_dir: P) -> Result<
let summary_items = prefix.chain(numbered).chain(suffix); let summary_items = prefix.chain(numbered).chain(suffix);
let chapters = summary_items let mut chapters = Vec::new();
.map(|i| load_summary_item(i, src_dir))
.collect::<Result<_>>() for summary_item in summary_items {
.chain_err(|| "Couldn't load chapters from disk")?; let chapter = load_summary_item(summary_item, src_dir, create_if_not_present)?;
chapters.push(chapter);
}
Ok(Book { sections: chapters }) Ok(Book { sections: chapters })
} }
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, create_if_not_present: bool) -> Result<BookItem> {
match *item { match *item {
SummaryItem::Separator => Ok(BookItem::Separator), SummaryItem::Separator => Ok(BookItem::Separator),
SummaryItem::Link(ref link) => load_chapter(link, src_dir).map(|c| BookItem::Chapter(c)), SummaryItem::Link(ref link) => {
let file = src_dir.as_ref().join(&link.location);
if create_if_not_present && !file.exists() {
let text = format!("# {}", link.name);
File::create(&file)?.write_all(text.as_bytes())?;
}
load_chapter(link, src_dir).map(|c| BookItem::Chapter(c))
},
} }
} }
@ -137,7 +146,7 @@ fn load_chapter<P: AsRef<Path>>(link: &Link, src_dir: P) -> Result<Chapter> {
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, false))
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
ch.sub_items = sub_items; ch.sub_items = sub_items;
@ -190,6 +199,7 @@ 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
@ -276,7 +286,7 @@ And here is some more text.
], ],
}); });
let got = load_summary_item(&SummaryItem::Link(root), temp.path()).unwrap(); let got = load_summary_item(&SummaryItem::Link(root), temp.path(), false).unwrap();
assert_eq!(got, should_be); assert_eq!(got, should_be);
} }
@ -298,7 +308,7 @@ And here is some more text.
], ],
}; };
let got = load_book_from_disk(&summary, temp.path()).unwrap(); let got = load_book_from_disk(&summary, temp.path(), false).unwrap();
assert_eq!(got, should_be); assert_eq!(got, should_be);
} }
@ -362,4 +372,21 @@ And here is some more text.
assert_eq!(chapter_names, should_be); assert_eq!(chapter_names, should_be);
} }
#[test]
fn create_missing_book_items() {
let (link, temp) = dummy_link();
let summary = Summary {
numbered_chapters: vec![SummaryItem::Link(link)],
..Default::default()
};
let chapter_1 = temp.path().join("chapter_1.md");
fs::remove_file(&chapter_1).unwrap();
assert!(!chapter_1.exists());
load_book_from_disk(&summary, temp.path(), true).unwrap();
assert!(chapter_1.exists());
}
} }

View File

@ -495,7 +495,7 @@ impl MDBook {
// Construct book // Construct book
fn parse_summary(&mut self) -> Result<()> { fn parse_summary(&mut self) -> Result<()> {
let src = self.config.get_source(); let src = self.config.get_source();
let book = load_book(&src)?; let book = load_book(&src, self.create_missing)?;
self.content = Some(book); self.content = Some(book);
Ok(()) Ok(())

View File

@ -16,6 +16,6 @@ fn load_the_example_book() {
.join("book-example") .join("book-example")
.join("src"); .join("src");
let book = load_book(example_src_dir).unwrap(); let book = load_book(example_src_dir, false).unwrap();
println!("{:#?}", book); println!("{:#?}", book);
} }