parent
69fb399726
commit
5caf24f06c
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -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)
|
let content = read_file_with_error(
|
||||||
.chain_err(|| {
|
path,
|
||||||
format!("No `{:?}` file found. Are you in the right directory?", file_name)
|
&format!("No `{:?}` file found. Are you in the right directory?", file_name),
|
||||||
})?
|
)?;
|
||||||
.read_to_string(&mut content)?;
|
|
||||||
|
|
||||||
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();
|
let content = read_file_with_error(
|
||||||
File::open(path)
|
path,
|
||||||
.chain_err(|| {
|
|
||||||
"No `theme.toml` file found. \
|
"No `theme.toml` file found. \
|
||||||
Is the `theme` defined in your `config.toml present in the `themes` directory \
|
Is the `theme` defined in your `config.toml present in the `themes` directory \
|
||||||
and does it have a `theme.toml` inside?"
|
and does it have a `theme.toml` inside?",
|
||||||
})?
|
)?;
|
||||||
.read_to_string(&mut content)?;
|
|
||||||
|
|
||||||
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,27 +1,102 @@
|
||||||
#![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! {
|
use std::convert::Into;
|
||||||
errors {}
|
use std::error::Error as StdError;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
links {
|
#[derive(Debug)]
|
||||||
Tera(tera::Error, tera::ErrorKind);
|
pub enum ErrorKind {
|
||||||
}
|
Msg(String),
|
||||||
|
Tera(tera::Error),
|
||||||
|
Io(::std::io::Error),
|
||||||
|
Toml(toml::de::Error),
|
||||||
|
Image(image::ImageError),
|
||||||
|
Syntect(syntect::LoadingError),
|
||||||
|
}
|
||||||
|
|
||||||
foreign_links {
|
/// The Error type
|
||||||
Io(::std::io::Error);
|
#[derive(Debug)]
|
||||||
Toml(toml::de::Error);
|
pub struct Error {
|
||||||
Image(image::ImageError);
|
/// Kind of error
|
||||||
Syntect(syntect::LoadingError);
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
/// Creates generic error
|
||||||
|
pub fn msg(value: impl ToString) -> Self {
|
||||||
|
Self { kind: ErrorKind::Msg(value.to_string()), source: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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]
|
||||||
macro_rules! bail {
|
macro_rules! bail {
|
||||||
|
|
|
@ -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(|| {
|
let meta = SectionFrontMatter::parse(&front_matter).map_err(|e| {
|
||||||
format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy())
|
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(|| {
|
let meta = PageFrontMatter::parse(&front_matter).map_err(|e| {
|
||||||
format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy())
|
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> {
|
||||||
|
|
1
docs/templates/page.html
vendored
1
docs/templates/page.html
vendored
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue