Coquille exposes its own Process class which you can interact with to execute commands. Process.run() is an async function so you can just await the exit code:
import Coquille
let process = Process(commandString: "pwd"))
_ = try await process.run() // Prints `pwd` to `stdout`
// Use `command:` for more easily working with variable command-line arguments
let deps = ["numpy", "torch"]
let process = Process(command: .init("python3", arguments: ["-m", "pip", "install"] + deps)))
_ = try await process.run()
I/O
By default Process does not pipe any output from the spawned process to stdout and stderr. This can be configured with printStdout and printStderr:
import Coquille
let process = Process(commandString: "brew install wget", printStdout: true))
_ = try await process.run() // Pipes standard output to `stdout` but will not pipe error output to `stderr`
You can also pass an OutputHandler for both stdout and stderr which will stream contents from both:
import Coquille
let process = Process(
commandString: "swift build",
stdout: { stdout in
...
},
stderr: { stderr in
...
})
_ = try await process.run() // Streams standard and error output to the handlers provided to `stdout:` and `stderr:`
Exit Codes
// `isSuccess` can be used to test the exit code for success
let hasRuby = (try await Process(commandString: "which ruby").run()).isSuccess
// Use `errorCode` to get a nonzero exit code
if let errorCode = (try await Process(commandString: "swift build").run()).errorCode {
switch errorCode {
case 127:
// Command not found
default:
...
}
}
Cancellation
The main Process.run() function signature is:
public func run() async throws -> Status
which allows you use Swift Concurrency to execute the subprocess and await the exit status. However if you want to support cancellation you can use the other run() function:
public func run(with completionHandler: @escaping ((Status) -> Void)) -> ProcessCancellationHandle
This immediately returns an opaque ProcessCancellationHandle type which you can call cancel() on, should you wish to cancel execution, and the process status is delivered through a completionHandler closure.
Acknowledgements
Thanks to Ben Chatelain for their blog post on intercepting stdout, used
to implement some of the tests in the test suite.
🐚 Coquille
A simple Swift wrapper around
Processsupporting Swift Concurrency and streamed output fromstdoutandstderr.Requirements
macOS 10.15+
Installation
Add Coquille to your project using Xcode (File > Add Packages…) or by adding it to your project’s
Package.swiftfile:Usage
Coquille exposes its own
Processclass which you can interact with to execute commands.Process.run()is anasyncfunction so you can justawaitthe exit code:I/O
By default
Processdoes not pipe any output from the spawned process tostdoutandstderr. This can be configured withprintStdoutandprintStderr:You can also pass an
OutputHandlerfor both stdout and stderr which will stream contents from both:Exit Codes
Cancellation
The main
Process.run()function signature is:which allows you use Swift Concurrency to execute the subprocess and
awaitthe exit status. However if you want to support cancellation you can use the otherrun()function:This immediately returns an opaque
ProcessCancellationHandletype which you can callcancel()on, should you wish to cancel execution, and the process status is delivered through acompletionHandlerclosure.Acknowledgements
Thanks to Ben Chatelain for their blog post on intercepting stdout, used to implement some of the tests in the test suite.