@@ -129,10 +129,20 @@ public final class Process: ObjectIdentifierProtocol {
129129 public enum OutputRedirection {
130130 /// Do not redirect the output
131131 case none
132- /// Collect stdout and stderr output and provide it back via ProcessResult object
133- case collect
134- /// Stream stdout and stderr via the corresponding closures
135- case stream( stdout: OutputClosure , stderr: OutputClosure )
132+ /// Collect stdout and stderr output and provide it back via ProcessResult object. If redirectStderr is true,
133+ /// stderr be redirected to stdout.
134+ case collect( redirectStderr: Bool )
135+ /// Stream stdout and stderr via the corresponding closures. If redirectStderr is true, stderr be redirected to
136+ /// stdout.
137+ case stream( stdout: OutputClosure , stderr: OutputClosure , redirectStderr: Bool )
138+
139+ /// Default collect OutputRedirection that defaults to not redirect stderr. Provided for API compatibility.
140+ public static let collect : OutputRedirection = . collect( redirectStderr: false )
141+
142+ /// Default stream OutputRedirection that defaults to not redirect stderr. Provided for API compatibility.
143+ public static func stream( stdout: @escaping OutputClosure , stderr: @escaping OutputClosure ) -> Self {
144+ return . stream( stdout: stdout, stderr: stderr, redirectStderr: false )
145+ }
136146
137147 public var redirectsOutput : Bool {
138148 switch self {
@@ -145,12 +155,23 @@ public final class Process: ObjectIdentifierProtocol {
145155
146156 public var outputClosures : ( stdoutClosure: OutputClosure , stderrClosure: OutputClosure ) ? {
147157 switch self {
148- case . stream( let stdoutClosure, let stderrClosure) :
158+ case let . stream( stdoutClosure, stderrClosure, _ ) :
149159 return ( stdoutClosure: stdoutClosure, stderrClosure: stderrClosure)
150160 case . collect, . none:
151161 return nil
152162 }
153163 }
164+
165+ public var redirectStderr : Bool {
166+ switch self {
167+ case let . collect( redirectStderr) :
168+ return redirectStderr
169+ case let . stream( _, _, redirectStderr) :
170+ return redirectStderr
171+ default :
172+ return false
173+ }
174+ }
154175 }
155176
156177 /// Typealias for process id type.
@@ -433,19 +454,30 @@ public final class Process: ObjectIdentifierProtocol {
433454 // Open /dev/null as stdin.
434455 posix_spawn_file_actions_addopen ( & fileActions, 0 , devNull, O_RDONLY, 0 )
435456
436- var outputPipe : [ Int32 ] = [ 0 , 0 ]
437- var stderrPipe : [ Int32 ] = [ 0 , 0 ]
457+ var outputPipe : [ Int32 ] = [ - 1 , - 1 ]
458+ var stderrPipe : [ Int32 ] = [ - 1 , - 1 ]
438459 if outputRedirection. redirectsOutput {
439- // Open the pipes .
460+ // Open the pipe .
440461 try open ( pipe: & outputPipe)
441- try open ( pipe : & stderrPipe )
442- // Open the write end of the pipe as stdout and stderr, if desired .
462+
463+ // Open the write end of the pipe.
443464 posix_spawn_file_actions_adddup2 ( & fileActions, outputPipe [ 1 ] , 1 )
444- posix_spawn_file_actions_adddup2 ( & fileActions , stderrPipe [ 1 ] , 2 )
465+
445466 // Close the other ends of the pipe.
446- for pipe in [ outputPipe, stderrPipe] {
447- posix_spawn_file_actions_addclose ( & fileActions, pipe [ 0 ] )
448- posix_spawn_file_actions_addclose ( & fileActions, pipe [ 1 ] )
467+ posix_spawn_file_actions_addclose ( & fileActions, outputPipe [ 0 ] )
468+ posix_spawn_file_actions_addclose ( & fileActions, outputPipe [ 1 ] )
469+
470+ if outputRedirection. redirectStderr {
471+ // If merged was requested, send stderr to stdout.
472+ posix_spawn_file_actions_adddup2 ( & fileActions, 1 , 2 )
473+ } else {
474+ // If no redirect was requested, open the pipe for stderr.
475+ try open ( pipe: & stderrPipe)
476+ posix_spawn_file_actions_adddup2 ( & fileActions, stderrPipe [ 1 ] , 2 )
477+
478+ // Close the other ends of the pipe.
479+ posix_spawn_file_actions_addclose ( & fileActions, stderrPipe [ 0 ] )
480+ posix_spawn_file_actions_addclose ( & fileActions, stderrPipe [ 1 ] )
449481 }
450482 } else {
451483 posix_spawn_file_actions_adddup2 ( & fileActions, 1 , 1 )
@@ -475,17 +507,20 @@ public final class Process: ObjectIdentifierProtocol {
475507 thread. start ( )
476508 self . stdout. thread = thread
477509
478- // Close the write end of the stderr pipe.
479- try close ( fd: & stderrPipe[ 1 ] )
510+ // Only schedule a thread for stderr if no redirect was requested.
511+ if !outputRedirection. redirectStderr {
512+ // Close the write end of the stderr pipe.
513+ try close ( fd: & stderrPipe[ 1 ] )
480514
481- // Create a thread and start reading the stderr output on it.
482- thread = Thread { [ weak self] in
483- if let readResult = self ? . readOutput ( onFD: stderrPipe [ 0 ] , outputClosure: outputClosures? . stderrClosure) {
484- self ? . stderr. result = readResult
515+ // Create a thread and start reading the stderr output on it.
516+ thread = Thread { [ weak self] in
517+ if let readResult = self ? . readOutput ( onFD: stderrPipe [ 0 ] , outputClosure: outputClosures? . stderrClosure) {
518+ self ? . stderr. result = readResult
519+ }
485520 }
521+ thread. start ( )
522+ self . stderr. thread = thread
486523 }
487- thread. start ( )
488- self . stderr. thread = thread
489524 }
490525 #endif // POSIX implementation
491526 }
0 commit comments