Skip to content

Commit 43c0d43

Browse files
committed
Add an overload that allows supplying custom stdout and stderr destinations AND a body
Every other combination of stdin/stdout/stderr with a custom body was present except for this one.
1 parent e62036c commit 43c0d43

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

Sources/Subprocess/API.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,70 @@ public func run<
142142

143143
// MARK: - Custom Execution Body
144144

145+
/// Run an executable with given parameters and a custom closure
146+
/// to manage the running subprocess' lifetime and its IOs.
147+
/// - Parameters:
148+
/// - executable: The executable to run.
149+
/// - arguments: The arguments to pass to the executable.
150+
/// - environment: The environment in which to run the executable.
151+
/// - workingDirectory: The working directory in which to run the executable.
152+
/// - platformOptions: The platform specific options to use
153+
/// when running the executable.
154+
/// - input: The input to send to the executable.
155+
/// - output: How to manage the executable standard ouput.
156+
/// - error: How to manager executable standard error.
157+
/// - isolation: the isolation context to run the body closure.
158+
/// - body: The custom execution body to manually control the running process
159+
/// - Returns a ExecutableResult type containing the return value
160+
/// of the closure.
161+
#if SubprocessSpan
162+
@available(SubprocessSpan, *)
163+
#endif
164+
public func run<Result, Input: InputProtocol, Output: OutputProtocol, Error: OutputProtocol>(
165+
_ executable: Executable,
166+
arguments: Arguments = [],
167+
environment: Environment = .inherit,
168+
workingDirectory: FilePath? = nil,
169+
platformOptions: PlatformOptions = PlatformOptions(),
170+
input: Input = .none,
171+
output: Output,
172+
error: Error,
173+
isolation: isolated (any Actor)? = #isolation,
174+
body: ((Execution) async throws -> Result)
175+
) async throws -> ExecutionResult<Result> where Error.OutputType == Void {
176+
return try await Configuration(
177+
executable: executable,
178+
arguments: arguments,
179+
environment: environment,
180+
workingDirectory: workingDirectory,
181+
platformOptions: platformOptions
182+
).run(
183+
input: try input.createPipe(),
184+
output: try output.createPipe(),
185+
error: try error.createPipe()
186+
) { execution, inputIO, _, _ in
187+
var inputIOBox: TrackedPlatformDiskIO? = consume inputIO
188+
return try await withThrowingTaskGroup(
189+
of: Void.self,
190+
returning: Result.self
191+
) { group in
192+
var inputIOContainer: TrackedPlatformDiskIO? = inputIOBox.take()
193+
group.addTask {
194+
if let inputIO = inputIOContainer.take() {
195+
let writer = StandardInputWriter(diskIO: inputIO)
196+
try await input.write(with: writer)
197+
try await writer.finish()
198+
}
199+
}
200+
201+
// Body runs in the same isolation
202+
let result = try await body(execution)
203+
try await group.waitForAll()
204+
return result
205+
}
206+
}
207+
}
208+
145209
/// Run an executable with given parameters and a custom closure
146210
/// to manage the running subprocess' lifetime and its IOs.
147211
/// - Parameters:

0 commit comments

Comments
 (0)