95 lines
2.6 KiB
Rust
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())
|
|
}
|