packer: Add concept of hooks to Environment
This commit is contained in:
parent
5ac06e116e
commit
8ed313e7b5
|
@ -84,9 +84,9 @@ func main() {
|
|||
}
|
||||
|
||||
envConfig := packer.DefaultEnvironmentConfig()
|
||||
envConfig.BuilderFunc = config.LoadBuilder
|
||||
envConfig.Commands = config.CommandNames()
|
||||
envConfig.CommandFunc = config.LoadCommand
|
||||
envConfig.Components.Builder = config.LoadBuilder
|
||||
envConfig.Components.Command = config.LoadCommand
|
||||
|
||||
env, err := packer.NewEnvironment(envConfig)
|
||||
if err != nil {
|
||||
|
|
|
@ -17,6 +17,7 @@ type Build interface {
|
|||
type coreBuild struct {
|
||||
name string
|
||||
builder Builder
|
||||
hooks map[string]Hook
|
||||
rawConfig interface{}
|
||||
|
||||
prepareCalled bool
|
||||
|
|
|
@ -16,31 +16,42 @@ type BuilderFunc func(name string) (Builder, error)
|
|||
// The function type used to lookup Command implementations.
|
||||
type CommandFunc func(name string) (Command, error)
|
||||
|
||||
// The function type used to lookup Hook implementations.
|
||||
type HookFunc func(name string) (Hook, error)
|
||||
|
||||
// ComponentFinder is a struct that contains the various function
|
||||
// pointers necessary to look up components of Packer such as builders,
|
||||
// commands, etc.
|
||||
type ComponentFinder struct {
|
||||
Builder BuilderFunc
|
||||
Command CommandFunc
|
||||
Hook HookFunc
|
||||
}
|
||||
|
||||
// The environment interface provides access to the configuration and
|
||||
// state of a single Packer run.
|
||||
//
|
||||
// It allows for things such as executing CLI commands, getting the
|
||||
// list of available builders, and more.
|
||||
type Environment interface {
|
||||
Builder(name string) (Builder, error)
|
||||
Cli(args []string) (int, error)
|
||||
Builder(string) (Builder, error)
|
||||
Cli([]string) (int, error)
|
||||
Hook(string) (Hook, error)
|
||||
Ui() Ui
|
||||
}
|
||||
|
||||
// An implementation of an Environment that represents the Packer core
|
||||
// environment.
|
||||
type coreEnvironment struct {
|
||||
builderFunc BuilderFunc
|
||||
commands []string
|
||||
commandFunc CommandFunc
|
||||
components ComponentFinder
|
||||
ui Ui
|
||||
}
|
||||
|
||||
// This struct configures new environments.
|
||||
type EnvironmentConfig struct {
|
||||
BuilderFunc BuilderFunc
|
||||
CommandFunc CommandFunc
|
||||
Commands []string
|
||||
Components ComponentFinder
|
||||
Ui Ui
|
||||
}
|
||||
|
||||
|
@ -48,8 +59,6 @@ type EnvironmentConfig struct {
|
|||
// be used to create a new enviroment with NewEnvironment with sane defaults.
|
||||
func DefaultEnvironmentConfig() *EnvironmentConfig {
|
||||
config := &EnvironmentConfig{}
|
||||
config.BuilderFunc = func(string) (Builder, error) { return nil, nil }
|
||||
config.CommandFunc = func(string) (Command, error) { return nil, nil }
|
||||
config.Commands = make([]string, 0)
|
||||
config.Ui = &ReaderWriterUi{os.Stdin, os.Stdout}
|
||||
return config
|
||||
|
@ -63,11 +72,25 @@ func NewEnvironment(config *EnvironmentConfig) (resultEnv Environment, err error
|
|||
}
|
||||
|
||||
env := &coreEnvironment{}
|
||||
env.builderFunc = config.BuilderFunc
|
||||
env.commandFunc = config.CommandFunc
|
||||
env.commands = config.Commands
|
||||
env.components = config.Components
|
||||
env.ui = config.Ui
|
||||
|
||||
// We want to make sure the components have valid function pointers.
|
||||
// If a function pointer was not given, we assume that the function
|
||||
// will just return a nil component.
|
||||
if env.components.Builder == nil {
|
||||
env.components.Builder = func(string) (Builder, error) { return nil, nil }
|
||||
}
|
||||
|
||||
if env.components.Command == nil {
|
||||
env.components.Command = func(string) (Command, error) { return nil, nil }
|
||||
}
|
||||
|
||||
if env.components.Hook == nil {
|
||||
env.components.Hook = func(string) (Hook, error) { return nil, nil }
|
||||
}
|
||||
|
||||
resultEnv = env
|
||||
return
|
||||
}
|
||||
|
@ -75,7 +98,7 @@ func NewEnvironment(config *EnvironmentConfig) (resultEnv Environment, err error
|
|||
// Returns a builder of the given name that is registered with this
|
||||
// environment.
|
||||
func (e *coreEnvironment) Builder(name string) (b Builder, err error) {
|
||||
b, err = e.builderFunc(name)
|
||||
b, err = e.components.Builder(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -87,6 +110,21 @@ func (e *coreEnvironment) Builder(name string) (b Builder, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Returns a hook of the given name that is registered with this
|
||||
// environment.
|
||||
func (e *coreEnvironment) Hook(name string) (h Hook, err error) {
|
||||
h, err = e.components.Hook(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if h == nil {
|
||||
err = fmt.Errorf("No hook returned for name: %s", name)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Executes a command as if it was typed on the command-line interface.
|
||||
// The return value is the exit code of the command.
|
||||
func (e *coreEnvironment) Cli(args []string) (result int, err error) {
|
||||
|
@ -113,7 +151,7 @@ func (e *coreEnvironment) Cli(args []string) (result int, err error) {
|
|||
}
|
||||
|
||||
if command == nil {
|
||||
command, err = e.commandFunc(args[0])
|
||||
command, err = e.components.Command(args[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -152,7 +190,7 @@ func (e *coreEnvironment) printHelp() {
|
|||
for _, key := range e.commands {
|
||||
var synopsis string
|
||||
|
||||
command, err := e.commandFunc(key)
|
||||
command, err := e.components.Command(key)
|
||||
if err != nil {
|
||||
synopsis = fmt.Sprintf("Error loading command: %s", err.Error())
|
||||
} else if command == nil {
|
||||
|
|
|
@ -52,6 +52,23 @@ func TestNewEnvironment_NoConfig(t *testing.T) {
|
|||
assert.NotNil(err, "should be an error")
|
||||
}
|
||||
|
||||
func TestEnvironment_NilComponents(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components = *new(ComponentFinder)
|
||||
|
||||
env, err := NewEnvironment(config)
|
||||
assert.Nil(err, "should not have an error")
|
||||
|
||||
// All of these should not cause panics... so we don't assert
|
||||
// anything but if there is a panic in the test then yeah, something
|
||||
// went wrong.
|
||||
env.Builder("foo")
|
||||
env.Cli([]string{"foo"})
|
||||
env.Hook("foo")
|
||||
}
|
||||
|
||||
func TestEnvironment_Builder(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
|
@ -60,7 +77,7 @@ func TestEnvironment_Builder(t *testing.T) {
|
|||
builders["foo"] = builder
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.BuilderFunc = func(n string) (Builder, error) { return builders[n], nil }
|
||||
config.Components.Builder = func(n string) (Builder, error) { return builders[n], nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returnedBuilder, err := env.Builder("foo")
|
||||
|
@ -72,7 +89,7 @@ func TestEnvironment_Builder_NilError(t *testing.T) {
|
|||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.BuilderFunc = func(n string) (Builder, error) { return nil, nil }
|
||||
config.Components.Builder = func(n string) (Builder, error) { return nil, nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returnedBuilder, err := env.Builder("foo")
|
||||
|
@ -84,7 +101,7 @@ func TestEnvironment_Builder_Error(t *testing.T) {
|
|||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.BuilderFunc = func(n string) (Builder, error) { return nil, errors.New("foo") }
|
||||
config.Components.Builder = func(n string) (Builder, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returnedBuilder, err := env.Builder("foo")
|
||||
|
@ -97,7 +114,7 @@ func TestEnvironment_Cli_Error(t *testing.T) {
|
|||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.CommandFunc = func(n string) (Command, error) { return nil, errors.New("foo") }
|
||||
config.Components.Command = func(n string) (Command, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
_, err := env.Cli([]string{"foo"})
|
||||
|
@ -114,7 +131,7 @@ func TestEnvironment_Cli_CallsRun(t *testing.T) {
|
|||
|
||||
config := &EnvironmentConfig{}
|
||||
config.Commands = []string{"foo"}
|
||||
config.CommandFunc = func(n string) (Command, error) { return commands[n], nil }
|
||||
config.Components.Command = func(n string) (Command, error) { return commands[n], nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
exitCode, err := env.Cli([]string{"foo", "bar", "baz"})
|
||||
|
@ -179,6 +196,47 @@ func TestEnvironment_DefaultCli_Version(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Hook(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
hook := &TestHook{}
|
||||
hooks := make(map[string]Hook)
|
||||
hooks["foo"] = hook
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Hook = func(n string) (Hook, error) { return hooks[n], nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Hook("foo")
|
||||
assert.Nil(err, "should be no error")
|
||||
assert.Equal(returned, hook, "should return correct hook")
|
||||
}
|
||||
|
||||
func TestEnvironment_Hook_NilError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Hook = func(n string) (Hook, error) { return nil, nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Hook("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Nil(returned, "should be no hook")
|
||||
}
|
||||
|
||||
func TestEnvironment_Hook_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Hook = func(n string) (Hook, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Hook("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Equal(err.Error(), "foo", "should be correct error")
|
||||
assert.Nil(returned, "should be no hook")
|
||||
}
|
||||
|
||||
func TestEnvironment_SettingUi(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package packer
|
||||
|
||||
type TestHook struct {
|
||||
runCalled bool
|
||||
}
|
||||
|
||||
func (t *TestHook) Run(string, interface{}) {
|
||||
t.runCalled = true
|
||||
}
|
Loading…
Reference in New Issue