diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-04-22 11:58:15 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-04-22 11:58:15 +0300 |
commit | 072b547737703066b383c8c338726c95c4b3591e (patch) | |
tree | 745cc70659c9fc363ff443a4ed0a6326c7cfd177 /src/codegen.rs | |
parent | 29770c165b7e25b4671760495298540c36f25c38 (diff) | |
download | subplot-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.rs | 85 |
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(), + )), } } |