Add graceful error handling to df script
This commit is contained in:
@ -1,13 +1,14 @@
|
||||
use crate::error::{Error, ErrorLocation, Errors};
|
||||
use crate::{ColorMode, Config};
|
||||
use async_recursion::async_recursion;
|
||||
use futures::future::join_all;
|
||||
use serde::Serialize;
|
||||
use std::ffi::OsStr;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::io::ErrorKind;
|
||||
use std::path::PathBuf;
|
||||
use templar::{Context, InnerData, StandardContext, Templar};
|
||||
use tokio::fs::{copy, create_dir, read_dir, read_to_string, write};
|
||||
use tokio::try_join;
|
||||
use tokio::join;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TemplateContext<'a> {
|
||||
@ -18,10 +19,14 @@ struct TemplateContext<'a> {
|
||||
|
||||
const TEMPLATE_EXTENSION: &str = "tpl";
|
||||
|
||||
pub async fn build_tree(cfg: &Config) -> io::Result<()> {
|
||||
pub async fn build_tree(cfg: &Config) -> Result<(), Errors> {
|
||||
let tpl = Templar::global();
|
||||
|
||||
let hostname = read_to_string("/etc/hostname").await?;
|
||||
let hostname_path: PathBuf = "/etc/hostname".into();
|
||||
let hostname = read_to_string(&hostname_path)
|
||||
.await
|
||||
.with_location(&hostname_path)?;
|
||||
|
||||
let darkmode = cfg.color == ColorMode::Dark;
|
||||
let ctx = StandardContext::new();
|
||||
ctx.set(
|
||||
@ -43,7 +48,7 @@ async fn dir(
|
||||
ctx: &StandardContext,
|
||||
tpl: &Templar,
|
||||
relative: PathBuf,
|
||||
) -> io::Result<()> {
|
||||
) -> Result<(), Errors> {
|
||||
let template_path = cfg.template_dir.join(&relative);
|
||||
let build_path = cfg.build_dir.join(&relative);
|
||||
|
||||
@ -52,16 +57,18 @@ async fn dir(
|
||||
match create_dir(&build_path).await {
|
||||
Ok(_) => {}
|
||||
Err(e) if e.kind() == ErrorKind::AlreadyExists => {}
|
||||
Err(e) => return Err(e),
|
||||
Err(e) => return Err(e.with_location(&build_path).into()),
|
||||
}
|
||||
|
||||
let mut walker = read_dir(&template_path).await?;
|
||||
let mut walker = read_dir(&template_path)
|
||||
.await
|
||||
.with_location(&template_path)?;
|
||||
|
||||
let mut dir_tasks = vec![];
|
||||
let mut file_tasks = vec![];
|
||||
|
||||
while let Some(entry) = walker.next_entry().await? {
|
||||
let meta = entry.metadata().await?;
|
||||
while let Some(entry) = walker.next_entry().await.with_location(&&template_path)? {
|
||||
let meta = entry.metadata().await.with_location(&entry.path())?;
|
||||
let new_relative = relative.join(entry.file_name());
|
||||
|
||||
if meta.is_dir() {
|
||||
@ -71,23 +78,25 @@ async fn dir(
|
||||
}
|
||||
}
|
||||
|
||||
let dirs = async {
|
||||
join_all(dir_tasks)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
let dirs = async { join_all(dir_tasks).await.into_iter().collect::<Vec<_>>() };
|
||||
let files = async { join_all(file_tasks).await.into_iter().collect::<Vec<_>>() };
|
||||
let (dirs, files) = join!(dirs, files);
|
||||
|
||||
let files = async {
|
||||
join_all(file_tasks)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
let mut errors: Errors = files
|
||||
.into_iter()
|
||||
.filter_map(|r| r.err())
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
|
||||
try_join!(dirs, files)?;
|
||||
for error in dirs.into_iter().filter_map(|r| r.err()) {
|
||||
errors.join(error);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
|
||||
async fn file(
|
||||
@ -95,31 +104,35 @@ async fn file(
|
||||
ctx: &StandardContext,
|
||||
tpl: &Templar,
|
||||
relative: PathBuf,
|
||||
) -> io::Result<()> {
|
||||
) -> Result<(), Error> {
|
||||
let template_path = cfg.template_dir.join(&relative);
|
||||
let mut new_path = cfg.build_dir.join(&relative);
|
||||
|
||||
info!("rendering {:?}", template_path);
|
||||
let file_data = read_to_string(&template_path).await?;
|
||||
|
||||
if template_path.extension() == Some(OsStr::new(TEMPLATE_EXTENSION)) {
|
||||
// perform templating
|
||||
// TODO: error handling
|
||||
let file_str = read_to_string(&template_path)
|
||||
.await
|
||||
.with_location(&template_path)?;
|
||||
|
||||
let rendered = tpl
|
||||
.parse_template(&file_data)
|
||||
.expect("failed to parse template")
|
||||
.parse_template(&file_str)
|
||||
.with_location(&template_path)?
|
||||
.render(ctx)
|
||||
.expect("failed to render template");
|
||||
.with_location(&template_path)?;
|
||||
|
||||
// remove template file extension
|
||||
new_path.set_extension("");
|
||||
|
||||
// write the rendered file
|
||||
write(&new_path, &rendered).await?;
|
||||
write(&new_path, &rendered).await.with_location(&new_path)?;
|
||||
} else {
|
||||
// else just copy the file
|
||||
info!("copying {:?}", template_path);
|
||||
copy(&template_path, &new_path).await?;
|
||||
copy(&template_path, &new_path)
|
||||
.await
|
||||
.with_location(&template_path)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user