use tera::{Context, Kwargs, State, Tera, TeraResult, Value};
use crate::Result;
const INLINE_TEMPLATE: &str = "__loco_inline";
#[allow(clippy::needless_pass_by_value)]
fn get_env(kwargs: Kwargs, _state: &State<'_>) -> TeraResult<Value> {
let name: String = kwargs.must_get("name")?;
match std::env::var(&name) {
Ok(value) => Ok(Value::from(value)),
Err(_) => kwargs.get::<Value>("default")?.ok_or_else(|| {
tera::Error::message(format!(
"environment variable `{name}` not found and no `default` was given"
))
}),
}
}
fn register_functions(tera: &mut Tera) {
tera.register_function("get_env", get_env);
}
#[must_use]
pub fn instance() -> Tera {
let mut tera = Tera::default();
register_functions(&mut tera);
crate::controller::views::tera_builtins::filters::register_filters(&mut tera);
tera
}
pub fn render_string(tera_template: &str, locals: &serde_json::Value) -> Result<String> {
let mut tera = Tera::default();
register_functions(&mut tera);
tera.add_raw_template(INLINE_TEMPLATE, tera_template)?;
Ok(tera.render(INLINE_TEMPLATE, &Context::from_serialize(locals)?)?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_env_falls_back_to_default_when_unset() {
let out = render_string(
r#"{{ get_env(name="LOCO_NOPE_UNSET", default="fallback") }}"#,
&serde_json::json!({}),
)
.unwrap();
assert_eq!(out, "fallback");
}
#[test]
fn get_env_reads_the_environment() {
unsafe { std::env::set_var("LOCO_TERA_TEST_VAR", "from-env") };
let out = render_string(
r#"{{ get_env(name="LOCO_TERA_TEST_VAR", default="fallback") }}"#,
&serde_json::json!({}),
)
.unwrap();
assert_eq!(out, "from-env");
unsafe { std::env::remove_var("LOCO_TERA_TEST_VAR") };
}
#[test]
fn get_env_errors_when_unset_and_no_default() {
assert!(render_string(
r#"{{ get_env(name="LOCO_NOPE_UNSET") }}"#,
&serde_json::json!({})
)
.is_err());
}
}