Skip to content

Commit 8a8c6b7

Browse files
authored
Merge pull request #48 from iCharlesHu/charles/buffer-improvements
AsyncBufferSequence.Buffer Improvements
2 parents e62036c + 195fcee commit 8a8c6b7

19 files changed

+701
-442
lines changed

README.md

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,17 @@ To have more precise control over input and output, you can provide a custom clo
6464
```swift
6565
import Subprocess
6666

67-
let result = try await run(
68-
.path("/bin/dd"),
69-
arguments: ["if=/path/to/document"]
70-
) { execution in
71-
var contents = ""
72-
for try await chunk in execution.standardOutput {
73-
let string = chunk.withUnsafeBytes { String(decoding: $0, as: UTF8.self) }
74-
contents += string
75-
if string == "Done" {
76-
// Stop execution
77-
await execution.teardown(
78-
using: [
79-
.gracefulShutDown(
80-
allowedDurationToNextStep: .seconds(0.5)
81-
)
82-
]
83-
)
84-
return contents
67+
// Monitor Nginx log via `tail -f`
68+
async let monitorResult = run(
69+
.path("/usr/bin/tail"),
70+
arguments: ["-f", "/path/to/nginx.log"]
71+
) { execution, standardOutput in
72+
for try await line in standardOutput.lines(encoding: UTF8.self) {
73+
// Parse the log text
74+
if line.contains("500") {
75+
// Oh no, 500 error
8576
}
8677
}
87-
return contents
8878
}
8979
```
9080

@@ -240,10 +230,6 @@ This option collects output as `[UInt8]`.
240230

241231
Use it by setting `.bytes` or `.bytes(limit:)` for `input` or `error`.
242232

243-
#### `SequenceOutput`:
244-
245-
This option redirects the child output to the `.standardOutput` or `.standardError` property of `Execution`. It’s only for the `run()` family that takes a custom closure.
246-
247233

248234
### Cross-platform support
249235

Sources/Subprocess/API.swift

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public func run<
143143
// MARK: - Custom Execution Body
144144

145145
/// Run an executable with given parameters and a custom closure
146-
/// to manage the running subprocess' lifetime and its IOs.
146+
/// to manage the running subprocess' lifetime and stream its standard output.
147147
/// - Parameters:
148148
/// - executable: The executable to run.
149149
/// - arguments: The arguments to pass to the executable.
@@ -152,23 +152,19 @@ public func run<
152152
/// - platformOptions: The platform specific options to use
153153
/// when running the executable.
154154
/// - input: The input to send to the executable.
155-
/// - output: How to manage the executable standard ouput.
156155
/// - error: How to manager executable standard error.
157156
/// - isolation: the isolation context to run the body closure.
158157
/// - body: The custom execution body to manually control the running process
159-
/// - Returns a ExecutableResult type containing the return value
158+
/// - Returns an executableResult type containing the return value
160159
/// of the closure.
161-
#if SubprocessSpan
162-
@available(SubprocessSpan, *)
163-
#endif
164160
public func run<Result, Input: InputProtocol, Error: OutputProtocol>(
165161
_ executable: Executable,
166162
arguments: Arguments = [],
167163
environment: Environment = .inherit,
168164
workingDirectory: FilePath? = nil,
169165
platformOptions: PlatformOptions = PlatformOptions(),
170166
input: Input = .none,
171-
error: Error,
167+
error: Error = .discarded,
172168
isolation: isolated (any Actor)? = #isolation,
173169
body: ((Execution, AsyncBufferSequence) async throws -> Result)
174170
) async throws -> ExecutionResult<Result> where Error.OutputType == Void {
@@ -208,9 +204,21 @@ public func run<Result, Input: InputProtocol, Error: OutputProtocol>(
208204
}
209205
}
210206

211-
#if SubprocessSpan
212-
@available(SubprocessSpan, *)
213-
#endif
207+
/// Run an executable with given parameters and a custom closure
208+
/// to manage the running subprocess' lifetime and stream its standard error.
209+
/// - Parameters:
210+
/// - executable: The executable to run.
211+
/// - arguments: The arguments to pass to the executable.
212+
/// - environment: The environment in which to run the executable.
213+
/// - workingDirectory: The working directory in which to run the executable.
214+
/// - platformOptions: The platform specific options to use
215+
/// when running the executable.
216+
/// - input: The input to send to the executable.
217+
/// - output: How to manager executable standard output.
218+
/// - isolation: the isolation context to run the body closure.
219+
/// - body: The custom execution body to manually control the running process
220+
/// - Returns an executableResult type containing the return value
221+
/// of the closure.
214222
public func run<Result, Input: InputProtocol, Output: OutputProtocol>(
215223
_ executable: Executable,
216224
arguments: Arguments = [],
@@ -258,16 +266,28 @@ public func run<Result, Input: InputProtocol, Output: OutputProtocol>(
258266
}
259267
}
260268

261-
#if SubprocessSpan
262-
@available(SubprocessSpan, *)
263-
#endif
269+
/// Run an executable with given parameters and a custom closure
270+
/// to manage the running subprocess' lifetime, write to its
271+
/// standard input, and stream its standard output.
272+
/// - Parameters:
273+
/// - executable: The executable to run.
274+
/// - arguments: The arguments to pass to the executable.
275+
/// - environment: The environment in which to run the executable.
276+
/// - workingDirectory: The working directory in which to run the executable.
277+
/// - platformOptions: The platform specific options to use
278+
/// when running the executable.
279+
/// - error: How to manager executable standard error.
280+
/// - isolation: the isolation context to run the body closure.
281+
/// - body: The custom execution body to manually control the running process
282+
/// - Returns an executableResult type containing the return value
283+
/// of the closure.
264284
public func run<Result, Error: OutputProtocol>(
265285
_ executable: Executable,
266286
arguments: Arguments = [],
267287
environment: Environment = .inherit,
268288
workingDirectory: FilePath? = nil,
269289
platformOptions: PlatformOptions = PlatformOptions(),
270-
error: Error,
290+
error: Error = .discarded,
271291
isolation: isolated (any Actor)? = #isolation,
272292
body: ((Execution, StandardInputWriter, AsyncBufferSequence) async throws -> Result)
273293
) async throws -> ExecutionResult<Result> where Error.OutputType == Void {
@@ -291,9 +311,21 @@ public func run<Result, Error: OutputProtocol>(
291311
}
292312
}
293313

294-
#if SubprocessSpan
295-
@available(SubprocessSpan, *)
296-
#endif
314+
/// Run an executable with given parameters and a custom closure
315+
/// to manage the running subprocess' lifetime, write to its
316+
/// standard input, and stream its standard error.
317+
/// - Parameters:
318+
/// - executable: The executable to run.
319+
/// - arguments: The arguments to pass to the executable.
320+
/// - environment: The environment in which to run the executable.
321+
/// - workingDirectory: The working directory in which to run the executable.
322+
/// - platformOptions: The platform specific options to use
323+
/// when running the executable.
324+
/// - output: How to manager executable standard output.
325+
/// - isolation: the isolation context to run the body closure.
326+
/// - body: The custom execution body to manually control the running process
327+
/// - Returns an executableResult type containing the return value
328+
/// of the closure.
297329
public func run<Result, Output: OutputProtocol>(
298330
_ executable: Executable,
299331
arguments: Arguments = [],
@@ -324,25 +356,20 @@ public func run<Result, Output: OutputProtocol>(
324356
}
325357
}
326358

327-
/// Run a executable with given parameters and a custom closure
328-
/// to manage the running subprocess' lifetime and write to its
329-
/// standard input via `StandardInputWriter`
359+
/// Run an executable with given parameters and a custom closure
360+
/// to manage the running subprocess' lifetime, write to its
361+
/// standard input, and stream its standard output and standard error.
330362
/// - Parameters:
331363
/// - executable: The executable to run.
332364
/// - arguments: The arguments to pass to the executable.
333365
/// - environment: The environment in which to run the executable.
334366
/// - workingDirectory: The working directory in which to run the executable.
335367
/// - platformOptions: The platform specific options to use
336368
/// when running the executable.
337-
/// - output:How to handle executable's standard output
338-
/// - error: How to handle executable's standard error
339369
/// - isolation: the isolation context to run the body closure.
340370
/// - body: The custom execution body to manually control the running process
341-
/// - Returns a ExecutableResult type containing the return value
371+
/// - Returns an executableResult type containing the return value
342372
/// of the closure.
343-
#if SubprocessSpan
344-
@available(SubprocessSpan, *)
345-
#endif
346373
public func run<Result>(
347374
_ executable: Executable,
348375
arguments: Arguments = [],
@@ -384,7 +411,7 @@ public func run<Result>(
384411

385412
// MARK: - Configuration Based
386413

387-
/// Run a `Configuration` asynchrously and returns
414+
/// Run a `Configuration` asynchronously and returns
388415
/// a `CollectedResult` containing the output of the child process.
389416
/// - Parameters:
390417
/// - configuration: The `Subprocess` configuration to run.
@@ -476,19 +503,15 @@ public func run<
476503
)
477504
}
478505

479-
/// Run a executable with given parameters specified by a `Configuration`
506+
/// Run an executable with given parameters specified by a `Configuration`
480507
/// - Parameters:
481508
/// - configuration: The `Subprocess` configuration to run.
482-
/// - output: The method to use for redirecting the standard output.
483-
/// - error: The method to use for redirecting the standard error.
484509
/// - isolation: the isolation context to run the body closure.
485510
/// - body: The custom configuration body to manually control
486-
/// the running process and write to its standard input.
487-
/// - Returns a ExecutableResult type containing the return value
511+
/// the running process, write to its standard input, stream
512+
/// its standard output and standard error.
513+
/// - Returns an executableResult type containing the return value
488514
/// of the closure.
489-
#if SubprocessSpan
490-
@available(SubprocessSpan, *)
491-
#endif
492515
public func run<Result>(
493516
_ configuration: Configuration,
494517
isolation: isolated (any Actor)? = #isolation,
@@ -511,7 +534,7 @@ public func run<Result>(
511534

512535
// MARK: - Detached
513536

514-
/// Run a executable with given parameters and return its process
537+
/// Run an executable with given parameters and return its process
515538
/// identifier immediately without monitoring the state of the
516539
/// subprocess nor waiting until it exits.
517540
///
@@ -528,9 +551,6 @@ public func run<Result>(
528551
/// - output: A file descriptor to bind to the subprocess' standard output.
529552
/// - error: A file descriptor to bind to the subprocess' standard error.
530553
/// - Returns: the process identifier for the subprocess.
531-
#if SubprocessSpan
532-
@available(SubprocessSpan, *)
533-
#endif
534554
public func runDetached(
535555
_ executable: Executable,
536556
arguments: Arguments = [],
@@ -551,7 +571,7 @@ public func runDetached(
551571
return try runDetached(config, input: input, output: output, error: error)
552572
}
553573

554-
/// Run a executable with given configuration and return its process
574+
/// Run an executable with given configuration and return its process
555575
/// identifier immediately without monitoring the state of the
556576
/// subprocess nor waiting until it exits.
557577
///
@@ -564,9 +584,6 @@ public func runDetached(
564584
/// - output: A file descriptor to bind to the subprocess' standard output.
565585
/// - error: A file descriptor to bind to the subprocess' standard error.
566586
/// - Returns: the process identifier for the subprocess.
567-
#if SubprocessSpan
568-
@available(SubprocessSpan, *)
569-
#endif
570587
public func runDetached(
571588
_ configuration: Configuration,
572589
input: FileDescriptor? = nil,

0 commit comments

Comments
 (0)