Added error-chain to the book and utils modules

This commit is contained in:
Michael Bryan 2017-06-25 00:04:57 +08:00
parent 0f93cd002b
commit 1356e0f068
4 changed files with 33 additions and 36 deletions

View file

@ -2,6 +2,8 @@ use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use std::path::PathBuf; use std::path::PathBuf;
use errors::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum BookItem { pub enum BookItem {
Chapter(String, Chapter), // String = section Chapter(String, Chapter), // String = section
@ -37,7 +39,7 @@ impl Chapter {
impl Serialize for Chapter { impl Serialize for Chapter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where S: Serializer where S: Serializer
{ {
let mut struct_ = serializer.serialize_struct("Chapter", 2)?; let mut struct_ = serializer.serialize_struct("Chapter", 2)?;

View file

@ -4,14 +4,12 @@ pub use self::bookitem::{BookItem, BookItems};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::fs::{self, File}; use std::fs::{self, File};
use std::error::Error; use std::io::{self, Read, Write};
use std::io;
use std::io::{Read, Write};
use std::io::ErrorKind;
use std::process::Command; use std::process::Command;
use {theme, parse, utils}; use {theme, parse, utils};
use renderer::{Renderer, HtmlHandlebars}; use renderer::{Renderer, HtmlHandlebars};
use errors::*;
use config::BookConfig; use config::BookConfig;
use config::tomlconfig::TomlConfig; use config::tomlconfig::TomlConfig;
@ -129,7 +127,7 @@ impl MDBook {
/// 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<(), Box<Error>> { pub fn init(&mut self) -> Result<()> {
debug!("[fn]: init"); debug!("[fn]: init");
@ -239,7 +237,7 @@ impl MDBook {
/// method of the current renderer. /// method of the current renderer.
/// ///
/// It is the renderer who generates all the output files. /// It is the renderer who generates all the output files.
pub fn build(&mut self) -> Result<(), Box<Error>> { pub fn build(&mut self) -> Result<()> {
debug!("[fn]: build"); debug!("[fn]: build");
self.init()?; self.init()?;
@ -249,9 +247,7 @@ impl MDBook {
utils::fs::remove_dir_content(htmlconfig.get_destination())?; utils::fs::remove_dir_content(htmlconfig.get_destination())?;
} }
self.renderer.render(&self)?; self.renderer.render(&self)
Ok(())
} }
@ -259,7 +255,7 @@ impl MDBook {
self.config.get_root().join(".gitignore") self.config.get_root().join(".gitignore")
} }
pub fn copy_theme(&self) -> Result<(), Box<Error>> { pub fn copy_theme(&self) -> Result<()> {
debug!("[fn]: copy_theme"); debug!("[fn]: copy_theme");
if let Some(htmlconfig) = self.config.get_html_config() { if let Some(htmlconfig) = self.config.get_html_config() {
@ -298,16 +294,14 @@ impl MDBook {
Ok(()) Ok(())
} }
pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<(), Box<Error>> { pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
let path = self.get_destination() let path = self.get_destination()
.ok_or(String::from("HtmlConfig not set, could not find a destination"))? .ok_or(String::from("HtmlConfig not set, could not find a destination"))?
.join(filename); .join(filename);
utils::fs::create_file(&path) utils::fs::create_file(&path)?
.and_then(|mut file| file.write_all(content)) .write_all(content)
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Could not create {}: {}", path.display(), e)))?; .map_err(|e| e.into())
Ok(())
} }
/// Parses the `book.json` file (if it exists) to extract /// Parses the `book.json` file (if it exists) to extract
@ -315,7 +309,7 @@ impl MDBook {
/// The `book.json` file should be in the root directory of the book. /// The `book.json` file should be in the root directory of the book.
/// 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, Box<Error>> { 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");
@ -369,9 +363,9 @@ impl MDBook {
self self
} }
pub fn test(&mut self) -> Result<(), Box<Error>> { pub fn test(&mut self) -> Result<()> {
// read in the chapters // read in the chapters
self.parse_summary()?; self.parse_summary().chain_err(|| "Couldn't parse summary")?;
for item in self.iter() { for item in self.iter() {
if let BookItem::Chapter(_, ref ch) = *item { if let BookItem::Chapter(_, ref ch) = *item {
@ -381,15 +375,10 @@ impl MDBook {
println!("[*]: Testing file: {:?}", path); println!("[*]: Testing file: {:?}", path);
let output_result = Command::new("rustdoc").arg(&path).arg("--test").output(); let output = Command::new("rustdoc").arg(&path).arg("--test").output()?;
let output = output_result?;
if !output.status.success() { if !output.status.success() {
return Err(Box::new(io::Error::new(ErrorKind::Other, bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(), output));
format!("{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)))) as
Box<Error>);
} }
} }
} }
@ -539,7 +528,7 @@ impl MDBook {
} }
// Construct book // Construct book
fn parse_summary(&mut self) -> Result<(), Box<Error>> { fn parse_summary(&mut self) -> Result<()> {
// When append becomes stable, use self.content.append() ... // When append becomes stable, use self.content.append() ...
self.content = parse::construct_bookitems(&self.get_source().join("SUMMARY.md"))?; self.content = parse::construct_bookitems(&self.get_source().join("SUMMARY.md"))?;
Ok(()) Ok(())

View file

@ -100,5 +100,11 @@ pub mod errors {
foreign_links { foreign_links {
Io(::std::io::Error); Io(::std::io::Error);
} }
errors {
Subprocess(message: String, output: ::std::process::Output) {
description("A subprocess failed")
}
}
} }
} }

View file

@ -1,16 +1,16 @@
use std::path::{Path, PathBuf, Component}; use std::path::{Path, PathBuf, Component};
use std::error::Error; use errors::*;
use std::io::{self, Read}; use std::io::{self, Read};
use std::fs::{self, File}; use std::fs::{self, File};
/// Takes a path to a file and try to read the file into a String /// Takes a path to a file and try to read the file into a String
pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> { pub fn file_to_string(path: &Path) -> Result<String> {
let mut file = match File::open(path) { let mut file = match File::open(path) {
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(e) => {
debug!("[*]: Failed to open {:?}", path); debug!("[*]: Failed to open {:?}", path);
return Err(Box::new(e)); bail!(e);
}, },
}; };
@ -18,7 +18,7 @@ pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
if let Err(e) = file.read_to_string(&mut content) { if let Err(e) = file.read_to_string(&mut content) {
debug!("[*]: Failed to read {:?}", path); debug!("[*]: Failed to read {:?}", path);
return Err(Box::new(e)); bail!(e);
} }
Ok(content) Ok(content)
@ -72,7 +72,7 @@ pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
/// it checks every directory in the path to see if it exists, /// it checks every directory in the path to see if it exists,
/// and if it does not it will be created. /// and if it does not it will be created.
pub fn create_file(path: &Path) -> io::Result<File> { pub fn create_file(path: &Path) -> Result<File> {
debug!("[fn]: create_file"); debug!("[fn]: create_file");
// Construct path // Construct path
@ -83,12 +83,12 @@ pub fn create_file(path: &Path) -> io::Result<File> {
} }
debug!("[*]: Create file: {:?}", path); debug!("[*]: Create file: {:?}", path);
File::create(path) File::create(path).map_err(|e| e.into())
} }
/// Removes all the content of a directory but not the directory itself /// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> { pub fn remove_dir_content(dir: &Path) -> Result<()> {
for item in fs::read_dir(dir)? { for item in fs::read_dir(dir)? {
if let Ok(item) = item { if let Ok(item) = item {
let item = item.path(); let item = item.path();
@ -108,7 +108,7 @@ pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
/// with the extensions given in the `ext_blacklist` array /// with the extensions given in the `ext_blacklist` array
pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str])
-> Result<(), Box<Error>> { -> Result<()> {
debug!("[fn] copy_files_except_ext"); debug!("[fn] copy_files_except_ext");
// Check that from and to are different // Check that from and to are different
if from == to { if from == to {