diff --git a/packer/build.go b/packer/build.go index ba2cff4df..698ccc0af 100644 --- a/packer/build.go +++ b/packer/build.go @@ -7,7 +7,7 @@ import "log" type Build interface { Name() string Prepare() error - Run(Ui) + Run(Ui) Artifact } // A build struct represents a single build job, the result of which should @@ -41,11 +41,11 @@ func (b *coreBuild) Prepare() (err error) { } // Runs the actual build. Prepare must be called prior to running this. -func (b *coreBuild) Run(ui Ui) { +func (b *coreBuild) Run(ui Ui) Artifact { if !b.prepareCalled { panic("Prepare must be called first") } hook := &DispatchHook{b.hooks} - b.builder.Run(ui, hook) + return b.builder.Run(ui, hook) } diff --git a/packer/rpc/build.go b/packer/rpc/build.go index 9256610d3..666c703ea 100644 --- a/packer/rpc/build.go +++ b/packer/rpc/build.go @@ -7,7 +7,7 @@ import ( // An implementation of packer.Build where the build is actually executed // over an RPC connection. -type Build struct { +type build struct { client *rpc.Client } @@ -23,23 +23,38 @@ type BuildRunArgs struct { UiRPCAddress string } -func (b *Build) Name() (result string) { +func Build(client *rpc.Client) *build { + return &build{client} +} + +func (b *build) Name() (result string) { b.client.Call("Build.Name", new(interface{}), &result) return } -func (b *Build) Prepare() (err error) { +func (b *build) Prepare() (err error) { b.client.Call("Build.Prepare", new(interface{}), &err) return } -func (b *Build) Run(ui packer.Ui) { +func (b *build) Run(ui packer.Ui) packer.Artifact { // Create and start the server for the UI // TODO: Error handling server := rpc.NewServer() RegisterUi(server, ui) args := &BuildRunArgs{serveSingleConn(server)} - b.client.Call("Build.Run", args, new(interface{})) + + var reply string + if err := b.client.Call("Build.Run", args, &reply); err != nil { + panic(err) + } + + client, err := rpc.Dial("tcp", reply) + if err != nil { + panic(err) + } + + return Artifact(client) } func (b *BuildServer) Name(args *interface{}, reply *string) error { @@ -52,14 +67,18 @@ func (b *BuildServer) Prepare(args *BuildPrepareArgs, reply *error) error { return nil } -func (b *BuildServer) Run(args *BuildRunArgs, reply *interface{}) error { +func (b *BuildServer) Run(args *BuildRunArgs, reply *string) error { client, err := rpc.Dial("tcp", args.UiRPCAddress) if err != nil { return err } - b.build.Run(&Ui{client}) + artifact := b.build.Run(&Ui{client}) + + // Wrap the artifact + server := rpc.NewServer() + RegisterArtifact(server, artifact) - *reply = nil + *reply = serveSingleConn(server) return nil } diff --git a/packer/rpc/build_test.go b/packer/rpc/build_test.go index 4b3b6d396..21f0c4b7a 100644 --- a/packer/rpc/build_test.go +++ b/packer/rpc/build_test.go @@ -7,6 +7,8 @@ import ( "testing" ) +var testBuildArtifact = &testArtifact{} + type testBuild struct { nameCalled bool prepareCalled bool @@ -24,32 +26,27 @@ func (b *testBuild) Prepare() error { return nil } -func (b *testBuild) Run(ui packer.Ui) { +func (b *testBuild) Run(ui packer.Ui) packer.Artifact { b.runCalled = true b.runUi = ui + return testBuildArtifact } func TestBuildRPC(t *testing.T) { assert := asserts.NewTestingAsserts(t, true) - // Create the UI to test + // Create the interface to test b := new(testBuild) - bServer := &BuildServer{b} - // Start the RPC server - readyChan := make(chan int) - stopChan := make(chan int) - defer func() { stopChan <- 1 }() - go testRPCServer(":1234", "Build", bServer, readyChan, stopChan) - <-readyChan + // Start the server + server := rpc.NewServer() + RegisterBuild(server, b) + address := serveSingleConn(server) // Create the client over RPC and run some methods to verify it works - client, err := rpc.Dial("tcp", ":1234") - if err != nil { - panic(err) - } - - bClient := &Build{client} + client, err := rpc.Dial("tcp", address) + assert.Nil(err, "should be able to connect") + bClient := Build(client) // Test Name bClient.Name() @@ -76,7 +73,7 @@ func TestBuild_ImplementsBuild(t *testing.T) { assert := asserts.NewTestingAsserts(t, true) var realBuild packer.Build - b := &Build{nil} + b := Build(nil) assert.Implementor(b, &realBuild, "should be a Build") }