Commit 21869295 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer: Build can return multiple artifacts

parent 9c89e33b
......@@ -163,7 +163,7 @@ func (c Command) Run(env packer.Environment, args []string) int {
// Run all the builds in parallel and wait for them to complete
var interruptWg, wg sync.WaitGroup
interrupted := false
artifacts := make(map[string]packer.Artifact)
artifacts := make(map[string][]packer.Artifact)
errors := make(map[string]error)
for _, b := range builds {
// Increment the waitgroup so we wait for this item to finish properly
......@@ -191,14 +191,14 @@ func (c Command) Run(env packer.Environment, args []string) int {
name := b.Name()
log.Printf("Starting build run: %s", name)
ui := buildUis[name]
artifact, err := b.Run(ui, env.Cache())
runArtifacts, err := b.Run(ui, env.Cache())
if err != nil {
ui.Error(fmt.Sprintf("Build errored: %s", err))
errors[name] = err
} else {
ui.Say("Build finished.")
artifacts[name] = artifact
artifacts[name] = runArtifacts
}
}(b)
......@@ -235,17 +235,19 @@ func (c Command) Run(env packer.Environment, args []string) int {
if len(artifacts) > 0 {
env.Ui().Say("\n==> Builds finished. The artifacts of successful builds are:")
for name, artifact := range artifacts {
var message bytes.Buffer
fmt.Fprintf(&message, "--> %s: ", name)
for name, buildArtifacts := range artifacts {
for _, artifact := range buildArtifacts {
var message bytes.Buffer
fmt.Fprintf(&message, "--> %s: ", name)
if artifact != nil {
fmt.Fprintf(&message, artifact.String())
} else {
fmt.Print("<nothing>")
}
if artifact != nil {
fmt.Fprintf(&message, artifact.String())
} else {
fmt.Print("<nothing>")
env.Ui().Say(message.String())
}
env.Ui().Say(message.String())
}
}
......
......@@ -23,7 +23,7 @@ type Build interface {
// Run runs the actual builder, returning an artifact implementation
// of what is built. If anything goes wrong, an error is returned.
Run(Ui, Cache) (Artifact, error)
Run(Ui, Cache) ([]Artifact, error)
// Cancel will cancel a running build. This will block until the build
// is actually completely cancelled.
......@@ -113,7 +113,7 @@ func (b *coreBuild) Prepare() (err error) {
}
// Runs the actual build. Prepare must be called prior to running this.
func (b *coreBuild) Run(ui Ui, cache Cache) (Artifact, error) {
func (b *coreBuild) Run(ui Ui, cache Cache) ([]Artifact, error) {
if !b.prepareCalled {
panic("Prepare must be called first")
}
......@@ -140,7 +140,14 @@ func (b *coreBuild) Run(ui Ui, cache Cache) (Artifact, error) {
}
hook := &DispatchHook{hooks}
return b.builder.Run(ui, hook, cache)
artifacts := make([]Artifact, 0, 1)
artifact, err := b.builder.Run(ui, hook, cache)
if artifact != nil {
artifacts = append(artifacts, artifact)
}
return artifacts, err
}
func (b *coreBuild) SetDebug(val bool) {
......
......@@ -38,24 +38,29 @@ func (b *build) Prepare() (err error) {
return
}
func (b *build) Run(ui packer.Ui, cache packer.Cache) (packer.Artifact, error) {
func (b *build) Run(ui packer.Ui, cache packer.Cache) ([]packer.Artifact, error) {
// Create and start the server for the UI
server := rpc.NewServer()
RegisterCache(server, cache)
RegisterUi(server, ui)
args := &BuildRunArgs{serveSingleConn(server)}
var reply string
if err := b.client.Call("Build.Run", args, &reply); err != nil {
var result []string
if err := b.client.Call("Build.Run", args, &result); err != nil {
return nil, err
}
client, err := rpc.Dial("tcp", reply)
if err != nil {
return nil, err
artifacts := make([]packer.Artifact, len(result))
for i, addr := range result {
client, err := rpc.Dial("tcp", addr)
if err != nil {
return nil, err
}
artifacts[i] = Artifact(client)
}
return Artifact(client), nil
return artifacts, nil
}
func (b *build) SetDebug(val bool) {
......@@ -80,22 +85,24 @@ func (b *BuildServer) Prepare(args interface{}, reply *error) error {
return nil
}
func (b *BuildServer) Run(args *BuildRunArgs, reply *string) error {
func (b *BuildServer) Run(args *BuildRunArgs, reply *[]string) error {
client, err := rpc.Dial("tcp", args.UiRPCAddress)
if err != nil {
return err
}
artifact, err := b.build.Run(&Ui{client}, Cache(client))
artifacts, err := b.build.Run(&Ui{client}, Cache(client))
if err != nil {
return NewBasicError(err)
}
// Wrap the artifact
server := rpc.NewServer()
RegisterArtifact(server, artifact)
*reply = make([]string, len(artifacts))
for i, artifact := range artifacts {
server := rpc.NewServer()
RegisterArtifact(server, artifact)
(*reply)[i] = serveSingleConn(server)
}
*reply = serveSingleConn(server)
return nil
}
......
......@@ -32,7 +32,7 @@ func (b *testBuild) Prepare() error {
return nil
}
func (b *testBuild) Run(ui packer.Ui, cache packer.Cache) (packer.Artifact, error) {
func (b *testBuild) Run(ui packer.Ui, cache packer.Cache) ([]packer.Artifact, error) {
b.runCalled = true
b.runCache = cache
b.runUi = ui
......@@ -40,7 +40,7 @@ func (b *testBuild) Run(ui packer.Ui, cache packer.Cache) (packer.Artifact, erro
if b.errRunResult {
return nil, errors.New("foo")
} else {
return testBuildArtifact, nil
return []packer.Artifact{testBuildArtifact}, nil
}
}
......@@ -79,9 +79,11 @@ func TestBuildRPC(t *testing.T) {
// Test Run
cache := new(testCache)
ui := new(testUi)
_, err = bClient.Run(ui, cache)
artifacts, err := bClient.Run(ui, cache)
assert.True(b.runCalled, "run should be called")
assert.Nil(err, "should not error")
assert.Equal(len(artifacts), 1, "should have one artifact")
assert.Equal(artifacts[0].BuilderId(), "bid", "should have proper builder id")
// Test the UI given to run, which should be fully functional
if b.runCalled {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment