Functional templating

This commit is contained in:
bluepython508
2023-10-13 13:37:30 +01:00
parent 953dc55b32
commit 342a364aed
8 changed files with 382 additions and 5 deletions

84
src/context.rs Normal file
View File

@@ -0,0 +1,84 @@
use std::path::{Path, PathBuf};
use crate::manifest::{FileDefinition, Manifest, Source, Transform, Params};
use eyre::Result;
use tracing::instrument;
#[derive(Debug)]
pub struct Context {
manifest: Manifest,
root: Source,
params: Params,
}
impl Context {
#[instrument(ret)]
pub fn load(source: Source, params: Params) -> Result<Self> {
let params = Params::load_user()?.merge(params);
Ok(Context {
manifest: load_manifest(&source)?,
root: source.parent().ok_or_else(|| eyre::eyre!("Expect manifest to have a parent"))?,
params,
})
}
#[instrument]
pub fn generate(self, dest: PathBuf) -> Result<()> {
std::fs::create_dir(&dest)?;
for (path, def) in &self.manifest.files {
self.generate_file(&dest, path, def)?;
}
Ok(())
}
#[instrument]
fn generate_file(&self, dest: &Path, path: &PathBuf, def: &FileDefinition) -> Result<()> {
std::fs::create_dir_all(dest.join(path).parent().expect("`dest` should be an absolute path with a parent"))?;
let mut input = self
.root
.join(
&def.src
.clone()
.unwrap_or_else(|| Source::Path(path.to_owned())),
)
.load()?;
for transform in &def.transforms {
input = self.run_transform(transform, input)?;
}
std::fs::write(dest.join(path), input)?;
Ok(())
}
#[instrument(skip(input))]
fn run_transform(&self, transform: &Transform, input: Vec<u8>) -> Result<Vec<u8>> {
match transform.r#type.as_str() {
"template" => run_template(&transform.args, &self.params, input),
_ => todo!(),
}
}
}
#[instrument(ret)]
fn load_manifest(src: &Source) -> Result<Manifest> {
Ok(toml::from_str(std::str::from_utf8(&src.load()?)?)?)
}
#[instrument(skip(input))]
fn run_template(
args: &Params,
params: &Params,
input: Vec<u8>,
) -> Result<Vec<u8>> {
let engine = upon::Engine::new();
let context = args.clone().merge(params.clone());
Ok(engine
.compile(std::str::from_utf8(&input)?)?
.render(context)
.to_string()?
.into_bytes())
}