Releases: swiftlang/swift-subprocess
Subprocess 0.4
Important
Subprocess 0.4 is the last planned release that supports Swift 6.1. We will remove 6.1 support in the next release. Please pin your dependency to 0.4 if you are still using Swift 6.1.
This release includes many important bug fixes and ships with several API changes:
API Changes
Error Overhaul (#220)
SubprocessError has been redesigned. Now you can compare SubprocessError.Code with a list of static values to check the failure reason. We also streamlined error throwing by ensuring Subprocess itself only throws SubprocessError while still allowing clients to throw any error in execution closures. With this redesign, we have the following recommendations on how to handle errors with Subprocess:
do {
let result = try await run(
.path(...),
) { execution, standardOutput in
throw MyError()
...
throw MyOtherError()
}
} catch let subprocessError as SubprocessError {
// Handle errors thrown by Subprocess itself
// These errors usualy indicate something's wrong
// with the environment or there's a bug in Subprocess itself
switch subprocessError.code {
case .spawnFailed:
...
case .executableNotFound:
...
}
} catch let myError as MyError {
// Handle custom errors from the execution closure.
} catch let myOtherError as MyOtherError {
// Handle custom errors from the execution closure.
}Rename ExecutionResult and CollectedResult (#225)
ExecutionResult has been renamed to ExecutionOutcome and CollectedResult has been renamed to ExecutionRecord. The new names avoid confusion with Swift's Result type.
Deprecated type aliases for ExecutionResult and CollectedResult are provided to ease the transition. These aliases will be removed in the 1.0 release.
Update TerminationStatus for Windows (#229)
TerminationStatus has been updated on Windows to remove the .unhandledException case, which is a Unix-specific concept. Windows now uses only .exited, reflecting how Windows handles exit codes. On Unix, .unhandledException has been renamed to .signaled, as "exception" is not a standard Unix term.
Important Bug Fixes
Fix Compiler Warnings and Documentation (#224 #229)
All compiler warnings have been resolved, and documentation has been updated for correctness and clarity.
Update Windows Named Pipes with Unique Names (#230)
Fixed an issue on Windows where the named pipes used to communicate with child processes were not uniquely named, which could cause concurrently running Subprocess instances to crash.
Detailed Change Log
- Subprocess error overhaul by @iCharlesHu in #220
- Add nullability specifier to pthread_t pointer in process_shims.h by @rnapier in #221
- Fix compiler warnings on all platforms by @iCharlesHu in #224
- Rename ExecutionResult to ExecutionOutcome; rename CollectedResult to ExecutionRecord by @iCharlesHu in #225
- Ensure Windows named pipes have unique names across processes. by @iCharlesHu in #230
- Update documentation and TerminationStatus to match the 1.0 proposal by @iCharlesHu in #229
New Contributors
Full Changelog: 0.3...0.4
Subprocess 0.3
This release includes many important bug fixes. In particular:
#211 fixes an issue that causes swiftly to arbitrarily select swift executables in PATH.
What's Changed
- Set interface include directory for the subprocess target by @owenv in #201
- Fix
Environment.updatingforcustomandrawBytesby @a7medev in #199 - Enable Android CI by @jakepetroules in #202
- Fix Android builds with NDK r28 and later by @jakepetroules in #203
- Fix the compiler version check for Span availability by @cmcgee1024 in #204
- Retroactively conform DispatchData to Sendable when building with older macOS SDKs in Swift CI by @owenv in #205
- Adapt to swiftlang/github-workflows changes by @jakepetroules in #208
- chore: restrict GitHub workflow permissions - future-proof by @incertum in #197
- Revert the compiler version check for the span default trait by @cmcgee1024 in #209
- Keep order of paths fixed by @SimplyDanny in #211
- Move
CODEOWNERSto.github/CODEOWNERSby @ahoppen in #216 - Update GitHub Workflow to use soundness.yml for Format Checking by @iCharlesHu in #219
- Add ENOTDIR as an acceptable spawn error by @iCharlesHu in #218
- Remove duplicate include by @AZero13 in #214
New Contributors
- @a7medev made their first contribution in #199
- @incertum made their first contribution in #197
- @SimplyDanny made their first contribution in #211
- @ahoppen made their first contribution in #216
- @AZero13 made their first contribution in #214
Full Changelog: 0.2...0.3
Subprocess 0.2.1
This is a minor release that fixes two issues:
- #201 Set interface include directory for the subprocess target
- #199 Fix
Environment.updatingfor custom andrawBytes
New Contributors
Full Changelog: 0.2...0.2.1
Subprocess 0.2
This release introduces two API changes and several important bug fixes.
API Changes
Introduced CombinedErrorOutput
A new output type for subprocesses that merges the standard error stream with the standard output stream.
When CombinedErrorOutput is used as the error output for a subprocess, both the standard output and standard error from the child process are combined into a single output stream. This is equivalent to using shell redirection such as 2>&1.
Updated Environment.updating to Accept [Key: String?]
This change allows an environment variable to be unset by assigning it a value of nil.
Important Bug Fixes
- #196 Fixed CMake support. Subprocess can now be used as a dependent project in CMake builds.
- #198 Fixed a hanging issue that occurs in release builds.
Detailed Change Log
- Fix incorrect documentation in Buffer.swift withUnsafeBytes method by @valeriyvan in #178
- Report proper error by @valeriyvan in #177
- Fix some typos by @valeriyvan in #181
- Introudce CombinedErrorOutput by @iCharlesHu in #180
- Fix dependency of Swift System by @0xTim in #187
- Change Environment.updating to accept [Key: String?] by @iCharlesHu in #193
- Add extern "C" to header process_shims.h by @j-hui in #195
- CMake fixes to allow use in dependent projects by @owenv in #196
- Don't suspend/resume the thread while holding an exclusive inout reference by @jakepetroules in #198
New Contributors
- @valeriyvan made their first contribution in #178
- @0xTim made their first contribution in #187
- @j-hui made their first contribution in #195
- @owenv made their first contribution in #196
Full Changelog: 0.1...0.2
Subprocess 0.1
This is the initial release of swift-subprocess.
API Changes Since Initial Proposal
-
Introduce
preferredBufferSizeparameter to allow custom buffer size when streaming subprocess output (#168)A new
preferredBufferSizeparameter was added to the streaming APIs, allowing developers to control the buffer size when reading subprocess output instead of relying on a fixed default.
public func run<Result, Input: InputProtocol, Error: OutputProtocol>(
_ executable: Executable,
arguments: Arguments = [],
environment: Environment = .inherit,
workingDirectory: FilePath? = nil,
platformOptions: PlatformOptions = PlatformOptions(),
input: Input = .none,
error: Error = .discarded,
preferredBufferSize: Int? = nil, // New API
isolation: isolated (any Actor)? = #isolation,
body: ((Execution, AsyncBufferSequence) async throws -> Result)
) async throws -> ExecutionResult<Result> where Error.OutputType == Void-
Expand API with
Configuration-basedrun()overloads (#164)Added new
run()overloads that allow subprocesses to be launched using aConfiguration, bringing parity with APIs that take individual parameters.
// New Configuration-based APIs
public func run<
InputElement: BitwiseCopyable,
Output: OutputProtocol,
Error: OutputProtocol
>(
_ configuration: Configuration,
input: borrowing Span<InputElement>,
output: Output,
error: Error = .discarded
) async throws -> CollectedResult<Output, Error>
public func run<Result, Input: InputProtocol, Output: OutputProtocol, Error: OutputProtocol>(
_ configuration: Configuration,
input: Input = .none,
output: Output = .discarded,
error: Error = .discarded,
isolation: isolated (any Actor)? = #isolation,
body: ((Execution) async throws -> Result)
) async throws -> ExecutionResult<Result> where Error.OutputType == Void
public func run<Result, Input: InputProtocol, Error: OutputProtocol>(
_ configuration: Configuration,
input: Input = .none,
error: Error = .discarded,
isolation: isolated (any Actor)? = #isolation,
body: ((Execution, AsyncBufferSequence) async throws -> Result)
) async throws -> ExecutionResult<Result> where Error.OutputType == Void
public func run<Result, Input: InputProtocol, Output: OutputProtocol>(
_ configuration: Configuration,
input: Input = .none,
output: Output,
isolation: isolated (any Actor)? = #isolation,
body: ((Execution, AsyncBufferSequence) async throws -> Result)
) async throws -> ExecutionResult<Result> where Output.OutputType == Void
public func run<Result, Error: OutputProtocol>(
_ configuration: Configuration,
error: Error = .discarded,
isolation: isolated (any Actor)? = #isolation,
body: ((Execution, StandardInputWriter, AsyncBufferSequence) async throws -> Result)
) async throws -> ExecutionResult<Result> where Error.OutputType == Void
public func run<Result, Output: OutputProtocol>(
_ configuration: Configuration,
output: Output,
isolation: isolated (any Actor)? = #isolation,
body: ((Execution, StandardInputWriter, AsyncBufferSequence) async throws -> Result)
) async throws -> ExecutionResult<Result> where Output.OutputType == Void-
Remove
preSpawnProcessConfiguratoron LinuxThis property has been removed due to async-signal-safety concerns. It is not possible to offer a safe implementation of this API.
-
Remove the default collected output buffer limit and throw an error when the limit is reached (#130)
The default output buffer has been removed. All run() methods now require developers to explicitly specify the output type and buffer limit. If the limit is reached, an error will be thrown. This change ensures developers choose buffer sizes that best fit their use case.
@@ -9,6 +9,6 @@ public func run<
workingDirectory: FilePath? = nil,
platformOptions: PlatformOptions = PlatformOptions(),
input: Input = .none,
- output: Output = .string,
+ output: Output,
error: Error = .discarded
) async throws -> CollectedResult<Output, Error>-
Expose platform-specific process file descriptors (#101)
Linux, FreeBSD, and Windows now expose their respective process descriptors (
pidfdon Linux and FreeBSD,HANDLEon Windows). These allow integration with system APIs that require descriptors rather than raw process IDs.
@@ -2,7 +2,7 @@
public struct ProcessIdentifier: Sendable, Hashable {
/// The platform-specific process identifier value
public let value: pid_t
- internal let processDescriptor: PlatformFileDescriptor
+ public let processDescriptor: PlatformFileDescriptor
}
#endif
@@ -10,7 +10,7 @@ public struct ProcessIdentifier: Sendable, Hashable {
public struct ProcessIdentifier: Sendable, Hashable {
/// Windows-specific process identifier value
public let value: DWORD
- internal nonisolated(unsafe) let processDescriptor: HANDLE
- internal nonisolated(unsafe) let threadHandle: HANDLE
+ public nonisolated(unsafe) let processDescriptor: HANDLE
+ public nonisolated(unsafe) let threadHandle: HANDLE
}
#endif-
Remove runDetached API (#95)
runDetachedwas originally proposed as the synchronous counterpart torun(). However, sinceposix_spawncan block, this API could not be implemented synchronously. It has therefore been removed. -
Make
Configuration.workingDirectoryoptional (#74)Configuration.workingDirectoryis now optional. Anilvalue means the subprocess will inherit the parent process’s working directory.
@@ -2,6 +2,6 @@ public struct Configuration: Sendable {
public var executable: Executable
public var arguments: Arguments
public var environment: Environment
- public var workingDirectory: FilePath
+ public var workingDirectory: FilePath?
public var platformOptions: PlatformOptions
}-
AsyncBufferSequence.BufferImprovements (#48)Introduced
AsyncBufferSequence.LineSequenceas the preferred way to stream output as text. This converts the rawBuffersequence into an asynchronous sequence of lines.
extension AsyncBufferSequence {
public struct LineSequence<Encoding: _UnicodeEncoding>: AsyncSequence, Sendable {
public typealias Element = String
public enum BufferingPolicy: Sendable {
case unbounded
case maxLineLength(Int)
}
public struct AsyncIterator: AsyncIteratorProtocol {
public mutating func next() async throws -> String?
}
public func makeAsyncIterator() -> AsyncIterator
}
public func lines() -> LineSequence<UTF8>
public func lines<Encoding: _UnicodeEncoding>(
encoding: Encoding.Type,
bufferingPolicy: LineSequence<Encoding>.BufferingPolicy = .maxLineLength(128 * 1024)
) -> LineSequence<Encoding>
}-
Make Environment keys case-insensitive on Windows (#174)
Introduced
Environment.Keyto provide a platform-aware way of accessing environment variables. Keys are now case-insensitive on Windows, while retaining case sensitivity on platforms where that is the convention.
public struct Key: ExpressibleByStringLiteral, Codable, Hashable, RawRepresentable, CustomStringConvertible, Sendable{
public var rawValue: String
public init(stringLiteral rawValue: String)
}