Commit ace53450 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer: More efficient RemoteCommand.ExitChan

parent c6dd5476
...@@ -41,10 +41,10 @@ func (c *comm) Start(cmd string) (remote *packer.RemoteCommand, err error) { ...@@ -41,10 +41,10 @@ func (c *comm) Start(cmd string) (remote *packer.RemoteCommand, err error) {
// Setup the remote command // Setup the remote command
remote = &packer.RemoteCommand{ remote = &packer.RemoteCommand{
Stdin: stdin, Stdin: stdin,
Stdout: stdout, Stdout: stdout,
Stderr: stderr, Stderr: stderr,
Exited: false, Exited: false,
ExitStatus: -1, ExitStatus: -1,
} }
...@@ -153,7 +153,6 @@ func (c *comm) Upload(path string, input io.Reader) error { ...@@ -153,7 +153,6 @@ func (c *comm) Upload(path string, input io.Reader) error {
return err return err
} }
log.Printf("scp stdout (length %d): %#v", stdout.Len(), stdout.Bytes()) log.Printf("scp stdout (length %d): %#v", stdout.Len(), stdout.Bytes())
log.Printf("scp stderr (length %d): %s", stderr.Len(), stderr.String()) log.Printf("scp stderr (length %d): %s", stderr.Len(), stderr.String())
......
...@@ -2,6 +2,7 @@ package packer ...@@ -2,6 +2,7 @@ package packer
import ( import (
"io" "io"
"log"
"sync" "sync"
"time" "time"
) )
...@@ -36,34 +37,55 @@ type RemoteCommand struct { ...@@ -36,34 +37,55 @@ type RemoteCommand struct {
Exited bool Exited bool
ExitStatus int ExitStatus int
exitChans []chan<- int
exitChanLock sync.Mutex exitChanLock sync.Mutex
} }
// StdoutStream returns a channel that will be sent all the output // StdoutStream returns a channel that will be sent all the output
// of stdout as it comes. The output isn't guaranteed to be a full line. // of stdout as it comes. The output isn't guaranteed to be a full line.
// When the channel is closed, the process is exited. // When the channel is closed, the process is exited.
func (r *RemoteCommand) StdoutChan() (<-chan string) { func (r *RemoteCommand) StdoutChan() <-chan string {
return nil return nil
} }
// ExitChan returns a channel that will be sent the exit status once // ExitChan returns a channel that will be sent the exit status once
// the process exits. This can be used in cases such a select statement // the process exits. This can be used in cases such a select statement
// waiting on the process to end. // waiting on the process to end.
func (r *RemoteCommand) ExitChan() (<-chan int) { func (r *RemoteCommand) ExitChan() <-chan int {
// TODO(mitchellh): Something more efficient than multiple Wait() calls
r.exitChanLock.Lock() r.exitChanLock.Lock()
defer r.exitChanLock.Unlock() defer r.exitChanLock.Unlock()
// Make a single buffered channel so that the send doesn't block. // If we haven't made any channels yet, make that slice
exitChan := make(chan int, 1) if r.exitChans == nil {
r.exitChans = make([]chan<- int, 0, 5)
go func() {
// Wait for the command to finish
r.Wait()
// Grab the exit chan lock so we can iterate over it and
// message to each channel.
r.exitChanLock.Lock()
defer r.exitChanLock.Unlock()
go func() { for _, ch := range r.exitChans {
defer close(exitChan) // Use a select so the send never blocks
r.Wait() select {
exitChan <- r.ExitStatus case ch <- r.ExitStatus:
}() default:
log.Println("remote command exit channel wouldn't blocked. Weird.")
}
close(ch)
}
r.exitChans = nil
}()
}
// Append our new channel onto it and return it
exitChan := make(chan int, 1)
r.exitChans = append(r.exitChans, exitChan)
return exitChan return exitChan
} }
......
...@@ -80,10 +80,10 @@ func (c *communicator) Start(cmd string) (rc *packer.RemoteCommand, err error) { ...@@ -80,10 +80,10 @@ func (c *communicator) Start(cmd string) (rc *packer.RemoteCommand, err error) {
// Build the response object using the streams we created // Build the response object using the streams we created
rc = &packer.RemoteCommand{ rc = &packer.RemoteCommand{
Stdin: stdinC, Stdin: stdinC,
Stdout: stdoutC, Stdout: stdoutC,
Stderr: stderrC, Stderr: stderrC,
Exited: false, Exited: false,
ExitStatus: -1, ExitStatus: -1,
} }
......
...@@ -39,10 +39,10 @@ func (t *testCommunicator) Start(cmd string) (*packer.RemoteCommand, error) { ...@@ -39,10 +39,10 @@ func (t *testCommunicator) Start(cmd string) (*packer.RemoteCommand, error) {
stderr, t.startErr = io.Pipe() stderr, t.startErr = io.Pipe()
rc := &packer.RemoteCommand{ rc := &packer.RemoteCommand{
Stdin: stdin, Stdin: stdin,
Stdout: stdout, Stdout: stdout,
Stderr: stderr, Stderr: stderr,
Exited: false, Exited: false,
ExitStatus: 0, ExitStatus: 0,
} }
......
...@@ -7,9 +7,9 @@ import ( ...@@ -7,9 +7,9 @@ import (
) )
type testUi struct { type testUi struct {
errorCalled bool errorCalled bool
errorMessage string errorMessage string
sayCalled bool sayCalled bool
sayMessage string sayMessage string
} }
......
package main package main
import ( import (
"github.com/mitchellh/packer/provisioner/shell"
"github.com/mitchellh/packer/packer/plugin" "github.com/mitchellh/packer/packer/plugin"
"github.com/mitchellh/packer/provisioner/shell"
) )
func main() { func main() {
......
...@@ -14,7 +14,7 @@ func TestProvisioner_Impl(t *testing.T) { ...@@ -14,7 +14,7 @@ func TestProvisioner_Impl(t *testing.T) {
} }
func TestProvisionerPrepare_Defaults(t *testing.T) { func TestProvisionerPrepare_Defaults(t *testing.T) {
raw := map[string]interface{} {} raw := map[string]interface{}{}
p := &Provisioner{} p := &Provisioner{}
p.Prepare(raw, nil) p.Prepare(raw, nil)
......
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