@@ -44,8 +44,6 @@ infix operator |> : AdditionPrecedence
44
44
public enum ErrorRedirection : Sendable {
45
45
/// Keep stderr separate (default behavior)
46
46
case separate
47
- /// Redirect stderr to stdout, replacing stdout entirely (stdout -> /dev/null)
48
- case replaceStdout
49
47
/// Merge stderr into stdout (both go to the same destination)
50
48
case mergeWithStdout
51
49
}
@@ -63,9 +61,6 @@ public struct ProcessStageOptions: Sendable {
63
61
/// Default options (no redirection)
64
62
public static let `default` = ProcessStageOptions ( )
65
63
66
- /// Redirect stderr to stdout, discarding original stdout
67
- public static let stderrToStdout = ProcessStageOptions ( errorRedirection: . replaceStdout)
68
-
69
64
/// Merge stderr with stdout
70
65
public static let mergeErrors = ProcessStageOptions ( errorRedirection: . mergeWithStdout)
71
66
}
@@ -143,7 +138,7 @@ public struct PipeStage: Sendable {
143
138
public struct PipeConfiguration <
144
139
Input: InputProtocol ,
145
140
Output: OutputProtocol ,
146
- Error: OutputProtocol
141
+ Error: ErrorOutputProtocol
147
142
> : Sendable , CustomStringConvertible {
148
143
/// Array of process stages in the pipeline
149
144
internal var stages : [ PipeStage ]
@@ -215,7 +210,7 @@ internal struct SendableCollectedResult: @unchecked Sendable {
215
210
let standardOutput : Any
216
211
let standardError : Any
217
212
218
- init < Output: OutputProtocol , Error: OutputProtocol > ( _ result: CollectedResult < Output , Error > ) {
213
+ init < Output: OutputProtocol , Error: ErrorOutputProtocol > ( _ result: CollectedResult < Output , Error > ) {
219
214
self . processIdentifier = result. processIdentifier
220
215
self . terminationStatus = result. terminationStatus
221
216
self . standardOutput = result. standardOutput
@@ -290,42 +285,13 @@ extension PipeConfiguration {
290
285
output: self . output,
291
286
error: self . error
292
287
)
293
-
294
- case . replaceStdout:
295
- // Redirect stderr to stdout, discard original stdout
296
- let result = try await Subprocess . run (
297
- configuration,
298
- input: self . input,
299
- output: . discarded,
300
- error: self . output
301
- )
302
-
303
- let emptyError : Error . OutputType =
304
- if Error . OutputType. self == Void . self {
305
- ( ) as! Error. OutputType
306
- } else if Error. OutputType. self == String ? . self {
307
- String ? . none as! Error . OutputType
308
- } else if Error . OutputType. self == [ UInt8] ? . self {
309
- [ UInt8] ? . none as! Error . OutputType
310
- } else {
311
- fatalError ( )
312
- }
313
-
314
- // Create a new result with the error output as the standard output
315
- return CollectedResult (
316
- processIdentifier: result. processIdentifier,
317
- terminationStatus: result. terminationStatus,
318
- standardOutput: result. standardError,
319
- standardError: emptyError
320
- )
321
-
322
288
case . mergeWithStdout:
323
289
// Redirect stderr to stdout, merge both streams
324
290
let finalResult = try await Subprocess . run (
325
291
configuration,
326
292
input: self . input,
327
293
output: self . output,
328
- error: self . output
294
+ error: . combineWithOutput
329
295
)
330
296
331
297
let emptyError : Error . OutputType =
@@ -440,23 +406,6 @@ extension PipeConfiguration {
440
406
error: FileDescriptorOutput ( fileDescriptor: sharedErrorPipe. writeEnd, closeAfterSpawningProcess: false )
441
407
)
442
408
443
- taskResult = PipelineTaskResult . success (
444
- 0 ,
445
- SendableCollectedResult (
446
- CollectedResult < FileDescriptorOutput , DiscardedOutput > (
447
- processIdentifier: originalResult. processIdentifier,
448
- terminationStatus: originalResult. terminationStatus,
449
- standardOutput: ( ) ,
450
- standardError: ( )
451
- ) ) )
452
- case . replaceStdout:
453
- let originalResult = try await Subprocess . run (
454
- configuration,
455
- input: self . input,
456
- output: . discarded,
457
- error: . fileDescriptor( writeEnd, closeAfterSpawningProcess: true )
458
- )
459
-
460
409
taskResult = PipelineTaskResult . success (
461
410
0 ,
462
411
SendableCollectedResult (
@@ -471,7 +420,7 @@ extension PipeConfiguration {
471
420
configuration,
472
421
input: self . input,
473
422
output: . fileDescriptor( writeEnd, closeAfterSpawningProcess: false ) ,
474
- error: . fileDescriptor ( writeEnd , closeAfterSpawningProcess : false )
423
+ error: . combineWithOutput
475
424
)
476
425
477
426
try writeEnd. close ( )
@@ -586,23 +535,6 @@ extension PipeConfiguration {
586
535
error: FileDescriptorOutput ( fileDescriptor: sharedErrorPipe. writeEnd, closeAfterSpawningProcess: false )
587
536
)
588
537
589
- taskResult = PipelineTaskResult . success (
590
- i,
591
- SendableCollectedResult (
592
- CollectedResult < FileDescriptorOutput , DiscardedOutput > (
593
- processIdentifier: originalResult. processIdentifier,
594
- terminationStatus: originalResult. terminationStatus,
595
- standardOutput: ( ) ,
596
- standardError: ( )
597
- ) ) )
598
- case . replaceStdout:
599
- let originalResult = try await Subprocess . run (
600
- configuration,
601
- input: . fileDescriptor( readEnd, closeAfterSpawningProcess: true ) ,
602
- output: . discarded,
603
- error: . fileDescriptor( writeEnd, closeAfterSpawningProcess: true )
604
- )
605
-
606
538
taskResult = PipelineTaskResult . success (
607
539
i,
608
540
SendableCollectedResult (
@@ -617,7 +549,7 @@ extension PipeConfiguration {
617
549
configuration,
618
550
input: . fileDescriptor( readEnd, closeAfterSpawningProcess: true ) ,
619
551
output: . fileDescriptor( writeEnd, closeAfterSpawningProcess: false ) ,
620
- error: . fileDescriptor ( writeEnd , closeAfterSpawningProcess : false )
552
+ error: . combineWithOutput
621
553
)
622
554
623
555
try writeEnd. close ( )
@@ -711,101 +643,16 @@ extension PipeConfiguration {
711
643
error: FileDescriptorOutput ( fileDescriptor: sharedErrorPipe. writeEnd, closeAfterSpawningProcess: false )
712
644
)
713
645
return PipelineTaskResult . success ( lastIndex, SendableCollectedResult ( finalResult) )
714
- case . replaceStdout:
715
- let finalResult = try await Subprocess . run (
716
- configuration,
717
- input: . fileDescriptor( readEnd, closeAfterSpawningProcess: true ) ,
718
- output: . discarded,
719
- error: self . output
720
- )
721
-
722
- let emptyError : Error . OutputType =
723
- if Error . OutputType. self == Void . self {
724
- ( ) as! Error. OutputType
725
- } else if Error. OutputType. self == String ? . self {
726
- String ? . none as! Error . OutputType
727
- } else if Error . OutputType. self == [ UInt8] ? . self {
728
- [ UInt8] ? . none as! Error . OutputType
729
- } else {
730
- fatalError ( )
731
- }
732
-
646
+ case . mergeWithStdout:
733
647
return PipelineTaskResult . success (
734
648
lastIndex,
735
649
SendableCollectedResult (
736
- CollectedResult < Output , Error > (
737
- processIdentifier : finalResult . processIdentifier ,
738
- terminationStatus : finalResult . terminationStatus ,
739
- standardOutput : finalResult . standardError ,
740
- standardError : emptyError
650
+ try await Subprocess . run (
651
+ configuration ,
652
+ input : . fileDescriptor ( readEnd , closeAfterSpawningProcess : true ) ,
653
+ output : self . output ,
654
+ error : . combineWithOutput
741
655
) ) )
742
- case . mergeWithStdout:
743
- let finalResult = try await Subprocess . run (
744
- configuration,
745
- input: . fileDescriptor( readEnd, closeAfterSpawningProcess: true ) ,
746
- output: self . output,
747
- error: self . output
748
- )
749
-
750
- let emptyError : Error . OutputType =
751
- if Error . OutputType. self == Void . self {
752
- ( ) as! Error. OutputType
753
- } else if Error. OutputType. self == String ? . self {
754
- String ? . none as! Error . OutputType
755
- } else if Error . OutputType. self == [ UInt8] ? . self {
756
- [ UInt8] ? . none as! Error . OutputType
757
- } else {
758
- fatalError ( )
759
- }
760
-
761
- // Merge the different kinds of output types (string, fd, etc.)
762
- if Output . OutputType. self == Void . self {
763
- return PipelineTaskResult . success (
764
- lastIndex,
765
- SendableCollectedResult (
766
- CollectedResult < Output , Error > (
767
- processIdentifier: finalResult. processIdentifier,
768
- terminationStatus: finalResult. terminationStatus,
769
- standardOutput: ( ) as! Output . OutputType ,
770
- standardError: finalResult. standardOutput as! Error . OutputType
771
- ) ) )
772
- } else if Output . OutputType. self == String ? . self {
773
- let out : String ? = finalResult. standardOutput as! String ?
774
- let err : String ? = finalResult. standardError as! String ?
775
-
776
- let finalOutput = ( out ?? " " ) + ( err ?? " " )
777
- // FIXME reduce the final output to the output.maxSize number of bytes
778
-
779
- return PipelineTaskResult . success (
780
- lastIndex,
781
- SendableCollectedResult (
782
- CollectedResult < Output , Error > (
783
- processIdentifier: finalResult. processIdentifier,
784
- terminationStatus: finalResult. terminationStatus,
785
- standardOutput: finalOutput as! Output . OutputType ,
786
- standardError: emptyError
787
- ) ) )
788
- } else if Output . OutputType. self == [ UInt8 ] . self {
789
- let out : [ UInt8 ] ? = finalResult. standardOutput as! [ UInt8 ] ?
790
- let err : [ UInt8 ] ? = finalResult. standardError as! [ UInt8 ] ?
791
-
792
- var finalOutput = ( out ?? [ ] ) + ( err ?? [ ] )
793
- if finalOutput. count > self . output. maxSize {
794
- finalOutput = [ UInt8] ( finalOutput [ ... self . output. maxSize] )
795
- }
796
-
797
- return PipelineTaskResult . success (
798
- lastIndex,
799
- SendableCollectedResult (
800
- CollectedResult < Output , Error > (
801
- processIdentifier: finalResult. processIdentifier,
802
- terminationStatus: finalResult. terminationStatus,
803
- standardOutput: finalOutput as! Output . OutputType ,
804
- standardError: emptyError
805
- ) ) )
806
- } else {
807
- fatalError ( )
808
- }
809
656
}
810
657
case . swiftFunction( let function) :
811
658
let inputReadFileDescriptor = createIODescriptor ( from: readEnd, closeWhenDone: true )
@@ -1086,7 +933,7 @@ extension Array where Element == PipeStage {
1086
933
}
1087
934
1088
935
/// Create a PipeConfiguration from stages with specific input, output, and error types
1089
- public func finally< FinalInput: InputProtocol , FinalOutput: OutputProtocol , FinalError: OutputProtocol > (
936
+ public func finally< FinalInput: InputProtocol , FinalOutput: OutputProtocol , FinalError: ErrorOutputProtocol > (
1090
937
input: FinalInput ,
1091
938
output: FinalOutput ,
1092
939
error: FinalError
@@ -1100,7 +947,7 @@ extension Array where Element == PipeStage {
1100
947
}
1101
948
1102
949
/// Create a PipeConfiguration from stages with no input and specific output and error types
1103
- public func finally< FinalOutput: OutputProtocol , FinalError: OutputProtocol > (
950
+ public func finally< FinalOutput: OutputProtocol , FinalError: ErrorOutputProtocol > (
1104
951
output: FinalOutput ,
1105
952
error: FinalError
1106
953
) -> PipeConfiguration < NoInput , FinalOutput , FinalError > {
@@ -1116,15 +963,15 @@ extension Array where Element == PipeStage {
1116
963
}
1117
964
1118
965
/// Final pipe operator for stage arrays with specific input, output and error types
1119
- public func |> < FinalInput: InputProtocol , FinalOutput: OutputProtocol , FinalError: OutputProtocol > (
966
+ public func |> < FinalInput: InputProtocol , FinalOutput: OutputProtocol , FinalError: ErrorOutputProtocol > (
1120
967
left: [ PipeStage ] ,
1121
968
right: ( input: FinalInput , output: FinalOutput , error: FinalError )
1122
969
) -> PipeConfiguration < FinalInput , FinalOutput , FinalError > {
1123
970
return left. finally ( input: right. input, output: right. output, error: right. error)
1124
971
}
1125
972
1126
973
/// Final pipe operator for stage arrays with specific output and error types
1127
- public func |> < FinalOutput: OutputProtocol , FinalError: OutputProtocol > (
974
+ public func |> < FinalOutput: OutputProtocol , FinalError: ErrorOutputProtocol > (
1128
975
left: [ PipeStage ] ,
1129
976
right: ( output: FinalOutput , error: FinalError )
1130
977
) -> PipeConfiguration < NoInput , FinalOutput , FinalError > {
0 commit comments