aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Letan <contact@thomasletan.fr>2019-08-04 23:06:18 +0200
committerThomas Letan <contact@thomasletan.fr>2019-08-04 23:10:04 +0200
commit56dbe3dc6024a39d5c588a38efc02f4e2933c5a0 (patch)
tree84767776cfd08c355d60af1090dafe42e28ae2f9
parentfix: Address several errors returned by EPUB Validator (diff)
refactor: Provide a less cumbersome error handling
-rw-r--r--src/epub.rs39
-rw-r--r--src/error.rs30
-rw-r--r--src/main.rs22
-rw-r--r--src/project.rs28
4 files changed, 71 insertions, 48 deletions
diff --git a/src/epub.rs b/src/epub.rs
index ebd68b4..db910e0 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -1,9 +1,13 @@
-use crate::project::{Error, Project, Chapter};
+use std::fs;
use std::fs::{create_dir_all};
use std::path::{Path, PathBuf};
+
use tera::{Tera, Context};
use serde_json::json;
+use crate::error::{Raise, Error};
+use crate::project::{Project, Chapter};
+
const EPUB_MIMETYPE: &'static str = "application/epub+zip";
fn write_template_to(tera : &Tera, template : &str, ctx : &Context, path : &PathBuf) -> Result<(), Error> {
@@ -11,21 +15,19 @@ fn write_template_to(tera : &Tera, template : &str, ctx : &Context, path : &Path
if !directory.exists() {
create_dir_all(directory)
- .map_err(|_| Error(format!("cannot create directory {:?}", directory)))?;
+ .or_raise(&format!("cannot create directory {:?}", directory))?;
}
let content = tera.render(template, ctx)
- .map_err(|e| Error(format!("cannot render {}: {}", template, e)))?;
+ .or_raise(&format!("cannot render {}", template))?;
- std::fs::write(path, content)
- .map_err(|_| Error(format!("cannot create {:?}", path)))?;
+ fs::write(path, content).or_raise(&format!("cannot create {:?}", path))?;
Ok(())
}
fn create_mimetype() -> Result<(), Error> {
- std::fs::write("mimetype", EPUB_MIMETYPE)
- .map_err(|_| Error(String::from("cannot create mimetype")))?;
+ fs::write("mimetype", EPUB_MIMETYPE).or_raise("cannot create mimetype")?;
Ok(())
}
@@ -85,18 +87,13 @@ fn fonts_dir(assets : &PathBuf) -> Result<PathBuf, Error> {
}
fn install_fonts(assets : &PathBuf, fonts : &Vec<&str>) -> Result<(), Error> {
- create_dir_all("OEBPS/Fonts/")
- .map_err(|_| Error(String::from("cannot create directory OEBPS/Fonts/")))?;
+ create_dir_all("OEBPS/Fonts/").or_raise("cannot create directory OEBPS/Fonts/")?;
for f in fonts {
- let mut src = fonts_dir(assets)?;
- src.push(f);
- let mut dst = PathBuf::from("OEBPS/Fonts");
- dst.push(f);
-
- std::fs::copy(src, dst)
- .map_err(|_| Error(format!("cannot copy {}", f)))?;
+ let src = fonts_dir(assets)?.join(f);
+ let dst = PathBuf::from("OEBPS/Fonts").join(f);
+ fs::copy(src, dst).or_raise(&format!("cannot copy {}", f))?;
}
Ok(())
@@ -104,15 +101,13 @@ fn install_fonts(assets : &PathBuf, fonts : &Vec<&str>) -> Result<(), Error> {
fn install_cover(cover : &PathBuf) -> Result<String, Error> {
let extension = cover.extension()
- .ok_or(Error(String::from("cover lacks an extension")))?
+ .or_raise("cover lacks an extension")?
.to_str()
- .ok_or(Error(String::from("cover extension is not valid utf-8")))?;
+ .or_raise("cover extension is not valid utf-8")?;
- let mut dst = PathBuf::from("OEBPS");
- dst.push(format!("cover.{}", extension));
+ let dst = PathBuf::from("OEBPS").join(format!("cover.{}", extension));
- std::fs::copy(cover, dst)
- .map_err(|_| Error(format!("cannot copy {:?}", cover)))?;
+ fs::copy(cover, dst).or_raise(&format!("cannot copy {:?}", cover))?;
Ok(extension.into())
}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..d92077e
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,30 @@
+#[derive(Debug)]
+pub struct Error(pub String);
+
+impl Error {
+ pub fn new(str : &str) -> Error {
+ Error(String::from(str))
+ }
+}
+
+pub trait Raise {
+ type Out;
+
+ fn or_raise(self, msg: &str) -> Self::Out;
+}
+
+impl<T> Raise for Option<T> {
+ type Out = Result<T, Error>;
+
+ fn or_raise(self, msg: &str) -> Result<T, Error> {
+ self.ok_or(Error(String::from(msg)))
+ }
+}
+
+impl<T, E> Raise for Result<T, E> {
+ type Out = Result<T, Error>;
+
+ fn or_raise(self, msg: &str) -> Result<T, Error> {
+ self.map_err(|_| Error(String::from(msg)))
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index b3d0251..bcccad1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,27 +8,28 @@ extern crate tera;
use clap::{App, SubCommand};
+pub mod error;
pub mod render;
pub mod project;
pub mod epub;
-use project::{Project, Error};
+use std::env::{current_dir, set_current_dir};
+use std::fs::{create_dir, remove_dir_all};
+use std::path::PathBuf;
+
use ogmarkup::typography::FRENCH;
-use std::path::PathBuf;
-use std::fs::{create_dir, remove_dir_all};
+use error::{Raise, Error};
+use project::Project;
const BUILD_DIR : &'static str = "_build";
fn cd_clean_build_dir() -> Result<(), Error> {
- remove_dir_all(BUILD_DIR)
- .map_err(|_| Error(String::from("cannot clean up _build/")))?;
+ remove_dir_all(BUILD_DIR).or_raise("cannot clean up _build/")?;
- create_dir(BUILD_DIR)
- .map_err(|_| Error(String::from("cannot create _build/")))?;
+ create_dir(BUILD_DIR).or_raise("cannot create _build/")?;
- std::env::set_current_dir(BUILD_DIR)
- .map_err(|_| Error(String::from("cannot set current directory to _build")))?;
+ set_current_dir(BUILD_DIR).or_raise("cannot set current directory to _build/")?;
Ok(())
}
@@ -60,8 +61,7 @@ fn main() -> Result<(), Error> {
let (subcommand, _args) = matches.subcommand();
// TODO: in release mode, look for /usr/share/celtchar/assets
- let assets: PathBuf = std::env::current_dir()
- .map_err(|_| Error(String::from("cannot get current directory")))?;
+ let assets: PathBuf = current_dir().or_raise("cannot get current directory")?;
match subcommand {
"build" => build(&assets)?,
diff --git a/src/project.rs b/src/project.rs
index 05d0f33..c411587 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -1,18 +1,16 @@
use std::fs;
use std::path::PathBuf;
-use std::env::current_dir;
+use std::env::{current_dir, set_current_dir};
use serde_derive::{Deserialize, Serialize};
use ogmarkup::typography::Typography;
use crate::render::Html;
+use crate::error::{Raise, Error};
const PROJECT_FILE: &'static str = "Book.toml";
-#[derive(Debug)]
-pub struct Error(pub String);
-
#[derive(Debug, Serialize, Deserialize)]
pub struct Chapter<A> {
pub title: Option<String>,
@@ -26,11 +24,12 @@ fn compile_file <'input, T> (
where
T : Typography,
{
- let input = fs::read_to_string(path.as_path()).map_err(|_| Error(format!("cannot open {:?}", path)))?;
+ let input = fs::read_to_string(path.as_path())
+ .or_raise(&format!("cannot open {:?}", path))?;
ogmarkup::compile(input.as_str(), typo)
.map(|x: Html| x.to_string())
- .map_err(|_| Error(format!("cannot render {:?}", path)))
+ .or_raise(&format!("cannot render {:?}", path))
}
impl Chapter<Vec<PathBuf>> {
@@ -62,8 +61,7 @@ pub struct Project<A> {
impl Project<Vec<PathBuf>> {
pub fn cd_root() -> Result<(), Error> {
- let mut cwd: PathBuf = current_dir()
- .map_err(|_| Error(String::from("cannot get current directory")))?;
+ let mut cwd: PathBuf = current_dir().or_raise("cannot get current directory")?;
loop {
cwd.push(PROJECT_FILE); // (*)
@@ -71,8 +69,8 @@ impl Project<Vec<PathBuf>> {
if cwd.exists() {
cwd.pop();
- std::env::set_current_dir(cwd.as_path())
- .map_err(|_| Error(format!("cannot set current directory to {:?}", cwd)))?;
+ set_current_dir(cwd.as_path())
+ .or_raise(&format!("cannot set current directory to {:?}", cwd))?;
return Ok(());
} else {
@@ -84,7 +82,7 @@ impl Project<Vec<PathBuf>> {
// `pop` returns false, we are at the root of the current FS, and
// there is no project file to find.
if !cwd.pop() {
- return Err(Error(String::from("could not find Book.toml")))
+ return Err(Error::new("could not find Book.toml"))
}
}
}
@@ -94,10 +92,10 @@ impl Project<Vec<PathBuf>> {
/// read it as a TOML file.
pub fn find_project() -> Result<Self, Error> {
let input = fs::read_to_string(PROJECT_FILE)
- .map_err(|_| Error(String::from("found Book.toml, but cannot read it")))?;
+ .or_raise("found Book.toml, but cannot read it")?;
- return toml::from_str(input.as_str())
- .map_err(|e| Error(String::from(format!("toml error: {:?}", e))));
+ toml::from_str(input.as_str())
+ .or_raise(&format!("could not parse Book.toml"))
}
pub fn load_and_render<'input, T> (
@@ -111,7 +109,7 @@ impl Project<Vec<PathBuf>> {
let title = self.title;
let cover = self.cover
.map(|x| fs::canonicalize(&x)
- .map_err(|_| Error(String::from("cannot compute a canonical path for the cover"))))
+ .or_raise("cannot compute a canonical path for the cover"))
// from Option<Result<_, E>> to Result<Option<_>, E>
.map_or(Ok(None), |r| r.map(Some))?;