packer: More efficient RemoteCommand.ExitChan
This commit is contained in:
parent
c6dd54760c
commit
ace53450b9
@ -41,10 +41,10 @@ func (c *comm) Start(cmd string) (remote *packer.RemoteCommand, err error) {
|
||||
|
||||
// Setup the remote command
|
||||
remote = &packer.RemoteCommand{
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
Exited: false,
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
Exited: false,
|
||||
ExitStatus: -1,
|
||||
}
|
||||
|
||||
@ -153,7 +153,6 @@ func (c *comm) Upload(path string, input io.Reader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
log.Printf("scp stdout (length %d): %#v", stdout.Len(), stdout.Bytes())
|
||||
log.Printf("scp stderr (length %d): %s", stderr.Len(), stderr.String())
|
||||
|
||||
|
@ -2,6 +2,7 @@ package packer
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@ -36,34 +37,55 @@ type RemoteCommand struct {
|
||||
Exited bool
|
||||
ExitStatus int
|
||||
|
||||
exitChans []chan<- int
|
||||
exitChanLock sync.Mutex
|
||||
}
|
||||
|
||||
// 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.
|
||||
// When the channel is closed, the process is exited.
|
||||
func (r *RemoteCommand) StdoutChan() (<-chan string) {
|
||||
func (r *RemoteCommand) StdoutChan() <-chan string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// waiting on the process to end.
|
||||
func (r *RemoteCommand) ExitChan() (<-chan int) {
|
||||
// TODO(mitchellh): Something more efficient than multiple Wait() calls
|
||||
|
||||
func (r *RemoteCommand) ExitChan() <-chan int {
|
||||
r.exitChanLock.Lock()
|
||||
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
|
||||
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()
|
||||
|
||||
for _, ch := range r.exitChans {
|
||||
// Use a select so the send never blocks
|
||||
select {
|
||||
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)
|
||||
|
||||
go func() {
|
||||
defer close(exitChan)
|
||||
r.Wait()
|
||||
exitChan <- r.ExitStatus
|
||||
}()
|
||||
|
||||
r.exitChans = append(r.exitChans, exitChan)
|
||||
return exitChan
|
||||
}
|
||||
|
||||
|
@ -80,10 +80,10 @@ func (c *communicator) Start(cmd string) (rc *packer.RemoteCommand, err error) {
|
||||
|
||||
// Build the response object using the streams we created
|
||||
rc = &packer.RemoteCommand{
|
||||
Stdin: stdinC,
|
||||
Stdout: stdoutC,
|
||||
Stderr: stderrC,
|
||||
Exited: false,
|
||||
Stdin: stdinC,
|
||||
Stdout: stdoutC,
|
||||
Stderr: stderrC,
|
||||
Exited: false,
|
||||
ExitStatus: -1,
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ func (t *testCommunicator) Start(cmd string) (*packer.RemoteCommand, error) {
|
||||
stderr, t.startErr = io.Pipe()
|
||||
|
||||
rc := &packer.RemoteCommand{
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
Exited: false,
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
Exited: false,
|
||||
ExitStatus: 0,
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
)
|
||||
|
||||
type testUi struct {
|
||||
errorCalled bool
|
||||
errorCalled bool
|
||||
errorMessage string
|
||||
sayCalled bool
|
||||
sayCalled bool
|
||||
sayMessage string
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/provisioner/shell"
|
||||
"github.com/mitchellh/packer/packer/plugin"
|
||||
"github.com/mitchellh/packer/provisioner/shell"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -14,7 +14,7 @@ func TestProvisioner_Impl(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProvisionerPrepare_Defaults(t *testing.T) {
|
||||
raw := map[string]interface{} {}
|
||||
raw := map[string]interface{}{}
|
||||
|
||||
p := &Provisioner{}
|
||||
p.Prepare(raw, nil)
|
||||
|
Loading…
x
Reference in New Issue
Block a user