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 }