diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index 8fcdb8fbdd3..9794b1bd28c 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -188,10 +188,19 @@ public struct CachingOptions: ParsableArguments { } /// Whether to use macro prebuilts or not - @Flag(name: .customLong("experimental-prebuilts"), - inversion: .prefixedEnableDisable, - help: "Whether to use prebuilt swift-syntax libraries for macros") + @Flag( + name: .customLong("experimental-prebuilts"), + inversion: .prefixedEnableDisable, + help: "Whether to use prebuilt swift-syntax libraries for macros" + ) public var usePrebuilts: Bool = false + + /// Hidden option to override the prebuilts download location for testing + @Option( + name: .customLong("experimental-prebuilts-download-url"), + help: .hidden + ) + public var prebuiltsDownloadURL: String? } public struct LoggingOptions: ParsableArguments { diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index b64d2736068..365de24add3 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -472,7 +472,8 @@ public final class SwiftCommandState { .init(url: $0, supportsAvailability: true) }, manifestImportRestrictions: .none, - usePrebuilts: options.caching.usePrebuilts + usePrebuilts: options.caching.usePrebuilts, + prebuiltsDownloadURL: options.caching.prebuiltsDownloadURL ), cancellator: self.cancellator, initializationWarningHandler: { self.observabilityScope.emit(warning: $0) }, diff --git a/Sources/PackageGraph/ModulesGraph+Loading.swift b/Sources/PackageGraph/ModulesGraph+Loading.swift index a95c87266c1..e1576cfd7dd 100644 --- a/Sources/PackageGraph/ModulesGraph+Loading.swift +++ b/Sources/PackageGraph/ModulesGraph+Loading.swift @@ -260,7 +260,12 @@ extension ModulesGraph { ) let rootPackages = resolvedPackages.filter { root.manifests.values.contains($0.manifest) } - checkAllDependenciesAreUsed(packages: resolvedPackages, rootPackages, observabilityScope: observabilityScope) + checkAllDependenciesAreUsed( + packages: resolvedPackages, + rootPackages, + prebuilts: prebuilts, + observabilityScope: observabilityScope + ) return try ModulesGraph( rootPackages: rootPackages, @@ -275,6 +280,7 @@ extension ModulesGraph { private func checkAllDependenciesAreUsed( packages: IdentifiableSet, _ rootPackages: [ResolvedPackage], + prebuilts: [PackageIdentity: [String: PrebuiltLibrary]], observabilityScope: ObservabilityScope ) { for package in rootPackages { @@ -352,9 +358,10 @@ private func checkAllDependenciesAreUsed( let usedByPackage = productDependencies.contains { $0.name == product.name } // We check if any of the products of this dependency is guarded by a trait. let traitGuarded = traitGuardedProductDependencies.contains(product.name) + // Consider prebuilts as used + let prebuilt = prebuilts[dependency.identity]?.keys.contains(product.name) ?? false - // If the product is either used directly or guarded by a trait we consider it as used - return usedByPackage || traitGuarded + return usedByPackage || traitGuarded || prebuilt } if !dependencyIsUsed && !observabilityScope.errorsReportedInAnyScope { @@ -672,8 +679,21 @@ private func createResolvedPackages( } if let package = productRef.package, prebuilts[.plain(package)]?[productRef.name] != nil { - // using a prebuilt instead. - continue + // See if we're using a prebuilt instead + if moduleBuilder.module.type == .macro { + continue + } else if moduleBuilder.module.type == .test { + // use prebuilt if this is a test that depends a macro target + // these are guaranteed built for host + if moduleBuilder.module.dependencies.contains(where: { dep in + guard let module = dep.module else { + return false + } + return module.type == .macro + }) { + continue + } + } } // Find the product in this package's dependency products. diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index 235f9287b30..e8c37923456 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -270,8 +270,8 @@ public struct BinaryArtifact { /// A structure representing a prebuilt library to be used instead of a source dependency public struct PrebuiltLibrary { - /// The package reference. - public let packageRef: PackageReference + /// The package identity. + public let identity: PackageIdentity /// The name of the binary target the artifact corresponds to. public let libraryName: String @@ -285,8 +285,8 @@ public struct PrebuiltLibrary { /// The C modules that need their includes directory added to the include path public let cModules: [String] - public init(packageRef: PackageReference, libraryName: String, path: AbsolutePath, products: [String], cModules: [String]) { - self.packageRef = packageRef + public init(identity: PackageIdentity, libraryName: String, path: AbsolutePath, products: [String], cModules: [String]) { + self.identity = identity self.libraryName = libraryName self.path = path self.products = products @@ -1242,31 +1242,34 @@ public final class PackageBuilder { table.add(assignment, for: .SWIFT_ACTIVE_COMPILATION_CONDITIONS) } - // Add in flags for prebuilts - let prebuiltLibraries: [String: PrebuiltLibrary] = target.dependencies.reduce(into: .init()) { - guard case let .product(name: name, package: package, moduleAliases: _, condition: _) = $1, - let package = package, - let prebuilt = prebuilts[.plain(package)]?[name] - else { - return - } + // Add in flags for prebuilts if the target is a macro or a macro test. + // Currently we only support prebuilts for macros. + if target.type == .macro || target.isMacroTest(in: manifest) { + let prebuiltLibraries: [String: PrebuiltLibrary] = target.dependencies.reduce(into: .init()) { + guard case let .product(name: name, package: package, moduleAliases: _, condition: _) = $1, + let package = package, + let prebuilt = prebuilts[.plain(package)]?[name] + else { + return + } - $0[prebuilt.libraryName] = prebuilt - } + $0[prebuilt.libraryName] = prebuilt + } - for prebuilt in prebuiltLibraries.values { - let lib = prebuilt.path.appending(components: ["lib", "lib\(prebuilt.libraryName).a"]).pathString - var ldFlagsAssignment = BuildSettings.Assignment() - ldFlagsAssignment.values = [lib] - table.add(ldFlagsAssignment, for: .OTHER_LDFLAGS) + for prebuilt in prebuiltLibraries.values { + let lib = prebuilt.path.appending(components: ["lib", "lib\(prebuilt.libraryName).a"]).pathString + var ldFlagsAssignment = BuildSettings.Assignment() + ldFlagsAssignment.values = [lib] + table.add(ldFlagsAssignment, for: .OTHER_LDFLAGS) - var includeDirs: [AbsolutePath] = [prebuilt.path.appending(component: "Modules")] - for cModule in prebuilt.cModules { - includeDirs.append(prebuilt.path.appending(components: "include", cModule)) + var includeDirs: [AbsolutePath] = [prebuilt.path.appending(component: "Modules")] + for cModule in prebuilt.cModules { + includeDirs.append(prebuilt.path.appending(components: "include", cModule)) + } + var includeAssignment = BuildSettings.Assignment() + includeAssignment.values = includeDirs.map({ "-I\($0.pathString)" }) + table.add(includeAssignment, for: .OTHER_SWIFT_FLAGS) } - var includeAssignment = BuildSettings.Assignment() - includeAssignment.values = includeDirs.map({ "-I\($0.pathString)" }) - table.add(includeAssignment, for: .OTHER_SWIFT_FLAGS) } return table @@ -1853,4 +1856,26 @@ extension TargetDescription { fileprivate var usesUnsafeFlags: Bool { settings.filter(\.kind.isUnsafeFlags).isEmpty == false } + + fileprivate func isMacroTest(in manifest: Manifest) -> Bool { + guard self.type == .test else { return false } + + return self.dependencies.contains(where: { + let name: String + switch $0 { + case .byName(name: let n, condition: _): + name = n + case .target(name: let n, condition: _): + name = n + default: + return false + } + + guard let target = manifest.targetMap[name] else { + return false + } + + return target.type == .macro + }) + } } diff --git a/Sources/Workspace/ManagedPrebuilt.swift b/Sources/Workspace/ManagedPrebuilt.swift index 108402e3b26..a148f936843 100644 --- a/Sources/Workspace/ManagedPrebuilt.swift +++ b/Sources/Workspace/ManagedPrebuilt.swift @@ -10,14 +10,19 @@ // //===----------------------------------------------------------------------===// +import struct TSCUtility.Version + import Basics import PackageModel extension Workspace { /// A downloaded prebuilt managed by the workspace. public struct ManagedPrebuilt { - /// The package reference. - public let packageRef: PackageReference + /// The package identity + public let identity: PackageIdentity + + /// The package version + public let version: Version /// The name of the binary target the artifact corresponds to. public let libraryName: String @@ -35,7 +40,7 @@ extension Workspace { extension Workspace.ManagedPrebuilt: CustomStringConvertible { public var description: String { - return "" + return "" } } @@ -45,60 +50,60 @@ extension Workspace { /// A collection of managed artifacts which have been downloaded. public final class ManagedPrebuilts { /// A mapping from package identity, to target name, to ManagedArtifact. - private var artifactMap: [PackageIdentity: [String: ManagedPrebuilt]] + private var prebuiltMap: [PackageIdentity: [String: ManagedPrebuilt]] - internal var artifacts: AnyCollection { - AnyCollection(self.artifactMap.values.lazy.flatMap{ $0.values }) + internal var prebuilts: AnyCollection { + AnyCollection(self.prebuiltMap.values.lazy.flatMap{ $0.values }) } init() { - self.artifactMap = [:] + self.prebuiltMap = [:] } - init(_ artifacts: [ManagedPrebuilt]) throws { - let artifactsByPackagePath = Dictionary(grouping: artifacts, by: { $0.packageRef.identity }) - self.artifactMap = try artifactsByPackagePath.mapValues{ artifacts in - try Dictionary(artifacts.map { ($0.libraryName, $0) }, uniquingKeysWith: { _, _ in + init(_ prebuilts: [ManagedPrebuilt]) throws { + let prebuiltsByPackagePath = Dictionary(grouping: prebuilts, by: { $0.identity }) + self.prebuiltMap = try prebuiltsByPackagePath.mapValues{ prebuilt in + try Dictionary(prebuilt.map { ($0.libraryName, $0) }, uniquingKeysWith: { _, _ in // should be unique - throw StringError("binary artifact already exists in managed artifacts") + throw StringError("prebuilt already exists in managed prebuilts") }) } } public subscript(packageIdentity packageIdentity: PackageIdentity, targetName targetName: String) -> ManagedPrebuilt? { - self.artifactMap[packageIdentity]?[targetName] + self.prebuiltMap[packageIdentity]?[targetName] } - public func add(_ artifact: ManagedPrebuilt) { - self.artifactMap[artifact.packageRef.identity, default: [:]][artifact.libraryName] = artifact + public func add(_ prebuilt: ManagedPrebuilt) { + self.prebuiltMap[prebuilt.identity, default: [:]][prebuilt.libraryName] = prebuilt } public func remove(packageIdentity: PackageIdentity, targetName: String) { - self.artifactMap[packageIdentity]?[targetName] = nil + self.prebuiltMap[packageIdentity]?[targetName] = nil } } } extension Workspace.ManagedPrebuilts: Collection { public var startIndex: AnyIndex { - self.artifacts.startIndex + self.prebuilts.startIndex } public var endIndex: AnyIndex { - self.artifacts.endIndex + self.prebuilts.endIndex } public subscript(index: AnyIndex) -> Workspace.ManagedPrebuilt { - self.artifacts[index] + self.prebuilts[index] } public func index(after index: AnyIndex) -> AnyIndex { - self.artifacts.index(after: index) + self.prebuilts.index(after: index) } } extension Workspace.ManagedPrebuilts: CustomStringConvertible { public var description: String { - "" + "" } } diff --git a/Sources/Workspace/Workspace+Configuration.swift b/Sources/Workspace/Workspace+Configuration.swift index b679c3f1237..2411ed6724e 100644 --- a/Sources/Workspace/Workspace+Configuration.swift +++ b/Sources/Workspace/Workspace+Configuration.swift @@ -792,6 +792,9 @@ public struct WorkspaceConfiguration { /// Whether or not to use prebuilt swift-syntax for macros public var usePrebuilts: Bool + /// String URL to allow override of the prebuilts download location + public var prebuiltsDownloadURL: String? + public init( skipDependenciesUpdates: Bool, prefetchBasedOnResolvedFile: Bool, @@ -805,7 +808,8 @@ public struct WorkspaceConfiguration { sourceControlToRegistryDependencyTransformation: SourceControlToRegistryDependencyTransformation, defaultRegistry: Registry?, manifestImportRestrictions: (startingToolsVersion: ToolsVersion, allowedImports: [String])?, - usePrebuilts: Bool + usePrebuilts: Bool, + prebuiltsDownloadURL: String? ) { self.skipDependenciesUpdates = skipDependenciesUpdates self.prefetchBasedOnResolvedFile = prefetchBasedOnResolvedFile @@ -820,6 +824,7 @@ public struct WorkspaceConfiguration { self.defaultRegistry = defaultRegistry self.manifestImportRestrictions = manifestImportRestrictions self.usePrebuilts = usePrebuilts + self.prebuiltsDownloadURL = prebuiltsDownloadURL } /// Default instance of WorkspaceConfiguration @@ -837,7 +842,8 @@ public struct WorkspaceConfiguration { sourceControlToRegistryDependencyTransformation: .disabled, defaultRegistry: .none, manifestImportRestrictions: .none, - usePrebuilts: false + usePrebuilts: false, + prebuiltsDownloadURL: nil ) } diff --git a/Sources/Workspace/Workspace+Prebuilts.swift b/Sources/Workspace/Workspace+Prebuilts.swift index cf766930115..71e455477f1 100644 --- a/Sources/Workspace/Workspace+Prebuilts.swift +++ b/Sources/Workspace/Workspace+Prebuilts.swift @@ -177,7 +177,8 @@ extension Workspace { cachePath: AbsolutePath?, customHTTPClient: HTTPClient?, customArchiver: Archiver?, - delegate: Delegate? + delegate: Delegate?, + prebuiltsDownloadURL: String? ) { self.fileSystem = fileSystem self.authorizationProvider = authorizationProvider @@ -186,33 +187,41 @@ extension Workspace { self.scratchPath = scratchPath self.cachePath = cachePath self.delegate = delegate + + self.prebuiltPackages = [ + // TODO: we should have this in a manifest somewhere, not hardcoded like this + .init( + identity: .plain("swift-syntax"), + packageRefs: [ + .init( + identity: .plain("swift-syntax"), + kind: .remoteSourceControl("https://github.com/swiftlang/swift-syntax.git") + ), + .init( + identity: .plain("swift-syntax"), + kind: .remoteSourceControl("git@github.com:swiftlang/swift-syntax.git") + ), + ], + prebuiltsURL: URL( + string: prebuiltsDownloadURL ?? "https://github.com/dschaefer2/swift-syntax/releases/download" + )! + ), + ] } struct PrebuiltPackage { - let packageRef: PackageReference + let identity: PackageIdentity + let packageRefs: [PackageReference] let prebuiltsURL: URL } - private let prebuiltPackages: [PrebuiltPackage] = [ - .init( - packageRef: .init( - identity: .plain("swift-syntax"), - kind: .remoteSourceControl("https://github.com/swiftlang/swift-syntax.git") - ), - prebuiltsURL: URL( - string: - "https://github.com/dschaefer2/swift-syntax/releases/download" - )! - ), - ] + private let prebuiltPackages: [PrebuiltPackage] // Version of the compiler we're building against private let swiftVersion = "\(SwiftVersion.current.major).\(SwiftVersion.current.minor)" - fileprivate func findPrebuilts(packages: [PackageReference]) - -> [PrebuiltPackage] - { + fileprivate func findPrebuilts(packages: [PackageReference]) -> [PrebuiltPackage] { var prebuilts: [PrebuiltPackage] = [] for packageRef in packages { guard case let .remoteSourceControl(pkgURL) = packageRef.kind else { @@ -221,21 +230,23 @@ extension Workspace { } if let prebuilt = prebuiltPackages.first(where: { - guard case let .remoteSourceControl(prebuiltURL) = $0.packageRef.kind, - $0.packageRef.identity == packageRef.identity else { - return false - } - - if pkgURL == prebuiltURL { - return true - } else if !pkgURL.lastPathComponent.hasSuffix(".git") { - // try with the git extension - // TODO: Does this need to be in the PackageRef Equatable? - let gitURL = SourceControlURL(pkgURL.absoluteString + ".git") - return gitURL == prebuiltURL - } else { - return false - } + $0.packageRefs.contains(where: { + guard case let .remoteSourceControl(prebuiltURL) = $0.kind, + $0.identity == packageRef.identity else { + return false + } + + if pkgURL == prebuiltURL { + return true + } else if !pkgURL.lastPathComponent.hasSuffix(".git") { + // try with the git extension + // TODO: Does this need to be in the PackageRef Equatable? + let gitURL = SourceControlURL(pkgURL.absoluteString + ".git") + return gitURL == prebuiltURL + } else { + return false + } + }) }) { prebuilts.append(prebuilt) } @@ -250,15 +261,17 @@ extension Workspace { ) async throws -> PrebuiltsManifest? { let manifestFile = swiftVersion + "-manifest.json" let prebuiltsDir = cachePath ?? scratchPath - let destination = prebuiltsDir.appending( - components: package.packageRef.identity.description, + let destination = prebuiltsDir.appending(components: + package.identity.description, + version.description, manifestFile ) if fileSystem.exists(destination) { do { return try JSONDecoder().decode( - PrebuiltsManifest.self, - from: try Data(contentsOf: destination.asURL) + path: destination, + fileSystem: fileSystem, + as: PrebuiltsManifest.self ) } catch { // redownload it @@ -278,39 +291,45 @@ extension Workspace { components: version.description, manifestFile ) - var headers = HTTPClientHeaders() - headers.add(name: "Accept", value: "application/json") - var request = HTTPClient.Request.download( - url: manifestURL, - headers: headers, - fileSystem: self.fileSystem, - destination: destination - ) - request.options.authorizationProvider = + + if manifestURL.scheme == "file" { + // simply copy it over + try fileSystem.copy(from: AbsolutePath(validating: manifestURL.path), to: destination) + } else { + var headers = HTTPClientHeaders() + headers.add(name: "Accept", value: "application/json") + var request = HTTPClient.Request.download( + url: manifestURL, + headers: headers, + fileSystem: self.fileSystem, + destination: destination + ) + request.options.authorizationProvider = self.authorizationProvider?.httpAuthorizationHeader(for:) - request.options.retryStrategy = .exponentialBackoff( - maxAttempts: 3, - baseDelay: .milliseconds(50) - ) - request.options.validResponseCodes = [200] + request.options.retryStrategy = .exponentialBackoff( + maxAttempts: 3, + baseDelay: .milliseconds(50) + ) + request.options.validResponseCodes = [200] - do { - _ = try await self.httpClient.execute(request) { _, _ in - // TODO: send to delegate + do { + _ = try await self.httpClient.execute(request) { _, _ in + // TODO: send to delegate + } + } catch { + observabilityScope.emit( + info: "Prebuilt \(manifestFile)", + underlyingError: error + ) + return nil } - } catch { - observabilityScope.emit( - info: "Prebuilt \(manifestFile)", - underlyingError: error - ) - return nil } do { - let data = try fileSystem.readFileContents(destination) return try JSONDecoder().decode( - PrebuiltsManifest.self, - from: Data(data.contents) + path: destination, + fileSystem: fileSystem, + as: PrebuiltsManifest.self ) } catch { observabilityScope.emit( @@ -337,7 +356,7 @@ extension Workspace { let artifactName = "\(swiftVersion)-\(library.name)-\(artifact.platform.rawValue)" let scratchDir = scratchPath.appending( - package.packageRef.identity.description + package.identity.description ) let artifactDir = scratchDir.appending(artifactName) guard !fileSystem.exists(artifactDir) else { @@ -346,8 +365,9 @@ extension Workspace { let artifactFile = artifactName + ".zip" let prebuiltsDir = cachePath ?? scratchPath - let destination = prebuiltsDir.appending( - components: package.packageRef.identity.description, + let destination = prebuiltsDir.appending(components: + package.identity.description, + version.description, artifactFile ) @@ -368,48 +388,53 @@ extension Workspace { components: version.description, artifactFile ) + let fetchStart = DispatchTime.now() - var headers = HTTPClientHeaders() - headers.add(name: "Accept", value: "application/octet-stream") - var request = HTTPClient.Request.download( - url: artifactURL, - headers: headers, - fileSystem: self.fileSystem, - destination: destination - ) - request.options.authorizationProvider = + if artifactURL.scheme == "file" { + try fileSystem.copy(from: AbsolutePath(validating: artifactURL.path), to: destination) + } else { + var headers = HTTPClientHeaders() + headers.add(name: "Accept", value: "application/octet-stream") + var request = HTTPClient.Request.download( + url: artifactURL, + headers: headers, + fileSystem: self.fileSystem, + destination: destination + ) + request.options.authorizationProvider = self.authorizationProvider?.httpAuthorizationHeader(for:) - request.options.retryStrategy = .exponentialBackoff( - maxAttempts: 3, - baseDelay: .milliseconds(50) - ) - request.options.validResponseCodes = [200] + request.options.retryStrategy = .exponentialBackoff( + maxAttempts: 3, + baseDelay: .milliseconds(50) + ) + request.options.validResponseCodes = [200] - self.delegate?.willDownloadPrebuilt( - from: artifactURL.absoluteString, - fromCache: false - ) - do { - _ = try await self.httpClient.execute(request) { - bytesDownloaded, - totalBytesToDownload in - self.delegate?.downloadingPrebuilt( + self.delegate?.willDownloadPrebuilt( + from: artifactURL.absoluteString, + fromCache: false + ) + do { + _ = try await self.httpClient.execute(request) { + bytesDownloaded, + totalBytesToDownload in + self.delegate?.downloadingPrebuilt( + from: artifactURL.absoluteString, + bytesDownloaded: bytesDownloaded, + totalBytesToDownload: totalBytesToDownload + ) + } + } catch { + observabilityScope.emit( + info: "Prebuilt artifact \(artifactFile)", + underlyingError: error + ) + self.delegate?.didDownloadPrebuilt( from: artifactURL.absoluteString, - bytesDownloaded: bytesDownloaded, - totalBytesToDownload: totalBytesToDownload + result: .failure(error), + duration: fetchStart.distance(to: .now()) ) + return nil } - } catch { - observabilityScope.emit( - info: "Prebuilt artifact \(artifactFile)", - underlyingError: error - ) - self.delegate?.didDownloadPrebuilt( - from: artifactURL.absoluteString, - result: .failure(error), - duration: fetchStart.distance(to: .now()) - ) - return nil } // Check the checksum @@ -465,13 +490,11 @@ extension Workspace { return } - for prebuilt in prebuiltsManager.findPrebuilts( - packages: try manifests.requiredPackages - ) { + let addedPrebuilts = ManagedPrebuilts() + + for prebuilt in prebuiltsManager.findPrebuilts(packages: try manifests.requiredPackages) { guard - let manifest = manifests.allDependencyManifests[ - prebuilt.packageRef.identity - ], + let manifest = manifests.allDependencyManifests[prebuilt.identity], let packageVersion = manifest.manifest.version, let prebuiltManifest = try await prebuiltsManager .downloadManifest( @@ -499,21 +522,30 @@ extension Workspace { artifact: artifact, observabilityScope: observabilityScope ) - { + { // Add to workspace state let managedPrebuilt = ManagedPrebuilt( - packageRef: prebuilt.packageRef, + identity: prebuilt.identity, + version: packageVersion, libraryName: library.name, path: path, products: library.products, cModules: library.cModules ) + addedPrebuilts.add(managedPrebuilt) self.state.prebuilts.add(managedPrebuilt) - try self.state.save() } } } } + + for prebuilt in self.state.prebuilts.prebuilts { + if !addedPrebuilts.contains(where: { $0.identity == prebuilt.identity && $0.version == prebuilt.version }) { + self.state.prebuilts.remove(packageIdentity: prebuilt.identity, targetName: prebuilt.libraryName) + } + } + + try self.state.save() } var hostPrebuiltsPlatform: PrebuiltsManifest.Platform? { diff --git a/Sources/Workspace/Workspace+State.swift b/Sources/Workspace/Workspace+State.swift index 533cac4adf2..7027dcb2491 100644 --- a/Sources/Workspace/Workspace+State.swift +++ b/Sources/Workspace/Workspace+State.swift @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import struct TSCUtility.Version + import Basics import Foundation import PackageGraph @@ -200,7 +202,7 @@ extension WorkspaceStateStorage { self.object = .init( dependencies: dependencies.map { .init($0) }.sorted { $0.packageRef.identity < $1.packageRef.identity }, artifacts: artifacts.map { .init($0) }.sorted { $0.packageRef.identity < $1.packageRef.identity }, - prebuilts: prebuilts.map { .init($0) }.sorted { $0.packageRef.identity < $1.packageRef.identity } + prebuilts: prebuilts.map { .init($0) }.sorted { $0.identity < $1.identity } ) } @@ -446,14 +448,16 @@ extension WorkspaceStateStorage { } struct Prebuilt: Codable { - let packageRef: PackageReference + let identity: PackageIdentity + let version: TSCUtility.Version let libraryName: String let path: AbsolutePath let products: [String] let cModules: [String] init(_ managedPrebuilt: Workspace.ManagedPrebuilt) { - self.packageRef = .init(managedPrebuilt.packageRef) + self.identity = managedPrebuilt.identity + self.version = managedPrebuilt.version self.libraryName = managedPrebuilt.libraryName self.path = managedPrebuilt.path self.products = managedPrebuilt.products @@ -525,8 +529,9 @@ extension Workspace.ManagedArtifact { extension Workspace.ManagedPrebuilt { fileprivate init(_ prebuilt: WorkspaceStateStorage.V7.Prebuilt) throws { - try self.init( - packageRef: .init(prebuilt.packageRef), + self.init( + identity: prebuilt.identity, + version: prebuilt.version, libraryName: prebuilt.libraryName, path: prebuilt.path, products: prebuilt.products, diff --git a/Sources/Workspace/Workspace.swift b/Sources/Workspace/Workspace.swift index 6199e356e5e..66b2c4d4eb8 100644 --- a/Sources/Workspace/Workspace.swift +++ b/Sources/Workspace/Workspace.swift @@ -567,7 +567,8 @@ public class Workspace { cachePath: customPrebuiltsManager?.useCache == false || !configuration.sharedDependenciesCacheEnabled ? .none : location.sharedPrebuiltsCacheDirectory, customHTTPClient: customPrebuiltsManager?.httpClient, customArchiver: customPrebuiltsManager?.archiver, - delegate: delegate.map(WorkspacePrebuiltsManagerDelegate.init(workspaceDelegate:)) + delegate: delegate.map(WorkspacePrebuiltsManagerDelegate.init(workspaceDelegate:)), + prebuiltsDownloadURL: configuration.prebuiltsDownloadURL ) : .none // register the prebuilt packages downloader with the cancellation handler if let prebuiltsManager { @@ -962,9 +963,9 @@ extension Workspace { } let prebuilts: [PackageIdentity: [String: PrebuiltLibrary]] = self.state.prebuilts.reduce(into: .init()) { - let prebuilt = PrebuiltLibrary(packageRef: $1.packageRef, libraryName: $1.libraryName, path: $1.path, products: $1.products, cModules: $1.cModules) + let prebuilt = PrebuiltLibrary(identity: $1.identity, libraryName: $1.libraryName, path: $1.path, products: $1.products, cModules: $1.cModules) for product in $1.products { - $0[$1.packageRef.identity, default: [:]][product] = prebuilt + $0[$1.identity, default: [:]][product] = prebuilt } } diff --git a/Sources/_InternalTestSupport/ManifestExtensions.swift b/Sources/_InternalTestSupport/ManifestExtensions.swift index 13268bbac57..1c25966c30d 100644 --- a/Sources/_InternalTestSupport/ManifestExtensions.swift +++ b/Sources/_InternalTestSupport/ManifestExtensions.swift @@ -266,4 +266,27 @@ extension Manifest { traits: self.traits ) } + + public func with(dependencies: [PackageDependency]) -> Manifest { + Manifest( + displayName: self.displayName, + path: self.path, + packageKind: self.packageKind, + packageLocation: self.packageLocation, + defaultLocalization: self.defaultLocalization, + platforms: self.platforms, + version: self.version, + revision: self.revision, + toolsVersion: self.toolsVersion, + pkgConfig: self.pkgConfig, + providers: self.providers, + cLanguageStandard: self.cLanguageStandard, + cxxLanguageStandard: self.cxxLanguageStandard, + swiftLanguageVersions: self.swiftLanguageVersions, + dependencies: dependencies, + products: self.products, + targets: self.targets, + traits: self.traits + ) + } } diff --git a/Sources/_InternalTestSupport/MockWorkspace.swift b/Sources/_InternalTestSupport/MockWorkspace.swift index e097a85dbe8..03c1b533d1c 100644 --- a/Sources/_InternalTestSupport/MockWorkspace.swift +++ b/Sources/_InternalTestSupport/MockWorkspace.swift @@ -355,7 +355,8 @@ public final class MockWorkspace { sourceControlToRegistryDependencyTransformation: self.sourceControlToRegistryDependencyTransformation, defaultRegistry: self.defaultRegistry, manifestImportRestrictions: .none, - usePrebuilts: customPrebuiltsManager != nil + usePrebuilts: customPrebuiltsManager != nil, + prebuiltsDownloadURL: nil ), customFingerprints: self.fingerprints, customMirrors: self.mirrors, @@ -506,7 +507,7 @@ public final class MockWorkspace { public func checkPackageGraph( roots: [String] = [], deps: [MockDependency], - _ result: (ModulesGraph, [Basics.Diagnostic]) -> Void + _ result: (ModulesGraph, [Basics.Diagnostic]) throws -> Void ) async throws { let dependencies = try deps.map { try $0.convert(baseURL: packagesDir, identityResolver: self.identityResolver) } try await self.checkPackageGraph(roots: roots, dependencies: dependencies, result) diff --git a/Sources/swift-build-prebuilts/BuildPrebuilts.swift b/Sources/swift-build-prebuilts/BuildPrebuilts.swift index 9d746b2a9d2..c8baaf8eb68 100644 --- a/Sources/swift-build-prebuilts/BuildPrebuilts.swift +++ b/Sources/swift-build-prebuilts/BuildPrebuilts.swift @@ -104,6 +104,11 @@ struct BuildPrebuilts: AsyncParsableCommand { try await shell("git clone \(repo.url)") for version in repo.versions { + let versionDir = stageDir.appending(version.tag) + if !fm.fileExists(atPath: versionDir.pathString) { + try fm.createDirectory(atPath: versionDir.pathString, withIntermediateDirectories: true) + } + _ = fm.changeCurrentDirectoryPath(repoDir.pathString) try await shell("git checkout \(version.tag)") @@ -159,7 +164,7 @@ struct BuildPrebuilts: AsyncParsableCommand { // Zip it up _ = fm.changeCurrentDirectoryPath(stageDir.pathString) - let zipFile = stageDir.appending("\(swiftVersion)-\(library.name)-\(platform).zip") + let zipFile = versionDir.appending("\(swiftVersion)-\(library.name)-\(platform).zip") let contentDirs = ["lib", "Modules"] + (library.cModules.isEmpty ? [] : ["include"]) #if os(Windows) try await shell("tar -acf \(zipFile.pathString) \(contentDirs.joined(separator: " "))") @@ -211,7 +216,7 @@ struct BuildPrebuilts: AsyncParsableCommand { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let manifestData = try encoder.encode(newManifest) - let manifestFile = stageDir.appending("\(swiftVersion)-manifest.json") + let manifestFile = versionDir.appending("\(swiftVersion)-manifest.json") try manifestData.write(to: manifestFile.asURL) } } @@ -264,7 +269,7 @@ struct BuildPrebuilts: AsyncParsableCommand { func downloadManifest(version: PrebuiltRepos.Version) async throws -> Workspace.PrebuiltsManifest? { let fm = FileManager.default let manifestFile = swiftVersion + "-manifest.json" - let destination = stageDir.appending(manifestFile) + let destination = stageDir.appending(components: version.tag, manifestFile) if fm.fileExists(atPath: destination.pathString) { do { return try JSONDecoder().decode( diff --git a/Tests/WorkspaceTests/PrebuiltsTests.swift b/Tests/WorkspaceTests/PrebuiltsTests.swift index 7739dbd75f2..7d22d8aa86d 100644 --- a/Tests/WorkspaceTests/PrebuiltsTests.swift +++ b/Tests/WorkspaceTests/PrebuiltsTests.swift @@ -18,6 +18,7 @@ import Basics import struct TSCBasic.SHA256 import struct TSCBasic.ByteString import struct TSCUtility.Version +import PackageGraph import PackageModel import Workspace import XCTest @@ -26,7 +27,9 @@ import _InternalTestSupport final class PrebuiltsTests: XCTestCase { let swiftVersion = "\(SwiftVersion.current.major).\(SwiftVersion.current.minor)" - func initData(artifact: Data, swiftSyntaxVersion: String) throws -> (Workspace.PrebuiltsManifest, MockPackage, MockPackage) { + func initData(artifact: Data, swiftSyntaxVersion: String, swiftSyntaxURL: String? = nil) throws -> (Workspace.PrebuiltsManifest, MockPackage, MockPackage) { + let swiftSyntaxURL = swiftSyntaxURL ?? "https://github.com/swiftlang/swift-syntax" + let manifest = Workspace.PrebuiltsManifest(libraries: [ .init( name: "MacroSupport", @@ -72,20 +75,22 @@ final class PrebuiltsTests: XCTestCase { dependencies: [ "FooMacros", .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), - ] - ) + ], + type: .test + ), ], dependencies: [ .sourceControl( - url: "https://github.com/swiftlang/swift-syntax", + url: swiftSyntaxURL, requirement: .exact(try XCTUnwrap(Version(swiftSyntaxVersion))) ) ] ) + let swiftSyntax = try MockPackage( name: "swift-syntax", - url: "https://github.com/swiftlang/swift-syntax", + url: swiftSyntaxURL, targets: [ MockTarget(name: "SwiftSyntaxMacrosTestSupport"), MockTarget(name: "SwiftCompilerPlugin"), @@ -96,13 +101,14 @@ final class PrebuiltsTests: XCTestCase { MockProduct(name: "SwiftCompilerPlugin", modules: ["SwiftCompilerPlugin"]), MockProduct(name: "SwiftSyntaxMacros", modules: ["SwiftSyntaxMacros"]), ], - versions: ["600.0.1", "600.0.2"] + versions: ["600.0.1", "600.0.2", "601.0.0"] ) return (manifest, rootPackage, swiftSyntax) } - func checkSettings(_ target: Module, usePrebuilt: Bool) throws { + func checkSettings(_ rootPackage: ResolvedPackage, _ targetName: String, usePrebuilt: Bool) throws { + let target = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == targetName })) if usePrebuilt { let swiftFlags = try XCTUnwrap(target.buildSettings.assignments[.OTHER_SWIFT_FLAGS]).flatMap({ $0.values }) XCTAssertTrue(swiftFlags.contains("-I/tmp/ws/.build/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64/Modules".fixwin)) @@ -123,6 +129,167 @@ final class PrebuiltsTests: XCTestCase { let (manifest, rootPackage, swiftSyntax) = try initData(artifact: artifact, swiftSyntaxVersion: "600.0.1") let manifestData = try JSONEncoder().encode(manifest) + let httpClient = HTTPClient { request, progressHandler in + guard case .download(let fileSystem, let destination) = request.kind else { + throw StringError("invalid request \(request.kind)") + } + + if request.url == "https://github.com/dschaefer2/swift-syntax/releases/download/600.0.1/\(self.swiftVersion)-manifest.json" { + try fileSystem.writeFileContents(destination, data: manifestData) + return .okay() + } else if request.url == "https://github.com/dschaefer2/swift-syntax/releases/download/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip" { + try fileSystem.writeFileContents(destination, data: artifact) + return .okay() + } else { + XCTFail("Unexpected URL \(request.url)") + return .notFound() + } + } + + let archiver = MockArchiver(handler: { _, archivePath, destination, completion in + XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) + XCTAssertEqual(destination.pathString, "/tmp/ws/.build/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64".fixwin) + completion(.success(())) + }) + + let workspace = try await MockWorkspace( + sandbox: sandbox, + fileSystem: fs, + roots: [ + rootPackage + ], + packages: [ + swiftSyntax + ], + prebuiltsManager: .init( + httpClient: httpClient, + archiver: archiver + ), + customHostTriple: Triple("arm64-apple-macosx15.0") + ) + + try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in + XCTAssertTrue(diagnostics.filter({ $0.severity == .error || $0.severity == .warning }).isEmpty) + let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: true) + try checkSettings(rootPackage, "FooTests", usePrebuilt: true) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) + } + } + + func testVersionChange() async throws { + let sandbox = AbsolutePath("/tmp/ws") + let fs = InMemoryFileSystem() + + let artifact = Data() + let (manifest, rootPackage, swiftSyntax) = try initData(artifact: artifact, swiftSyntaxVersion: "600.0.1") + let manifestData = try JSONEncoder().encode(manifest) + + let httpClient = HTTPClient { request, progressHandler in + guard case .download(let fileSystem, let destination) = request.kind else { + throw StringError("invalid request \(request.kind)") + } + + if request.url == "https://github.com/dschaefer2/swift-syntax/releases/download/600.0.1/\(self.swiftVersion)-manifest.json" { + try fileSystem.writeFileContents(destination, data: manifestData) + return .okay() + } else if request.url == "https://github.com/dschaefer2/swift-syntax/releases/download/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip" { + try fileSystem.writeFileContents(destination, data: artifact) + return .okay() + } else { + // make sure it's the updated one + XCTAssertEqual( + request.url, + "https://github.com/dschaefer2/swift-syntax/releases/download/601.0.0/\(self.swiftVersion)-manifest.json" + ) + return .notFound() + } + } + + let archiver = MockArchiver(handler: { _, archivePath, destination, completion in + XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) + XCTAssertEqual(destination.pathString, "/tmp/ws/.build/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64".fixwin) + completion(.success(())) + }) + + let workspace = try await MockWorkspace( + sandbox: sandbox, + fileSystem: fs, + roots: [ + rootPackage + ], + packages: [ + swiftSyntax + ], + prebuiltsManager: .init( + httpClient: httpClient, + archiver: archiver + ), + customHostTriple: Triple("arm64-apple-macosx15.0") + ) + + try await workspace.checkPackageGraph(roots: [rootPackage.name]) { modulesGraph, diagnostics in + XCTAssertTrue(diagnostics.filter({ $0.severity == .error || $0.severity == .warning }).isEmpty) + let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: true) + try checkSettings(rootPackage, "FooTests", usePrebuilt: true) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) + } + + // Change the version of swift syntax to one that doesn't have prebuilts + try workspace.closeWorkspace(resetState: false, resetResolvedFile: false) + let key = MockManifestLoader.Key(url: sandbox.appending(components: "roots", rootPackage.name).pathString) + let oldManifest = try XCTUnwrap(workspace.manifestLoader.manifests[key]) + let oldSCM: PackageDependency.SourceControl + if case let .sourceControl(scm) = oldManifest.dependencies[0] { + oldSCM = scm + } else { + XCTFail("not source control") + return + } + let newDep = PackageDependency.sourceControl( + identity: oldSCM.identity, + nameForTargetDependencyResolutionOnly: oldSCM.nameForTargetDependencyResolutionOnly, + location: oldSCM.location, + requirement: .exact(try XCTUnwrap(Version("601.0.0"))), + productFilter: oldSCM.productFilter + ) + let newManifest = oldManifest.with(dependencies: [newDep]) + workspace.manifestLoader.manifests[key] = newManifest + + try await workspace.checkPackageGraph(roots: [rootPackage.name]) { modulesGraph, diagnostics in + XCTAssertTrue(diagnostics.filter({ $0.severity == .error || $0.severity == .warning }).isEmpty) + let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) + } + + // Change it back + try workspace.closeWorkspace(resetState: false, resetResolvedFile: false) + workspace.manifestLoader.manifests[key] = oldManifest + + try await workspace.checkPackageGraph(roots: [rootPackage.name]) { modulesGraph, diagnostics in + XCTAssertTrue(diagnostics.filter({ $0.severity == .error || $0.severity == .warning }).isEmpty) + let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: true) + try checkSettings(rootPackage, "FooTests", usePrebuilt: true) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) + } + } + + func testSSHURL() async throws { + let sandbox = AbsolutePath("/tmp/ws") + let fs = InMemoryFileSystem() + + let artifact = Data() + let (manifest, rootPackage, swiftSyntax) = try initData(artifact: artifact, swiftSyntaxVersion: "600.0.1", swiftSyntaxURL: "git@github.com:swiftlang/swift-syntax.git") + let manifestData = try JSONEncoder().encode(manifest) + let httpClient = HTTPClient { request, progressHandler in guard case .download(let fileSystem, let destination) = request.kind else { throw StringError("invalid request \(request.kind)") @@ -141,7 +308,7 @@ final class PrebuiltsTests: XCTestCase { } let archiver = MockArchiver(handler: { _, archivePath, destination, completion in - XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) + XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) XCTAssertEqual(destination.pathString, "/tmp/ws/.build/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64".fixwin) completion(.success(())) }) @@ -165,10 +332,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: true) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: true) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: true) + try checkSettings(rootPackage, "FooTests", usePrebuilt: true) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -177,7 +344,7 @@ final class PrebuiltsTests: XCTestCase { let fs = InMemoryFileSystem() let artifact = Data() - let cacheFile = try AbsolutePath(validating: "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip") + let cacheFile = try AbsolutePath(validating: "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip") try fs.writeFileContents(cacheFile, data: artifact) let (manifest, rootPackage, swiftSyntax) = try initData(artifact: artifact, swiftSyntaxVersion: "600.0.1") @@ -202,7 +369,7 @@ final class PrebuiltsTests: XCTestCase { } let archiver = MockArchiver(handler: { _, archivePath, destination, completion in - XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) + XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) XCTAssertEqual(destination.pathString, "/tmp/ws/.build/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64".fixwin) completion(.success(())) }) @@ -226,10 +393,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: true) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: true) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: true) + try checkSettings(rootPackage, "FooTests", usePrebuilt: true) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -272,10 +439,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: false) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: false) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -325,10 +492,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: false) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: false) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -372,12 +539,11 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: false) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: false) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } - } func testBadChecksumHttp() async throws { @@ -431,10 +597,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: false) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: false) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -468,7 +634,7 @@ final class PrebuiltsTests: XCTestCase { } let archiver = MockArchiver(handler: { _, archivePath, destination, completion in - XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) + XCTAssertEqual(archivePath.pathString, "/home/user/caches/org.swift.swiftpm/prebuilts/swift-syntax/600.0.1/\(self.swiftVersion)-MacroSupport-macos_aarch64.zip".fixwin) XCTAssertEqual(destination.pathString, "/tmp/ws/.build/prebuilts/swift-syntax/\(self.swiftVersion)-MacroSupport-macos_aarch64".fixwin) completion(.success(())) }) @@ -492,10 +658,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: true) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: true) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: true) + try checkSettings(rootPackage, "FooTests", usePrebuilt: true) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -545,10 +711,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: false) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: false) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } @@ -574,10 +740,10 @@ final class PrebuiltsTests: XCTestCase { try await workspace.checkPackageGraph(roots: ["Foo"]) { modulesGraph, diagnostics in XCTAssertTrue(diagnostics.filter({ $0.severity == .error }).isEmpty) let rootPackage = try XCTUnwrap(modulesGraph.rootPackages.first) - let macroTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooMacros" })) - try checkSettings(macroTarget, usePrebuilt: false) - let testTarget = try XCTUnwrap(rootPackage.underlying.modules.first(where: { $0.name == "FooTests" })) - try checkSettings(testTarget, usePrebuilt: false) + try checkSettings(rootPackage, "FooMacros", usePrebuilt: false) + try checkSettings(rootPackage, "FooTests", usePrebuilt: false) + try checkSettings(rootPackage, "Foo", usePrebuilt: false) + try checkSettings(rootPackage, "FooClient", usePrebuilt: false) } } }