@@ -129,10 +129,20 @@ public final class Process: ObjectIdentifierProtocol {
129
129
public enum OutputRedirection {
130
130
/// Do not redirect the output
131
131
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
+ }
136
146
137
147
public var redirectsOutput : Bool {
138
148
switch self {
@@ -145,12 +155,23 @@ public final class Process: ObjectIdentifierProtocol {
145
155
146
156
public var outputClosures : ( stdoutClosure: OutputClosure , stderrClosure: OutputClosure ) ? {
147
157
switch self {
148
- case . stream( let stdoutClosure, let stderrClosure) :
158
+ case let . stream( stdoutClosure, stderrClosure, _ ) :
149
159
return ( stdoutClosure: stdoutClosure, stderrClosure: stderrClosure)
150
160
case . collect, . none:
151
161
return nil
152
162
}
153
163
}
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
+ }
154
175
}
155
176
156
177
/// Typealias for process id type.
@@ -433,19 +454,30 @@ public final class Process: ObjectIdentifierProtocol {
433
454
// Open /dev/null as stdin.
434
455
posix_spawn_file_actions_addopen ( & fileActions, 0 , devNull, O_RDONLY, 0 )
435
456
436
- var outputPipe : [ Int32 ] = [ 0 , 0 ]
437
- var stderrPipe : [ Int32 ] = [ 0 , 0 ]
457
+ var outputPipe : [ Int32 ] = [ - 1 , - 1 ]
458
+ var stderrPipe : [ Int32 ] = [ - 1 , - 1 ]
438
459
if outputRedirection. redirectsOutput {
439
- // Open the pipes .
460
+ // Open the pipe .
440
461
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.
443
464
posix_spawn_file_actions_adddup2 ( & fileActions, outputPipe [ 1 ] , 1 )
444
- posix_spawn_file_actions_adddup2 ( & fileActions , stderrPipe [ 1 ] , 2 )
465
+
445
466
// 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 ] )
449
481
}
450
482
} else {
451
483
posix_spawn_file_actions_adddup2 ( & fileActions, 1 , 1 )
@@ -475,17 +507,20 @@ public final class Process: ObjectIdentifierProtocol {
475
507
thread. start ( )
476
508
self . stdout. thread = thread
477
509
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 ] )
480
514
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
+ }
485
520
}
521
+ thread. start ( )
522
+ self . stderr. thread = thread
486
523
}
487
- thread. start ( )
488
- self . stderr. thread = thread
489
524
}
490
525
#endif // POSIX implementation
491
526
}
0 commit comments