From ab6780dec12cb8362cc63d7c0104ee9e99354c72 Mon Sep 17 00:00:00 2001 From: Michael Link Date: Mon, 1 Jul 2024 13:55:07 -0700 Subject: [PATCH] Swift 6 updates --- Package.swift | 69 +++++-------------- .../Subprocess/AsyncSequence+Additions.swift | 4 ++ Sources/Subprocess/AsyncStream+Yield.swift | 4 ++ Sources/Subprocess/Input.swift | 5 ++ Sources/Subprocess/Pipe+AsyncBytes.swift | 4 ++ Sources/Subprocess/Shell.swift | 4 ++ Sources/Subprocess/Subprocess.swift | 5 ++ .../SubprocessDependencyBuilder.swift | 4 ++ Sources/SubprocessMocks/MockOutput.swift | 4 ++ Sources/SubprocessMocks/MockProcess.swift | 8 ++- Sources/SubprocessMocks/MockShell.swift | 5 +- Sources/SubprocessMocks/MockSubprocess.swift | 6 +- .../MockSubprocessDependencyBuilder.swift | 10 +-- 13 files changed, 71 insertions(+), 61 deletions(-) diff --git a/Package.swift b/Package.swift index d4fb083..42542a1 100644 --- a/Package.swift +++ b/Package.swift @@ -54,7 +54,8 @@ let package = Package( .target(name: "Subprocess") ] ) - ] + ], + swiftLanguageVersions: [.v5, .version("6")] ) for target in package.targets { @@ -65,60 +66,24 @@ for target in package.targets { // as upcoming features will result in a compiler error. Currently in the // latest 5.10 compiler this doesn't happen, the compiler ignores it. // - // If the situation does change and enabling default language features - // does result in an error in future versions we attempt to guard against - // this by using the hasFeature(x) compiler directive to see if we have a - // feature already, or if we can enable it. It's safe to enable features - // that don't exist in older compiler versions as the compiler will ignore - // features it doesn't have implemented. - - // swift 6 - #if !hasFeature(ConciseMagicFile) - swiftSettings.append(.enableUpcomingFeature("ConciseMagicFile")) - #endif - - #if !hasFeature(ForwardTrailingClosures) - swiftSettings.append(.enableUpcomingFeature("ForwardTrailingClosures")) - #endif - - #if !hasFeature(StrictConcurrency) - swiftSettings.append(.enableUpcomingFeature("StrictConcurrency")) - // StrictConcurrency is under experimental features in Swift <=5.10 contrary to some posts and documentation - swiftSettings.append(.enableExperimentalFeature("StrictConcurrency")) - #endif - - #if !hasFeature(BareSlashRegexLiterals) - swiftSettings.append(.enableUpcomingFeature("BareSlashRegexLiterals")) - #endif - - #if !hasFeature(ImplicitOpenExistentials) - swiftSettings.append(.enableUpcomingFeature("ImplicitOpenExistentials")) - #endif - - #if !hasFeature(ImportObjcForwardDeclarations) - swiftSettings.append(.enableUpcomingFeature("ImportObjcForwardDeclarations")) - #endif - - #if !hasFeature(DisableOutwardActorInference) - swiftSettings.append(.enableUpcomingFeature("DisableOutwardActorInference")) - #endif - - #if !hasFeature(InternalImportsByDefault) - swiftSettings.append(.enableUpcomingFeature("InternalImportsByDefault")) - #endif - - #if !hasFeature(IsolatedDefaultValues) - swiftSettings.append(.enableUpcomingFeature("IsolatedDefaultValues")) - #endif - - #if !hasFeature(GlobalConcurrency) - swiftSettings.append(.enableUpcomingFeature("GlobalConcurrency")) - #endif + // The Swift 6 compiler on the other hand does emit errors when features + // are enabled. Unfortunately it appears that the preprocessor + // !hasFeature(xxx) cannot be used to test for this situation nor does + // #if swift(<6) guard against this. There must be some sort of magic + // used that is special for compiling the Package.swift manifest. + // Instead a versioned Package.swift can be used (e.g. Package@swift-5.10.swift) + // and the implemented now default features can be removed in Package.swift. + // + // Or you can just delete the Swift 6 features that are enabled instead of + // creating another manifest file and test to see if building under Swift 5 + // still works (it should almost always work). + // + // It's still safe to enable features that don't exist in older compiler + // versions as the compiler will ignore features it doesn't have implemented. // swift 7 - #if !hasFeature(ExistentialAny) swiftSettings.append(.enableUpcomingFeature("ExistentialAny")) - #endif + swiftSettings.append(.enableUpcomingFeature("InternalImportsByDefault")) target.swiftSettings = swiftSettings } diff --git a/Sources/Subprocess/AsyncSequence+Additions.swift b/Sources/Subprocess/AsyncSequence+Additions.swift index f39bd85..f236d4a 100644 --- a/Sources/Subprocess/AsyncSequence+Additions.swift +++ b/Sources/Subprocess/AsyncSequence+Additions.swift @@ -25,7 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif extension AsyncSequence { /// Returns a sequence of all the elements. diff --git a/Sources/Subprocess/AsyncStream+Yield.swift b/Sources/Subprocess/AsyncStream+Yield.swift index 383edba..e69b83d 100644 --- a/Sources/Subprocess/AsyncStream+Yield.swift +++ b/Sources/Subprocess/AsyncStream+Yield.swift @@ -25,7 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif extension AsyncStream.Continuation where Element == UInt8 { /// Resume the task awaiting the next iteration point by having it return diff --git a/Sources/Subprocess/Input.swift b/Sources/Subprocess/Input.swift index 1598ae4..340dbbc 100644 --- a/Sources/Subprocess/Input.swift +++ b/Sources/Subprocess/Input.swift @@ -24,7 +24,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // + +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif /// Interface representing input to the process public struct Input { diff --git a/Sources/Subprocess/Pipe+AsyncBytes.swift b/Sources/Subprocess/Pipe+AsyncBytes.swift index 78cebd7..34342fc 100644 --- a/Sources/Subprocess/Pipe+AsyncBytes.swift +++ b/Sources/Subprocess/Pipe+AsyncBytes.swift @@ -25,7 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif // `FileHandle.AsyncBytes` has a bug that can block reading of stdout when also reading stderr. // We can avoid this problem if we create independent handlers. diff --git a/Sources/Subprocess/Shell.swift b/Sources/Subprocess/Shell.swift index ebf8fd0..04eb85b 100644 --- a/Sources/Subprocess/Shell.swift +++ b/Sources/Subprocess/Shell.swift @@ -25,7 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif /// Class used for synchronous process execution @available(*, deprecated, message: "Use Swift Concurrency methods instead which are part of the Subprocess class") diff --git a/Sources/Subprocess/Subprocess.swift b/Sources/Subprocess/Subprocess.swift index 1784157..7060b31 100644 --- a/Sources/Subprocess/Subprocess.swift +++ b/Sources/Subprocess/Subprocess.swift @@ -25,8 +25,13 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +public import Combine +#else import Foundation import Combine +#endif /// Class used for asynchronous process execution public class Subprocess: @unchecked Sendable { diff --git a/Sources/Subprocess/SubprocessDependencyBuilder.swift b/Sources/Subprocess/SubprocessDependencyBuilder.swift index df23179..f924753 100644 --- a/Sources/Subprocess/SubprocessDependencyBuilder.swift +++ b/Sources/Subprocess/SubprocessDependencyBuilder.swift @@ -25,7 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif /// Protocol call used for dependency injection public protocol SubprocessDependencyFactory { diff --git a/Sources/SubprocessMocks/MockOutput.swift b/Sources/SubprocessMocks/MockOutput.swift index 79b911c..aa9bdc0 100644 --- a/Sources/SubprocessMocks/MockOutput.swift +++ b/Sources/SubprocessMocks/MockOutput.swift @@ -25,7 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation +#endif /// A way to supply data to mock methods public protocol MockOutput: Sendable { diff --git a/Sources/SubprocessMocks/MockProcess.swift b/Sources/SubprocessMocks/MockProcess.swift index f524504..22db9e9 100644 --- a/Sources/SubprocessMocks/MockProcess.swift +++ b/Sources/SubprocessMocks/MockProcess.swift @@ -25,10 +25,12 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation -#if !COCOA_PODS -import Subprocess #endif +import Subprocess /// Interface used for mocking a process public struct MockProcess: Sendable { @@ -66,7 +68,7 @@ public struct MockProcess: Sendable { } /// Subclass of `Process` used for mocking -open class MockProcessReference: Process { +open class MockProcessReference: Process, @unchecked Sendable { /// Context information and values used for overriden properties public struct Context { diff --git a/Sources/SubprocessMocks/MockShell.swift b/Sources/SubprocessMocks/MockShell.swift index c716e0b..571fec1 100644 --- a/Sources/SubprocessMocks/MockShell.swift +++ b/Sources/SubprocessMocks/MockShell.swift @@ -25,8 +25,11 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +public import Subprocess +#else import Foundation -#if !COCOA_PODS import Subprocess #endif diff --git a/Sources/SubprocessMocks/MockSubprocess.swift b/Sources/SubprocessMocks/MockSubprocess.swift index 3e32242..f3c989e 100644 --- a/Sources/SubprocessMocks/MockSubprocess.swift +++ b/Sources/SubprocessMocks/MockSubprocess.swift @@ -25,9 +25,13 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +public import Combine +public import Subprocess +#else import Foundation import Combine -#if !COCOA_PODS import Subprocess #endif diff --git a/Sources/SubprocessMocks/MockSubprocessDependencyBuilder.swift b/Sources/SubprocessMocks/MockSubprocessDependencyBuilder.swift index ded6da8..1a61b6a 100644 --- a/Sources/SubprocessMocks/MockSubprocessDependencyBuilder.swift +++ b/Sources/SubprocessMocks/MockSubprocessDependencyBuilder.swift @@ -25,10 +25,12 @@ // SOFTWARE. // +#if swift(>=6.0) +public import Foundation +#else import Foundation -#if !COCOA_PODS -import Subprocess #endif +import Subprocess /// Error representing a failed call to Subprocess.expect or Shell.expect public struct ExpectationError: Error { @@ -66,11 +68,11 @@ public extension SubprocessMockObject { static func reset() { MockSubprocessDependencyBuilder.shared.reset() } } -public class MockFileHandle: FileHandle { +public class MockFileHandle: FileHandle, @unchecked Sendable { public var url: URL? } -public final class MockPipe: Pipe { +public final class MockPipe: Pipe, @unchecked Sendable { private static let queue = DispatchQueue(label: "\(MockPipe.self)") private var _data: Data? public var data: Data? {