@@ -82,61 +82,73 @@ extension Process {
8282extension Process {
8383 public static func getOutput( url: URL , arguments: [ String ] , currentDirectoryURL: URL ? = nil , environment: Environment ? = nil , interruptible: Bool = true ) async throws -> Processes . ExecutionResult {
8484 if #available( macOS 15 , iOS 18 , tvOS 18 , watchOS 11 , visionOS 2 , * ) {
85+ let stdoutPipe = Pipe ( )
86+ let stderrPipe = Pipe ( )
87+
8588 // 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)
97100 }
101+ return Processes . ExecutionResult ( exitStatus: exitStatus, stdout: Data ( output. stdoutData) , stderr: Data ( output. stderrData) )
98102 } else {
103+ let stdoutPipe = Pipe ( )
104+ let stderrPipe = Pipe ( )
105+
99106 // 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)
111118 }
119+ return Processes . ExecutionResult ( exitStatus: exitStatus, stdout: Data ( output. stdoutData) , stderr: Data ( output. stderrData) )
112120 }
113121 }
114122
115123 public static func getMergedOutput( url: URL , arguments: [ String ] , currentDirectoryURL: URL ? = nil , environment: Environment ? = nil , interruptible: Bool = true ) async throws -> ( exitStatus: Processes . ExitStatus , output: Data ) {
116124 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 ( )
127136 }
137+ return ( exitStatus: exitStatus, output: Data ( output) )
128138 } 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 ( )
139150 }
151+ return ( exitStatus: exitStatus, output: Data ( output) )
140152 }
141153 }
142154
0 commit comments