@@ -82,61 +82,73 @@ extension Process {
82
82
extension Process {
83
83
public static func getOutput( url: URL , arguments: [ String ] , currentDirectoryURL: URL ? = nil , environment: Environment ? = nil , interruptible: Bool = true ) async throws -> Processes . ExecutionResult {
84
84
if #available( macOS 15 , iOS 18 , tvOS 18 , watchOS 11 , visionOS 2 , * ) {
85
+ let stdoutPipe = Pipe ( )
86
+ let stderrPipe = Pipe ( )
87
+
85
88
// Extend the lifetime of the pipes to avoid file descriptors being closed until the AsyncStream is finished being consumed.
86
- return try await withExtendedLifetime ( ( Pipe ( ) , Pipe ( ) ) ) { ( stdoutPipe , stderrPipe ) in
87
- let ( exitStatus , output ) = try await _getOutput ( url : url , arguments : arguments , currentDirectoryURL : currentDirectoryURL , environment : environment , interruptible : interruptible ) { process in
88
- let stdoutStream = process . makeStream ( for : \ . standardOutputPipe , using : stdoutPipe )
89
- let stderrStream = process . makeStream ( for : \ . standardErrorPipe , using : stderrPipe )
90
- return ( stdoutStream , stderrStream )
91
- } collect : { ( stdoutStream , stderrStream ) in
92
- let stdoutData = try await stdoutStream . collect ( )
93
- let stderrData = try await stderrStream. collect ( )
94
- return ( stdoutData : stdoutData , stderrData : stderrData )
95
- }
96
- return Processes . ExecutionResult ( exitStatus : exitStatus , stdout : Data ( output . stdoutData) , stderr : Data ( output . stderrData) )
89
+ defer { withExtendedLifetime ( stdoutPipe ) { } }
90
+ defer { withExtendedLifetime ( stderrPipe ) { } }
91
+
92
+ let ( exitStatus , output ) = try await _getOutput ( url : url , arguments : arguments , currentDirectoryURL : currentDirectoryURL , environment : environment , interruptible : interruptible ) { process in
93
+ let stdoutStream = process . makeStream ( for : \ . standardOutputPipe , using : stdoutPipe )
94
+ let stderrStream = process . makeStream ( for : \ . standardErrorPipe , using : stderrPipe )
95
+ return ( stdoutStream , stderrStream )
96
+ } collect : { ( stdoutStream , stderrStream) in
97
+ let stdoutData = try await stdoutStream . collect ( )
98
+ let stderrData = try await stderrStream . collect ( )
99
+ return ( stdoutData : stdoutData, stderrData : stderrData)
97
100
}
101
+ return Processes . ExecutionResult ( exitStatus: exitStatus, stdout: Data ( output. stdoutData) , stderr: Data ( output. stderrData) )
98
102
} else {
103
+ let stdoutPipe = Pipe ( )
104
+ let stderrPipe = Pipe ( )
105
+
99
106
// Extend the lifetime of the pipes to avoid file descriptors being closed until the AsyncStream is finished being consumed.
100
- return try await withExtendedLifetime ( ( Pipe ( ) , Pipe ( ) ) ) { ( stdoutPipe , stderrPipe ) in
101
- let ( exitStatus , output ) = try await _getOutput ( url : url , arguments : arguments , currentDirectoryURL : currentDirectoryURL , environment : environment , interruptible : interruptible ) { process in
102
- let stdoutStream = process . _makeStream ( for : \ . standardOutputPipe , using : stdoutPipe )
103
- let stderrStream = process . _makeStream ( for : \ . standardErrorPipe , using : stderrPipe )
104
- return ( stdoutStream , stderrStream )
105
- } collect : { ( stdoutStream , stderrStream ) in
106
- let stdoutData = try await stdoutStream . collect ( )
107
- let stderrData = try await stderrStream. collect ( )
108
- return ( stdoutData : stdoutData , stderrData : stderrData )
109
- }
110
- return Processes . ExecutionResult ( exitStatus : exitStatus , stdout : Data ( output . stdoutData) , stderr : Data ( output . stderrData) )
107
+ defer { withExtendedLifetime ( stdoutPipe ) { } }
108
+ defer { withExtendedLifetime ( stderrPipe ) { } }
109
+
110
+ let ( exitStatus , output ) = try await _getOutput ( url : url , arguments : arguments , currentDirectoryURL : currentDirectoryURL , environment : environment , interruptible : interruptible ) { process in
111
+ let stdoutStream = process . _makeStream ( for : \ . standardOutputPipe , using : stdoutPipe )
112
+ let stderrStream = process . _makeStream ( for : \ . standardErrorPipe , using : stderrPipe )
113
+ return ( stdoutStream , stderrStream )
114
+ } collect : { ( stdoutStream , stderrStream) in
115
+ let stdoutData = try await stdoutStream . collect ( )
116
+ let stderrData = try await stderrStream . collect ( )
117
+ return ( stdoutData : stdoutData, stderrData : stderrData)
111
118
}
119
+ return Processes . ExecutionResult ( exitStatus: exitStatus, stdout: Data ( output. stdoutData) , stderr: Data ( output. stderrData) )
112
120
}
113
121
}
114
122
115
123
public static func getMergedOutput( url: URL , arguments: [ String ] , currentDirectoryURL: URL ? = nil , environment: Environment ? = nil , interruptible: Bool = true ) async throws -> ( exitStatus: Processes . ExitStatus , output: Data ) {
116
124
if #available( macOS 15 , iOS 18 , tvOS 18 , watchOS 11 , visionOS 2 , * ) {
117
- // Extend the lifetime of the pipe to avoid file descriptors being closed until the AsyncStream is finished being consumed.
118
- return try await withExtendedLifetime ( Pipe ( ) ) { pipe in
119
- let ( exitStatus, output) = try await _getOutput ( url: url, arguments: arguments, currentDirectoryURL: currentDirectoryURL, environment: environment, interruptible: interruptible) { process in
120
- process. standardOutputPipe = pipe
121
- process. standardErrorPipe = pipe
122
- return pipe. fileHandleForReading. bytes ( on: . global( ) )
123
- } collect: { stream in
124
- try await stream. collect ( )
125
- }
126
- return ( exitStatus: exitStatus, output: Data ( output) )
125
+ let pipe = Pipe ( )
126
+
127
+ // Extend the lifetime of the pipes to avoid file descriptors being closed until the AsyncStream is finished being consumed.
128
+ defer { withExtendedLifetime ( pipe) { } }
129
+
130
+ let ( exitStatus, output) = try await _getOutput ( url: url, arguments: arguments, currentDirectoryURL: currentDirectoryURL, environment: environment, interruptible: interruptible) { process in
131
+ process. standardOutputPipe = pipe
132
+ process. standardErrorPipe = pipe
133
+ return pipe. fileHandleForReading. bytes ( on: . global( ) )
134
+ } collect: { stream in
135
+ try await stream. collect ( )
127
136
}
137
+ return ( exitStatus: exitStatus, output: Data ( output) )
128
138
} else {
129
- // Extend the lifetime of the pipe to avoid file descriptors being closed until the AsyncStream is finished being consumed.
130
- return try await withExtendedLifetime ( Pipe ( ) ) { pipe in
131
- let ( exitStatus, output) = try await _getOutput ( url: url, arguments: arguments, currentDirectoryURL: currentDirectoryURL, environment: environment, interruptible: interruptible) { process in
132
- process. standardOutputPipe = pipe
133
- process. standardErrorPipe = pipe
134
- return pipe. fileHandleForReading. _bytes ( on: . global( ) )
135
- } collect: { stream in
136
- try await stream. collect ( )
137
- }
138
- return ( exitStatus: exitStatus, output: Data ( output) )
139
+ let pipe = Pipe ( )
140
+
141
+ // Extend the lifetime of the pipes to avoid file descriptors being closed until the AsyncStream is finished being consumed.
142
+ defer { withExtendedLifetime ( pipe) { } }
143
+
144
+ let ( exitStatus, output) = try await _getOutput ( url: url, arguments: arguments, currentDirectoryURL: currentDirectoryURL, environment: environment, interruptible: interruptible) { process in
145
+ process. standardOutputPipe = pipe
146
+ process. standardErrorPipe = pipe
147
+ return pipe. fileHandleForReading. _bytes ( on: . global( ) )
148
+ } collect: { stream in
149
+ try await stream. collect ( )
139
150
}
151
+ return ( exitStatus: exitStatus, output: Data ( output) )
140
152
}
141
153
}
142
154
0 commit comments