summaryrefslogtreecommitdiff
path: root/src/codegen.rs
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2020-04-22 11:58:15 +0300
committerLars Wirzenius <liw@liw.fi>2020-04-22 11:58:15 +0300
commit072b547737703066b383c8c338726c95c4b3591e (patch)
tree745cc70659c9fc363ff443a4ed0a6326c7cfd177 /src/codegen.rs
parent29770c165b7e25b4671760495298540c36f25c38 (diff)
downloadsubplot-072b547737703066b383c8c338726c95c4b3591e.tar.gz
Refactor: move code generation logic to src/codegen.rs
This lets sp-codegen.rs be only about the command line parsing etc.
Diffstat (limited to 'src/codegen.rs')
-rw-r--r--src/codegen.rs85
1 files changed, 80 insertions, 5 deletions
diff --git a/src/codegen.rs b/src/codegen.rs
index bbe1ae7..fd398af 100644
--- a/src/codegen.rs
+++ b/src/codegen.rs
@@ -1,8 +1,83 @@
-use crate::Scenario;
+use crate::{Document, TemplateSpec};
+use std::collections::HashMap;
+use std::fs::File;
+use std::io::prelude::{Read, Write};
+use std::path::Path;
-/// Give a unique name for each scenario.
-pub fn name_scenarios(scens: &mut [Scenario]) {
- for (i, scen) in scens.iter_mut().enumerate() {
- scen.set_name(&format!("scenario_{}", i));
+use base64::encode;
+
+use tera::{Context, Tera, Value};
+
+use anyhow::Result;
+
+/// Return the requested template specification.
+pub fn template_spec(templates: &Path, doc: &Document) -> Result<TemplateSpec> {
+ let template = match doc.meta().template_name() {
+ Some(x) => &x,
+ None => "python",
+ };
+
+ let mut filename = templates.to_path_buf();
+ filename.push(Path::new(template));
+ filename.push(Path::new("template.yaml"));
+ Ok(TemplateSpec::from_file(&filename)?)
+}
+
+/// Generate a test program from a document, using a template spec.
+pub fn generate_test_program(
+ doc: &mut Document,
+ spec: &TemplateSpec,
+ filename: &Path,
+) -> Result<()> {
+ let context = context(doc)?;
+ let tera = tera(&spec)?;
+ let code = tera.render("template", &context).expect("render");
+ write(filename, &code)?;
+ Ok(())
+}
+
+fn context(doc: &mut Document) -> Result<Context> {
+ let mut context = Context::new();
+ context.insert("scenarios", &doc.matched_scenarios()?);
+ context.insert("files", doc.files());
+
+ let (funcs_filename, funcs) = match doc.meta().functions_filename() {
+ Some(filename) => (filename, cat(filename)?),
+ None => ("", "".to_string()),
+ };
+ context.insert("functions", &funcs);
+ context.insert("functions_filename", funcs_filename);
+
+ Ok(context)
+}
+
+fn tera(tmplspec: &TemplateSpec) -> Result<Tera> {
+ // Tera insists on a glob, but we want to load a specific template
+ // only, so we use a glob that doesn't match anything.
+ let mut tera = Tera::new(&"*notexist").expect("new");
+ tera.register_filter("base64", base64);
+ tera.add_template_file(tmplspec.template_filename(), Some("template"))?;
+ Ok(tera)
+}
+
+fn cat<P: AsRef<Path>>(filename: P) -> Result<String> {
+ let mut f = File::open(filename)?;
+ let mut buf = String::new();
+ f.read_to_string(&mut buf)?;
+ Ok(buf)
+}
+
+fn write(filename: &Path, content: &str) -> Result<()> {
+ let mut f: File = File::create(filename)?;
+ f.write_all(&content.as_bytes())?;
+ Ok(())
+}
+
+fn base64(v: &Value, _: &HashMap<String, Value>) -> tera::Result<Value> {
+ match v {
+ Value::String(s) => Ok(Value::String(encode(s))),
+ _ => Err(tera::Error::msg(
+ "can only base64 encode strings".to_string(),
+ )),
}
}