From e753ffe5d951a9edc37a6a36a0d44d96b83148a2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 1 Jun 2013 18:31:22 -0700 Subject: [PATCH] packer: Refactor on StdoutChan so it'll work for stderr easily --- packer/communicator.go | 63 +++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/packer/communicator.go b/packer/communicator.go index ab79389e8..183b78158 100644 --- a/packer/communicator.go +++ b/packer/communicator.go @@ -55,35 +55,7 @@ func (r *RemoteCommand) StdoutChan() <-chan string { // and start the goroutine to read and send to them. if r.outChans == nil { r.outChans = make([]chan<- string, 0, 5) - - go func() { - buf := bufio.NewReader(r.Stdout) - - var err error - for err != io.EOF { - var data []byte - data, err = buf.ReadSlice('\n') - - if len(data) > 0 { - for _, ch := range r.outChans { - // Note: this blocks if the channel is full (they - // are buffered by default). What to do? - ch <- string(data) - } - } - } - - // Clean up the channels by closing them and setting the - // list to nil. - r.outChanLock.Lock() - defer r.outChanLock.Unlock() - - for _, ch := range r.outChans { - close(ch) - } - - r.outChans = nil - }() + go r.channelReader(r.Stdout, &r.outChans, &r.outChanLock) } // Create the channel, append it to the channels we care about @@ -141,3 +113,36 @@ func (r *RemoteCommand) Wait() { time.Sleep(10 * time.Millisecond) } } + +// Takes an io.Reader and then writes its data to a slice of channels. +// The channel slice is expected to be protected by the given mutex, and +// after the io.Reader is over, all channels will be closed and the slice +// set to nil. +func (*RemoteCommand) channelReader(r io.Reader, chans *[]chan<- string, chanLock *sync.Mutex) { + buf := bufio.NewReader(r) + + var err error + for err != io.EOF { + var data []byte + data, err = buf.ReadSlice('\n') + + if len(data) > 0 { + for _, ch := range *chans { + // Note: this blocks if the channel is full (they + // are buffered by default). What to do? + ch <- string(data) + } + } + } + + // Clean up the channels by closing them and setting the + // list to nil. + chanLock.Lock() + defer chanLock.Unlock() + + for _, ch := range *chans { + close(ch) + } + + *chans = nil +}