impove error handling
This commit is contained in:
parent
6d9cd24341
commit
8ac7254c01
52
src/error.rs
52
src/error.rs
|
@ -1,36 +1,72 @@
|
||||||
use std::{io::{Error as IOError, ErrorKind}, path::StripPrefixError};
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
|
io::{Error as IOError, ErrorKind},
|
||||||
|
path::StripPrefixError,
|
||||||
|
};
|
||||||
|
|
||||||
use glob::PatternError;
|
use glob::PatternError;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Error {
|
pub struct Error<'a> {
|
||||||
message: String,
|
message: String,
|
||||||
|
source: Option<&'a dyn std::error::Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Error {
|
impl<'a> Display for Error<'a> {
|
||||||
fn from(value: String) -> Self {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
Self { message: value }
|
write!(f, "{}", &self.message)?;
|
||||||
|
|
||||||
|
if let Some(source) = self.source {
|
||||||
|
write!(f, " ({})", &source)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PatternError> for Error {
|
impl<'a> std::error::Error for Error<'a> {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<String> for Error<'a> {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self {
|
||||||
|
message: value,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<PatternError> for Error<'a> {
|
||||||
fn from(value: PatternError) -> Self {
|
fn from(value: PatternError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
message: value.to_string(),
|
message: value.to_string(),
|
||||||
|
source: Some(&value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StripPrefixError> for Error {
|
impl<'a> From<StripPrefixError> for Error<'a> {
|
||||||
fn from(value: StripPrefixError) -> Self {
|
fn from(value: StripPrefixError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
message: value.to_string(),
|
message: value.to_string(),
|
||||||
|
source: Some(&value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for IOError {
|
impl<'a> From<Error<'a>> for IOError {
|
||||||
fn from(value: Error) -> Self {
|
fn from(value: Error) -> Self {
|
||||||
IOError::new(ErrorKind::Other, value.message)
|
IOError::new(ErrorKind::Other, value.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&dyn std::error::Error> for Error<'a> {
|
||||||
|
fn from(value: &dyn std::error::Error) -> Self {
|
||||||
|
Self {
|
||||||
|
message: value.to_string(),
|
||||||
|
source: Some(&value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
125
src/main.rs
125
src/main.rs
|
@ -1,17 +1,19 @@
|
||||||
pub mod error;
|
|
||||||
pub mod context;
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod context;
|
||||||
|
pub mod error;
|
||||||
mod file_path;
|
mod file_path;
|
||||||
|
|
||||||
use clap::Parser as Clap;
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use context::Context;
|
use context::Context;
|
||||||
|
use error::Error;
|
||||||
use file_path::FilePath;
|
use file_path::FilePath;
|
||||||
use crate::error::Error;
|
|
||||||
use roxy_markdown_parser::MarkdownParser;
|
use roxy_markdown_parser::MarkdownParser;
|
||||||
use roxy_markdown_tera_rewriter::{MarkdownTeraPreformatter, MarkdownTeraRewriter};
|
use roxy_markdown_tera_rewriter::{MarkdownTeraPreformatter, MarkdownTeraRewriter};
|
||||||
use roxy_syntect::SyntectParser;
|
use roxy_syntect::SyntectParser;
|
||||||
use roxy_tera_parser::{TeraParser, TeraParserOptions};
|
use roxy_tera_parser::{TeraParser, TeraParserOptions};
|
||||||
|
|
||||||
|
use clap::Parser as Clap;
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{BufReader, Read},
|
io::{BufReader, Read},
|
||||||
|
@ -48,71 +50,94 @@ fn get_files<P: AsRef<Path> + std::fmt::Debug>(path: &P) -> Result<Vec<PathBuf>,
|
||||||
Ok(files)
|
Ok(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn load_config(path: &Path) -> Config {
|
||||||
let opts = Options::parse();
|
fs::read_to_string(path).map_or_else(
|
||||||
|
|
||||||
let file_path = FilePath::new(&opts.input, &opts.output);
|
|
||||||
|
|
||||||
let config_path = file_path.input.with_file_name("config.toml");
|
|
||||||
let config = fs::read_to_string(&config_path).map_or_else(
|
|
||||||
|_| Config::default(),
|
|_| Config::default(),
|
||||||
|f| {
|
|f| {
|
||||||
toml::from_str::<Config>(f.as_str())
|
toml::from_str::<Config>(f.as_str())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.merge(Config::default())
|
.merge(Config::default())
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context_from_meta_files<'a, T: AsRef<Path>>(
|
||||||
|
files: &Vec<&PathBuf>,
|
||||||
|
file_path: &'a FilePath<T>,
|
||||||
|
) -> Result<Context, Error<'a>> {
|
||||||
|
let mut context = Context::new();
|
||||||
|
|
||||||
|
for path in files {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
let mut file = File::open(path).map(BufReader::new)?;
|
||||||
|
file.read_to_end(&mut buf)?;
|
||||||
|
let mut str = String::from_utf8(buf)?;
|
||||||
|
let toml: Table = toml::from_str(&mut str)?;
|
||||||
|
|
||||||
|
context.insert(&file_path.strip_root(path)?, &tera::to_value(toml)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_parser<'a, T: AsRef<Path>>(
|
||||||
|
file: &Path,
|
||||||
|
file_path: &FilePath<T>,
|
||||||
|
context: &'a Context,
|
||||||
|
theme: &str,
|
||||||
|
) -> Result<Parser<'a>, Error<'a>> {
|
||||||
|
let mut parser = Parser::new();
|
||||||
|
let mut preformatter = MarkdownTeraPreformatter::new();
|
||||||
|
parser.push(&mut preformatter);
|
||||||
|
|
||||||
|
let mut syntect = SyntectParser::new(theme);
|
||||||
|
parser.push(&mut syntect);
|
||||||
|
|
||||||
|
let mut md = MarkdownParser::new();
|
||||||
|
parser.push(&mut md);
|
||||||
|
|
||||||
|
let mut rewriter = MarkdownTeraRewriter::new();
|
||||||
|
parser.push(&mut rewriter);
|
||||||
|
|
||||||
|
let file_name = file.with_extension("html");
|
||||||
|
let output_path = file_path.to_output(&file_name)?;
|
||||||
|
|
||||||
|
if let Ok(path) = &file_path.strip_root(&file_name) {
|
||||||
|
if let Some(current_context) = context.get(path) {
|
||||||
|
context.insert(&"this", ¤t_context.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tera = tera::Tera::default();
|
||||||
|
let mut html = TeraParser::new(&mut tera, TeraParserOptions::default());
|
||||||
|
html.add_context(context.to_inner());
|
||||||
|
Ok(parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let opts = Options::parse();
|
||||||
|
|
||||||
|
let file_path = FilePath::new(&opts.input, &opts.output);
|
||||||
|
|
||||||
|
let config_path = file_path.input.with_file_name("config.toml");
|
||||||
|
let config = load_config(&config_path);
|
||||||
|
|
||||||
let files = get_files(&file_path.input)?;
|
let files = get_files(&file_path.input)?;
|
||||||
let (meta, files): (Vec<&PathBuf>, Vec<&PathBuf>) =
|
let (meta, files): (Vec<&PathBuf>, Vec<&PathBuf>) =
|
||||||
files.iter().partition(|f| f.extension().unwrap() == "toml");
|
files.iter().partition(|f| f.extension().unwrap() == "toml");
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = context_from_meta_files(&meta, &file_path)?;
|
||||||
|
|
||||||
for path in meta {
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
|
|
||||||
let mut file = File::open(path).map(BufReader::new).unwrap();
|
|
||||||
file.read_to_end(&mut buf).unwrap();
|
|
||||||
let mut str = String::from_utf8(buf).unwrap();
|
|
||||||
let toml: Table = toml::from_str(&mut str).unwrap();
|
|
||||||
|
|
||||||
context.insert(
|
|
||||||
&file_path.strip_root(path).unwrap(),
|
|
||||||
&tera::to_value(toml).unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let theme = config.theme.unwrap_or(DEFAULT_THEME.to_string());
|
let theme = config.theme.unwrap_or(DEFAULT_THEME.to_string());
|
||||||
for file in files {
|
for file in files {
|
||||||
let mut parser = Parser::new();
|
let mut parser = create_parser(file, &file_path, &context, &theme)?;
|
||||||
let mut preformatter = MarkdownTeraPreformatter::new();
|
|
||||||
parser.push(&mut preformatter);
|
|
||||||
|
|
||||||
let mut syntect = SyntectParser::new(&theme.as_str());
|
|
||||||
parser.push(&mut syntect);
|
|
||||||
|
|
||||||
let mut md = MarkdownParser::new();
|
|
||||||
parser.push(&mut md);
|
|
||||||
|
|
||||||
let mut rewriter = MarkdownTeraRewriter::new();
|
|
||||||
parser.push(&mut rewriter);
|
|
||||||
|
|
||||||
let file_name = file.with_extension("html");
|
let file_name = file.with_extension("html");
|
||||||
let output_path = file_path.to_output(&file_name)?;
|
let output_path = file_path.to_output(&file_name)?;
|
||||||
|
|
||||||
if let Ok(path) = &file_path.strip_root(&file_name) {
|
|
||||||
if let Some(current_context) = context.get(path) {
|
|
||||||
context.insert(&"this", ¤t_context.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tera = tera::Tera::default();
|
|
||||||
let mut html = TeraParser::new(&mut tera, TeraParserOptions::default());
|
|
||||||
html.add_context(context.to_inner());
|
|
||||||
parser.push(&mut html);
|
|
||||||
|
|
||||||
Roxy::process_file(&file, &output_path, &mut parser).unwrap();
|
Roxy::process_file(&file, &output_path, &mut parser).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue