impove error handling

This commit is contained in:
KitsuneCafe 2024-02-03 15:51:34 -05:00
parent 6d9cd24341
commit 8ac7254c01
2 changed files with 119 additions and 58 deletions

View file

@ -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;
#[derive(Debug)]
pub struct Error {
pub struct Error<'a> {
message: String,
source: Option<&'a dyn std::error::Error>,
}
impl From<String> for Error {
fn from(value: String) -> Self {
Self { message: value }
impl<'a> Display for Error<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
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 {
Self {
message: value.to_string(),
source: Some(&value),
}
}
}
impl From<StripPrefixError> for Error {
impl<'a> From<StripPrefixError> for Error<'a> {
fn from(value: StripPrefixError) -> Self {
Self {
message: value.to_string(),
source: Some(&value),
}
}
}
impl From<Error> for IOError {
impl<'a> From<Error<'a>> for IOError {
fn from(value: Error) -> Self {
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),
}
}
}

View file

@ -1,17 +1,19 @@
pub mod error;
pub mod context;
pub mod config;
pub mod context;
pub mod error;
mod file_path;
use clap::Parser as Clap;
use config::Config;
use context::Context;
use error::Error;
use file_path::FilePath;
use crate::error::Error;
use roxy_markdown_parser::MarkdownParser;
use roxy_markdown_tera_rewriter::{MarkdownTeraPreformatter, MarkdownTeraRewriter};
use roxy_syntect::SyntectParser;
use roxy_tera_parser::{TeraParser, TeraParserOptions};
use clap::Parser as Clap;
use std::{
fs::{self, File},
io::{BufReader, Read},
@ -48,71 +50,94 @@ fn get_files<P: AsRef<Path> + std::fmt::Debug>(path: &P) -> Result<Vec<PathBuf>,
Ok(files)
}
fn main() -> Result<(), 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 = fs::read_to_string(&config_path).map_or_else(
fn load_config(path: &Path) -> Config {
fs::read_to_string(path).map_or_else(
|_| Config::default(),
|f| {
toml::from_str::<Config>(f.as_str())
.unwrap()
.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", &current_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 (meta, files): (Vec<&PathBuf>, Vec<&PathBuf>) =
files.iter().partition(|f| f.extension().unwrap() == "toml");
let mut context = Context::new();
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 mut context = context_from_meta_files(&meta, &file_path)?;
let theme = config.theme.unwrap_or(DEFAULT_THEME.to_string());
for file in files {
let mut parser = Parser::new();
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 mut parser = create_parser(file, &file_path, &context, &theme)?;
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", &current_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();
}
Ok(())
}