github.com/ruphin/docker@v1.10.1/runconfig/streams.go (about)

     1  package runconfig
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/pkg/broadcaster"
    10  	"github.com/docker/docker/pkg/ioutils"
    11  )
    12  
    13  // StreamConfig holds information about I/O streams managed together.
    14  //
    15  // streamConfig.StdinPipe returns a WriteCloser which can be used to feed data
    16  // to the standard input of the streamConfig's active process.
    17  // streamConfig.StdoutPipe and streamConfig.StderrPipe each return a ReadCloser
    18  // which can be used to retrieve the standard output (and error) generated
    19  // by the container's active process. The output (and error) are actually
    20  // copied and delivered to all StdoutPipe and StderrPipe consumers, using
    21  // a kind of "broadcaster".
    22  type StreamConfig struct {
    23  	stdout    *broadcaster.Unbuffered
    24  	stderr    *broadcaster.Unbuffered
    25  	stdin     io.ReadCloser
    26  	stdinPipe io.WriteCloser
    27  }
    28  
    29  // NewStreamConfig creates a stream config and initializes
    30  // the standard err and standard out to new unbuffered broadcasters.
    31  func NewStreamConfig() *StreamConfig {
    32  	return &StreamConfig{
    33  		stderr: new(broadcaster.Unbuffered),
    34  		stdout: new(broadcaster.Unbuffered),
    35  	}
    36  }
    37  
    38  // Stdout returns the standard output in the configuration.
    39  func (streamConfig *StreamConfig) Stdout() *broadcaster.Unbuffered {
    40  	return streamConfig.stdout
    41  }
    42  
    43  // Stderr returns the standard error in the configuration.
    44  func (streamConfig *StreamConfig) Stderr() *broadcaster.Unbuffered {
    45  	return streamConfig.stderr
    46  }
    47  
    48  // Stdin returns the standard input in the configuration.
    49  func (streamConfig *StreamConfig) Stdin() io.ReadCloser {
    50  	return streamConfig.stdin
    51  }
    52  
    53  // StdinPipe returns an input writer pipe as an io.WriteCloser.
    54  func (streamConfig *StreamConfig) StdinPipe() io.WriteCloser {
    55  	return streamConfig.stdinPipe
    56  }
    57  
    58  // StdoutPipe creates a new io.ReadCloser with an empty bytes pipe.
    59  // It adds this new out pipe to the Stdout broadcaster.
    60  func (streamConfig *StreamConfig) StdoutPipe() io.ReadCloser {
    61  	bytesPipe := ioutils.NewBytesPipe(nil)
    62  	streamConfig.stdout.Add(bytesPipe)
    63  	return bytesPipe
    64  }
    65  
    66  // StderrPipe creates a new io.ReadCloser with an empty bytes pipe.
    67  // It adds this new err pipe to the Stderr broadcaster.
    68  func (streamConfig *StreamConfig) StderrPipe() io.ReadCloser {
    69  	bytesPipe := ioutils.NewBytesPipe(nil)
    70  	streamConfig.stderr.Add(bytesPipe)
    71  	return bytesPipe
    72  }
    73  
    74  // NewInputPipes creates new pipes for both standard inputs, Stdin and StdinPipe.
    75  func (streamConfig *StreamConfig) NewInputPipes() {
    76  	streamConfig.stdin, streamConfig.stdinPipe = io.Pipe()
    77  }
    78  
    79  // NewNopInputPipe creates a new input pipe that will silently drop all messages in the input.
    80  func (streamConfig *StreamConfig) NewNopInputPipe() {
    81  	streamConfig.stdinPipe = ioutils.NopWriteCloser(ioutil.Discard)
    82  }
    83  
    84  // CloseStreams ensures that the configured streams are properly closed.
    85  func (streamConfig *StreamConfig) CloseStreams() error {
    86  	var errors []string
    87  
    88  	if streamConfig.stdin != nil {
    89  		if err := streamConfig.stdin.Close(); err != nil {
    90  			errors = append(errors, fmt.Sprintf("error close stdin: %s", err))
    91  		}
    92  	}
    93  
    94  	if err := streamConfig.stdout.Clean(); err != nil {
    95  		errors = append(errors, fmt.Sprintf("error close stdout: %s", err))
    96  	}
    97  
    98  	if err := streamConfig.stderr.Clean(); err != nil {
    99  		errors = append(errors, fmt.Sprintf("error close stderr: %s", err))
   100  	}
   101  
   102  	if len(errors) > 0 {
   103  		return fmt.Errorf(strings.Join(errors, "\n"))
   104  	}
   105  
   106  	return nil
   107  }