@@ -44,8 +44,6 @@ infix operator |> : AdditionPrecedence
4444public enum ErrorRedirection : Sendable {
4545 /// Keep stderr separate (default behavior)
4646 case separate
47- /// Redirect stderr to stdout, replacing stdout entirely (stdout -> /dev/null)
48- case replaceStdout
4947 /// Merge stderr into stdout (both go to the same destination)
5048 case mergeWithStdout
5149}
@@ -63,9 +61,6 @@ public struct ProcessStageOptions: Sendable {
6361 /// Default options (no redirection)
6462 public static let `default` = ProcessStageOptions ( )
6563
66- /// Redirect stderr to stdout, discarding original stdout
67- public static let stderrToStdout = ProcessStageOptions ( errorRedirection: . replaceStdout)
68-
6964 /// Merge stderr with stdout
7065 public static let mergeErrors = ProcessStageOptions ( errorRedirection: . mergeWithStdout)
7166}
@@ -143,7 +138,7 @@ public struct PipeStage: Sendable {
143138public struct PipeConfiguration <
144139 Input: InputProtocol ,
145140 Output: OutputProtocol ,
146- Error: OutputProtocol
141+ Error: ErrorOutputProtocol
147142> : Sendable , CustomStringConvertible {
148143 /// Array of process stages in the pipeline
149144 internal var stages : [ PipeStage ]
@@ -215,7 +210,7 @@ internal struct SendableCollectedResult: @unchecked Sendable {
215210 let standardOutput : Any
216211 let standardError : Any
217212
218- init < Output: OutputProtocol , Error: OutputProtocol > ( _ result: CollectedResult < Output , Error > ) {
213+ init < Output: OutputProtocol , Error: ErrorOutputProtocol > ( _ result: CollectedResult < Output , Error > ) {
219214 self . processIdentifier = result. processIdentifier
220215 self . terminationStatus = result. terminationStatus
221216 self . standardOutput = result. standardOutput
@@ -290,42 +285,13 @@ extension PipeConfiguration {
290285 output: self . output,
291286 error: self . error
292287 )
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-
322288 case . mergeWithStdout:
323289 // Redirect stderr to stdout, merge both streams
324290 let finalResult = try await Subprocess . run (
325291 configuration,
326292 input: self . input,
327293 output: self . output,
328- error: self . output
294+ error: . combineWithOutput
329295 )
330296
331297 let emptyError : Error . OutputType =
@@ -440,23 +406,6 @@ extension PipeConfiguration {
440406 error: FileDescriptorOutput ( fileDescriptor: sharedErrorPipe. writeEnd, closeAfterSpawningProcess: false )
441407 )
442408
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-
460409 taskResult = PipelineTaskResult . success (
461410 0 ,
462411 SendableCollectedResult (
@@ -471,7 +420,7 @@ extension PipeConfiguration {
471420 configuration,
472421 input: self . input,
473422 output: . fileDescriptor( writeEnd, closeAfterSpawningProcess: false ) ,
474- error: . fileDescriptor ( writeEnd , closeAfterSpawningProcess : false )
423+ error: . combineWithOutput
475424 )
476425
477426 try writeEnd. close ( )
@@ -586,23 +535,6 @@ extension PipeConfiguration {
586535 error: FileDescriptorOutput ( fileDescriptor: sharedErrorPipe. writeEnd, closeAfterSpawningProcess: false )
587536 )
588537
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-
606538 taskResult = PipelineTaskResult . success (
607539 i,
608540 SendableCollectedResult (
@@ -617,7 +549,7 @@ extension PipeConfiguration {
617549 configuration,
618550 input: . fileDescriptor( readEnd, closeAfterSpawningProcess: true ) ,
619551 output: . fileDescriptor( writeEnd, closeAfterSpawningProcess: false ) ,
620- error: . fileDescriptor ( writeEnd , closeAfterSpawningProcess : false )
552+ error: . combineWithOutput
621553 )
622554
623555 try writeEnd. close ( )
@@ -711,101 +643,16 @@ extension PipeConfiguration {
711643 error: FileDescriptorOutput ( fileDescriptor: sharedErrorPipe. writeEnd, closeAfterSpawningProcess: false )
712644 )
713645 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:
733647 return PipelineTaskResult . success (
734648 lastIndex,
735649 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
741655 ) ) )
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- }
809656 }
810657 case . swiftFunction( let function) :
811658 let inputReadFileDescriptor = createIODescriptor ( from: readEnd, closeWhenDone: true )
@@ -1086,7 +933,7 @@ extension Array where Element == PipeStage {
1086933 }
1087934
1088935 /// 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 > (
1090937 input: FinalInput ,
1091938 output: FinalOutput ,
1092939 error: FinalError
@@ -1100,7 +947,7 @@ extension Array where Element == PipeStage {
1100947 }
1101948
1102949 /// 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 > (
1104951 output: FinalOutput ,
1105952 error: FinalError
1106953 ) -> PipeConfiguration < NoInput , FinalOutput , FinalError > {
@@ -1116,15 +963,15 @@ extension Array where Element == PipeStage {
1116963}
1117964
1118965/// 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 > (
1120967 left: [ PipeStage ] ,
1121968 right: ( input: FinalInput , output: FinalOutput , error: FinalError )
1122969) -> PipeConfiguration < FinalInput , FinalOutput , FinalError > {
1123970 return left. finally ( input: right. input, output: right. output, error: right. error)
1124971}
1125972
1126973/// 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 > (
1128975 left: [ PipeStage ] ,
1129976 right: ( output: FinalOutput , error: FinalError )
1130977) -> PipeConfiguration < NoInput , FinalOutput , FinalError > {
0 commit comments