diff --git a/Benchmarks/Benchmarks/PackageGraphBenchmarks/PackageGraphBenchmarks.swift b/Benchmarks/Benchmarks/PackageGraphBenchmarks/PackageGraphBenchmarks.swift index bab1f4af582..194251a60ab 100644 --- a/Benchmarks/Benchmarks/PackageGraphBenchmarks/PackageGraphBenchmarks.swift +++ b/Benchmarks/Benchmarks/PackageGraphBenchmarks/PackageGraphBenchmarks.swift @@ -65,7 +65,7 @@ let benchmarks = { let workspace = try Workspace(fileSystem: localFileSystem, location: .init(forRootPackage: path, fileSystem: localFileSystem)) for _ in benchmark.scaledIterations { - try workspace.loadPackageGraph(rootPath: path, observabilityScope: ObservabilitySystem.NOOP) + try await workspace.loadPackageGraph(rootPath: path, observabilityScope: ObservabilitySystem.NOOP) } } diff --git a/Sources/Basics/CMakeLists.txt b/Sources/Basics/CMakeLists.txt index 5a9c35891ea..d20af712c33 100644 --- a/Sources/Basics/CMakeLists.txt +++ b/Sources/Basics/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(Basics DispatchTimeInterval+Extensions.swift EnvironmentVariables.swift Errors.swift + GraphAlgorithms.swift FileSystem/AbsolutePath.swift FileSystem/FileSystem+Extensions.swift FileSystem/InMemoryFileSystem.swift diff --git a/Sources/Basics/Concurrency/ConcurrencyHelpers.swift b/Sources/Basics/Concurrency/ConcurrencyHelpers.swift index 7927d2e2dec..6967b943c34 100644 --- a/Sources/Basics/Concurrency/ConcurrencyHelpers.swift +++ b/Sources/Basics/Concurrency/ConcurrencyHelpers.swift @@ -81,3 +81,17 @@ public func safe_async(_ body: @escaping @Sendable (@escaping (Result( + transform: @escaping (Element) async throws -> NewElement + ) async rethrows -> [NewElement] { + try await withThrowingTaskGroup(of: NewElement.self) { group in + for element in self { + group.addTask { try await transform(element) } + } + + return try await group.reduce(into: []) { $0.append($1) } + } + } +} diff --git a/Sources/Basics/GraphAlgorithms.swift b/Sources/Basics/GraphAlgorithms.swift new file mode 100644 index 00000000000..cbc49a3f634 --- /dev/null +++ b/Sources/Basics/GraphAlgorithms.swift @@ -0,0 +1,121 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See http://swift.org/LICENSE.txt for license information + See http://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import OrderedCollections + +package func findCycle( + _ nodes: [T], + successors: (T) async throws -> [T] +) async rethrows -> (path: [T], cycle: [T])? { + // Ordered set to hold the current traversed path. + var path = OrderedSet() + var validNodes = Set() + + // Function to visit nodes recursively. + // FIXME: Convert to stack. + func visit(_ node: T, _ successors: (T) async throws -> [T]) async rethrows -> (path: [T], cycle: [T])? { + if validNodes.contains(node) { return nil } + + // If this node is already in the current path then we have found a cycle. + if !path.append(node).inserted { + let index = path.firstIndex(of: node)! + return (Array(path[path.startIndex..( + _ nodes: [T], successors: (T) async throws -> [T] +) async throws -> [T] { + // Implements a topological sort via recursion and reverse postorder DFS. + func visit( + _ node: T, + _ stack: inout OrderedSet, + _ visited: inout Set, + _ result: inout [T], + _ successors: (T) async throws -> [T] + ) async throws { + // Mark this node as visited -- we are done if it already was. + if !visited.insert(node).inserted { + return + } + + // Otherwise, visit each adjacent node. + for succ in try await successors(node) { + guard stack.append(succ).inserted else { + // If the successor is already in this current stack, we have found a cycle. + // + // FIXME: We could easily include information on the cycle we found here. + throw GraphError.unexpectedCycle + } + // FIXME: This should use a stack not recursion. + try await visit(succ, &stack, &visited, &result, successors) + let popped = stack.removeLast() + assert(popped == succ) + } + + // Add to the result. + result.append(node) + } + + var visited = Set() + var result = [T]() + var stack = OrderedSet() + for node in nodes { + precondition(stack.isEmpty) + stack.append(node) + try await visit(node, &stack, &visited, &result, successors) + let popped = stack.removeLast() + assert(popped == node) + } + + return result.reversed() +} diff --git a/Sources/Basics/Observability.swift b/Sources/Basics/Observability.swift index 8a5afc23a70..eb64ce72816 100644 --- a/Sources/Basics/Observability.swift +++ b/Sources/Basics/Observability.swift @@ -250,6 +250,20 @@ extension DiagnosticsEmitterProtocol { } } + /// trap an async throwing closure, emitting diagnostics on error and returning the value returned by the closure + public func trap(_ closure: () async throws -> T) async -> T? { + do { + return try await closure() + } catch Diagnostics.fatalError { + // FIXME: (diagnostics) deprecate this with Diagnostics.fatalError + return nil + } catch { + self.emit(error) + return nil + } + } + + /// trap a throwing closure, emitting diagnostics on error and returning boolean representing success @discardableResult public func trap(_ closure: () throws -> Void) -> Bool { @@ -265,6 +279,21 @@ extension DiagnosticsEmitterProtocol { } } + /// trap an async throwing closure, emitting diagnostics on error and returning boolean representing success + @discardableResult + public func trap(_ closure: () async throws -> Void) async -> Bool { + do { + try await closure() + return true + } catch Diagnostics.fatalError { + // FIXME: (diagnostics) deprecate this with Diagnostics.fatalError + return false + } catch { + self.emit(error) + return false + } + } + /// If `underlyingError` is not `nil`, its human-readable description is interpolated with `message`, /// otherwise `message` itself is returned. private func makeMessage(from message: String, underlyingError: Error?) -> String { diff --git a/Sources/Commands/PackageCommands/APIDiff.swift b/Sources/Commands/PackageCommands/APIDiff.swift index acb38e87ed0..489ef5cfd14 100644 --- a/Sources/Commands/PackageCommands/APIDiff.swift +++ b/Sources/Commands/PackageCommands/APIDiff.swift @@ -32,7 +32,7 @@ struct DeprecatedAPIDiff: ParsableCommand { } } -struct APIDiff: SwiftCommand { +struct APIDiff: AsyncSwiftCommand { static let configuration = CommandConfiguration( commandName: "diagnose-api-breaking-changes", abstract: "Diagnose API-breaking changes to Swift modules in a package", @@ -74,7 +74,7 @@ struct APIDiff: SwiftCommand { @Flag(help: "Regenerate the API baseline, even if an existing one is available.") var regenerateBaseline: Bool = false - func run(_ swiftCommandState: SwiftCommandState) throws { + func run(_ swiftCommandState: SwiftCommandState) async throws { let apiDigesterPath = try swiftCommandState.getTargetToolchain().getSwiftAPIDigester() let apiDigesterTool = SwiftAPIDigester(fileSystem: swiftCommandState.fileSystem, tool: apiDigesterPath) @@ -104,7 +104,7 @@ struct APIDiff: SwiftCommand { observabilityScope: swiftCommandState.observabilityScope ) - let baselineDir = try baselineDumper.emitAPIBaseline( + let baselineDir = try await baselineDumper.emitAPIBaseline( for: modulesToDiff, at: overrideBaselineDir, force: regenerateBaseline, diff --git a/Sources/Commands/PackageCommands/EditCommands.swift b/Sources/Commands/PackageCommands/EditCommands.swift index ff199a05101..a015c5873b8 100644 --- a/Sources/Commands/PackageCommands/EditCommands.swift +++ b/Sources/Commands/PackageCommands/EditCommands.swift @@ -16,7 +16,7 @@ import CoreCommands import SourceControl extension SwiftPackageCommand { - struct Edit: SwiftCommand { + struct Edit: AsyncSwiftCommand { static let configuration = CommandConfiguration( abstract: "Put a package in editable mode") @@ -35,12 +35,12 @@ extension SwiftPackageCommand { @Argument(help: "The name of the package to edit") var packageName: String - func run(_ swiftCommandState: SwiftCommandState) throws { - try swiftCommandState.resolve() + func run(_ swiftCommandState: SwiftCommandState) async throws { + try await swiftCommandState.resolve() let workspace = try swiftCommandState.getActiveWorkspace() // Put the dependency in edit mode. - workspace.edit( + await workspace.edit( packageName: packageName, path: path, revision: revision, @@ -50,7 +50,7 @@ extension SwiftPackageCommand { } } - struct Unedit: SwiftCommand { + struct Unedit: AsyncSwiftCommand { static let configuration = CommandConfiguration( abstract: "Remove a package from editable mode") @@ -64,11 +64,11 @@ extension SwiftPackageCommand { @Argument(help: "The name of the package to unedit") var packageName: String - func run(_ swiftCommandState: SwiftCommandState) throws { - try swiftCommandState.resolve() + func run(_ swiftCommandState: SwiftCommandState) async throws { + try await swiftCommandState.resolve() let workspace = try swiftCommandState.getActiveWorkspace() - try workspace.unedit( + try await workspace.unedit( packageName: packageName, forceRemove: shouldForceRemove, root: swiftCommandState.getWorkspaceRoot(), diff --git a/Sources/Commands/PackageCommands/InstalledPackages.swift b/Sources/Commands/PackageCommands/InstalledPackages.swift index 0ad9603eb7b..5303579bebf 100644 --- a/Sources/Commands/PackageCommands/InstalledPackages.swift +++ b/Sources/Commands/PackageCommands/InstalledPackages.swift @@ -17,7 +17,7 @@ import PackageModel import TSCBasic extension SwiftPackageCommand { - struct Install: SwiftCommand { + struct Install: AsyncSwiftCommand { static let configuration = CommandConfiguration( commandName: "experimental-install", abstract: "Offers the ability to install executable products of the current package." @@ -29,7 +29,7 @@ extension SwiftPackageCommand { @Option(help: "The name of the executable product to install") var product: String? - func run(_ tool: SwiftCommandState) throws { + func run(_ tool: SwiftCommandState) async throws { let swiftpmBinDir = try tool.fileSystem.getOrCreateSwiftPMInstalledBinariesDirectory() let env = ProcessInfo.processInfo.environment @@ -48,7 +48,7 @@ extension SwiftPackageCommand { let workspace = try tool.getActiveWorkspace() let packageRoot = try tool.getPackageRoot() - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootPath: packageRoot, observabilityScope: tool.observabilityScope ) diff --git a/Sources/Commands/PackageCommands/Resolve.swift b/Sources/Commands/PackageCommands/Resolve.swift index 2107e60bc67..c6147c675d6 100644 --- a/Sources/Commands/PackageCommands/Resolve.swift +++ b/Sources/Commands/PackageCommands/Resolve.swift @@ -29,7 +29,7 @@ extension SwiftPackageCommand { var packageName: String? } - struct Resolve: SwiftCommand { + struct Resolve: AsyncSwiftCommand { static let configuration = CommandConfiguration( abstract: "Resolve package dependencies") @@ -39,11 +39,11 @@ extension SwiftPackageCommand { @OptionGroup() var resolveOptions: ResolveOptions - func run(_ swiftCommandState: SwiftCommandState) throws { + func run(_ swiftCommandState: SwiftCommandState) async throws { // If a package is provided, use that to resolve the dependencies. if let packageName = resolveOptions.packageName { let workspace = try swiftCommandState.getActiveWorkspace() - try workspace.resolve( + try await workspace.resolve( packageName: packageName, root: swiftCommandState.getWorkspaceRoot(), version: resolveOptions.version, @@ -56,12 +56,12 @@ extension SwiftPackageCommand { } } else { // Otherwise, run a normal resolve. - try swiftCommandState.resolve() + try await swiftCommandState.resolve() } } } - struct Fetch: SwiftCommand { + struct Fetch: AsyncSwiftCommand { static let configuration = CommandConfiguration(shouldDisplay: false) @OptionGroup(visibility: .hidden) @@ -70,11 +70,11 @@ extension SwiftPackageCommand { @OptionGroup() var resolveOptions: ResolveOptions - func run(_ swiftCommandState: SwiftCommandState) throws { + func run(_ swiftCommandState: SwiftCommandState) async throws { swiftCommandState.observabilityScope.emit(warning: "'fetch' command is deprecated; use 'resolve' instead") let resolveCommand = Resolve(globalOptions: _globalOptions, resolveOptions: _resolveOptions) - try resolveCommand.run(swiftCommandState) + try await resolveCommand.run(swiftCommandState) } } } diff --git a/Sources/Commands/PackageCommands/Update.swift b/Sources/Commands/PackageCommands/Update.swift index 90622a8ccdb..633bfa3274b 100644 --- a/Sources/Commands/PackageCommands/Update.swift +++ b/Sources/Commands/PackageCommands/Update.swift @@ -18,7 +18,7 @@ import PackageGraph import Workspace extension SwiftPackageCommand { - struct Update: SwiftCommand { + struct Update: AsyncSwiftCommand { static let configuration = CommandConfiguration( abstract: "Update package dependencies") @@ -32,10 +32,10 @@ extension SwiftPackageCommand { @Argument(help: "The packages to update") var packages: [String] = [] - func run(_ swiftCommandState: SwiftCommandState) throws { + func run(_ swiftCommandState: SwiftCommandState) async throws { let workspace = try swiftCommandState.getActiveWorkspace() - let changes = try workspace.updateDependencies( + let changes = try await workspace.updateDependencies( root: swiftCommandState.getWorkspaceRoot(), packages: packages, dryRun: dryRun, diff --git a/Sources/Commands/SwiftBuildCommand.swift b/Sources/Commands/SwiftBuildCommand.swift index 0b6567cfed8..badc3c908ee 100644 --- a/Sources/Commands/SwiftBuildCommand.swift +++ b/Sources/Commands/SwiftBuildCommand.swift @@ -180,7 +180,7 @@ public struct SwiftBuildCommand: AsyncSwiftCommand { library: library ) } - for library in try options.testLibraryOptions.enabledTestingLibraries(swiftCommandState: swiftCommandState) { + for library in try await options.testLibraryOptions.enabledTestingLibraries(swiftCommandState: swiftCommandState) { updateTestingParameters(of: &productsBuildParameters, library: library) updateTestingParameters(of: &toolsBuildParameters, library: library) try build(swiftCommandState, subset: subset, productsBuildParameters: productsBuildParameters, toolsBuildParameters: toolsBuildParameters) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index c3daf48ec5b..cc6964a9c88 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -235,14 +235,14 @@ public struct SwiftTestCommand: AsyncSwiftCommand { throw TestError.xcodeNotInstalled } - let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: .xctest) + let (productsBuildParameters, _) = try await swiftCommandState.buildParametersForTest(options: self.options, library: .xctest) // Remove test output from prior runs and validate priors. if self.options.enableExperimentalTestOutput && productsBuildParameters.triple.supportsTestSummary { _ = try? localFileSystem.removeFileTree(productsBuildParameters.testOutputPath) } - let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .xctest) + let testProducts = try await buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .xctest) if !self.options.shouldRunInParallel { let xctestArgs = try xctestArgs(for: testProducts, swiftCommandState: swiftCommandState) try await runTestProducts( @@ -365,8 +365,8 @@ public struct SwiftTestCommand: AsyncSwiftCommand { // MARK: - swift-testing private func swiftTestingRun(_ swiftCommandState: SwiftCommandState) async throws { - let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: .swiftTesting) - let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .swiftTesting) + let (productsBuildParameters, _) = try await swiftCommandState.buildParametersForTest(options: self.options, library: .swiftTesting) + let testProducts = try await buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .swiftTesting) let additionalArguments = Array(CommandLine.arguments.dropFirst()) try await runTestProducts( testProducts, @@ -389,13 +389,13 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } if self.options.shouldPrintCodeCovPath { - try printCodeCovPath(swiftCommandState) + try await printCodeCovPath(swiftCommandState) } else if self.options._deprecated_shouldListTests { // backward compatibility 6/2022 for deprecation of flag into a subcommand let command = try List.parse() - try command.run(swiftCommandState) + try await command.run(swiftCommandState) } else { - if try options.testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) { + if try await options.testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) { try await swiftTestingRun(swiftCommandState) } if options.testLibraryOptions.enableXCTestSupport { @@ -502,23 +502,26 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } // Merge all the profraw files to produce a single profdata file. - try mergeCodeCovRawDataFiles(swiftCommandState: swiftCommandState, library: library) + try await mergeCodeCovRawDataFiles(swiftCommandState: swiftCommandState, library: library) - let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let (productsBuildParameters, _) = try await swiftCommandState.buildParametersForTest(options: self.options, library: library) for product in testProducts { // Export the codecov data as JSON. let jsonPath = productsBuildParameters.codeCovAsJSONPath(packageName: rootManifest.displayName) - try exportCodeCovAsJSON(to: jsonPath, testBinary: product.binaryPath, swiftCommandState: swiftCommandState, library: library) + try await exportCodeCovAsJSON(to: jsonPath, testBinary: product.binaryPath, swiftCommandState: swiftCommandState, library: library) } } /// Merges all profraw profiles in codecoverage directory into default.profdata file. - private func mergeCodeCovRawDataFiles(swiftCommandState: SwiftCommandState, library: BuildParameters.Testing.Library) throws { + private func mergeCodeCovRawDataFiles( + swiftCommandState: SwiftCommandState, + library: BuildParameters.Testing.Library + ) async throws { // Get the llvm-prof tool. let llvmProf = try swiftCommandState.getTargetToolchain().getLLVMProf() // Get the profraw files. - let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let (productsBuildParameters, _) = try await swiftCommandState.buildParametersForTest(options: self.options, library: library) let codeCovFiles = try swiftCommandState.fileSystem.getDirectoryContents(productsBuildParameters.codeCovPath) // Construct arguments for invoking the llvm-prof tool. @@ -531,7 +534,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } args += ["-o", productsBuildParameters.codeCovDataFile.pathString] - try TSCBasic.Process.checkNonZeroExit(arguments: args) + try await TSCBasic.Process.checkNonZeroExit(arguments: args) } /// Exports profdata as a JSON file. @@ -540,17 +543,17 @@ public struct SwiftTestCommand: AsyncSwiftCommand { testBinary: AbsolutePath, swiftCommandState: SwiftCommandState, library: BuildParameters.Testing.Library - ) throws { + ) async throws { // Export using the llvm-cov tool. let llvmCov = try swiftCommandState.getTargetToolchain().getLLVMCov() - let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let (productsBuildParameters, _) = try await swiftCommandState.buildParametersForTest(options: self.options, library: library) let args = [ llvmCov.pathString, "export", "-instr-profile=\(productsBuildParameters.codeCovDataFile)", testBinary.pathString ] - let result = try TSCBasic.Process.popen(arguments: args) + let result = try await TSCBasic.Process.popen(arguments: args) if result.exitStatus != .terminated(code: 0) { let output = try result.utf8Output() + result.utf8stderrOutput() @@ -565,8 +568,8 @@ public struct SwiftTestCommand: AsyncSwiftCommand { private func buildTestsIfNeeded( swiftCommandState: SwiftCommandState, library: BuildParameters.Testing.Library - ) throws -> [BuiltTestProduct] { - let (productsBuildParameters, toolsBuildParameters) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + ) async throws -> [BuiltTestProduct] { + let (productsBuildParameters, toolsBuildParameters) = try await swiftCommandState.buildParametersForTest(options: self.options, library: library) return try Commands.buildTestsIfNeeded( swiftCommandState: swiftCommandState, productsBuildParameters: productsBuildParameters, @@ -607,16 +610,13 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } extension SwiftTestCommand { - func printCodeCovPath(_ swiftCommandState: SwiftCommandState) throws { + func printCodeCovPath(_ swiftCommandState: SwiftCommandState) async throws { let workspace = try swiftCommandState.getActiveWorkspace() let root = try swiftCommandState.getWorkspaceRoot() - let rootManifests = try temp_await { - workspace.loadRootManifests( - packages: root.packages, - observabilityScope: swiftCommandState.observabilityScope, - completion: $0 - ) - } + let rootManifests = try await workspace.loadRootManifests( + packages: root.packages, + observabilityScope: swiftCommandState.observabilityScope + ) guard let rootManifest = rootManifests.values.first else { throw StringError("invalid manifests at \(root.packages)") } @@ -638,7 +638,7 @@ extension SwiftTestCommand { } } - struct List: SwiftCommand { + struct List: AsyncSwiftCommand { static let configuration = CommandConfiguration( abstract: "Lists test methods in specifier format" ) @@ -731,8 +731,8 @@ extension SwiftTestCommand { // MARK: - Common implementation - func run(_ swiftCommandState: SwiftCommandState) throws { - if try testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) { + func run(_ swiftCommandState: SwiftCommandState) async throws { + if try await testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) { try swiftTestingRun(swiftCommandState) } if testLibraryOptions.enableXCTestSupport { @@ -1302,7 +1302,7 @@ extension SwiftCommandState { func buildParametersForTest( options: TestCommandOptions, library: BuildParameters.Testing.Library - ) throws -> (productsBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters) { + ) async throws -> (productsBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters) { var result = try self.buildParametersForTest( enableCodeCoverage: options.enableCodeCoverage, enableTestability: options.enableTestableImports, @@ -1310,7 +1310,7 @@ extension SwiftCommandState { experimentalTestOutput: options.enableExperimentalTestOutput, library: library ) - if try options.testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: self) { + if try await options.testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: self) { result.productsBuildParameters.flags.swiftCompilerFlags += ["-DSWIFT_PM_SUPPORTS_SWIFT_TESTING"] result.toolsBuildParameters.flags.swiftCompilerFlags += ["-DSWIFT_PM_SUPPORTS_SWIFT_TESTING"] } diff --git a/Sources/Commands/Utilities/APIDigester.swift b/Sources/Commands/Utilities/APIDigester.swift index 7a8b5f4dd6b..e8d3963d1b1 100644 --- a/Sources/Commands/Utilities/APIDigester.swift +++ b/Sources/Commands/Utilities/APIDigester.swift @@ -74,7 +74,7 @@ struct APIDigesterBaselineDumper { force: Bool, logLevel: Basics.Diagnostic.Severity, swiftCommandState: SwiftCommandState - ) throws -> AbsolutePath { + ) async throws -> AbsolutePath { var modulesToDiff = modulesToDiff let apiDiffDir = productsBuildParameters.apiDiff let baselineDir = (baselineDir ?? apiDiffDir).appending(component: baselineRevision.identifier) @@ -118,7 +118,7 @@ struct APIDigesterBaselineDumper { cancellator: swiftCommandState.cancellator ) - let graph = try workspace.loadPackageGraph( + let graph = try await workspace.loadPackageGraph( rootPath: baselinePackageRoot, observabilityScope: self.observabilityScope ) diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index 882ab69afdb..c981564f599 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -15,7 +15,6 @@ import ArgumentParser import var Basics.localFileSystem import struct Basics.AbsolutePath import struct Basics.Triple -import func Basics.temp_await import struct Foundation.URL @@ -590,7 +589,7 @@ public struct TestLibraryOptions: ParsableArguments { /// Whether to enable support for swift-testing. public func enableSwiftTestingLibrarySupport( swiftCommandState: SwiftCommandState - ) throws -> Bool { + ) async throws -> Bool { // Honor the user's explicit command-line selection, if any. if let callerSuppliedValue = explicitlyEnableSwiftTestingLibrarySupport { return callerSuppliedValue @@ -599,13 +598,10 @@ public struct TestLibraryOptions: ParsableArguments { // If the active package has a dependency on swift-testing, automatically enable support for it so that extra steps are not needed. let workspace = try swiftCommandState.getActiveWorkspace() let root = try swiftCommandState.getWorkspaceRoot() - let rootManifests = try temp_await { - workspace.loadRootManifests( - packages: root.packages, - observabilityScope: swiftCommandState.observabilityScope, - completion: $0 - ) - } + let rootManifests = try await workspace.loadRootManifests( + packages: root.packages, + observabilityScope: swiftCommandState.observabilityScope + ) // Is swift-testing among the dependencies of the package being built? // If so, enable support. @@ -637,13 +633,13 @@ public struct TestLibraryOptions: ParsableArguments { /// Get the set of enabled testing libraries. public func enabledTestingLibraries( swiftCommandState: SwiftCommandState - ) throws -> Set { + ) async throws -> Set { var result = Set() if enableXCTestSupport { result.insert(.xctest) } - if try enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) { + if try await enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) { result.insert(.swiftTesting) } diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index 7d8e406a575..f022394eb4a 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +import _Concurrency import ArgumentParser import Basics import Dispatch @@ -478,15 +479,20 @@ public final class SwiftCommandState { return workspace } - public func getRootPackageInformation() throws -> (dependencies: [PackageIdentity: [PackageIdentity]], targets: [PackageIdentity: [String]]) { + package func getRootPackageInformation() throws -> (dependencies: [PackageIdentity: [PackageIdentity]], targets: [PackageIdentity: [String]]) { let workspace = try self.getActiveWorkspace() let root = try self.getWorkspaceRoot() - let rootManifests = try temp_await { - workspace.loadRootManifests( - packages: root.packages, - observabilityScope: self.observabilityScope, - completion: $0 - ) + let rootManifests = try temp_await { (completion: @escaping (Result<[AbsolutePath: Manifest], Error>) -> ()) in + Task { + do { + try await completion(.success(workspace.loadRootManifests( + packages: root.packages, + observabilityScope: self.observabilityScope + ))) + } catch { + completion(.failure(error)) + } + } } var identities = [PackageIdentity: [PackageIdentity]]() @@ -585,11 +591,11 @@ public final class SwiftCommandState { } /// Resolve the dependencies. - public func resolve() throws { + package func resolve() async throws { let workspace = try getActiveWorkspace() let root = try getWorkspaceRoot() - try workspace.resolve( + try await workspace.resolve( root: root, forceResolution: false, forceResolvedVersions: options.resolver.forceResolvedVersions, @@ -612,12 +618,10 @@ public final class SwiftCommandState { public func loadPackageGraph( explicitProduct: String? = nil, testEntryPointPath: AbsolutePath? = nil - ) throws -> ModulesGraph { + ) async throws -> ModulesGraph { do { - let workspace = try getActiveWorkspace() - // Fetch and load the package graph. - let graph = try workspace.loadPackageGraph( + let graph = try await workspace.loadPackageGraph( rootInput: getWorkspaceRoot(), explicitProduct: explicitProduct, forceResolvedVersions: options.resolver.forceResolvedVersions, diff --git a/Sources/PackageGraph/PackageContainer.swift b/Sources/PackageGraph/PackageContainer.swift index 27a680c21d0..5772a310eb9 100644 --- a/Sources/PackageGraph/PackageContainer.swift +++ b/Sources/PackageGraph/PackageContainer.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +import _Concurrency import Basics import Dispatch import PackageModel @@ -35,12 +36,12 @@ import struct TSCUtility.Version /// This is also designed in such a way to extend naturally to multiple packages /// being contained within a single repository, should we choose to support that /// later. -public protocol PackageContainer { +public protocol PackageContainer: Actor { /// The identifier for the package. - var package: PackageReference { get } + nonisolated var package: PackageReference { get } - var shouldInvalidatePinnedVersions: Bool { get } + nonisolated var shouldInvalidatePinnedVersions: Bool { get } /// Returns true if the tools version is compatible at the given version. func isToolsVersionCompatible(at version: Version) -> Bool @@ -107,7 +108,7 @@ extension PackageContainer { try self.versionsAscending().reversed() } - public var shouldInvalidatePinnedVersions: Bool { + public nonisolated var shouldInvalidatePinnedVersions: Bool { return true } } diff --git a/Sources/PackageGraph/Resolution/DependencyResolutionNode.swift b/Sources/PackageGraph/Resolution/DependencyResolutionNode.swift index ffadb471bbd..3cb213f7a2e 100644 --- a/Sources/PackageGraph/Resolution/DependencyResolutionNode.swift +++ b/Sources/PackageGraph/Resolution/DependencyResolutionNode.swift @@ -61,7 +61,7 @@ public enum DependencyResolutionNode { case root(package: PackageReference) /// The package. - public var package: PackageReference { + package var package: PackageReference { switch self { case .empty(let package), .product(_, let package), .root(let package): return package @@ -69,7 +69,7 @@ public enum DependencyResolutionNode { } /// The name of the specific product if the node is a product node, otherwise `nil`. - public var specificProduct: String? { + package var specificProduct: String? { switch self { case .empty, .root: return nil @@ -79,7 +79,7 @@ public enum DependencyResolutionNode { } /// Assembles the product filter to use on the manifest for this node to determine its dependencies. - public var productFilter: ProductFilter { + package var productFilter: ProductFilter { switch self { case .empty: return .specific([]) @@ -93,7 +93,7 @@ public enum DependencyResolutionNode { /// Returns the dependency that a product has on its own package, if relevant. /// /// This is the constraint that requires all products from a package resolve to the same version. - internal func versionLock(version: Version) -> PackageContainerConstraint? { + func versionLock(version: Version) -> PackageContainerConstraint? { // Don’t create a version lock for anything but a product. guard specificProduct != nil else { return nil } return PackageContainerConstraint( diff --git a/Sources/PackageGraph/Resolution/DependencyResolverBinding.swift b/Sources/PackageGraph/Resolution/DependencyResolverBinding.swift index 64af5af37a7..4eacdd1d5b2 100644 --- a/Sources/PackageGraph/Resolution/DependencyResolverBinding.swift +++ b/Sources/PackageGraph/Resolution/DependencyResolverBinding.swift @@ -13,8 +13,8 @@ import enum PackageModel.ProductFilter import struct PackageModel.PackageReference -public struct DependencyResolverBinding { - public let package: PackageReference - public let boundVersion: BoundVersion - public let products: ProductFilter +package struct DependencyResolverBinding { + package let package: PackageReference + package let boundVersion: BoundVersion + package let products: ProductFilter } diff --git a/Sources/PackageGraph/Resolution/DependencyResolverDelegate.swift b/Sources/PackageGraph/Resolution/DependencyResolverDelegate.swift index d570deb2711..3a574d7ab71 100644 --- a/Sources/PackageGraph/Resolution/DependencyResolverDelegate.swift +++ b/Sources/PackageGraph/Resolution/DependencyResolverDelegate.swift @@ -16,7 +16,7 @@ import PackageModel import struct TSCUtility.Version -public protocol DependencyResolverDelegate { +package protocol DependencyResolverDelegate { func willResolve(term: Term) func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) @@ -28,42 +28,42 @@ public protocol DependencyResolverDelegate { func solved(result: [DependencyResolverBinding]) } -public struct ObservabilityDependencyResolverDelegate: DependencyResolverDelegate { +package struct ObservabilityDependencyResolverDelegate: DependencyResolverDelegate { private let observabilityScope: ObservabilityScope - public init (observabilityScope: ObservabilityScope) { + package init (observabilityScope: ObservabilityScope) { self.observabilityScope = observabilityScope.makeChildScope(description: "DependencyResolver") } - public func willResolve(term: Term) { + package func willResolve(term: Term) { self.debug("resolving '\(term.node.package.identity)'") } - public func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) { + package func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) { self.debug("resolved '\(term.node.package.identity)' @ '\(version)'") } - public func derived(term: Term) { + package func derived(term: Term) { self.debug("derived '\(term.node.package.identity)' requirement '\(term.requirement)'") } - public func conflict(conflict: Incompatibility) { + package func conflict(conflict: Incompatibility) { self.debug("conflict: \(conflict)") } - public func failedToResolve(incompatibility: Incompatibility) { + package func failedToResolve(incompatibility: Incompatibility) { self.debug("failed to resolve '\(incompatibility)'") } - public func satisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility) { + package func satisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility) { self.debug("'\(term)' is satisfied by '\(assignment)', which is caused by '\(assignment.cause?.description ?? "unknown cause")'. new incompatibility: '\(incompatibility)'") } - public func partiallySatisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility, difference: Term) { + package func partiallySatisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility, difference: Term) { self.debug("\(term) is partially satisfied by '\(assignment)', which is caused by '\(assignment.cause?.description ?? "unknown cause")'. new incompatibility \(incompatibility)") } - public func solved(result: [DependencyResolverBinding]) { + package func solved(result: [DependencyResolverBinding]) { for binding in result { self.debug("solved '\(binding.package.identity)' (\(binding.package.locationString)) at '\(binding.boundVersion)'") } @@ -78,39 +78,39 @@ public struct ObservabilityDependencyResolverDelegate: DependencyResolverDelegat public struct MultiplexResolverDelegate: DependencyResolverDelegate { private let underlying: [DependencyResolverDelegate] - public init (_ underlying: [DependencyResolverDelegate]) { + package init (_ underlying: [DependencyResolverDelegate]) { self.underlying = underlying } - public func willResolve(term: Term) { + package func willResolve(term: Term) { underlying.forEach { $0.willResolve(term: term) } } - public func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) { + package func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) { underlying.forEach { $0.didResolve(term: term, version: version, duration: duration) } } - public func derived(term: Term) { + package func derived(term: Term) { underlying.forEach { $0.derived(term: term) } } - public func conflict(conflict: Incompatibility) { + package func conflict(conflict: Incompatibility) { underlying.forEach { $0.conflict(conflict: conflict) } } - public func satisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility) { + package func satisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility) { underlying.forEach { $0.satisfied(term: term, by: assignment, incompatibility: incompatibility) } } - public func partiallySatisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility, difference: Term) { + package func partiallySatisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility, difference: Term) { underlying.forEach { $0.partiallySatisfied(term: term, by: assignment, incompatibility: incompatibility, difference: difference) } } - public func failedToResolve(incompatibility: Incompatibility) { + package func failedToResolve(incompatibility: Incompatibility) { underlying.forEach { $0.failedToResolve(incompatibility: incompatibility) } } - public func solved(result: [DependencyResolverBinding]) { + package func solved(result: [DependencyResolverBinding]) { underlying.forEach { $0.solved(result: result) } } diff --git a/Sources/PackageGraph/Resolution/DependencyResolverError.swift b/Sources/PackageGraph/Resolution/DependencyResolverError.swift index 153031c41d4..7b66e8d8dcf 100644 --- a/Sources/PackageGraph/Resolution/DependencyResolverError.swift +++ b/Sources/PackageGraph/Resolution/DependencyResolverError.swift @@ -12,13 +12,13 @@ import Foundation -public enum DependencyResolverError: Error, Equatable { +package enum DependencyResolverError: Error, Equatable { /// A revision-based dependency contains a local package dependency. case revisionDependencyContainsLocalPackage(dependency: String, localPackage: String) } extension DependencyResolverError: CustomStringConvertible { - public var description: String { + package var description: String { switch self { case .revisionDependencyContainsLocalPackage(let dependency, let localPackage): return "package '\(dependency)' is required using a revision-based requirement and it depends on local package '\(localPackage)', which is not supported" diff --git a/Sources/PackageGraph/Resolution/PubGrub/Assignment.swift b/Sources/PackageGraph/Resolution/PubGrub/Assignment.swift index e6181a61cdd..ec7ded2fdad 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/Assignment.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/Assignment.swift @@ -18,11 +18,11 @@ /// at or before it in the partial solution that caused it to be derived. This /// is later used during conflict resolution to figure out how far back to jump /// when a conflict is found. -public struct Assignment: Equatable { - public let term: Term - public let decisionLevel: Int - public let cause: Incompatibility? - public let isDecision: Bool +package struct Assignment: Equatable { + package let term: Term + package let decisionLevel: Int + package let cause: Incompatibility? + package let isDecision: Bool private init( term: Term, @@ -37,7 +37,7 @@ public struct Assignment: Equatable { } /// An assignment made during decision making. - public static func decision(_ term: Term, decisionLevel: Int) -> Assignment { + package static func decision(_ term: Term, decisionLevel: Int) -> Assignment { assert(term.requirement.isExact, "Cannot create a decision assignment with a non-exact version selection: \(term.requirement)") return self.init( @@ -50,7 +50,7 @@ public struct Assignment: Equatable { /// An assignment derived from previously known incompatibilities during /// unit propagation. - public static func derivation( + package static func derivation( _ term: Term, cause: Incompatibility, decisionLevel: Int @@ -65,7 +65,7 @@ public struct Assignment: Equatable { } extension Assignment: CustomStringConvertible { - public var description: String { + package var description: String { switch self.isDecision { case true: return "[Decision \(self.decisionLevel): \(self.term)]" diff --git a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift index c20021d3642..77180118e2a 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift @@ -62,7 +62,14 @@ final class ContainerProvider { return container } + func getContainer(for package: PackageReference) async throws -> PubGrubPackageContainer { + try await safe_async { + self.getContainer(for: package, completion: $0) + } + } + /// Get the container for the given identifier, loading it if necessary. + @available(*, noasync, message: "Use the async alternative") func getContainer( for package: PackageReference, completion: @escaping (Result) -> Void diff --git a/Sources/PackageGraph/Resolution/PubGrub/DiagnosticReportBuilder.swift b/Sources/PackageGraph/Resolution/PubGrub/DiagnosticReportBuilder.swift index 0a5289587e2..457dfb10a68 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/DiagnosticReportBuilder.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/DiagnosticReportBuilder.swift @@ -25,7 +25,7 @@ struct DiagnosticReportBuilder { self.provider = provider } - mutating func makeErrorReport(for rootCause: Incompatibility) throws -> String { + mutating func makeErrorReport(for rootCause: Incompatibility) async throws -> String { /// Populate `derivations`. func countDerivations(_ i: Incompatibility) { self.derivations[i, default: 0] += 1 @@ -38,12 +38,12 @@ struct DiagnosticReportBuilder { countDerivations(rootCause) if rootCause.cause.isConflict { - try self.visit(rootCause) + try await self.visit(rootCause) } else { assertionFailure("Unimplemented") - self.record( + try await self.record( rootCause, - message: try self.description(for: rootCause), + message: self.description(for: rootCause), isNumbered: false ) } @@ -71,10 +71,10 @@ struct DiagnosticReportBuilder { private mutating func visit( _ incompatibility: Incompatibility, isConclusion: Bool = false - ) throws { + ) async throws { let isNumbered = isConclusion || self.derivations[incompatibility]! > 1 let conjunction = isConclusion || incompatibility.cause == .root ? "As a result, " : "" - let incompatibilityDesc = try description(for: incompatibility) + let incompatibilityDesc = try await description(for: incompatibility) guard case .conflict(let cause) = incompatibility.cause else { assertionFailure("\(incompatibility)") @@ -86,9 +86,9 @@ struct DiagnosticReportBuilder { let otherLine = self.lineNumbers[cause.other] if let conflictLine, let otherLine { - self.record( + try await self.record( incompatibility, - message: "\(incompatibilityDesc) because \(try self.description(for: cause.conflict)) (\(conflictLine)) and \(try self.description(for: cause.other)) (\(otherLine).", + message: "\(incompatibilityDesc) because \(self.description(for: cause.conflict)) (\(conflictLine)) and \(try await self.description(for: cause.other)) (\(otherLine).", isNumbered: isNumbered ) } else if conflictLine != nil || otherLine != nil { @@ -105,10 +105,10 @@ struct DiagnosticReportBuilder { line = otherLine! } - try self.visit(withoutLine) - self.record( + try await self.visit(withoutLine) + try await self.record( incompatibility, - message: "\(conjunction)\(incompatibilityDesc) because \(try self.description(for: withLine)) \(line).", + message: "\(conjunction)\(incompatibilityDesc) because \(self.description(for: withLine)) \(line).", isNumbered: isNumbered ) } else { @@ -117,19 +117,19 @@ struct DiagnosticReportBuilder { if singleLineOther || singleLineConflict { let first = singleLineOther ? cause.conflict : cause.other let second = singleLineOther ? cause.other : cause.conflict - try self.visit(first) - try self.visit(second) + try await self.visit(first) + try await self.visit(second) self.record( incompatibility, message: "\(incompatibilityDesc).", isNumbered: isNumbered ) } else { - try self.visit(cause.conflict, isConclusion: true) - try self.visit(cause.other) - self.record( + try await self.visit(cause.conflict, isConclusion: true) + try await self.visit(cause.other) + try await self.record( incompatibility, - message: "\(conjunction)\(incompatibilityDesc) because \(try self.description(for: cause.conflict)) (\(self.lineNumbers[cause.conflict]!)).", + message: "\(conjunction)\(incompatibilityDesc) because \(self.description(for: cause.conflict)) (\(self.lineNumbers[cause.conflict]!)).", isNumbered: isNumbered ) } @@ -139,9 +139,9 @@ struct DiagnosticReportBuilder { let ext = cause.conflict.cause.isConflict ? cause.other : cause.conflict let derivedLine = self.lineNumbers[derived] if let derivedLine { - self.record( + try await self.record( incompatibility, - message: "\(incompatibilityDesc) because \(try self.description(for: ext)) and \(try self.description(for: derived)) (\(derivedLine)).", + message: "\(incompatibilityDesc) because \(self.description(for: ext)) and \(try self.description(for: derived)) (\(derivedLine)).", isNumbered: isNumbered ) } else if self.isCollapsible(derived) { @@ -153,30 +153,30 @@ struct DiagnosticReportBuilder { let collapsedDerived = derivedCause.conflict.cause.isConflict ? derivedCause.conflict : derivedCause.other let collapsedExt = derivedCause.conflict.cause.isConflict ? derivedCause.other : derivedCause.conflict - try self.visit(collapsedDerived) - self.record( + try await self.visit(collapsedDerived) + try await self.record( incompatibility, - message: "\(conjunction)\(incompatibilityDesc) because \(try self.description(for: collapsedExt)) and \(try self.description(for: ext)).", + message: "\(conjunction)\(incompatibilityDesc) because \(self.description(for: collapsedExt)) and \(try await self.description(for: ext)).", isNumbered: isNumbered ) } else { - try self.visit(derived) - self.record( + try await self.visit(derived) + try await self.record( incompatibility, - message: "\(conjunction)\(incompatibilityDesc) because \(try self.description(for: ext)).", + message: "\(conjunction)\(incompatibilityDesc) because \(self.description(for: ext)).", isNumbered: isNumbered ) } } else { - self.record( + try await self.record( incompatibility, - message: "\(incompatibilityDesc) because \(try self.description(for: cause.conflict)) and \(try self.description(for: cause.other)).", + message: "\(incompatibilityDesc) because \(self.description(for: cause.conflict)) and \(try self.description(for: cause.other)).", isNumbered: isNumbered ) } } - private func description(for incompatibility: Incompatibility) throws -> String { + private func description(for incompatibility: Incompatibility) async throws -> String { switch incompatibility.cause { case .dependency(let causeNode): assert(incompatibility.terms.count == 2) @@ -190,9 +190,9 @@ struct DiagnosticReportBuilder { if depender.node == self.rootNode, causeNode != self.rootNode { dependerDesc = causeNode.nameForDiagnostics } else { - dependerDesc = try self.description(for: depender, normalizeRange: true) + dependerDesc = try await self.description(for: depender, normalizeRange: true) } - let dependeeDesc = try description(for: dependee) + let dependeeDesc = try await description(for: dependee) return "\(dependerDesc) depends on \(dependeeDesc)" case .noAvailableVersion: assert(incompatibility.terms.count == 1) @@ -213,13 +213,13 @@ struct DiagnosticReportBuilder { return "package '\(versionedDependency.identity)' is required using a stable-version but '\(versionedDependency.identity)' depends on an unstable-version package '\(unversionedDependency.identity)'" case .incompatibleToolsVersion(let version): let term = incompatibility.terms.first! - return "\(try self.description(for: term, normalizeRange: true)) contains incompatible tools version (\(version))" + return "\(try await self.description(for: term, normalizeRange: true)) contains incompatible tools version (\(version))" } let terms = incompatibility.terms if terms.count == 1 { let term = terms.first! - let prefix = try hasEffectivelyAnyRequirement(term) ? term.node.nameForDiagnostics : self.description(for: term, normalizeRange: true) + let prefix = try await hasEffectivelyAnyRequirement(term) ? term.node.nameForDiagnostics : self.description(for: term, normalizeRange: true) return "\(prefix) " + (term.isPositive ? "cannot be used" : "is required") } else if terms.count == 2 { let term1 = terms.first! @@ -233,12 +233,12 @@ struct DiagnosticReportBuilder { } } - let positive = try terms.filter(\.isPositive).map { try description(for: $0) } - let negative = try terms.filter { !$0.isPositive }.map { try description(for: $0) } + let positive = try await terms.filter(\.isPositive).parallelMap { try await description(for: $0) } + let negative = try await terms.filter { !$0.isPositive }.parallelMap { try await description(for: $0) } if !positive.isEmpty, !negative.isEmpty { if positive.count == 1 { let positiveTerm = terms.first { $0.isPositive }! - return "\(try self.description(for: positiveTerm, normalizeRange: true)) practically depends on \(negative.joined(separator: " or "))" + return "\(try await self.description(for: positiveTerm, normalizeRange: true)) practically depends on \(negative.joined(separator: " or "))" } else { return "if \(positive.joined(separator: " and ")) then \(negative.joined(separator: " or "))" } @@ -251,7 +251,7 @@ struct DiagnosticReportBuilder { /// Returns true if the requirement on this term is effectively "any" because of either the actual /// `any` requirement or because the version range is large enough to fit all current available versions. - private func hasEffectivelyAnyRequirement(_ term: Term) throws -> Bool { + private func hasEffectivelyAnyRequirement(_ term: Term) async throws -> Bool { switch term.requirement { case .any: return true @@ -262,7 +262,7 @@ struct DiagnosticReportBuilder { guard let container = try? provider.getCachedContainer(for: term.node.package) else { return false } - let bounds = try container.computeBounds(for: range) + let bounds = try await container.computeBounds(for: range) return !bounds.includesLowerBound && !bounds.includesUpperBound } } @@ -289,7 +289,7 @@ struct DiagnosticReportBuilder { return !self.lineNumbers.keys.contains(complex) } - private func description(for term: Term, normalizeRange: Bool = false) throws -> String { + private func description(for term: Term, normalizeRange: Bool = false) async throws -> String { let name = term.node.nameForDiagnostics switch term.requirement { @@ -307,7 +307,7 @@ struct DiagnosticReportBuilder { return "\(name) \(range.description)" } - switch try container.computeBounds(for: range) { + switch try await container.computeBounds(for: range) { case (true, true): return "\(name) \(range.description)" case (false, false): diff --git a/Sources/PackageGraph/Resolution/PubGrub/Incompatibility.swift b/Sources/PackageGraph/Resolution/PubGrub/Incompatibility.swift index c2646deb806..a51f0474463 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/Incompatibility.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/Incompatibility.swift @@ -18,20 +18,20 @@ import PackageModel /// all be true at the same time. In dependency resolution, these are derived /// from version requirements and when running into unresolvable situations. public struct Incompatibility: Equatable, Hashable { - public let terms: OrderedCollections.OrderedSet - public let cause: Cause + package let terms: OrderedCollections.OrderedSet + package let cause: Cause - public init(terms: OrderedCollections.OrderedSet, cause: Cause) { + package init(terms: OrderedCollections.OrderedSet, cause: Cause) { self.terms = terms self.cause = cause } - public init(_ terms: Term..., root: DependencyResolutionNode, cause: Cause = .root) throws { + package init(_ terms: Term..., root: DependencyResolutionNode, cause: Cause = .root) throws { let termSet = OrderedCollections.OrderedSet(terms) try self.init(termSet, root: root, cause: cause) } - public init(_ terms: OrderedCollections.OrderedSet, root: DependencyResolutionNode, cause: Cause) throws { + package init(_ terms: OrderedCollections.OrderedSet, root: DependencyResolutionNode, cause: Cause) throws { if terms.isEmpty { self.init(terms: terms, cause: cause) return @@ -63,7 +63,7 @@ extension Incompatibility: CustomStringConvertible { } } -public extension Incompatibility { +package extension Incompatibility { /// Every incompatibility has a cause to explain its presence in the /// derivation graph. Only the root incompatibility uses `.root`. All other /// incompatibilities are either obtained from dependency constraints, diff --git a/Sources/PackageGraph/Resolution/PubGrub/PartialSolution.swift b/Sources/PackageGraph/Resolution/PubGrub/PartialSolution.swift index c59b209216c..3ba3a1b12f3 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/PartialSolution.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/PartialSolution.swift @@ -17,30 +17,30 @@ import struct TSCUtility.Version /// The partial solution is a constantly updated solution used throughout the /// dependency resolution process, tracking know assignments. -public struct PartialSolution { +package struct PartialSolution { var root: DependencyResolutionNode? /// All known assignments. - public private(set) var assignments: [Assignment] + package private(set) var assignments: [Assignment] /// All known decisions. - public private(set) var decisions: [DependencyResolutionNode: Version] = [:] + package private(set) var decisions: [DependencyResolutionNode: Version] = [:] /// The intersection of all positive assignments for each package, minus any /// negative assignments that refer to that package. - public private(set) var _positive: OrderedCollections.OrderedDictionary = [:] + package private(set) var _positive: OrderedCollections.OrderedDictionary = [:] /// Union of all negative assignments for a package. /// /// Only present if a package has no positive assignment. - public private(set) var _negative: [DependencyResolutionNode: Term] = [:] + package private(set) var _negative: [DependencyResolutionNode: Term] = [:] /// The current decision level. - public var decisionLevel: Int { + package var decisionLevel: Int { decisions.count - 1 } - public init(assignments: [Assignment] = []) { + package init(assignments: [Assignment] = []) { self.assignments = assignments for assignment in assignments { register(assignment) @@ -48,13 +48,13 @@ public struct PartialSolution { } /// A list of all packages that have been assigned, but are not yet satisfied. - public var undecided: [Term] { + package var undecided: [Term] { _positive.values.filter { !decisions.keys.contains($0.node) } } /// Create a new derivation assignment and add it to the partial solution's /// list of known assignments. - public mutating func derive(_ term: Term, cause: Incompatibility) { + package mutating func derive(_ term: Term, cause: Incompatibility) { let derivation = Assignment.derivation(term, cause: cause, decisionLevel: self.decisionLevel) self.assignments.append(derivation) register(derivation) @@ -62,7 +62,7 @@ public struct PartialSolution { /// Create a new decision assignment and add it to the partial solution's /// list of known assignments. - public mutating func decide(_ node: DependencyResolutionNode, at version: Version) { + package mutating func decide(_ node: DependencyResolutionNode, at version: Version) { decisions[node] = version let term = Term(node, .exact(version)) let decision = Assignment.decision(term, decisionLevel: decisionLevel) @@ -92,7 +92,7 @@ public struct PartialSolution { /// Returns the first Assignment in this solution such that the list of /// assignments up to and including that entry satisfies term. - public func satisfier(for term: Term) throws -> Assignment { + package func satisfier(for term: Term) throws -> Assignment { var assignedTerm: Term? for assignment in assignments { @@ -111,7 +111,7 @@ public struct PartialSolution { /// Backtrack to a specific decision level by dropping all assignments with /// a decision level which is greater. - public mutating func backtrack(toDecisionLevel decisionLevel: Int) { + package mutating func backtrack(toDecisionLevel decisionLevel: Int) { var toBeRemoved: [(Int, Assignment)] = [] for (idx, assignment) in zip(0..., assignments) { diff --git a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift index 3986f614703..ab9c9d147c1 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +import _Concurrency import Basics import Dispatch import class Foundation.NSLock @@ -20,9 +21,9 @@ import struct TSCUtility.Version /// The solver that is able to transitively resolve a set of package constraints /// specified by a root package. -public struct PubGrubDependencyResolver { +package struct PubGrubDependencyResolver { /// The type of the constraints the resolver operates on. - public typealias Constraint = PackageContainerConstraint + package typealias Constraint = PackageContainerConstraint /// the mutable state that get computed final class State { @@ -36,10 +37,10 @@ public struct PubGrubDependencyResolver { /// A collection of all known incompatibilities matched to the packages they /// refer to. This means an incompatibility can occur several times. - public private(set) var incompatibilities: [DependencyResolutionNode: [Incompatibility]] = [:] + package private(set) var incompatibilities: [DependencyResolutionNode: [Incompatibility]] = [:] /// The current best guess for a solution satisfying all requirements. - public private(set) var solution: PartialSolution + package private(set) var solution: PartialSolution private let lock = NSLock() @@ -122,7 +123,7 @@ public struct PubGrubDependencyResolver { /// Resolver delegate private let delegate: DependencyResolverDelegate? - public init( + package init( provider: PackageContainerProvider, pins: PinsStore.Pins = [:], availableLibraries: [ProvidedLibrary] = [], @@ -146,7 +147,7 @@ public struct PubGrubDependencyResolver { } /// Execute the resolution algorithm to find a valid assignment of versions. - public func solve(constraints: [Constraint]) -> Result<[DependencyResolverBinding], Error> { + package func solve(constraints: [Constraint]) async throws -> [DependencyResolverBinding] { // the graph resolution root let root: DependencyResolutionNode if constraints.count == 1, let constraint = constraints.first, constraint.package.kind.isRoot { @@ -161,8 +162,7 @@ public struct PubGrubDependencyResolver { } do { - let bindings = try self.solve(root: root, constraints: constraints).bindings - return .success(bindings) + return try await self.solve(root: root, constraints: constraints).bindings } catch { // If version solving failing, build the user-facing diagnostic. if let pubGrubError = error as? PubgrubError, let rootCause = pubGrubError.rootCause, @@ -174,26 +174,26 @@ public struct PubGrubDependencyResolver { incompatibilities: incompatibilities, provider: self.provider ) - let diagnostic = try builder.makeErrorReport(for: rootCause) - return .failure(PubgrubError.unresolvable(diagnostic)) + let diagnostic = try await builder.makeErrorReport(for: rootCause) + throw PubgrubError.unresolvable(diagnostic) } catch { // failed to construct the report, will report the original error - return .failure(error) + throw error } } - return .failure(error) + throw error } } /// Find a set of dependencies that fit the given constraints. If dependency /// resolution is unable to provide a result, an error is thrown. /// - Warning: It is expected that the root package reference has been set before this is called. - func solve(root: DependencyResolutionNode, constraints: [Constraint]) throws -> ( + func solve(root: DependencyResolutionNode, constraints: [Constraint]) async throws -> ( bindings: [DependencyResolverBinding], state: State ) { // first process inputs - let inputs = try self.processInputs(root: root, with: constraints) + let inputs = try await self.processInputs(root: root, with: constraints) // Prefetch the containers if prefetching is enabled. if self.prefetchBasedOnResolvedFile { @@ -222,7 +222,7 @@ public struct PubGrubDependencyResolver { state.addIncompatibility(incompatibility, at: .topLevel) } - try self.run(state: state) + try await self.run(state: state) let decisions = state.solution.assignments.filter(\.isDecision) var flattenedAssignments: [PackageReference: (binding: BoundVersion, products: ProductFilter)] = [:] @@ -253,9 +253,8 @@ public struct PubGrubDependencyResolver { if case .version(_, let library) = boundVersion, library != nil { updatePackage = package } else { - // TODO: replace with async/await when available - let container = try temp_await { self.provider.getContainer(for: package, completion: $0) } - updatePackage = try container.underlying.loadPackageReference(at: boundVersion) + let container = try await self.provider.getContainer(for: package) + updatePackage = try await container.underlying.loadPackageReference(at: boundVersion) } if var existing = flattenedAssignments[updatePackage] { @@ -278,9 +277,8 @@ public struct PubGrubDependencyResolver { // Add overridden packages to the result. for (package, override) in state.overriddenPackages { - // TODO: replace with async/await when available - let container = try temp_await { self.provider.getContainer(for: package, completion: $0) } - let updatePackage = try container.underlying.loadPackageReference(at: override.version) + let container = try await self.provider.getContainer(for: package) + let updatePackage = try await container.underlying.loadPackageReference(at: override.version) finalAssignments.append(.init( package: updatePackage, boundVersion: override.version, @@ -296,7 +294,7 @@ public struct PubGrubDependencyResolver { private func processInputs( root: DependencyResolutionNode, with constraints: [Constraint] - ) throws -> ( + ) async throws -> ( overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)], rootIncompatibilities: [Incompatibility] ) { @@ -344,9 +342,8 @@ public struct PubGrubDependencyResolver { // We collect all version-based dependencies in a separate structure so they can // be processed at the end. This allows us to override them when there is a non-version // based (unversioned/branch-based) constraint present in the graph. - // TODO: replace with async/await when available - let container = try temp_await { self.provider.getContainer(for: node.package, completion: $0) } - for dependency in try container.underlying + let container = try await self.provider.getContainer(for: node.package) + for dependency in try await container.underlying .getUnversionedDependencies(productFilter: node.productFilter) { if let versionedBasedConstraints = VersionBasedConstraint.constraints(dependency) { @@ -422,7 +419,7 @@ public struct PubGrubDependencyResolver { } for node in constraint.nodes() { - var unprocessedDependencies = try container.underlying.getDependencies( + var unprocessedDependencies = try await container.underlying.getDependencies( at: revisionForDependencies, productFilter: constraint.products ) @@ -489,7 +486,7 @@ public struct PubGrubDependencyResolver { /// decisions if nothing else is left to be done. /// After this method returns `solution` is either populated with a list of /// final version assignments or an error is thrown. - private func run(state: State) throws { + private func run(state: State) async throws { var next: DependencyResolutionNode? = state.root while let nxt = next { @@ -505,7 +502,7 @@ public struct PubGrubDependencyResolver { // If decision making determines that no more decisions are to be // made, it returns nil to signal that version solving is done. // TODO: replace with async/await when available - next = try temp_await { self.makeDecision(state: state, completion: $0) } + next = try await self.makeDecision(state: state) } } @@ -692,43 +689,28 @@ public struct PubGrubDependencyResolver { incompatibility.terms.isEmpty || (incompatibility.terms.count == 1 && incompatibility.terms.first?.node == root) } - private func computeCounts( - for terms: [Term], - completion: @escaping (Result<[Term: Int], Error>) -> Void - ) { + private func computeCounts(for terms: [Term]) async throws -> [Term: Int] { if terms.isEmpty { - return completion(.success([:])) + return [:] } - let sync = DispatchGroup() - let results = ThreadSafeKeyValueStore>() - - for term in terms { - sync.enter() - self.provider.getContainer(for: term.node.package) { result in - defer { sync.leave() } - results[term] = result - .flatMap { container in Result(catching: { try container.versionCount(term.requirement) }) } + return try await withThrowingTaskGroup(of: (Term, Int).self) { group in + for term in terms { + group.addTask { + let container = try await self.provider.getContainer(for: term.node.package) + return try await (term, container.versionCount(term.requirement)) + } } - } - sync.notify(queue: .sharedConcurrent) { - do { - try completion(.success(results.mapValues { try $0.get() })) - } catch { - completion(.failure(error)) - } + return try await group.reduce(into: [:]) { $0[$1.0] = $1.1 } } } - func makeDecision( - state: State, - completion: @escaping (Result) -> Void - ) { + func makeDecision(state: State) async throws -> DependencyResolutionNode? { // If there are no more undecided terms, version solving is complete. let undecided = state.solution.undecided guard !undecided.isEmpty else { - return completion(.success(nil)) + return nil } // If prebuilt libraries are available, let's attempt their versions first before going for @@ -755,59 +737,54 @@ public struct PubGrubDependencyResolver { // Prefer packages with least number of versions that fit the current requirements so we // get conflicts (if any) sooner. - self.computeCounts(for: undecided) { result in - do { - let start = DispatchTime.now() - let counts = try result.get() - // forced unwraps safe since we are testing for count and errors above - let pkgTerm = undecided.min { counts[$0]! < counts[$1]! }! - self.delegate?.willResolve(term: pkgTerm) - // at this point the container is cached - let container = try self.provider.getCachedContainer(for: pkgTerm.node.package) - - // Get the best available version for this package. - guard let version = try container.getBestAvailableVersion(for: pkgTerm) else { - try state.addIncompatibility( - Incompatibility(pkgTerm, root: state.root, cause: .noAvailableVersion), - at: .decisionMaking - ) - return completion(.success(pkgTerm.node)) - } - - // Add all of this version's dependencies as incompatibilities. - let depIncompatibilities = try container.incompatibilites( - at: version, - node: pkgTerm.node, - overriddenPackages: state.overriddenPackages, - root: state.root - ) + let counts = try await self.computeCounts(for: undecided) + let start = DispatchTime.now() + + // forced unwraps safe since we are testing for count and errors above + let pkgTerm = undecided.min { counts[$0]! < counts[$1]! }! + self.delegate?.willResolve(term: pkgTerm) + // at this point the container is cached + let container = try self.provider.getCachedContainer(for: pkgTerm.node.package) + + // Get the best available version for this package. + guard let version = try await container.getBestAvailableVersion(for: pkgTerm) else { + try state.addIncompatibility( + Incompatibility(pkgTerm, root: state.root, cause: .noAvailableVersion), + at: .decisionMaking + ) + return pkgTerm.node + } - var haveConflict = false - for incompatibility in depIncompatibilities { - // Add the incompatibility to our partial solution. - state.addIncompatibility(incompatibility, at: .decisionMaking) - - // Check if this incompatibility will satisfy the solution. - haveConflict = haveConflict || incompatibility.terms.allSatisfy { - // We only need to check if the terms other than this package - // are satisfied because we _know_ that the terms matching - // this package will be satisfied if we make this version - // as a decision. - $0.node == pkgTerm.node || state.solution.satisfies($0) - } - } + // Add all of this version's dependencies as incompatibilities. + let depIncompatibilities = try await container.incompatibilites( + at: version, + node: pkgTerm.node, + overriddenPackages: state.overriddenPackages, + root: state.root + ) - // Decide this version if there was no conflict with its dependencies. - if !haveConflict { - self.delegate?.didResolve(term: pkgTerm, version: version, duration: start.distance(to: .now())) - state.decide(pkgTerm.node, at: version) - } + var haveConflict = false + for incompatibility in depIncompatibilities { + // Add the incompatibility to our partial solution. + state.addIncompatibility(incompatibility, at: .decisionMaking) - completion(.success(pkgTerm.node)) - } catch { - completion(.failure(error)) + // Check if this incompatibility will satisfy the solution. + haveConflict = haveConflict || incompatibility.terms.allSatisfy { + // We only need to check if the terms other than this package + // are satisfied because we _know_ that the terms matching + // this package will be satisfied if we make this version + // as a decision. + $0.node == pkgTerm.node || state.solution.satisfies($0) } } + + // Decide this version if there was no conflict with its dependencies. + if !haveConflict { + self.delegate?.didResolve(term: pkgTerm, version: version, duration: start.distance(to: .now())) + state.decide(pkgTerm.node, at: version) + } + + return pkgTerm.node } } @@ -818,36 +795,34 @@ enum LogLocation: String { case conflictResolution = "conflict resolution" } -extension PubGrubDependencyResolver { - public enum PubgrubError: Swift.Error, CustomStringConvertible { - case _unresolvable(Incompatibility, [DependencyResolutionNode: [Incompatibility]]) - case unresolvable(String) +public enum PubgrubError: Swift.Error, CustomStringConvertible { + case _unresolvable(Incompatibility, [DependencyResolutionNode: [Incompatibility]]) + case unresolvable(String) - public var description: String { - switch self { - case ._unresolvable(let rootCause, _): - return rootCause.description - case .unresolvable(let error): - return error - } + public var description: String { + switch self { + case ._unresolvable(let rootCause, _): + return rootCause.description + case .unresolvable(let error): + return error } + } - var rootCause: Incompatibility? { - switch self { - case ._unresolvable(let rootCause, _): - return rootCause - case .unresolvable: - return nil - } + var rootCause: Incompatibility? { + switch self { + case ._unresolvable(let rootCause, _): + return rootCause + case .unresolvable: + return nil } + } - var incompatibilities: [DependencyResolutionNode: [Incompatibility]]? { - switch self { - case ._unresolvable(_, let incompatibilities): - return incompatibilities - case .unresolvable: - return nil - } + var incompatibilities: [DependencyResolutionNode: [Incompatibility]]? { + switch self { + case ._unresolvable(_, let incompatibilities): + return incompatibilities + case .unresolvable: + return nil } } } diff --git a/Sources/PackageGraph/Resolution/PubGrub/PubGrubPackageContainer.swift b/Sources/PackageGraph/Resolution/PubGrub/PubGrubPackageContainer.swift index 62cbc679b40..4cbe348f818 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/PubGrubPackageContainer.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/PubGrubPackageContainer.swift @@ -18,7 +18,7 @@ import struct TSCUtility.Version /// A container for an individual package. This enhances PackageContainer to add PubGrub specific /// logic which is mostly related to computing incompatibilities at a particular version. -internal final class PubGrubPackageContainer { +final class PubGrubPackageContainer { /// The underlying package container. let underlying: PackageContainer @@ -45,22 +45,22 @@ internal final class PubGrubPackageContainer { } /// Returns the numbers of versions that are satisfied by the given version requirement. - func versionCount(_ requirement: VersionSetSpecifier) throws -> Int { + func versionCount(_ requirement: VersionSetSpecifier) async throws -> Int { if let pinnedVersion, requirement.contains(pinnedVersion) { return 1 } - return try self.underlying.versionsDescending().filter(requirement.contains).count + return try await self.underlying.versionsDescending().filter(requirement.contains).count } /// Computes the bounds of the given range against the versions available in the package. /// /// `includesLowerBound` is `false` if range's lower bound is less than or equal to the lowest available version. /// Similarly, `includesUpperBound` is `false` if range's upper bound is greater than or equal to the highest available version. - func computeBounds(for range: Range) throws -> (includesLowerBound: Bool, includesUpperBound: Bool) { + func computeBounds(for range: Range) async throws -> (includesLowerBound: Bool, includesUpperBound: Bool) { var includeLowerBound = true var includeUpperBound = true - let versions = try self.underlying.versionsDescending() + let versions = try await self.underlying.versionsDescending() if let last = versions.last, range.lowerBound < last { includeLowerBound = false @@ -74,7 +74,7 @@ internal final class PubGrubPackageContainer { } /// Returns the best available version for a given term. - func getBestAvailableVersion(for term: Term) throws -> Version? { + func getBestAvailableVersion(for term: Term) async throws -> Version? { assert(term.isPositive, "Expected term to be positive") var versionSet = term.requirement @@ -85,7 +85,7 @@ internal final class PubGrubPackageContainer { versionSet = .exact(pinnedVersion) } else { // Make sure the pinned version is still available - let version = try self.underlying.versionsDescending().first { pinnedVersion == $0 } + let version = try await self.underlying.versionsDescending().first { pinnedVersion == $0 } if version != nil { return version } @@ -94,13 +94,14 @@ internal final class PubGrubPackageContainer { } // Return the highest version that is allowed by the input requirement. - return try self.underlying.versionsDescending().first { versionSet.contains($0) } + return try await self.underlying.versionsDescending().first { versionSet.contains($0) } } /// Compute the bounds of incompatible tools version starting from the given version. - private func computeIncompatibleToolsVersionBounds(fromVersion: Version) throws -> VersionSetSpecifier { - assert(!self.underlying.isToolsVersionCompatible(at: fromVersion)) - let versions: [Version] = try self.underlying.versionsAscending() + private func computeIncompatibleToolsVersionBounds(fromVersion: Version) async throws -> VersionSetSpecifier { + let isToolsVersionCompatible = await self.underlying.isToolsVersionCompatible(at: fromVersion) + assert(!isToolsVersionCompatible) + let versions: [Version] = try await self.underlying.versionsAscending() // This is guaranteed to be present. let idx = versions.firstIndex(of: fromVersion)! @@ -109,7 +110,7 @@ internal final class PubGrubPackageContainer { var upperBound = fromVersion for version in versions.dropFirst(idx + 1) { - let isToolsVersionCompatible = self.underlying.isToolsVersionCompatible(at: version) + let isToolsVersionCompatible = await self.underlying.isToolsVersionCompatible(at: version) if isToolsVersionCompatible { break } @@ -117,7 +118,7 @@ internal final class PubGrubPackageContainer { } for version in versions.dropLast(versions.count - idx).reversed() { - let isToolsVersionCompatible = self.underlying.isToolsVersionCompatible(at: version) + let isToolsVersionCompatible = await self.underlying.isToolsVersionCompatible(at: version) if isToolsVersionCompatible { break } @@ -152,15 +153,15 @@ internal final class PubGrubPackageContainer { node: DependencyResolutionNode, overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)], root: DependencyResolutionNode - ) throws -> [Incompatibility] { + ) async throws -> [Incompatibility] { // FIXME: It would be nice to compute bounds for this as well. - if !self.underlying.isToolsVersionCompatible(at: version) { - let requirement = try self.computeIncompatibleToolsVersionBounds(fromVersion: version) - let toolsVersion = try self.underlying.toolsVersion(for: version) + if await !self.underlying.isToolsVersionCompatible(at: version) { + let requirement = try await self.computeIncompatibleToolsVersionBounds(fromVersion: version) + let toolsVersion = try await self.underlying.toolsVersion(for: version) return [try Incompatibility(Term(node, requirement), root: root, cause: .incompatibleToolsVersion(toolsVersion))] } - var unprocessedDependencies = try self.underlying.getDependencies(at: version, productFilter: node.productFilter) + var unprocessedDependencies = try await self.underlying.getDependencies(at: version, productFilter: node.productFilter) if let sharedVersion = node.versionLock(version: version) { unprocessedDependencies.append(sharedVersion) } diff --git a/Sources/PackageGraph/Resolution/PubGrub/Term.swift b/Sources/PackageGraph/Resolution/PubGrub/Term.swift index 4899071270e..d9bc3651a0d 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/Term.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/Term.swift @@ -11,28 +11,28 @@ //===----------------------------------------------------------------------===// /// A term represents a statement about a package that may be true or false. -public struct Term: Equatable, Hashable { - public let node: DependencyResolutionNode - public let requirement: VersionSetSpecifier - public let isPositive: Bool +package struct Term: Equatable, Hashable { + package let node: DependencyResolutionNode + package let requirement: VersionSetSpecifier + package let isPositive: Bool - public init(node: DependencyResolutionNode, requirement: VersionSetSpecifier, isPositive: Bool) { + package init(node: DependencyResolutionNode, requirement: VersionSetSpecifier, isPositive: Bool) { self.node = node self.requirement = requirement self.isPositive = isPositive } - public init(_ node: DependencyResolutionNode, _ requirement: VersionSetSpecifier) { + package init(_ node: DependencyResolutionNode, _ requirement: VersionSetSpecifier) { self.init(node: node, requirement: requirement, isPositive: true) } /// Create a new negative term. - public init(not node: DependencyResolutionNode, _ requirement: VersionSetSpecifier) { + package init(not node: DependencyResolutionNode, _ requirement: VersionSetSpecifier) { self.init(node: node, requirement: requirement, isPositive: false) } /// The same term with an inversed `isPositive` value. - public var inverse: Term { + package var inverse: Term { Term( node: self.node, requirement: self.requirement, @@ -42,14 +42,14 @@ public struct Term: Equatable, Hashable { /// Check if this term satisfies another term, e.g. if `self` is true, /// `other` must also be true. - public func satisfies(_ other: Term) -> Bool { + package func satisfies(_ other: Term) -> Bool { // TODO: This probably makes more sense as isSatisfied(by:) instead. guard self.node == other.node else { return false } return self.relation(with: other) == .subset } /// Create an intersection with another term. - public func intersect(with other: Term) -> Term? { + package func intersect(with other: Term) -> Term? { guard self.node == other.node else { return nil } return self.intersect(withRequirement: other.requirement, andPolarity: other.isPositive) } @@ -59,7 +59,7 @@ public struct Term: Equatable, Hashable { /// and given term. /// /// - returns: `nil` if an intersection is not possible. - public func intersect( + package func intersect( withRequirement requirement: VersionSetSpecifier, andPolarity otherIsPositive: Bool ) -> Term? { @@ -90,7 +90,7 @@ public struct Term: Equatable, Hashable { return Term(node: self.node, requirement: versionIntersection, isPositive: isPositive) } - public func difference(with other: Term) -> Term? { + package func difference(with other: Term) -> Term? { self.intersect(with: other.inverse) } @@ -99,7 +99,7 @@ public struct Term: Equatable, Hashable { /// - There has to exist a positive derivation for it. /// - There has to be no decision for it. /// - The package version has to match all assignments. - public func isValidDecision(for solution: PartialSolution) -> Bool { + package func isValidDecision(for solution: PartialSolution) -> Bool { for assignment in solution.assignments where assignment.term.node == self.node { assert(!assignment.isDecision, "Expected assignment to be a derivation.") guard satisfies(assignment.term) else { return false } @@ -108,7 +108,7 @@ public struct Term: Equatable, Hashable { } // From: https://github.com/dart-lang/pub/blob/master/lib/src/solver/term.dart - public func relation(with other: Term) -> SetRelation { + package func relation(with other: Term) -> SetRelation { if self.node != other.node { assertionFailure("attempting to compute relation between different packages \(self) \(other)") return .error @@ -154,7 +154,7 @@ public struct Term: Equatable, Hashable { } } - public enum SetRelation: Equatable { + package enum SetRelation: Equatable { /// The sets have nothing in common. case disjoint /// The sets have elements in common but first set is not a subset of second. @@ -167,7 +167,7 @@ public struct Term: Equatable, Hashable { } extension Term: CustomStringConvertible { - public var description: String { + package var description: String { let pkg = "\(node)" let req = self.requirement.description diff --git a/Sources/SPMTestSupport/MockPackageContainer.swift b/Sources/SPMTestSupport/MockPackageContainer.swift index 730ddffe12b..a07bddef383 100644 --- a/Sources/SPMTestSupport/MockPackageContainer.swift +++ b/Sources/SPMTestSupport/MockPackageContainer.swift @@ -19,8 +19,8 @@ import XCTest import struct TSCUtility.Version -public class MockPackageContainer: CustomPackageContainer { - public typealias Constraint = PackageContainerConstraint +package actor MockPackageContainer: CustomPackageContainer { + package typealias Constraint = PackageContainerConstraint public typealias Dependency = (container: PackageReference, requirement: PackageRequirement) diff --git a/Sources/SPMTestSupport/MockWorkspace.swift b/Sources/SPMTestSupport/MockWorkspace.swift index ff8bc051461..699662b0719 100644 --- a/Sources/SPMTestSupport/MockWorkspace.swift +++ b/Sources/SPMTestSupport/MockWorkspace.swift @@ -86,7 +86,7 @@ public final class MockWorkspace { skipDependenciesUpdates: Bool = false, sourceControlToRegistryDependencyTransformation: WorkspaceConfiguration.SourceControlToRegistryDependencyTransformation = .disabled, defaultRegistry: Registry? = .none - ) throws { + ) async throws { try fileSystem.createMockToolchain() self.sandbox = sandbox @@ -121,7 +121,7 @@ public final class MockWorkspace { archiver: MockArchiver() ) self.customHostToolchain = try UserToolchain.mockHostToolchain(fileSystem) - try self.create() + try await self.create() } public var rootsDir: AbsolutePath { @@ -144,7 +144,7 @@ public final class MockWorkspace { return try AbsolutePath(validating: name, relativeTo: self.packagesDir) } - private func create() throws { + private func create() async throws { // Remove the sandbox if present. try self.fileSystem.removeFileTree(self.sandbox) @@ -155,7 +155,7 @@ public final class MockWorkspace { var manifests: [MockManifestLoader.Key: Manifest] = [:] - func create(package: MockPackage, basePath: AbsolutePath, isRoot: Bool) throws { + func create(package: MockPackage, basePath: AbsolutePath, isRoot: Bool) async throws { let packagePath: AbsolutePath switch package.location { case .fileSystem(let path): @@ -176,7 +176,10 @@ public final class MockWorkspace { guard let customContainer = container as? CustomPackageContainer else { throw StringError("invalid custom container: \(container)") } - packagePath = try customContainer.retrieve(at: try Version(versionString: package.versions.first!!), observabilityScope: observability.topScope) + packagePath = try await customContainer.retrieve( + at: try Version(versionString: package.versions.first!!), + observabilityScope: observability.topScope + ) } else { packagePath = basePath.appending(components: "sourceControl", url.absoluteString.spm_mangledToC99ExtendedIdentifier()) } @@ -284,12 +287,12 @@ public final class MockWorkspace { // Create root packages. for package in self.roots { - try create(package: package, basePath: self.rootsDir, isRoot: true) + try await create(package: package, basePath: self.rootsDir, isRoot: true) } // Create dependency packages. for package in self.packages { - try create(package: package, basePath: self.packagesDir, isRoot: false) + try await create(package: package, basePath: self.packagesDir, isRoot: false) } self.manifestLoader = MockManifestLoader(manifests: manifests) @@ -369,11 +372,11 @@ public final class MockWorkspace { revision: Revision? = nil, checkoutBranch: String? = nil, _ result: ([Basics.Diagnostic]) -> Void - ) { + ) async { let observability = ObservabilitySystem.makeForTesting() - observability.topScope.trap { + await observability.topScope.trap { let ws = try self.getOrCreateWorkspace() - ws.edit( + await ws.edit( packageName: packageName, path: path, revision: revision, @@ -389,12 +392,12 @@ public final class MockWorkspace { roots: [String], forceRemove: Bool = false, _ result: ([Basics.Diagnostic]) -> Void - ) { + ) async { let observability = ObservabilitySystem.makeForTesting() - observability.topScope.trap { + await observability.topScope.trap { let rootInput = PackageGraphRootInput(packages: try rootPaths(for: roots)) let ws = try self.getOrCreateWorkspace() - try ws.unedit( + try await ws.unedit( packageName: packageName, forceRemove: forceRemove, root: rootInput, @@ -404,12 +407,24 @@ public final class MockWorkspace { result(observability.diagnostics) } - public func checkResolve(pkg: String, roots: [String], version: TSCUtility.Version, _ result: ([Basics.Diagnostic]) -> Void) { + package func checkResolve( + pkg: String, + roots: [String], + version: TSCUtility.Version, + _ result: ([Basics.Diagnostic]) -> Void + ) async { let observability = ObservabilitySystem.makeForTesting() - observability.topScope.trap { + await observability.topScope.trap { let rootInput = PackageGraphRootInput(packages: try rootPaths(for: roots)) let workspace = try self.getOrCreateWorkspace() - try workspace.resolve(packageName: pkg, root: rootInput, version: version, branch: nil, revision: nil, observabilityScope: observability.topScope) + try await workspace.resolve( + packageName: pkg, + root: rootInput, + version: version, + branch: nil, + revision: nil, + observabilityScope: observability.topScope + ) } result(observability.diagnostics) } @@ -437,17 +452,21 @@ public final class MockWorkspace { deps: [MockDependency] = [], packages: [String] = [], _ result: ([Basics.Diagnostic]) -> Void - ) throws { + ) async throws { let dependencies = try deps.map { try $0.convert(baseURL: packagesDir, identityResolver: self.identityResolver) } let observability = ObservabilitySystem.makeForTesting() - observability.topScope.trap { + await observability.topScope.trap { let rootInput = PackageGraphRootInput( packages: try rootPaths(for: roots), dependencies: dependencies ) let workspace = try self.getOrCreateWorkspace() - try workspace.updateDependencies(root: rootInput, packages: packages, observabilityScope: observability.topScope) + try await workspace.updateDependencies( + root: rootInput, + packages: packages, + observabilityScope: observability.topScope + ) } result(observability.diagnostics) } @@ -456,7 +475,7 @@ public final class MockWorkspace { roots: [String] = [], deps: [MockDependency] = [], _ result: ([(PackageReference, Workspace.PackageStateChange)]?, [Basics.Diagnostic]) -> Void - ) throws { + ) async throws { let dependencies = try deps.map { try $0.convert(baseURL: packagesDir, identityResolver: self.identityResolver) } let rootInput = PackageGraphRootInput( packages: try rootPaths(for: roots), @@ -464,9 +483,13 @@ public final class MockWorkspace { ) let observability = ObservabilitySystem.makeForTesting() - let changes = observability.topScope.trap { () -> [(PackageReference, Workspace.PackageStateChange)]? in + let changes = await observability.topScope.trap { () -> [(PackageReference, Workspace.PackageStateChange)]? in let workspace = try self.getOrCreateWorkspace() - return try workspace.updateDependencies(root: rootInput, dryRun: true, observabilityScope: observability.topScope) + return try await workspace.updateDependencies( + root: rootInput, + dryRun: true, + observabilityScope: observability.topScope + ) } ?? nil result(changes, observability.diagnostics) } @@ -475,9 +498,9 @@ public final class MockWorkspace { roots: [String] = [], deps: [MockDependency], _ result: (ModulesGraph, [Basics.Diagnostic]) -> Void - ) throws { + ) async throws { let dependencies = try deps.map { try $0.convert(baseURL: packagesDir, identityResolver: self.identityResolver) } - try self.checkPackageGraph(roots: roots, dependencies: dependencies, result) + try await self.checkPackageGraph(roots: roots, dependencies: dependencies, result) } public func checkPackageGraph( @@ -486,14 +509,14 @@ public final class MockWorkspace { forceResolvedVersions: Bool = false, expectedSigningEntities: [PackageIdentity: RegistryReleaseMetadata.SigningEntity] = [:], _ result: (ModulesGraph, [Basics.Diagnostic]) throws -> Void - ) throws { + ) async throws { let observability = ObservabilitySystem.makeForTesting() let rootInput = PackageGraphRootInput( packages: try rootPaths(for: roots), dependencies: dependencies ) let workspace = try self.getOrCreateWorkspace() do { - let graph = try workspace.loadPackageGraph( + let graph = try await workspace.loadPackageGraph( rootInput: rootInput, forceResolvedVersions: forceResolvedVersions, expectedSigningEntities: expectedSigningEntities, @@ -513,9 +536,9 @@ public final class MockWorkspace { roots: [String] = [], deps: [MockDependency], _ result: ([Basics.Diagnostic]) -> Void - ) throws { + ) async throws { let dependencies = try deps.map { try $0.convert(baseURL: packagesDir, identityResolver: self.identityResolver) } - self.checkPackageGraphFailure(roots: roots, dependencies: dependencies, result) + await self.checkPackageGraphFailure(roots: roots, dependencies: dependencies, result) } public func checkPackageGraphFailure( @@ -523,15 +546,15 @@ public final class MockWorkspace { dependencies: [PackageDependency] = [], forceResolvedVersions: Bool = false, _ result: ([Basics.Diagnostic]) -> Void - ) { + ) async { let observability = ObservabilitySystem.makeForTesting() - observability.topScope.trap { + await observability.topScope.trap { let rootInput = PackageGraphRootInput( packages: try rootPaths(for: roots), dependencies: dependencies ) let workspace = try self.getOrCreateWorkspace() - try workspace.loadPackageGraph( + try await workspace.loadPackageGraph( rootInput: rootInput, forceResolvedVersions: forceResolvedVersions, observabilityScope: observability.topScope @@ -557,12 +580,12 @@ public final class MockWorkspace { ) let root = PackageGraphRoot(input: rootInput, manifests: rootManifests, observabilityScope: observability.topScope) - let dependencyManifests = try workspace.loadDependencyManifests( + let dependencyManifests = try await workspace.loadDependencyManifests( root: root, observabilityScope: observability.topScope ) - let result = try workspace.precomputeResolution( + let result = try await workspace.precomputeResolution( root: root, dependencyManifests: dependencyManifests, pinsStore: pinsStore, @@ -764,22 +787,24 @@ public final class MockWorkspace { public func loadDependencyManifests( roots: [String] = [], - deps: [MockDependency] = [], - _ result: (Workspace.DependencyManifests, [Basics.Diagnostic]) -> Void - ) throws { + deps: [MockDependency] = [] + ) async throws -> (Workspace.DependencyManifests, [Basics.Diagnostic]) { let observability = ObservabilitySystem.makeForTesting() let dependencies = try deps.map { try $0.convert(baseURL: packagesDir, identityResolver: self.identityResolver) } let workspace = try self.getOrCreateWorkspace() let rootInput = PackageGraphRootInput( packages: try rootPaths(for: roots), dependencies: dependencies ) - let rootManifests = try temp_await { workspace.loadRootManifests(packages: rootInput.packages, observabilityScope: observability.topScope, completion: $0) } + let rootManifests = try await workspace.loadRootManifests( + packages: rootInput.packages, + observabilityScope: observability.topScope + ) let graphRoot = PackageGraphRoot(input: rootInput, manifests: rootManifests, observabilityScope: observability.topScope) - let manifests = try workspace.loadDependencyManifests( + let manifests = try await workspace.loadDependencyManifests( root: graphRoot, observabilityScope: observability.topScope ) - result(manifests, observability.diagnostics) + return (manifests, observability.diagnostics) } public func checkManagedDependencies(file: StaticString = #file, line: UInt = #line, _ result: (ManagedDependencyResult) throws -> Void) { diff --git a/Sources/SPMTestSupport/XCTAssertHelpers.swift b/Sources/SPMTestSupport/XCTAssertHelpers.swift index 5e401a38fa7..d05d750be17 100644 --- a/Sources/SPMTestSupport/XCTAssertHelpers.swift +++ b/Sources/SPMTestSupport/XCTAssertHelpers.swift @@ -65,6 +65,21 @@ public func XCTAssertAsyncThrowsError( } } +/// An `async`-friendly replacement for `XCTAssertNoThrow`. +package func XCTAssertAsyncNoThrow( + _ expression: @autoclosure () async throws -> T, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line, + _ errorHandler: (_ error: any Error) -> Void = { _ in } +) async { + do { + _ = try await expression() + } catch { + XCTFail(message(), file: file, line: line) + } +} + public func XCTAssertBuilds( _ path: AbsolutePath, diff --git a/Sources/Workspace/PackageContainer/FileSystemPackageContainer.swift b/Sources/Workspace/PackageContainer/FileSystemPackageContainer.swift index 9c5ffe11aba..897ba1c901b 100644 --- a/Sources/Workspace/PackageContainer/FileSystemPackageContainer.swift +++ b/Sources/Workspace/PackageContainer/FileSystemPackageContainer.swift @@ -24,7 +24,7 @@ import struct TSCUtility.Version /// There is no need to perform any git operations on such packages and they /// should be used as-is. In fact, they might not even have a git repository. /// Examples: Root packages, local dependencies, edited packages. -public struct FileSystemPackageContainer: PackageContainer { +public actor FileSystemPackageContainer: PackageContainer { public let package: PackageReference private let identityResolver: IdentityResolver private let dependencyMapper: DependencyMapper @@ -135,7 +135,7 @@ public struct FileSystemPackageContainer: PackageContainer { } extension FileSystemPackageContainer: CustomStringConvertible { - public var description: String { + public nonisolated var description: String { return "FileSystemPackageContainer(\(self.package.identity))" } } diff --git a/Sources/Workspace/PackageContainer/RegistryPackageContainer.swift b/Sources/Workspace/PackageContainer/RegistryPackageContainer.swift index fc5d451c8c4..4e24550337f 100644 --- a/Sources/Workspace/PackageContainer/RegistryPackageContainer.swift +++ b/Sources/Workspace/PackageContainer/RegistryPackageContainer.swift @@ -21,7 +21,7 @@ import class TSCBasic.InMemoryFileSystem import struct TSCUtility.Version -public class RegistryPackageContainer: PackageContainer { +public actor RegistryPackageContainer: PackageContainer { public let package: PackageReference private let registryClient: RegistryClient @@ -245,7 +245,7 @@ public class RegistryPackageContainer: PackageContainer { // MARK: - CustomStringConvertible extension RegistryPackageContainer: CustomStringConvertible { - public var description: String { + public nonisolated var description: String { return "RegistryPackageContainer(\(package.identity))" } } diff --git a/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift b/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift index 03f48dd0120..3a7efb45a0c 100644 --- a/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift +++ b/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift @@ -25,26 +25,27 @@ import enum TSCUtility.Git import struct TSCUtility.Version /// Adaptor to expose an individual repository as a package container. -internal final class SourceControlPackageContainer: PackageContainer, CustomStringConvertible { - public typealias Constraint = PackageContainerConstraint +actor SourceControlPackageContainer: PackageContainer, CustomStringConvertible { + + typealias Constraint = PackageContainerConstraint // A wrapper for getDependencies() errors. This adds additional information // about the container to identify it for diagnostics. - public struct GetDependenciesError: Error, CustomStringConvertible { + struct GetDependenciesError: Error, CustomStringConvertible { /// The repository that encountered the error. - public let repository: RepositorySpecifier + let repository: RepositorySpecifier /// The source control reference (version, branch, revision, etc) that was involved. - public let reference: String + let reference: String /// The actual error that occurred. - public let underlyingError: Error + let underlyingError: Error /// Optional suggestion for how to resolve the error. - public let suggestion: String? + let suggestion: String? /// Description shown for errors of this kind. - public var description: String { + var description: String { var desc = "\(underlyingError) in \(self.repository.location)" if let suggestion { desc += " (\(suggestion))" @@ -53,7 +54,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public let package: PackageReference + let package: PackageReference private let repositorySpecifier: RepositorySpecifier private let repository: Repository private let identityResolver: IdentityResolver @@ -132,12 +133,12 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public func versionsAscending() throws -> [Version] { + func versionsAscending() throws -> [Version] { [Version](try self.knownVersions().keys).sorted() } /// The available version list (in reverse order). - public func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { + func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { let reversedVersions = try self.versionsDescending() return reversedVersions.lazy.filter { // If we have the result cached, return that. @@ -152,7 +153,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public func getTag(for version: Version) -> String? { + func getTag(for version: Version) -> String? { return try? self.knownVersions()[version] } @@ -226,17 +227,17 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } /// Returns revision for the given tag. - public func getRevision(forTag tag: String) throws -> Revision { + func getRevision(forTag tag: String) throws -> Revision { return try repository.resolveRevision(tag: tag) } /// Returns revision for the given identifier. - public func getRevision(forIdentifier identifier: String) throws -> Revision { + func getRevision(forIdentifier identifier: String) throws -> Revision { return try repository.resolveRevision(identifier: identifier) } /// Returns the tools version of the given version of the package. - public func toolsVersion(for version: Version) throws -> ToolsVersion { + func toolsVersion(for version: Version) throws -> ToolsVersion { try self.toolsVersionsCache.memoize(version) { guard let tag = try self.knownVersions()[version] else { throw StringError("unknown tag \(version)") @@ -248,7 +249,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [Constraint] { + func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [Constraint] { do { return try self.getCachedDependencies(forIdentifier: version.description, productFilter: productFilter) { guard let tag = try self.knownVersions()[version] else { @@ -266,7 +267,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public func getDependencies(at revision: String, productFilter: ProductFilter) throws -> [Constraint] { + func getDependencies(at revision: String, productFilter: ProductFilter) throws -> [Constraint] { do { return try self.getCachedDependencies(forIdentifier: revision, productFilter: productFilter) { // resolve the revision identifier and return its dependencies. @@ -345,12 +346,12 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri return (manifest, try manifest.dependencyConstraints(productFilter: productFilter)) } - public func getUnversionedDependencies(productFilter: ProductFilter) throws -> [Constraint] { + func getUnversionedDependencies(productFilter: ProductFilter) throws -> [Constraint] { // We just return an empty array if requested for unversioned dependencies. return [] } - public func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { + func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { let revision: Revision var version: Version? switch boundVersion { @@ -382,7 +383,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public func isToolsVersionCompatible(at version: Version) -> Bool { + func isToolsVersionCompatible(at version: Version) -> Bool { return (try? self.toolsVersion(for: version)).flatMap(self.isValidToolsVersion(_:)) ?? false } @@ -422,11 +423,11 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri } } - public var isRemoteContainer: Bool? { + var isRemoteContainer: Bool? { return true } - public var description: String { + nonisolated var description: String { return "SourceControlPackageContainer(\(self.repositorySpecifier))" } } diff --git a/Sources/Workspace/ResolverPrecomputationProvider.swift b/Sources/Workspace/ResolverPrecomputationProvider.swift index 7308bbcfcac..1234891a469 100644 --- a/Sources/Workspace/ResolverPrecomputationProvider.swift +++ b/Sources/Workspace/ResolverPrecomputationProvider.swift @@ -92,7 +92,7 @@ struct ResolverPrecomputationProvider: PackageContainerProvider { } } -private struct LocalPackageContainer: PackageContainer { +private actor LocalPackageContainer: PackageContainer { let package: PackageReference let manifest: Manifest /// The managed dependency if the package is not a root package. @@ -100,6 +100,19 @@ private struct LocalPackageContainer: PackageContainer { let currentToolsVersion: ToolsVersion let shouldInvalidatePinnedVersions = false + init( + package: PackageReference, + manifest: Manifest, + dependency: Workspace.ManagedDependency?, + currentToolsVersion: ToolsVersion + ) { + self.package = package + self.manifest = manifest + self.dependency = dependency + self.currentToolsVersion = currentToolsVersion + } + + func versionsAscending() throws -> [Version] { switch self.dependency?.state { case .sourceControlCheckout(.version(let version, revision: _)): diff --git a/Sources/Workspace/Workspace+Dependencies.swift b/Sources/Workspace/Workspace+Dependencies.swift index 2e99b7d2107..3912799434f 100644 --- a/Sources/Workspace/Workspace+Dependencies.swift +++ b/Sources/Workspace/Workspace+Dependencies.swift @@ -58,7 +58,7 @@ extension Workspace { packages: [String] = [], dryRun: Bool = false, observabilityScope: ObservabilityScope - ) throws -> [(PackageReference, Workspace.PackageStateChange)]? { + ) async throws -> [(PackageReference, Workspace.PackageStateChange)]? { let start = DispatchTime.now() self.delegate?.willUpdateDependencies() defer { @@ -70,11 +70,10 @@ extension Workspace { // FIXME: this should not block // Load the root manifests and currently checked out manifests. - let rootManifests = try temp_await { self.loadRootManifests( + let rootManifests = try await self.loadRootManifests( packages: root.packages, - observabilityScope: observabilityScope, - completion: $0 - ) } + observabilityScope: observabilityScope + ) let rootManifestsMinimumToolsVersion = rootManifests.values.map(\.toolsVersion).min() ?? ToolsVersion.current let resolvedFileOriginHash = try self.computeResolvedFileOriginHash(root: root) @@ -85,7 +84,7 @@ extension Workspace { dependencyMapper: self.dependencyMapper, observabilityScope: observabilityScope ) - let currentManifests = try self.loadDependencyManifests( + let currentManifests = try await self.loadDependencyManifests( root: graphRoot, observabilityScope: observabilityScope ) @@ -125,7 +124,7 @@ extension Workspace { ) self.activeResolver = resolver - let updateResults = self.resolveDependencies( + let updateResults = await self.resolveDependencies( resolver: resolver, constraints: updateConstraints, observabilityScope: observabilityScope @@ -139,8 +138,8 @@ extension Workspace { } if dryRun { - return observabilityScope.trap { - try self.computePackageStateChanges( + return await observabilityScope.trap { + try await self.computePackageStateChanges( root: graphRoot, resolvedDependencies: updateResults, updateBranches: true, @@ -150,7 +149,7 @@ extension Workspace { } // Update the checkouts based on new dependency resolution. - let packageStateChanges = self.updateDependenciesCheckouts( + let packageStateChanges = await self.updateDependenciesCheckouts( root: graphRoot, updateResults: updateResults, updateBranches: true, @@ -161,7 +160,7 @@ extension Workspace { } // Load the updated manifests. - let updatedDependencyManifests = try self.loadDependencyManifests( + let updatedDependencyManifests = try await self.loadDependencyManifests( root: graphRoot, observabilityScope: observabilityScope ) @@ -198,7 +197,7 @@ extension Workspace { explicitProduct: String?, resolvedFileStrategy: ResolvedFileStrategy, observabilityScope: ObservabilityScope - ) throws -> DependencyManifests { + ) async throws -> DependencyManifests { let start = DispatchTime.now() self.delegate?.willResolveDependencies() defer { @@ -208,19 +207,19 @@ extension Workspace { switch resolvedFileStrategy { case .lockFile: observabilityScope.emit(info: "using '\(self.location.resolvedVersionsFile.basename)' file as lock file") - return try self._resolveBasedOnResolvedVersionsFile( + return try await self._resolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, observabilityScope: observabilityScope ) case .update(let forceResolution): - return try resolveAndUpdateResolvedFile(forceResolution: forceResolution) + return try await resolveAndUpdateResolvedFile(forceResolution: forceResolution) case .bestEffort: guard !self.state.dependencies.hasEditedDependencies() else { - return try resolveAndUpdateResolvedFile(forceResolution: false) + return try await resolveAndUpdateResolvedFile(forceResolution: false) } guard self.fileSystem.exists(self.location.resolvedVersionsFile) else { - return try resolveAndUpdateResolvedFile(forceResolution: false) + return try await resolveAndUpdateResolvedFile(forceResolution: false) } guard let pinsStore = try? self.pinsStore.load(), let storedHash = pinsStore.originHash else { @@ -228,7 +227,7 @@ extension Workspace { .emit( debug: "'\(self.location.resolvedVersionsFile.basename)' origin hash is missing. resolving and updating accordingly" ) - return try resolveAndUpdateResolvedFile(forceResolution: false) + return try await resolveAndUpdateResolvedFile(forceResolution: false) } let currentHash = try self.computeResolvedFileOriginHash(root: root) @@ -237,14 +236,14 @@ extension Workspace { .emit( debug: "'\(self.location.resolvedVersionsFile.basename)' origin hash does do not match manifest dependencies. resolving and updating accordingly" ) - return try resolveAndUpdateResolvedFile(forceResolution: false) + return try await resolveAndUpdateResolvedFile(forceResolution: false) } observabilityScope .emit( debug: "'\(self.location.resolvedVersionsFile.basename)' origin hash matches manifest dependencies, attempting resolution based on this file" ) - let (manifests, precomputationResult) = try self.tryResolveBasedOnResolvedVersionsFile( + let (manifests, precomputationResult) = try await self.tryResolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, observabilityScope: observabilityScope @@ -261,13 +260,13 @@ extension Workspace { .emit( debug: "resolution based on '\(self.location.resolvedVersionsFile.basename)' could not be completed because \(reasonString). resolving and updating accordingly" ) - return try resolveAndUpdateResolvedFile(forceResolution: false) + return try await resolveAndUpdateResolvedFile(forceResolution: false) } } - func resolveAndUpdateResolvedFile(forceResolution: Bool) throws -> DependencyManifests { + func resolveAndUpdateResolvedFile(forceResolution: Bool) async throws -> DependencyManifests { observabilityScope.emit(debug: "resolving and updating '\(self.location.resolvedVersionsFile.basename)'") - return try self.resolveAndUpdateResolvedFile( + return try await self.resolveAndUpdateResolvedFile( root: root, explicitProduct: explicitProduct, forceResolution: forceResolution, @@ -297,8 +296,8 @@ extension Workspace { root: PackageGraphRootInput, explicitProduct: String?, observabilityScope: ObservabilityScope - ) throws -> DependencyManifests { - let (manifests, precomputationResult) = try self.tryResolveBasedOnResolvedVersionsFile( + ) async throws -> DependencyManifests { + let (manifests, precomputationResult) = try await self.tryResolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, observabilityScope: observabilityScope @@ -334,16 +333,15 @@ extension Workspace { root: PackageGraphRootInput, explicitProduct: String?, observabilityScope: ObservabilityScope - ) throws -> (DependencyManifests, ResolutionPrecomputationResult) { + ) async throws -> (DependencyManifests, ResolutionPrecomputationResult) { // Ensure the cache path exists. self.createCacheDirectories(observabilityScope: observabilityScope) // FIXME: this should not block - let rootManifests = try temp_await { self.loadRootManifests( + let rootManifests = try await self.loadRootManifests( packages: root.packages, - observabilityScope: observabilityScope, - completion: $0 - ) } + observabilityScope: observabilityScope + ) let graphRoot = PackageGraphRoot( input: root, manifests: rootManifests, @@ -356,7 +354,7 @@ extension Workspace { guard let pinsStore = observabilityScope.trap({ try self.pinsStore.load() }), !observabilityScope.errorsReported else { - return try ( + return try await ( self.loadDependencyManifests( root: graphRoot, observabilityScope: observabilityScope @@ -464,7 +462,7 @@ extension Workspace { } } - let currentManifests = try self.loadDependencyManifests( + let currentManifests = try await self.loadDependencyManifests( root: graphRoot, automaticallyAddManagedDependencies: true, observabilityScope: observabilityScope @@ -476,7 +474,7 @@ extension Workspace { observabilityScope: observabilityScope ) - let precomputationResult = try self.precomputeResolution( + let precomputationResult = try await self.precomputeResolution( root: graphRoot, dependencyManifests: currentManifests, pinsStore: pinsStore, @@ -500,17 +498,16 @@ extension Workspace { forceResolution: Bool, constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope - ) throws -> DependencyManifests { + ) async throws -> DependencyManifests { // Ensure the cache path exists and validate that edited dependencies. self.createCacheDirectories(observabilityScope: observabilityScope) // FIXME: this should not block // Load the root manifests and currently checked out manifests. - let rootManifests = try temp_await { self.loadRootManifests( + let rootManifests = try await self.loadRootManifests( packages: root.packages, - observabilityScope: observabilityScope, - completion: $0 - ) } + observabilityScope: observabilityScope + ) let rootManifestsMinimumToolsVersion = rootManifests.values.map(\.toolsVersion).min() ?? ToolsVersion.current let resolvedFileOriginHash = try self.computeResolvedFileOriginHash(root: root) @@ -522,7 +519,7 @@ extension Workspace { dependencyMapper: self.dependencyMapper, observabilityScope: observabilityScope ) - let currentManifests = try self.loadDependencyManifests( + let currentManifests = try await self.loadDependencyManifests( root: graphRoot, observabilityScope: observabilityScope ) @@ -555,7 +552,7 @@ extension Workspace { } else if !constraints.isEmpty || forceResolution { delegate?.willResolveDependencies(reason: .forced) } else { - let result = try self.precomputeResolution( + let result = try await self.precomputeResolution( root: graphRoot, dependencyManifests: currentManifests, pinsStore: pinsStore, @@ -599,7 +596,7 @@ extension Workspace { ) self.activeResolver = resolver - let result = self.resolveDependencies( + let result = await self.resolveDependencies( resolver: resolver, constraints: computedConstraints, observabilityScope: observabilityScope @@ -613,7 +610,7 @@ extension Workspace { } // Update the checkouts with dependency resolution result. - let packageStateChanges = self.updateDependenciesCheckouts( + let packageStateChanges = await self.updateDependenciesCheckouts( root: graphRoot, updateResults: result, observabilityScope: observabilityScope @@ -623,7 +620,7 @@ extension Workspace { } // Update the pinsStore. - let updatedDependencyManifests = try self.loadDependencyManifests( + let updatedDependencyManifests = try await self.loadDependencyManifests( root: graphRoot, observabilityScope: observabilityScope ) @@ -667,10 +664,10 @@ extension Workspace { updateResults: [DependencyResolverBinding], updateBranches: Bool = false, observabilityScope: ObservabilityScope - ) -> [(PackageReference, PackageStateChange)] { + ) async -> [(PackageReference, PackageStateChange)] { // Get the update package states from resolved results. - guard let packageStateChanges = observabilityScope.trap({ - try self.computePackageStateChanges( + guard let packageStateChanges = await observabilityScope.trap({ + try await self.computePackageStateChanges( root: root, resolvedDependencies: updateResults, updateBranches: updateBranches, @@ -697,20 +694,20 @@ extension Workspace { // Update or clone new packages. for (packageRef, state) in packageStateChanges { - observabilityScope.makeChildScope( + await observabilityScope.makeChildScope( description: "updating or cloning new packages", metadata: packageRef.diagnosticsMetadata ).trap { switch state { case .added(let state): - _ = try self.updateDependency( + _ = try await self.updateDependency( package: packageRef, requirement: state.requirement, productFilter: state.products, observabilityScope: observabilityScope ) case .updated(let state): - _ = try self.updateDependency( + _ = try await self.updateDependency( package: packageRef, requirement: state.requirement, productFilter: state.products, @@ -750,7 +747,7 @@ extension Workspace { requirement: PackageStateChange.Requirement, productFilter: ProductFilter, observabilityScope: ObservabilityScope - ) throws -> AbsolutePath { + ) async throws -> AbsolutePath { switch requirement { case .version(let version): // FIXME: this should not block @@ -768,13 +765,13 @@ extension Workspace { // FIXME: We need to get the revision here, and we don't have a // way to get it back out of the resolver which is very // annoying. Maybe we should make an SPI on the provider for this? - guard let tag = container.getTag(for: version) else { - throw try InternalError( + guard let tag = await container.getTag(for: version) else { + throw try await InternalError( "unable to get tag for \(package) \(version); available versions \(container.versionsDescending())" ) } - let revision = try container.getRevision(forTag: tag) - try container.checkIntegrity(version: version, revision: revision) + let revision = try await container.getRevision(forTag: tag) + try await container.checkIntegrity(version: version, revision: revision) return try self.checkoutRepository( package: package, at: .version(version, revision: revision), @@ -787,7 +784,7 @@ extension Workspace { observabilityScope: observabilityScope ) } else if let customContainer = container as? CustomPackageContainer { - let path = try customContainer.retrieve(at: version, observabilityScope: observabilityScope) + let path = try await customContainer.retrieve(at: version, observabilityScope: observabilityScope) let dependency = try ManagedDependency( packageRef: package, state: .custom(version: version, path: path), @@ -849,7 +846,7 @@ extension Workspace { pinsStore: PinsStore, constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope - ) throws -> ResolutionPrecomputationResult { + ) async throws -> ResolutionPrecomputationResult { let computedConstraints = try root.constraints() + // Include constraints from the manifests in the graph root. @@ -867,24 +864,23 @@ extension Workspace { availableLibraries: self.providedLibraries, observabilityScope: observabilityScope ) - let result = resolver.solve(constraints: computedConstraints) + do { + _ = try await resolver.solve(constraints: computedConstraints) - guard !observabilityScope.errorsReported else { - return .required(reason: .errorsPreviouslyReported) - } + guard !observabilityScope.errorsReported else { + return .required(reason: .errorsPreviouslyReported) + } - switch result { - case .success: return .notRequired - case .failure(ResolverPrecomputationError.missingPackage(let package)): + } catch ResolverPrecomputationError.missingPackage(let package) { return .required(reason: .newPackages(packages: [package])) - case .failure(ResolverPrecomputationError.differentRequirement(let package, let state, let requirement)): + } catch ResolverPrecomputationError.differentRequirement(let package, let state, let requirement) { return .required(reason: .packageRequirementChange( package: package, state: state, requirement: requirement )) - case .failure(let error): + } catch { return .required(reason: .other("\(error.interpolationDescription)")) } } @@ -1011,7 +1007,7 @@ extension Workspace { resolvedDependencies: [DependencyResolverBinding], updateBranches: Bool, observabilityScope: ObservabilityScope - ) throws -> [(PackageReference, PackageStateChange)] { + ) async throws -> [(PackageReference, PackageStateChange)] { // Load pins store and managed dependencies. let pinsStore = try self.pinsStore.load() var packageStateChanges: [PackageIdentity: (PackageReference, PackageStateChange)] = [:] @@ -1075,7 +1071,7 @@ extension Workspace { "invalid container for \(binding.package) expected a SourceControlPackageContainer" ) } - var revision = try container.getRevision(forIdentifier: identifier) + var revision = try await container.getRevision(forIdentifier: identifier) let branch = branch ?? (identifier == revision.identifier ? nil : identifier) // If we have a branch and we shouldn't be updating the @@ -1178,17 +1174,15 @@ extension Workspace { resolver: PubGrubDependencyResolver, constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope - ) -> [DependencyResolverBinding] { + ) async -> [DependencyResolverBinding] { os_signpost(.begin, name: SignpostName.pubgrub) - let result = resolver.solve(constraints: constraints) + do { + let result = try await resolver.solve(constraints: constraints) - os_signpost(.end, name: SignpostName.pubgrub) + os_signpost(.end, name: SignpostName.pubgrub) - // Take an action based on the result. - switch result { - case .success(let bindings): - return bindings - case .failure(let error): + return result + } catch { observabilityScope.emit(error) return [] } diff --git a/Sources/Workspace/Workspace+Editing.swift b/Sources/Workspace/Workspace+Editing.swift index cf429ad2eaa..c1d904a9d2d 100644 --- a/Sources/Workspace/Workspace+Editing.swift +++ b/Sources/Workspace/Workspace+Editing.swift @@ -27,7 +27,7 @@ extension Workspace { revision: Revision? = nil, checkoutBranch: String? = nil, observabilityScope: ObservabilityScope - ) throws { + ) async throws { // Look up the dependency and check if we can edit it. guard let dependency = self.state.dependencies[.plain(packageName)] else { observabilityScope.emit(.dependencyNotFound(packageName: packageName)) @@ -68,16 +68,13 @@ extension Workspace { // a valid manifest with name same as the package we are trying to edit. if fileSystem.exists(destination) { // FIXME: this should not block - let manifest = try temp_await { - self.loadManifest( - packageIdentity: dependency.packageRef.identity, - packageKind: .fileSystem(destination), - packagePath: destination, - packageLocation: dependency.packageRef.locationString, - observabilityScope: observabilityScope, - completion: $0 - ) - } + let manifest = try await self.loadManifest( + packageIdentity: dependency.packageRef.identity, + packageKind: .fileSystem(destination), + packagePath: destination, + packageLocation: dependency.packageRef.locationString, + observabilityScope: observabilityScope + ) guard manifest.displayName == packageName else { return observabilityScope @@ -174,7 +171,7 @@ extension Workspace { forceRemove: Bool, root: PackageGraphRootInput? = nil, observabilityScope: ObservabilityScope - ) throws { + ) async throws { // Compute if we need to force remove. var forceRemove = forceRemove @@ -234,7 +231,7 @@ extension Workspace { // Resolve the dependencies if workspace root is provided. We do this to // ensure the unedited version of this dependency is resolved properly. if let root { - try self._resolve( + try await self._resolve( root: root, explicitProduct: .none, resolvedFileStrategy: .update(forceResolution: false), diff --git a/Sources/Workspace/Workspace+Manifests.swift b/Sources/Workspace/Workspace+Manifests.swift index 8b48dea8df2..f2c386c25d4 100644 --- a/Sources/Workspace/Workspace+Manifests.swift +++ b/Sources/Workspace/Workspace+Manifests.swift @@ -10,12 +10,15 @@ // //===----------------------------------------------------------------------===// + +import _Concurrency import struct Basics.AbsolutePath import struct Basics.Diagnostic import struct Basics.InternalError import class Basics.ObservabilityScope import struct Basics.SwiftVersion -import func Basics.temp_await +import func Basics.findCycle +import func Basics.topologicalSort import func Basics.depthFirstSearch import class Basics.ThreadSafeKeyValueStore import class Dispatch.DispatchGroup @@ -36,10 +39,8 @@ import struct PackageModel.PackageReference import enum PackageModel.ProductFilter import struct PackageModel.ToolsVersion import protocol TSCBasic.FileSystem -import func TSCBasic.findCycle import struct TSCBasic.KeyedPair import struct TSCBasic.StringError -import func TSCBasic.topologicalSort import func TSCBasic.transitiveClosure import enum TSCUtility.Diagnostics import struct TSCUtility.Version @@ -418,7 +419,7 @@ extension Workspace { root: PackageGraphRoot, automaticallyAddManagedDependencies: Bool = false, observabilityScope: ObservabilityScope - ) throws -> DependencyManifests { + ) async throws -> DependencyManifests { let prepopulateManagedDependencies: ([PackageReference]) throws -> Void = { refs in // pre-populate managed dependencies if we are asked to do so (this happens when resolving to a resolved // file) @@ -458,7 +459,7 @@ extension Workspace { } // Validates that all the managed dependencies are still present in the file system. - self.fixManagedDependencies( + await self.fixManagedDependencies( observabilityScope: observabilityScope ) guard !observabilityScope.errorsReported else { @@ -474,11 +475,10 @@ extension Workspace { // Load root dependencies manifests (in parallel) let rootDependencies = root.dependencies.map(\.packageRef) try prepopulateManagedDependencies(rootDependencies) - let rootDependenciesManifests = try temp_await { self.loadManagedManifests( + let rootDependenciesManifests = try await self.loadManagedManifests( for: rootDependencies, - observabilityScope: observabilityScope, - completion: $0 - ) } + observabilityScope: observabilityScope + ) let topLevelManifests = root.manifests.merging(rootDependenciesManifests, uniquingKeysWith: { lhs, _ in lhs // prefer roots! @@ -486,26 +486,24 @@ extension Workspace { // optimization: preload first level dependencies manifest (in parallel) let firstLevelDependencies = topLevelManifests.values.map { $0.dependencies.map(\.packageRef) }.flatMap { $0 } - let firstLevelManifests = try temp_await { self.loadManagedManifests( + let firstLevelManifests = try await self.loadManagedManifests( for: firstLevelDependencies, - observabilityScope: observabilityScope, - completion: $0 - ) } // FIXME: this should not block + observabilityScope: observabilityScope + ) // Continue to load the rest of the manifest for this graph // Creates a map of loaded manifests. We do this to avoid reloading the shared nodes. var loadedManifests = firstLevelManifests - let successorManifests: (KeyedPair) throws -> [KeyedPair] = { pair in + let successorManifests: (KeyedPair) async throws -> [KeyedPair] = { pair in // optimization: preload manifest we know about in parallel let dependenciesRequired = pair.item.dependenciesRequired(for: pair.key.productFilter) let dependenciesToLoad = dependenciesRequired.map(\.packageRef) .filter { !loadedManifests.keys.contains($0.identity) } try prepopulateManagedDependencies(dependenciesToLoad) - let dependenciesManifests = try temp_await { self.loadManagedManifests( + let dependenciesManifests = try await self.loadManagedManifests( for: dependenciesToLoad, - observabilityScope: observabilityScope, - completion: $0 - ) } + observabilityScope: observabilityScope + ) dependenciesManifests.forEach { loadedManifests[$0.key] = $0.value } return dependenciesRequired.compactMap { dependency in loadedManifests[dependency.identity].flatMap { @@ -557,12 +555,18 @@ extension Workspace { { observabilityScope .emit( - error: "unable to override package '\(manifest.displayName)' because its identity '\(PackageIdentity(urlString: manifest.packageLocation))' doesn't match override's identity (directory name) '\(PackageIdentity(urlString: override.packageLocation))'" + error: """ + unable to override package '\(manifest.displayName)' because its identity '\( + PackageIdentity(urlString: manifest.packageLocation) + )' doesn't match override's identity (directory name) '\( + PackageIdentity(urlString: override.packageLocation) + )' + """ ) } } - let dependencies = try dependencyManifests.map { identity, manifest, productFilter -> ( + let dependencies = try await dependencyManifests.parallelMap { identity, manifest, productFilter -> ( Manifest, ManagedDependency, ProductFilter, @@ -573,7 +577,7 @@ extension Workspace { } let packageRef = PackageReference(identity: identity, kind: manifest.packageKind) - let fileSystem = try self.getFileSystem( + let fileSystem = try await self.getFileSystem( package: packageRef, state: dependency.state, observabilityScope: observabilityScope @@ -592,39 +596,38 @@ extension Workspace { /// Loads the given manifests, if it is present in the managed dependencies. private func loadManagedManifests( for packages: [PackageReference], - observabilityScope: ObservabilityScope, - completion: @escaping (Result<[PackageIdentity: Manifest], Error>) -> Void - ) { - let sync = DispatchGroup() - let manifests = ThreadSafeKeyValueStore() - Set(packages).forEach { package in - sync.enter() - self.loadManagedManifest(for: package, observabilityScope: observabilityScope) { manifest in - defer { sync.leave() } - if let manifest { - manifests[package.identity] = manifest + observabilityScope: ObservabilityScope + ) async throws -> [PackageIdentity: Manifest] { + try await withThrowingTaskGroup(of: (PackageIdentity, Manifest?).self) { group in + for package in Set(packages) { + group.addTask { + await ( + package.identity, + self.loadManagedManifest(for: package, observabilityScope: observabilityScope) + ) } } - } - sync.notify(queue: .sharedConcurrent) { - completion(.success(manifests.get())) + var result = [PackageIdentity: Manifest]() + for try await case let (identity, manifest?) in group { + result[identity] = manifest + } + return result } } /// Loads the given manifest, if it is present in the managed dependencies. private func loadManagedManifest( for package: PackageReference, - observabilityScope: ObservabilityScope, - completion: @escaping (Manifest?) -> Void - ) { + observabilityScope: ObservabilityScope + ) async -> Manifest? { // Check if this dependency is available. // we also compare the location as this function may attempt to load // dependencies that have the same identity but from a different location // which is an error case we diagnose an report about in the GraphLoading part which // is prepared to handle the case where not all manifest are available guard let managedDependency = self.state.dependencies[comparingLocation: package] else { - return completion(.none) + return nil } // Get the path of the package. @@ -663,7 +666,7 @@ extension Workspace { let fileSystem: FileSystem? do { - fileSystem = try self.getFileSystem( + fileSystem = try await self.getFileSystem( package: package, state: managedDependency.state, observabilityScope: observabilityScope @@ -678,7 +681,8 @@ extension Workspace { } // Load and return the manifest. - self.loadManifest( + // error is added to diagnostics in the function below + return try? await self.loadManifest( packageIdentity: managedDependency.packageRef.identity, packageKind: packageKind, packagePath: packagePath, @@ -686,10 +690,7 @@ extension Workspace { packageVersion: packageVersion, fileSystem: fileSystem, observabilityScope: observabilityScope - ) { result in - // error is added to diagnostics in the function above - completion(try? result.get()) - } + ) } /// Load the manifest at a given path. @@ -702,9 +703,8 @@ extension Workspace { packageLocation: String, packageVersion: Version? = nil, fileSystem: FileSystem? = nil, - observabilityScope: ObservabilityScope, - completion: @escaping (Result) -> Void - ) { + observabilityScope: ObservabilityScope + ) async throws -> Manifest { let fileSystem = fileSystem ?? self.fileSystem // Load the manifest, bracketed by the calls to the delegate callbacks. @@ -722,61 +722,74 @@ extension Workspace { var manifestLoadingDiagnostics = [Diagnostic]() + defer { + manifestLoadingScope.emit(manifestLoadingDiagnostics) + } + let start = DispatchTime.now() - self.manifestLoader.load( - packagePath: packagePath, - packageIdentity: packageIdentity, - packageKind: packageKind, - packageLocation: packageLocation, - packageVersion: packageVersion.map { (version: $0, revision: nil) }, - currentToolsVersion: self.currentToolsVersion, - identityResolver: self.identityResolver, - dependencyMapper: self.dependencyMapper, - fileSystem: fileSystem, - observabilityScope: manifestLoadingScope, - delegateQueue: .sharedConcurrent, - callbackQueue: .sharedConcurrent - ) { result in + do { + let manifest = try await self.manifestLoader.load( + packagePath: packagePath, + packageIdentity: packageIdentity, + packageKind: packageKind, + packageLocation: packageLocation, + packageVersion: packageVersion.map { (version: $0, revision: nil) }, + currentToolsVersion: self.currentToolsVersion, + identityResolver: self.identityResolver, + dependencyMapper: self.dependencyMapper, + fileSystem: fileSystem, + observabilityScope: manifestLoadingScope, + delegateQueue: .sharedConcurrent, + callbackQueue: .sharedConcurrent + ) + let duration = start.distance(to: .now()) - var result = result - switch result { - case .failure(let error): - manifestLoadingDiagnostics.append(.error(error)) - self.delegate?.didLoadManifest( - packageIdentity: packageIdentity, - packagePath: packagePath, - url: packageLocation, - version: packageVersion, - packageKind: packageKind, - manifest: nil, - diagnostics: manifestLoadingDiagnostics, - duration: duration - ) - case .success(let manifest): - let validator = ManifestValidator( - manifest: manifest, - sourceControlValidator: self.repositoryManager, - fileSystem: self.fileSystem - ) - let validationIssues = validator.validate() - if !validationIssues.isEmpty { - // Diagnostics.fatalError indicates that a more specific diagnostic has already been added. - result = .failure(Diagnostics.fatalError) - manifestLoadingDiagnostics.append(contentsOf: validationIssues) - } - self.delegate?.didLoadManifest( - packageIdentity: packageIdentity, - packagePath: packagePath, - url: packageLocation, - version: packageVersion, - packageKind: packageKind, - manifest: manifest, - diagnostics: manifestLoadingDiagnostics, - duration: duration - ) + let validator = ManifestValidator( + manifest: manifest, + sourceControlValidator: self.repositoryManager, + fileSystem: self.fileSystem + ) + let validationIssues = validator.validate() + var diagnostics: Diagnostics? + if !validationIssues.isEmpty { + manifestLoadingDiagnostics.append(contentsOf: validationIssues) + + // Diagnostics.fatalError indicates that a more specific diagnostic has already been added. + diagnostics = Diagnostics.fatalError } - manifestLoadingScope.emit(manifestLoadingDiagnostics) - completion(result) + self.delegate?.didLoadManifest( + packageIdentity: packageIdentity, + packagePath: packagePath, + url: packageLocation, + version: packageVersion, + packageKind: packageKind, + manifest: manifest, + diagnostics: manifestLoadingDiagnostics, + duration: duration + ) + + if let diagnostics { + throw diagnostics + } + + return manifest + } catch Diagnostics.fatalError { + // Rethrow `fatalError` without a delegate `didLoadManifest` call, as it already happened + throw Diagnostics.fatalError + } catch { + let duration = start.distance(to: .now()) + manifestLoadingDiagnostics.append(.error(error)) + self.delegate?.didLoadManifest( + packageIdentity: packageIdentity, + packagePath: packagePath, + url: packageLocation, + version: packageVersion, + packageKind: packageKind, + manifest: nil, + diagnostics: manifestLoadingDiagnostics, + duration: duration + ) + throw error } } @@ -786,7 +799,7 @@ extension Workspace { /// fallback on the original checkout. private func fixManagedDependencies( observabilityScope: ObservabilityScope - ) { + ) async { // Reset managed dependencies if the state file was removed during the lifetime of the Workspace object. if !self.state.dependencies.isEmpty && !self.state.stateFileExists() { try? self.state.reset() @@ -795,7 +808,7 @@ extension Workspace { // Make a copy of dependencies as we might mutate them in the for loop. let allDependencies = Array(self.state.dependencies) for dependency in allDependencies { - observabilityScope.makeChildScope( + await observabilityScope.makeChildScope( description: "copying managed dependencies", metadata: dependency.packageRef.diagnosticsMetadata ).trap { @@ -827,17 +840,18 @@ extension Workspace { .emit(.registryDependencyMissing(packageName: dependency.packageRef.identity.description)) case .custom(let version, let path): - let container = try temp_await { - self.packageContainerProvider.getContainer( - for: dependency.packageRef, - updateStrategy: .never, - observabilityScope: observabilityScope, - on: .sharedConcurrent, - completion: $0 - ) - } + let container = try await self.packageContainerProvider.getContainer( + for: dependency.packageRef, + updateStrategy: .never, + observabilityScope: observabilityScope, + on: .sharedConcurrent + ) + if let customContainer = container as? CustomPackageContainer { - let newPath = try customContainer.retrieve(at: version, observabilityScope: observabilityScope) + let newPath = try await customContainer.retrieve( + at: version, + observabilityScope: observabilityScope + ) observabilityScope .emit(.customDependencyMissing(packageName: dependency.packageRef.identity.description)) @@ -855,7 +869,7 @@ extension Workspace { // Note: We don't resolve the dependencies when unediting // here because we expect this method to be called as part // of some other resolve operation (i.e. resolve, update, etc). - try self.unedit( + try await self.unedit( dependency: dependency, forceRemove: true, observabilityScope: observabilityScope @@ -880,7 +894,7 @@ extension Workspace { package: PackageReference, state: Workspace.ManagedDependency.State, observabilityScope: ObservabilityScope - ) throws -> FileSystem? { + ) async throws -> FileSystem? { // Only custom containers may provide a file system. guard self.customPackageContainerProvider != nil else { return nil @@ -891,20 +905,17 @@ extension Workspace { case .fileSystem: return nil case .custom: - let container = try temp_await { - self.packageContainerProvider.getContainer( - for: package, - updateStrategy: .never, - observabilityScope: observabilityScope, - on: .sharedConcurrent, - completion: $0 - ) - } + let container = try await self.packageContainerProvider.getContainer( + for: package, + updateStrategy: .never, + observabilityScope: observabilityScope, + on: .sharedConcurrent + ) guard let customContainer = container as? CustomPackageContainer else { observabilityScope.emit(error: "invalid custom dependency container: \(container)") return nil } - return try customContainer.getFileSystem() + return try await customContainer.getFileSystem() default: observabilityScope.emit(error: "invalid managed dependency state for custom dependency: \(state)") return nil diff --git a/Sources/Workspace/Workspace.swift b/Sources/Workspace/Workspace.swift index 8d462a0b7ff..3c82242984c 100644 --- a/Sources/Workspace/Workspace.swift +++ b/Sources/Workspace/Workspace.swift @@ -612,9 +612,9 @@ extension Workspace { revision: Revision? = nil, checkoutBranch: String? = nil, observabilityScope: ObservabilityScope - ) { + ) async { do { - try self._edit( + try await self._edit( packageName: packageName, path: path, revision: revision, @@ -642,7 +642,7 @@ extension Workspace { forceRemove: Bool, root: PackageGraphRootInput, observabilityScope: ObservabilityScope - ) throws { + ) async throws { guard let dependency = self.state.dependencies[.plain(packageName)] else { observabilityScope.emit(.dependencyNotFound(packageName: packageName)) return @@ -653,7 +653,7 @@ extension Workspace { metadata: dependency.packageRef.diagnosticsMetadata ) - try self.unedit( + try await self.unedit( dependency: dependency, forceRemove: forceRemove, root: root, @@ -673,8 +673,8 @@ extension Workspace { forceResolution: Bool = false, forceResolvedVersions: Bool = false, observabilityScope: ObservabilityScope - ) throws { - try self._resolve( + ) async throws { + try await self._resolve( root: root, explicitProduct: explicitProduct, resolvedFileStrategy: forceResolvedVersions ? .lockFile : forceResolution ? .update(forceResolution: true) : @@ -703,7 +703,7 @@ extension Workspace { branch: String? = nil, revision: String? = nil, observabilityScope: ObservabilityScope - ) throws { + ) async throws { // Look up the dependency and check if we can pin it. guard let dependency = self.state.dependencies[.plain(packageName)] else { throw StringError("dependency '\(packageName)' was not found") @@ -748,7 +748,7 @@ extension Workspace { ) // Run the resolution. - try self.resolveAndUpdateResolvedFile( + try await self.resolveAndUpdateResolvedFile( root: root, forceResolution: false, constraints: [constraint], @@ -763,8 +763,8 @@ extension Workspace { public func resolveBasedOnResolvedVersionsFile( root: PackageGraphRootInput, observabilityScope: ObservabilityScope - ) throws { - try self._resolveBasedOnResolvedVersionsFile( + ) async throws { + try await self._resolveBasedOnResolvedVersionsFile( root: root, explicitProduct: .none, observabilityScope: observabilityScope @@ -872,8 +872,8 @@ extension Workspace { packages: [String] = [], dryRun: Bool = false, observabilityScope: ObservabilityScope - ) throws -> [(PackageReference, Workspace.PackageStateChange)]? { - try self._updateDependencies( + ) async throws -> [(PackageReference, Workspace.PackageStateChange)]? { + try await self._updateDependencies( root: root, packages: packages, dryRun: dryRun, @@ -890,7 +890,7 @@ extension Workspace { testEntryPointPath: AbsolutePath? = nil, expectedSigningEntities: [PackageIdentity: RegistryReleaseMetadata.SigningEntity] = [:], observabilityScope: ObservabilityScope - ) throws -> ModulesGraph { + ) async throws -> ModulesGraph { let start = DispatchTime.now() self.delegate?.willLoadGraph() defer { @@ -904,7 +904,7 @@ extension Workspace { try self.state.reload() // Perform dependency resolution, if required. - let manifests = try self._resolve( + let manifests = try await self._resolve( root: root, explicitProduct: explicitProduct, resolvedFileStrategy: forceResolvedVersions ? .lockFile : .bestEffort, @@ -950,8 +950,8 @@ extension Workspace { rootPath: AbsolutePath, explicitProduct: String? = nil, observabilityScope: ObservabilityScope - ) throws -> ModulesGraph { - try self.loadPackageGraph( + ) async throws -> ModulesGraph { + try await self.loadPackageGraph( rootInput: PackageGraphRootInput(packages: [rootPath]), explicitProduct: explicitProduct, observabilityScope: observabilityScope @@ -963,52 +963,31 @@ extension Workspace { packages: [AbsolutePath], observabilityScope: ObservabilityScope ) async throws -> [AbsolutePath: Manifest] { - try await withCheckedThrowingContinuation { continuation in - self.loadRootManifests(packages: packages, observabilityScope: observabilityScope) { result in - continuation.resume(with: result) - } - } - } - - /// Loads and returns manifests at the given paths. - @available(*, noasync, message: "Use the async alternative") - public func loadRootManifests( - packages: [AbsolutePath], - observabilityScope: ObservabilityScope, - completion: @escaping (Result<[AbsolutePath: Manifest], Error>) -> Void - ) { - let lock = NSLock() - let sync = DispatchGroup() - var rootManifests = [AbsolutePath: Manifest]() - Set(packages).forEach { package in - sync.enter() - // TODO: this does not use the identity resolver which is probably fine since its the root packages - self.loadManifest( - packageIdentity: PackageIdentity(path: package), - packageKind: .root(package), - packagePath: package, - packageLocation: package.pathString, - observabilityScope: observabilityScope - ) { result in - defer { sync.leave() } - if case .success(let manifest) = result { - lock.withLock { - rootManifests[package] = manifest - } + try await withThrowingTaskGroup(of: (AbsolutePath, Manifest?).self) { group in + for package in Set(packages) { + group.addTask { + // TODO: this does not use the identity resolver which is probably fine since its the root packages + (package, try? await self.loadManifest( + packageIdentity: PackageIdentity(path: package), + packageKind: .root(package), + packagePath: package, + packageLocation: package.pathString, + observabilityScope: observabilityScope + )) } } - } - sync.notify(queue: .sharedConcurrent) { + let rootManifests = try await group.reduce(into: [:]) { $0[$1.0] = $1.1 } + // Check for duplicate root packages. let duplicateRoots = rootManifests.values.spm_findDuplicateElements(by: \.displayName) if !duplicateRoots.isEmpty { let name = duplicateRoots[0][0].displayName observabilityScope.emit(error: "found multiple top-level packages named '\(name)'") - return completion(.success([:])) + return [:] } - completion(.success(rootManifests)) + return rootManifests } } @@ -1017,103 +996,75 @@ extension Workspace { at path: AbsolutePath, observabilityScope: ObservabilityScope ) async throws -> Manifest { - try await withCheckedThrowingContinuation { continuation in - self.loadRootManifest(at: path, observabilityScope: observabilityScope) { result in - continuation.resume(with: result) - } + let manifest = try await self.loadRootManifests(packages: [path], observabilityScope: observabilityScope) + + // normally, we call loadRootManifests which attempts to load any manifest it can and report errors via + // diagnostics + // in this case, we want to load a specific manifest, so if the diagnostics contains an error we want to + // throw + guard !observabilityScope.errorsReported else { + throw Diagnostics.fatalError } - } - - /// Loads and returns manifest at the given path. - public func loadRootManifest( - at path: AbsolutePath, - observabilityScope: ObservabilityScope, - completion: @escaping (Result) -> Void - ) { - self.loadRootManifests(packages: [path], observabilityScope: observabilityScope) { result in - completion(result.tryMap { - // normally, we call loadRootManifests which attempts to load any manifest it can and report errors via - // diagnostics - // in this case, we want to load a specific manifest, so if the diagnostics contains an error we want to - // throw - guard !observabilityScope.errorsReported else { - throw Diagnostics.fatalError - } - guard let manifest = $0[path] else { - throw InternalError("Unknown manifest for '\(path)'") - } - return manifest - }) - } - } - - /// Loads root package - public func loadRootPackage(at path: AbsolutePath, observabilityScope: ObservabilityScope) async throws -> Package { - try await withCheckedThrowingContinuation { continuation in - self.loadRootPackage(at: path, observabilityScope: observabilityScope) { result in - continuation.resume(with: result) - } + guard let manifest = manifest[path] else { + throw InternalError("Unknown manifest for '\(path)'") } + return manifest } /// Loads root package public func loadRootPackage( at path: AbsolutePath, - observabilityScope: ObservabilityScope, - completion: @escaping (Result) -> Void - ) { - self.loadRootManifest(at: path, observabilityScope: observabilityScope) { result in - let result = result.tryMap { manifest -> Package in - let identity = try self.identityResolver.resolveIdentity(for: manifest.packageKind) - - // radar/82263304 - // compute binary artifacts for the sake of constructing a project model - // note this does not actually download remote artifacts and as such does not have the artifact's type - // or path - let binaryArtifacts = try manifest.targets.filter { $0.type == .binary } - .reduce(into: [String: BinaryArtifact]()) { partial, target in - if let path = target.path { - let artifactPath = try manifest.path.parentDirectory - .appending(RelativePath(validating: path)) - guard let (_, artifactKind) = try BinaryArtifactsManager.deriveBinaryArtifact( - fileSystem: self.fileSystem, - path: artifactPath, - observabilityScope: observabilityScope - ) else { - throw StringError("\(artifactPath) does not contain binary artifact") - } - partial[target.name] = BinaryArtifact( - kind: artifactKind, - originURL: .none, - path: artifactPath - ) - } else if let url = target.url.flatMap(URL.init(string:)) { - let fakePath = try manifest.path.parentDirectory.appending(components: "remote", "archive") - .appending(RelativePath(validating: url.lastPathComponent)) - partial[target.name] = BinaryArtifact( - kind: .unknown, - originURL: url.absoluteString, - path: fakePath - ) - } else { - throw InternalError("a binary target should have either a path or a URL and a checksum") - } + observabilityScope: ObservabilityScope + ) async throws -> Package { + let manifest = try await self.loadRootManifest(at: path, observabilityScope: observabilityScope) + + let identity = try self.identityResolver.resolveIdentity(for: manifest.packageKind) + + // radar/82263304 + // compute binary artifacts for the sake of constructing a project model + // note this does not actually download remote artifacts and as such does not have the artifact's type + // or path + let binaryArtifacts = try manifest.targets.filter { $0.type == .binary } + .reduce(into: [String: BinaryArtifact]()) { partial, target in + if let path = target.path { + let artifactPath = try manifest.path.parentDirectory + .appending(RelativePath(validating: path)) + guard let (_, artifactKind) = try BinaryArtifactsManager.deriveBinaryArtifact( + fileSystem: self.fileSystem, + path: artifactPath, + observabilityScope: observabilityScope + ) else { + throw StringError("\(artifactPath) does not contain binary artifact") } - - let builder = PackageBuilder( - identity: identity, - manifest: manifest, - productFilter: .everything, - path: path, - additionalFileRules: [], - binaryArtifacts: binaryArtifacts, - fileSystem: self.fileSystem, - observabilityScope: observabilityScope - ) - return try builder.construct() + partial[target.name] = BinaryArtifact( + kind: artifactKind, + originURL: .none, + path: artifactPath + ) + } else if let url = target.url.flatMap(URL.init(string:)) { + let fakePath = try manifest.path.parentDirectory.appending(components: "remote", "archive") + .appending(RelativePath(validating: url.lastPathComponent)) + partial[target.name] = BinaryArtifact( + kind: .unknown, + originURL: url.absoluteString, + path: fakePath + ) + } else { + throw InternalError("a binary target should have either a path or a URL and a checksum") + } } - completion(result) - } + + let builder = PackageBuilder( + identity: identity, + manifest: manifest, + productFilter: .everything, + path: path, + additionalFileRules: [], + binaryArtifacts: binaryArtifacts, + fileSystem: self.fileSystem, + observabilityScope: observabilityScope + ) + return try builder.construct() } public func loadPluginImports( @@ -1145,55 +1096,40 @@ extension Workspace { } return importList } - - public func loadPackage( - with identity: PackageIdentity, - packageGraph: ModulesGraph, - observabilityScope: ObservabilityScope - ) async throws -> Package { - try await safe_async { - self.loadPackage(with: identity, packageGraph: packageGraph, observabilityScope: observabilityScope, completion: $0) - } - } /// Loads a single package in the context of a previously loaded graph. This can be useful for incremental loading /// in a longer-lived program, like an IDE. - @available(*, noasync, message: "Use the async alternative") public func loadPackage( with identity: PackageIdentity, packageGraph: ModulesGraph, - observabilityScope: ObservabilityScope, - completion: @escaping (Result) -> Void - ) { + observabilityScope: ObservabilityScope + ) async throws -> Package { guard let previousPackage = packageGraph.package(for: identity) else { - return completion(.failure(StringError("could not find package with identity \(identity)"))) + throw StringError("could not find package with identity \(identity)") } - self.loadManifest( + let manifest = try await self.loadManifest( packageIdentity: identity, packageKind: previousPackage.underlying.manifest.packageKind, packagePath: previousPackage.path, packageLocation: previousPackage.underlying.manifest.packageLocation, observabilityScope: observabilityScope - ) { result in - let result = result.tryMap { manifest -> Package in - let builder = PackageBuilder( - identity: identity, - manifest: manifest, - productFilter: .everything, - // TODO: this will not be correct when reloading a transitive dependencies if `ENABLE_TARGET_BASED_DEPENDENCY_RESOLUTION` is enabled - path: previousPackage.path, - additionalFileRules: self.configuration.additionalFileRules, - binaryArtifacts: packageGraph.binaryArtifacts[identity] ?? [:], - shouldCreateMultipleTestProducts: self.configuration.shouldCreateMultipleTestProducts, - createREPLProduct: self.configuration.createREPLProduct, - fileSystem: self.fileSystem, - observabilityScope: observabilityScope - ) - return try builder.construct() - } - completion(result) - } + ) + + let builder = PackageBuilder( + identity: identity, + manifest: manifest, + productFilter: .everything, + // TODO: this will not be correct when reloading a transitive dependencies if `ENABLE_TARGET_BASED_DEPENDENCY_RESOLUTION` is enabled + path: previousPackage.path, + additionalFileRules: self.configuration.additionalFileRules, + binaryArtifacts: packageGraph.binaryArtifacts[identity] ?? [:], + shouldCreateMultipleTestProducts: self.configuration.shouldCreateMultipleTestProducts, + createREPLProduct: self.configuration.createREPLProduct, + fileSystem: self.fileSystem, + observabilityScope: observabilityScope + ) + return try builder.construct() } /// Returns `true` if the file at the given path might influence build settings for a `swiftc` or `clang` invocation diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 0535c88fccc..5d8b4c64e88 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -3374,7 +3374,7 @@ final class PackageCommandTests: CommandsTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let _ = try workspace.loadPackageGraph( + let _ = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) diff --git a/Tests/FunctionalTests/PluginTests.swift b/Tests/FunctionalTests/PluginTests.swift index e22eef6f0c4..93671749be2 100644 --- a/Tests/FunctionalTests/PluginTests.swift +++ b/Tests/FunctionalTests/PluginTests.swift @@ -445,7 +445,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) @@ -632,7 +632,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) @@ -729,7 +729,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) @@ -1045,7 +1045,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) diff --git a/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift b/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift deleted file mode 100644 index ca2438ccb00..00000000000 --- a/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift +++ /dev/null @@ -1,208 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 2014-2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import Basics -import PackageGraph -import PackageLoading -import PackageModel -import SourceControl -import SPMTestSupport -import XCTest - -import enum TSCBasic.JSON -import protocol TSCBasic.JSONMappable -import protocol TSCBasic.JSONSerializable - -import func TSCUtility.measure -import struct TSCUtility.Version - -import class TSCTestSupport.XCTestCasePerf - -private let v1: Version = "1.0.0" -private let v1Range: VersionSetSpecifier = .range("1.0.0" ..< "2.0.0") - -class DependencyResolverRealWorldPerfTests: XCTestCasePerf { - func testKituraPubGrub_X100() throws { - #if !os(macOS) - try XCTSkipIf(true, "test is only supported on macOS") - #endif - try runPackageTestPubGrub(name: "kitura.json", N: 100) - } - - func testZewoPubGrub_X100() throws { - #if !os(macOS) - try XCTSkipIf(true, "test is only supported on macOS") - #endif - try runPackageTestPubGrub(name: "ZewoHTTPServer.json", N: 100) - } - - func testPerfectPubGrub_X100() throws { - #if !os(macOS) - try XCTSkipIf(true, "test is only supported on macOS") - #endif - try runPackageTestPubGrub(name: "PerfectHTTPServer.json", N: 100) - } - - func testSourceKittenPubGrub_X100() throws { - #if !os(macOS) - try XCTSkipIf(true, "test is only supported on macOS") - #endif - try runPackageTestPubGrub(name: "SourceKitten.json", N: 100) - } - - func runPackageTestPubGrub(name: String, N: Int = 1) throws { - let graph = try mockGraph(for: name) - let provider = MockPackageContainerProvider(containers: graph.containers) - - measure { - for _ in 0 ..< N { - let resolver = PubGrubDependencyResolver(provider: provider, observabilityScope: ObservabilitySystem.NOOP) - switch resolver.solve(constraints: graph.constraints) { - case .success(let result): - let result: [(container: PackageReference, version: Version)] = result.compactMap { - guard case .version(let version, _) = $0.boundVersion else { - XCTFail("Unexpected result") - return nil - } - return ($0.package, version) - } - graph.checkResult(result) - case .failure: - XCTFail("Unexpected result") - return - } - } - } - } - - func mockGraph(for name: String) throws -> MockDependencyGraph { - let input = AbsolutePath(#file).parentDirectory.appending("Inputs").appending(component: name) - let jsonString: Data = try localFileSystem.readFileContents(input) - let json = try JSON(data: jsonString) - return MockDependencyGraph(json) - } -} - - -// MARK: - JSON - -public extension MockDependencyGraph { - init(_ json: JSON) { - guard case .dictionary(let dict) = json else { fatalError() } - guard case .string(let name)? = dict["name"] else { fatalError() } - guard case .array(let constraints)? = dict["constraints"] else { fatalError() } - guard case .array(let containers)? = dict["containers"] else { fatalError() } - guard case .dictionary(let result)? = dict["result"] else { fatalError() } - - self.init( - name: name, - constraints: constraints.map(PackageContainerConstraint.init(json:)), - containers: containers.map(MockPackageContainer.init(json:)), - result: Dictionary(uniqueKeysWithValues: try! result.map { value in - let (container, version) = value - guard case .string(let str) = version else { fatalError() } - let package = PackageReference.localSourceControl(identity: .plain(container.lowercased()), path: try .init(validating: "/\(container)")) - return (package, Version(str)!) - }) - ) - } -} - -private extension MockPackageContainer { - convenience init(json: JSON) { - guard case .dictionary(let dict) = json else { fatalError() } - guard case .string(let identifier)? = dict["identifier"] else { fatalError() } - guard case .dictionary(let versions)? = dict["versions"] else { fatalError() } - - var depByVersion: [Version: [(container: String, versionRequirement: VersionSetSpecifier)]] = [:] - for (version, deps) in versions { - guard case .array(let depArray) = deps else { fatalError() } - depByVersion[Version(version)!] = depArray - .map(PackageContainerConstraint.init(json:)) - .map { constraint in - switch constraint.requirement { - case .versionSet(let versionSet): - return (constraint.package.identity.description, versionSet) - case .unversioned: - fatalError() - case .revision: - fatalError() - } - } - } - - try! self.init(name: identifier, dependenciesByVersion: depByVersion) - } -} - -private extension MockPackageContainer.Constraint { - init(json: JSON) { - guard case .dictionary(let dict) = json else { fatalError() } - guard case .string(let identifier)? = dict["identifier"] else { fatalError() } - guard let requirement = dict["requirement"] else { fatalError() } - let products: ProductFilter = try! JSON(dict).get("products") - let ref = PackageReference.localSourceControl(identity: .plain(identifier), path: .root) - self.init(package: ref, versionRequirement: VersionSetSpecifier(requirement), products: products) - } -} - -private extension VersionSetSpecifier { - init(_ json: JSON) { - switch json { - case .string(let str): - switch str { - case "any": self = .any - case "empty": self = .empty - default: fatalError() - } - case .array(let arr): - switch arr.count { - case 1: - guard case .string(let str) = arr[0] else { fatalError() } - self = .exact(Version(str)!) - case 2: - let versions = arr.map { json -> Version in - guard case .string(let str) = json else { fatalError() } - return Version(str)! - } - self = .range(versions[0] ..< versions[1]) - default: fatalError() - } - default: fatalError() - } - } -} - -extension ProductFilter { - public func toJSON() -> JSON { - switch self { - case .everything: - return "all".toJSON() - case .specific(let products): - return products.sorted().toJSON() - } - } - - public init(json: JSON) throws { - if let products = try? [String](json: json) { - self = .specific(Set(products)) - } else { - self = .everything - } - } -} - -#if compiler(<6.0) -extension ProductFilter: JSONSerializable, JSONMappable {} -#else -extension ProductFilter: @retroactive JSONSerializable, @retroactive JSONMappable {} -#endif diff --git a/Tests/PackageGraphTests/PubgrubTests.swift b/Tests/PackageGraphTests/PubgrubTests.swift index 5152cda19d1..ef8d3de143e 100644 --- a/Tests/PackageGraphTests/PubgrubTests.swift +++ b/Tests/PackageGraphTests/PubgrubTests.swift @@ -325,11 +325,10 @@ final class PubgrubTests: XCTestCase { ]) } - func testUpdatePackageIdentifierAfterResolution() throws { + func testUpdatePackageIdentifierAfterResolution() async throws { let fooURL = SourceControlURL("https://example.com/foo") let fooRef = PackageReference.remoteSourceControl(identity: PackageIdentity(url: fooURL), url: fooURL) - let foo = MockContainer(package: fooRef, dependenciesByVersion: [v1: [:]]) - foo.manifestName = "bar" + let foo = MockContainer(package: fooRef, dependenciesByVersion: [v1: [:]], manifestName: "bar") let provider = MockProvider(containers: [foo]) @@ -337,16 +336,11 @@ final class PubgrubTests: XCTestCase { let deps = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: deps) + let bindings = try await resolver.solve(constraints: deps) - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let bindings): - XCTAssertEqual(bindings.count, 1) - let foo = bindings.first { $0.package.identity == .plain("foo") } - XCTAssertEqual(foo?.package.deprecatedName, "bar") - } + XCTAssertEqual(bindings.count, 1) + let fooBinding = bindings.first { $0.package.identity == .plain("foo") } + XCTAssertEqual(fooBinding?.package.deprecatedName, "bar") } func testResolverConflictResolution() throws { @@ -362,12 +356,12 @@ final class PubgrubTests: XCTestCase { XCTAssertThrowsError(try solver1.resolve(state: state1, conflict: notRoot)) } - func testResolverDecisionMaking() throws { + func testResolverDecisionMaking() async throws { let solver1 = PubGrubDependencyResolver(provider: emptyProvider, observabilityScope: ObservabilitySystem.NOOP) let state1 = PubGrubDependencyResolver.State(root: rootNode) // No decision can be made if no unsatisfied terms are available. - XCTAssertNil(try temp_await { solver1.makeDecision(state: state1, completion: $0) }) + try await XCTAssertAsyncNil(try await solver1.makeDecision(state: state1)) let a = MockContainer(package: aRef, dependenciesByVersion: [ "0.0.0": [:], @@ -383,7 +377,7 @@ final class PubgrubTests: XCTestCase { XCTAssertEqual(state2.incompatibilities.count, 0) - let decision = try temp_await { solver2.makeDecision(state: state2, completion: $0) } + let decision = try await solver2.makeDecision(state: state2) XCTAssertEqual(decision, .product("a", package: "a")) XCTAssertEqual(state2.incompatibilities.count, 3) @@ -627,20 +621,20 @@ final class PubgrubTests: XCTestCase { ) XCTAssertThrowsError(try solver.resolve(state: state, conflict: conflict)) { error in - XCTAssertTrue(error is PubGrubDependencyResolver.PubgrubError) + XCTAssertTrue(error is PubgrubError) } } - func testResolutionNoConflicts() throws { - try builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) - try builder.serve("b", at: v1) - try builder.serve("b", at: v2) + func testResolutionNoConflicts() async throws { + try await builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -648,19 +642,19 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionAvoidingConflictResolutionDuringDecisionMaking() throws { - try builder.serve("a", at: v1) - try builder.serve("a", at: v1_1, with: ["a": ["b": (.versionSet(v2Range), .specific(["b"]))]]) - try builder.serve("b", at: v1) - try builder.serve("b", at: v1_1) - try builder.serve("b", at: v2) + func testResolutionAvoidingConflictResolutionDuringDecisionMaking() async throws { + try await builder.serve("a", at: v1) + try await builder.serve("a", at: v1_1, with: ["a": ["b": (.versionSet(v2Range), .specific(["b"]))]]) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v1_1) + try await builder.serve("b", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .specific(["a"])), "b": (.versionSet(v1Range), .specific(["b"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -668,37 +662,37 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionPerformingConflictResolution() throws { + func testResolutionPerformingConflictResolution() async throws { // Pubgrub has a listed as >=1.0.0, which we can't really represent here. // It's either .any or 1.0.0..2. Both should have the same // effect though. - try builder.serve("a", at: v1) - try builder.serve("a", at: v2, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) - try builder.serve("b", at: v1, with: ["b": ["a": (.versionSet(v1Range), .specific(["a"]))]]) + try await builder.serve("a", at: v1) + try await builder.serve("a", at: v2, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) + try await builder.serve("b", at: v1, with: ["b": ["a": (.versionSet(v1Range), .specific(["a"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1to3Range), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), ]) } - func testResolutionConflictResolutionWithAPartialSatisfier() throws { - try builder.serve("foo", at: v1) - try builder.serve("foo", at: v1_1, with: [ + func testResolutionConflictResolutionWithAPartialSatisfier() async throws { + try await builder.serve("foo", at: v1) + try await builder.serve("foo", at: v1_1, with: [ "foo": ["left": (.versionSet(v1Range), .specific(["left"]))], "foo": ["right": (.versionSet(v1Range), .specific(["right"]))], ]) - try builder.serve("left", at: v1, with: ["left": ["shared": (.versionSet(v1Range), .specific(["shared"]))]]) - try builder.serve("right", at: v1, with: ["right": ["shared": (.versionSet(v1Range), .specific(["shared"]))]]) - try builder.serve("shared", at: v1, with: ["shared": ["target": (.versionSet(v1Range), .specific(["target"]))]]) - try builder.serve("shared", at: v2) - try builder.serve("target", at: v1) - try builder.serve("target", at: v2) + try await builder.serve("left", at: v1, with: ["left": ["shared": (.versionSet(v1Range), .specific(["shared"]))]]) + try await builder.serve("right", at: v1, with: ["right": ["shared": (.versionSet(v1Range), .specific(["shared"]))]]) + try await builder.serve("shared", at: v1, with: ["shared": ["target": (.versionSet(v1Range), .specific(["target"]))]]) + try await builder.serve("shared", at: v2) + try await builder.serve("target", at: v1) + try await builder.serve("target", at: v2) // foo 1.1.0 transitively depends on a version of target that's not compatible // with root's constraint. This dependency only exists because of left @@ -709,7 +703,7 @@ final class PubgrubTests: XCTestCase { "foo": (.versionSet(v1Range), .specific(["foo"])), "target": (.versionSet(v2Range), .specific(["target"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1)), @@ -717,8 +711,8 @@ final class PubgrubTests: XCTestCase { ]) } - func testUsecase1() throws { - try builder.serve( + func testUsecase1() async throws { + try await builder.serve( "a", at: "1.0.0", with: [ @@ -729,7 +723,7 @@ final class PubgrubTests: XCTestCase { ] ) - try builder.serve( + try await builder.serve( "b", at: "1.0.0", with: [ @@ -738,7 +732,7 @@ final class PubgrubTests: XCTestCase { ], ] ) - try builder.serve( + try await builder.serve( "b", at: "1.1.0", with: [ @@ -748,7 +742,7 @@ final class PubgrubTests: XCTestCase { ] ) - try builder.serve( + try await builder.serve( "c", at: ["1.0.0", "1.1.0", "1.2.0", "1.2.1", "1.3.0", "1.3.1", "1.4.0", "1.4.1", "2.0.0", "2.1.0"], with: [ @@ -756,14 +750,14 @@ final class PubgrubTests: XCTestCase { ] ) - try builder.serve("d", at: ["1.0.0", "1.1.0", "1.1.1", "1.1.2", "1.2.0", "1.2.1"]) + try await builder.serve("d", at: ["1.0.0", "1.1.0", "1.1.1", "1.1.2", "1.2.0", "1.2.1"]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .everything), "c": (.versionSet(v1Range), .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -773,31 +767,31 @@ final class PubgrubTests: XCTestCase { ]) } - func testCycle1() throws { - try builder.serve("foo", at: v1_1, with: ["foo": ["foo": (.versionSet(v1Range), .specific(["foo"]))]]) + func testCycle1() async throws { + try await builder.serve("foo", at: v1_1, with: ["foo": ["foo": (.versionSet(v1Range), .specific(["foo"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1_1)), ]) } - func testCycle2() throws { - try builder.serve("foo", at: v1_1, with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) - try builder.serve("bar", at: v1, with: ["bar": ["baz": (.versionSet(v1Range), .specific(["baz"]))]]) - try builder.serve("baz", at: v1, with: ["baz": ["bam": (.versionSet(v1Range), .specific(["bam"]))]]) - try builder.serve("bam", at: v1, with: ["bam": ["baz": (.versionSet(v1Range), .specific(["baz"]))]]) + func testCycle2() async throws { + try await builder.serve("foo", at: v1_1, with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) + try await builder.serve("bar", at: v1, with: ["bar": ["baz": (.versionSet(v1Range), .specific(["baz"]))]]) + try await builder.serve("baz", at: v1, with: ["baz": ["bam": (.versionSet(v1Range), .specific(["bam"]))]]) + try await builder.serve("bam", at: v1, with: ["bam": ["baz": (.versionSet(v1Range), .specific(["baz"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1_1)), @@ -807,14 +801,14 @@ final class PubgrubTests: XCTestCase { ]) } - func testLocalPackageCycle() throws { - try builder.serve("foo", at: .unversioned, with: [ + func testLocalPackageCycle() async throws { + try await builder.serve("foo", at: .unversioned, with: [ "foo": ["bar": (.unversioned, .specific(["bar"]))], ]) - try builder.serve("bar", at: .unversioned, with: [ + try await builder.serve("bar", at: .unversioned, with: [ "bar": ["baz": (.unversioned, .specific(["baz"]))], ]) - try builder.serve("baz", at: .unversioned, with: [ + try await builder.serve("baz", at: .unversioned, with: [ "baz": ["foo": (.unversioned, .specific(["foo"]))], ]) @@ -822,7 +816,7 @@ final class PubgrubTests: XCTestCase { let dependencies = try builder.create(dependencies: [ "foo": (.unversioned, .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -831,14 +825,14 @@ final class PubgrubTests: XCTestCase { ]) } - func testBranchBasedPackageCycle() throws { - try builder.serve("foo", at: .revision("develop"), with: [ + func testBranchBasedPackageCycle() async throws { + try await builder.serve("foo", at: .revision("develop"), with: [ "foo": ["bar": (.revision("develop"), .specific(["bar"]))], ]) - try builder.serve("bar", at: .revision("develop"), with: [ + try await builder.serve("bar", at: .revision("develop"), with: [ "bar": ["baz": (.revision("develop"), .specific(["baz"]))], ]) - try builder.serve("baz", at: .revision("develop"), with: [ + try await builder.serve("baz", at: .revision("develop"), with: [ "baz": ["foo": (.revision("develop"), .specific(["foo"]))], ]) @@ -846,7 +840,7 @@ final class PubgrubTests: XCTestCase { let dependencies = try builder.create(dependencies: [ "foo": (.revision("develop"), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("develop")), @@ -855,27 +849,27 @@ final class PubgrubTests: XCTestCase { ]) } - func testNonExistentPackage() throws { + func testNonExistentPackage() async throws { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(.exact(v1)), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } AssertError(result, _MockLoadingError.unknownModule) } - func testUnversioned1() throws { - try builder.serve("foo", at: .unversioned) - try builder.serve("bar", at: v1_5) - try builder.serve("bar", at: v2) + func testUnversioned1() async throws { + try await builder.serve("foo", at: .unversioned) + try await builder.serve("bar", at: v1_5) + try await builder.serve("bar", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.unversioned, .specific(["foo"])), "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -883,14 +877,14 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned2() throws { - try builder.serve("foo", at: .unversioned, with: [ + func testUnversioned2() async throws { + try await builder.serve("foo", at: .unversioned, with: [ "foo": ["bar": (.versionSet(.range(v1 ..< "1.2.0")), .specific(["bar"]))], ]) - try builder.serve("bar", at: v1) - try builder.serve("bar", at: v1_1) - try builder.serve("bar", at: v1_5) - try builder.serve("bar", at: v2) + try await builder.serve("bar", at: v1) + try await builder.serve("bar", at: v1_1) + try await builder.serve("bar", at: v1_5) + try await builder.serve("bar", at: v2) let resolver = builder.create() @@ -898,7 +892,7 @@ final class PubgrubTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -906,9 +900,9 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned3() throws { - try builder.serve("foo", at: .unversioned) - try builder.serve("bar", at: v1, with: [ + func testUnversioned3() async throws { + try await builder.serve("foo", at: .unversioned) + try await builder.serve("bar", at: v1, with: [ "bar": ["foo": (.versionSet(.exact(v1)), .specific(["foo"]))], ]) @@ -917,7 +911,7 @@ final class PubgrubTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -925,9 +919,9 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned4() throws { - try builder.serve("foo", at: .unversioned) - try builder.serve("bar", at: .revision("master"), with: [ + func testUnversioned4() async throws { + try await builder.serve("foo", at: .unversioned) + try await builder.serve("bar", at: .revision("master"), with: [ "bar": ["foo": (.versionSet(v1Range), .specific(["foo"]))], ]) @@ -936,7 +930,7 @@ final class PubgrubTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), "bar": (.revision("master"), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -944,10 +938,10 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned5() throws { - try builder.serve("foo", at: .unversioned) - try builder.serve("foo", at: .revision("master")) - try builder.serve("bar", at: .revision("master"), with: [ + func testUnversioned5() async throws { + try await builder.serve("foo", at: .unversioned) + try await builder.serve("foo", at: .revision("master")) + try await builder.serve("bar", at: .revision("master"), with: [ "bar": ["foo": (.revision("master"), .specific(["foo"]))], ]) @@ -956,7 +950,7 @@ final class PubgrubTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), "bar": (.revision("master"), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -964,19 +958,19 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned7() throws { - try builder.serve("local", at: .unversioned, with: [ + func testUnversioned7() async throws { + try await builder.serve("local", at: .unversioned, with: [ "local": ["remote": (.unversioned, .specific(["remote"]))], ]) - try builder.serve("remote", at: .unversioned) - try builder.serve("remote", at: v1) + try await builder.serve("remote", at: .unversioned) + try await builder.serve("remote", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "local": (.unversioned, .specific(["local"])), "remote": (.versionSet(v1Range), .specific(["remote"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("remote", .unversioned), @@ -984,24 +978,24 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned8() throws { - try builder.serve("entry", at: .unversioned, with: [ + func testUnversioned8() async throws { + try await builder.serve("entry", at: .unversioned, with: [ "entry": [ "remote": (.versionSet(v1Range), .specific(["remote"])), "local": (.unversioned, .specific(["local"])), ], ]) - try builder.serve("local", at: .unversioned, with: [ + try await builder.serve("local", at: .unversioned, with: [ "local": ["remote": (.unversioned, .specific(["remote"]))], ]) - try builder.serve("remote", at: .unversioned) - try builder.serve("remote", at: v1) + try await builder.serve("remote", at: .unversioned) + try await builder.serve("remote", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "entry": (.unversioned, .specific(["entry"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("entry", .unversioned), @@ -1010,24 +1004,24 @@ final class PubgrubTests: XCTestCase { ]) } - func testUnversioned9() throws { - try builder.serve("entry", at: .unversioned, with: [ + func testUnversioned9() async throws { + try await builder.serve("entry", at: .unversioned, with: [ "entry": [ "local": (.unversioned, .specific(["local"])), "remote": (.versionSet(v1Range), .specific(["remote"])), ], ]) - try builder.serve("local", at: .unversioned, with: [ + try await builder.serve("local", at: .unversioned, with: [ "local": ["remote": (.unversioned, .specific(["remote"]))], ]) - try builder.serve("remote", at: .unversioned) - try builder.serve("remote", at: v1) + try await builder.serve("remote", at: .unversioned) + try await builder.serve("remote", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "entry": (.unversioned, .specific(["entry"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("entry", .unversioned), @@ -1038,11 +1032,11 @@ final class PubgrubTests: XCTestCase { // root -> version -> version // root -> version -> version - func testHappyPath1() throws { - try builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("bar", at: v1_1, with: ["bar": ["config": (.versionSet(v1_1Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + func testHappyPath1() async throws { + try await builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("bar", at: v1_1, with: ["bar": ["config": (.versionSet(v1_1Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1050,7 +1044,7 @@ final class PubgrubTests: XCTestCase { "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1_1)), @@ -1061,15 +1055,15 @@ final class PubgrubTests: XCTestCase { // root -> version -> version // root -> non-versioned -> version - func testHappyPath2() throws { - try builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve( + func testHappyPath2() async throws { + try await builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve( "bar", at: .unversioned, with: ["bar": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1077,7 +1071,7 @@ final class PubgrubTests: XCTestCase { "bar": (.unversioned, .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1_1)), @@ -1088,16 +1082,16 @@ final class PubgrubTests: XCTestCase { // root -> version -> version // root -> non-versioned -> non-versioned -> version - func testHappyPath3() throws { - try builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) - try builder.serve( + func testHappyPath3() async throws { + try await builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) + try await builder.serve( "baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1105,7 +1099,7 @@ final class PubgrubTests: XCTestCase { "bar": (.unversioned, .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1_1)), @@ -1117,10 +1111,10 @@ final class PubgrubTests: XCTestCase { // root -> version // root -> version -> version - func testHappyPath4() throws { - try builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + func testHappyPath4() async throws { + try await builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1128,7 +1122,7 @@ final class PubgrubTests: XCTestCase { "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1_1)), @@ -1138,14 +1132,14 @@ final class PubgrubTests: XCTestCase { // root -> version // root -> non-versioned -> version - func testHappyPath5() throws { - try builder.serve( + func testHappyPath5() async throws { + try await builder.serve( "foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1153,7 +1147,7 @@ final class PubgrubTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -1163,15 +1157,15 @@ final class PubgrubTests: XCTestCase { // root -> version // root -> non-versioned -> non-versioned -> version - func testHappyPath6() throws { - try builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) - try builder.serve( + func testHappyPath6() async throws { + try await builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) + try await builder.serve( "bar", at: .unversioned, with: ["bar": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1179,7 +1173,7 @@ final class PubgrubTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .unversioned), @@ -1190,24 +1184,24 @@ final class PubgrubTests: XCTestCase { // top level package -> version // top level package -> version -> version - func testHappyPath7() throws { + func testHappyPath7() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.versionSet(v1Range), .specific(["foo"])), ], ]) - try builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("package", .unversioned), @@ -1218,28 +1212,28 @@ final class PubgrubTests: XCTestCase { // top level package -> version // top level package -> non-versioned -> version - func testHappyPath8() throws { + func testHappyPath8() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.unversioned, .specific(["foo"])), ], ]) - try builder.serve( + try await builder.serve( "foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("package", .unversioned), @@ -1250,30 +1244,30 @@ final class PubgrubTests: XCTestCase { // top level package -> version // top level package -> non-versioned -> non-versioned -> version - func testHappyPath9() throws { + func testHappyPath9() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.unversioned, .specific(["foo"])), ], ]) - try builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) - try builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) - try builder.serve( + try await builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) + try await builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) + try await builder.serve( "baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v1_1) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v1_1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("package", .unversioned), @@ -1286,36 +1280,36 @@ final class PubgrubTests: XCTestCase { // top level package -> beta version // beta version -> version - func testHappyPath10() throws { + func testHappyPath10() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "foo": (.versionSet(.range("1.0.0-alpha" ..< "2.0.0")), .specific(["foo"])), ], ]) - try builder.serve( + try await builder.serve( "foo", at: "1.0.0-alpha.1", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] ) - try builder.serve( + try await builder.serve( "foo", at: "1.0.0-alpha.2", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] ) - try builder.serve("foo", at: "1.0.0-beta.1", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) - try builder.serve("foo", at: "1.0.0-beta.2", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) - try builder.serve("foo", at: "1.0.0-beta.3", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) - try builder.serve("bar", at: v1) - try builder.serve("bar", at: v1_1) - try builder.serve("bar", at: v1_5) + try await builder.serve("foo", at: "1.0.0-beta.1", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) + try await builder.serve("foo", at: "1.0.0-beta.2", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) + try await builder.serve("foo", at: "1.0.0-beta.3", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) + try await builder.serve("bar", at: v1) + try await builder.serve("bar", at: v1_1) + try await builder.serve("bar", at: v1_5) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("package", .unversioned), @@ -1324,20 +1318,20 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionWithSimpleBranchBasedDependency() throws { - try builder.serve( + func testResolutionWithSimpleBranchBasedDependency() async throws { + try await builder.serve( "foo", at: .revision("master"), with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] ) - try builder.serve("bar", at: v1) + try await builder.serve("bar", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.revision("master"), .specific(["foo"])), "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), @@ -1345,19 +1339,19 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionWithSimpleBranchBasedDependency2() throws { - try builder.serve( + func testResolutionWithSimpleBranchBasedDependency2() async throws { + try await builder.serve( "foo", at: .revision("master"), with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] ) - try builder.serve("bar", at: v1) + try await builder.serve("bar", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.revision("master"), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), @@ -1365,9 +1359,9 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionWithOverridingBranchBasedDependency() throws { - try builder.serve("foo", at: .revision("master")) - try builder.serve("bar", at: v1, with: ["bar": ["foo": (.versionSet(v1Range), .specific(["foo"]))]]) + func testResolutionWithOverridingBranchBasedDependency() async throws { + try await builder.serve("foo", at: .revision("master")) + try await builder.serve("bar", at: v1, with: ["bar": ["foo": (.versionSet(v1Range), .specific(["foo"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1375,7 +1369,7 @@ final class PubgrubTests: XCTestCase { "bar": (.versionSet(.exact(v1)), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), @@ -1383,16 +1377,16 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionWithOverridingBranchBasedDependency2() throws { - try builder.serve("foo", at: .revision("master")) - try builder.serve("bar", at: v1, with: ["bar": ["foo": (.versionSet(v1Range), .specific(["foo"]))]]) + func testResolutionWithOverridingBranchBasedDependency2() async throws { + try await builder.serve("foo", at: .revision("master")) + try await builder.serve("bar", at: v1, with: ["bar": ["foo": (.versionSet(v1Range), .specific(["foo"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "bar": (.versionSet(.exact(v1)), .specific(["bar"])), "foo": (.revision("master"), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), @@ -1400,17 +1394,17 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionWithOverridingBranchBasedDependency3() throws { - try builder.serve( + func testResolutionWithOverridingBranchBasedDependency3() async throws { + try await builder.serve( "foo", at: .revision("master"), with: ["foo": ["bar": (.revision("master"), .specific(["bar"]))]] ) - try builder.serve("bar", at: .revision("master")) - try builder.serve("bar", at: v1) + try await builder.serve("bar", at: .revision("master")) + try await builder.serve("bar", at: v1) - try builder.serve( + try await builder.serve( "baz", at: .revision("master"), with: ["baz": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] @@ -1421,7 +1415,7 @@ final class PubgrubTests: XCTestCase { "foo": (.revision("master"), .specific(["foo"])), "baz": (.revision("master"), .specific(["baz"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), @@ -1430,33 +1424,33 @@ final class PubgrubTests: XCTestCase { ]) } - func testResolutionWithUnavailableRevision() throws { - try builder.serve("foo", at: .version(v1)) + func testResolutionWithUnavailableRevision() async throws { + try await builder.serve("foo", at: .version(v1)) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.revision("master"), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } AssertError(result, _MockLoadingError.unknownRevision) } - func testResolutionWithRevisionConflict() throws { - try builder.serve( + func testResolutionWithRevisionConflict() async throws { + try await builder.serve( "foo", at: .revision("master"), with: ["foo": ["bar": (.revision("master"), .specific(["bar"]))]] ) - try builder.serve("bar", at: .version(v1)) - try builder.serve("bar", at: .revision("master")) + try await builder.serve("bar", at: .version(v1)) + try await builder.serve("bar", at: .revision("master")) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "bar": (.versionSet(v1Range), .specific(["bar"])), "foo": (.revision("master"), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), @@ -1464,13 +1458,13 @@ final class PubgrubTests: XCTestCase { ]) } - func testBranchOverriding3() throws { - try builder.serve("swift-nio", at: v1) - try builder.serve("swift-nio", at: .revision("master")) - try builder.serve("swift-nio-ssl", at: .revision("master"), with: [ + func testBranchOverriding3() async throws { + try await builder.serve("swift-nio", at: v1) + try await builder.serve("swift-nio", at: .revision("master")) + try await builder.serve("swift-nio-ssl", at: .revision("master"), with: [ "swift-nio-ssl": ["swift-nio": (.versionSet(v2Range), .specific(["swift-nio"]))], ]) - try builder.serve("foo", at: "1.0.0", with: [ + try await builder.serve("foo", at: "1.0.0", with: [ "foo": ["swift-nio": (.versionSet(v1Range), .specific(["swift-nio"]))], ]) @@ -1480,7 +1474,7 @@ final class PubgrubTests: XCTestCase { "swift-nio": (.revision("master"), .specific(["swift-nio"])), "swift-nio-ssl": (.revision("master"), .specific(["swift-nio-ssl"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("swift-nio-ssl", .revision("master")), @@ -1489,25 +1483,25 @@ final class PubgrubTests: XCTestCase { ]) } - func testBranchOverriding4() throws { - try builder.serve("swift-nio", at: v1) - try builder.serve("swift-nio", at: .revision("master")) - try builder.serve("swift-nio-ssl", at: .revision("master"), with: [ + func testBranchOverriding4() async throws { + try await builder.serve("swift-nio", at: v1) + try await builder.serve("swift-nio", at: .revision("master")) + try await builder.serve("swift-nio-ssl", at: .revision("master"), with: [ "swift-nio-ssl": ["swift-nio": (.versionSet(v2Range), .specific(["swift-nio"]))], ]) - try builder.serve("nio-postgres", at: .revision("master"), with: [ + try await builder.serve("nio-postgres", at: .revision("master"), with: [ "nio-postgres": [ "swift-nio": (.revision("master"), .specific(["swift-nio"])), "swift-nio-ssl": (.revision("master"), .specific(["swift-nio-ssl"])), ], ]) - try builder.serve("http-client", at: v1, with: [ + try await builder.serve("http-client", at: v1, with: [ "http-client": [ "swift-nio": (.versionSet(v1Range), .specific(["swift-nio"])), "boring-ssl": (.versionSet(v1Range), .specific(["boring-ssl"])), ], ]) - try builder.serve("boring-ssl", at: v1, with: [ + try await builder.serve("boring-ssl", at: v1, with: [ "boring-ssl": ["swift-nio": (.versionSet(v1Range), .specific(["swift-nio"]))], ]) @@ -1517,7 +1511,7 @@ final class PubgrubTests: XCTestCase { "http-client": (.versionSet(v1Range), .specific(["https-client"])), "boring-ssl": (.versionSet(v1Range), .specific(["boring-ssl"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("swift-nio-ssl", .revision("master")), @@ -1528,28 +1522,28 @@ final class PubgrubTests: XCTestCase { ]) } - func testNonVersionDependencyInVersionDependency2() throws { - try builder.serve("foo", at: v1_1, with: [ + func testNonVersionDependencyInVersionDependency2() async throws { + try await builder.serve("foo", at: v1_1, with: [ "foo": ["bar": (.revision("master"), .specific(["bar"]))], ]) - try builder.serve("foo", at: v1) + try await builder.serve("foo", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1)), ]) } - func testTrivialPinStore() throws { - try builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) - try builder.serve("a", at: v1_1) - try builder.serve("b", at: v1) - try builder.serve("b", at: v1_1) - try builder.serve("b", at: v2) + func testTrivialPinStore() async throws { + try await builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) + try await builder.serve("a", at: v1_1) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v1_1) + try await builder.serve("b", at: v2) let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .specific(["a"])), @@ -1561,7 +1555,7 @@ final class PubgrubTests: XCTestCase { ]) let resolver = builder.create(pins: pinsStore.pins) - let result = try resolver.solve(root: rootNode, constraints: dependencies) + let result = try await resolver.solve(root: rootNode, constraints: dependencies) // Since a was pinned, we shouldn't have computed bounds for its incomaptibilities. let aIncompat = try result.state.positiveIncompatibilities(for: .product( @@ -1570,20 +1564,20 @@ final class PubgrubTests: XCTestCase { ))![0] XCTAssertEqual(aIncompat.terms[0].requirement, .exact("1.0.0")) - AssertResult(Result.success(result.bindings), [ + AssertResult(result.bindings, [ ("a", .version(v1)), ("b", .version(v1)), ]) } - func testPartialPins() throws { + func testPartialPins() async throws { // This checks that we can drop pins that are not valid anymore but still keep the ones // which fit the constraints. - try builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) - try builder.serve("a", at: v1_1) - try builder.serve("b", at: v1) - try builder.serve("b", at: v1_1) - try builder.serve("c", at: v1, with: ["c": ["b": (.versionSet(.range(v1_1 ..< v2)), .specific(["b"]))]]) + try await builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) + try await builder.serve("a", at: v1_1) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v1_1) + try await builder.serve("c", at: v1, with: ["c": ["b": (.versionSet(.range(v1_1 ..< v2)), .specific(["b"]))]]) let dependencies = try builder.create(dependencies: [ "c": (.versionSet(v1Range), .specific(["c"])), @@ -1598,7 +1592,7 @@ final class PubgrubTests: XCTestCase { ]) let resolver = builder.create(pins: pinsStore.pins) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -1607,13 +1601,13 @@ final class PubgrubTests: XCTestCase { ]) } - func testMissingPin() throws { + func testMissingPin() async throws { // This checks that we can drop pins that are no longer available but still keep the ones // which fit the constraints. - try builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) - try builder.serve("a", at: v1_1) - try builder.serve("b", at: v1) - try builder.serve("b", at: v1_1) + try await builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v1Range), .specific(["b"]))]]) + try await builder.serve("a", at: v1_1) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v1_1) let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .specific(["a"])), @@ -1627,7 +1621,7 @@ final class PubgrubTests: XCTestCase { ]) let resolver = builder.create(pins: pinsStore.pins) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -1635,11 +1629,11 @@ final class PubgrubTests: XCTestCase { ]) } - func testBranchedBasedPin() throws { + func testBranchedBasedPin() async throws { // This test ensures that we get the SHA listed in Package.resolved for branch-based // dependencies. - try builder.serve("a", at: .revision("develop-sha-1")) - try builder.serve("b", at: .revision("master-sha-2")) + try await builder.serve("a", at: .revision("develop-sha-1")) + try await builder.serve("b", at: .revision("master-sha-2")) let dependencies = try builder.create(dependencies: [ "a": (.revision("develop"), .specific(["a"])), @@ -1652,7 +1646,7 @@ final class PubgrubTests: XCTestCase { ]) let resolver = builder.create(pins: pinsStore.pins) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .revision("develop-sha-1", branch: "develop")), @@ -1660,39 +1654,39 @@ final class PubgrubTests: XCTestCase { ]) } - func testIncompatibleToolsVersion2() throws { - try builder.serve("a", at: v1_1, toolsVersion: ToolsVersion.v5) - try builder.serve("a", at: v1) + func testIncompatibleToolsVersion2() async throws { + try await builder.serve("a", at: v1_1, toolsVersion: ToolsVersion.v5) + try await builder.serve("a", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), ]) } - func testUnreachableProductsSkipped() throws { + func testUnreachableProductsSkipped() async throws { #if ENABLE_TARGET_BASED_DEPENDENCY_RESOLUTION #else try XCTSkipIf(true) #endif - try builder.serve("root", at: .unversioned, with: [ + try await builder.serve("root", at: .unversioned, with: [ "root": ["immediate": (.versionSet(v1Range), .specific(["ImmediateUsed"]))], ]) - try builder.serve("immediate", at: v1, with: [ + try await builder.serve("immediate", at: v1, with: [ "ImmediateUsed": ["transitive": (.versionSet(v1Range), .specific(["TransitiveUsed"]))], "ImmediateUnused": [ "transitive": (.versionSet(v1Range), .specific(["TransitiveUnused"])), "nonexistent": (.versionSet(v1Range), .specific(["Nonexistent"])), ], ]) - try builder.serve("transitive", at: v1, with: [ + try await builder.serve("transitive", at: v1, with: [ "TransitiveUsed": [:], "TransitiveUnused": [ "nonexistent": (.versionSet(v1Range), .specific(["Nonexistent"])), @@ -1703,7 +1697,7 @@ final class PubgrubTests: XCTestCase { let dependencies = try builder.create(dependencies: [ "root": (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("root", .unversioned), @@ -1712,7 +1706,7 @@ final class PubgrubTests: XCTestCase { ]) } - func testDelegate() throws { + func testDelegate() async throws { class TestDelegate: DependencyResolverDelegate { var events = [String]() let lock = NSLock() @@ -1753,15 +1747,15 @@ final class PubgrubTests: XCTestCase { } } - try builder.serve("foo", at: "1.0.0") - try builder.serve("foo", at: "1.1.0") - try builder.serve("foo", at: "2.0.0") - try builder.serve("foo", at: "2.0.1") + try await builder.serve("foo", at: "1.0.0") + try await builder.serve("foo", at: "1.1.0") + try await builder.serve("foo", at: "2.0.0") + try await builder.serve("foo", at: "2.0.1") - try builder.serve("bar", at: "1.0.0") - try builder.serve("bar", at: "1.1.0") - try builder.serve("bar", at: "2.0.0") - try builder.serve("bar", at: "2.0.1") + try await builder.serve("bar", at: "1.0.0") + try await builder.serve("bar", at: "1.1.0") + try await builder.serve("bar", at: "2.0.0") + try await builder.serve("bar", at: "2.0.1") let delegate = TestDelegate() let resolver = builder.create(delegate: delegate) @@ -1769,7 +1763,7 @@ final class PubgrubTests: XCTestCase { "foo": (.versionSet(v1Range), .specific(["foo"])), "bar": (.versionSet(v2Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version("1.1.0")), @@ -1783,7 +1777,7 @@ final class PubgrubTests: XCTestCase { XCTAssertMatch(delegate.events, ["solved: 'bar' at '2.0.1', 'foo' at '1.1.0'"]) } - func testPubGrubPackageContainerCacheParameterization() throws { + func testPubGrubPackageContainerCacheParameterization() async throws { let container = try PubGrubPackageContainer( underlying: MockPackageContainer( name: "Package", @@ -1814,8 +1808,8 @@ final class PubgrubTests: XCTestCase { identity: .init(path: dependencyBLocation), path: dependencyBLocation ) - XCTAssertEqual( - try container.incompatibilites( + try await XCTAssertAsyncEqual( + try await container.incompatibilites( at: Version(1, 0, 0), node: .product( "FilterA", @@ -1853,8 +1847,8 @@ final class PubgrubTests: XCTestCase { ), ] ) - XCTAssertEqual( - try container.incompatibilites( + try await XCTAssertAsyncEqual( + try await container.incompatibilites( at: Version(1, 0, 0), node: .product( "FilterB", @@ -1896,23 +1890,23 @@ final class PubgrubTests: XCTestCase { } final class PubGrubTestsBasicGraphs: XCTestCase { - func testSimple1() throws { - try builder.serve("a", at: v1, with: [ + func testSimple1() async throws { + try await builder.serve("a", at: v1, with: [ "a": [ "aa": (.versionSet(.exact("1.0.0")), .specific(["aa"])), "ab": (.versionSet(.exact("1.0.0")), .specific(["ab"])), ], ]) - try builder.serve("aa", at: v1) - try builder.serve("ab", at: v1) - try builder.serve("b", at: v1, with: [ + try await builder.serve("aa", at: v1) + try await builder.serve("ab", at: v1) + try await builder.serve("b", at: v1, with: [ "b": [ "ba": (.versionSet(.exact("1.0.0")), .specific(["ba"])), "bb": (.versionSet(.exact("1.0.0")), .specific(["bb"])), ], ]) - try builder.serve("ba", at: v1) - try builder.serve("bb", at: v1) + try await builder.serve("ba", at: v1) + try await builder.serve("bb", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1920,7 +1914,7 @@ final class PubGrubTestsBasicGraphs: XCTestCase { "b": (.versionSet(.exact("1.0.0")), .specific(["b"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), ("aa", .version(v1)), @@ -1931,18 +1925,18 @@ final class PubGrubTestsBasicGraphs: XCTestCase { ]) } - func testSharedDependency1() throws { - try builder.serve("a", at: v1, with: [ + func testSharedDependency1() async throws { + try await builder.serve("a", at: v1, with: [ "a": ["shared": (.versionSet(.range("2.0.0" ..< "4.0.0")), .specific(["shared"]))], ]) - try builder.serve("b", at: v1, with: [ + try await builder.serve("b", at: v1, with: [ "b": ["shared": (.versionSet(.range("3.0.0" ..< "5.0.0")), .specific(["shared"]))], ]) - try builder.serve("shared", at: "2.0.0") - try builder.serve("shared", at: "3.0.0") - try builder.serve("shared", at: "3.6.9") - try builder.serve("shared", at: "4.0.0") - try builder.serve("shared", at: "5.0.0") + try await builder.serve("shared", at: "2.0.0") + try await builder.serve("shared", at: "3.0.0") + try await builder.serve("shared", at: "3.6.9") + try await builder.serve("shared", at: "4.0.0") + try await builder.serve("shared", at: "5.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1950,7 +1944,7 @@ final class PubGrubTestsBasicGraphs: XCTestCase { "b": (.versionSet(.exact("1.0.0")), .specific(["b"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), ("b", .version(v1)), @@ -1958,23 +1952,23 @@ final class PubGrubTestsBasicGraphs: XCTestCase { ]) } - func testSharedDependency2() throws { - try builder.serve("foo", at: "1.0.0") - try builder.serve("foo", at: "1.0.1", with: [ + func testSharedDependency2() async throws { + try await builder.serve("foo", at: "1.0.0") + try await builder.serve("foo", at: "1.0.1", with: [ "foo": ["bang": (.versionSet(.exact("1.0.0")), .specific(["bang"]))], ]) - try builder.serve("foo", at: "1.0.2", with: [ + try await builder.serve("foo", at: "1.0.2", with: [ "foo": ["whoop": (.versionSet(.exact("1.0.0")), .specific(["whoop"]))], ]) - try builder.serve("foo", at: "1.0.3", with: [ + try await builder.serve("foo", at: "1.0.3", with: [ "foo": ["zoop": (.versionSet(.exact("1.0.0")), .specific(["zoop"]))], ]) - try builder.serve("bar", at: "1.0.0", with: [ + try await builder.serve("bar", at: "1.0.0", with: [ "bar": ["foo": (.versionSet(.range("0.0.0" ..< "1.0.2")), .specific(["foo"]))], ]) - try builder.serve("bang", at: "1.0.0") - try builder.serve("whoop", at: "1.0.0") - try builder.serve("zoop", at: "1.0.0") + try await builder.serve("bang", at: "1.0.0") + try await builder.serve("whoop", at: "1.0.0") + try await builder.serve("zoop", at: "1.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1982,7 +1976,7 @@ final class PubGrubTestsBasicGraphs: XCTestCase { "bar": (.versionSet(.exact("1.0.0")), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version("1.0.1")), ("bar", .version(v1)), @@ -1990,14 +1984,14 @@ final class PubGrubTestsBasicGraphs: XCTestCase { ]) } - func testFallbacksToOlderVersion() throws { - try builder.serve("foo", at: "1.0.0") - try builder.serve("foo", at: "2.0.0") - try builder.serve("bar", at: "1.0.0") - try builder.serve("bar", at: "2.0.0", with: [ + func testFallbacksToOlderVersion() async throws { + try await builder.serve("foo", at: "1.0.0") + try await builder.serve("foo", at: "2.0.0") + try await builder.serve("bar", at: "1.0.0") + try await builder.serve("bar", at: "2.0.0", with: [ "bar": ["baz": (.versionSet(.exact("1.0.0")), .specific(["baz"]))], ]) - try builder.serve("baz", at: "1.0.0", with: [ + try await builder.serve("baz", at: "1.0.0", with: [ "baz": ["foo": (.versionSet(.exact("2.0.0")), .specific(["foo"]))], ]) @@ -2007,21 +2001,21 @@ final class PubGrubTestsBasicGraphs: XCTestCase { "foo": (.versionSet(.exact("1.0.0")), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1)), ("bar", .version(v1)), ]) } - func testAvailableLibraries() throws { + func testAvailableLibraries() async throws { let fooRef: PackageReference = .remoteSourceControl( identity: .plain("foo"), url: .init("https://example.com/org/foo") ) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.0.0"))) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.2.0"))) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "2.0.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.0.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.2.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "2.0.0"))) let availableLibraries: [ProvidedLibrary] = [ .init( @@ -2043,47 +2037,46 @@ final class PubGrubTestsBasicGraphs: XCTestCase { fooRef: (.versionSet(.range("1.1.0" ..< "2.0.0")), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies1) - print(try result.get()) + let result = try await resolver.solve(constraints: dependencies1) AssertResult(result, [ ("foo", .version(.init(stringLiteral: "1.0.0"), library: availableLibraries.first!)), ]) - let result2 = resolver.solve(constraints: dependencies2) + let result2 = try await resolver.solve(constraints: dependencies2) AssertResult(result2, [ ("foo", .version(.init(stringLiteral: "1.2.0"))), ]) } - func testAvailableLibrariesArePreferred() throws { + func testAvailableLibrariesArePreferred() async throws { let fooRef: PackageReference = .remoteSourceControl( identity: .plain("foo"), url: .init("https://example.com/org/foo") ) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.0.0"))) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.1.0")), with: [ + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.0.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.1.0")), with: [ "foo": [ "left": (.versionSet(.range(.upToNextMajor(from: "1.0.0"))), .everything), "right": (.versionSet(.range(.upToNextMajor(from: "1.0.0"))), .everything), ], ]) - try builder.serve("left", at: "1.0.0", with: [ + try await builder.serve("left", at: "1.0.0", with: [ "left": ["shared": (.versionSet(.range(.upToNextMajor(from: "1.0.0"))), .everything)], ]) - try builder.serve("right", at: "1.0.0", with: [ + try await builder.serve("right", at: "1.0.0", with: [ "right": ["shared": (.versionSet(.range("0.0.0" ..< "2.0.0")), .everything)], ]) - try builder.serve("shared", at: "1.0.0", with: [ + try await builder.serve("shared", at: "1.0.0", with: [ "shared": ["target": (.versionSet(.range(.upToNextMajor(from: "1.0.0"))), .everything)], ]) - try builder.serve("shared", at: "2.0.0") + try await builder.serve("shared", at: "2.0.0") - try builder.serve("target", at: "1.0.0") - try builder.serve("target", at: "2.0.0") + try await builder.serve("target", at: "1.0.0") + try await builder.serve("target", at: "2.0.0") let availableLibraries: [ProvidedLibrary] = [ .init( @@ -2108,14 +2101,14 @@ final class PubGrubTestsBasicGraphs: XCTestCase { // pick "1.0.0" because "foo" 1.1.0 dependency version requirements are incompatible // with "target" 2.0.0. - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(.init(stringLiteral: "1.1.0"), library: availableLibraries.first!)), ("target", .version(.init(stringLiteral: "2.0.0"))), ]) } - func testAvailableLibrariesWithFallback() throws { + func testAvailableLibrariesWithFallback() async throws { let fooRef: PackageReference = .remoteSourceControl( identity: .plain("foo"), url: .init("https://example.com/org/foo") @@ -2123,15 +2116,15 @@ final class PubGrubTestsBasicGraphs: XCTestCase { let barRef: PackageReference = .init(stringLiteral: "bar") - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.0.0"))) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.1.0"))) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.2.0"))) - try builder.serve(fooRef, at: .version(.init(stringLiteral: "2.0.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.0.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.1.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "1.2.0"))) + try await builder.serve(fooRef, at: .version(.init(stringLiteral: "2.0.0"))) - try builder.serve("bar", at: "1.0.0", with: [ + try await builder.serve("bar", at: "1.0.0", with: [ "bar": [fooRef: (.versionSet(.range(.upToNextMinor(from: "1.1.0"))), .everything)], ]) - try builder.serve("bar", at: "2.0.0", with: [ + try await builder.serve("bar", at: "2.0.0", with: [ "bar": [fooRef: (.versionSet(.range(.upToNextMinor(from: "2.0.0"))), .everything)], ]) @@ -2153,7 +2146,7 @@ final class PubGrubTestsBasicGraphs: XCTestCase { barRef: (.versionSet(.range("1.0.0" ..< "3.0.0")), .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(.init(stringLiteral: "1.1.0"))), ("bar", .version(.init(stringLiteral: "1.0.0"))), @@ -2162,59 +2155,59 @@ final class PubGrubTestsBasicGraphs: XCTestCase { } final class PubGrubDiagnosticsTests: XCTestCase { - func testMissingVersion() throws { - try builder.serve("package", at: v1_1) + func testMissingVersion() async throws { + try await builder.serve("package", at: v1_1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(v2Range), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'package' match the requirement 2.0.0..<3.0.0 and root depends on 'package' 2.0.0..<3.0.0. """) } - func testResolutionNonExistentVersion() throws { - try builder.serve("package", at: v2) + func testResolutionNonExistentVersion() async throws { + try await builder.serve("package", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(.exact(v1)), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'package' match the requirement 1.0.0 and root depends on 'package' 1.0.0. """) } - func testResolutionNonExistentBetaVersion() throws { - try builder.serve("package", at: "0.0.1") + func testResolutionNonExistentBetaVersion() async throws { + try await builder.serve("package", at: "0.0.1") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(.range("1.0.0-beta" ..< "2.0.0")), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'package' match the requirement 1.0.0-beta..<2.0.0 and root depends on 'package' 1.0.0-beta..<2.0.0. """) } - func testResolutionNonExistentTransitiveVersion() throws { - try builder.serve("package", at: v1_5, with: [ + func testResolutionNonExistentTransitiveVersion() async throws { + try await builder.serve("package", at: v1_5, with: [ "package": ["foo": (.versionSet(v1Range), .specific(["foo"]))], ]) - try builder.serve("foo", at: "0.0.1") + try await builder.serve("foo", at: "0.0.1") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(v1Range), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'foo' match the requirement 1.0.0..<2.0.0 and root depends on 'package' 1.0.0..<2.0.0. @@ -2222,17 +2215,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testResolutionNonExistentTransitiveBetaVersion() throws { - try builder.serve("package", at: v1_5, with: [ + func testResolutionNonExistentTransitiveBetaVersion() async throws { + try await builder.serve("package", at: v1_5, with: [ "package": ["foo": (.versionSet(.range("1.0.0-beta" ..< "2.0.0")), .specific(["foo"]))], ]) - try builder.serve("foo", at: "0.0.1") + try await builder.serve("foo", at: "0.0.1") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(v1Range), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'foo' match the requirement 1.0.0-beta..<2.0.0 and root depends on 'package' 1.0.0..<2.0.0. @@ -2240,17 +2233,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testResolutionBetaVersionNonExistentTransitiveVersion() throws { - try builder.serve("package", at: "1.0.0-beta.1", with: [ + func testResolutionBetaVersionNonExistentTransitiveVersion() async throws { + try await builder.serve("package", at: "1.0.0-beta.1", with: [ "package": ["foo": (.versionSet(v1Range), .specific(["foo"]))], ]) - try builder.serve("foo", at: "0.0.1") + try await builder.serve("foo", at: "0.0.1") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "package": (.versionSet(.range("1.0.0-beta" ..< "2.0.0")), .specific(["package"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'foo' match the requirement 1.0.0..<2.0.0 and root depends on 'package' 1.0.0-beta..<2.0.0. @@ -2258,15 +2251,15 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testResolutionLinearErrorReporting() throws { - try builder.serve("foo", at: v1, with: ["foo": ["bar": (.versionSet(v2Range), .specific(["bar"]))]]) - try builder.serve( + func testResolutionLinearErrorReporting() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["bar": (.versionSet(v2Range), .specific(["bar"]))]]) + try await builder.serve( "bar", at: v2, with: ["bar": ["baz": (.versionSet(.range("3.0.0" ..< "4.0.0")), .specific(["baz"]))]] ) - try builder.serve("baz", at: v1) - try builder.serve("baz", at: "3.0.0") + try await builder.serve("baz", at: v1) + try await builder.serve("baz", at: "3.0.0") // root transitively depends on a version of baz that's not compatible // with root's constraint. @@ -2276,7 +2269,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.versionSet(v1Range), .specific(["foo"])), "baz": (.versionSet(v1Range), .specific(["baz"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0 and root depends on 'baz' 1.0.0..<2.0.0. @@ -2286,33 +2279,31 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testResolutionBranchingErrorReporting() throws { - try builder.serve("foo", at: v1, with: [ + func testResolutionBranchingErrorReporting() async throws { + try await builder.serve("foo", at: v1, with: [ "foo": [ "a": (.versionSet(v1Range), .specific(["a"])), "b": (.versionSet(v1Range), .specific(["b"])), ], ]) - try builder.serve("foo", at: v1_1, with: [ + try await builder.serve("foo", at: v1_1, with: [ "foo": [ "x": (.versionSet(v1Range), .specific(["x"])), "y": (.versionSet(v1Range), .specific(["y"])), ], ]) - try builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v2Range), .specific(["b"]))]]) - try builder.serve("b", at: v1) - try builder.serve("b", at: v2) - try builder.serve("x", at: v1, with: ["x": ["y": (.versionSet(v2Range), .specific(["y"]))]]) - try builder.serve("y", at: v1) - try builder.serve("y", at: v2) + try await builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v2Range), .specific(["b"]))]]) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v2) + try await builder.serve("x", at: v1, with: ["x": ["y": (.versionSet(v2Range), .specific(["y"]))]]) + try await builder.serve("y", at: v1) + try await builder.serve("y", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) - - print(result.errorMsg!) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0. @@ -2325,18 +2316,18 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testConflict1() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("bar", at: v1, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + func testConflict1() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("bar", at: v1, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0 and root depends on 'bar' 1.0.0..<2.0.0. @@ -2345,20 +2336,20 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testConflict2() throws { - func addDeps() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + func testConflict2() async throws { + func addDeps() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) } let dependencies1 = try builder.create(dependencies: [ "config": (.versionSet(v2Range), .specific(["config"])), "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - try addDeps() + try await addDeps() let resolver1 = builder.create() - let result1 = resolver1.solve(constraints: dependencies1) + let result1 = await Result { try await resolver1.solve(constraints: dependencies1) } XCTAssertEqual(result1.errorMsg, """ Dependencies could not be resolved because root depends on 'config' 2.0.0..<3.0.0 and root depends on 'foo' 1.0.0..<2.0.0. @@ -2369,9 +2360,9 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.versionSet(v1Range), .specific(["foo"])), "config": (.versionSet(v2Range), .specific(["config"])), ]) - try addDeps() + try await addDeps() let resolver2 = builder.create() - let result2 = resolver2.solve(constraints: dependencies2) + let result2 = await Result { try await resolver2.solve(constraints: dependencies2) } XCTAssertEqual(result2.errorMsg, """ Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0 and root depends on 'config' 2.0.0..<3.0.0. @@ -2379,31 +2370,31 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testConflict3() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) + func testConflict3() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v2Range), .specific(["config"])), "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'config' match the requirement 2.0.0..<3.0.0 and root depends on 'config' 2.0.0..<3.0.0. """) } - func testConflict4() throws { - try builder.serve("foo", at: v1, with: [ + func testConflict4() async throws { + try await builder.serve("foo", at: v1, with: [ "foo": ["shared": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["shared"]))], ]) - try builder.serve("bar", at: v1, with: [ + try await builder.serve("bar", at: v1, with: [ "bar": ["shared": (.versionSet(.range("2.9.0" ..< "4.0.0")), .specific(["shared"]))], ]) - try builder.serve("shared", at: "2.5.0") - try builder.serve("shared", at: "3.5.0") + try await builder.serve("shared", at: "2.5.0") + try await builder.serve("shared", at: "3.5.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2411,7 +2402,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.versionSet(.exact(v1)), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'bar' 1.0.0 and root depends on 'foo' 1.0.0. @@ -2420,17 +2411,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testConflict5() throws { - try builder.serve("a", at: v1, with: [ + func testConflict5() async throws { + try await builder.serve("a", at: v1, with: [ "a": ["b": (.versionSet(.exact("1.0.0")), .specific(["b"]))], ]) - try builder.serve("a", at: "2.0.0", with: [ + try await builder.serve("a", at: "2.0.0", with: [ "a": ["b": (.versionSet(.exact("2.0.0")), .specific(["b"]))], ]) - try builder.serve("b", at: "1.0.0", with: [ + try await builder.serve("b", at: "1.0.0", with: [ "b": ["a": (.versionSet(.exact("2.0.0")), .specific(["a"]))], ]) - try builder.serve("b", at: "2.0.0", with: [ + try await builder.serve("b", at: "2.0.0", with: [ "b": ["a": (.versionSet(.exact("1.0.0")), .specific(["a"]))], ]) @@ -2440,7 +2431,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "a": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'a' 0.0.0..<5.0.0. @@ -2453,11 +2444,11 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version -> version // root -> version -> conflicting version - func testConflict6() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("bar", at: v1, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + func testConflict6() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("bar", at: v1, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2465,7 +2456,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "bar": (.versionSet(v1Range), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0 and root depends on 'bar' 1.0.0..<2.0.0. @@ -2476,15 +2467,15 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version -> version // root -> non-versioned -> conflicting version - func testConflict7() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve( + func testConflict7() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve( "bar", at: .unversioned, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2492,7 +2483,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "bar": (.unversioned, .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'bar' depends on 'config' 2.0.0..<3.0.0 and root depends on 'foo' 1.0.0..<2.0.0. @@ -2502,16 +2493,16 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version -> version // root -> non-versioned -> non-versioned -> conflicting version - func testConflict8() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) - try builder.serve( + func testConflict8() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) + try await builder.serve( "baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2519,7 +2510,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "bar": (.unversioned, .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'baz' depends on 'config' 2.0.0..<3.0.0 and root depends on 'foo' 1.0.0..<2.0.0. @@ -2529,14 +2520,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version -> version // root -> non-versioned -> non-existing version - func testConflict9() throws { - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try builder.serve( + func testConflict9() async throws { + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) + try await builder.serve( "bar", at: .unversioned, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) + try await builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2544,7 +2535,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "bar": (.unversioned, .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because no versions of 'config' match the requirement 2.0.0..<3.0.0 and 'bar' depends on 'config' 2.0.0..<3.0.0. @@ -2553,14 +2544,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version // root -> non-versioned -> conflicting version - func testConflict10() throws { - try builder.serve( + func testConflict10() async throws { + try await builder.serve( "foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2568,7 +2559,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'foo' depends on 'config' 2.0.0..<3.0.0 and root depends on 'config' 1.0.0..<2.0.0. @@ -2577,13 +2568,13 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version // root -> non-versioned -> non-existing version - func testConflict11() throws { - try builder.serve( + func testConflict11() async throws { + try await builder.serve( "foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) + try await builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2591,7 +2582,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'foo' depends on 'config' 2.0.0..<3.0.0 and root depends on 'config' 1.0.0..<2.0.0. @@ -2600,15 +2591,15 @@ final class PubGrubDiagnosticsTests: XCTestCase { // root -> version // root -> non-versioned -> non-versioned -> conflicting version - func testConflict12() throws { - try builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) - try builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) - try builder.serve( + func testConflict12() async throws { + try await builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) + try await builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) + try await builder.serve( "baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) + try await builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2616,7 +2607,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.unversioned, .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'baz' depends on 'config' 2.0.0..<3.0.0 and root depends on 'config' 1.0.0..<2.0.0. @@ -2625,24 +2616,24 @@ final class PubGrubDiagnosticsTests: XCTestCase { // top level package -> version // top level package -> version -> conflicting version - func testConflict13() throws { + func testConflict13() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.versionSet(v1Range), .specific(["foo"])), ], ]) - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'config' 1.0.0..<2.0.0 and root depends on 'foo' 1.0.0..<2.0.0. @@ -2652,23 +2643,23 @@ final class PubGrubDiagnosticsTests: XCTestCase { // top level package -> version // top level package -> version -> non-existing version - func testConflict14() throws { + func testConflict14() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.versionSet(v1Range), .specific(["foo"])), ], ]) - try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) - try builder.serve("config", at: v1) + try await builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) + try await builder.serve("config", at: v1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'config' 1.0.0..<2.0.0 and root depends on 'foo' 1.0.0..<2.0.0. @@ -2678,28 +2669,28 @@ final class PubGrubDiagnosticsTests: XCTestCase { // top level package -> version // top level package -> non-versioned -> conflicting version - func testConflict15() throws { + func testConflict15() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.unversioned, .specific(["foo"])), ], ]) - try builder.serve( + try await builder.serve( "foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'config' 1.0.0..<2.0.0 and 'foo' depends on 'config' 2.0.0..<3.0.0. @@ -2708,27 +2699,27 @@ final class PubGrubDiagnosticsTests: XCTestCase { // top level package -> version // top level package -> non-versioned -> non-existing version - func testConflict16() throws { + func testConflict16() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.unversioned, .specific(["foo"])), ], ]) - try builder.serve( + try await builder.serve( "foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) + try await builder.serve("config", at: v1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'config' 1.0.0..<2.0.0 and 'foo' depends on 'config' 2.0.0..<3.0.0. @@ -2737,39 +2728,39 @@ final class PubGrubDiagnosticsTests: XCTestCase { // top level package -> version // top level package -> non-versioned -> non-versioned -> conflicting version - func testConflict17() throws { + func testConflict17() async throws { let package = PackageReference.root(identity: .plain("package"), path: .root) - try builder.serve(package, at: .unversioned, with: [ + try await builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), "foo": (.unversioned, .specific(["foo"])), ], ]) - try builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) - try builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) - try builder.serve( + try await builder.serve("foo", at: .unversioned, with: ["foo": ["bar": (.unversioned, .specific(["bar"]))]]) + try await builder.serve("bar", at: .unversioned, with: ["bar": ["baz": (.unversioned, .specific(["baz"]))]]) + try await builder.serve( "baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]] ) - try builder.serve("config", at: v1) - try builder.serve("config", at: v2) + try await builder.serve("config", at: v1) + try await builder.serve("config", at: v2) let resolver = builder.create() let dependencies = builder.create(dependencies: [ package: (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'config' 1.0.0..<2.0.0 and 'baz' depends on 'config' 2.0.0..<3.0.0. """) } - func testUnversioned6() throws { - try builder.serve("foo", at: .unversioned) - try builder.serve("bar", at: .revision("master"), with: [ + func testUnversioned6() async throws { + try await builder.serve("foo", at: .unversioned) + try await builder.serve("bar", at: .revision("master"), with: [ "bar": ["foo": (.unversioned, .specific(["foo"]))], ]) @@ -2778,7 +2769,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { let dependencies = try builder.create(dependencies: [ "bar": (.revision("master"), .specific(["bar"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual( result.errorMsg, @@ -2786,17 +2777,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { ) } - func testResolutionWithOverridingBranchBasedDependency4() throws { - try builder.serve( + func testResolutionWithOverridingBranchBasedDependency4() async throws { + try await builder.serve( "foo", at: .revision("master"), with: ["foo": ["bar": (.revision("master"), .specific(["bar"]))]] ) - try builder.serve("bar", at: .revision("master")) - try builder.serve("bar", at: v1) + try await builder.serve("bar", at: .revision("master")) + try await builder.serve("bar", at: v1) - try builder.serve( + try await builder.serve( "baz", at: .revision("master"), with: ["baz": ["bar": (.revision("develop"), .specific(["baz"]))]] @@ -2807,7 +2798,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "foo": (.revision("master"), .specific(["foo"])), "baz": (.revision("master"), .specific(["baz"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual( result.errorMsg, @@ -2815,17 +2806,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { ) } - func testNonVersionDependencyInVersionDependency1() throws { - try builder.serve("foo", at: v1_1, with: [ + func testNonVersionDependencyInVersionDependency1() async throws { + try await builder.serve("foo", at: v1_1, with: [ "foo": ["bar": (.revision("master"), .specific(["bar"]))], ]) - try builder.serve("bar", at: .revision("master")) + try await builder.serve("bar", at: .revision("master")) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0. @@ -2833,40 +2824,40 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testNonVersionDependencyInVersionDependency2() throws { - try builder.serve("foo", at: v1, with: [ + func testNonVersionDependencyInVersionDependency2() async throws { + try await builder.serve("foo", at: v1, with: [ "foo": ["bar": (.unversioned, .specific(["bar"]))], ]) - try builder.serve("bar", at: .unversioned) + try await builder.serve("bar", at: .unversioned) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(.exact(v1)), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar' and root depends on 'foo' 1.0.0. """) } - func testNonVersionDependencyInVersionDependency3() throws { - try builder.serve("foo", at: "1.0.0-beta.1", with: [ + func testNonVersionDependencyInVersionDependency3() async throws { + try await builder.serve("foo", at: "1.0.0-beta.1", with: [ "foo": ["bar": (.revision("master"), .specific(["bar"]))], ]) - try builder.serve("foo", at: "1.0.0-beta.2", with: [ + try await builder.serve("foo", at: "1.0.0-beta.2", with: [ "foo": ["bar": (.revision("master"), .specific(["bar"]))], ]) - try builder.serve("foo", at: "1.0.0-beta.3", with: [ + try await builder.serve("foo", at: "1.0.0-beta.3", with: [ "foo": ["bar": (.revision("master"), .specific(["bar"]))], ]) - try builder.serve("bar", at: .revision("master")) + try await builder.serve("bar", at: .revision("master")) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(.range("1.0.0-beta" ..< "2.0.0")), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar' and root depends on 'foo' 1.0.0-beta..<2.0.0. @@ -2875,15 +2866,15 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testIncompatibleToolsVersion1() throws { - try builder.serve("a", at: v1, toolsVersion: .v5) + func testIncompatibleToolsVersion1() async throws { + try await builder.serve("a", at: v1, toolsVersion: .v5) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(v1Range), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'a' 1.0.0..<2.0.0. @@ -2894,14 +2885,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testIncompatibleToolsVersion3() throws { - try builder.serve("a", at: v1_1, with: [ + func testIncompatibleToolsVersion3() async throws { + try await builder.serve("a", at: v1_1, with: [ "a": ["b": (.versionSet(v1Range), .specific(["b"]))], ]) - try builder.serve("a", at: v1, toolsVersion: .v4) + try await builder.serve("a", at: v1, toolsVersion: .v4) - try builder.serve("b", at: v1) - try builder.serve("b", at: v2) + try await builder.serve("b", at: v1) + try await builder.serve("b", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2909,7 +2900,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { "b": (.versionSet(v2Range), .specific(["b"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because root depends on 'a' 1.0.0..<2.0.0 and root depends on 'b' 2.0.0..<3.0.0. @@ -2921,17 +2912,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testIncompatibleToolsVersion4() throws { - try builder.serve("a", at: "3.2.1", toolsVersion: .v3) - try builder.serve("a", at: "3.2.2", toolsVersion: .v4) - try builder.serve("a", at: "3.2.3", toolsVersion: .v3) + func testIncompatibleToolsVersion4() async throws { + try await builder.serve("a", at: "3.2.1", toolsVersion: .v3) + try await builder.serve("a", at: "3.2.2", toolsVersion: .v4) + try await builder.serve("a", at: "3.2.3", toolsVersion: .v3) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(.range("3.2.0" ..< "4.0.0")), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'a' contains incompatible tools version (\( @@ -2941,17 +2932,17 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testIncompatibleToolsVersion5() throws { - try builder.serve("a", at: "3.2.0", toolsVersion: .v3) - try builder.serve("a", at: "3.2.1", toolsVersion: .v4) - try builder.serve("a", at: "3.2.2", toolsVersion: .v5) + func testIncompatibleToolsVersion5() async throws { + try await builder.serve("a", at: "3.2.0", toolsVersion: .v3) + try await builder.serve("a", at: "3.2.1", toolsVersion: .v4) + try await builder.serve("a", at: "3.2.2", toolsVersion: .v5) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(.range("3.2.0" ..< "4.0.0")), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'a' contains incompatible tools version (\( @@ -2961,20 +2952,20 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testIncompatibleToolsVersion6() throws { - try builder.serve("a", at: "3.2.1", toolsVersion: .v5) - try builder.serve("a", at: "3.2.0", with: [ + func testIncompatibleToolsVersion6() async throws { + try await builder.serve("a", at: "3.2.1", toolsVersion: .v5) + try await builder.serve("a", at: "3.2.0", with: [ "a": ["b": (.versionSet(v1Range), .specific(["b"]))], ]) - try builder.serve("a", at: "3.2.2", toolsVersion: .v4) - try builder.serve("b", at: "1.0.0", toolsVersion: .v3) + try await builder.serve("a", at: "3.2.2", toolsVersion: .v4) + try await builder.serve("b", at: "1.0.0", toolsVersion: .v3) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "a": (.versionSet(.range("3.2.0" ..< "4.0.0")), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } XCTAssertEqual(result.errorMsg, """ Dependencies could not be resolved because 'a' >= 3.2.1 contains incompatible tools version (\( @@ -2989,28 +2980,28 @@ final class PubGrubDiagnosticsTests: XCTestCase { """) } - func testProductsCannotResolveToDifferentVersions() throws { - try builder.serve("package", at: .unversioned, with: [ + func testProductsCannotResolveToDifferentVersions() async throws { + try await builder.serve("package", at: .unversioned, with: [ "package": [ "intermediate_a": (.versionSet(v1Range), .specific(["Intermediate A"])), "intermediate_b": (.versionSet(v1Range), .specific(["Intermediate B"])), ], ]) - try builder.serve("intermediate_a", at: v1, with: [ + try await builder.serve("intermediate_a", at: v1, with: [ "Intermediate A": [ "transitive": (.versionSet(.exact(v1)), .specific(["Product A"])), ], ]) - try builder.serve("intermediate_b", at: v1, with: [ + try await builder.serve("intermediate_b", at: v1, with: [ "Intermediate B": [ "transitive": (.versionSet(.exact(v1_1)), .specific(["Product B"])), ], ]) - try builder.serve("transitive", at: v1, with: [ + try await builder.serve("transitive", at: v1, with: [ "Product A": [:], "Product B": [:], ]) - try builder.serve("transitive", at: v1_1, with: [ + try await builder.serve("transitive", at: v1_1, with: [ "Product A": [:], "Product B": [:], ]) @@ -3019,7 +3010,7 @@ final class PubGrubDiagnosticsTests: XCTestCase { let dependencies = try builder.create(dependencies: [ "package": (.unversioned, .everything), ]) - let result = resolver.solve(constraints: dependencies) + let result = await Result { try await resolver.solve(constraints: dependencies) } // TODO: this description could use refinement XCTAssertEqual( @@ -3035,12 +3026,12 @@ final class PubGrubDiagnosticsTests: XCTestCase { } final class PubGrubBacktrackTests: XCTestCase { - func testBacktrack1() throws { - try builder.serve("a", at: v1) - try builder.serve("a", at: "2.0.0", with: [ + func testBacktrack1() async throws { + try await builder.serve("a", at: v1) + try await builder.serve("a", at: "2.0.0", with: [ "a": ["b": (.versionSet(.exact("1.0.0")), .specific(["b"]))], ]) - try builder.serve("b", at: "1.0.0", with: [ + try await builder.serve("b", at: "1.0.0", with: [ "b": ["a": (.versionSet(.exact("1.0.0")), .specific(["a"]))], ]) @@ -3049,29 +3040,29 @@ final class PubGrubBacktrackTests: XCTestCase { "a": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["a"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), ]) } - func testBacktrack2() throws { - try builder.serve("a", at: v1) - try builder.serve("a", at: "2.0.0", with: [ + func testBacktrack2() async throws { + try await builder.serve("a", at: v1) + try await builder.serve("a", at: "2.0.0", with: [ "a": ["c": (.versionSet(.range("1.0.0" ..< "2.0.0")), .specific(["c"]))], ]) - try builder.serve("b", at: "1.0.0", with: [ + try await builder.serve("b", at: "1.0.0", with: [ "b": ["c": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["c"]))], ]) - try builder.serve("b", at: "2.0.0", with: [ + try await builder.serve("b", at: "2.0.0", with: [ "b": ["c": (.versionSet(.range("3.0.0" ..< "4.0.0")), .specific(["c"]))], ]) - try builder.serve("c", at: "1.0.0") - try builder.serve("c", at: "2.0.0") - try builder.serve("c", at: "3.0.0") + try await builder.serve("c", at: "1.0.0") + try await builder.serve("c", at: "2.0.0") + try await builder.serve("c", at: "3.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -3079,7 +3070,7 @@ final class PubGrubBacktrackTests: XCTestCase { "b": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["b"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -3088,30 +3079,30 @@ final class PubGrubBacktrackTests: XCTestCase { ]) } - func testBacktrack3() throws { - try builder.serve("a", at: "1.0.0", with: [ + func testBacktrack3() async throws { + try await builder.serve("a", at: "1.0.0", with: [ "a": ["x": (.versionSet(.range("1.0.0" ..< "5.0.0")), .specific(["x"]))], ]) - try builder.serve("b", at: "1.0.0", with: [ + try await builder.serve("b", at: "1.0.0", with: [ "b": ["x": (.versionSet(.range("0.0.0" ..< "2.0.0")), .specific(["x"]))], ]) - try builder.serve("c", at: "1.0.0") - try builder.serve("c", at: "2.0.0", with: [ + try await builder.serve("c", at: "1.0.0") + try await builder.serve("c", at: "2.0.0", with: [ "c": [ "a": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["a"])), "b": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["b"])), ], ]) - try builder.serve("x", at: "0.0.0") - try builder.serve("x", at: "2.0.0") - try builder.serve("x", at: "1.0.0", with: [ + try await builder.serve("x", at: "0.0.0") + try await builder.serve("x", at: "2.0.0") + try await builder.serve("x", at: "1.0.0", with: [ "x": ["y": (.versionSet(.exact(v1)), .specific(["y"]))], ]) - try builder.serve("y", at: "1.0.0") - try builder.serve("y", at: "2.0.0") + try await builder.serve("y", at: "1.0.0") + try await builder.serve("y", at: "2.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -3119,7 +3110,7 @@ final class PubGrubBacktrackTests: XCTestCase { "y": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["y"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("c", .version(v1)), @@ -3127,30 +3118,30 @@ final class PubGrubBacktrackTests: XCTestCase { ]) } - func testBacktrack4() throws { - try builder.serve("a", at: "1.0.0", with: [ + func testBacktrack4() async throws { + try await builder.serve("a", at: "1.0.0", with: [ "a": ["x": (.versionSet(.range("1.0.0" ..< "5.0.0")), .specific(["x"]))], ]) - try builder.serve("b", at: "1.0.0", with: [ + try await builder.serve("b", at: "1.0.0", with: [ "b": ["x": (.versionSet(.range("0.0.0" ..< "2.0.0")), .specific(["x"]))], ]) - try builder.serve("c", at: "1.0.0") - try builder.serve("c", at: "2.0.0", with: [ + try await builder.serve("c", at: "1.0.0") + try await builder.serve("c", at: "2.0.0", with: [ "c": [ "a": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["a"])), "b": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["b"])), ], ]) - try builder.serve("x", at: "0.0.0") - try builder.serve("x", at: "2.0.0") - try builder.serve("x", at: "1.0.0", with: [ + try await builder.serve("x", at: "0.0.0") + try await builder.serve("x", at: "2.0.0") + try await builder.serve("x", at: "1.0.0", with: [ "x": ["y": (.versionSet(.exact(v1)), .specific(["y"]))], ]) - try builder.serve("y", at: "1.0.0") - try builder.serve("y", at: "2.0.0") + try await builder.serve("y", at: "1.0.0") + try await builder.serve("y", at: "2.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -3158,7 +3149,7 @@ final class PubGrubBacktrackTests: XCTestCase { "y": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["y"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("c", .version(v1)), @@ -3166,35 +3157,35 @@ final class PubGrubBacktrackTests: XCTestCase { ]) } - func testBacktrack5() throws { - try builder.serve("foo", at: "1.0.0", with: [ + func testBacktrack5() async throws { + try await builder.serve("foo", at: "1.0.0", with: [ "foo": ["bar": (.versionSet(.exact("1.0.0")), .specific(["bar"]))], ]) - try builder.serve("foo", at: "2.0.0", with: [ + try await builder.serve("foo", at: "2.0.0", with: [ "foo": ["bar": (.versionSet(.exact("2.0.0")), .specific(["bar"]))], ]) - try builder.serve("foo", at: "3.0.0", with: [ + try await builder.serve("foo", at: "3.0.0", with: [ "foo": ["bar": (.versionSet(.exact("3.0.0")), .specific(["bar"]))], ]) - try builder.serve("bar", at: "1.0.0", with: [ + try await builder.serve("bar", at: "1.0.0", with: [ "bar": ["baz": (.versionSet(.range("0.0.0" ..< "3.0.0")), .specific(["baz"]))], ]) - try builder.serve("bar", at: "2.0.0", with: [ + try await builder.serve("bar", at: "2.0.0", with: [ "bar": ["baz": (.versionSet(.exact("3.0.0")), .specific(["baz"]))], ]) - try builder.serve("bar", at: "3.0.0", with: [ + try await builder.serve("bar", at: "3.0.0", with: [ "bar": ["baz": (.versionSet(.exact("3.0.0")), .specific(["baz"]))], ]) - try builder.serve("baz", at: "1.0.0") + try await builder.serve("baz", at: "1.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["foo"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .version(v1)), @@ -3203,17 +3194,17 @@ final class PubGrubBacktrackTests: XCTestCase { ]) } - func testBacktrack6() throws { - try builder.serve("a", at: "1.0.0") - try builder.serve("a", at: "2.0.0") - try builder.serve("b", at: "1.0.0", with: [ + func testBacktrack6() async throws { + try await builder.serve("a", at: "1.0.0") + try await builder.serve("a", at: "2.0.0") + try await builder.serve("b", at: "1.0.0", with: [ "b": ["a": (.versionSet(.exact("1.0.0")), .specific(["a"]))], ]) - try builder.serve("c", at: "1.0.0", with: [ + try await builder.serve("c", at: "1.0.0", with: [ "c": ["b": (.versionSet(.range("0.0.0" ..< "3.0.0")), .specific(["b"]))], ]) - try builder.serve("d", at: "1.0.0") - try builder.serve("d", at: "2.0.0") + try await builder.serve("d", at: "1.0.0") + try await builder.serve("d", at: "2.0.0") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -3222,7 +3213,7 @@ final class PubGrubBacktrackTests: XCTestCase { "d": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["d"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version(v1)), @@ -3232,17 +3223,17 @@ final class PubGrubBacktrackTests: XCTestCase { ]) } - func testLogging() throws { - try builder.serve("a", at: "1.0.0") - try builder.serve("a", at: "2.0.0") - try builder.serve("b", at: "1.0.1", with: [ + func testLogging() async throws { + try await builder.serve("a", at: "1.0.0") + try await builder.serve("a", at: "2.0.0") + try await builder.serve("b", at: "1.0.1", with: [ "b": ["a": (.versionSet(.exact("1.0.0")), .specific(["a"]))], ]) - try builder.serve("c", at: "1.5.2", with: [ + try await builder.serve("c", at: "1.5.2", with: [ "c": ["b": (.versionSet(.range("0.0.0" ..< "3.0.0")), .specific(["b"]))], ]) - try builder.serve("d", at: "1.0.1") - try builder.serve("d", at: "2.3.0") + try await builder.serve("d", at: "1.0.1") + try await builder.serve("d", at: "2.3.0") let observability = ObservabilitySystem.makeForTesting() @@ -3256,7 +3247,7 @@ final class PubGrubBacktrackTests: XCTestCase { "d": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["d"])), ]) - let result = resolver.solve(constraints: dependencies) + let result = try await resolver.solve(constraints: dependencies) AssertResult(result, [ ("a", .version("1.0.0")), @@ -3336,21 +3327,21 @@ private func AssertBindings( /// Asserts that a result succeeded and contains the specified bindings. private func AssertResult( - _ result: Result<[DependencyResolverBinding], Error>, + _ bindings: [DependencyResolverBinding], _ packages: [(identifier: String, version: BoundVersion)], file: StaticString = #file, line: UInt = #line ) { - switch result { - case .success(let bindings): - AssertBindings( - bindings, - packages.map { (PackageIdentity($0.identifier), $0.version) }, - file: file, - line: line - ) - case .failure(let error): - XCTFail("Unexpected error: \(error)", file: file, line: line) + AssertBindings(bindings, packages.map { (PackageIdentity($0.identifier), $0.version) }, file: file, line: line) +} + +extension Result where Failure == any Error { + init(_ f: () async throws -> Success) async { + do { + self = .success(try await f()) + } catch { + self = .failure(error) + } } } @@ -3371,19 +3362,19 @@ private func AssertError( } // FIXME: this is not thread-safe -public class MockContainer: PackageContainer { - public typealias Dependency = ( +private actor MockContainer: PackageContainer { + typealias Dependency = ( container: PackageReference, requirement: PackageRequirement, productFilter: ProductFilter ) - public var package: PackageReference - var manifestName: PackageReference? + let package: PackageReference + let manifestName: PackageReference? var dependencies: [String: [String: [Dependency]]] - public var unversionedDeps: [PackageContainerConstraint] = [] + var unversionedDeps: [PackageContainerConstraint] /// The list of versions that have incompatible tools version. var toolsVersion: ToolsVersion = .current @@ -3392,7 +3383,7 @@ public class MockContainer: PackageContainer { private var _versions: [BoundVersion] // TODO: this does not actually do anything with the tools-version - public func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { + func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { var versions: [Version] = [] for version in self._versions.reversed() { guard case .version(let v, _) = version else { continue } @@ -3401,7 +3392,7 @@ public class MockContainer: PackageContainer { return versions } - public func versionsAscending() throws -> [Version] { + func versionsAscending() throws -> [Version] { var versions: [Version] = [] for version in self._versions { guard case .version(let v, _) = version else { continue } @@ -3410,7 +3401,7 @@ public class MockContainer: PackageContainer { return versions } - public func isToolsVersionCompatible(at version: Version) -> Bool { + func isToolsVersionCompatible(at version: Version) -> Bool { // this checks for *exact* version match which is good enough for our current tests if let toolsVersion = try? self.toolsVersion(for: version) { return self.toolsVersion == toolsVersion @@ -3419,7 +3410,7 @@ public class MockContainer: PackageContainer { return (try? self.toolsVersionsAppropriateVersionsDescending().contains(version)) ?? false } - public func toolsVersion(for version: Version) throws -> ToolsVersion { + func toolsVersion(for version: Version) throws -> ToolsVersion { struct NotFound: Error {} guard let version = versionsToolsVersions[version] else { @@ -3428,14 +3419,14 @@ public class MockContainer: PackageContainer { return version } - public func getDependencies( + func getDependencies( at version: Version, productFilter: ProductFilter ) throws -> [PackageContainerConstraint] { try self.getDependencies(at: version.description, productFilter: productFilter) } - public func getDependencies( + func getDependencies( at revision: String, productFilter: ProductFilter ) throws -> [PackageContainerConstraint] { @@ -3452,7 +3443,7 @@ public class MockContainer: PackageContainer { } } - public func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint] { + func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint] { // FIXME: This is messy, remove unversionedDeps property. if !self.unversionedDeps.isEmpty { return self.unversionedDeps @@ -3460,9 +3451,9 @@ public class MockContainer: PackageContainer { return try self.getDependencies(at: PackageRequirement.unversioned.description, productFilter: productFilter) } - public func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { + func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { if let manifestName { - self.package = self.package.withName(manifestName.identity.description) + return self.package.withName(manifestName.identity.description) } return self.package } @@ -3478,7 +3469,32 @@ public class MockContainer: PackageContainer { }) } - public convenience init( + func serve( + at version: BoundVersion, + toolsVersion: ToolsVersion? = nil, + with dependencies: KeyValuePairs< + String, + OrderedCollections.OrderedDictionary + > = [:] + ) async throws { + if case .version(let v) = version { + self.versionsToolsVersions[v] = toolsVersion ?? self.toolsVersion + } + + self.appendVersion(version) + + if self.dependencies[version.description] == nil { + self.dependencies[version.description] = [:] + } + for (product, filteredDependencies) in dependencies { + let packageDependencies: [MockContainer.Dependency] = filteredDependencies.map { + (container: $0, requirement: $1.0, productFilter: $1.1) + } + self.dependencies[version.description, default: [:]][product, default: []] += packageDependencies + } + } + + public init( package: PackageReference, unversionedDependencies: [( package: PackageReference, @@ -3486,22 +3502,26 @@ public class MockContainer: PackageContainer { productFilter: ProductFilter )] ) { - self.init(package: package) - self.unversionedDeps = unversionedDependencies - .map { PackageContainerConstraint( - package: $0.package, - requirement: $0.requirement, - products: $0.productFilter - ) } + self.init( + package: package, + unversionedDependencies: unversionedDependencies.map { + PackageContainerConstraint( + package: $0.package, + requirement: $0.requirement, + products: $0.productFilter + ) + } + ) } - public convenience init( + public init( package: PackageReference, dependenciesByVersion: [Version: [String: [( package: PackageReference, requirement: VersionSetSpecifier, productFilter: ProductFilter - )]]] + )]]], + manifestName: PackageReference? = nil ) { var dependencies: [String: [String: [Dependency]]] = [:] for (version, productDependencies) in dependenciesByVersion { @@ -3514,15 +3534,19 @@ public class MockContainer: PackageContainer { } } } - self.init(package: package, dependencies: dependencies) + self.init(package: package, dependencies: dependencies, manifestName: manifestName) } public init( package: PackageReference, - dependencies: [String: [String: [Dependency]]] = [:] + dependencies: [String: [String: [Dependency]]] = [:], + unversionedDependencies: [PackageContainerConstraint] = [], + manifestName: PackageReference? = nil ) { self.package = package self.dependencies = dependencies + self.unversionedDeps = unversionedDependencies + self.manifestName = manifestName let versions = dependencies.keys.compactMap(Version.init(_:)) self._versions = versions .sorted() @@ -3530,39 +3554,36 @@ public class MockContainer: PackageContainer { } } -public enum _MockLoadingError: Error { +private enum _MockLoadingError: Error { case unknownModule case unknownRevision } -public struct MockProvider: PackageContainerProvider { - public let containers: [MockContainer] - public let containersByIdentifier: [PackageReference: MockContainer] +private struct MockProvider: PackageContainerProvider { + let containers: [MockContainer] + let containersByIdentifier: [PackageReference: MockContainer] - public init(containers: [MockContainer]) { + init(containers: [MockContainer]) { self.containers = containers self.containersByIdentifier = Dictionary(uniqueKeysWithValues: containers.map { ($0.package, $0) }) } - public func getContainer( + func getContainer( for package: PackageReference, updateStrategy: ContainerUpdateStrategy, observabilityScope: ObservabilityScope, on queue: DispatchQueue, - completion: @escaping ( - Result - ) -> Void + completion: @escaping (Result) -> Void ) { queue.async { completion( - self.containersByIdentifier[package].map { .success($0) } ?? - .failure(_MockLoadingError.unknownModule) + self.containersByIdentifier[package].map { .success($0) } ?? .failure(_MockLoadingError.unknownModule) ) } } } -class DependencyGraphBuilder { +final class DependencyGraphBuilder { private var containers: [String: MockContainer] = [:] private var references: [String: PackageReference] = [:] @@ -3607,8 +3628,8 @@ class DependencyGraphBuilder { String, OrderedCollections.OrderedDictionary > = [:] - ) throws { - try self.serve(package, at: versions.map { .version($0) }, toolsVersion: toolsVersion, with: dependencies) + ) async throws { + try await self.serve(package, at: versions.map { .version($0) }, toolsVersion: toolsVersion, with: dependencies) } func serve( @@ -3619,8 +3640,8 @@ class DependencyGraphBuilder { String, OrderedCollections.OrderedDictionary > = [:] - ) throws { - try self.serve(package, at: .version(version), toolsVersion: toolsVersion, with: dependencies) + ) async throws { + try await self.serve(package, at: .version(version), toolsVersion: toolsVersion, with: dependencies) } func serve( @@ -3631,9 +3652,9 @@ class DependencyGraphBuilder { String, OrderedCollections.OrderedDictionary > = [:] - ) throws { + ) async throws { let packageReference = try reference(for: package) - try self.serve( + try await self.serve( packageReference, at: versions, toolsVersion: toolsVersion, @@ -3649,9 +3670,9 @@ class DependencyGraphBuilder { String, OrderedCollections.OrderedDictionary > = [:] - ) throws { + ) async throws { let packageReference = try reference(for: package) - try self.serve( + try await self.serve( packageReference, at: version, toolsVersion: toolsVersion, @@ -3667,9 +3688,9 @@ class DependencyGraphBuilder { String, OrderedCollections.OrderedDictionary > = [:] - ) throws { + ) async throws { for version in versions { - try self.serve(packageReference, at: version, toolsVersion: toolsVersion, with: dependencies) + try await self.serve(packageReference, at: version, toolsVersion: toolsVersion, with: dependencies) } } @@ -3681,7 +3702,7 @@ class DependencyGraphBuilder { String, OrderedCollections.OrderedDictionary > = [:] - ) throws { + ) async throws { let container = self .containers[packageReference.identity.description] ?? MockContainer(package: packageReference) @@ -3815,7 +3836,7 @@ extension Result where Success == [DependencyResolverBinding] { switch self { case .failure(let error): switch error { - case let err as PubGrubDependencyResolver.PubgrubError: + case let err as PubgrubError: guard case .unresolvable(let msg) = err else { XCTFail("Unexpected result \(self)") return nil diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index 58b233e8cbb..902c3eca3f2 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -316,7 +316,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) @@ -696,7 +696,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - XCTAssertThrowsError(try workspace.loadPackageGraph( + await XCTAssertAsyncThrowsError(try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope )) { error in @@ -775,7 +775,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - XCTAssertThrowsError(try workspace.loadPackageGraph( + await XCTAssertAsyncThrowsError(try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope)) { error in var diagnosed = false @@ -884,7 +884,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) @@ -1078,7 +1078,7 @@ final class PluginInvocationTests: XCTestCase { ) XCTAssert(rootManifests.count == 1, "\(rootManifests)") - let graph = try workspace.loadPackageGraph( + let graph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) @@ -1225,7 +1225,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( + let packageGraph = try await workspace.loadPackageGraph( rootInput: rootInput, observabilityScope: observability.topScope ) diff --git a/Tests/WorkspaceTests/RegistryPackageContainerTests.swift b/Tests/WorkspaceTests/RegistryPackageContainerTests.swift index 4ff02d352b3..5f35e6f4822 100644 --- a/Tests/WorkspaceTests/RegistryPackageContainerTests.swift +++ b/Tests/WorkspaceTests/RegistryPackageContainerTests.swift @@ -99,7 +99,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v4) let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, ["1.0.1"]) } @@ -107,7 +107,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v4_2) let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, ["1.0.2", "1.0.1"]) } @@ -115,7 +115,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_4) let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, ["1.0.3", "1.0.2", "1.0.1"]) } } @@ -167,8 +167,8 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_2) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_3) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + try await XCTAssertAsyncEqual(try await container.toolsVersion(for: packageVersion), .v5_3) + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, []) } @@ -176,8 +176,8 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_3) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_3) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + try await XCTAssertAsyncEqual(try await container.toolsVersion(for: packageVersion), .v5_3) + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) } @@ -185,8 +185,8 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_4) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_4) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + try await XCTAssertAsyncEqual(try await container.toolsVersion(for: packageVersion), .v5_4) + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) } @@ -194,8 +194,8 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_5) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_5) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + try await XCTAssertAsyncEqual(try await container.toolsVersion(for: packageVersion), .v5_5) + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) } @@ -203,8 +203,8 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_6) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) - XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_5) - let versions = try container.toolsVersionsAppropriateVersionsDescending() + try await XCTAssertAsyncEqual(try await container.toolsVersion(for: packageVersion), .v5_5) + let versions = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) } } @@ -293,7 +293,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_3) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer - let manifest = try container.loadManifest(version: packageVersion) + let manifest = try await container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_3) } @@ -301,7 +301,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(v5_3_3) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer - let manifest = try container.loadManifest(version: packageVersion) + let manifest = try await container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, v5_3_3) } @@ -309,7 +309,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_4) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer - let manifest = try container.loadManifest(version: packageVersion) + let manifest = try await container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_4) } @@ -317,7 +317,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_5) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer - let manifest = try container.loadManifest(version: packageVersion) + let manifest = try await container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_5) } @@ -325,7 +325,7 @@ final class RegistryPackageContainerTests: XCTestCase { let provider = try createProvider(.v5_6) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer - let manifest = try container.loadManifest(version: packageVersion) + let manifest = try await container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_5) } } diff --git a/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift b/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift index de87b5c1a9e..1682c54bfb0 100644 --- a/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift +++ b/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift @@ -232,7 +232,7 @@ final class SourceControlPackageContainerTests: XCTestCase { let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) - let v = try container.toolsVersionsAppropriateVersionsDescending() + let v = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["2.0.3", "1.0.3", "1.0.2", "1.0.1", "1.0.0"]) } @@ -292,7 +292,7 @@ final class SourceControlPackageContainerTests: XCTestCase { let provider = try createProvider(ToolsVersion(version: "4.0.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) - let v = try container.toolsVersionsAppropriateVersionsDescending() + let v = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["1.0.1"]) } @@ -300,12 +300,12 @@ final class SourceControlPackageContainerTests: XCTestCase { let provider = try createProvider(ToolsVersion(version: "4.2.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) as! SourceControlPackageContainer - XCTAssertTrue(container.validToolsVersionsCache.isEmpty) - let v = try container.toolsVersionsAppropriateVersionsDescending() - XCTAssertEqual(container.validToolsVersionsCache["1.0.0"], false) - XCTAssertEqual(container.validToolsVersionsCache["1.0.1"], true) - XCTAssertEqual(container.validToolsVersionsCache["1.0.2"], true) - XCTAssertEqual(container.validToolsVersionsCache["1.0.3"], true) + await XCTAssertAsyncTrue(await container.validToolsVersionsCache.isEmpty) + let v = try await container.toolsVersionsAppropriateVersionsDescending() + await XCTAssertAsyncEqual(await container.validToolsVersionsCache["1.0.0"], false) + await XCTAssertAsyncEqual(await container.validToolsVersionsCache["1.0.1"], true) + await XCTAssertAsyncEqual(await container.validToolsVersionsCache["1.0.2"], true) + await XCTAssertAsyncEqual(await container.validToolsVersionsCache["1.0.3"], true) XCTAssertEqual(v, ["1.0.3", "1.0.2", "1.0.1"]) } @@ -313,7 +313,7 @@ final class SourceControlPackageContainerTests: XCTestCase { let provider = try createProvider(ToolsVersion(version: "3.0.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) - let v = try container.toolsVersionsAppropriateVersionsDescending() + let v = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, []) } @@ -322,9 +322,9 @@ final class SourceControlPackageContainerTests: XCTestCase { let provider = try createProvider(ToolsVersion(version: "4.0.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) as! SourceControlPackageContainer - let revision = try container.getRevision(forTag: "1.0.0") + let revision = try await container.getRevision(forTag: "1.0.0") do { - _ = try container.getDependencies(at: revision.identifier, productFilter: .nothing) + _ = try await container.getDependencies(at: revision.identifier, productFilter: .nothing) } catch let error as SourceControlPackageContainer.GetDependenciesError { let error = error.underlyingError as! UnsupportedToolsVersion XCTAssertMatch(error.description, .and(.prefix("package '\(PackageIdentity(path: repoPath))' @"), .suffix("is using Swift tools version 3.1.0 which is no longer supported; consider using '// swift-tools-version:4.0' to specify the current tools version"))) @@ -375,7 +375,7 @@ final class SourceControlPackageContainerTests: XCTestCase { let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) - let v = try container.toolsVersionsAppropriateVersionsDescending() + let v = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["1.0.4-alpha", "1.0.2-dev.2", "1.0.2-dev", "1.0.1", "1.0.0", "1.0.0-beta.1", "1.0.0-alpha.1"]) } @@ -426,7 +426,7 @@ final class SourceControlPackageContainerTests: XCTestCase { ) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) let container = try await provider.getContainer(for: ref) - let v = try container.toolsVersionsAppropriateVersionsDescending() + let v = try await container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["2.0.1", "1.3.0", "1.2.0", "1.1.0", "1.0.4", "1.0.2", "1.0.1", "1.0.0"]) } @@ -615,7 +615,7 @@ final class SourceControlPackageContainerTests: XCTestCase { let container = try await containerProvider.getContainer(for: packageRef) as! SourceControlPackageContainer // Simulate accessing a fictitious dependency on the `master` branch, and check that we get back the expected error. - do { _ = try container.getDependencies(at: "master", productFilter: .everything) } + do { _ = try await container.getDependencies(at: "master", productFilter: .everything) } catch let error as SourceControlPackageContainer.GetDependenciesError { // We expect to get an error message that mentions main. XCTAssertMatch(error.description, .and(.prefix("could not find a branch named ‘master’"), .suffix("(did you mean ‘main’?)"))) @@ -624,7 +624,7 @@ final class SourceControlPackageContainerTests: XCTestCase { } // Simulate accessing a fictitious dependency on some random commit that doesn't exist, and check that we get back the expected error. - do { _ = try container.getDependencies(at: "535f4cb5b4a0872fa691473e82d7b27b9894df00", productFilter: .everything) } + do { _ = try await container.getDependencies(at: "535f4cb5b4a0872fa691473e82d7b27b9894df00", productFilter: .everything) } catch let error as SourceControlPackageContainer.GetDependenciesError { // We expect to get an error message about the specific commit. XCTAssertMatch(error.description, .prefix("could not find the commit 535f4cb5b4a0872fa691473e82d7b27b9894df00")) @@ -780,8 +780,8 @@ final class SourceControlPackageContainerTests: XCTestCase { let packageReference = PackageReference.localSourceControl(identity: PackageIdentity(path: packageDirectory), path: packageDirectory) let container = try await containerProvider.getContainer(for: packageReference) - let forNothing = try container.getDependencies(at: version, productFilter: .specific([])) - let forProduct = try container.getDependencies(at: version, productFilter: .specific(["Product"])) + let forNothing = try await container.getDependencies(at: version, productFilter: .specific([])) + let forProduct = try await container.getDependencies(at: version, productFilter: .specific(["Product"])) #if ENABLE_TARGET_BASED_DEPENDENCY_RESOLUTION // If the cache overlaps (incorrectly), these will be the same. XCTAssertNotEqual(forNothing, forProduct) diff --git a/Tests/WorkspaceTests/WorkspaceTests.swift b/Tests/WorkspaceTests/WorkspaceTests.swift index ae996deb4cc..9b541cd492a 100644 --- a/Tests/WorkspaceTests/WorkspaceTests.swift +++ b/Tests/WorkspaceTests/WorkspaceTests.swift @@ -28,11 +28,11 @@ import struct TSCBasic.ByteString import struct TSCUtility.Version final class WorkspaceTests: XCTestCase { - func testBasics() throws { + func testBasics() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -79,7 +79,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(path: "./Quix", requirement: .upToNextMajor(from: "1.0.0"), products: .specific(["Quix"])), .sourceControl(path: "./Baz", requirement: .exact("1.0.0"), products: .specific(["Baz"])), ] - try workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Baz", "Foo", "Quix") @@ -143,7 +143,7 @@ final class WorkspaceTests: XCTestCase { // Remove state file and check we can get the state back automatically. try fs.removeFileTree(stateFile) - try workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { _, _ in } + try await workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { _, _ in } XCTAssertTrue(fs.exists(stateFile), "workspace state file should exist") // Remove state file and check we get back to a clean state. @@ -262,11 +262,11 @@ final class WorkspaceTests: XCTestCase { } } - func testMultipleRootPackages() throws { + func testMultipleRootPackages() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -305,7 +305,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo", "Bar"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo", "Bar"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Bar", "Foo") result.check(packages: "Bar", "Baz", "Foo") @@ -319,11 +319,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRootPackagesOverride() throws { + func testRootPackagesOverride() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -371,7 +371,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo", "Bar", "Overridden/bazzz"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo", "Bar", "Overridden/bazzz"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Bar", "Foo", "Baz") result.check(packages: "Bar", "Baz", "Foo") @@ -381,11 +381,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateRootPackages() throws { + func testDuplicateRootPackages() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -410,7 +410,7 @@ final class WorkspaceTests: XCTestCase { packages: [] ) - workspace.checkPackageGraphFailure(roots: ["Foo", "Nested/Foo"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Foo", "Nested/Foo"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .equal("found multiple top-level packages named 'Foo'"), severity: .error) } @@ -418,11 +418,11 @@ final class WorkspaceTests: XCTestCase { } /// Test that the explicit name given to a package is not used as its identity. - func testExplicitPackageNameIsNotUsedAsPackageIdentity() throws { + func testExplicitPackageNameIsNotUsedAsPackageIdentity() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -472,7 +472,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph( + try await workspace.checkPackageGraph( roots: ["foo-package", "bar-package"], dependencies: [ .localSourceControl( @@ -491,11 +491,11 @@ final class WorkspaceTests: XCTestCase { } /// Test that the remote repository is not resolved when a root package with same name is already present. - func testRootAsDependency1() throws { + func testRootAsDependency1() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -535,7 +535,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo", "Baz"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo", "Baz"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Baz", "Foo") result.check(packages: "Baz", "Foo") @@ -552,11 +552,11 @@ final class WorkspaceTests: XCTestCase { } /// Test that a root package can be used as a dependency when the remote version was resolved previously. - func testRootAsDependency2() throws { + func testRootAsDependency2() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -596,7 +596,7 @@ final class WorkspaceTests: XCTestCase { ) // Load only Foo right now so Baz is loaded from remote. - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Baz", "Foo") @@ -616,7 +616,7 @@ final class WorkspaceTests: XCTestCase { // Now load with Baz as a root package. workspace.delegate.clear() - try workspace.checkPackageGraph(roots: ["Foo", "Baz"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo", "Baz"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Baz", "Foo") result.check(packages: "Baz", "Foo") @@ -639,11 +639,11 @@ final class WorkspaceTests: XCTestCase { ) } - func testGraphRootDependencies() throws { + func testGraphRootDependencies() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [], @@ -687,7 +687,7 @@ final class WorkspaceTests: XCTestCase { ), ] - try workspace.checkPackageGraph(dependencies: dependencies) { graph, diagnostics in + try await workspace.checkPackageGraph(dependencies: dependencies) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(packages: "Bar", "Foo") result.check(targets: "Bar", "Foo") @@ -701,11 +701,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCanResolveWithIncompatiblePins() throws { + func testCanResolveWithIncompatiblePins() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [], @@ -754,7 +754,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./A", requirement: .exact("1.0.0"), products: .specific(["A"])), ] - try workspace.checkPackageGraph(deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(packages: "A", "AA") result.check(targets: "A", "AA") @@ -777,7 +777,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./A", requirement: .exact("1.0.1"), products: .specific(["A"])), ] - try workspace.checkPackageGraph(deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.checkTarget("A") { result in result.check(dependencies: "AA") } } @@ -803,11 +803,11 @@ final class WorkspaceTests: XCTestCase { } } - func testResolverCanHaveError() throws { + func testResolverCanHaveError() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [], @@ -855,7 +855,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(path: "./A", requirement: .exact("1.0.0"), products: .specific(["A"])), .sourceControl(path: "./B", requirement: .exact("1.0.0"), products: .specific(["B"])), ] - try workspace.checkPackageGraph(deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(deps: deps) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .contains("Dependencies could not be resolved"), severity: .error) } @@ -871,7 +871,7 @@ final class WorkspaceTests: XCTestCase { let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) let v2 = CheckoutState.version("2.0.0", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -916,7 +916,7 @@ final class WorkspaceTests: XCTestCase { let v1Requirement: SourceControlRequirement = .range("1.0.0" ..< "2.0.0") let v1 = CheckoutState.version("1.0.0", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -979,7 +979,7 @@ final class WorkspaceTests: XCTestCase { let branchRequirement: SourceControlRequirement = .branch("master") let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1044,7 +1044,7 @@ final class WorkspaceTests: XCTestCase { let cPath = RelativePath("C") let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) - let testWorkspace = try MockWorkspace( + let testWorkspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1097,7 +1097,7 @@ final class WorkspaceTests: XCTestCase { let masterRequirement: SourceControlRequirement = .branch("master") let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1164,7 +1164,7 @@ final class WorkspaceTests: XCTestCase { let v1Requirement: SourceControlRequirement = .range("1.0.0" ..< "2.0.0") let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1232,7 +1232,7 @@ final class WorkspaceTests: XCTestCase { let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) let master = CheckoutState.branch(name: "master", revision: Revision(identifier: "master")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1300,7 +1300,7 @@ final class WorkspaceTests: XCTestCase { let v2Requirement: SourceControlRequirement = .range("2.0.0" ..< "3.0.0") let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1370,7 +1370,7 @@ final class WorkspaceTests: XCTestCase { let v1_5 = CheckoutState.version("1.0.5", revision: Revision(identifier: "hello")) let v2 = CheckoutState.version("2.0.0", revision: Revision(identifier: "hello")) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1425,11 +1425,11 @@ final class WorkspaceTests: XCTestCase { XCTAssertEqual(result.result.isRequired, false) } - func testLoadingRootManifests() throws { + func testLoadingRootManifests() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1440,7 +1440,7 @@ final class WorkspaceTests: XCTestCase { packages: [] ) - try workspace.checkPackageGraph(roots: ["A", "B", "C"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["A", "B", "C"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(packages: "A", "B", "C") result.check(targets: "A", "B", "C") @@ -1449,11 +1449,11 @@ final class WorkspaceTests: XCTestCase { } } - func testUpdate() throws { + func testUpdate() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1511,7 +1511,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./Foo", requirement: .exact("1.0.0"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -1524,10 +1524,10 @@ final class WorkspaceTests: XCTestCase { } // Run update. - try workspace.checkUpdate(roots: ["Root"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -1544,17 +1544,17 @@ final class WorkspaceTests: XCTestCase { // Run update again. // Ensure that up-to-date delegate is called when there is nothing to update. - try workspace.checkUpdate(roots: ["Root"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } XCTAssertMatch(workspace.delegate.events, [.equal("Everything is already up-to-date")]) } - func testUpdateDryRun() throws { + func testUpdateDryRun() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1600,7 +1600,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(path: "./Foo", requirement: .exact("1.0.0"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -1612,7 +1612,7 @@ final class WorkspaceTests: XCTestCase { } // Run update. - try workspace.checkUpdateDryRun(roots: ["Root"]) { changes, diagnostics in + try await workspace.checkUpdateDryRun(roots: ["Root"]) { changes, diagnostics in XCTAssertNoDiagnostics(diagnostics) #if ENABLE_TARGET_BASED_DEPENDENCY_RESOLUTION let stateChange = Workspace.PackageStateChange @@ -1633,7 +1633,7 @@ final class WorkspaceTests: XCTestCase { } XCTAssertEqual(expectedChange, change) } - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -1645,11 +1645,11 @@ final class WorkspaceTests: XCTestCase { } } - func testPartialUpdate() throws { + func testPartialUpdate() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1710,7 +1710,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./Foo", requirement: .exact("1.0.0"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -1722,7 +1722,7 @@ final class WorkspaceTests: XCTestCase { // // Try to update just Bar. This shouldn't do anything because Bar can't be updated due // to Foo's requirements. - try workspace.checkUpdate(roots: ["Root"], packages: ["Bar"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"], packages: ["Bar"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -1731,7 +1731,7 @@ final class WorkspaceTests: XCTestCase { } // Try to update just Foo. This should update Foo but not Bar. - try workspace.checkUpdate(roots: ["Root"], packages: ["Foo"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"], packages: ["Foo"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -1740,7 +1740,7 @@ final class WorkspaceTests: XCTestCase { } // Run full update. - try workspace.checkUpdate(roots: ["Root"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -1749,11 +1749,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCleanAndReset() throws { + func testCleanAndReset() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1785,7 +1785,7 @@ final class WorkspaceTests: XCTestCase { ) // Load package graph. - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -1828,11 +1828,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDependencyManifestLoading() throws { + func testDependencyManifestLoading() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1864,19 +1864,18 @@ final class WorkspaceTests: XCTestCase { ) // Check that we can compute missing dependencies. - try workspace.loadDependencyManifests(roots: ["Root1", "Root2"]) { manifests, diagnostics in - XCTAssertEqual( - try! manifests.missingPackages.map(\.locationString).sorted(), - [ - sandbox.appending(components: "pkgs", "Bar").pathString, - sandbox.appending(components: "pkgs", "Foo").pathString, - ] - ) - XCTAssertNoDiagnostics(diagnostics) - } + var (manifests, diagnostics) = try await workspace.loadDependencyManifests(roots: ["Root1", "Root2"]) + XCTAssertEqual( + try! manifests.missingPackages.map(\.locationString).sorted(), + [ + sandbox.appending(components: "pkgs", "Bar").pathString, + sandbox.appending(components: "pkgs", "Foo").pathString, + ] + ) + XCTAssertNoDiagnostics(diagnostics) // Load the graph with one root. - try workspace.checkPackageGraph(roots: ["Root1"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root1"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(packages: "Foo", "Root1") } @@ -1884,16 +1883,15 @@ final class WorkspaceTests: XCTestCase { } // Check that we compute the correct missing dependencies. - try workspace.loadDependencyManifests(roots: ["Root1", "Root2"]) { manifests, diagnostics in - XCTAssertEqual( - try! manifests.missingPackages.map(\.locationString).sorted(), - [sandbox.appending(components: "pkgs", "Bar").pathString] - ) - XCTAssertNoDiagnostics(diagnostics) - } + (manifests, diagnostics) = try await workspace.loadDependencyManifests(roots: ["Root1", "Root2"]) + XCTAssertEqual( + try! manifests.missingPackages.map(\.locationString).sorted(), + [sandbox.appending(components: "pkgs", "Bar").pathString] + ) + XCTAssertNoDiagnostics(diagnostics) // Load the graph with both roots. - try workspace.checkPackageGraph(roots: ["Root1", "Root2"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root1", "Root2"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(packages: "Bar", "Foo", "Root1", "Root2") } @@ -1901,17 +1899,16 @@ final class WorkspaceTests: XCTestCase { } // Check that we compute the correct missing dependencies. - try workspace.loadDependencyManifests(roots: ["Root1", "Root2"]) { manifests, diagnostics in - XCTAssertEqual(try! manifests.missingPackages.map(\.locationString).sorted(), []) - XCTAssertNoDiagnostics(diagnostics) - } + (manifests, diagnostics) = try await workspace.loadDependencyManifests(roots: ["Root1", "Root2"]) + XCTAssertEqual(try! manifests.missingPackages.map(\.locationString).sorted(), []) + XCTAssertNoDiagnostics(diagnostics) } - func testDependencyManifestsOrder() throws { + func testDependencyManifestsOrder() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -1962,25 +1959,24 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root1"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root1"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } - try workspace.loadDependencyManifests(roots: ["Root1"]) { manifests, diagnostics in - // Ensure that the order of the manifests is stable. - XCTAssertEqual( - manifests.allDependencyManifests.map(\.value.manifest.displayName), - ["Bam", "Baz", "Bar", "Foo"] - ) - XCTAssertNoDiagnostics(diagnostics) - } + let (manifests, diagnostics) = try await workspace.loadDependencyManifests(roots: ["Root1"]) + // Ensure that the order of the manifests is stable. + XCTAssertEqual( + manifests.allDependencyManifests.map(\.value.manifest.displayName), + ["Bam", "Baz", "Bar", "Foo"] + ) + XCTAssertNoDiagnostics(diagnostics) } - func testBranchAndRevision() throws { + func testBranchAndRevision() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2027,7 +2023,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./Bar", requirement: .revision(barRevision), products: .specific(["Bar"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -2040,11 +2036,11 @@ final class WorkspaceTests: XCTestCase { } } - func testResolve() throws { + func testResolve() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2074,7 +2070,7 @@ final class WorkspaceTests: XCTestCase { ) // Load initial version. - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -2089,7 +2085,7 @@ final class WorkspaceTests: XCTestCase { } // Resolve to an older version. - workspace.checkResolve(pkg: "Foo", roots: ["Root"], version: "1.0.0") { diagnostics in + await workspace.checkResolve(pkg: "Foo", roots: ["Root"], version: "1.0.0") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2100,7 +2096,7 @@ final class WorkspaceTests: XCTestCase { } // Check failure. - workspace.checkResolve(pkg: "Foo", roots: ["Root"], version: "1.3.0") { diagnostics in + await workspace.checkResolve(pkg: "Foo", roots: ["Root"], version: "1.3.0") { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .contains("'foo' 1.3.0"), severity: .error) } @@ -2113,11 +2109,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDeletedCheckoutDirectory() throws { + func testDeletedCheckoutDirectory() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2138,7 +2134,7 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -2148,7 +2144,7 @@ final class WorkspaceTests: XCTestCase { try fs.removeFileTree(workspace.getOrCreateWorkspace().location.repositoriesCheckoutsDirectory) - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -2159,11 +2155,11 @@ final class WorkspaceTests: XCTestCase { } } - func testMinimumRequiredToolsVersionInDependencyResolution() throws { + func testMinimumRequiredToolsVersionInDependencyResolution() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2193,18 +2189,18 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .contains("'foo' 1.0.0..<2.0.0"), severity: .error) } } } - func testToolsVersionRootPackages() throws { + func testToolsVersionRootPackages() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2240,11 +2236,11 @@ final class WorkspaceTests: XCTestCase { try fs.writeFileContents(roots[1], bytes: "// swift-tools-version:4.1.0") try fs.writeFileContents(roots[2], bytes: "// swift-tools-version:3.1") - try workspace.checkPackageGraph(roots: ["Foo"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } - workspace.checkPackageGraphFailure(roots: ["Bar"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Bar"]) { diagnostics in testDiagnostics(diagnostics) { result in let diagnostic = result.check( diagnostic: .equal( @@ -2255,7 +2251,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertEqual(diagnostic?.metadata?.packageIdentity, .plain("bar")) } } - workspace.checkPackageGraphFailure(roots: ["Foo", "Bar"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Foo", "Bar"]) { diagnostics in testDiagnostics(diagnostics) { result in let diagnostic = result.check( diagnostic: .equal( @@ -2266,7 +2262,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertEqual(diagnostic?.metadata?.packageIdentity, .plain("bar")) } } - workspace.checkPackageGraphFailure(roots: ["Baz"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Baz"]) { diagnostics in testDiagnostics(diagnostics) { result in let diagnostic = result.check( diagnostic: .equal( @@ -2279,11 +2275,11 @@ final class WorkspaceTests: XCTestCase { } } - func testEditDependency() throws { + func testEditDependency() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2324,7 +2320,7 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -2334,7 +2330,7 @@ final class WorkspaceTests: XCTestCase { // Edit foo. let fooPath = try workspace.getOrCreateWorkspace().location.editsDirectory.appending("Foo") - workspace.checkEdit(packageName: "Foo") { diagnostics in + await workspace.checkEdit(packageName: "Foo") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2342,14 +2338,13 @@ final class WorkspaceTests: XCTestCase { } XCTAssertTrue(fs.exists(fooPath)) - try workspace.loadDependencyManifests(roots: ["Root"]) { manifests, diagnostics in - let editedPackages = manifests.editedPackagesConstraints - XCTAssertEqual(editedPackages.map(\.package.locationString), [fooPath.pathString]) - XCTAssertNoDiagnostics(diagnostics) - } + let (manifests, diagnostics) = try await workspace.loadDependencyManifests(roots: ["Root"]) + let editedPackages = manifests.editedPackagesConstraints + XCTAssertEqual(editedPackages.map(\.package.locationString), [fooPath.pathString]) + XCTAssertNoDiagnostics(diagnostics) // Try re-editing foo. - workspace.checkEdit(packageName: "Foo") { diagnostics in + await workspace.checkEdit(packageName: "Foo") { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .equal("dependency 'foo' already in edit mode"), severity: .error) } @@ -2359,7 +2354,7 @@ final class WorkspaceTests: XCTestCase { } // Try editing bar at bad revision. - workspace.checkEdit(packageName: "Bar", revision: Revision(identifier: "dev")) { diagnostics in + await workspace.checkEdit(packageName: "Bar", revision: Revision(identifier: "dev")) { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .equal("revision 'dev' does not exist"), severity: .error) } @@ -2367,7 +2362,7 @@ final class WorkspaceTests: XCTestCase { // Edit bar at a custom path and branch (ToT). let barPath = AbsolutePath("/tmp/ws/custom/bar") - workspace.checkEdit(packageName: "Bar", path: barPath, checkoutBranch: "dev") { diagnostics in + await workspace.checkEdit(packageName: "Bar", path: barPath, checkoutBranch: "dev") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2377,21 +2372,21 @@ final class WorkspaceTests: XCTestCase { XCTAssert(barRepo.revisions.contains("dev")) // Test unediting. - workspace.checkUnedit(packageName: "Foo", roots: ["Root"]) { diagnostics in + await workspace.checkUnedit(packageName: "Foo", roots: ["Root"]) { diagnostics in XCTAssertFalse(fs.exists(fooPath)) XCTAssertNoDiagnostics(diagnostics) } - workspace.checkUnedit(packageName: "Bar", roots: ["Root"]) { diagnostics in + await workspace.checkUnedit(packageName: "Bar", roots: ["Root"]) { diagnostics in XCTAssert(fs.exists(barPath)) XCTAssertNoDiagnostics(diagnostics) } } - func testMissingEditCanRestoreOriginalCheckout() throws { + func testMissingEditCanRestoreOriginalCheckout() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2421,11 +2416,11 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { _, _ in } + try await workspace.checkPackageGraph(roots: ["Root"]) { _, _ in } // Edit foo. let fooPath = try workspace.getOrCreateWorkspace().location.editsDirectory.appending("Foo") - workspace.checkEdit(packageName: "Foo") { diagnostics in + await workspace.checkEdit(packageName: "Foo") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2435,7 +2430,7 @@ final class WorkspaceTests: XCTestCase { // Remove the edited package. try fs.removeFileTree(fooPath) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -2450,11 +2445,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCanUneditRemovedDependencies() throws { + func testCanUneditRemovedDependencies() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [], @@ -2478,13 +2473,13 @@ final class WorkspaceTests: XCTestCase { let ws = try workspace.getOrCreateWorkspace() // Load the graph and edit foo. - try workspace.checkPackageGraph(deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(packages: "Foo") } XCTAssertNoDiagnostics(diagnostics) } - workspace.checkEdit(packageName: "Foo") { diagnostics in + await workspace.checkEdit(packageName: "Foo") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2492,14 +2487,14 @@ final class WorkspaceTests: XCTestCase { } // Remove foo. - try workspace.checkUpdate { diagnostics in + try await workspace.checkUpdate { diagnostics in XCTAssertNoDiagnostics(diagnostics) } XCTAssertMatch( workspace.delegate.events, [.equal("removing repo: \(sandbox.appending(components: "pkgs", "Foo"))")] ) - try workspace.checkPackageGraph(deps: []) { _, diagnostics in + try await workspace.checkPackageGraph(deps: []) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -2516,7 +2511,7 @@ final class WorkspaceTests: XCTestCase { } // Unedit foo. - workspace.checkUnedit(packageName: "Foo", roots: []) { diagnostics in + await workspace.checkUnedit(packageName: "Foo", roots: []) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2524,11 +2519,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDependencyResolutionWithEdit() throws { + func testDependencyResolutionWithEdit() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2572,7 +2567,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(path: "./Foo", requirement: .exact("1.0.0"), products: .specific(["Foo"])), ] // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -2585,7 +2580,7 @@ final class WorkspaceTests: XCTestCase { } // Edit bar. - workspace.checkEdit(packageName: "Bar") { diagnostics in + await workspace.checkEdit(packageName: "Bar") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2606,7 +2601,7 @@ final class WorkspaceTests: XCTestCase { } // Now, resolve foo at a different version. - workspace.checkResolve(pkg: "Foo", roots: ["Root"], version: "1.2.0") { diagnostics in + await workspace.checkResolve(pkg: "Foo", roots: ["Root"], version: "1.2.0") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2619,7 +2614,7 @@ final class WorkspaceTests: XCTestCase { } // Try package update. - try workspace.checkUpdate(roots: ["Root"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2632,7 +2627,7 @@ final class WorkspaceTests: XCTestCase { } // Unedit should get the Package.resolved entry back. - workspace.checkUnedit(packageName: "bar", roots: ["Root"]) { diagnostics in + await workspace.checkUnedit(packageName: "bar", roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2645,11 +2640,11 @@ final class WorkspaceTests: XCTestCase { } } - func testPrefetchingWithOverridenPackage() throws { + func testPrefetchingWithOverridenPackage() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2702,7 +2697,7 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -2716,7 +2711,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .fileSystem(path: "./Foo", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Bar", "Root") @@ -2730,11 +2725,11 @@ final class WorkspaceTests: XCTestCase { } // Test that changing a particular dependency re-resolves the graph. - func testChangeOneDependency() throws { + func testChangeOneDependency() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2766,7 +2761,7 @@ final class WorkspaceTests: XCTestCase { ) // Initial resolution. - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Bar", "Foo") @@ -2807,7 +2802,7 @@ final class WorkspaceTests: XCTestCase { XCTFail("unexpected dependency type") } - try workspace.checkPackageGraph(roots: ["Foo"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2815,11 +2810,11 @@ final class WorkspaceTests: XCTestCase { } } - func testResolutionFailureWithEditedDependency() throws { + func testResolutionFailureWithEditedDependency() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2859,14 +2854,14 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") } XCTAssertNoDiagnostics(diagnostics) } - workspace.checkEdit(packageName: "Foo") { diagnostics in + await workspace.checkEdit(packageName: "Foo") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -2888,18 +2883,18 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./Bar", requirement: .exact("1.1.0"), products: .specific(["Bar"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .contains("'bar' 1.1.0"), severity: .error) } } } - func testStateModified() throws { + func testStateModified() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -2943,7 +2938,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"], deps: []) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: []) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "Bar", "Foo", "Root") @@ -2969,7 +2964,7 @@ final class WorkspaceTests: XCTestCase { } // reload graph after "external" change - try workspace.checkPackageGraph(roots: ["Root"], deps: []) { graph, _ in + try await workspace.checkPackageGraph(roots: ["Root"], deps: []) { graph, _ in PackageGraphTester(graph) { result in result.check(packages: "Bar", "Foo", "Root") } @@ -2986,11 +2981,11 @@ final class WorkspaceTests: XCTestCase { } } - func testSkipUpdate() throws { + func testSkipUpdate() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3023,23 +3018,23 @@ final class WorkspaceTests: XCTestCase { ) // Run update and remove all events. - try workspace.checkUpdate(roots: ["Root"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.delegate.clear() // Check we don't have updating Foo event. - try workspace.checkUpdate(roots: ["Root"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertMatch(workspace.delegate.events, ["Everything is already up-to-date"]) } } - func testLocalDependencyBasics() throws { + func testLocalDependencyBasics() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3083,7 +3078,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Bar", "Baz", "Foo") @@ -3101,23 +3096,23 @@ final class WorkspaceTests: XCTestCase { } // Test that its not possible to edit or resolve this package. - workspace.checkEdit(packageName: "Bar") { diagnostics in + await workspace.checkEdit(packageName: "Bar") { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .contains("local dependency 'bar' can't be edited"), severity: .error) } } - workspace.checkResolve(pkg: "Bar", roots: ["Foo"], version: "1.0.0") { diagnostics in + await workspace.checkResolve(pkg: "Bar", roots: ["Foo"], version: "1.0.0") { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .contains("local dependency 'bar' can't be resolved"), severity: .error) } } } - func testLocalDependencyTransitive() throws { + func testLocalDependencyTransitive() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3160,7 +3155,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Foo") @@ -3175,11 +3170,11 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalDependencyWithPackageUpdate() throws { + func testLocalDependencyWithPackageUpdate() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3208,7 +3203,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Bar", "Foo") @@ -3223,7 +3218,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .fileSystem(path: "./Bar", products: .specific(["Bar"])), ] - try workspace.checkUpdate(roots: ["Foo"], deps: deps) { diagnostics in + try await workspace.checkUpdate(roots: ["Foo"], deps: deps) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3231,7 +3226,7 @@ final class WorkspaceTests: XCTestCase { } // Go back to the versioned state. - try workspace.checkUpdate(roots: ["Foo"]) { diagnostics in + try await workspace.checkUpdate(roots: ["Foo"]) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3239,11 +3234,11 @@ final class WorkspaceTests: XCTestCase { } } - func testMissingLocalDependencyDiagnostic() throws { + func testMissingLocalDependencyDiagnostic() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3262,7 +3257,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Foo") @@ -3279,11 +3274,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRevisionVersionSwitch() throws { + func testRevisionVersionSwitch() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3316,7 +3311,7 @@ final class WorkspaceTests: XCTestCase { var deps: [MockDependency] = [ .sourceControl(path: "./Foo", requirement: .branch("develop"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -3330,7 +3325,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .sourceControl(path: "./Foo", requirement: .upToNextMajor(from: "1.0.0"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3340,7 +3335,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .sourceControl(path: "./Foo", requirement: .branch("develop"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3348,11 +3343,11 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalVersionSwitch() throws { + func testLocalVersionSwitch() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3385,7 +3380,7 @@ final class WorkspaceTests: XCTestCase { var deps: [MockDependency] = [ .fileSystem(path: "./Foo", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -3399,7 +3394,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .sourceControl(path: "./Foo", requirement: .upToNextMajor(from: "1.0.0"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3409,7 +3404,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .fileSystem(path: "./Foo", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3417,11 +3412,11 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalLocalSwitch() throws { + func testLocalLocalSwitch() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3465,7 +3460,7 @@ final class WorkspaceTests: XCTestCase { var deps: [MockDependency] = [ .fileSystem(path: "./Foo", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -3479,7 +3474,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .fileSystem(path: "./Foo2", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3489,11 +3484,11 @@ final class WorkspaceTests: XCTestCase { // Test that switching between two same local packages placed at // different locations works correctly. - func testDependencySwitchLocalWithSameIdentity() throws { + func testDependencySwitchLocalWithSameIdentity() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3534,7 +3529,7 @@ final class WorkspaceTests: XCTestCase { var deps: [MockDependency] = [ .fileSystem(path: "./Foo", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Foo", "Root") @@ -3552,7 +3547,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .fileSystem(path: "./Nested/Foo", products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3566,11 +3561,11 @@ final class WorkspaceTests: XCTestCase { // Test that switching between two remote packages at // different locations works correctly. - func testDependencySwitchRemoteWithSameIdentity() throws { + func testDependencySwitchRemoteWithSameIdentity() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3612,7 +3607,7 @@ final class WorkspaceTests: XCTestCase { var deps: [MockDependency] = [ .sourceControl(url: "https://scm.com/org/foo", requirement: .exact("1.0.0")), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -3630,7 +3625,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .sourceControl(url: "https://scm.com/other/foo", requirement: .exact("1.1.0")), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3642,11 +3637,11 @@ final class WorkspaceTests: XCTestCase { } } - func testResolvedFileUpdate() throws { + func testResolvedFileUpdate() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3676,7 +3671,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./Foo", requirement: .upToNextMajor(from: "1.0.0"), products: .specific(["Foo"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3686,7 +3681,7 @@ final class WorkspaceTests: XCTestCase { result.check(dependency: "foo", at: .checkout(.version("1.0.0"))) } - try workspace.checkPackageGraph(roots: ["Root"], deps: []) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: []) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3697,7 +3692,7 @@ final class WorkspaceTests: XCTestCase { } } - func testResolvedFileSchemeToolsVersion() throws { + func testResolvedFileSchemeToolsVersion() async throws { let fs = InMemoryFileSystem() for pair in [ @@ -3706,7 +3701,7 @@ final class WorkspaceTests: XCTestCase { (ToolsVersion.v5_2, ToolsVersion.v5_6), ] { let sandbox = AbsolutePath("/tmp/ws/") - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3749,7 +3744,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root1", "Root2"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root1", "Root2"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3765,11 +3760,11 @@ final class WorkspaceTests: XCTestCase { } } - func testResolvedFileStableCanonicalLocation() throws { + func testResolvedFileStableCanonicalLocation() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -3852,7 +3847,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(url: "https://localhost/org/foo", requirement: .exact("1.0.0")), .sourceControl(url: "https://localhost/org/bar", requirement: .exact("1.0.0")), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -3885,7 +3880,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace(resetResolvedFile: false) XCTAssertTrue(fs.exists(sandbox.appending("Package.resolved"))) // run update - try workspace.checkUpdate(roots: ["Root"], deps: deps) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"], deps: deps) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -3920,7 +3915,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace(resetResolvedFile: false) XCTAssertTrue(fs.exists(sandbox.appending("Package.resolved"))) // run update - try workspace.checkUpdate(roots: ["Root"], deps: deps) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"], deps: deps) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -3959,7 +3954,7 @@ final class WorkspaceTests: XCTestCase { try fs.removeFileTree(sandbox.appending("Package.resolved")) XCTAssertFalse(fs.exists(sandbox.appending("Package.resolved"))) // run update - try workspace.checkUpdate(roots: ["Root"], deps: deps) { diagnostics in + try await workspace.checkUpdate(roots: ["Root"], deps: deps) { diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -3991,11 +3986,11 @@ final class WorkspaceTests: XCTestCase { } } - func testPreferResolvedFileWhenExists() throws { + func testPreferResolvedFileWhenExists() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4058,7 +4053,7 @@ final class WorkspaceTests: XCTestCase { // initial resolution without resolved file do { - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4088,7 +4083,7 @@ final class WorkspaceTests: XCTestCase { // reset but keep resolved file try workspace.closeWorkspace(resetResolvedFile: false) // run resolution again, now it should rely on the resolved file - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4114,7 +4109,7 @@ final class WorkspaceTests: XCTestCase { try fs.writeFileContents(rootManifestPath, string: manifestContent.appending("\n")) // run resolution again, but change requirements - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4139,7 +4134,7 @@ final class WorkspaceTests: XCTestCase { // restore original manifest try fs.writeFileContents(rootManifestPath, string: manifestContent) // run resolution again, now it should rely on the resolved file - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4164,7 +4159,7 @@ final class WorkspaceTests: XCTestCase { .remoteSourceControl(url: "https://localhost/org/baz", requirement: .upToNextMinor(from: "1.0.0")) ] // run resolution again, but change requirements - try workspace.checkPackageGraph(roots: ["Root"], dependencies: changedDeps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], dependencies: changedDeps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Baz", "Foo", "Root") @@ -4187,7 +4182,7 @@ final class WorkspaceTests: XCTestCase { // reset but keep resolved file try workspace.closeWorkspace(resetResolvedFile: false) // run resolution again, but change requirements back to original - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4210,7 +4205,7 @@ final class WorkspaceTests: XCTestCase { // reset but keep resolved file try workspace.closeWorkspace(resetResolvedFile: false) // run resolution again, now it should rely on the resolved file - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4231,7 +4226,7 @@ final class WorkspaceTests: XCTestCase { // reset including removing resolved file try workspace.closeWorkspace(resetResolvedFile: true) // run resolution again - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Root") result.check(packages: "Bar", "Foo", "Root") @@ -4259,7 +4254,7 @@ final class WorkspaceTests: XCTestCase { } } - func testPackageSimpleMirrorPath() throws { + func testPackageSimpleMirrorPath() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -4273,7 +4268,7 @@ final class WorkspaceTests: XCTestCase { for: sandbox.appending(components: "pkgs", "Baz").pathString ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4334,7 +4329,7 @@ final class WorkspaceTests: XCTestCase { mirrors: mirrors ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "BarMirror", "BazMirror", "Foo", "Dep") @@ -4351,7 +4346,7 @@ final class WorkspaceTests: XCTestCase { } } - func testPackageMirrorPath() throws { + func testPackageMirrorPath() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -4365,7 +4360,7 @@ final class WorkspaceTests: XCTestCase { for: sandbox.appending(components: "pkgs", "Baz").pathString ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4438,7 +4433,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(path: "./Baz", requirement: .upToNextMajor(from: "1.0.0"), products: .specific(["Baz"])), ] - try workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "BarMirror", "Foo", "Dep") @@ -4454,7 +4449,7 @@ final class WorkspaceTests: XCTestCase { } } - func testPackageSimpleMirrorURL() throws { + func testPackageSimpleMirrorURL() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -4462,7 +4457,7 @@ final class WorkspaceTests: XCTestCase { try mirrors.set(mirror: "https://scm.com/org/bar-mirror", for: "https://scm.com/org/bar") try mirrors.set(mirror: "https://scm.com/org/baz-mirror", for: "https://scm.com/org/baz") - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4526,7 +4521,7 @@ final class WorkspaceTests: XCTestCase { mirrors: mirrors ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "BarMirror", "BazMirror", "Foo", "Dep") @@ -4543,7 +4538,7 @@ final class WorkspaceTests: XCTestCase { } } - func testPackageMirrorURL() throws { + func testPackageMirrorURL() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -4551,7 +4546,7 @@ final class WorkspaceTests: XCTestCase { try mirrors.set(mirror: "https://scm.com/org/bar-mirror", for: "https://scm.com/org/bar") try mirrors.set(mirror: "https://scm.com/org/bar-mirror", for: "https://scm.com/org/baz") - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4632,7 +4627,7 @@ final class WorkspaceTests: XCTestCase { ), ] - try workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "BarMirror", "Foo", "Dep") @@ -4648,14 +4643,14 @@ final class WorkspaceTests: XCTestCase { } } - func testPackageMirrorURLToRegistry() throws { + func testPackageMirrorURLToRegistry() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let mirrors = try DependencyMirrors() try mirrors.set(mirror: "org.bar-mirror", for: "https://scm.com/org/bar") - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4703,7 +4698,7 @@ final class WorkspaceTests: XCTestCase { mirrors: mirrors ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "BarMirror", "Baz", "Foo") @@ -4718,14 +4713,14 @@ final class WorkspaceTests: XCTestCase { } } - func testPackageMirrorRegistryToURL() throws { + func testPackageMirrorRegistryToURL() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let mirrors = try DependencyMirrors() try mirrors.set(mirror: "https://scm.com/org/bar-mirror", for: "org.bar") - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4773,7 +4768,7 @@ final class WorkspaceTests: XCTestCase { mirrors: mirrors ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "BarMirror", "Baz", "Foo") @@ -4791,7 +4786,7 @@ final class WorkspaceTests: XCTestCase { // In this test, we get into a state where an entry in the resolved // file for a transitive dependency whose URL is later changed to // something else, while keeping the same package identity. - func testTransitiveDependencySwitchWithSameIdentity() throws { + func testTransitiveDependencySwitchWithSameIdentity() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -4799,7 +4794,7 @@ final class WorkspaceTests: XCTestCase { // package despite having different URLs. let fooRevision = String((UUID().uuidString + UUID().uuidString).prefix(40)) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4889,7 +4884,7 @@ final class WorkspaceTests: XCTestCase { var deps: [MockDependency] = [ .sourceControl(url: "https://scm.com/org/bar", requirement: .exact("1.0.0")), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -4916,7 +4911,7 @@ final class WorkspaceTests: XCTestCase { deps = [ .sourceControl(url: "https://scm.com/org/bar", requirement: .exact("1.1.0")), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -4938,11 +4933,11 @@ final class WorkspaceTests: XCTestCase { } } - func testForceResolveToResolvedVersions() throws { + func testForceResolveToResolvedVersions() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -4986,7 +4981,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(path: "./Bar", requirement: .revision("develop"), products: .specific(["Bar"])), ] - try workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], deps: deps) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5017,7 +5012,7 @@ final class WorkspaceTests: XCTestCase { } // Check force resolve. This should produce an error because the resolved file is out-of-date. - workspace.checkPackageGraphFailure(roots: ["Root"], forceResolvedVersions: true) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"], forceResolvedVersions: true) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "an out-of-date resolved file was detected at \(sandbox.appending(components: "Package.resolved")), which is not allowed when automatic dependency resolution is disabled; please make sure to update the file to reflect the changes in dependencies. Running resolver because requirements have changed.", @@ -5035,7 +5030,7 @@ final class WorkspaceTests: XCTestCase { } // A normal resolution. - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5048,7 +5043,7 @@ final class WorkspaceTests: XCTestCase { } // This force resolution should succeed. - try workspace.checkPackageGraph(roots: ["Root"], forceResolvedVersions: true) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], forceResolvedVersions: true) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5061,11 +5056,11 @@ final class WorkspaceTests: XCTestCase { } } - func testForceResolveToResolvedVersionsDuplicateLocalDependency() throws { + func testForceResolveToResolvedVersionsDuplicateLocalDependency() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5104,19 +5099,19 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root", "Bar"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root", "Bar"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } - try workspace.checkPackageGraph(roots: ["Root", "Bar"], forceResolvedVersions: true) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root", "Bar"], forceResolvedVersions: true) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testForceResolveWithNoResolvedFile() throws { + func testForceResolveWithNoResolvedFile() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5156,7 +5151,7 @@ final class WorkspaceTests: XCTestCase { ] ) - workspace.checkPackageGraphFailure(roots: ["Root"], forceResolvedVersions: true) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"], forceResolvedVersions: true) { diagnostics in // rdar://82544922 (`WorkspaceResolveReason` is non-deterministic) testDiagnostics(diagnostics) { result in result.check( @@ -5169,11 +5164,11 @@ final class WorkspaceTests: XCTestCase { } } - func testForceResolveToResolvedVersionsLocalPackage() throws { + func testForceResolveToResolvedVersionsLocalPackage() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5202,7 +5197,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"], forceResolvedVersions: true) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], forceResolvedVersions: true) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5210,11 +5205,11 @@ final class WorkspaceTests: XCTestCase { } } - func testForceResolveToResolvedVersionsLocalPackageInAdditionalDependencies() throws { + func testForceResolveToResolvedVersionsLocalPackageInAdditionalDependencies() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5241,7 +5236,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"], dependencies: [.fileSystem(path: workspace.packagesDir.appending(component: "Foo"))], forceResolvedVersions: true) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"], dependencies: [.fileSystem(path: workspace.packagesDir.appending(component: "Foo"))], forceResolvedVersions: true) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5286,7 +5281,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertFalse(observability.hasWarningDiagnostics, observability.diagnostics.description) XCTAssertFalse(observability.hasErrorDiagnostics, observability.diagnostics.description) - let graph = try workspace.loadPackageGraph( + let graph = try await workspace.loadPackageGraph( rootPath: packagePath, observabilityScope: observability.topScope ) @@ -5309,11 +5304,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRevisionDepOnLocal() throws { + func testRevisionDepOnLocal() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5355,7 +5350,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -5367,11 +5362,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRootPackagesOverrideBasenameMismatch() throws { + func testRootPackagesOverrideBasenameMismatch() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5405,7 +5400,7 @@ final class WorkspaceTests: XCTestCase { .sourceControl(path: "./bazzz", requirement: .exact("1.0.0"), products: .specific(["Baz"])), ] - try workspace.checkPackageGraphFailure(roots: ["Overridden/bazzz-master"], deps: deps) { diagnostics in + try await workspace.checkPackageGraphFailure(roots: ["Overridden/bazzz-master"], deps: deps) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -5417,11 +5412,11 @@ final class WorkspaceTests: XCTestCase { } } - func testManagedDependenciesNotCaseSensitive() throws { + func testManagedDependenciesNotCaseSensitive() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5482,7 +5477,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"]) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Bar", "Baz", "Foo") @@ -5511,11 +5506,11 @@ final class WorkspaceTests: XCTestCase { } } - func testUnsafeFlags() throws { + func testUnsafeFlags() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5573,7 +5568,7 @@ final class WorkspaceTests: XCTestCase { ) // We should only see errors about use of unsafe flag in the version-based dependency. - try workspace.checkPackageGraph(roots: ["Foo", "Bar"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo", "Bar"]) { _, diagnostics in testDiagnostics(diagnostics) { result in let diagnostic1 = result.checkUnordered( diagnostic: .equal("the target 'Baz' in product 'Baz' contains unsafe build flags"), @@ -5591,11 +5586,11 @@ final class WorkspaceTests: XCTestCase { } } - func testUnsafeFlagsInFoundation() throws { + func testUnsafeFlagsInFoundation() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5628,16 +5623,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Test"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Test"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testEditDependencyHadOverridableConstraints() throws { + func testEditDependencyHadOverridableConstraints() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5694,7 +5689,7 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5705,7 +5700,7 @@ final class WorkspaceTests: XCTestCase { // Edit foo. let fooPath = try workspace.getOrCreateWorkspace().location.editsDirectory.appending("Foo") - workspace.checkEdit(packageName: "Foo") { diagnostics in + await workspace.checkEdit(packageName: "Foo") { diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5723,7 +5718,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertMatch(workspace.delegate.events, [.equal("will resolve dependencies")]) workspace.delegate.clear() - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5734,7 +5729,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertNoMatch(workspace.delegate.events, [.equal("will resolve dependencies")]) } - func testTargetBasedDependency() throws { + func testTargetBasedDependency() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -5749,7 +5744,7 @@ final class WorkspaceTests: XCTestCase { barProducts = [MockProduct(name: "Bar", targets: ["Bar"])] #endif - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5828,7 +5823,7 @@ final class WorkspaceTests: XCTestCase { ) // Load the graph. - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } workspace.checkManagedDependencies { result in @@ -5841,7 +5836,7 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArchivedArtifactExtractionHappyPath() throws { + func testLocalArchivedArtifactExtractionHappyPath() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -5866,7 +5861,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -5950,7 +5945,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertFalse(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/A/A2.artifactbundle"))) XCTAssertFalse(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/B/B.xcframework"))) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) // Ensure that the artifacts have been properly extracted @@ -6011,7 +6006,7 @@ final class WorkspaceTests: XCTestCase { // This test covers the last 4 permutations where the `local-archived` source is involved. // It ensures that all the appropriate clean-up operations are executed, and the workspace // contains the correct set of managed artifacts after the transition. - func testLocalArchivedArtifactSourceTransitionPermutations() throws { + func testLocalArchivedArtifactSourceTransitionPermutations() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -6081,7 +6076,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6221,7 +6216,7 @@ final class WorkspaceTests: XCTestCase { recursive: true ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) // Ensure that the original archives have been untouched @@ -6286,7 +6281,7 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArchivedArtifactNameDoesNotMatchTargetName() throws { + func testLocalArchivedArtifactNameDoesNotMatchTargetName() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -6311,7 +6306,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6340,12 +6335,12 @@ final class WorkspaceTests: XCTestCase { bytes: ByteString([0xA1]) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testLocalArchivedArtifactExtractionError() throws { + func testLocalArchivedArtifactExtractionError() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -6353,7 +6348,7 @@ final class WorkspaceTests: XCTestCase { completion(.failure(DummyError())) }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6378,7 +6373,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.checkUnordered( diagnostic: .contains( @@ -6396,7 +6391,7 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArchiveDoesNotMatchTargetName() throws { + func testLocalArchiveDoesNotMatchTargetName() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -6416,7 +6411,7 @@ final class WorkspaceTests: XCTestCase { completion(.failure(error)) } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6451,7 +6446,7 @@ final class WorkspaceTests: XCTestCase { try fs.createDirectory(aArtifactBundlesPath, recursive: true) try fs.writeFileContents(aArtifactBundlesPath.appending("A2.zip"), bytes: ByteString([0xA2])) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -6471,7 +6466,7 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArchivedArtifactChecksumChange() throws { + func testLocalArchivedArtifactChecksumChange() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -6494,7 +6489,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6552,7 +6547,7 @@ final class WorkspaceTests: XCTestCase { let a2FrameworkArchivePath = frameworksPath.appending("A2.zip") try fs.writeFileContents(a2FrameworkArchivePath, bytes: ByteString([0xA2])) - try workspace.checkPackageGraph(roots: ["Root"]) { _, _ in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, _ in // Ensure that only the artifact archive with the changed checksum has been extracted XCTAssertEqual(archiver.extractions.map(\.destinationPath.parentDirectory).sorted(), [ AbsolutePath("/tmp/ws/.build/artifacts/extract/root/A1"), @@ -6575,7 +6570,7 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArchivedArtifactStripFirstComponent() throws { + func testLocalArchivedArtifactStripFirstComponent() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -6609,7 +6604,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6653,7 +6648,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertFalse(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/root/nested/nested.artifactbundle"))) XCTAssertFalse(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/root/nested2/nested2.xcframework"))) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/root"))) XCTAssertEqual(archiver.extractions.map(\.destinationPath.parentDirectory).sorted(), [ @@ -6685,11 +6680,11 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArtifactHappyPath() throws { + func testLocalArtifactHappyPath() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6717,7 +6712,7 @@ final class WorkspaceTests: XCTestCase { try createDummyXCFramework(fileSystem: fs, path: rootPath.appending("XCFrameworks"), name: "A1") try createDummyArtifactBundle(fileSystem: fs, path: rootPath.appending("ArtifactBundles"), name: "A2") - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -6737,11 +6732,11 @@ final class WorkspaceTests: XCTestCase { } } - func testLocalArtifactDoesNotExist() throws { + func testLocalArtifactDoesNotExist() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6763,7 +6758,7 @@ final class WorkspaceTests: XCTestCase { ] ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.checkUnordered( diagnostic: .contains( @@ -6781,7 +6776,7 @@ final class WorkspaceTests: XCTestCase { } } - func testArtifactDownloadHappyPath() throws { + func testArtifactDownloadHappyPath() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let downloads = ThreadSafeKeyValueStore() @@ -6839,7 +6834,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -6905,7 +6900,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/a"))) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/b"))) @@ -6974,7 +6969,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertMatch(workspace.delegate.events, ["finished downloading binary artifact package: https://b.com/b.zip"]) } - func testArtifactDownloadWithPreviousState() throws { + func testArtifactDownloadWithPreviousState() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let downloads = ThreadSafeKeyValueStore() @@ -7040,7 +7035,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7199,7 +7194,7 @@ final class WorkspaceTests: XCTestCase { ] ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "downloaded archive of binary target 'A3' from 'https://a.com/a3.zip' does not contain a binary artifact.", @@ -7286,7 +7281,7 @@ final class WorkspaceTests: XCTestCase { } } - func testArtifactDownloadTwice() throws { + func testArtifactDownloadTwice() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let downloads = ThreadSafeArrayStore<(URL, AbsolutePath)>() @@ -7342,7 +7337,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7365,7 +7360,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/root"))) XCTAssertEqual(workspace.checksumAlgorithm.hashes.map(\.hexadecimalRepresentation).sorted(), [ @@ -7390,7 +7385,7 @@ final class WorkspaceTests: XCTestCase { // do it again - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/root"))) @@ -7412,7 +7407,7 @@ final class WorkspaceTests: XCTestCase { ) } - func testArtifactDownloadServerError() throws { + func testArtifactDownloadServerError() async throws { let fs = InMemoryFileSystem() let sandbox = AbsolutePath("/tmp/ws/") try fs.createDirectory(sandbox, recursive: true) @@ -7436,7 +7431,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7457,7 +7452,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains( @@ -7473,7 +7468,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertFalse(fs.exists(AbsolutePath("/tmp/ws/.build/artifacts/root/a.zip"))) } - func testArtifactDownloaderOrArchiverError() throws { + func testArtifactDownloaderOrArchiverError() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -7506,7 +7501,7 @@ final class WorkspaceTests: XCTestCase { completion(.failure(DummyError())) }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7540,7 +7535,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.checkUnordered( diagnostic: .contains( @@ -7564,7 +7559,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactNotAnArchiveError() throws { + func testDownloadedArtifactNotAnArchiveError() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -7622,7 +7617,7 @@ final class WorkspaceTests: XCTestCase { } ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7658,7 +7653,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.checkUnordered( diagnostic: .contains( @@ -7676,7 +7671,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactInvalid() throws { + func testDownloadedArtifactInvalid() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -7715,7 +7710,7 @@ final class WorkspaceTests: XCTestCase { } ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7739,7 +7734,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.checkUnordered( diagnostic: .contains( @@ -7751,7 +7746,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactDoesNotMatchTargetName() throws { + func testDownloadedArtifactDoesNotMatchTargetName() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -7789,7 +7784,7 @@ final class WorkspaceTests: XCTestCase { } ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7813,7 +7808,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -7830,7 +7825,7 @@ final class WorkspaceTests: XCTestCase { } } - func testArtifactChecksum() throws { + func testArtifactChecksum() async throws { let fs = InMemoryFileSystem() try fs.createMockToolchain() let sandbox = AbsolutePath("/tmp/ws/") @@ -7902,7 +7897,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactChecksumChange() throws { + func testDownloadedArtifactChecksumChange() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -7910,7 +7905,7 @@ final class WorkspaceTests: XCTestCase { XCTFail("should not be called") }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -7944,7 +7939,7 @@ final class WorkspaceTests: XCTestCase { ] ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains("artifact of binary target 'A' has changed checksum"), @@ -7954,7 +7949,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactChecksumChangeURLChange() throws { + func testDownloadedArtifactChecksumChangeURLChange() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -8004,7 +7999,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8044,12 +8039,12 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testArtifactDownloadAddsAcceptHeader() throws { + func testArtifactDownloadAddsAcceptHeader() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() var acceptHeaders: [String] = [] @@ -8099,7 +8094,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8121,7 +8116,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(acceptHeaders, [ "application/octet-stream", @@ -8129,7 +8124,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactNoCache() throws { + func testDownloadedArtifactNoCache() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() var downloads = 0 @@ -8179,7 +8174,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8203,26 +8198,26 @@ final class WorkspaceTests: XCTestCase { ) // should not come from cache - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 1) } // state is there, should not come from local cache - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 1) } // resetting state, should not come from global cache try workspace.resetState() - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 2) } } - func testDownloadedArtifactCache() throws { + func testDownloadedArtifactCache() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() var downloads = 0 @@ -8272,7 +8267,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8296,20 +8291,20 @@ final class WorkspaceTests: XCTestCase { ) // should not come from cache - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 1) } // state is there, should not come from local cache - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 1) } // resetting state, should come from global cache try workspace.resetState() - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 1) } @@ -8317,20 +8312,20 @@ final class WorkspaceTests: XCTestCase { // delete global cache, should download again try workspace.resetState() try fs.removeFileTree(fs.swiftPMCacheDirectory) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 2) } // resetting state, should come from global cache again try workspace.resetState() - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads, 2) } } - func testDownloadedArtifactTransitive() throws { + func testDownloadedArtifactTransitive() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let downloads = ThreadSafeKeyValueStore() @@ -8388,7 +8383,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8473,7 +8468,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/a"))) XCTAssertEqual(downloads.map(\.key.absoluteString).sorted(), [ @@ -8504,7 +8499,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactArchiveExists() throws { + func testDownloadedArtifactArchiveExists() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() // this relies on internal knowledge of the destination path construction @@ -8570,7 +8565,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8602,7 +8597,7 @@ final class WorkspaceTests: XCTestCase { atomically: true ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -8619,7 +8614,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactConcurrency() throws { + func testDownloadedArtifactConcurrency() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -8689,7 +8684,7 @@ final class WorkspaceTests: XCTestCase { ) } - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8716,7 +8711,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["App"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["App"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } @@ -8740,7 +8735,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadedArtifactStripFirstComponent() throws { + func testDownloadedArtifactStripFirstComponent() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let downloads = ThreadSafeKeyValueStore() @@ -8813,7 +8808,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8849,7 +8844,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/root"))) XCTAssertEqual(downloads.map(\.key.absoluteString).sorted(), [ @@ -8904,7 +8899,7 @@ final class WorkspaceTests: XCTestCase { } } - func testArtifactMultipleExtensions() throws { + func testArtifactMultipleExtensions() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() let downloads = ThreadSafeKeyValueStore() @@ -8960,7 +8955,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -8990,7 +8985,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssertEqual(downloads.map(\.key.absoluteString).sorted(), [ "https://a.com/a1.xcframework.zip", @@ -9036,7 +9031,7 @@ final class WorkspaceTests: XCTestCase { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9076,7 +9071,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) } - func testDownloadArchiveIndexFilesHappyPath() throws { + func testDownloadArchiveIndexFilesHappyPath() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() try fs.createMockToolchain() @@ -9182,7 +9177,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9249,7 +9244,7 @@ final class WorkspaceTests: XCTestCase { checksumAlgorithm: checksumAlgorithm ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/a"))) XCTAssert(fs.isDirectory(AbsolutePath("/tmp/ws/.build/artifacts/b"))) @@ -9325,7 +9320,7 @@ final class WorkspaceTests: XCTestCase { XCTAssertMatch(workspace.delegate.events, ["finished downloading binary artifact package: https://b.com/b.zip"]) } - func testDownloadArchiveIndexServerError() throws { + func testDownloadArchiveIndexServerError() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -9334,7 +9329,7 @@ final class WorkspaceTests: XCTestCase { completion(.success(.serverError())) }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9355,7 +9350,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains( @@ -9367,7 +9362,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadArchiveIndexFileBadChecksum() throws { + func testDownloadArchiveIndexFileBadChecksum() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() try fs.createMockToolchain() @@ -9404,7 +9399,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9425,7 +9420,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains( @@ -9437,11 +9432,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadArchiveIndexFileChecksumChanges() throws { + func testDownloadArchiveIndexFileChecksumChanges() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9477,7 +9472,7 @@ final class WorkspaceTests: XCTestCase { ] ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains("artifact of binary target 'A' has changed checksum"), @@ -9487,7 +9482,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadArchiveIndexFileBadArchivesChecksum() throws { + func testDownloadArchiveIndexFileBadArchivesChecksum() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() try fs.createMockToolchain() @@ -9564,7 +9559,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9586,7 +9581,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains( @@ -9598,7 +9593,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadArchiveIndexFileArchiveNotFound() throws { + func testDownloadArchiveIndexFileArchiveNotFound() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() try fs.createMockToolchain() @@ -9641,7 +9636,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9662,7 +9657,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains( @@ -9674,7 +9669,7 @@ final class WorkspaceTests: XCTestCase { } } - func testDownloadArchiveIndexTripleNotFound() throws { + func testDownloadArchiveIndexTripleNotFound() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() try fs.createMockToolchain() @@ -9715,7 +9710,7 @@ final class WorkspaceTests: XCTestCase { } }) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9736,7 +9731,7 @@ final class WorkspaceTests: XCTestCase { ) ) - workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["Root"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains( @@ -9748,11 +9743,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateDependencyIdentityWithNameAtRoot() throws { + func testDuplicateDependencyIdentityWithNameAtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9807,7 +9802,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on '\(sandbox.appending(components: "pkgs", "bar", "utility"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo", "utility"))' which has the same identity 'utility'", @@ -9817,11 +9812,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateDependencyIdentityWithoutNameAtRoot() throws { + func testDuplicateDependencyIdentityWithoutNameAtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9868,7 +9863,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on '\(sandbox.appending(components: "pkgs", "bar", "utility"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo", "utility"))' which has the same identity 'utility'", @@ -9878,11 +9873,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateExplicitDependencyName_AtRoot() throws { + func testDuplicateExplicitDependencyName_AtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9937,7 +9932,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on '\(sandbox.appending(components: "pkgs", "bar"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo"))' which has the same explicit name 'FooPackage'", @@ -9947,11 +9942,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateManifestNameAtRoot() throws { + func testDuplicateManifestNameAtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -9997,16 +9992,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testDuplicateManifestName_ExplicitProductPackage_AtRoot() throws { + func testDuplicateManifestName_ExplicitProductPackage_AtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10052,16 +10047,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testManifestNameAndIdentityConflict_AtRoot_Pre52() throws { + func testManifestNameAndIdentityConflict_AtRoot_Pre52() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10107,16 +10102,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testManifestNameAndIdentityConflict_AtRoot_Post52_Incorrect() throws { + func testManifestNameAndIdentityConflict_AtRoot_Post52_Incorrect() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10162,7 +10157,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "dependency 'FooProduct' in target 'RootTarget' requires explicit declaration; reference the package in the target dependency with '.product(name: \"FooProduct\", package: \"foo\")'", @@ -10176,11 +10171,11 @@ final class WorkspaceTests: XCTestCase { } } - func testManifestNameAndIdentityConflict_AtRoot_Post52_Correct() throws { + func testManifestNameAndIdentityConflict_AtRoot_Post52_Correct() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10226,16 +10221,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testManifestNameAndIdentityConflict_ExplicitDependencyNames_AtRoot() throws { + func testManifestNameAndIdentityConflict_ExplicitDependencyNames_AtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10285,7 +10280,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on '\(sandbox.appending(components: "pkgs", "bar"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo"))' which has the same explicit name 'foo'", @@ -10295,11 +10290,11 @@ final class WorkspaceTests: XCTestCase { } } - func testManifestNameAndIdentityConflict_ExplicitDependencyNames_ExplicitProductPackage_AtRoot() throws { + func testManifestNameAndIdentityConflict_ExplicitDependencyNames_ExplicitProductPackage_AtRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10349,7 +10344,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on '\(sandbox.appending(components: "pkgs", "bar"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo"))' which has the same explicit name 'foo'", @@ -10359,11 +10354,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateTransitiveIdentityWithNames() throws { + func testDuplicateTransitiveIdentityWithNames() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10438,7 +10433,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'bar' dependency on '\(sandbox.appending(components: "pkgs", "other", "utility"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo", "utility"))' which has the same identity 'utility'", @@ -10448,11 +10443,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateTransitiveIdentityWithoutNames() throws { + func testDuplicateTransitiveIdentityWithoutNames() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10517,7 +10512,7 @@ final class WorkspaceTests: XCTestCase { // 9/2021 this is currently emitting a warning only to support backwards compatibility // we will escalate this to an error in a few versions to tighten up the validation - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'bar' dependency on '\(sandbox.appending(components: "pkgs", "other-foo", "utility"))' conflicts with dependency on '\(sandbox.appending(components: "pkgs", "foo", "utility"))' which has the same identity 'utility'. this will be escalated to an error in future versions of SwiftPM.", @@ -10533,11 +10528,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateTransitiveIdentitySimilarURLs1() throws { + func testDuplicateTransitiveIdentitySimilarURLs1() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10603,16 +10598,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testDuplicateTransitiveIdentitySimilarURLs2() throws { + func testDuplicateTransitiveIdentitySimilarURLs2() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10678,16 +10673,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testDuplicateTransitiveIdentityGitHubURLs1() throws { + func testDuplicateTransitiveIdentityGitHubURLs1() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10753,16 +10748,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testDuplicateTransitiveIdentityGitHubURLs2() throws { + func testDuplicateTransitiveIdentityGitHubURLs2() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10831,16 +10826,16 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testDuplicateTransitiveIdentityUnfamiliarURLs() throws { + func testDuplicateTransitiveIdentityUnfamiliarURLs() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -10911,7 +10906,7 @@ final class WorkspaceTests: XCTestCase { // 9/2021 this is currently emitting a warning only to support backwards compatibility // we will escalate this to an error in a few versions to tighten up the validation - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'bar' dependency on 'https://github.com/foo-moved/foo.git' conflicts with dependency on 'https://github.com/foo/foo.git' which has the same identity 'foo'. this will be escalated to an error in future versions of SwiftPM.", @@ -10921,11 +10916,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateTransitiveIdentityWithSimilarURLs() throws { + func testDuplicateTransitiveIdentityWithSimilarURLs() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11029,7 +11024,7 @@ final class WorkspaceTests: XCTestCase { // 9/2021 this is currently emitting a warning only to support backwards compatibility // we will escalate this to an error in a few versions to tighten up the validation - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics, minSeverity: .info) { result in result.checkUnordered( diagnostic: "dependency on 'foo' is represented by similar locations ('https://github.com/org/foo.git' and 'https://github.com/ORG/Foo.git') which are treated as the same canonical location 'github.com/org/foo'.", @@ -11043,11 +11038,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateNestedTransitiveIdentityWithNames() throws { + func testDuplicateNestedTransitiveIdentityWithNames() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11125,7 +11120,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in // FIXME: rdar://72940946 // we need to improve this situation or diagnostics when working on identity @@ -11137,11 +11132,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDuplicateNestedTransitiveIdentityWithoutNames() throws { + func testDuplicateNestedTransitiveIdentityWithoutNames() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11209,7 +11204,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in // FIXME: rdar://72940946 // we need to improve this situation or diagnostics when working on identity @@ -11221,11 +11216,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRootPathConflictsWithTransitiveIdentity() throws { + func testRootPathConflictsWithTransitiveIdentity() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11284,7 +11279,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["foo"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["foo"]) { _, diagnostics in testDiagnostics(diagnostics) { result in // FIXME: rdar://72940946 // we need to improve this situation or diagnostics when working on identity @@ -11296,11 +11291,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDeterministicURLPreference() throws { + func testDeterministicURLPreference() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11423,7 +11418,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "BarPackage", "BazPackage", "FooPackage", "Root", "QuxPackage") @@ -11452,11 +11447,11 @@ final class WorkspaceTests: XCTestCase { } } - func testDeterministicURLPreferenceWithRoot() throws { + func testDeterministicURLPreferenceWithRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11560,7 +11555,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "BarPackage", "BazPackage", "FooPackage", "Root") @@ -11589,11 +11584,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCanonicalURLWithPreviousManagedState() throws { + func testCanonicalURLWithPreviousManagedState() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11701,7 +11696,7 @@ final class WorkspaceTests: XCTestCase { // resolve to set previous state - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "BarPackage", "FooPackage", "Root") @@ -11720,7 +11715,7 @@ final class WorkspaceTests: XCTestCase { // update to a different url via transitive dependencies - try workspace.checkPackageGraph(roots: ["Root2"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root2"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "BarPackage", "BazPackage", "FooPackage", "Root2") @@ -11745,11 +11740,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCanonicalURLChanges() throws { + func testCanonicalURLChanges() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11812,7 +11807,7 @@ final class WorkspaceTests: XCTestCase { // check usage of canonical URL - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "FooPackage", "Root") @@ -11831,7 +11826,7 @@ final class WorkspaceTests: XCTestCase { // update URL to one with different scheme - try workspace.checkPackageGraph(roots: ["Root2"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root2"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "FooPackage", "Root2") @@ -11850,11 +11845,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCanonicalURLChangesWithTransitiveDependencies() throws { + func testCanonicalURLChangesWithTransitiveDependencies() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -11958,7 +11953,7 @@ final class WorkspaceTests: XCTestCase { // check usage of canonical URL - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "BarPackage", "FooPackage", "Root") @@ -11984,7 +11979,7 @@ final class WorkspaceTests: XCTestCase { // update URL to one with different scheme - try workspace.checkPackageGraph(roots: ["Root2"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root2"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(packages: "BarPackage", "FooPackage", "Root2") @@ -12009,11 +12004,11 @@ final class WorkspaceTests: XCTestCase { } } - func testCycleRoot() throws { + func testCycleRoot() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12115,7 +12110,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root1", "Root2"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root1", "Root2"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .regex("cyclic dependency declaration found: Root[1|2]Target -> *"), @@ -12125,11 +12120,11 @@ final class WorkspaceTests: XCTestCase { } } - func testResolutionBranchAndVersion() throws { + func testResolutionBranchAndVersion() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12180,7 +12175,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -12196,8 +12191,8 @@ final class WorkspaceTests: XCTestCase { } } - func testBinaryArtifactsInvalidPath() throws { - try testWithTemporaryDirectory { path in + func testBinaryArtifactsInvalidPath() async throws { + try await testWithTemporaryDirectory { path in let fs = localFileSystem let observability = ObservabilitySystem.makeForTesting() @@ -12225,7 +12220,7 @@ final class WorkspaceTests: XCTestCase { delegate: MockWorkspaceDelegate() ) - try workspace.resolve(root: .init(packages: [foo]), observabilityScope: observability.topScope) + try await workspace.resolve(root: .init(packages: [foo]), observabilityScope: observability.topScope) testDiagnostics(observability.diagnostics) { result in result.check( diagnostic: "invalid local path '/best.xcframework' for binary target 'best', path expected to be relative to package root.", @@ -12235,7 +12230,7 @@ final class WorkspaceTests: XCTestCase { } } - func testManifestLoaderDiagnostics() throws { + func testManifestLoaderDiagnostics() async throws { struct TestLoader: ManifestLoaderProtocol { let error: Error? @@ -12307,7 +12302,7 @@ final class WorkspaceTests: XCTestCase { customManifestLoader: TestLoader(error: .none), delegate: delegate ) - try workspace.loadPackageGraph(rootPath: .root, observabilityScope: observability.topScope) + try await workspace.loadPackageGraph(rootPath: .root, observabilityScope: observability.topScope) XCTAssertNotNil(delegate.manifest) XCTAssertNoDiagnostics(observability.diagnostics) @@ -12325,7 +12320,7 @@ final class WorkspaceTests: XCTestCase { customManifestLoader: TestLoader(error: StringError("boom")), delegate: delegate ) - try workspace.loadPackageGraph(rootPath: .root, observabilityScope: observability.topScope) + try await workspace.loadPackageGraph(rootPath: .root, observabilityScope: observability.topScope) XCTAssertNil(delegate.manifest) testDiagnostics(delegate.manifestLoadingDiagnostics ?? []) { result in @@ -12337,11 +12332,11 @@ final class WorkspaceTests: XCTestCase { } } - func testBasicResolutionFromSourceControl() throws { + func testBasicResolutionFromSourceControl() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12396,7 +12391,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "MyPackage") @@ -12443,11 +12438,11 @@ final class WorkspaceTests: XCTestCase { ) } - func testBasicTransitiveResolutionFromSourceControl() throws { + func testBasicTransitiveResolutionFromSourceControl() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12529,7 +12524,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "MyPackage") @@ -12587,11 +12582,11 @@ final class WorkspaceTests: XCTestCase { ) } - func testBasicResolutionFromRegistry() throws { + func testBasicResolutionFromRegistry() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12646,7 +12641,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "MyPackage") @@ -12693,11 +12688,11 @@ final class WorkspaceTests: XCTestCase { ) } - func testBasicTransitiveResolutionFromRegistry() throws { + func testBasicTransitiveResolutionFromRegistry() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12779,7 +12774,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "MyPackage") @@ -12838,11 +12833,11 @@ final class WorkspaceTests: XCTestCase { } // no dups - func testResolutionMixedRegistryAndSourceControl1() throws { + func testResolutionMixedRegistryAndSourceControl1() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -12904,7 +12899,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -12927,7 +12922,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -12950,7 +12945,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -12969,11 +12964,11 @@ final class WorkspaceTests: XCTestCase { } // duplicate package at root level - func testResolutionMixedRegistryAndSourceControl2() throws { + func testResolutionMixedRegistryAndSourceControl2() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13023,7 +13018,15 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertThrowsError(try workspace.checkPackageGraph(roots: ["root"]) { _, _ in + await XCTAssertAsyncThrowsError(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + testDiagnostics(diagnostics) { result in + result.check( + diagnostic: .contains(""" + multiple targets named 'FooTarget' in: 'foo', 'org.foo' + """), + severity: .error + ) + } }) { error in XCTAssertEqual((error as? PackageGraphError)?.description, "multiple packages (\'foo\' (from \'https://git/org/foo\'), \'org.foo\') declare products with a conflicting name: \'FooProduct’; product names need to be unique across the package graph") } @@ -13035,7 +13038,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on 'org.foo' conflicts with dependency on 'https://git/org/foo' which has the same identity 'org.foo'", @@ -13052,7 +13055,7 @@ final class WorkspaceTests: XCTestCase { workspace.sourceControlToRegistryDependencyTransformation = .swizzle // TODO: this error message should be improved - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: "'root' dependency on 'org.foo' conflicts with dependency on 'org.foo' which has the same identity 'org.foo'", @@ -13065,11 +13068,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 scm // --> dep2 scm --> dep1 registry - func testResolutionMixedRegistryAndSourceControl3() throws { + func testResolutionMixedRegistryAndSourceControl3() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13135,7 +13138,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13153,7 +13156,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13184,7 +13187,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in @@ -13208,7 +13211,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -13228,11 +13231,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 scm // --> dep2 registry --> dep1 registry - func testResolutionMixedRegistryAndSourceControl4() throws { + func testResolutionMixedRegistryAndSourceControl4() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13298,7 +13301,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13316,7 +13319,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13346,7 +13349,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -13366,11 +13369,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 scm // --> dep2 scm --> dep1 registry incompatible version - func testResolutionMixedRegistryAndSourceControl5() throws { + func testResolutionMixedRegistryAndSourceControl5() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13436,7 +13439,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13454,7 +13457,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: @@ -13474,7 +13477,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: @@ -13491,11 +13494,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 registry // --> dep2 registry --> dep1 scm - func testResolutionMixedRegistryAndSourceControl6() throws { + func testResolutionMixedRegistryAndSourceControl6() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13561,7 +13564,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13579,7 +13582,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13617,7 +13620,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -13637,11 +13640,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 registry // --> dep2 registry --> dep1 scm incompatible version - func testResolutionMixedRegistryAndSourceControl7() throws { + func testResolutionMixedRegistryAndSourceControl7() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13707,7 +13710,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13725,7 +13728,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: @@ -13745,7 +13748,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: @@ -13762,11 +13765,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 registry --> dep3 scm // --> dep2 registry --> dep3 registry - func testResolutionMixedRegistryAndSourceControl8() throws { + func testResolutionMixedRegistryAndSourceControl8() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -13848,7 +13851,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13866,7 +13869,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -13909,7 +13912,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in result.check(roots: "Root") @@ -13932,11 +13935,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 registry --> dep3 scm // --> dep2 registry --> dep3 registry incompatible version - func testResolutionMixedRegistryAndSourceControl9() throws { + func testResolutionMixedRegistryAndSourceControl9() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14018,7 +14021,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -14036,7 +14039,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: """ @@ -14056,7 +14059,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: """ @@ -14073,11 +14076,11 @@ final class WorkspaceTests: XCTestCase { // mixed graph root --> dep1 scm branch // --> dep2 registry --> dep1 registry - func testResolutionMixedRegistryAndSourceControl10() throws { + func testResolutionMixedRegistryAndSourceControl10() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14143,7 +14146,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .disabled - XCTAssertNoThrow(try workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in + await XCTAssertAsyncNoThrow(try await workspace.checkPackageGraph(roots: ["root"]) { _, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -14161,7 +14164,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .identity - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -14191,7 +14194,7 @@ final class WorkspaceTests: XCTestCase { do { workspace.sourceControlToRegistryDependencyTransformation = .swizzle - try workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["root"]) { graph, diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .contains(""" @@ -14220,7 +14223,7 @@ final class WorkspaceTests: XCTestCase { } } - func testCustomPackageContainerProvider() throws { + func testCustomPackageContainerProvider() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -14254,7 +14257,7 @@ final class WorkspaceTests: XCTestCase { let fooPackageReference = PackageReference(identity: PackageIdentity(path: fooPath), kind: .root(fooPath)) let fooContainer = MockPackageContainer(package: fooPackageReference) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14292,7 +14295,7 @@ final class WorkspaceTests: XCTestCase { let deps: [MockDependency] = [ .sourceControl(url: bazURL, requirement: .exact("1.0.0")), ] - try workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["Foo"], deps: deps) { graph, diagnostics in PackageGraphTester(graph) { result in result.check(roots: "Foo") result.check(packages: "Baz", "Foo") @@ -14309,7 +14312,7 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryMissingConfigurationErrors() throws { + func testRegistryMissingConfigurationErrors() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -14320,7 +14323,7 @@ final class WorkspaceTests: XCTestCase { fileSystem: fs ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14355,18 +14358,18 @@ final class WorkspaceTests: XCTestCase { registryClient: registryClient ) - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check(diagnostic: .equal("no registry configured for 'org' scope"), severity: .error) } } } - func testRegistryReleasesServerErrors() throws { + func testRegistryReleasesServerErrors() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14412,7 +14415,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal("failed fetching org.foo releases list from http://localhost: boom"), @@ -14434,7 +14437,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -14447,11 +14450,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryReleaseChecksumServerErrors() throws { + func testRegistryReleaseChecksumServerErrors() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14497,7 +14500,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -14521,7 +14524,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -14534,11 +14537,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryManifestServerErrors() throws { + func testRegistryManifestServerErrors() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14584,7 +14587,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal("failed retrieving org.foo version 1.0.0 manifest from http://localhost: boom"), @@ -14606,7 +14609,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -14619,11 +14622,11 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryDownloadServerErrors() throws { + func testRegistryDownloadServerErrors() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14669,7 +14672,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -14693,7 +14696,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .equal( @@ -14706,7 +14709,7 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryArchiveErrors() throws { + func testRegistryArchiveErrors() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -14719,7 +14722,7 @@ final class WorkspaceTests: XCTestCase { fileSystem: fs ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14756,7 +14759,7 @@ final class WorkspaceTests: XCTestCase { try workspace.closeWorkspace() workspace.registryClient = registryClient - workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in + await workspace.checkPackageGraphFailure(roots: ["MyPackage"]) { diagnostics in testDiagnostics(diagnostics) { result in result.check( diagnostic: .regex( @@ -14768,7 +14771,7 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryMetadata() throws { + func testRegistryMetadata() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -14787,7 +14790,7 @@ final class WorkspaceTests: XCTestCase { fileSystem: fs ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14831,7 +14834,7 @@ final class WorkspaceTests: XCTestCase { ] ) - try workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in guard let foo = result.find(package: "org.foo") else { @@ -14850,7 +14853,7 @@ final class WorkspaceTests: XCTestCase { } } - func testRegistryDefaultRegistryConfiguration() throws { + func testRegistryDefaultRegistryConfiguration() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -14864,7 +14867,7 @@ final class WorkspaceTests: XCTestCase { fileSystem: fs ) - let workspace = try MockWorkspace( + let workspace = try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14903,7 +14906,7 @@ final class WorkspaceTests: XCTestCase { ) ) - try workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in + try await workspace.checkPackageGraph(roots: ["MyPackage"]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) PackageGraphTester(graph) { result in XCTAssertNotNil(result.find(package: "org.foo"), "missing package") @@ -14913,11 +14916,14 @@ final class WorkspaceTests: XCTestCase { // MARK: - Expected signing entity verification - func createBasicRegistryWorkspace(metadata: [String: RegistryReleaseMetadata], mirrors: DependencyMirrors? = nil) throws -> MockWorkspace { + func createBasicRegistryWorkspace( + metadata: [String: RegistryReleaseMetadata], + mirrors: DependencyMirrors? = nil + ) async throws -> MockWorkspace { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() - return try MockWorkspace( + return try await MockWorkspace( sandbox: sandbox, fileSystem: fs, roots: [ @@ -14999,7 +15005,7 @@ final class WorkspaceTests: XCTestCase { ) } - func testSigningEntityVerification_SignedCorrectly() throws { + func testSigningEntityVerification_SignedCorrectly() async throws { let actualMetadata = RegistryReleaseMetadata.createWithSigningEntity(.recognized( type: "adp", commonName: "John Doe", @@ -15007,16 +15013,16 @@ final class WorkspaceTests: XCTestCase { identity: "XYZ") ) - let workspace = try createBasicRegistryWorkspace(metadata: ["org.bar": actualMetadata]) + let workspace = try await createBasicRegistryWorkspace(metadata: ["org.bar": actualMetadata]) - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): try XCTUnwrap(actualMetadata.signature?.signedBy), ]) { _, diagnostics in XCTAssertNoDiagnostics(diagnostics) } } - func testSigningEntityVerification_SignedIncorrectly() throws { + func testSigningEntityVerification_SignedIncorrectly() async throws { let actualMetadata = RegistryReleaseMetadata.createWithSigningEntity(.recognized( type: "adp", commonName: "John Doe", @@ -15030,10 +15036,10 @@ final class WorkspaceTests: XCTestCase { identity: "ABC" ) - let workspace = try createBasicRegistryWorkspace(metadata: ["org.bar": actualMetadata]) + let workspace = try await createBasicRegistryWorkspace(metadata: ["org.bar": actualMetadata]) do { - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): expectedSigningEntity, ]) { _, _ in } XCTFail("should not succeed") @@ -15045,7 +15051,7 @@ final class WorkspaceTests: XCTestCase { } } - func testSigningEntityVerification_Unsigned() throws { + func testSigningEntityVerification_Unsigned() async throws { let expectedSigningEntity: RegistryReleaseMetadata.SigningEntity = .recognized( type: "adp", commonName: "Jane Doe", @@ -15053,10 +15059,10 @@ final class WorkspaceTests: XCTestCase { identity: "XYZ" ) - let workspace = try createBasicRegistryWorkspace(metadata: [:]) + let workspace = try await createBasicRegistryWorkspace(metadata: [:]) do { - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): expectedSigningEntity, ]) { _, _ in } XCTFail("should not succeed") @@ -15067,7 +15073,7 @@ final class WorkspaceTests: XCTestCase { } } - func testSigningEntityVerification_NotFound() throws { + func testSigningEntityVerification_NotFound() async throws { let expectedSigningEntity: RegistryReleaseMetadata.SigningEntity = .recognized( type: "adp", commonName: "Jane Doe", @@ -15075,10 +15081,10 @@ final class WorkspaceTests: XCTestCase { identity: "XYZ" ) - let workspace = try createBasicRegistryWorkspace(metadata: [:]) + let workspace = try await createBasicRegistryWorkspace(metadata: [:]) do { - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("foo.bar"): expectedSigningEntity, ]) { _, _ in } XCTFail("should not succeed") @@ -15089,7 +15095,7 @@ final class WorkspaceTests: XCTestCase { } } - func testSigningEntityVerification_MirroredSignedCorrectly() throws { + func testSigningEntityVerification_MirroredSignedCorrectly() async throws { let mirrors = try DependencyMirrors() try mirrors.set(mirror: "ecorp.bar", for: "org.bar") @@ -15100,9 +15106,9 @@ final class WorkspaceTests: XCTestCase { identity: "XYZ") ) - let workspace = try createBasicRegistryWorkspace(metadata: ["ecorp.bar": actualMetadata], mirrors: mirrors) + let workspace = try await createBasicRegistryWorkspace(metadata: ["ecorp.bar": actualMetadata], mirrors: mirrors) - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): try XCTUnwrap(actualMetadata.signature?.signedBy), ]) { graph, diagnostics in XCTAssertNoDiagnostics(diagnostics) @@ -15113,7 +15119,7 @@ final class WorkspaceTests: XCTestCase { } } - func testSigningEntityVerification_MirrorSignedIncorrectly() throws { + func testSigningEntityVerification_MirrorSignedIncorrectly() async throws { let mirrors = try DependencyMirrors() try mirrors.set(mirror: "ecorp.bar", for: "org.bar") @@ -15130,10 +15136,10 @@ final class WorkspaceTests: XCTestCase { identity: "ABC" ) - let workspace = try createBasicRegistryWorkspace(metadata: ["ecorp.bar": actualMetadata], mirrors: mirrors) + let workspace = try await createBasicRegistryWorkspace(metadata: ["ecorp.bar": actualMetadata], mirrors: mirrors) do { - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): expectedSigningEntity, ]) { _, _ in } XCTFail("should not succeed") @@ -15145,7 +15151,7 @@ final class WorkspaceTests: XCTestCase { } } - func testSigningEntityVerification_MirroredUnsigned() throws { + func testSigningEntityVerification_MirroredUnsigned() async throws { let mirrors = try DependencyMirrors() try mirrors.set(mirror: "ecorp.bar", for: "org.bar") @@ -15156,10 +15162,10 @@ final class WorkspaceTests: XCTestCase { identity: "XYZ" ) - let workspace = try createBasicRegistryWorkspace(metadata: [:], mirrors: mirrors) + let workspace = try await createBasicRegistryWorkspace(metadata: [:], mirrors: mirrors) do { - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): expectedSigningEntity, ]) { _, _ in } XCTFail("should not succeed") @@ -15170,7 +15176,7 @@ final class WorkspaceTests: XCTestCase { } } - func testSigningEntityVerification_MirroredToSCM() throws { + func testSigningEntityVerification_MirroredToSCM() async throws { let mirrors = try DependencyMirrors() try mirrors.set(mirror: "https://scm.com/org/bar-mirror", for: "org.bar") @@ -15181,10 +15187,10 @@ final class WorkspaceTests: XCTestCase { identity: "XYZ" ) - let workspace = try createBasicRegistryWorkspace(metadata: [:], mirrors: mirrors) + let workspace = try await createBasicRegistryWorkspace(metadata: [:], mirrors: mirrors) do { - try workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ + try await workspace.checkPackageGraph(roots: ["MyPackage"], expectedSigningEntities: [ PackageIdentity.plain("org.bar"): expectedSigningEntity, ]) { _, _ in } XCTFail("should not succeed")