From a8d3659b6d01dcaaa4922be52753cd7817361d98 Mon Sep 17 00:00:00 2001 From: Michael Link Date: Wed, 7 Feb 2024 17:36:52 -0600 Subject: [PATCH] CON-4576 minor updats to explicit Sendability --- CHANGELOG.md | 8 ++++++++ Package.swift | 25 +++++++++++++++++++++---- Sources/Subprocess/Subprocess.swift | 10 +++++----- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b22af..2d474d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Package.swift b/Package.swift index f72edb6..3f6fc73 100644 --- a/Package.swift +++ b/Package.swift @@ -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") ], @@ -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 ) ] ) diff --git a/Sources/Subprocess/Subprocess.swift b/Sources/Subprocess/Subprocess.swift index 5ce893f..5ad7489 100644 --- a/Sources/Subprocess/Subprocess.swift +++ b/Sources/Subprocess/Subprocess.swift @@ -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 @@ -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. @@ -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 @@ -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) } @@ -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(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(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)) }