Add manager script

This commit is contained in:
2021-04-06 20:28:59 +02:00
commit ecb50e1cf5
6 changed files with 1096 additions and 0 deletions

111
manager/src/builder.rs Normal file
View File

@ -0,0 +1,111 @@
use crate::{ColorMode, Opt};
use async_recursion::async_recursion;
use futures::future::join_all;
use handlebars::{Context, Handlebars};
use serde::Serialize;
use std::ffi::OsStr;
use std::io::{self, ErrorKind};
use std::path::PathBuf;
use tokio::fs::{copy, create_dir, read_dir, read_to_string, write};
use tokio::try_join;
#[derive(Serialize)]
struct TemplateContext<'a> {
hostname: &'a str,
lightmode: bool,
darkmode: bool,
}
pub async fn build_tree(opt: &Opt) -> io::Result<()> {
let hostname = read_to_string("/etc/hostname").await?;
let darkmode = opt.color.map(|m| m == ColorMode::Dark).unwrap_or(true);
let hbs = Handlebars::new();
let ctx = Context::wraps(TemplateContext {
hostname: hostname.trim(),
darkmode,
lightmode: !darkmode,
})
.expect("template context");
dir(opt, &ctx, &hbs, PathBuf::new()).await
}
#[async_recursion]
async fn dir(opt: &Opt, ctx: &Context, hbs: &Handlebars<'_>, relative: PathBuf) -> io::Result<()> {
let template_path = opt.template_dir.join(&relative);
let build_path = opt.build_dir.join(&relative);
info!("traversing {:?}", template_path);
match create_dir(&build_path).await {
Ok(_) => {}
Err(e) if e.kind() == ErrorKind::AlreadyExists => {}
Err(e) => return Err(e),
}
let mut walker = read_dir(&template_path).await?;
let mut dir_tasks = vec![];
let mut file_tasks = vec![];
while let Some(entry) = walker.next_entry().await? {
let meta = entry.metadata().await?;
let new_relative = relative.join(entry.file_name());
if meta.is_dir() {
dir_tasks.push(dir(opt, ctx, hbs, new_relative));
} else if meta.is_file() {
file_tasks.push(file(opt, ctx, hbs, new_relative));
}
}
let dirs = async {
join_all(dir_tasks)
.await
.into_iter()
.collect::<Result<Vec<_>, _>>()
};
let files = async {
join_all(file_tasks)
.await
.into_iter()
.collect::<Result<Vec<_>, _>>()
};
try_join!(dirs, files)?;
Ok(())
}
async fn file(opt: &Opt, ctx: &Context, hbs: &Handlebars<'_>, relative: PathBuf) -> io::Result<()> {
let template_path = opt.template_dir.join(&relative);
let mut new_path = opt.build_dir.join(&relative);
// if it is a handlebars file
if template_path.extension() == Some(OsStr::new("hbs")) {
info!("rendering {:?}", template_path);
let file_data = read_to_string(&template_path).await?;
// perform templating
// TODO: error handling
let rendered = hbs
.render_template_with_context(&file_data, &ctx)
.expect("template error");
// remove .hbs
new_path.set_extension("");
// write the rendered file
write(&new_path, &rendered).await?;
} else {
// else just copy the file
info!("copying {:?}", template_path);
copy(&template_path, &new_path).await?;
}
Ok(())
}