Skip to content

Commit

Permalink
Using handlebers 6 - first pass
Browse files Browse the repository at this point in the history
Signed-off-by: Abhijit Gadgil <[email protected]>
  • Loading branch information
agadgil-progress committed Feb 5, 2025
1 parent f0bb73a commit 32d03cb
Show file tree
Hide file tree
Showing 23 changed files with 401 additions and 267 deletions.
241 changes: 138 additions & 103 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion components/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ habitat_core = { path = "../core" }
# with our templating syntax; we use "foo[0]", but it now requires
# "foo.[0]"
# See https://github.com/sunng87/handlebars-rust/commit/707f05442ef6f441a1cfc6b13ac180b78cb296db
handlebars = { version = "= 0.28.3", default-features = false }
handlebars = { version = "*", default-features = false }
lazy_static = "*"
libc = "*"
log = "0.4"
Expand Down
14 changes: 9 additions & 5 deletions components/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ pub enum Error {
StringFromUtf8Error(string::FromUtf8Error),
/// When an error occurs registering template file
// Boxed due to clippy::large_enum_variant
TemplateFileError(Box<handlebars::TemplateFileError>),
TemplateError(handlebars::TemplateError),
/// When an error occurs rendering template
/// The error is constructed with a handlebars::RenderError's format string instead
/// of the handlebars::RenderError itself because the cause field of the
/// handlebars::RenderError in the handlebars crate version we use implements send
/// and not sync which can lead to upstream compile errors when dealing with the
/// failure crate. We should change this to a RenderError after we update the
/// handlebars crate. See https://github.com/sunng87/handlebars-rust/issues/194
TemplateRenderError(String),
TemplateRenderError(handlebars::RenderError),
/// When an error occurs merging toml
TomlMergeError(String),
/// When an error occurs parsing toml
Expand Down Expand Up @@ -216,7 +216,7 @@ impl fmt::Display for Error {
}
Error::StrFromUtf8Error(ref e) => format!("{}", e),
Error::StringFromUtf8Error(ref e) => format!("{}", e),
Error::TemplateFileError(ref err) => format!("{:?}", err),
Error::TemplateError(ref err) => format!("{:?}", err),
Error::TemplateRenderError(ref err) => err.to_string(),
Error::TomlMergeError(ref e) => format!("Failed to merge TOML: {}", e),
Error::TomlParser(ref err) => format!("Failed to parse TOML: {}", err),
Expand All @@ -242,8 +242,12 @@ impl From<api_client::Error> for Error {
fn from(err: api_client::Error) -> Self { Error::APIClient(err) }
}

impl From<handlebars::TemplateFileError> for Error {
fn from(err: handlebars::TemplateFileError) -> Self { Error::TemplateFileError(Box::new(err)) }
impl From<handlebars::TemplateError> for Error {
fn from(err: handlebars::TemplateError) -> Self { Error::TemplateError(err) }
}

impl From<handlebars::RenderError> for Error {
fn from(err: handlebars::RenderError) -> Self { Error::TemplateRenderError(err) }
}

impl From<hcore::Error> for Error {
Expand Down
30 changes: 15 additions & 15 deletions components/common/src/templating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use crate::{error::{Error,
FeatureFlag};
use handlebars::{Handlebars,
RenderError,
TemplateFileError};
TemplateError,
TemplateErrorReason};
use lazy_static::lazy_static;
use log::debug;
use regex::Regex;
Expand Down Expand Up @@ -69,12 +70,12 @@ pub async fn compile_for_package_install(package: &PackageInstall,

pub type RenderResult<T> = result::Result<T, RenderError>;

pub struct TemplateRenderer(Handlebars);
pub struct TemplateRenderer(Handlebars<'static>);

impl TemplateRenderer {
pub fn new() -> Self {
pub fn new() -> TemplateRenderer {
let mut handlebars = Handlebars::new();
handlebars.register_helper("eachAlive", Box::new(helpers::EACH_ALIVE));
// handlebars.register_helper("eachAlive", Box::new(helpers::EACH_ALIVE));
handlebars.register_helper("pkgPathFor", Box::new(helpers::PKG_PATH_FOR));
handlebars.register_helper("strConcat", Box::new(helpers::STR_CONCAT));
handlebars.register_helper("strJoin", Box::new(helpers::STR_JOIN));
Expand All @@ -96,7 +97,7 @@ impl TemplateRenderer {
debug!("Rendering template with context, {}, {}", template, raw);
self.0
.render(template, &raw)
.map_err(|e| Error::TemplateRenderError(format!("{}", e)))
.map_err(|e| Error::TemplateRenderError(e))
}

// This method is only implemented so we can intercept the call to Handlebars and display
Expand All @@ -106,14 +107,14 @@ impl TemplateRenderer {
pub fn register_template_file<P>(&mut self,
name: &str,
path: P)
-> result::Result<(), TemplateFileError>
-> result::Result<(), TemplateError>
where P: AsRef<std::path::Path>
{
let path = path.as_ref();
let template_string =
std::fs::read_to_string(path).map_err(|e| {
TemplateFileError::IOError(e, name.to_owned())
})?;
let template_string = std::fs::read_to_string(path).map_err(|e| {
TemplateError::of(TemplateErrorReason::IoError(e,
name.to_owned()))
})?;

// If we detect deprecated object access syntax notify the user.
if RE.is_match(&template_string) {
Expand All @@ -136,8 +137,7 @@ impl TemplateRenderer {
});
}

self.0.register_template_string(name, template_string)?;
Ok(())
self.0.register_template_string(name, template_string)
}
}

Expand All @@ -148,13 +148,13 @@ impl fmt::Debug for TemplateRenderer {
}

impl Deref for TemplateRenderer {
type Target = Handlebars;
type Target = Handlebars<'static>;

fn deref(&self) -> &Handlebars { &self.0 }
fn deref(&self) -> &Handlebars<'static> { &self.0 }
}

impl DerefMut for TemplateRenderer {
fn deref_mut(&mut self) -> &mut Handlebars { &mut self.0 }
fn deref_mut(&mut self) -> &mut Handlebars<'static> { &mut self.0 }
}

/// Disables HTML escaping which is enabled by default in Handlebars.
Expand Down
15 changes: 8 additions & 7 deletions components/common/src/templating/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,14 @@ impl CfgRenderer {
pub fn new<T>(templates_path: T) -> Result<Self>
where T: AsRef<Path>
{
if templates_path.as_ref().is_dir() {
load_templates(templates_path.as_ref(),
&PathBuf::new(),
TemplateRenderer::new()).map(CfgRenderer)
let renderer = if templates_path.as_ref().is_dir() {
let path = PathBuf::new();
let renderer = TemplateRenderer::new();
load_templates(templates_path.as_ref(), &path, renderer)?
} else {
Ok(CfgRenderer(TemplateRenderer::new()))
}
TemplateRenderer::new()
};
Ok(CfgRenderer(renderer))
}

/// Compile and write all configuration files to the configuration directory.
Expand Down Expand Up @@ -562,7 +563,7 @@ fn load_templates(dir: &Path,
Ok(file_type) if file_type.is_file() => {
// JW TODO: This error needs improvement. TemplateFileError is too generic.
template.register_template_file(&relative_path.to_string_lossy(), &entry.path())
.map_err(|e| Error::TemplateFileError(Box::new(e)))?;
.map_err(|e| Error::TemplateError(e))?;
}
Ok(file_type) if file_type.is_dir() => {
template = load_templates(&entry.path(), &relative_path, template)?
Expand Down
5 changes: 3 additions & 2 deletions components/common/src/templating/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod each_alive;
// mod each_alive;
mod pkg_path_for;
mod str_concat;
mod str_join;
Expand All @@ -9,7 +9,7 @@ mod to_toml;
mod to_uppercase;
mod to_yaml;

pub use self::{each_alive::EACH_ALIVE,
pub use self::{// each_alive::EACH_ALIVE,
pkg_path_for::PKG_PATH_FOR,
str_concat::STR_CONCAT,
str_join::STR_JOIN,
Expand Down Expand Up @@ -42,6 +42,7 @@ impl JsonTruthy for Json {
}
}

#[allow(dead_code)]
/// Helper which will serialize to Json the given reference or return `Json::Null`
fn to_json<T>(src: &T) -> Json
where T: Serialize
Expand Down
21 changes: 14 additions & 7 deletions components/common/src/templating/helpers/each_alive.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use super::{super::RenderResult,
to_json,
JsonTruthy};
use handlebars::{Handlebars,
use handlebars::{Context,
Handlebars,
Helper,
HelperDef,
HelperResult,
Output,
RenderContext,
RenderError,
Renderable};
Expand All @@ -14,13 +17,17 @@ use std::collections::BTreeMap;
pub struct EachAliveHelper;

impl HelperDef for EachAliveHelper {
fn call(&self, h: &Helper<'_>, r: &Handlebars, rc: &mut RenderContext<'_>) -> RenderResult<()> {
fn call<'reg: 'rc, 'rc>(&self,
h: &Helper<'rc>,
r: &'reg Handlebars<'reg>,
rc: &'rc Context,
rc: &mut RenderContext<'reg, 'rc>,
_: &mut dyn Output)
-> HelperResult {
let value = h.param(0)
.ok_or_else(|| RenderError::new("Param not found for helper \"eachAlive\""))?;
.ok_or(|| RenderErrorReason::ParamNotFoundForIndex("eachAlive", 0))?;

if let Some(template) = h.template() {
rc.promote_local_vars();
let local_path_root = value.path_root()
.map(|p| format!("{}/{}", rc.get_path(), p));
let rendered = match (value.value().is_truthy(), value.value()) {
(true, Json::Array(list)) => {
let alive_members: Vec<Json> = list.iter()
Expand All @@ -36,7 +43,7 @@ impl HelperDef for EachAliveHelper {
.collect();
let len = alive_members.len();
for (i, alive_member) in alive_members.iter().enumerate() {
let mut local_rc = rc.derive();
let mut local_rc = rc.block_mut();
local_rc.set_local_var("@first".to_string(), to_json(&(i == 0usize)));
local_rc.set_local_var("@last".to_string(), to_json(&(i == len - 1)));
local_rc.set_local_var("@index".to_string(), to_json(&i));
Expand Down
25 changes: 17 additions & 8 deletions components/common/src/templating/helpers/pkg_path_for.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
use super::super::RenderResult;
use crate::hcore::{fs,
package::{Identifiable,
PackageIdent}};
use handlebars::{Handlebars,
use handlebars::{Context,
Handlebars,
Helper,
HelperDef,
HelperResult,
Output,
RenderContext,
RenderError};
RenderErrorReason};
use std::str::FromStr;

#[derive(Clone, Copy)]
pub struct PkgPathForHelper;

impl HelperDef for PkgPathForHelper {
fn call(&self, h: &Helper<'_>, _: &Handlebars, rc: &mut RenderContext<'_>) -> RenderResult<()> {
fn call<'reg: 'rc, 'rc>(&self,
h: &Helper<'rc>,
_r: &'reg Handlebars<'reg>,
ctx: &'rc Context,
_rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output)
-> HelperResult {
let param =
h.param(0)
.and_then(|v| v.value().as_str())
.and_then(|v| PackageIdent::from_str(v).ok())
.ok_or_else(|| RenderError::new("Invalid package identifier for \"pkgPathFor\""))?;
.ok_or_else(|| {
RenderErrorReason::Other("Invalid package identifier for \"pkgPathFor\"".to_string())
})?;
let deps =
serde_json::from_value::<Vec<PackageIdent>>(rc.context().data()["pkg"]["deps"].clone())
.unwrap();
serde_json::from_value::<Vec<PackageIdent>>(ctx.data()["pkg"]["deps"].clone()).unwrap();
let target_pkg =
deps.iter()
.find_map(|ident| {
Expand All @@ -33,7 +42,7 @@ impl HelperDef for PkgPathForHelper {
}
})
.unwrap_or_default();
rc.writer.write_all(target_pkg.into_bytes().as_ref())?;
out.write(target_pkg.as_ref())?;
Ok(())
}
}
Expand Down
21 changes: 14 additions & 7 deletions components/common/src/templating/helpers/str_concat.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
use handlebars::{Handlebars,
use handlebars::{Context,
Handlebars,
Helper,
HelperDef,
HelperResult,
Output,
RenderContext};

use super::super::RenderResult;

#[derive(Clone, Copy)]
pub struct StrConcatHelper;

impl HelperDef for StrConcatHelper {
fn call(&self, h: &Helper<'_>, _: &Handlebars, rc: &mut RenderContext<'_>) -> RenderResult<()> {
fn call<'reg: 'rc, 'rc>(&self,
h: &Helper<'rc>,
_: &'reg Handlebars<'reg>,
_: &'rc Context,
_rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output)
-> HelperResult {
let list: Vec<String> = h.params()
.iter()
.map(handlebars::ContextJson::value)
.map(handlebars::PathAndJson::value)
.filter(|v| !v.is_object())
.map(|v| v.to_string().replace('\"', ""))
.collect();

rc.writer.write_all(list.concat().into_bytes().as_ref())?;
out.write(list.concat().as_ref())?;
Ok(())
}
}
Expand All @@ -35,7 +42,7 @@ mod test {
handlebars.register_helper("strConcat", Box::new(STR_CONCAT));
let expected = "foobarbaz";
assert_eq!(expected,
handlebars.template_render("{{strConcat \"foo\" \"bar\" \"baz\"}}", &json!({}))
handlebars.render_template("{{strConcat \"foo\" \"bar\" \"baz\"}}", &json!({}))
.unwrap());
}
}
Loading

0 comments on commit 32d03cb

Please sign in to comment.