diff --git a/AblyChat.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AblyChat.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9cffb1e..74c3fc8 100644 --- a/AblyChat.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/AblyChat.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "fcc346d6fe86e610ac200cdbbf91c56204df67286546d5079bd9c610ee65953b", + "originHash" : "6a8d15fb1d326ac6e8a40c286c152332146d6f58c73123cb8083f68d483dd728", "pins" : [ { "identity" : "ably-cocoa", "kind" : "remoteSourceControl", "location" : "https://github.com/ably/ably-cocoa", "state" : { - "revision" : "7f639c609e50053abd4590f34333f9472645558a", - "version" : "1.2.33" + "branch" : "main", + "revision" : "ccca241a8a7f08b22a93802161460c843d9b5bf3" } }, { diff --git a/Example/AblyChatExample/Mocks/MockRealtime.swift b/Example/AblyChatExample/Mocks/MockRealtime.swift index 067e8f6..e74923a 100644 --- a/Example/AblyChatExample/Mocks/MockRealtime.swift +++ b/Example/AblyChatExample/Mocks/MockRealtime.swift @@ -44,6 +44,10 @@ final class MockRealtime: NSObject, RealtimeClientProtocol, Sendable { fatalError("Not implemented") } + var properties: ARTChannelProperties { + fatalError("Not implemented") + } + func attach() { fatalError("Not implemented") } @@ -211,4 +215,8 @@ final class MockRealtime: NSObject, RealtimeClientProtocol, Sendable { func close() { fatalError("Not implemented") } + + func request(_: String, path _: String, params _: [String: String]?, body _: Any?, headers _: [String: String]?, callback _: @escaping ARTHTTPPaginatedCallback) throws { + fatalError("Not implemented") + } } diff --git a/Package.resolved b/Package.resolved index 9cffb1e..03ddbb8 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "fcc346d6fe86e610ac200cdbbf91c56204df67286546d5079bd9c610ee65953b", + "originHash" : "db24f2979451a46f504f45d35893eb8501f27488ae70e1412340139a0e7551e2", "pins" : [ { "identity" : "ably-cocoa", "kind" : "remoteSourceControl", "location" : "https://github.com/ably/ably-cocoa", "state" : { - "revision" : "7f639c609e50053abd4590f34333f9472645558a", - "version" : "1.2.33" + "branch" : "main", + "revision" : "ccca241a8a7f08b22a93802161460c843d9b5bf3" } }, { diff --git a/Package.swift b/Package.swift index fc233cd..14f5e28 100644 --- a/Package.swift +++ b/Package.swift @@ -20,7 +20,8 @@ let package = Package( dependencies: [ .package( url: "https://github.com/ably/ably-cocoa", - from: "1.2.0" + // TODO: Switch back to using a tag (https://github.com/ably-labs/ably-chat-swift/issues/80) + branch: "main" ), .package( url: "https://github.com/apple/swift-argument-parser", diff --git a/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift b/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift index b193a9f..ae17fde 100644 --- a/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift +++ b/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift @@ -1,10 +1,7 @@ import Ably -// TODO: remove "@unchecked Sendable" once https://github.com/ably/ably-cocoa/issues/1962 done +extension ARTRealtime: RealtimeClientProtocol {} -// This @retroactive is needed to silence the Swift 6 compiler error "extension declares a conformance of imported type 'ARTRealtimeChannels' to imported protocol 'Sendable'; this will not behave correctly if the owners of 'Ably' introduce this conformance in the future (…) add '@retroactive' to silence this warning". I don’t fully understand the implications of this but don’t really mind since both libraries are in our control. -extension ARTRealtime: RealtimeClientProtocol, @retroactive @unchecked Sendable {} +extension ARTRealtimeChannels: RealtimeChannelsProtocol {} -extension ARTRealtimeChannels: RealtimeChannelsProtocol, @retroactive @unchecked Sendable {} - -extension ARTRealtimeChannel: RealtimeChannelProtocol, @retroactive @unchecked Sendable {} +extension ARTRealtimeChannel: RealtimeChannelProtocol {} diff --git a/Sources/BuildTool/BuildTool.swift b/Sources/BuildTool/BuildTool.swift index 1a5bd27..5c451a1 100644 --- a/Sources/BuildTool/BuildTool.swift +++ b/Sources/BuildTool/BuildTool.swift @@ -96,6 +96,7 @@ struct Lint: AsyncParsableCommand { enum Error: Swift.Error { case malformedSwiftVersionFile case malformedPackageManifestFile + case malformedPackageLockfile case mismatchedVersions(swiftVersionFileVersion: String, packageManifestFileVersion: String) case packageLockfilesHaveDifferentContents(paths: [String]) } @@ -152,12 +153,14 @@ struct Lint: AsyncParsableCommand { } /// Checks that the SPM-managed Package.resolved matches the Xcode-managed one. (I still don’t fully understand _why_ there are two files). + /// + /// Ignores the `originHash` property of the Package.resolved file, because this property seems to frequently be different between the SPM version and the Xcode version, and I don’t know enough about SPM to know what this property means or whether there’s a reproducible way to get them to match. func comparePackageLockfiles() async throws { let lockfilePaths = ["Package.resolved", "AblyChat.xcworkspace/xcshareddata/swiftpm/Package.resolved"] - let lockfileContents = try await withThrowingTaskGroup(of: String.self) { group in + let lockfileContents = try await withThrowingTaskGroup(of: Data.self) { group in for lockfilePath in lockfilePaths { group.addTask { - try await loadUTF8StringFromFile(at: lockfilePath) + try await loadDataFromFile(at: lockfilePath) } } @@ -166,13 +169,30 @@ struct Lint: AsyncParsableCommand { } } - if Set(lockfileContents).count > 1 { + // Remove the `originHash` property from the Package.resolved contents before comparing (for reasons described above). + let lockfileContentsWeCareAbout = try lockfileContents.map { data in + guard var dictionary = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { + throw Error.malformedPackageLockfile + } + + dictionary.removeValue(forKey: "originHash") + + // We use .sortedKeys to get a canonical JSON encoding for comparison. + return try JSONSerialization.data(withJSONObject: dictionary, options: .sortedKeys) + } + + if Set(lockfileContentsWeCareAbout).count > 1 { throw Error.packageLockfilesHaveDifferentContents(paths: lockfilePaths) } } - private func loadUTF8StringFromFile(at path: String) async throws -> String { + private func loadDataFromFile(at path: String) async throws -> Data { let (data, _) = try await URLSession.shared.data(from: .init(filePath: path)) + return data + } + + private func loadUTF8StringFromFile(at path: String) async throws -> String { + let data = try await loadDataFromFile(at: path) return try String(data: data, encoding: .utf8) } } diff --git a/Tests/AblyChatTests/Mocks/MockRealtime.swift b/Tests/AblyChatTests/Mocks/MockRealtime.swift index e8c8277..6d0309d 100644 --- a/Tests/AblyChatTests/Mocks/MockRealtime.swift +++ b/Tests/AblyChatTests/Mocks/MockRealtime.swift @@ -62,4 +62,8 @@ final class MockRealtime: NSObject, RealtimeClientProtocol, Sendable { func close() { fatalError("Not implemented") } + + func request(_: String, path _: String, params _: [String: String]?, body _: Any?, headers _: [String: String]?, callback _: @escaping ARTHTTPPaginatedCallback) throws { + fatalError("Not implemented") + } } diff --git a/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift b/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift index f01f70b..5d556ae 100644 --- a/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift +++ b/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift @@ -54,6 +54,10 @@ final class MockRealtimeChannel: NSObject, RealtimeChannelProtocol { fatalError("Not implemented") } + var properties: ARTChannelProperties { + fatalError("Not implemented") + } + func attach() { fatalError("Not implemented") }