Commit 262d8aa9 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

Template can create Builds

parent 8f08c5d8
...@@ -7,6 +7,7 @@ package packer ...@@ -7,6 +7,7 @@ package packer
type Build struct { type Build struct {
name string name string
builder Builder builder Builder
rawConfig interface{}
prepareCalled bool prepareCalled bool
} }
...@@ -43,9 +44,9 @@ func (NilBuilderFactory) CreateBuilder(name string) Builder { ...@@ -43,9 +44,9 @@ func (NilBuilderFactory) CreateBuilder(name string) Builder {
// Prepare prepares the build by doing some initialization for the builder // Prepare prepares the build by doing some initialization for the builder
// and any hooks. This _must_ be called prior to Run. // and any hooks. This _must_ be called prior to Run.
func (b *Build) Prepare(config interface{}) { func (b *Build) Prepare() {
b.prepareCalled = true b.prepareCalled = true
b.builder.Prepare(config) b.builder.Prepare(b.rawConfig)
} }
// Runs the actual build. Prepare must be called prior to running this. // Runs the actual build. Prepare must be called prior to running this.
......
...@@ -5,6 +5,14 @@ import ( ...@@ -5,6 +5,14 @@ import (
"testing" "testing"
) )
type hashBuilderFactory struct {
builderMap map[string]Builder
}
func (bf *hashBuilderFactory) CreateBuilder(name string) Builder {
return bf.builderMap[name]
}
type TestBuilder struct { type TestBuilder struct {
prepareCalled bool prepareCalled bool
prepareConfig interface{} prepareConfig interface{}
...@@ -28,17 +36,25 @@ func testBuild() *Build { ...@@ -28,17 +36,25 @@ func testBuild() *Build {
return &Build{ return &Build{
name: "test", name: "test",
builder: &TestBuilder{}, builder: &TestBuilder{},
rawConfig: 42,
} }
} }
func testBuilder() *TestBuilder {
return &TestBuilder{}
}
func testBuildFactory(builderMap map[string]Builder) BuilderFactory {
return &hashBuilderFactory{builderMap}
}
func TestBuild_Prepare(t *testing.T) { func TestBuild_Prepare(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true) assert := asserts.NewTestingAsserts(t, true)
build := testBuild() build := testBuild()
build.Prepare(42)
builder := build.builder.(*TestBuilder) builder := build.builder.(*TestBuilder)
build.Prepare()
assert.True(builder.prepareCalled, "prepare should be called") assert.True(builder.prepareCalled, "prepare should be called")
assert.Equal(builder.prepareConfig, 42, "prepare config should be 42") assert.Equal(builder.prepareConfig, 42, "prepare config should be 42")
} }
...@@ -49,7 +65,7 @@ func TestBuild_Run(t *testing.T) { ...@@ -49,7 +65,7 @@ func TestBuild_Run(t *testing.T) {
ui := testUi() ui := testUi()
build := testBuild() build := testBuild()
build.Prepare(nil) build.Prepare()
build.Run(ui) build.Run(ui)
builder := build.builder.(*TestBuilder) builder := build.builder.(*TestBuilder)
......
package packer package packer
import "encoding/json" import (
"encoding/json"
"fmt"
)
// The rawTemplate struct represents the structure of a template read // The rawTemplate struct represents the structure of a template read
// directly from a file. The builders and other components map just to // directly from a file. The builders and other components map just to
...@@ -74,3 +77,42 @@ func ParseTemplate(data []byte) (t *Template, err error) { ...@@ -74,3 +77,42 @@ func ParseTemplate(data []byte) (t *Template, err error) {
return return
} }
// BuildNames returns a slice of the available names of builds that
// this template represents.
func (t *Template) BuildNames() []string {
names := make([]string, len(t.Builders))
i := 0
for name, _ := range t.Builders {
names[i] = name
i++
}
return names
}
// Build returns a Build for the given name.
//
// If the build does not exist as part of this template, an error is
// returned.
func (t *Template) Build(name string, bf BuilderFactory) (b *Build, err error) {
builderConfig, ok := t.Builders[name]
if !ok {
err = fmt.Errorf("No such build found in template: %s", name)
return
}
builder := bf.CreateBuilder(builderConfig.builderName)
if builder == nil {
err = fmt.Errorf("Builder could not be found: %s", builderConfig.builderName)
return
}
b = &Build{
name: name,
builder: builder,
rawConfig: builderConfig.rawConfig,
}
return
}
...@@ -2,6 +2,7 @@ package packer ...@@ -2,6 +2,7 @@ package packer
import ( import (
"cgl.tideland.biz/asserts" "cgl.tideland.biz/asserts"
"sort"
"testing" "testing"
) )
...@@ -87,3 +88,121 @@ func TestParseTemplate_BuilderWithName(t *testing.T) { ...@@ -87,3 +88,121 @@ func TestParseTemplate_BuilderWithName(t *testing.T) {
assert.True(ok, "should have bob builder") assert.True(ok, "should have bob builder")
assert.Equal(builder.builderName, "amazon-ebs", "builder should be amazon-ebs") assert.Equal(builder.builderName, "amazon-ebs", "builder should be amazon-ebs")
} }
func TestTemplate_BuildNames(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
data := `
{
"name": "my-image",
"builders": [
{
"name": "bob",
"type": "amazon-ebs"
},
{
"name": "chris",
"type": "another"
}
]
}
`
result, err := ParseTemplate([]byte(data))
assert.Nil(err, "should not error")
buildNames := result.BuildNames()
sort.Strings(buildNames)
assert.Equal(buildNames, []string{"bob", "chris"}, "should have proper builds")
}
func TestTemplate_BuildUnknown(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
data := `
{
"name": "my-image",
"builders": [
{
"name": "test1",
"type": "test-builder"
}
]
}
`
template, err := ParseTemplate([]byte(data))
assert.Nil(err, "should not error")
build, err := template.Build("nope", nil)
assert.Nil(build, "build should be nil")
assert.NotNil(err, "should have error")
}
func TestTemplate_BuildUnknownBuilder(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
data := `
{
"name": "my-image",
"builders": [
{
"name": "test1",
"type": "test-builder"
}
]
}
`
template, err := ParseTemplate([]byte(data))
assert.Nil(err, "should not error")
builderFactory := testBuildFactory(map[string]Builder{})
build, err := template.Build("test1", builderFactory)
assert.Nil(build, "build should be nil")
assert.NotNil(err, "should have error")
}
func TestTemplate_Build(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
data := `
{
"name": "my-image",
"builders": [
{
"name": "test1",
"type": "test-builder"
}
]
}
`
expectedConfig := map[string]interface{} {
"name": "test1",
"type": "test-builder",
}
template, err := ParseTemplate([]byte(data))
assert.Nil(err, "should not error")
builder := testBuilder()
builderMap := map[string]Builder {
"test-builder": builder,
}
builderFactory := testBuildFactory(builderMap)
// Get the build, verifying we can get it without issue, but also
// that the proper builder was looked up and used for the build.
build, err := template.Build("test1", builderFactory)
assert.Nil(err, "should not error")
build.Prepare()
build.Run(testUi())
assert.True(builder.prepareCalled, "prepare should be called")
assert.Equal(builder.prepareConfig, expectedConfig, "prepare config should be correct")
assert.True(builder.runCalled, "run should be called")
assert.Equal(builder.runBuild, build, "run should be called with build")
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment