Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CON-4576 minor updats to explicit Sendability #25

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 3.0.2 - 2024-02-07

### Added
- Additional `Sendable` conformance where it can't be implicitly determined outside of this package.

### Removed
- `open` scope from `Subprocess` since none of its members were `open`.

## 3.0.1 - 2023-11-27

### Added
Expand Down
25 changes: 21 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

import PackageDescription

#if swift(<6)
let swiftSettings: [SwiftSetting] = [
.enableUpcomingFeature("StrictConcurrency"),
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("ForwardTrailingClosures"),
.enableUpcomingFeature("ImplicitOpenExistentials"),
.enableUpcomingFeature("BareSlashRegexLiterals"),
.enableUpcomingFeature("ConciseMagicFile"),
]
#else
let swiftSettings: [SwiftSetting] = []
#endif

let package = Package(
name: "Subprocess",
platforms: [ .macOS("10.15.4") ],
Expand Down Expand Up @@ -33,26 +46,30 @@ let package = Package(
targets: [
.target(
name: "Subprocess",
dependencies: []
dependencies: [],
swiftSettings: swiftSettings
),
.target(
name: "SubprocessMocks",
dependencies: [
.target(name: "Subprocess")
]
],
swiftSettings: swiftSettings
),
.testTarget(
name: "UnitTests",
dependencies: [
.target(name: "Subprocess"),
.target(name: "SubprocessMocks")
]
],
swiftSettings: swiftSettings
),
.testTarget(
name: "SystemTests",
dependencies: [
.target(name: "Subprocess")
]
],
swiftSettings: swiftSettings
)
]
)
10 changes: 5 additions & 5 deletions Sources/Subprocess/Subprocess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Foundation
import Combine

/// Class used for asynchronous process execution
open class Subprocess: @unchecked Sendable {
public class Subprocess: @unchecked Sendable {
/// Output options.
public struct OutputOptions: OptionSet {
public let rawValue: Int
Expand Down Expand Up @@ -240,7 +240,7 @@ open class Subprocess: @unchecked Sendable {
// Methods for typical one-off acquisition of output from running some command.
extension Subprocess {
/// Additional configuration options.
public struct RunOptions: OptionSet {
public struct RunOptions: OptionSet, Sendable {
public let rawValue: Int

/// Throw an error if the process exited with a non-zero exit code.
Expand All @@ -259,7 +259,7 @@ extension Subprocess {
/// - command: An external command to run with optional arguments.
/// - standardInput: A type conforming to `DataProtocol` (typically a `Data` type) from which to read input to the external command.
/// - options: Options used to specify runtime behavior.
public static func data(for command: [String], standardInput: (any DataProtocol)? = nil, options: RunOptions = .throwErrorOnNonZeroExit) async throws -> Data {
public static func data(for command: [String], standardInput: (any DataProtocol & Sendable)? = nil, options: RunOptions = .throwErrorOnNonZeroExit) async throws -> Data {
let subprocess = Self(command)
let (standardOutput, standardError, waitForExit) = if let standardInput {
try subprocess.run(standardInput: AsyncStream(UInt8.self, { continuation in
Expand Down Expand Up @@ -422,7 +422,7 @@ extension Subprocess {
/// - standardInput: A type conforming to `DataProtocol` (typically a `Data` type) from which to read input to the external command.
/// - options: Options used to specify runtime behavior.
@inlinable
public static func string(for command: [String], standardInput: (any DataProtocol)? = nil, options: RunOptions = .throwErrorOnNonZeroExit) async throws -> String {
public static func string(for command: [String], standardInput: (any DataProtocol & Sendable)? = nil, options: RunOptions = .throwErrorOnNonZeroExit) async throws -> String {
String(decoding: try await data(for: command, standardInput: standardInput, options: options), as: UTF8.self)
}

Expand Down Expand Up @@ -455,7 +455,7 @@ extension Subprocess {
/// - options: Options used to specify runtime behavior.
/// - decoder: A `TopLevelDecoder` that will be used to decode the data.
@inlinable
public static func value<Content, Decoder>(for command: [String], standardInput: (any DataProtocol)? = nil, options: RunOptions = .throwErrorOnNonZeroExit, decoder: Decoder) async throws -> Content where Content : Decodable, Decoder : TopLevelDecoder, Decoder.Input == Data {
public static func value<Content, Decoder>(for command: [String], standardInput: (any DataProtocol & Sendable)? = nil, options: RunOptions = .throwErrorOnNonZeroExit, decoder: Decoder) async throws -> Content where Content : Decodable, Decoder : TopLevelDecoder, Decoder.Input == Data {
try await decoder.decode(Content.self, from: data(for: command, standardInput: standardInput, options: options))
}

Expand Down
Loading