Template can create Builds

This commit is contained in:
Mitchell Hashimoto 2013-04-21 12:36:55 -07:00
parent 8f08c5d8a2
commit 262d8aa9a8
4 changed files with 184 additions and 6 deletions

View File

@ -7,6 +7,7 @@ package packer
type Build struct {
name string
builder Builder
rawConfig interface{}
prepareCalled bool
}
@ -43,9 +44,9 @@ func (NilBuilderFactory) CreateBuilder(name string) Builder {
// Prepare prepares the build by doing some initialization for the builder
// and any hooks. This _must_ be called prior to Run.
func (b *Build) Prepare(config interface{}) {
func (b *Build) Prepare() {
b.prepareCalled = true
b.builder.Prepare(config)
b.builder.Prepare(b.rawConfig)
}
// Runs the actual build. Prepare must be called prior to running this.

View File

@ -5,6 +5,14 @@ import (
"testing"
)
type hashBuilderFactory struct {
builderMap map[string]Builder
}
func (bf *hashBuilderFactory) CreateBuilder(name string) Builder {
return bf.builderMap[name]
}
type TestBuilder struct {
prepareCalled bool
prepareConfig interface{}
@ -28,17 +36,25 @@ func testBuild() *Build {
return &Build{
name: "test",
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) {
assert := asserts.NewTestingAsserts(t, true)
build := testBuild()
build.Prepare(42)
builder := build.builder.(*TestBuilder)
build.Prepare()
assert.True(builder.prepareCalled, "prepare should be called")
assert.Equal(builder.prepareConfig, 42, "prepare config should be 42")
}
@ -49,7 +65,7 @@ func TestBuild_Run(t *testing.T) {
ui := testUi()
build := testBuild()
build.Prepare(nil)
build.Prepare()
build.Run(ui)
builder := build.builder.(*TestBuilder)

View File

@ -1,6 +1,9 @@
package packer
import "encoding/json"
import (
"encoding/json"
"fmt"
)
// The rawTemplate struct represents the structure of a template read
// directly from a file. The builders and other components map just to
@ -74,3 +77,42 @@ func ParseTemplate(data []byte) (t *Template, err error) {
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
}

View File

@ -2,6 +2,7 @@ package packer
import (
"cgl.tideland.biz/asserts"
"sort"
"testing"
)
@ -87,3 +88,121 @@ func TestParseTemplate_BuilderWithName(t *testing.T) {
assert.True(ok, "should have bob builder")
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")
}