diff --git a/api.go b/api.go index b45f1a35d..127ad7760 100644 --- a/api.go +++ b/api.go @@ -169,9 +169,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r return fmt.Errorf("Missing parameter") } job := srv.Eng.Job("export", vars["name"]) - if err := job.Stdout.Add(w); err != nil { - return err - } + job.Stdout.Add(w) if err := job.Run(); err != nil { return err } @@ -573,9 +571,7 @@ func getImagesGet(srv *Server, version float64, w http.ResponseWriter, r *http.R w.Header().Set("Content-Type", "application/x-tar") } job := srv.Eng.Job("image_export", vars["name"]) - if err := job.Stdout.Add(w); err != nil { - return err - } + job.Stdout.Add(w) return job.Run() } @@ -806,7 +802,7 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r job.Setenv("stderr", r.Form.Get("stderr")) job.Stdin.Add(inStream) job.Stdout.Add(outStream) - job.Stderr.Add(errStream) + job.Stderr.Set(errStream) if err := job.Run(); err != nil { fmt.Fprintf(outStream, "Error: %s\n", err) @@ -836,7 +832,7 @@ func wsContainersAttach(srv *Server, version float64, w http.ResponseWriter, r * job.Setenv("stderr", r.Form.Get("stderr")) job.Stdin.Add(ws) job.Stdout.Add(ws) - job.Stderr.Add(ws) + job.Stderr.Set(ws) if err := job.Run(); err != nil { utils.Errorf("Error: %s", err) } diff --git a/engine/streams.go b/engine/streams.go index 703a56256..4b1f172b4 100644 --- a/engine/streams.go +++ b/engine/streams.go @@ -23,20 +23,28 @@ func NewOutput() *Output { // Return true if something was written on this output func (o *Output) Used() bool { - o.Mutex.Lock() - defer o.Mutex.Unlock() + o.Lock() + defer o.Unlock() return o.used } // Add attaches a new destination to the Output. Any data subsequently written // to the output will be written to the new destination in addition to all the others. // This method is thread-safe. -// FIXME: Add cannot fail -func (o *Output) Add(dst io.Writer) error { - o.Mutex.Lock() - defer o.Mutex.Unlock() +func (o *Output) Add(dst io.Writer) { + o.Lock() + defer o.Unlock() o.dests = append(o.dests, dst) - return nil +} + +// Set closes and remove existing destination and then attaches a new destination to +// the Output. Any data subsequently written to the output will be written to the new +// destination in addition to all the others. This method is thread-safe. +func (o *Output) Set(dst io.Writer) { + o.Close() + o.Lock() + defer o.Unlock() + o.dests = []io.Writer{dst} } // AddPipe creates an in-memory pipe with io.Pipe(), adds its writing end as a destination, @@ -88,8 +96,8 @@ func (o *Output) AddString(dst *string) error { // Write writes the same data to all registered destinations. // This method is thread-safe. func (o *Output) Write(p []byte) (n int, err error) { - o.Mutex.Lock() - defer o.Mutex.Unlock() + o.Lock() + defer o.Unlock() o.used = true var firstErr error for _, dst := range o.dests { @@ -105,8 +113,8 @@ func (o *Output) Write(p []byte) (n int, err error) { // AddTail and AddString tasks to complete. // The Close method of each destination is called if it exists. func (o *Output) Close() error { - o.Mutex.Lock() - defer o.Mutex.Unlock() + o.Lock() + defer o.Unlock() var firstErr error for _, dst := range o.dests { if closer, ok := dst.(io.WriteCloser); ok { diff --git a/engine/streams_test.go b/engine/streams_test.go index 37720c61e..30d31d295 100644 --- a/engine/streams_test.go +++ b/engine/streams_test.go @@ -95,9 +95,7 @@ func TestOutputAddEnv(t *testing.T) { func TestOutputAddClose(t *testing.T) { o := NewOutput() var s sentinelWriteCloser - if err := o.Add(&s); err != nil { - t.Fatal(err) - } + o.Add(&s) if err := o.Close(); err != nil { t.Fatal(err) }