diff --git a/packer/build.go b/packer/build.go index c08fc8161..ba2cff4df 100644 --- a/packer/build.go +++ b/packer/build.go @@ -7,7 +7,7 @@ import "log" type Build interface { Name() string Prepare() error - Run(ui Ui) + Run(Ui) } // A build struct represents a single build job, the result of which should @@ -46,5 +46,6 @@ func (b *coreBuild) Run(ui Ui) { panic("Prepare must be called first") } - b.builder.Run(b, ui) + hook := &DispatchHook{b.hooks} + b.builder.Run(ui, hook) } diff --git a/packer/build_test.go b/packer/build_test.go index e156d8418..4f33a2dce 100644 --- a/packer/build_test.go +++ b/packer/build_test.go @@ -9,7 +9,7 @@ type TestBuilder struct { prepareCalled bool prepareConfig interface{} runCalled bool - runBuild Build + runHook Hook runUi Ui } @@ -19,9 +19,9 @@ func (tb *TestBuilder) Prepare(config interface{}) error { return nil } -func (tb *TestBuilder) Run(b Build, ui Ui) { +func (tb *TestBuilder) Run(ui Ui, h Hook) { tb.runCalled = true - tb.runBuild = b + tb.runHook = h tb.runUi = ui } @@ -67,7 +67,6 @@ func TestBuild_Run(t *testing.T) { builder := build.(*coreBuild).builder.(*TestBuilder) assert.True(builder.runCalled, "run should be called") - assert.Equal(builder.runBuild, build, "run should be called with build") assert.Equal(builder.runUi, ui, "run should be called with ui") } diff --git a/packer/builder.go b/packer/builder.go index 55ea5bff0..1c1a739a5 100644 --- a/packer/builder.go +++ b/packer/builder.go @@ -11,5 +11,5 @@ package packer // Run is where the actual build should take place. It takes a Build and a Ui. type Builder interface { Prepare(config interface{}) error - Run(build Build, ui Ui) + Run(ui Ui, hook Hook) } diff --git a/packer/hook.go b/packer/hook.go index 1bb629736..63cfb98d9 100644 --- a/packer/hook.go +++ b/packer/hook.go @@ -11,3 +11,23 @@ package packer type Hook interface { Run(string, interface{}, Ui) } + +// A Hook implementation that dispatches based on an internal mapping. +type DispatchHook struct { + Mapping map[string][]Hook +} + +// Runs the hook with the given name by dispatching it to the proper +// hooks if a mapping exists. If a mapping doesn't exist, then nothing +// happens. +func (h *DispatchHook) Run(name string, data interface{}, ui Ui) { + hooks, ok := h.Mapping[name] + if !ok { + // No hooks for that name. No problem. + return + } + + for _, hook := range hooks { + hook.Run(name, data, ui) + } +} diff --git a/packer/hook_test.go b/packer/hook_test.go index 22229d4a4..1067ea79e 100644 --- a/packer/hook_test.go +++ b/packer/hook_test.go @@ -1,9 +1,41 @@ package packer +import ( + "cgl.tideland.biz/asserts" + "testing" +) + type TestHook struct { runCalled bool + runData interface{} + runName string + runUi Ui } -func (t *TestHook) Run(string, interface{}, Ui) { +func (t *TestHook) Run(name string, data interface{}, ui Ui) { t.runCalled = true + t.runData = data + t.runName = name + t.runUi = ui +} + +func TestDispatchHook_Run_NoHooks(t *testing.T) { + // Just make sure nothing blows up + dh := &DispatchHook{make(map[string][]Hook)} + dh.Run("foo", nil, nil) +} + +func TestDispatchHook_Run(t *testing.T) { + assert := asserts.NewTestingAsserts(t, true) + + hook := &TestHook{} + + mapping := make(map[string][]Hook) + mapping["foo"] = []Hook{hook} + dh := &DispatchHook{mapping} + dh.Run("foo", 42, nil) + + assert.True(hook.runCalled, "run should be called") + assert.Equal(hook.runName, "foo", "should be proper event") + assert.Equal(hook.runData, 42, "should be correct data") } diff --git a/packer/template_test.go b/packer/template_test.go index 9e0f415be..ae05db369 100644 --- a/packer/template_test.go +++ b/packer/template_test.go @@ -229,5 +229,4 @@ func TestTemplate_Build(t *testing.T) { 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") }