Files
sablono/src/context.rs
2023-12-12 21:51:23 +00:00

95 lines
2.6 KiB
Rust

use std::path::{Path, PathBuf};
use crate::manifest::{FileDefinition, Manifest, Params, Source, Transform};
use eyre::{Result, ensure};
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)?;
}
for command in &self.manifest.commands {
let success = std::process::Command::new(&command.command)
.args(&command.args)
.current_dir(&dest)
.status()?
.success();
ensure!(success, "Command {:?} failed", command.command);
}
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())
}