lyrs/src/templates.rs

92 lines
2.6 KiB
Rust
Raw Normal View History

2024-05-14 14:30:03 -05:00
use crate::{file_watcher::prelude::*, prelude::*};
use minijinja::Environment;
use pathdiff::diff_paths;
2024-05-14 14:30:03 -05:00
use std::{path::PathBuf, sync::Arc};
use tokio::sync::Mutex;
2024-05-14 12:28:27 -05:00
use tower_livereload::Reloader;
2024-05-14 14:30:03 -05:00
use tracing::{info, instrument};
2024-05-14 14:30:03 -05:00
#[derive(Clone, Debug)]
pub struct Templates {
env: Arc<Mutex<Environment<'static>>>,
2024-05-14 12:28:27 -05:00
dir: PathBuf,
}
impl Templates {
2024-05-14 12:28:27 -05:00
pub fn for_dir<P: Into<PathBuf>>(dir: P) -> Self {
let env = Arc::new(Mutex::new(Environment::new()));
2024-05-14 12:28:27 -05:00
Self {
env,
dir: dir.into(),
}
}
2024-05-14 14:30:03 -05:00
pub async fn try_load<P: Into<PathBuf>>(dir: P) -> Result<Self> {
2024-05-14 12:28:27 -05:00
let result = Self::for_dir(dir);
result.load_env().await?;
Ok(result)
}
2024-05-14 12:28:27 -05:00
pub async fn start_watcher(
self: Arc<Self>,
reloader: Option<Reloader>,
2024-05-14 14:30:03 -05:00
) -> Result<Option<FileWatcher>> {
2024-05-14 12:28:27 -05:00
if let Some(rl) = reloader {
Ok(Some(self.watch(rl).await?))
} else {
Ok(None)
}
}
2024-05-14 14:30:03 -05:00
async fn watch(self: Arc<Self>, reloader: Reloader) -> Result<FileWatcher> {
// TODO: only reload template that changed?
let watcher = file_monitor(self.dir.clone(), move || {
futures::executor::block_on(async {
self.load_env()
2024-05-14 12:28:27 -05:00
.await
.expect("Failed to reload templates after template changed during runtime");
2024-05-14 14:30:03 -05:00
reloader.reload();
});
})?;
2024-05-14 12:28:27 -05:00
Ok(watcher)
}
2024-05-14 14:30:03 -05:00
#[instrument]
pub async fn load_env(&self) -> Result<()> {
info!("Loading templates...");
2024-05-14 12:28:27 -05:00
for d in walkdir::WalkDir::new(&self.dir) {
match d {
Ok(d) => {
if d.file_type().is_dir() {
continue;
}
let filename: String = diff_paths(d.path(), "src/templates")
.unwrap()
.to_string_lossy()
.into_owned();
2024-05-14 14:30:03 -05:00
info!("Loading template {filename:?} ({d:?})");
self.env
.lock()
.await
.add_template_owned(filename, std::fs::read_to_string(d.path())?)?;
}
Err(_) => todo!(),
}
}
Ok(())
}
pub async fn render<S: serde::ser::Serialize>(
&self,
template_name: &str,
context: S,
2024-05-14 14:30:03 -05:00
) -> Result<String> {
Ok(self
.env
.lock()
.await
.get_template(template_name)?
2024-05-14 14:30:03 -05:00
.render(context)?)
}
}