chore: Switch to failure

This commit is contained in:
Ed Page 2019-01-30 20:44:08 -07:00
parent 6dee6d44ff
commit 6fb1bbbcd7
24 changed files with 156 additions and 183 deletions

21
Cargo.lock generated
View file

@ -203,7 +203,8 @@ dependencies = [
"deunicode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"exitfailure 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ghp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)",
"ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -372,14 +373,6 @@ dependencies = [
"backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "escargot"
version = "0.3.1"
@ -389,6 +382,14 @@ dependencies = [
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "exitfailure"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.5"
@ -1746,8 +1747,8 @@ dependencies = [
"checksum encoding_rs 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "a69d152eaa438a291636c1971b0a370212165ca8a75759eb66818c5ce9b538f7"
"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
"checksum escargot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19db1f7e74438642a5018cdf263bb1325b2e792f02dd0a3ca6d6c0f0d7b1d5a5"
"checksum exitfailure 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ff5bd832af37f366c6c194d813a11cd90ac484f124f079294f28e357ae40515"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"

View file

@ -35,7 +35,8 @@ pulldown-cmark = {version="0.2", default-features = false}
notify = "4.0"
ghp = "0.1"
regex = "1.1"
error-chain = "0.12"
failure = "0.1"
exitfailure = "0.5"
lazy_static = "1.1"
itertools = "0.8"
ignore = "0.4"

View file

@ -4,6 +4,7 @@ use std::path;
use clap;
use env_logger;
use failure::ResultExt;
use crate::error::*;
use cobalt;
@ -41,7 +42,7 @@ pub fn get_config(matches: &clap::ArgMatches) -> Result<cobalt::ConfigBuilder> {
// Fetch config information if available
let mut config = if let Some(config_path) = config_path {
cobalt::ConfigBuilder::from_file(config_path)
.chain_err(|| format!("Error reading config file {:?}", config_path))?
.with_context(|_| failure::format_err!("Error reading config file {:?}", config_path))?
} else {
let cwd = env::current_dir().expect("How does this fail?");
cobalt::ConfigBuilder::from_cwd(cwd)?

View file

@ -60,7 +60,7 @@ pub fn clean(config: &cobalt::Config) -> Result<()> {
}
};
if cwd.starts_with(&destdir) {
bail!(
failure::bail!(
"Attempting to delete current directory ({:?}), \
Cancelling the operation",
destdir
@ -116,7 +116,7 @@ fn import(config: &cobalt::Config, branch: &str, message: &str) -> Result<()> {
info!("Importing {:?} to {}", config.destination, branch);
if !config.destination.is_dir() {
bail!("`{:?}` is not a directory", config.destination);
failure::bail!("`{:?}` is not a directory", config.destination);
}
ghp::import_dir(&config.destination, branch, message)?;

View file

@ -44,7 +44,7 @@ pub fn debug_command(matches: &clap::ArgMatches) -> Result<()> {
println!("{}", name);
}
}
_ => bail!(matches.usage()),
_ => failure::bail!(matches.usage().to_owned()),
},
("files", Some(matches)) => {
let config = args::get_config(matches)?;
@ -80,14 +80,14 @@ pub fn debug_command(matches: &clap::ArgMatches) -> Result<()> {
}
}
None => {
bail!("Must specify collection");
failure::bail!("Must specify collection");
}
_ => {
bail!("Collection is not yet supported");
failure::bail!("Collection is not yet supported");
}
}
}
_ => bail!(matches.usage()),
_ => failure::bail!(matches.usage().to_owned()),
}
Ok(())

View file

@ -1,29 +1,2 @@
use std::io;
use std::sync;
use clap;
use cobalt;
use ghp;
use hyper;
use notify;
use serde_yaml;
error_chain! {
links {
}
foreign_links {
Clap(clap::Error);
Cobalt(cobalt::Error);
Ghp(ghp::Error);
Hyper(hyper::Error);
Io(io::Error);
Notify(notify::Error);
Recv(sync::mpsc::RecvError);
SerdeYaml(serde_yaml::Error);
}
errors {
}
}
pub use failure::Error;
pub type Result<T> = std::result::Result<T, Error>;

View file

@ -1,18 +1,8 @@
#![warn(warnings)]
extern crate cobalt;
extern crate env_logger;
extern crate ghp;
extern crate hyper;
extern crate notify;
extern crate serde_yaml;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate clap;
@ -29,13 +19,17 @@ mod serve;
use std::alloc;
use clap::{App, AppSettings};
use failure::ResultExt;
use crate::error::*;
#[global_allocator]
static GLOBAL: alloc::System = alloc::System;
quick_main!(run);
fn main() -> std::result::Result<(), exitfailure::ExitFailure> {
run()?;
Ok(())
}
fn run() -> Result<()> {
let app_cli = App::new("Cobalt")
@ -76,10 +70,10 @@ fn run() -> Result<()> {
"import" => build::import_command(matches),
"debug" => debug::debug_command(matches),
_ => {
bail!(global_matches.usage());
failure::bail!(global_matches.usage().to_owned());
}
}
.chain_err(|| format!("{} command failed", command))?;
.with_context(|_| failure::format_err!("{} command failed", command))?;
Ok(())
}

View file

@ -7,6 +7,7 @@ use std::path;
use clap;
use cobalt::cobalt_model;
use failure::ResultExt;
use crate::args;
use crate::error::*;
@ -26,7 +27,7 @@ pub fn init_command(matches: &clap::ArgMatches) -> Result<()> {
let directory = matches.value_of("DIRECTORY").unwrap();
create_new_project(&directory.to_string())
.chain_err(|| "Could not create a new cobalt project")?;
.with_context(|_| failure::err_msg("Could not create a new cobalt project"))?;
info!("Created new project at {}", directory);
Ok(())
@ -73,7 +74,7 @@ pub fn new_command(matches: &clap::ArgMatches) -> Result<()> {
let ext = matches.value_of("with-ext");
create_new_document(&config, title, file, ext)
.chain_err(|| format!("Could not create `{}`", title))?;
.with_context(|_| failure::format_err!("Could not create `{}`", title))?;
Ok(())
}
@ -119,7 +120,7 @@ pub fn rename_command(matches: &clap::ArgMatches) -> Result<()> {
let file = file;
rename_document(&config, source, title, file)
.chain_err(|| format!("Could not rename `{}`", title))?;
.with_context(|_| failure::format_err!("Could not rename `{}`", title))?;
Ok(())
}
@ -145,7 +146,8 @@ pub fn publish_command(matches: &clap::ArgMatches) -> Result<()> {
let config = args::get_config(matches)?;
let config = config.build()?;
publish_document(&config, &file).chain_err(|| format!("Could not publish `{:?}`", file))?;
publish_document(&config, &file)
.with_context(|_| failure::format_err!("Could not publish `{:?}`", file))?;
Ok(())
}
@ -256,9 +258,10 @@ pub fn create_new_document(
};
let rel_file = file.strip_prefix(&config.source).map_err(|_| {
format!(
"New file {:?} not project directory ({:?})",
file, config.source
failure::format_err!(
"New file {} not project directory ({})",
file.display(),
config.source.display()
)
})?;
@ -279,9 +282,9 @@ pub fn create_new_document(
{
pages.slug.as_str()
} else {
bail!(
"Target file wouldn't be a member of any collection: {:?}",
file
failure::bail!(
"Target file wouldn't be a member of any collection: {}",
file.display()
);
};
@ -290,17 +293,17 @@ pub fn create_new_document(
.join(format!("_defaults/{}.{}", file_type, extension));
let source = if source_path.is_file() {
cobalt_model::files::read_file(&source_path)
.chain_err(|| format!("Failed to read default: {:?}", source_path))?
.with_context(|_| failure::format_err!("Failed to read default: {:?}", source_path))?
} else {
debug!(
"No custom default provided ({:?}), falling back to built-in",
source_path
);
if extension != "md" {
bail!(
"No builtin default for `{}` files, only `md`: {:?}",
failure::bail!(
"No builtin default for `{}` files, only `md`: {}",
extension,
file
file.display()
);
}
// For custom collections, use a post default.
@ -331,7 +334,7 @@ fn create_file_for_path(path: &path::Path, content: &str) -> Result<()> {
.write(true)
.create_new(true)
.open(path)
.chain_err(|| format!("Failed to create file {:?}", path))?;
.with_context(|_| failure::format_err!("Failed to create file {}", path.display()))?;
file.write_all(content.as_bytes())?;
@ -389,7 +392,7 @@ pub fn rename_document(
.merge_path(rel_src)
.merge(pages.default.clone())
} else {
bail!(
failure::bail!(
"Target file wouldn't be a member of any collection: {:?}",
target
);
@ -461,7 +464,7 @@ fn move_from_drafts_to_posts(
);
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("Could not create {:?}: {}", parent, e))?;
.with_context(|_| failure::format_err!("Could not create {}", parent.display()))?;
}
fs::rename(file, &target)?;
Ok(target)

View file

@ -8,7 +8,7 @@ use std::time;
use clap;
use cobalt::cobalt_model;
use error_chain::ChainedError;
use failure::ResultExt;
use hyper;
use hyper::server::{Request, Response, Server};
use hyper::uri::RequestUri;
@ -170,18 +170,20 @@ fn watch(config: &cobalt_model::Config) -> Result<()> {
// Files::includes_file
let source = path::Path::new(&config.source)
.canonicalize()
.chain_err(|| "Failed in processing source")?;
.with_context(|_| failure::err_msg("Failed in processing source"))?;
let (tx, rx) = channel();
let mut watcher =
notify::watcher(tx, time::Duration::from_secs(1)).chain_err(|| "Notify error")?;
let mut watcher = notify::watcher(tx, time::Duration::from_secs(1))
.with_context(|_| failure::err_msg("Notify error"))?;
watcher
.watch(&source, notify::RecursiveMode::Recursive)
.chain_err(|| "Notify error")?;
.with_context(|_| failure::err_msg("Notify error"))?;
info!("Watching {:?} for changes", &config.source);
loop {
let event = rx.recv().chain_err(|| "Notify error")?;
let event = rx
.recv()
.with_context(|_| failure::err_msg("Notify error"))?;
let event_path = match event {
notify::DebouncedEvent::Create(ref path)
| notify::DebouncedEvent::NoticeWrite(ref path)
@ -209,7 +211,8 @@ fn watch(config: &cobalt_model::Config) -> Result<()> {
if rebuild {
let result = build::build(config.clone());
if let Err(fail) = result {
error!("build failed\n{}", fail.display_chain());
let fail: exitfailure::ExitFailure = fail.into();
error!("build failed\n{:?}", fail);
}
}
}

View file

@ -4,6 +4,7 @@ use std::fs;
use std::io::Write;
use std::path;
use failure::ResultExt;
use jsonfeed;
use jsonfeed::Feed;
use liquid;
@ -147,9 +148,13 @@ fn generate_doc(
);
doc.render_excerpt(&globals, &context.liquid, &context.markdown)
.chain_err(|| format!("Failed to render excerpt for {:?}", doc.file_path))?;
.with_context(|_| {
failure::format_err!("Failed to render excerpt for {}", doc.file_path.display())
})?;
doc.render_content(&globals, &context.liquid, &context.markdown)
.chain_err(|| format!("Failed to render content for {:?}", doc.file_path))?;
.with_context(|_| {
failure::format_err!("Failed to render content for {}", doc.file_path.display())
})?;
// Refresh `page` with the `excerpt` / `content` attribute
globals.insert(
@ -158,7 +163,9 @@ fn generate_doc(
);
let doc_html = doc
.render(&globals, &context.liquid, &context.layouts)
.chain_err(|| format!("Failed to render for {:?}", doc.file_path))?;
.with_context(|_| {
failure::format_err!("Failed to render for {}", doc.file_path.display())
})?;
files::write_document_file(doc_html, context.destination.join(&doc.file_path))?;
Ok(())
}
@ -291,7 +298,7 @@ fn parse_drafts(
let default_front = collection.default.clone().set_draft(true);
let doc = Document::parse(&file_path, &new_path, default_front)
.chain_err(|| format!("Failed to parse {:?}", rel_src))?;
.with_context(|_| failure::format_err!("Failed to parse {}", rel_src.display()))?;
documents.push(doc);
}
Ok(())
@ -311,12 +318,15 @@ fn parse_layouts(files: &files::Files) -> HashMap<String, String> {
.strip_prefix(files.root())
.expect("file was found under the root");
let layout_data = files::read_file(&file_path)
.map_err(|e| format!("Failed to load layout {:?}: {}", rel_src, e))?;
let layout_data = files::read_file(&file_path).with_context(|_| {
failure::format_err!("Failed to load layout {}", rel_src.display())
})?;
let path = rel_src
.to_str()
.ok_or_else(|| format!("File name not valid liquid path: {:?}", rel_src))?
.ok_or_else(|| {
failure::format_err!("File name not valid liquid path: {}", rel_src.display())
})?
.to_owned();
Ok((path, layout_data))
@ -347,7 +357,7 @@ fn parse_pages(
let default_front = collection.default.clone();
let doc = Document::parse(&file_path, rel_src, default_front)
.chain_err(|| format!("Failed to parse {:?}", rel_src))?;
.with_context(|_| failure::format_err!("Failed to parse {}", rel_src.display()))?;
if !doc.front.is_draft || collection.include_drafts {
documents.push(doc);
}
@ -374,7 +384,7 @@ fn create_rss(
let link = collection
.base_url
.as_ref()
.ok_or(ErrorKind::ConfigFileMissingFields)?;
.ok_or_else(|| failure::err_msg("`base_url` is required for RSS support"))?;
let items: Result<Vec<rss::Item>> = documents.iter().map(|doc| doc.to_rss(link)).collect();
let items = items?;
@ -384,14 +394,16 @@ fn create_rss(
.link(link.to_owned())
.description(description.to_owned())
.items(items)
.build()?;
.build()
.map_err(|s| failure::err_msg(s))?;
let rss_string = channel.to_string();
trace!("RSS data: {}", rss_string);
// create target directories if any exist
if let Some(parent) = rss_path.parent() {
fs::create_dir_all(parent).map_err(|e| format!("Could not create {:?}: {}", parent, e))?;
fs::create_dir_all(parent)
.with_context(|_| failure::format_err!("Could not create {}", parent.display()))?;
}
let mut rss_file = fs::File::create(&rss_path)?;
@ -421,7 +433,7 @@ fn create_jsonfeed(
let link = collection
.base_url
.as_ref()
.ok_or(ErrorKind::ConfigFileMissingFields)?;
.ok_or_else(|| failure::err_msg("`base_url` is required for jsonfeed support"))?;
let jsonitems = documents.iter().map(|doc| doc.to_jsonfeed(link)).collect();

View file

@ -25,7 +25,7 @@ impl AssetsBuilder {
let sass = sass.build();
let source = source.ok_or_else(|| "No asset source provided")?;
let source = source.ok_or_else(|| failure::err_msg("No asset source provided"))?;
let mut files = files::FilesBuilder::new(source)?;
for line in ignore {

View file

@ -70,10 +70,10 @@ impl CollectionBuilder {
default,
} = self;
let title = title.ok_or("Collection is missing a `title`")?;
let title = title.ok_or_else(|| failure::err_msg("Collection is missing a `title`"))?;
let slug = slug.unwrap_or_else(|| slug::slugify(&title));
let source = source.ok_or_else(|| "No asset source provided")?;
let source = source.ok_or_else(|| failure::err_msg("No asset source provided"))?;
let dir = dir.unwrap_or_else(|| slug.clone());
let pages = Self::build_files(&source, &dir, &template_extensions, &ignore)?;
@ -129,7 +129,7 @@ impl CollectionBuilder {
ignore: &[String],
) -> Result<files::Files> {
if dir.starts_with('/') {
bail!("Collection dir {} must be a relative path", dir)
failure::bail!("Collection dir {} must be a relative path", dir)
}
let dir = files::cleanup_path(dir);
let mut pages = files::FilesBuilder::new(source)?;

View file

@ -1,6 +1,7 @@
use std::fmt;
use std::path;
use failure::ResultExt;
use liquid;
use serde_yaml;
@ -316,7 +317,7 @@ impl ConfigBuilder {
let config = file_path
.map(|p| {
debug!("Using config file {:?}", &p);
Self::from_file(&p).chain_err(|| format!("Error reading config file {:?}", p))
Self::from_file(&p).with_context(|_| format!("Error reading config file {:?}", p))
})
.unwrap_or_else(|| {
warn!("No _cobalt.yml file found in current directory, using default config.");
@ -353,7 +354,7 @@ impl ConfigBuilder {
}
if template_extensions.is_empty() {
return Err("`template_extensions` should not be empty.".into());
failure::bail!("`template_extensions` should not be empty.");
}
let source = files::cleanup_path(&source);

View file

@ -6,6 +6,7 @@ use std::iter::FromIterator;
use std::path;
use crate::error::Result;
use failure::ResultExt;
use ignore::gitignore::{Gitignore, GitignoreBuilder};
use ignore::Match;
use normalize_line_endings::normalized;
@ -266,12 +267,18 @@ pub fn read_file<P: AsRef<path::Path>>(path: P) -> Result<String> {
pub fn copy_file(src_file: &path::Path, dest_file: &path::Path) -> Result<()> {
// create target directories if any exist
if let Some(parent) = dest_file.parent() {
fs::create_dir_all(parent).map_err(|e| format!("Could not create {:?}: {}", parent, e))?;
fs::create_dir_all(parent)
.with_context(|_| failure::format_err!("Could not create {}", parent.display()))?;
}
debug!("Copying {:?} to {:?}", src_file, dest_file);
fs::copy(src_file, dest_file)
.map_err(|e| format!("Could not copy {:?} into {:?}: {}", src_file, dest_file, e))?;
fs::copy(src_file, dest_file).with_context(|_| {
failure::format_err!(
"Could not copy {} into {}",
src_file.display(),
dest_file.display()
)
})?;
Ok(())
}
@ -285,11 +292,12 @@ pub fn write_document_file<S: AsRef<str>, P: AsRef<path::Path>>(
fn write_document_file_internal(content: &str, dest_file: &path::Path) -> Result<()> {
// create target directories if any exist
if let Some(parent) = dest_file.parent() {
fs::create_dir_all(parent).map_err(|e| format!("Could not create {:?}: {}", parent, e))?;
fs::create_dir_all(parent)
.with_context(|_| failure::format_err!("Could not create {}", parent.display()))?;
}
let mut file = fs::File::create(dest_file)
.map_err(|e| format!("Could not create {:?}: {}", dest_file, e))?;
.with_context(|_| failure::format_err!("Could not create {}", dest_file.display()))?;
file.write_all(content.as_bytes())?;
trace!("Wrote {}", dest_file.display());

View file

@ -418,9 +418,9 @@ impl FrontmatterBuilder {
let permalink = permalink.unwrap_or_else(|| PATH_ALIAS.to_owned());
let permalink = if !permalink.starts_with('/') {
let resolved = *PERMALINK_ALIASES
.get(permalink.as_str())
.ok_or_else(|| format!("Unsupported permalink alias '{}'", permalink))?;
let resolved = *PERMALINK_ALIASES.get(permalink.as_str()).ok_or_else(|| {
failure::format_err!("Unsupported permalink alias '{}'", permalink)
})?;
resolved.to_owned()
} else {
permalink
@ -428,7 +428,7 @@ impl FrontmatterBuilder {
if let Some(ref tags) = tags {
if tags.iter().any(|x| x.trim().is_empty()) {
return Err("Empty strings are not allowed in tags".into());
failure::bail!("Empty strings are not allowed in tags");
}
}
let tags = if tags.as_ref().map(|t| t.len()).unwrap_or(0) == 0 {
@ -439,8 +439,8 @@ impl FrontmatterBuilder {
let fm = Frontmatter {
permalink,
slug: slug.ok_or_else(|| "No slug")?,
title: title.ok_or_else(|| "No title")?,
slug: slug.ok_or_else(|| failure::err_msg("No slug"))?,
title: title.ok_or_else(|| failure::err_msg("No title"))?,
description,
excerpt,
categories: categories.unwrap_or_else(|| vec![]),
@ -456,7 +456,7 @@ impl FrontmatterBuilder {
};
if !cfg!(feature = "pagination-unstable") && fm.pagination.is_some() {
Err("Unsupported `pagination` field".into())
failure::bail!("Unsupported `pagination` field");
} else {
Ok(fm)
}

View file

@ -77,7 +77,8 @@ impl SassCompiler {
SassOutputStyle::Compact => sass_rs::OutputStyle::Compact,
SassOutputStyle::Compressed => sass_rs::OutputStyle::Compressed,
};
let content = sass_rs::compile_file(file_path, sass_opts)?;
let content =
sass_rs::compile_file(file_path, sass_opts).map_err(|e| failure::err_msg(e))?;
let rel_src = file_path
.strip_prefix(source)

View file

@ -2,6 +2,7 @@ use std::ffi::OsStr;
use std::fs;
use std::path;
use failure::ResultExt;
use liquid;
use serde_json;
use serde_yaml;
@ -74,7 +75,7 @@ fn deep_insert(
let mut map = data_map;
for part in path.iter() {
let key = part.to_str().ok_or_else(|| {
format!(
failure::format_err!(
"The data from {:?} can't be loaded as it contains non utf-8 characters",
path
)
@ -86,7 +87,7 @@ fn deep_insert(
.or_insert_with(|| liquid::value::Value::Object(liquid::value::Object::new()))
.as_object_mut()
.ok_or_else(|| {
format!(
failure::format_err!(
"Aborting: Duplicate in data tree. Would overwrite {:?} ",
path
)
@ -99,7 +100,7 @@ fn deep_insert(
match target_map.insert(target_key.into(), data) {
None => Ok(()),
_ => Err(format!(
_ => Err(failure::format_err!(
"The data from {:?} can't be loaded: the key already exists",
file_path
)
@ -122,7 +123,7 @@ fn load_data(data_path: &path::Path) -> Result<liquid::value::Value> {
let text = files::read_file(data_path)?;
data = toml::from_str(&text)?;
} else {
bail!(
failure::bail!(
"Failed to load of data {:?}: unknown file type '{:?}'.\n\
Supported data files extensions are: yml, yaml, json and toml.",
data_path,
@ -148,10 +149,10 @@ fn insert_data_dir(data: &mut liquid::value::Object, data_root: &path::Path) ->
.expect("Files will always return with a stem");
let file_stem = String::from(file_stem.to_str().unwrap());
let data_fragment = load_data(&full_path)
.chain_err(|| format!("Loading data from {:?} failed", full_path))?;
.with_context(|_| format!("Loading data from {:?} failed", full_path))?;
deep_insert(data, rel_path, file_stem, data_fragment)
.chain_err(|| format!("Merging data into {:?} failed", rel_path))?;
.with_context(|_| format!("Merging data into {:?} failed", rel_path))?;
}
Ok(())

View file

@ -48,7 +48,10 @@ impl LiquidBuilder {
fn highlight(theme: String) -> Result<Box<liquid::compiler::ParseBlock>> {
let result: Result<()> = match syntax_highlight::has_syntax_theme(&theme) {
Ok(true) => Ok(()),
Ok(false) => Err(format!("Syntax theme '{}' is unsupported", theme).into()),
Ok(false) => Err(failure::format_err!(
"Syntax theme '{}' is unsupported",
theme
)),
Err(err) => {
warn!("Syntax theme named '{}' ignored. Reason: {}", theme, err);
Ok(())

View file

@ -4,6 +4,7 @@ use std::default::Default;
use std::path::{Path, PathBuf};
use chrono::{Datelike, Timelike};
use failure::ResultExt;
use itertools;
use jsonfeed;
use liquid;
@ -206,7 +207,9 @@ impl Document {
let (file_path, url_path) = {
let perma_attributes = permalink_attributes(&front, rel_path);
let url_path = permalink::explode_permalink(&front.permalink, &perma_attributes)
.chain_err(|| format!("Failed to create permalink `{}`", front.permalink))?;
.with_context(|_| {
failure::format_err!("Failed to create permalink `{}`", front.permalink)
})?;
let file_path = permalink::format_url_as_file(&url_path);
(file_path, url_path)
};
@ -228,7 +231,8 @@ impl Document {
let guid = rss::GuidBuilder::default()
.value(link.clone())
.permalink(true)
.build()?;
.build()
.map_err(|e| failure::err_msg(e))?;
let item = rss::ItemBuilder::default()
.title(Some(self.front.title.clone()))
@ -236,7 +240,8 @@ impl Document {
.guid(Some(guid))
.pub_date(self.front.published_date.map(|date| date.to_rfc2822()))
.description(self.description_to_str())
.build()?;
.build()
.map_err(|e| failure::err_msg(e))?;
Ok(item)
}
@ -350,25 +355,26 @@ impl Document {
) -> Result<String> {
if let Some(ref layout) = self.front.layout {
let layout_data_ref = layouts.get(layout).ok_or_else(|| {
format!(
"Layout {} does not exist (referenced in {:?}).",
layout, self.file_path
failure::format_err!(
"Layout {} does not exist (referenced in {}).",
layout,
self.file_path.display()
)
})?;
let template = parser
.parse(layout_data_ref)
.chain_err(|| format!("Failed to parse layout {:?}", layout))?;
.with_context(|_| failure::format_err!("Failed to parse layout {:?}", layout))?;
let content_html = template
.render(globals)
.chain_err(|| format!("Failed to render layout {:?}", layout))?;
.with_context(|_| failure::format_err!("Failed to render layout {:?}", layout))?;
Ok(content_html)
} else {
let content_html = globals
.get("page")
.ok_or("Internal error: page isn't in globals")?
.ok_or_else(|| failure::err_msg("Internal error: page isn't in globals"))?
.get(&liquid::value::Scalar::new("content"))
.ok_or("Internal error: page.content isn't in globals")?
.ok_or_else(|| failure::err_msg("Internal error: page.content isn't in globals"))?
.render()
.to_string();

View file

@ -1,30 +1,2 @@
use std::io;
error_chain! {
links {
}
foreign_links {
Io(io::Error);
Liquid(liquid::Error);
WalkDir(walkdir::Error);
SerdeYaml(serde_yaml::Error);
SerdeJson(serde_json::Error);
Toml(toml::de::Error);
Ignore(ignore::Error);
}
errors {
ConfigFileMissingFields {
description("missing fields in config file")
display("name, description and link need to be defined in the config file to \
generate RSS")
}
UnsupportedPlatform(functionality: &'static str, platform: &'static str) {
description("functionality is not implemented for this platform")
display("{} is not implemented for the {} platform", functionality, platform)
}
}
}
pub use failure::Error;
pub type Result<T> = std::result::Result<T, Error>;

View file

@ -3,9 +3,6 @@
#[macro_use]
extern crate log;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lazy_static;

View file

@ -249,7 +249,10 @@ fn distribute_posts_by_tags<'a>(
for post in all_posts {
if let Some(tags) = extract_tags(post) {
for tag in tags {
let tag = tag.as_scalar().ok_or("Should have string tags")?.to_str();
let tag = tag
.as_scalar()
.ok_or_else(|| failure::err_msg("Should have string tags"))?
.to_str();
// add_to_tag(&tag.to_string(), post, &mut per_tags)
let cur_tag = per_tags.entry(tag.to_string()).or_insert(vec![]);
cur_tag.push(post);

View file

@ -12,7 +12,7 @@ use pulldown_cmark as cmark;
use crate::error;
pub fn has_syntax_theme(_name: &str) -> error::Result<bool> {
bail!("Themes are unsupported in this build.");
failure::bail!("Themes are unsupported in this build.");
}
pub fn list_syntax_themes<'a>() -> Vec<&'a String> {

View file

@ -1,17 +1,11 @@
#[macro_use]
extern crate difference;
extern crate assert_fs;
extern crate cobalt;
extern crate error_chain;
extern crate walkdir;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use assert_fs::prelude::*;
use error_chain::ChainedError;
use walkdir::WalkDir;
macro_rules! assert_contains {
@ -155,13 +149,9 @@ pub fn syntax_highlight() {
pub fn incomplete_rss() {
let err = run_test("incomplete_rss");
assert!(err.is_err());
let err = err.unwrap_err();
assert_eq!(
format!("{}", err),
"name, description and link need to be defined in the config file to generate RSS"
);
assert_eq!(err.description(), "missing fields in config file");
let err: exitfailure::ExitFailure = err.unwrap_err().into();
let error_message = format!("{:?}", err);
assert_contains!(error_message, "base_url");
}
#[test]
@ -179,10 +169,12 @@ pub fn liquid_raw() {
pub fn no_extends_error() {
let err = run_test("no_extends_error");
assert!(err.is_err());
let err: exitfailure::ExitFailure = err.unwrap_err().into();
let error_message = format!("{:?}", err);
assert_contains!(
format!("{}", err.unwrap_err().display_chain()),
error_message,
"Layout default_nonexistent.liquid does not exist (referenced in \
\"index.html\")"
index.html)"
);
}
@ -220,7 +212,8 @@ pub fn ignore_files() {
pub fn yaml_error() {
let err = run_test("yaml_error");
assert!(err.is_err());
let error_message = format!("{}", err.unwrap_err().display_chain());
let err: exitfailure::ExitFailure = err.unwrap_err().into();
let error_message = format!("{:?}", err);
assert_contains!(error_message, "unexpected character");
}