diff --git a/Cargo.lock b/Cargo.lock index df0e952..6f7a003 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,7 @@ dependencies = [ "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "syntect 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "utils 0.1.0", ] [[package]] @@ -616,7 +617,6 @@ dependencies = [ name = "errors" version = "0.1.0" dependencies = [ - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntect 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2229,7 +2229,6 @@ dependencies = [ "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.1.0", "csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "errors 0.1.0", "imageproc 0.1.0", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/config/Cargo.toml b/components/config/Cargo.toml index ad0f929..a8090aa 100644 --- a/components/config/Cargo.toml +++ b/components/config/Cargo.toml @@ -13,3 +13,4 @@ lazy_static = "1" syntect = "3" errors = { path = "../errors" } +utils = { path = "../utils" } diff --git a/components/config/src/config.rs b/components/config/src/config.rs index 57c8284..4c02086 100644 --- a/components/config/src/config.rs +++ b/components/config/src/config.rs @@ -1,6 +1,4 @@ use std::collections::HashMap; -use std::fs::File; -use std::io::prelude::*; use std::path::{Path, PathBuf}; use chrono::Utc; @@ -9,9 +7,10 @@ use syntect::parsing::{SyntaxSet, SyntaxSetBuilder}; use toml; use toml::Value as Toml; -use errors::{Result, ResultExt}; +use errors::Result; use highlighting::THEME_SET; use theme::Theme; +use utils::fs::read_file_with_error; // We want a default base url for tests static DEFAULT_BASE_URL: &'static str = "http://a-website.com"; @@ -66,7 +65,13 @@ impl Taxonomy { impl Default for Taxonomy { fn default() -> Taxonomy { - Taxonomy { name: String::new(), paginate_by: None, paginate_path: None, rss: false, lang: None } + Taxonomy { + name: String::new(), + paginate_by: None, + paginate_path: None, + rss: false, + lang: None, + } } } @@ -172,15 +177,12 @@ impl Config { /// Parses a config file from the given path pub fn from_file>(path: P) -> Result { - let mut content = String::new(); let path = path.as_ref(); let file_name = path.file_name().unwrap(); - File::open(path) - .chain_err(|| { - format!("No `{:?}` file found. Are you in the right directory?", file_name) - })? - .read_to_string(&mut content)?; - + let content = read_file_with_error( + path, + &format!("No `{:?}` file found. Are you in the right directory?", file_name), + )?; Config::parse(&content) } diff --git a/components/config/src/lib.rs b/components/config/src/lib.rs index b7a4ebc..3c7443a 100644 --- a/components/config/src/lib.rs +++ b/components/config/src/lib.rs @@ -1,14 +1,16 @@ #[macro_use] extern crate serde_derive; -extern crate toml; -#[macro_use] -extern crate errors; extern crate chrono; extern crate globset; +extern crate toml; #[macro_use] extern crate lazy_static; extern crate syntect; +#[macro_use] +extern crate errors; +extern crate utils; + mod config; pub mod highlighting; mod theme; diff --git a/components/config/src/theme.rs b/components/config/src/theme.rs index 1bce6bf..d6bd40c 100644 --- a/components/config/src/theme.rs +++ b/components/config/src/theme.rs @@ -1,11 +1,10 @@ use std::collections::HashMap; -use std::fs::File; -use std::io::prelude::*; use std::path::PathBuf; use toml::Value as Toml; -use errors::{Result, ResultExt}; +use errors::Result; +use utils::fs::read_file_with_error; /// Holds the data from a `theme.toml` file. /// There are other fields than `extra` in it but Zola @@ -40,15 +39,12 @@ impl Theme { /// Parses a theme file from the given path pub fn from_file(path: &PathBuf) -> Result { - let mut content = String::new(); - File::open(path) - .chain_err(|| { - "No `theme.toml` file found. \ - Is the `theme` defined in your `config.toml present in the `themes` directory \ - and does it have a `theme.toml` inside?" - })? - .read_to_string(&mut content)?; - + let content = read_file_with_error( + path, + "No `theme.toml` file found. \ + Is the `theme` defined in your `config.toml present in the `themes` directory \ + and does it have a `theme.toml` inside?", + )?; Theme::parse(&content) } } diff --git a/components/errors/Cargo.toml b/components/errors/Cargo.toml index eacf916..c065109 100644 --- a/components/errors/Cargo.toml +++ b/components/errors/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors = ["Vincent Prouillet "] [dependencies] -error-chain = "0.12" tera = "0.11" toml = "0.4" image = "0.20" diff --git a/components/errors/src/lib.rs b/components/errors/src/lib.rs index 0d0a32d..5c2c2da 100755 --- a/components/errors/src/lib.rs +++ b/components/errors/src/lib.rs @@ -1,26 +1,101 @@ -#![allow(unused_doc_comments)] - -#[macro_use] -extern crate error_chain; extern crate image; extern crate syntect; extern crate tera; extern crate toml; -error_chain! { - errors {} +use std::convert::Into; +use std::error::Error as StdError; +use std::fmt; + +#[derive(Debug)] +pub enum ErrorKind { + Msg(String), + Tera(tera::Error), + Io(::std::io::Error), + Toml(toml::de::Error), + Image(image::ImageError), + Syntect(syntect::LoadingError), +} + +/// The Error type +#[derive(Debug)] +pub struct Error { + /// Kind of error + pub kind: ErrorKind, + pub source: Option>, +} +unsafe impl Sync for Error {} +unsafe impl Send for Error {} + +impl StdError for Error { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.source.as_ref().map(|c| &**c) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.kind { + ErrorKind::Msg(ref message) => write!(f, "{}", message), + ErrorKind::Tera(ref e) => write!(f, "{}", e), + ErrorKind::Io(ref e) => write!(f, "{}", e), + ErrorKind::Toml(ref e) => write!(f, "{}", e), + ErrorKind::Image(ref e) => write!(f, "{}", e), + ErrorKind::Syntect(ref e) => write!(f, "{}", e), + } + } +} - links { - Tera(tera::Error, tera::ErrorKind); +impl Error { + /// Creates generic error + pub fn msg(value: impl ToString) -> Self { + Self { kind: ErrorKind::Msg(value.to_string()), source: None } } - foreign_links { - Io(::std::io::Error); - Toml(toml::de::Error); - Image(image::ImageError); - Syntect(syntect::LoadingError); + /// Creates generic error with a cause + pub fn chain(value: impl ToString, source: impl Into>) -> Self { + Self { kind: ErrorKind::Msg(value.to_string()), source: Some(source.into()) } + } +} + + +impl From<&str> for Error { + fn from(e: &str) -> Self { + Self::msg(e) + } +} +impl From for Error { + fn from(e: String) -> Self { + Self::msg(e) + } +} +impl From for Error { + fn from(e: toml::de::Error) -> Self { + Self { kind: ErrorKind::Toml(e), source: None } + } +} +impl From for Error { + fn from(e: syntect::LoadingError) -> Self { + Self { kind: ErrorKind::Syntect(e), source: None } + } +} +impl From for Error { + fn from(e: tera::Error) -> Self { + Self { kind: ErrorKind::Tera(e), source: None } + } +} +impl From<::std::io::Error> for Error { + fn from(e: ::std::io::Error) -> Self { + Self { kind: ErrorKind::Io(e), source: None } + } +} +impl From for Error { + fn from(e: image::ImageError) -> Self { + Self { kind: ErrorKind::Image(e), source: None } } } +/// Convenient wrapper around std::Result. +pub type Result = ::std::result::Result; // So we can use bail! in all other crates #[macro_export] diff --git a/components/front_matter/src/lib.rs b/components/front_matter/src/lib.rs index 986399c..c0ca8b7 100644 --- a/components/front_matter/src/lib.rs +++ b/components/front_matter/src/lib.rs @@ -12,7 +12,7 @@ extern crate toml; extern crate errors; extern crate utils; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use regex::Regex; use std::path::Path; @@ -71,8 +71,8 @@ pub fn split_section_content( content: &str, ) -> Result<(SectionFrontMatter, String)> { let (front_matter, content) = split_content(file_path, content)?; - let meta = SectionFrontMatter::parse(&front_matter).chain_err(|| { - format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()) + let meta = SectionFrontMatter::parse(&front_matter).map_err(|e| { + Error::chain(format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()), e) })?; Ok((meta, content)) } @@ -81,8 +81,8 @@ pub fn split_section_content( /// Returns a parsed `PageFrontMatter` and the rest of the content pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> { let (front_matter, content) = split_content(file_path, content)?; - let meta = PageFrontMatter::parse(&front_matter).chain_err(|| { - format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()) + let meta = PageFrontMatter::parse(&front_matter).map_err(|e| { + Error::chain(format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()), e) })?; Ok((meta, content)) } diff --git a/components/imageproc/src/lib.rs b/components/imageproc/src/lib.rs index e195184..4ebdbea 100644 --- a/components/imageproc/src/lib.rs +++ b/components/imageproc/src/lib.rs @@ -20,7 +20,7 @@ use image::{FilterType, GenericImageView}; use rayon::prelude::*; use regex::Regex; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use utils::fs as ufs; static RESIZED_SUBDIR: &'static str = "processed_images"; @@ -456,7 +456,7 @@ impl Processor { let target = self.resized_path.join(Self::op_filename(*hash, op.collision_id, op.format)); op.perform(&self.content_path, &target) - .chain_err(|| format!("Failed to process image: {}", op.source)) + .map_err(|e| Error::chain(format!("Failed to process image: {}", op.source), e)) }) .collect::>() } diff --git a/components/library/src/content/page.rs b/components/library/src/content/page.rs index 5736e17..9a80014 100644 --- a/components/library/src/content/page.rs +++ b/components/library/src/content/page.rs @@ -8,7 +8,7 @@ use slug::slugify; use tera::{Context as TeraContext, Tera}; use config::Config; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use front_matter::{split_page_content, InsertAnchor, PageFrontMatter}; use library::Library; use rendering::{render_content, Header, RenderContext}; @@ -234,7 +234,7 @@ impl Page { context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None)); let res = render_content(&self.raw_content, &context) - .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?; + .map_err(|e| Error::chain(format!("Failed to render content of {}", self.file.path.display()), e))?; self.summary = res.summary_len.map(|l| res.body[0..l].to_owned()); self.content = res.body; @@ -258,7 +258,7 @@ impl Page { context.insert("lang", &self.lang); render_template(&tpl_name, tera, &context, &config.theme) - .chain_err(|| format!("Failed to render page '{}'", self.file.path.display())) + .map_err(|e| Error::chain(format!("Failed to render page '{}'", self.file.path.display()), e)) } /// Creates a vectors of asset URLs. diff --git a/components/library/src/content/section.rs b/components/library/src/content/section.rs index 041b9ac..cb2d940 100644 --- a/components/library/src/content/section.rs +++ b/components/library/src/content/section.rs @@ -5,7 +5,7 @@ use slotmap::Key; use tera::{Context as TeraContext, Tera}; use config::Config; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use front_matter::{split_section_content, SectionFrontMatter}; use rendering::{render_content, Header, RenderContext}; use utils::fs::{find_related_assets, read_file}; @@ -172,7 +172,7 @@ impl Section { context.tera_context.insert("section", &SerializingSection::from_section_basic(self, None)); let res = render_content(&self.raw_content, &context) - .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?; + .map_err(|e| Error::chain(format!("Failed to render content of {}", self.file.path.display()), e))?; self.content = res.body; self.toc = res.toc; Ok(()) @@ -190,7 +190,7 @@ impl Section { context.insert("lang", &self.lang); render_template(tpl_name, tera, &context, &config.theme) - .chain_err(|| format!("Failed to render section '{}'", self.file.path.display())) + .map_err(|e| Error::chain(format!("Failed to render section '{}'", self.file.path.display()), e)) } /// Is this the index section? diff --git a/components/library/src/pagination/mod.rs b/components/library/src/pagination/mod.rs index ad02385..da2c1c1 100644 --- a/components/library/src/pagination/mod.rs +++ b/components/library/src/pagination/mod.rs @@ -4,7 +4,7 @@ use slotmap::Key; use tera::{to_value, Context, Tera, Value}; use config::Config; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use utils::templates::render_template; use content::{Section, SerializingPage, SerializingSection}; @@ -222,7 +222,7 @@ impl<'a> Paginator<'a> { context.insert("paginator", &self.build_paginator_context(pager)); render_template(&self.template, tera, &context, &config.theme) - .chain_err(|| format!("Failed to render pager {}", pager.index)) + .map_err(|e| Error::chain(format!("Failed to render pager {}", pager.index), e)) } } diff --git a/components/library/src/taxonomies/mod.rs b/components/library/src/taxonomies/mod.rs index 6b74f9c..c44265c 100644 --- a/components/library/src/taxonomies/mod.rs +++ b/components/library/src/taxonomies/mod.rs @@ -5,7 +5,7 @@ use slug::slugify; use tera::{Context, Tera}; use config::{Config, Taxonomy as TaxonomyConfig}; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use utils::templates::render_template; use content::SerializingPage; @@ -145,7 +145,7 @@ impl Taxonomy { context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug)); render_template(&format!("{}/single.html", self.kind.name), tera, &context, &config.theme) - .chain_err(|| format!("Failed to render single term {} page.", self.kind.name)) + .map_err(|e| Error::chain(format!("Failed to render single term {} page.", self.kind.name), e)) } pub fn render_all_terms( @@ -164,7 +164,7 @@ impl Taxonomy { context.insert("current_path", &self.kind.name); render_template(&format!("{}/list.html", self.kind.name), tera, &context, &config.theme) - .chain_err(|| format!("Failed to render a list of {} page.", self.kind.name)) + .map_err(|e| Error::chain(format!("Failed to render a list of {} page.", self.kind.name), e)) } pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializedTaxonomy<'a> { @@ -334,7 +334,7 @@ mod tests { let err = taxonomies.unwrap_err(); // no path as this is created by Default assert_eq!( - err.description(), + format!("{}", err), "Page `` has taxonomy `tags` which is not defined in config.toml" ); } @@ -442,7 +442,7 @@ mod tests { let err = taxonomies.unwrap_err(); // no path as this is created by Default assert_eq!( - err.description(), + format!("{}", err), "Page `` has taxonomy `tags` which is not available in that language" ); } diff --git a/components/rendering/src/shortcode.rs b/components/rendering/src/shortcode.rs index 804b487..6836b20 100644 --- a/components/rendering/src/shortcode.rs +++ b/components/rendering/src/shortcode.rs @@ -4,7 +4,7 @@ use regex::Regex; use tera::{to_value, Context, Map, Value}; use context::RenderContext; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; // This include forces recompiling this source file if the grammar file changes. // Uncomment it when doing changes to the .pest file @@ -116,7 +116,7 @@ fn render_shortcode( let res = context .tera .render(&tpl_name, &tera_context) - .chain_err(|| format!("Failed to render {} shortcode", name))?; + .map_err(|e| Error::chain(format!("Failed to render {} shortcode", name), e))?; // Small hack to avoid having multiple blank lines because of Tera tags for example // A blank like will cause the markdown parser to think we're out of HTML and start looking diff --git a/components/rendering/tests/markdown.rs b/components/rendering/tests/markdown.rs index 6f189ed..ebd7494 100644 --- a/components/rendering/tests/markdown.rs +++ b/components/rendering/tests/markdown.rs @@ -660,7 +660,7 @@ fn can_show_error_message_for_invalid_external_links() { let res = render_content("[a link](http://google.comy)", &context); assert!(res.is_err()); let err = res.unwrap_err(); - assert!(err.description().contains("Link http://google.comy is not valid")); + assert!(format!("{}", err).contains("Link http://google.comy is not valid")); } #[test] diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index 2308cbc..9b59e56 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -30,7 +30,7 @@ use sass_rs::{compile_file, Options as SassOptions, OutputStyle}; use tera::{Context, Tera}; use config::{get_config, Config}; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; use front_matter::InsertAnchor; use library::{ find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy, @@ -87,7 +87,7 @@ impl Site { format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*.*ml"); // Only parsing as we might be extending templates from themes and that would error // as we haven't loaded them yet - let mut tera = Tera::parse(&tpl_glob).chain_err(|| "Error parsing templates")?; + let mut tera = Tera::parse(&tpl_glob).map_err(|e| Error::chain("Error parsing templates", e))?; if let Some(theme) = config.theme.clone() { // Grab data from the extra section of the theme config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?; @@ -104,9 +104,9 @@ impl Site { format!("themes/{}/templates/**/*.*ml", theme) ); let mut tera_theme = - Tera::parse(&theme_tpl_glob).chain_err(|| "Error parsing templates from themes")?; + Tera::parse(&theme_tpl_glob).map_err(|e| Error::chain("Error parsing templates from themes", e))?; rewrite_theme_paths(&mut tera_theme, &theme); - // TODO: same as below + // TODO: we do that twice, make it dry? if theme_path.join("templates").join("robots.txt").exists() { tera_theme .add_template_file(theme_path.join("templates").join("robots.txt"), None)?; @@ -470,7 +470,7 @@ impl Site { pub fn clean(&self) -> Result<()> { if self.output_path.exists() { // Delete current `public` directory so we can start fresh - remove_dir_all(&self.output_path).chain_err(|| "Couldn't delete output directory")?; + remove_dir_all(&self.output_path).map_err(|e| Error::chain("Couldn't delete output directory", e))?; } Ok(()) diff --git a/components/templates/Cargo.toml b/components/templates/Cargo.toml index c3001f4..b84e15b 100644 --- a/components/templates/Cargo.toml +++ b/components/templates/Cargo.toml @@ -11,7 +11,6 @@ pulldown-cmark = "0.2" toml = "0.4" csv = "1" serde_json = "1.0" -error-chain = "0.12" reqwest = "0.9" url = "1.5" diff --git a/components/templates/src/global_fns/mod.rs b/components/templates/src/global_fns/mod.rs index 310b265..ffb390b 100644 --- a/components/templates/src/global_fns/mod.rs +++ b/components/templates/src/global_fns/mod.rs @@ -1,5 +1,3 @@ -extern crate error_chain; - use std::collections::HashMap; use std::sync::{Arc, Mutex}; diff --git a/components/templates/src/lib.rs b/components/templates/src/lib.rs index c9723fb..a75e2ff 100644 --- a/components/templates/src/lib.rs +++ b/components/templates/src/lib.rs @@ -25,7 +25,7 @@ pub mod global_fns; use tera::{Context, Tera}; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; lazy_static! { pub static ref ZOLA_TERA: Tera = { @@ -57,5 +57,5 @@ pub fn render_redirect_template(url: &str, tera: &Tera) -> Result { context.insert("url", &url); tera.render("internal/alias.html", &context) - .chain_err(|| format!("Failed to render alias for '{}'", url)) + .map_err(|e| Error::chain(format!("Failed to render alias for '{}'", url), e)) } diff --git a/components/utils/src/fs.rs b/components/utils/src/fs.rs index ec08d3f..fdbccbd 100644 --- a/components/utils/src/fs.rs +++ b/components/utils/src/fs.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use std::time::SystemTime; use walkdir::WalkDir; -use errors::{Result, ResultExt}; +use errors::{Result, Error}; pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result { let canonical_path = path @@ -19,7 +19,8 @@ pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result { /// Create a file with the content given pub fn create_file(path: &Path, content: &str) -> Result<()> { - let mut file = File::create(&path).chain_err(|| format!("Failed to create {:?}", path))?; + let mut file = File::create(&path) + .map_err(|e| Error::chain(format!("Failed to create {:?}", path), e))?; file.write_all(content.as_bytes())?; Ok(()) } @@ -37,7 +38,7 @@ pub fn ensure_directory_exists(path: &Path) -> Result<()> { pub fn create_directory(path: &Path) -> Result<()> { if !path.exists() { create_dir_all(path) - .chain_err(|| format!("Was not able to create folder {}", path.display()))?; + .map_err(|e| Error::chain(format!("Was not able to create folder {}", path.display()), e))?; } Ok(()) } @@ -46,7 +47,7 @@ pub fn create_directory(path: &Path) -> Result<()> { pub fn read_file(path: &Path) -> Result { let mut content = String::new(); File::open(path) - .chain_err(|| format!("Failed to open '{:?}'", path.display()))? + .map_err(|e| Error::chain(format!("Failed to open '{:?}'", path.display()), e))? .read_to_string(&mut content)?; // Remove utf-8 BOM if any. @@ -57,6 +58,19 @@ pub fn read_file(path: &Path) -> Result { Ok(content) } +/// Return the content of a file, with error handling added. +/// The default error message is overwritten by the message given. +/// That means it is allocation 2 strings, oh well +pub fn read_file_with_error(path: &Path, message: &str) -> Result { + let res = read_file(&path); + if res.is_ok() { + return res; + } + let mut err = Error::msg(message); + err.source = res.unwrap_err().source; + Err(err) +} + /// Looks into the current folder for the path and see if there's anything that is not a .md /// file. Those will be copied next to the rendered .html file pub fn find_related_assets(path: &Path) -> Vec { diff --git a/docs/templates/page.html b/docs/templates/page.html index 8f6c09b..723f0b1 100644 --- a/docs/templates/page.html +++ b/docs/templates/page.html @@ -4,4 +4,5 @@ {% block doc_content %}

{{page.title}}

{{page.content | safe}} +{{hey}} {% endblock doc_content %} diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 7672aac..43408ef 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -36,7 +36,7 @@ use ctrlc; use notify::{watcher, RecursiveMode, Watcher}; use ws::{Message, Sender, WebSocket}; -use errors::{Result, ResultExt}; +use errors::{Result, Error as ZolaError}; use site::Site; use utils::fs::copy_file; @@ -179,23 +179,23 @@ pub fn serve( let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); watcher .watch("content/", RecursiveMode::Recursive) - .chain_err(|| "Can't watch the `content` folder. Does it exist?")?; + .map_err(|e| ZolaError::chain("Can't watch the `content` folder. Does it exist?", e))?; watcher .watch(config_file, RecursiveMode::Recursive) - .chain_err(|| "Can't watch the `config` file. Does it exist?")?; + .map_err(|e| ZolaError::chain("Can't watch the `config` file. Does it exist?", e))?; if Path::new("static").exists() { watching_static = true; watcher .watch("static/", RecursiveMode::Recursive) - .chain_err(|| "Can't watch the `static` folder.")?; + .map_err(|e| ZolaError::chain("Can't watch the `static` folder.", e))?; } if Path::new("templates").exists() { watching_templates = true; watcher .watch("templates/", RecursiveMode::Recursive) - .chain_err(|| "Can't watch the `templates` folder.")?; + .map_err(|e| ZolaError::chain("Can't watch the `templates` folder.", e))?; } // Sass support is optional so don't make it an error to no have a sass folder diff --git a/src/console.rs b/src/console.rs index 4d1ba19..2d50ca9 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,4 +1,5 @@ use std::env; +use std::error::Error as StdError; use std::io::Write; use std::time::Instant; @@ -6,7 +7,6 @@ use atty; use chrono::Duration; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; -use errors::Error; use site::Site; lazy_static! { @@ -91,13 +91,15 @@ pub fn report_elapsed_time(instant: Instant) { } /// Display an error message and the actual error(s) -pub fn unravel_errors(message: &str, error: &Error) { +pub fn unravel_errors(message: &str, error: &StdError) { if !message.is_empty() { self::error(message); } self::error(&format!("Error: {}", error)); - for e in error.iter().skip(1) { + let mut cause = error.source(); + while let Some(e) = cause { self::error(&format!("Reason: {}", e)); + cause = e.source(); } }