@@ -342,6 +342,7 @@ dependencies = [ | |||||
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", | "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)", | "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)", | "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"utils 0.1.0", | |||||
] | ] | ||||
[[package]] | [[package]] | ||||
@@ -616,7 +617,6 @@ dependencies = [ | |||||
name = "errors" | name = "errors" | ||||
version = "0.1.0" | version = "0.1.0" | ||||
dependencies = [ | 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)", | "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)", | "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)", | "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)", | "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"config 0.1.0", | "config 0.1.0", | ||||
"csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", | "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", | "errors 0.1.0", | ||||
"imageproc 0.1.0", | "imageproc 0.1.0", | ||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -13,3 +13,4 @@ lazy_static = "1" | |||||
syntect = "3" | syntect = "3" | ||||
errors = { path = "../errors" } | errors = { path = "../errors" } | ||||
utils = { path = "../utils" } |
@@ -1,6 +1,4 @@ | |||||
use std::collections::HashMap; | use std::collections::HashMap; | ||||
use std::fs::File; | |||||
use std::io::prelude::*; | |||||
use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||
use chrono::Utc; | use chrono::Utc; | ||||
@@ -9,9 +7,10 @@ use syntect::parsing::{SyntaxSet, SyntaxSetBuilder}; | |||||
use toml; | use toml; | ||||
use toml::Value as Toml; | use toml::Value as Toml; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::Result; | |||||
use highlighting::THEME_SET; | use highlighting::THEME_SET; | ||||
use theme::Theme; | use theme::Theme; | ||||
use utils::fs::read_file_with_error; | |||||
// We want a default base url for tests | // We want a default base url for tests | ||||
static DEFAULT_BASE_URL: &'static str = "http://a-website.com"; | static DEFAULT_BASE_URL: &'static str = "http://a-website.com"; | ||||
@@ -66,7 +65,13 @@ impl Taxonomy { | |||||
impl Default for Taxonomy { | impl Default for Taxonomy { | ||||
fn default() -> 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 | /// Parses a config file from the given path | ||||
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> { | pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> { | ||||
let mut content = String::new(); | |||||
let path = path.as_ref(); | let path = path.as_ref(); | ||||
let file_name = path.file_name().unwrap(); | 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) | Config::parse(&content) | ||||
} | } | ||||
@@ -1,14 +1,16 @@ | |||||
#[macro_use] | #[macro_use] | ||||
extern crate serde_derive; | extern crate serde_derive; | ||||
extern crate toml; | |||||
#[macro_use] | |||||
extern crate errors; | |||||
extern crate chrono; | extern crate chrono; | ||||
extern crate globset; | extern crate globset; | ||||
extern crate toml; | |||||
#[macro_use] | #[macro_use] | ||||
extern crate lazy_static; | extern crate lazy_static; | ||||
extern crate syntect; | extern crate syntect; | ||||
#[macro_use] | |||||
extern crate errors; | |||||
extern crate utils; | |||||
mod config; | mod config; | ||||
pub mod highlighting; | pub mod highlighting; | ||||
mod theme; | mod theme; | ||||
@@ -1,11 +1,10 @@ | |||||
use std::collections::HashMap; | use std::collections::HashMap; | ||||
use std::fs::File; | |||||
use std::io::prelude::*; | |||||
use std::path::PathBuf; | use std::path::PathBuf; | ||||
use toml::Value as Toml; | 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. | /// Holds the data from a `theme.toml` file. | ||||
/// There are other fields than `extra` in it but Zola | /// There are other fields than `extra` in it but Zola | ||||
@@ -40,15 +39,12 @@ impl Theme { | |||||
/// Parses a theme file from the given path | /// Parses a theme file from the given path | ||||
pub fn from_file(path: &PathBuf) -> Result<Theme> { | pub fn from_file(path: &PathBuf) -> Result<Theme> { | ||||
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) | Theme::parse(&content) | ||||
} | } | ||||
} | } |
@@ -4,7 +4,6 @@ version = "0.1.0" | |||||
authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"] | authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"] | ||||
[dependencies] | [dependencies] | ||||
error-chain = "0.12" | |||||
tera = "0.11" | tera = "0.11" | ||||
toml = "0.4" | toml = "0.4" | ||||
image = "0.20" | image = "0.20" | ||||
@@ -1,26 +1,101 @@ | |||||
#![allow(unused_doc_comments)] | |||||
#[macro_use] | |||||
extern crate error_chain; | |||||
extern crate image; | extern crate image; | ||||
extern crate syntect; | extern crate syntect; | ||||
extern crate tera; | extern crate tera; | ||||
extern crate toml; | 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<Box<dyn StdError>>, | |||||
} | |||||
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<Box<dyn StdError>>) -> 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<String> for Error { | |||||
fn from(e: String) -> Self { | |||||
Self::msg(e) | |||||
} | |||||
} | |||||
impl From<toml::de::Error> for Error { | |||||
fn from(e: toml::de::Error) -> Self { | |||||
Self { kind: ErrorKind::Toml(e), source: None } | |||||
} | |||||
} | |||||
impl From<syntect::LoadingError> for Error { | |||||
fn from(e: syntect::LoadingError) -> Self { | |||||
Self { kind: ErrorKind::Syntect(e), source: None } | |||||
} | |||||
} | |||||
impl From<tera::Error> 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<image::ImageError> for Error { | |||||
fn from(e: image::ImageError) -> Self { | |||||
Self { kind: ErrorKind::Image(e), source: None } | |||||
} | } | ||||
} | } | ||||
/// Convenient wrapper around std::Result. | |||||
pub type Result<T> = ::std::result::Result<T, Error>; | |||||
// So we can use bail! in all other crates | // So we can use bail! in all other crates | ||||
#[macro_export] | #[macro_export] | ||||
@@ -12,7 +12,7 @@ extern crate toml; | |||||
extern crate errors; | extern crate errors; | ||||
extern crate utils; | extern crate utils; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use regex::Regex; | use regex::Regex; | ||||
use std::path::Path; | use std::path::Path; | ||||
@@ -71,8 +71,8 @@ pub fn split_section_content( | |||||
content: &str, | content: &str, | ||||
) -> Result<(SectionFrontMatter, String)> { | ) -> Result<(SectionFrontMatter, String)> { | ||||
let (front_matter, content) = split_content(file_path, content)?; | 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)) | Ok((meta, content)) | ||||
} | } | ||||
@@ -81,8 +81,8 @@ pub fn split_section_content( | |||||
/// Returns a parsed `PageFrontMatter` and the rest of the content | /// Returns a parsed `PageFrontMatter` and the rest of the content | ||||
pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> { | pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> { | ||||
let (front_matter, content) = split_content(file_path, content)?; | 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)) | Ok((meta, content)) | ||||
} | } | ||||
@@ -20,7 +20,7 @@ use image::{FilterType, GenericImageView}; | |||||
use rayon::prelude::*; | use rayon::prelude::*; | ||||
use regex::Regex; | use regex::Regex; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use utils::fs as ufs; | use utils::fs as ufs; | ||||
static RESIZED_SUBDIR: &'static str = "processed_images"; | static RESIZED_SUBDIR: &'static str = "processed_images"; | ||||
@@ -456,7 +456,7 @@ impl Processor { | |||||
let target = | let target = | ||||
self.resized_path.join(Self::op_filename(*hash, op.collision_id, op.format)); | self.resized_path.join(Self::op_filename(*hash, op.collision_id, op.format)); | ||||
op.perform(&self.content_path, &target) | 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::<Result<()>>() | .collect::<Result<()>>() | ||||
} | } | ||||
@@ -8,7 +8,7 @@ use slug::slugify; | |||||
use tera::{Context as TeraContext, Tera}; | use tera::{Context as TeraContext, Tera}; | ||||
use config::Config; | use config::Config; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use front_matter::{split_page_content, InsertAnchor, PageFrontMatter}; | use front_matter::{split_page_content, InsertAnchor, PageFrontMatter}; | ||||
use library::Library; | use library::Library; | ||||
use rendering::{render_content, Header, RenderContext}; | use rendering::{render_content, Header, RenderContext}; | ||||
@@ -234,7 +234,7 @@ impl Page { | |||||
context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None)); | context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None)); | ||||
let res = render_content(&self.raw_content, &context) | 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.summary = res.summary_len.map(|l| res.body[0..l].to_owned()); | ||||
self.content = res.body; | self.content = res.body; | ||||
@@ -258,7 +258,7 @@ impl Page { | |||||
context.insert("lang", &self.lang); | context.insert("lang", &self.lang); | ||||
render_template(&tpl_name, tera, &context, &config.theme) | 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. | /// Creates a vectors of asset URLs. | ||||
@@ -5,7 +5,7 @@ use slotmap::Key; | |||||
use tera::{Context as TeraContext, Tera}; | use tera::{Context as TeraContext, Tera}; | ||||
use config::Config; | use config::Config; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use front_matter::{split_section_content, SectionFrontMatter}; | use front_matter::{split_section_content, SectionFrontMatter}; | ||||
use rendering::{render_content, Header, RenderContext}; | use rendering::{render_content, Header, RenderContext}; | ||||
use utils::fs::{find_related_assets, read_file}; | 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)); | context.tera_context.insert("section", &SerializingSection::from_section_basic(self, None)); | ||||
let res = render_content(&self.raw_content, &context) | 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.content = res.body; | ||||
self.toc = res.toc; | self.toc = res.toc; | ||||
Ok(()) | Ok(()) | ||||
@@ -190,7 +190,7 @@ impl Section { | |||||
context.insert("lang", &self.lang); | context.insert("lang", &self.lang); | ||||
render_template(tpl_name, tera, &context, &config.theme) | 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? | /// Is this the index section? | ||||
@@ -4,7 +4,7 @@ use slotmap::Key; | |||||
use tera::{to_value, Context, Tera, Value}; | use tera::{to_value, Context, Tera, Value}; | ||||
use config::Config; | use config::Config; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use utils::templates::render_template; | use utils::templates::render_template; | ||||
use content::{Section, SerializingPage, SerializingSection}; | use content::{Section, SerializingPage, SerializingSection}; | ||||
@@ -222,7 +222,7 @@ impl<'a> Paginator<'a> { | |||||
context.insert("paginator", &self.build_paginator_context(pager)); | context.insert("paginator", &self.build_paginator_context(pager)); | ||||
render_template(&self.template, tera, &context, &config.theme) | 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)) | |||||
} | } | ||||
} | } | ||||
@@ -5,7 +5,7 @@ use slug::slugify; | |||||
use tera::{Context, Tera}; | use tera::{Context, Tera}; | ||||
use config::{Config, Taxonomy as TaxonomyConfig}; | use config::{Config, Taxonomy as TaxonomyConfig}; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use utils::templates::render_template; | use utils::templates::render_template; | ||||
use content::SerializingPage; | use content::SerializingPage; | ||||
@@ -145,7 +145,7 @@ impl Taxonomy { | |||||
context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug)); | context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug)); | ||||
render_template(&format!("{}/single.html", self.kind.name), tera, &context, &config.theme) | 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( | pub fn render_all_terms( | ||||
@@ -164,7 +164,7 @@ impl Taxonomy { | |||||
context.insert("current_path", &self.kind.name); | context.insert("current_path", &self.kind.name); | ||||
render_template(&format!("{}/list.html", self.kind.name), tera, &context, &config.theme) | 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> { | pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializedTaxonomy<'a> { | ||||
@@ -334,7 +334,7 @@ mod tests { | |||||
let err = taxonomies.unwrap_err(); | let err = taxonomies.unwrap_err(); | ||||
// no path as this is created by Default | // no path as this is created by Default | ||||
assert_eq!( | assert_eq!( | ||||
err.description(), | |||||
format!("{}", err), | |||||
"Page `` has taxonomy `tags` which is not defined in config.toml" | "Page `` has taxonomy `tags` which is not defined in config.toml" | ||||
); | ); | ||||
} | } | ||||
@@ -442,7 +442,7 @@ mod tests { | |||||
let err = taxonomies.unwrap_err(); | let err = taxonomies.unwrap_err(); | ||||
// no path as this is created by Default | // no path as this is created by Default | ||||
assert_eq!( | assert_eq!( | ||||
err.description(), | |||||
format!("{}", err), | |||||
"Page `` has taxonomy `tags` which is not available in that language" | "Page `` has taxonomy `tags` which is not available in that language" | ||||
); | ); | ||||
} | } | ||||
@@ -4,7 +4,7 @@ use regex::Regex; | |||||
use tera::{to_value, Context, Map, Value}; | use tera::{to_value, Context, Map, Value}; | ||||
use context::RenderContext; | use context::RenderContext; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
// This include forces recompiling this source file if the grammar file changes. | // This include forces recompiling this source file if the grammar file changes. | ||||
// Uncomment it when doing changes to the .pest file | // Uncomment it when doing changes to the .pest file | ||||
@@ -116,7 +116,7 @@ fn render_shortcode( | |||||
let res = context | let res = context | ||||
.tera | .tera | ||||
.render(&tpl_name, &tera_context) | .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 | // 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 | // A blank like will cause the markdown parser to think we're out of HTML and start looking | ||||
@@ -660,7 +660,7 @@ fn can_show_error_message_for_invalid_external_links() { | |||||
let res = render_content("[a link](http://google.comy)", &context); | let res = render_content("[a link](http://google.comy)", &context); | ||||
assert!(res.is_err()); | assert!(res.is_err()); | ||||
let err = res.unwrap_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] | #[test] | ||||
@@ -30,7 +30,7 @@ use sass_rs::{compile_file, Options as SassOptions, OutputStyle}; | |||||
use tera::{Context, Tera}; | use tera::{Context, Tera}; | ||||
use config::{get_config, Config}; | use config::{get_config, Config}; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
use front_matter::InsertAnchor; | use front_matter::InsertAnchor; | ||||
use library::{ | use library::{ | ||||
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy, | 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"); | format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*.*ml"); | ||||
// Only parsing as we might be extending templates from themes and that would error | // Only parsing as we might be extending templates from themes and that would error | ||||
// as we haven't loaded them yet | // 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() { | if let Some(theme) = config.theme.clone() { | ||||
// Grab data from the extra section of the theme | // Grab data from the extra section of the theme | ||||
config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?; | config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?; | ||||
@@ -104,9 +104,9 @@ impl Site { | |||||
format!("themes/{}/templates/**/*.*ml", theme) | format!("themes/{}/templates/**/*.*ml", theme) | ||||
); | ); | ||||
let mut tera_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); | 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() { | if theme_path.join("templates").join("robots.txt").exists() { | ||||
tera_theme | tera_theme | ||||
.add_template_file(theme_path.join("templates").join("robots.txt"), None)?; | .add_template_file(theme_path.join("templates").join("robots.txt"), None)?; | ||||
@@ -470,7 +470,7 @@ impl Site { | |||||
pub fn clean(&self) -> Result<()> { | pub fn clean(&self) -> Result<()> { | ||||
if self.output_path.exists() { | if self.output_path.exists() { | ||||
// Delete current `public` directory so we can start fresh | // 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(()) | Ok(()) | ||||
@@ -11,7 +11,6 @@ pulldown-cmark = "0.2" | |||||
toml = "0.4" | toml = "0.4" | ||||
csv = "1" | csv = "1" | ||||
serde_json = "1.0" | serde_json = "1.0" | ||||
error-chain = "0.12" | |||||
reqwest = "0.9" | reqwest = "0.9" | ||||
url = "1.5" | url = "1.5" | ||||
@@ -1,5 +1,3 @@ | |||||
extern crate error_chain; | |||||
use std::collections::HashMap; | use std::collections::HashMap; | ||||
use std::sync::{Arc, Mutex}; | use std::sync::{Arc, Mutex}; | ||||
@@ -25,7 +25,7 @@ pub mod global_fns; | |||||
use tera::{Context, Tera}; | use tera::{Context, Tera}; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
lazy_static! { | lazy_static! { | ||||
pub static ref ZOLA_TERA: Tera = { | pub static ref ZOLA_TERA: Tera = { | ||||
@@ -57,5 +57,5 @@ pub fn render_redirect_template(url: &str, tera: &Tera) -> Result<String> { | |||||
context.insert("url", &url); | context.insert("url", &url); | ||||
tera.render("internal/alias.html", &context) | 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)) | |||||
} | } |
@@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; | |||||
use std::time::SystemTime; | use std::time::SystemTime; | ||||
use walkdir::WalkDir; | use walkdir::WalkDir; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error}; | |||||
pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result<bool> { | pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result<bool> { | ||||
let canonical_path = path | let canonical_path = path | ||||
@@ -19,7 +19,8 @@ pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result<bool> { | |||||
/// Create a file with the content given | /// Create a file with the content given | ||||
pub fn create_file(path: &Path, content: &str) -> Result<()> { | 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())?; | file.write_all(content.as_bytes())?; | ||||
Ok(()) | Ok(()) | ||||
} | } | ||||
@@ -37,7 +38,7 @@ pub fn ensure_directory_exists(path: &Path) -> Result<()> { | |||||
pub fn create_directory(path: &Path) -> Result<()> { | pub fn create_directory(path: &Path) -> Result<()> { | ||||
if !path.exists() { | if !path.exists() { | ||||
create_dir_all(path) | 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(()) | Ok(()) | ||||
} | } | ||||
@@ -46,7 +47,7 @@ pub fn create_directory(path: &Path) -> Result<()> { | |||||
pub fn read_file(path: &Path) -> Result<String> { | pub fn read_file(path: &Path) -> Result<String> { | ||||
let mut content = String::new(); | let mut content = String::new(); | ||||
File::open(path) | 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)?; | .read_to_string(&mut content)?; | ||||
// Remove utf-8 BOM if any. | // Remove utf-8 BOM if any. | ||||
@@ -57,6 +58,19 @@ pub fn read_file(path: &Path) -> Result<String> { | |||||
Ok(content) | 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<String> { | |||||
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 | /// 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 | /// file. Those will be copied next to the rendered .html file | ||||
pub fn find_related_assets(path: &Path) -> Vec<PathBuf> { | pub fn find_related_assets(path: &Path) -> Vec<PathBuf> { | ||||
@@ -4,4 +4,5 @@ | |||||
{% block doc_content %} | {% block doc_content %} | ||||
<h1>{{page.title}}</h1> | <h1>{{page.title}}</h1> | ||||
{{page.content | safe}} | {{page.content | safe}} | ||||
{{hey}} | |||||
{% endblock doc_content %} | {% endblock doc_content %} |
@@ -36,7 +36,7 @@ use ctrlc; | |||||
use notify::{watcher, RecursiveMode, Watcher}; | use notify::{watcher, RecursiveMode, Watcher}; | ||||
use ws::{Message, Sender, WebSocket}; | use ws::{Message, Sender, WebSocket}; | ||||
use errors::{Result, ResultExt}; | |||||
use errors::{Result, Error as ZolaError}; | |||||
use site::Site; | use site::Site; | ||||
use utils::fs::copy_file; | use utils::fs::copy_file; | ||||
@@ -179,23 +179,23 @@ pub fn serve( | |||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); | let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); | ||||
watcher | watcher | ||||
.watch("content/", RecursiveMode::Recursive) | .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 | watcher | ||||
.watch(config_file, RecursiveMode::Recursive) | .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() { | if Path::new("static").exists() { | ||||
watching_static = true; | watching_static = true; | ||||
watcher | watcher | ||||
.watch("static/", RecursiveMode::Recursive) | .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() { | if Path::new("templates").exists() { | ||||
watching_templates = true; | watching_templates = true; | ||||
watcher | watcher | ||||
.watch("templates/", RecursiveMode::Recursive) | .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 | // Sass support is optional so don't make it an error to no have a sass folder | ||||
@@ -1,4 +1,5 @@ | |||||
use std::env; | use std::env; | ||||
use std::error::Error as StdError; | |||||
use std::io::Write; | use std::io::Write; | ||||
use std::time::Instant; | use std::time::Instant; | ||||
@@ -6,7 +7,6 @@ use atty; | |||||
use chrono::Duration; | use chrono::Duration; | ||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; | use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; | ||||
use errors::Error; | |||||
use site::Site; | use site::Site; | ||||
lazy_static! { | lazy_static! { | ||||
@@ -91,13 +91,15 @@ pub fn report_elapsed_time(instant: Instant) { | |||||
} | } | ||||
/// Display an error message and the actual error(s) | /// 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() { | if !message.is_empty() { | ||||
self::error(message); | self::error(message); | ||||
} | } | ||||
self::error(&format!("Error: {}", error)); | 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)); | self::error(&format!("Reason: {}", e)); | ||||
cause = e.source(); | |||||
} | } | ||||
} | } | ||||