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
Process
supporting Swift Concurrency and streamed output fromstdout
andstderr
.Requirements
macOS 10.15+
Installation
Add Coquille to your project using Xcode (File > Add Packages…) or by adding it to your project’s
Package.swift
file:Usage
Coquille exposes its own
Process
class which you can interact with to execute commands.Process.run()
is anasync
function so you can justawait
the exit code:I/O
By default
Process
does not pipe any output from the spawned process tostdout
andstderr
. This can be configured withprintStdout
andprintStderr
:You can also pass an
OutputHandler
for 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
await
the exit status. However if you want to support cancellation you can use the otherrun()
function:This immediately returns an opaque
ProcessCancellationHandle
type which you can callcancel()
on, should you wish to cancel execution, and the process status is delivered through acompletionHandler
closure.Acknowledgements
Thanks to Ben Chatelain for their blog post on intercepting stdout, used to implement some of the tests in the test suite.