Switch to custom templating library

This commit is contained in:
2021-05-20 16:16:02 +02:00
parent 6f8e1d46c7
commit 00412be372
8 changed files with 207 additions and 395 deletions

View File

@ -1,12 +1,12 @@
use crate::error::{Error, ErrorLocation, Errors};
use crate::{ColorMode, Config};
use crate::error::{Error, ErrorLocation, Errors, InnerError};
use crate::Config;
use async_recursion::async_recursion;
use blueprint::{parse_file, Env, Value};
use futures::future::join_all;
use serde::Serialize;
use std::ffi::OsStr;
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::join;
@ -20,35 +20,28 @@ struct TemplateContext<'a> {
const TEMPLATE_EXTENSION: &str = "tpl";
pub async fn build_tree(cfg: &Config) -> Result<(), Errors> {
let tpl = Templar::global();
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(
InnerData::new(TemplateContext {
hostname: hostname.trim(),
darkmode,
lightmode: !darkmode,
})
.expect("serialize template context"),
)
.expect("set template context");
let mut env = Env::new();
env.insert("hostname".into(), Value::Str(hostname));
dir(cfg, &ctx, &tpl, PathBuf::new()).await
for flag in &cfg.flags {
env.insert(flag.to_string(), Value::Bool(true));
}
info!("env:");
for (k, v) in &env {
info!(" {}: {:?}", k, v);
}
dir(cfg, &env, PathBuf::new()).await
}
#[async_recursion]
async fn dir(
cfg: &Config,
ctx: &StandardContext,
tpl: &Templar,
relative: PathBuf,
) -> Result<(), Errors> {
async fn dir(cfg: &Config, env: &Env, relative: PathBuf) -> Result<(), Errors> {
let template_path = cfg.template_dir.join(&relative);
let build_path = cfg.build_dir.join(&relative);
@ -72,9 +65,9 @@ async fn dir(
let new_relative = relative.join(entry.file_name());
if meta.is_dir() {
dir_tasks.push(dir(cfg, ctx, tpl, new_relative));
dir_tasks.push(dir(cfg, env, new_relative));
} else if meta.is_file() {
file_tasks.push(file(cfg, ctx, tpl, new_relative));
file_tasks.push(file(cfg, env, new_relative));
}
}
@ -99,16 +92,11 @@ async fn dir(
}
}
async fn file(
cfg: &Config,
ctx: &StandardContext,
tpl: &Templar,
relative: PathBuf,
) -> Result<(), Error> {
async fn file(cfg: &Config, env: &Env, relative: PathBuf) -> Result<(), Error> {
let template_path = cfg.template_dir.join(&relative);
let mut new_path = cfg.build_dir.join(&relative);
info!("rendering {:?}", template_path);
debug!("rendering {:?}", template_path);
if template_path.extension() == Some(OsStr::new(TEMPLATE_EXTENSION)) {
// perform templating
@ -116,11 +104,13 @@ async fn file(
.await
.with_location(&template_path)?;
let rendered = tpl
.parse_template(&file_str)
let mut rendered = Vec::<u8>::new();
parse_file(&file_str)
.map_err(|_| InnerError::TemplateParseErr)
.with_location(&template_path)?
.render(ctx)
.write(&env, &mut rendered)
.with_location(&template_path)?;
let rendered = std::str::from_utf8(&rendered).unwrap();
// remove template file extension
new_path.set_extension("");
@ -129,7 +119,7 @@ async fn file(
write(&new_path, &rendered).await.with_location(&new_path)?;
} else {
// else just copy the file
info!("copying {:?}", template_path);
debug!("copying {:?}", template_path);
copy(&template_path, &new_path)
.await
.with_location(&template_path)?;

View File

@ -1,6 +1,6 @@
use compound_error::CompoundError;
use std::io;
use std::path::{Path, PathBuf};
use thiserror::Error;
#[derive(Default)]
pub struct Errors {
@ -12,10 +12,13 @@ pub struct Error {
inner: InnerError,
}
#[derive(CompoundError, Debug)]
#[derive(Debug, Error)]
pub enum InnerError {
IoErr(io::Error),
TemplateErr(templar::TemplarError),
#[error("IO Error: {0}")]
IoErr(#[from] io::Error),
#[error("Failed to parse template file")]
TemplateParseErr,
}
impl From<Vec<Error>> for Errors {
@ -51,8 +54,8 @@ impl Errors {
error!("{} errors occured:", self.errors.len());
for (i, error) in self.errors.iter().enumerate() {
error!("{:.2}. {:?}", i, error.location);
error!(" {:?}", error.inner);
error!(" err {:02} at {:?}:", i, error.location);
error!(" {}", error.inner);
}
}
}

View File

@ -67,13 +67,13 @@ async fn file(cfg: &Config, relative: PathBuf) -> Result<(), Error> {
match remove_file(&link_path).await {
Ok(_) => {
info!("removed existing file {:?}", link_path);
debug!("removed existing file {:?}", link_path);
}
Err(e) if e.kind() == ErrorKind::NotFound => {}
Err(e) => return Err(e.with_location(&link_path)),
};
info!("linking {:?} to {:?}", link_path, build_path);
debug!("linking {:?} to {:?}", link_path, build_path);
let symlink_content = if build_path.is_absolute() {
build_path
} else {

View File

@ -24,11 +24,10 @@ struct Opt {
#[structopt(short, long)]
link_dir: Option<PathBuf>,
#[structopt(subcommand)]
color: Option<ColorMode>,
#[structopt(short, parse(from_occurrences))]
verbosity: u8,
flags: Vec<String>,
}
#[derive(Debug)]
@ -36,13 +35,7 @@ pub struct Config {
template_dir: PathBuf,
build_dir: PathBuf,
link_dir: PathBuf,
color: ColorMode,
}
#[derive(StructOpt, PartialEq, Eq, Clone, Copy, Debug)]
pub enum ColorMode {
Dark,
Light,
flags: Vec<String>,
}
#[tokio::main]
@ -79,7 +72,7 @@ async fn run() -> Result<(), Errors> {
link_dir: opt
.link_dir
.unwrap_or_else(|| env::var("HOME").expect("$HOME").into()),
color: opt.color.unwrap_or(ColorMode::Dark),
flags: opt.flags,
};
info!("building tree");