From c580faa1a5a3a08277cdebd75a928200a2adc254 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 9 May 2013 13:59:33 -0700 Subject: [PATCH] packer/rpc: error interface wrapper to RPC errors around --- command/build/command.go | 6 +++++- packer/plugin/client.go | 2 +- packer/rpc/builder.go | 12 ++++++++++-- packer/rpc/error.go | 17 +++++++++++++++++ packer/rpc/error_test.go | 25 +++++++++++++++++++++++++ packer/rpc/init.go | 8 ++++++++ 6 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 packer/rpc/error.go create mode 100644 packer/rpc/error_test.go create mode 100644 packer/rpc/init.go diff --git a/command/build/command.go b/command/build/command.go index 24f127afb..19ab76e2b 100644 --- a/command/build/command.go +++ b/command/build/command.go @@ -47,7 +47,11 @@ func (Command) Run(env packer.Environment, args []string) int { // Prepare all the builds for _, b := range builds { log.Printf("Preparing build: %s\n", b.Name()) - b.Prepare() + err := b.Prepare() + if err != nil { + env.Ui().Error("%s\n", err) + return 1 + } } env.Ui().Say("YAY!\n") diff --git a/packer/plugin/client.go b/packer/plugin/client.go index fd5423740..d0086bb9f 100644 --- a/packer/plugin/client.go +++ b/packer/plugin/client.go @@ -91,7 +91,7 @@ func (c *client) Start() (address string, err error) { // Start goroutine to wait for process to exit go func() { c.cmd.Wait() - log.Println("plugin process exited") + log.Printf("%s: plugin process exited\n", c.cmd.Path) c.exited = true }() diff --git a/packer/rpc/builder.go b/packer/rpc/builder.go index 3efb9e63c..b2450af8a 100644 --- a/packer/rpc/builder.go +++ b/packer/rpc/builder.go @@ -30,7 +30,11 @@ func Builder(client *rpc.Client) *builder { } func (b *builder) Prepare(config interface{}) (err error) { - b.client.Call("Builder.Prepare", &BuilderPrepareArgs{config}, &err) + cerr := b.client.Call("Builder.Prepare", &BuilderPrepareArgs{config}, &err) + if cerr != nil { + err = cerr + } + return } @@ -46,7 +50,11 @@ func (b *builder) Run(build packer.Build, ui packer.Ui) { } func (b *BuilderServer) Prepare(args *BuilderPrepareArgs, reply *error) error { - *reply = b.builder.Prepare(args.Config) + err := b.builder.Prepare(args.Config) + if err != nil { + *reply = NewBasicError(err) + } + return nil } diff --git a/packer/rpc/error.go b/packer/rpc/error.go new file mode 100644 index 000000000..a5880fbac --- /dev/null +++ b/packer/rpc/error.go @@ -0,0 +1,17 @@ +package rpc + +// This is a type that wraps error types so that they can be messaged +// across RPC channels. Since "error" is an interface, we can't always +// gob-encode the underlying structure. This is a valid error interface +// implementer that we will push across. +type BasicError struct { + Message string +} + +func NewBasicError(err error) *BasicError { + return &BasicError{err.Error()} +} + +func (e *BasicError) Error() string { + return e.Message +} diff --git a/packer/rpc/error_test.go b/packer/rpc/error_test.go new file mode 100644 index 000000000..af631f46a --- /dev/null +++ b/packer/rpc/error_test.go @@ -0,0 +1,25 @@ +package rpc + +import ( + "cgl.tideland.biz/asserts" + "errors" + "testing" +) + +func TestBasicError_ImplementsError(t *testing.T) { + assert := asserts.NewTestingAsserts(t, true) + + var r error + e := &BasicError{""} + + assert.Implementor(e, &r, "should be an error") +} + +func TestBasicError_MatchesMessage(t *testing.T) { + assert := asserts.NewTestingAsserts(t, true) + + err := errors.New("foo") + wrapped := NewBasicError(err) + + assert.Equal(wrapped.Error(), err.Error(), "should have the same error") +} diff --git a/packer/rpc/init.go b/packer/rpc/init.go new file mode 100644 index 000000000..25bb4fdae --- /dev/null +++ b/packer/rpc/init.go @@ -0,0 +1,8 @@ +package rpc + +import "encoding/gob" + +func init() { + gob.Register(new(map[string]interface{})) + gob.Register(new(BasicError)) +}