diff --git a/Sources/PackageModel/SwiftSDKBundle.swift b/Sources/PackageModel/SwiftSDKBundle.swift index 1bcb435ffb4..68f60a11033 100644 --- a/Sources/PackageModel/SwiftSDKBundle.swift +++ b/Sources/PackageModel/SwiftSDKBundle.swift @@ -79,30 +79,30 @@ public struct SwiftSDKBundle { /// - observabilityScope: observability scope to log warnings about multiple matches. /// - Returns: `Destination` value matching `query` either by artifact ID or target triple, `nil` if none found. public static func selectBundle( - fromBundlesAt destinationsDirectory: AbsolutePath?, + fromBundlesAt swiftSDKsDirectory: AbsolutePath?, fileSystem: FileSystem, matching selector: String, hostTriple: Triple, observabilityScope: ObservabilityScope ) throws -> Destination { - guard let destinationsDirectory = destinationsDirectory else { + guard let swiftSDKsDirectory else { throw StringError( """ - No directory found for installed Swift SDKs, specify one + No directory found for installed Swift SDKs, specify one \ with `--experimental-swift-sdks-path` option. """ ) } let validBundles = try SwiftSDKBundle.getAllValidBundles( - swiftSDKsDirectory: destinationsDirectory, + swiftSDKsDirectory: swiftSDKsDirectory, fileSystem: fileSystem, observabilityScope: observabilityScope ) guard !validBundles.isEmpty else { throw StringError( - "No valid Swift SDK bundles found at \(destinationsDirectory)." + "No valid Swift SDK bundles found at \(swiftSDKsDirectory)." ) } @@ -113,8 +113,8 @@ public struct SwiftSDKBundle { ) else { throw StringError( """ - No Swift SDK found matching query `\(selector)` and host triple - `\(hostTriple.tripleString)`. Use `swift experimental-sdk list` command to see + No Swift SDK found matching query `\(selector)` and host triple \ + `\(hostTriple.tripleString)`. Use `swift experimental-sdk list` command to see \ available destinations. """ ) @@ -434,7 +434,22 @@ extension [SwiftSDKBundle] { for bundle in self { for (artifactID, variants) in bundle.artifacts { for variant in variants { - guard variant.metadata.supportedTriples.contains(hostTriple) else { + guard variant.metadata.supportedTriples.contains(where: { variantTriple in + if + hostTriple.arch == variantTriple.arch && + hostTriple.vendor == variantTriple.vendor && + hostTriple.os == variantTriple.os && + hostTriple.environment == variantTriple.environment + { + if let hostOSVersion = hostTriple.osVersion, let variantOSVersion = variantTriple.osVersion { + return hostOSVersion >= variantOSVersion + } else { + return true + } + } else { + return false + } + }) else { continue } diff --git a/Tests/PackageModelTests/SwiftSDKBundleTests.swift b/Tests/PackageModelTests/SwiftSDKBundleTests.swift index ab232006da3..8f89bac4e8a 100644 --- a/Tests/PackageModelTests/SwiftSDKBundleTests.swift +++ b/Tests/PackageModelTests/SwiftSDKBundleTests.swift @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Basics -import PackageModel +@testable import PackageModel import SPMTestSupport import XCTest @@ -22,27 +22,58 @@ import class TSCBasic.InMemoryFileSystem private let testArtifactID = "test-artifact" -private func generateInfoJSON(artifacts: [MockArtifact]) -> String { - """ - { - "artifacts" : { - \(artifacts.map { - """ - "\($0.id)" : { - "type" : "swiftSDK", - "version" : "0.0.1", - "variants" : [ - { - "path" : "\($0.id)/aarch64-unknown-linux", - "supportedTriples" : \($0.supportedTriples.map(\.tripleString)) +private let targetTriple = try! Triple("aarch64-unknown-linux") + +private let jsonEncoder = JSONEncoder() + +private func generateBundleFiles(bundle: MockBundle) throws -> [(String, ByteString)] { + try [ + ( + "\(bundle.path)/info.json", + ByteString(""" + { + "artifacts" : { + \(bundle.artifacts.map { + """ + "\($0.id)" : { + "type" : "swiftSDK", + "version" : "0.0.1", + "variants" : [ + { + "path" : "\($0.id)/\(targetTriple.triple)", + "supportedTriples" : \($0.supportedTriples.map(\.tripleString)) + } + ] } - ] - } - """ - }.joined(separator: ",\n") - ) - }, - "schemaVersion" : "1.0" + """ + }.joined(separator: ",\n") + ) + }, + "schemaVersion" : "1.0" + } + """.utf8) + ), + + ] + bundle.artifacts.map { + ( + "\(bundle.path)/\($0.id)/\(targetTriple.tripleString)/swift-sdk.json", + ByteString(try generateSwiftSDKMetadata(jsonEncoder).utf8) + ) + } +} + +private func generateSwiftSDKMetadata(_ encoder: JSONEncoder) throws -> String { + try """ + { + "schemaVersion": "4.0", + "targetTriples": \( + String( + bytes: encoder.encode([ + targetTriple.tripleString: SwiftSDKMetadataV4.TripleProperties(sdkRootPath: "sdk") + ]), + encoding: .utf8 + )! + ) } """ } @@ -64,15 +95,13 @@ private func generateTestFileSystem(bundleArtifacts: [MockArtifact]) throws -> ( return MockBundle(name: "test\(i).artifactbundle", path: "/\(bundleName)", artifacts: [artifacts]) } - let fileSystem = InMemoryFileSystem( - files: Dictionary(uniqueKeysWithValues: bundles.map { - ( - "\($0.path)/info.json", - ByteString( - encodingAsUTF8: generateInfoJSON(artifacts: $0.artifacts) - ) - ) - }) + + let fileSystem = try InMemoryFileSystem( + files: Dictionary( + uniqueKeysWithValues: bundles.flatMap { + try generateBundleFiles(bundle: $0) + } + ) ) let swiftSDKsDirectory = try AbsolutePath(validating: "/sdks") @@ -209,4 +238,34 @@ final class SwiftSDKBundleTests: XCTestCase { XCTAssertEqual(validBundles.count, bundles.count) } + + func testBundleSelection() async throws { + let (fileSystem, bundles, swiftSDKsDirectory) = try generateTestFileSystem( + bundleArtifacts: [ + .init(id: "\(testArtifactID)1", supportedTriples: [arm64Triple]), + .init(id: "\(testArtifactID)2", supportedTriples: [i686Triple]) + ] + ) + let system = ObservabilitySystem.makeForTesting() + + for bundle in bundles { + try SwiftSDKBundle.install( + bundlePathOrURL: bundle.path, + swiftSDKsDirectory: swiftSDKsDirectory, + fileSystem, + MockArchiver(), + system.topScope + ) + } + + let sdk = try SwiftSDKBundle.selectBundle( + fromBundlesAt: swiftSDKsDirectory, + fileSystem: fileSystem, + matching: "\(testArtifactID)1", + hostTriple: Triple("arm64-apple-macosx14.0"), + observabilityScope: system.topScope + ) + + XCTAssertEqual(sdk.targetTriple, targetTriple) + } }