Merge pull request #2232 from mitchellh/f-build-name

core: add build_name and build_type functions
This commit is contained in:
Mitchell Hashimoto 2015-06-15 09:42:22 -07:00
commit 723b91ccf3
8 changed files with 159 additions and 4 deletions

View File

@ -106,6 +106,8 @@ func Decode(target interface{}, config *DecodeOpts, raws ...interface{}) error {
// detecting things like user variables from the raw configuration params.
func DetectContext(raws ...interface{}) (*interpolate.Context, error) {
var s struct {
BuildName string `mapstructure:"packer_build_name"`
BuildType string `mapstructure:"packer_builder_type"`
TemplatePath string `mapstructure:"packer_template_path"`
Vars map[string]string `mapstructure:"packer_user_variables"`
}
@ -117,6 +119,8 @@ func DetectContext(raws ...interface{}) (*interpolate.Context, error) {
}
return &interpolate.Context{
BuildName: s.BuildName,
BuildType: s.BuildType,
TemplatePath: s.TemplatePath,
UserVariables: s.Vars,
}, nil

View File

@ -142,6 +142,64 @@ func TestCoreBuild_env(t *testing.T) {
}
}
func TestCoreBuild_buildNameVar(t *testing.T) {
config := TestCoreConfig(t)
testCoreTemplate(t, config, fixtureDir("build-var-build-name.json"))
b := TestBuilder(t, config, "test")
core := TestCore(t, config)
b.ArtifactId = "hello"
build, err := core.Build("test")
if err != nil {
t.Fatalf("err: %s", err)
}
if _, err := build.Prepare(); err != nil {
t.Fatalf("err: %s", err)
}
// Interpolate the config
var result map[string]interface{}
err = configHelper.Decode(&result, nil, b.PrepareConfig...)
if err != nil {
t.Fatalf("err: %s", err)
}
if result["value"] != "test" {
t.Fatalf("bad: %#v", result)
}
}
func TestCoreBuild_buildTypeVar(t *testing.T) {
config := TestCoreConfig(t)
testCoreTemplate(t, config, fixtureDir("build-var-build-type.json"))
b := TestBuilder(t, config, "test")
core := TestCore(t, config)
b.ArtifactId = "hello"
build, err := core.Build("test")
if err != nil {
t.Fatalf("err: %s", err)
}
if _, err := build.Prepare(); err != nil {
t.Fatalf("err: %s", err)
}
// Interpolate the config
var result map[string]interface{}
err = configHelper.Decode(&result, nil, b.PrepareConfig...)
if err != nil {
t.Fatalf("err: %s", err)
}
if result["value"] != "test" {
t.Fatalf("bad: %#v", result)
}
}
func TestCoreBuild_nonExist(t *testing.T) {
config := TestCoreConfig(t)
testCoreTemplate(t, config, fixtureDir("build-basic.json"))

View File

@ -0,0 +1,6 @@
{
"builders": [{
"type": "test",
"value": "{{build_name}}"
}]
}

View File

@ -0,0 +1,6 @@
{
"builders": [{
"type": "test",
"value": "{{build_type}}"
}]
}

View File

@ -24,6 +24,8 @@ func init() {
// Funcs are the interpolation funcs that are available within interpolations.
var FuncGens = map[string]FuncGenerator{
"build_name": funcGenBuildName,
"build_type": funcGenBuildType,
"env": funcGenEnv,
"isotime": funcGenIsotime,
"pwd": funcGenPwd,
@ -56,6 +58,26 @@ func Funcs(ctx *Context) template.FuncMap {
return template.FuncMap(result)
}
func funcGenBuildName(ctx *Context) interface{} {
return func() (string, error) {
if ctx == nil || ctx.BuildName == "" {
return "", errors.New("build_name not available")
}
return ctx.BuildName, nil
}
}
func funcGenBuildType(ctx *Context) interface{} {
return func() (string, error) {
if ctx == nil || ctx.BuildType == "" {
return "", errors.New("build_name not available")
}
return ctx.BuildType, nil
}
}
func funcGenEnv(ctx *Context) interface{} {
return func(k string) (string, error) {
if !ctx.EnableEnv {

View File

@ -8,6 +8,56 @@ import (
"time"
)
func TestFuncBuildName(t *testing.T) {
cases := []struct {
Input string
Output string
}{
{
`{{build_name}}`,
"foo",
},
}
ctx := &Context{BuildName: "foo"}
for _, tc := range cases {
i := &I{Value: tc.Input}
result, err := i.Render(ctx)
if err != nil {
t.Fatalf("Input: %s\n\nerr: %s", tc.Input, err)
}
if result != tc.Output {
t.Fatalf("Input: %s\n\nGot: %s", tc.Input, result)
}
}
}
func TestFuncBuildType(t *testing.T) {
cases := []struct {
Input string
Output string
}{
{
`{{build_type}}`,
"foo",
},
}
ctx := &Context{BuildType: "foo"}
for _, tc := range cases {
i := &I{Value: tc.Input}
result, err := i.Render(ctx)
if err != nil {
t.Fatalf("Input: %s\n\nerr: %s", tc.Input, err)
}
if result != tc.Output {
t.Fatalf("Input: %s\n\nGot: %s", tc.Input, result)
}
}
}
func TestFuncEnv(t *testing.T) {
cases := []struct {
Input string

View File

@ -14,16 +14,23 @@ type Context struct {
// Funcs are extra functions available in the template
Funcs map[string]interface{}
// TemplatePath is the path to the template that this is being
// rendered within.
TemplatePath string
// UserVariables is the mapping of user variables that the
// "user" function reads from.
UserVariables map[string]string
// EnableEnv enables the env function
EnableEnv bool
// All the fields below are used for built-in functions.
//
// BuildName and BuildType are the name and type, respectively,
// of the builder being used.
//
// TemplatePath is the path to the template that this is being
// rendered within.
BuildName string
BuildType string
TemplatePath string
}
// Render is shorthand for constructing an I and calling Render.

View File

@ -55,6 +55,8 @@ While some configuration settings have local variables specific to only that
configuration, a set of functions are available globally for use in _any string_
in Packer templates. These are listed below for reference.
* `build_name` - The name of the build being run.
* `build_type` - The type of the builder being used currently.
* `isotime [FORMAT]` - UTC time, which can be [formatted](http://golang.org/pkg/time/#example_Time_Format).
See more examples below.
* `lower` - Lowercases the string.