@@ -28,13 +28,14 @@ import (
28
28
// Pipe represents a pipe object with an associated [ReadAutoCloser].
29
29
type Pipe struct {
30
30
// Reader is the underlying reader.
31
- Reader ReadAutoCloser
32
- stdout , stderr io.Writer
33
- httpClient * http.Client
31
+ Reader ReadAutoCloser
32
+ stdout io.Writer
33
+ httpClient * http.Client
34
34
35
- // because pipe stages are concurrent, protect 'err'
36
- mu * sync.Mutex
37
- err error
35
+ // because pipe stages are concurrent, protect 'err' and 'stderr'
36
+ mu * sync.Mutex
37
+ err error
38
+ stderr io.Writer
38
39
}
39
40
40
41
// Args creates a pipe containing the program's command-line arguments from
@@ -414,8 +415,9 @@ func (p *Pipe) Exec(cmdLine string) *Pipe {
414
415
cmd .Stdin = r
415
416
cmd .Stdout = w
416
417
cmd .Stderr = w
417
- if p .stderr != nil {
418
- cmd .Stderr = p .stderr
418
+ pipeStderr := p .stdErr ()
419
+ if pipeStderr != nil {
420
+ cmd .Stderr = pipeStderr
419
421
}
420
422
err = cmd .Start ()
421
423
if err != nil {
@@ -454,8 +456,9 @@ func (p *Pipe) ExecForEach(cmdLine string) *Pipe {
454
456
cmd := exec .Command (args [0 ], args [1 :]... )
455
457
cmd .Stdout = w
456
458
cmd .Stderr = w
457
- if p .stderr != nil {
458
- cmd .Stderr = p .stderr
459
+ pipeStderr := p .stdErr ()
460
+ if pipeStderr != nil {
461
+ cmd .Stderr = pipeStderr
459
462
}
460
463
err = cmd .Start ()
461
464
if err != nil {
@@ -839,6 +842,18 @@ func (p *Pipe) Slice() ([]string, error) {
839
842
return result , p .Error ()
840
843
}
841
844
845
+ // stdErr returns the pipe's configured standard error writer for commands run
846
+ // via [Pipe.Exec] and [Pipe.ExecForEach]. The default is nil, which means that
847
+ // error output will go to the pipe.
848
+ func (p * Pipe ) stdErr () io.Writer {
849
+ if p .mu == nil { // uninitialised pipe
850
+ return nil
851
+ }
852
+ p .mu .Lock ()
853
+ defer p .mu .Unlock ()
854
+ return p .stderr
855
+ }
856
+
842
857
// Stdout copies the pipe's contents to its configured standard output (using
843
858
// [Pipe.WithStdout]), or to [os.Stdout] otherwise, and returns the number of
844
859
// bytes successfully written, together with any error.
@@ -913,10 +928,11 @@ func (p *Pipe) WithReader(r io.Reader) *Pipe {
913
928
return p
914
929
}
915
930
916
- // WithStderr redirects the standard error output for commands run via
917
- // [Pipe.Exec] or [Pipe.ExecForEach] to the writer w, instead of going to the
918
- // pipe as it normally would.
931
+ // WithStderr sets the standard error output for [Pipe.Exec] or
932
+ // [Pipe.ExecForEach] commands to w, instead of the pipe.
919
933
func (p * Pipe ) WithStderr (w io.Writer ) * Pipe {
934
+ p .mu .Lock ()
935
+ defer p .mu .Unlock ()
920
936
p .stderr = w
921
937
return p
922
938
}
0 commit comments