From 896d03ce0b426298fdb4c71403eeba89e3e2737b Mon Sep 17 00:00:00 2001 From: Fedor Korotkov Date: Thu, 11 Apr 2024 17:53:10 +0200 Subject: [PATCH] Fixed Swift Warning (#787) * Fixed Swift Warning Plus updated all the dependencies and Swift Tools. Fixes #785 * Fixed race condition --- .cirrus.yml | 2 +- Package.resolved | 40 ++++++++++++------- Package.swift | 20 +++++----- Sources/tart/Commands/Suspend.swift | 2 +- .../KeychainCredentialsProvider.swift | 2 +- Sources/tart/Network/Network.swift | 3 +- Sources/tart/Network/NetworkBridged.swift | 3 +- Sources/tart/Network/NetworkShared.swift | 3 +- Sources/tart/Network/Softnet.swift | 7 ++-- Sources/tart/OCI/Layerizer/DiskV2.swift | 2 +- Sources/tart/OCI/Registry.swift | 8 ++-- Sources/tart/VM.swift | 11 ++--- Tests/TartTests/TokenResponseTests.swift | 6 ++- 13 files changed, 60 insertions(+), 49 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 617140b..e28499a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ use_compute_credits: true env: - XCODE_TAG: 15.2 + XCODE_TAG: latest task: name: Test on Sonoma diff --git a/Package.resolved b/Package.resolved index 66e0a3a..8ac986e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "b6263fb821fd8d1b501b388d41e163542fe1aa79613c2842b2495eb23f3424f3", "pins" : [ { "identity" : "antlr4", @@ -18,13 +19,22 @@ "revision" : "772883073d044bc754d401cabb6574624eb3778f" } }, + { + "identity" : "semaphore", + "kind" : "remoteSourceControl", + "location" : "https://github.com/groue/Semaphore", + "state" : { + "revision" : "f1c4a0acabeb591068dea6cffdd39660b86dec28", + "version" : "0.0.8" + } + }, { "identity" : "sentry-cocoa", "kind" : "remoteSourceControl", "location" : "https://github.com/getsentry/sentry-cocoa", "state" : { - "revision" : "bf7bdd75e25556d0f97ad54fb804b4287863e106", - "version" : "8.22.4" + "revision" : "ef4fec9dfb8dd5027b09a4a5c9362feafd118e1a", + "version" : "8.24.0" } }, { @@ -32,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-algorithms", "state" : { - "revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e", - "version" : "1.0.0" + "revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42", + "version" : "1.2.0" } }, { @@ -41,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { - "revision" : "f3c9084a71ef4376f2fabbdf1d3d90a49f1fabdb", - "version" : "1.1.2" + "revision" : "46989693916f56d1186bd59ac15124caef896560", + "version" : "1.3.1" } }, { @@ -59,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-atomics.git", "state" : { - "revision" : "919eb1d83e02121cdb434c7bfc1f0c66ef17febe", - "version" : "1.0.2" + "revision" : "cd142fd2f64be2100422d658e7411e39489da985", + "version" : "1.2.0" } }, { @@ -86,8 +96,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/sersoft-gmbh/swift-sysctl.git", "state" : { - "revision" : "71fd64ee84819bb19fbecfb36d5a4503726b6fb7", - "version" : "1.6.0" + "revision" : "a91be36de6803ebe48f678699dfd0694c2200d2f", + "version" : "1.8.0" } }, { @@ -95,8 +105,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/malcommac/SwiftDate", "state" : { - "revision" : "6190d0cefff3013e77ed567e6b074f324e5c5bf5", - "version" : "6.3.1" + "revision" : "5d943224c3bb173e6ecf27295611615eba90c80e", + "version" : "7.0.0" } }, { @@ -104,8 +114,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/nicklockwood/SwiftFormat", "state" : { - "revision" : "da637c398c5d08896521b737f2868ddc2e7996ae", - "version" : "0.50.6" + "revision" : "9df3b01f477163b33d5e63c5e2e5b9f946a49c56", + "version" : "0.53.6" } }, { @@ -127,5 +137,5 @@ } } ], - "version" : 2 + "version" : 3 } diff --git a/Package.swift b/Package.swift index fad1d18..9ce8271 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.7 +// swift-tools-version:5.10 import PackageDescription let package = Package( @@ -10,18 +10,19 @@ let package = Package( .executable(name: "tart", targets: ["tart"]) ], dependencies: [ - .package(url: "https://github.com/apple/swift-argument-parser", from: "1.1.2"), + .package(url: "https://github.com/apple/swift-argument-parser", from: "1.3.1"), .package(url: "https://github.com/mhdhejazi/Dynamic", branch: "master"), - .package(url: "https://github.com/apple/swift-algorithms", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"), .package(url: "https://github.com/apple/swift-async-algorithms", branch: "main"), - .package(url: "https://github.com/malcommac/SwiftDate", from: "6.3.1"), + .package(url: "https://github.com/malcommac/SwiftDate", from: "7.0.0"), .package(url: "https://github.com/antlr/antlr4", branch: "dev"), - .package(url: "https://github.com/apple/swift-atomics.git", .upToNextMajor(from: "1.0.0")), - .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.50.6"), - .package(url: "https://github.com/getsentry/sentry-cocoa", from: "8.22.4"), + .package(url: "https://github.com/apple/swift-atomics.git", .upToNextMajor(from: "1.2.0")), + .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.53.6"), + .package(url: "https://github.com/getsentry/sentry-cocoa", from: "8.24.0"), .package(url: "https://github.com/cfilipov/TextTable", branch: "master"), - .package(url: "https://github.com/sersoft-gmbh/swift-sysctl.git", from: "1.0.0"), - .package(url: "https://github.com/orchetect/SwiftRadix", from: "1.3.0") + .package(url: "https://github.com/sersoft-gmbh/swift-sysctl.git", from: "1.8.0"), + .package(url: "https://github.com/orchetect/SwiftRadix", from: "1.3.1"), + .package(url: "https://github.com/groue/Semaphore", from: "0.0.8") ], targets: [ .executableTarget(name: "tart", dependencies: [ @@ -36,6 +37,7 @@ let package = Package( .product(name: "TextTable", package: "TextTable"), .product(name: "Sysctl", package: "swift-sysctl"), .product(name: "SwiftRadix", package: "SwiftRadix"), + .product(name: "Semaphore", package: "Semaphore"), ], exclude: [ "OCI/Reference/Makefile", "OCI/Reference/Reference.g4", diff --git a/Sources/tart/Commands/Suspend.swift b/Sources/tart/Commands/Suspend.swift index b38fc3b..8da9e96 100644 --- a/Sources/tart/Commands/Suspend.swift +++ b/Sources/tart/Commands/Suspend.swift @@ -14,7 +14,7 @@ struct Suspend: AsyncParsableCommand { let lock = try vmDir.lock() // Find the VM's PID - var pid = try lock.pid() + let pid = try lock.pid() if pid == 0 { throw RuntimeError.VMNotRunning("VM \"\(name)\" is not running") } diff --git a/Sources/tart/Credentials/KeychainCredentialsProvider.swift b/Sources/tart/Credentials/KeychainCredentialsProvider.swift index 6705c6e..be9d272 100644 --- a/Sources/tart/Credentials/KeychainCredentialsProvider.swift +++ b/Sources/tart/Credentials/KeychainCredentialsProvider.swift @@ -41,7 +41,7 @@ class KeychainCredentialsProvider: CredentialsProvider { kSecAttrLabel as String: "Tart Credentials", ] let value: [String: Any] = [kSecAttrAccount as String: user, - kSecValueData as String: passwordData, + kSecValueData as String: passwordData as Any, ] let status = SecItemCopyMatching(key as CFDictionary, nil) diff --git a/Sources/tart/Network/Network.swift b/Sources/tart/Network/Network.swift index 7df6c33..b92a35b 100644 --- a/Sources/tart/Network/Network.swift +++ b/Sources/tart/Network/Network.swift @@ -1,7 +1,8 @@ import Virtualization +import Semaphore protocol Network { func attachments() -> [VZNetworkDeviceAttachment] - func run(_ sema: DispatchSemaphore) throws + func run(_ sema: AsyncSemaphore) throws func stop() async throws } diff --git a/Sources/tart/Network/NetworkBridged.swift b/Sources/tart/Network/NetworkBridged.swift index 2fbd4df..e879c20 100644 --- a/Sources/tart/Network/NetworkBridged.swift +++ b/Sources/tart/Network/NetworkBridged.swift @@ -1,4 +1,5 @@ import Foundation +import Semaphore import Virtualization class NetworkBridged: Network { @@ -12,7 +13,7 @@ class NetworkBridged: Network { interfaces.map { VZBridgedNetworkDeviceAttachment(interface: $0) } } - func run(_ sema: DispatchSemaphore) throws { + func run(_ sema: AsyncSemaphore) throws { // no-op, only used for Softnet } diff --git a/Sources/tart/Network/NetworkShared.swift b/Sources/tart/Network/NetworkShared.swift index c58cc41..24208c2 100644 --- a/Sources/tart/Network/NetworkShared.swift +++ b/Sources/tart/Network/NetworkShared.swift @@ -1,4 +1,5 @@ import Foundation +import Semaphore import Virtualization class NetworkShared: Network { @@ -6,7 +7,7 @@ class NetworkShared: Network { [VZNATNetworkDeviceAttachment()] } - func run(_ sema: DispatchSemaphore) throws { + func run(_ sema: AsyncSemaphore) throws { // no-op, only used for Softnet } diff --git a/Sources/tart/Network/Softnet.swift b/Sources/tart/Network/Softnet.swift index 8b288dd..dda828a 100644 --- a/Sources/tart/Network/Softnet.swift +++ b/Sources/tart/Network/Softnet.swift @@ -1,7 +1,8 @@ -import Foundation -import Virtualization import Atomics +import Foundation +import Semaphore import System +import Virtualization enum SoftnetError: Error { case InitializationFailed(why: String) @@ -44,7 +45,7 @@ class Softnet: Network { return executableURL } - func run(_ sema: DispatchSemaphore) throws { + func run(_ sema: AsyncSemaphore) throws { try process.run() monitorTask = Task { diff --git a/Sources/tart/OCI/Layerizer/DiskV2.swift b/Sources/tart/OCI/Layerizer/DiskV2.swift index dde0085..ecab387 100644 --- a/Sources/tart/OCI/Layerizer/DiskV2.swift +++ b/Sources/tart/OCI/Layerizer/DiskV2.swift @@ -10,7 +10,7 @@ class DiskV2: Disk { var pushedLayers: [OCIManifestLayer] = [] // Open the disk file - var mappedDisk = try Data(contentsOf: diskURL, options: [.alwaysMapped]) + let mappedDisk = try Data(contentsOf: diskURL, options: [.alwaysMapped]) // Compress the disk file as multiple individually decompressible streams, // each equal ``Self.layerLimitBytes`` bytes or slightly larger due to the diff --git a/Sources/tart/OCI/Registry.swift b/Sources/tart/OCI/Registry.swift index 680e86e..8558fd6 100644 --- a/Sources/tart/OCI/Registry.swift +++ b/Sources/tart/OCI/Registry.swift @@ -42,9 +42,6 @@ extension AsyncThrowingChannel { } struct TokenResponse: Decodable, Authentication { - let defaultIssuedAt = Date() - let defaultExpiresIn = 60 - var token: String? var accessToken: String? var expiresIn: Int? @@ -66,7 +63,8 @@ struct TokenResponse: Decodable, Authentication { return dateFormatter.date(from: dateString) ?? Date() } - let response = try decoder.decode(TokenResponse.self, from: fromData) + var response = try decoder.decode(TokenResponse.self, from: fromData) + response.issuedAt = response.issuedAt ?? Date() guard response.token != nil || response.accessToken != nil else { throw DecodingError.keyNotFound(CodingKeys.token, .init(codingPath: [], debugDescription: "Missing token or access_token. One must be present.")) @@ -85,7 +83,7 @@ struct TokenResponse: Decodable, Authentication { // // [1]: https://docs.docker.com/registry/spec/auth/token/#requesting-a-token - (issuedAt ?? defaultIssuedAt) + TimeInterval(expiresIn ?? defaultExpiresIn) + (issuedAt ?? Date()) + TimeInterval(expiresIn ?? 60) } } diff --git a/Sources/tart/VM.swift b/Sources/tart/VM.swift index e825d55..6a6be9d 100644 --- a/Sources/tart/VM.swift +++ b/Sources/tart/VM.swift @@ -1,6 +1,7 @@ import Foundation import Virtualization import AsyncAlgorithms +import Semaphore struct UnsupportedRestoreImageError: Error { } @@ -30,7 +31,7 @@ class VM: NSObject, VZVirtualMachineDelegate, ObservableObject { var configuration: VZVirtualMachineConfiguration // Semaphore used to communicate with the VZVirtualMachineDelegate - var sema = DispatchSemaphore(value: 0) + var sema = AsyncSemaphore(value: 0) // VM's config var name: String @@ -243,13 +244,7 @@ class VM: NSObject, VZVirtualMachineDelegate, ObservableObject { } func run() async throws { - await withTaskCancellationHandler(operation: { - // Wait for the VM to finish running - // or for the exit condition - sema.wait() - }, onCancel: { - sema.signal() - }) + try await sema.waitUnlessCancelled() if Task.isCancelled { try await stop() diff --git a/Tests/TartTests/TokenResponseTests.swift b/Tests/TartTests/TokenResponseTests.swift index f961c05..6eb5ae2 100644 --- a/Tests/TartTests/TokenResponseTests.swift +++ b/Tests/TartTests/TokenResponseTests.swift @@ -3,24 +3,26 @@ import XCTest final class TokenResponseTests: XCTestCase { func testBasic() throws { + var expectedTokenExpiresAtRange = DateInterval() let tokenResponseRaw = Data("{\"token\":\"some token\"}".utf8) let tokenResponse = try TokenResponse.parse(fromData: tokenResponseRaw) XCTAssertEqual(tokenResponse.token, "some token") - let expectedTokenExpiresAtRange = Date()...Date().addingTimeInterval(60) + expectedTokenExpiresAtRange.end = Date().addingTimeInterval(60) XCTAssertTrue(expectedTokenExpiresAtRange.contains(tokenResponse.tokenExpiresAt)) XCTAssertTrue(tokenResponse.isValid()) } func testExpirationBasic() throws { + var expectedTokenExpiresAtRange = DateInterval() let tokenResponseRaw = Data("{\"token\":\"some token\",\"expires_in\":2}".utf8) let tokenResponse = try TokenResponse.parse(fromData: tokenResponseRaw) XCTAssertEqual(tokenResponse.expiresIn, 2) - let expectedTokenExpiresAtRange = Date()...Date().addingTimeInterval(2) + expectedTokenExpiresAtRange.end = Date().addingTimeInterval(2) XCTAssertTrue(expectedTokenExpiresAtRange.contains(tokenResponse.tokenExpiresAt)) XCTAssertTrue(tokenResponse.isValid())