diff --git a/components/sup/src/package/hooks.rs b/components/sup/src/package/hooks.rs index b7340c47af..223e639ef8 100644 --- a/components/sup/src/package/hooks.rs +++ b/components/sup/src/package/hooks.rs @@ -25,6 +25,7 @@ use error::{Error, Result}; use package::Package; use service_config::{ServiceConfig, never_escape_fn}; use util::convert; +use util::handlebars_helpers; static LOGKEY: &'static str = "PH"; @@ -117,6 +118,8 @@ impl Hook { if let Some(ctx) = context { debug!("Rendering hook {:?}", self); let mut handlebars = Handlebars::new(); + handlebars.register_helper("json", Box::new(handlebars_helpers::json_helper)); + handlebars.register_helper("toml", Box::new(handlebars_helpers::toml_helper)); handlebars.register_escape_fn(never_escape_fn); try!(handlebars.register_template_file("hook", &self.template)); let toml = try!(ctx.to_toml()); diff --git a/components/sup/src/service_config.rs b/components/sup/src/service_config.rs index 154b77ff3c..8b89024170 100644 --- a/components/sup/src/service_config.rs +++ b/components/sup/src/service_config.rs @@ -34,6 +34,7 @@ use hcore::crypto; use package::Package; use util; use util::convert; +use util::handlebars_helpers; use VERSION; static LOGKEY: &'static str = "SC"; @@ -147,9 +148,13 @@ impl ServiceConfig { let mut last_toml = try!(File::create(pi.svc_path().join("config.toml"))); try!(write!(&mut last_toml, "{}", toml::encode_str(&final_toml))); } + let mut handlebars = Handlebars::new(); + + debug!("Registering handlebars helpers"); + handlebars.register_helper("json", Box::new(handlebars_helpers::json_helper)); + handlebars.register_helper("toml", Box::new(handlebars_helpers::toml_helper)); debug!("Registering configuration templates"); - let mut handlebars = Handlebars::new(); // By default, handlebars escapes HTML. We don't want that. handlebars.register_escape_fn(never_escape_fn); diff --git a/components/sup/src/util/handlebars_helpers.rs b/components/sup/src/util/handlebars_helpers.rs new file mode 100644 index 0000000000..fb446fd0dc --- /dev/null +++ b/components/sup/src/util/handlebars_helpers.rs @@ -0,0 +1,94 @@ +// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError}; +use rustc_serialize::Encodable; +use toml; + +pub fn json_helper(_: &Context, + h: &Helper, + _: &Handlebars, + rc: &mut RenderContext) + -> Result<(), RenderError> { + let value_to_render = try!(h.param(0) + .ok_or_else(|| RenderError::new("Param not found for helper \"json\""))) + .value(); + try!(rc.writer.write(value_to_render.pretty().to_string().into_bytes().as_ref())); + Ok(()) +} + +pub fn toml_helper(_: &Context, + h: &Helper, + _: &Handlebars, + rc: &mut RenderContext) + -> Result<(), RenderError> { + let value_to_render = try!(h.param(0) + .ok_or_else(|| RenderError::new("Param not found for helper \"toml\""))) + .value(); + let mut toml_encoder = toml::Encoder::new(); + value_to_render.encode(&mut toml_encoder).unwrap(); + let table: toml::Table = toml_encoder.toml; + try!(rc.writer.write(toml::encode_str(&table).into_bytes().as_ref())); + Ok(()) +} + +#[cfg(test)] +mod test { + use handlebars::{Handlebars, Template}; + use std::collections::BTreeMap; + use super::{json_helper, toml_helper}; + + #[test] + fn test_handlebars_json_helper() { + let t = Template::compile("{{json x}}".to_string()).ok().unwrap(); + let mut data = BTreeMap::new(); + data.insert("test".into(), "something".into()); + + let mut handlebars = Handlebars::new(); + handlebars.register_helper("json", Box::new(json_helper)); + handlebars.register_template("t", t); + + let mut m: BTreeMap> = BTreeMap::new(); + m.insert("x".into(), data); + + let r = handlebars.render("t", &m); + + assert_eq!(r.ok().unwrap(), + r#"{ + "test": "something" +}"# + .to_string()); + } + + #[test] + fn test_handlebars_toml_helper() { + let t = Template::compile("{{toml x}}".to_string()).ok().unwrap(); + let mut data = BTreeMap::new(); + data.insert("test".into(), "something".into()); + + let mut handlebars = Handlebars::new(); + handlebars.register_helper("toml", Box::new(toml_helper)); + handlebars.register_template("t", t); + + let mut m: BTreeMap> = BTreeMap::new(); + m.insert("x".into(), data); + + let r = handlebars.render("t", &m); + + assert_eq!(r.ok().unwrap(), + r#"test = "something" +"# + .to_string()); + } +} diff --git a/components/sup/src/util/mod.rs b/components/sup/src/util/mod.rs index 13b824d508..c946c7eef2 100644 --- a/components/sup/src/util/mod.rs +++ b/components/sup/src/util/mod.rs @@ -13,6 +13,7 @@ // limitations under the License. pub mod convert; +pub mod handlebars_helpers; pub mod path; pub mod sys; pub mod signals; diff --git a/www/source/docs/create-packages-configure.html.md b/www/source/docs/create-packages-configure.html.md index 226b912182..aecba6569e 100644 --- a/www/source/docs/create-packages-configure.html.md +++ b/www/source/docs/create-packages-configure.html.md @@ -120,6 +120,68 @@ like this: host = host-2 port = 3434 +## File format helpers + +### JSON + +To output configuration data as JSON, you can use the `json` helper. + +Given a default.toml that looks like: + + [web] + + [["servers"]] + host = "host-1" + port = 4545 + + [["servers"]] + host = "host-2" + port = 3434 + +and a template: + + {{ json cfg.web }} + +when rendered, it will look like: + + { + "servers": [ + { + "host": "host-1", + "port": 4545 + }, + { + "host": "host-2", + "port": 3434 + } + ] + } + +This can be useful if you have a confugration file that is in JSON format and +has the same structure as your TOML configuration data. + +### TOML + +The `toml` helper can be used to output TOML. + +Given a default.toml that looks like: + + [web] + + port = 00 + +and a template: + + {{ toml cfg.web }} + +when rendered, it will look like: + + port = 80 + +This can be useful if you have an app that uses TOML as its configuration file +format, but may have not been designed for Habitat, and you only need certain +parts of the configuration data in the rendered TOML file. + ## Further examples For an example of how to templatize a configuration file and add it to your plan, see [Add configuration to your plan](/tutorials/getting-started-configure-plan) from the getting started tutorial.