From 94eb23e342152c367d3bc4690c7e655d09d764a3 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 Jul 2024 15:07:41 -0700 Subject: [PATCH 1/4] Revert Improvements to prebuilt/provided library handling This reverts commit 6a719f42d5ceb12254b6d1b6ad15ab6bb1310b5e. This reverts commit a76b970ae2cc40c110466d323f095095e443d7a1. This reverts commit ec680ec3c5c6e7bec8166d08aaeae7921baece4c. This reverts commit 0486f94c94c6bd65a5071dc8784e2ae1a62c5c20. This reverts commit 2ad3bf2fd19e96398436077bc7792d9a917ad40c. This reverts commit bb7f9e783d9f27e481d40904133270e93ca88c1f. This reverts commit 04b26ea209ae8abb1fe32930dd1f965b12d21689. This reverts commit 78c68fe73cdf43b13ffd51cec73ccb5940e5110f. This reverts commit 6d7e7953845dfb8e251ed4d143f014fbeffe539c. This reverts commit 139c6fad31c9ad13bb3dde9053e2f7b3e31c9414. This reverts commit fd7995e8e05e8cc07438a41b49c7a71b2a333a9b. This reverts commit 3eb69105f571ff5685c5f50084c73e639a8c4190. This reverts commit 5aa48354e1496e23b94d1dc700e3f02e88ae8a6f. This reverts commit b88cd882fc8c79a632009df2bd5e1dfc83cf4600. This reverts commit 6d0f18ee441dffe1ac151fbac5a3cb8aee97aafa. This reverts commit 6f12e54169dec46da302b9081a2d072d339cdcf1. --- .../ProductBuildDescription.swift | 5 - .../LLBuildManifestBuilder+Swift.swift | 4 +- Sources/Build/BuildOperation.swift | 6 +- .../Build/BuildPlan/BuildPlan+Product.swift | 8 +- Sources/Build/BuildPlan/BuildPlan+Swift.swift | 6 +- Sources/Build/BuildPlan/BuildPlan.swift | 2 +- .../PackageCommands/EditCommands.swift | 1 + Sources/Commands/PackageCommands/Update.swift | 2 +- Sources/Commands/Snippets/Cards/TopCard.swift | 2 - Sources/PackageGraph/BoundVersion.swift | 5 +- .../PackageGraph/ModulesGraph+Loading.swift | 45 +++++--- Sources/PackageGraph/ModulesGraph.swift | 1 + .../PubGrub/ContainerProvider.swift | 8 +- .../PubGrub/PubGrubDependencyResolver.swift | 68 ++++++----- Sources/PackageLoading/PackageBuilder.swift | 15 --- Sources/PackageModel/CMakeLists.txt | 1 - .../LibraryMetadata.swift | 17 +-- Sources/PackageModel/Manifest/Manifest.swift | 48 -------- .../Manifest/TargetDescription.swift | 19 +--- .../ManifestSourceGeneration.swift | 2 - Sources/PackageModel/Module/Module.swift | 1 - .../Module/ProvidedLibraryModule.swift | 38 ------- Sources/PackageModel/PackageReference.swift | 2 +- Sources/PackageModel/Toolchain.swift | 2 +- Sources/PackageModel/UserToolchain.swift | 14 +-- Sources/PackageModelSyntax/AddTarget.swift | 4 +- .../TargetDescription+Syntax.swift | 1 - .../Plugins/PluginContextSerializer.swift | 2 +- Sources/Workspace/ManagedDependency.swift | 16 --- .../SourceControlPackageContainer.swift | 2 +- .../Workspace/Workspace+Dependencies.swift | 96 ++++++---------- Sources/Workspace/Workspace+Editing.swift | 7 +- Sources/Workspace/Workspace+Manifests.swift | 50 +++++--- Sources/Workspace/Workspace+Pinning.swift | 2 +- Sources/Workspace/Workspace+State.swift | 26 ----- Sources/Workspace/Workspace.swift | 16 ++- Sources/XCBuildSupport/PIFBuilder.swift | 3 - .../MockBuildTestHelper.swift | 1 - .../_InternalTestSupport/MockWorkspace.swift | 6 + Sources/swift-bootstrap/main.swift | 1 + Tests/BuildTests/BuildOperationTests.swift | 15 +-- Tests/BuildTests/BuildPlanTests.swift | 107 ------------------ Tests/CommandsTests/PackageCommandTests.swift | 1 + Tests/FunctionalTests/PluginTests.swift | 4 + .../DependencyResolverPerfTests.swift | 2 +- .../PackageGraphPerfTests.swift | 1 + Tests/PackageGraphTests/PubgrubTests.swift | 83 ++++++-------- .../PluginInvocationTests.swift | 6 + 48 files changed, 232 insertions(+), 542 deletions(-) delete mode 100644 Sources/PackageModel/Module/ProvidedLibraryModule.swift diff --git a/Sources/Build/BuildDescription/ProductBuildDescription.swift b/Sources/Build/BuildDescription/ProductBuildDescription.swift index 1ab25182110..f04fb7ec09c 100644 --- a/Sources/Build/BuildDescription/ProductBuildDescription.swift +++ b/Sources/Build/BuildDescription/ProductBuildDescription.swift @@ -46,9 +46,6 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription // Computed during build planning. var dylibs: [ProductBuildDescription] = [] - /// The list of provided libraries that are going to be used by this product. - var providedLibraries: [String: AbsolutePath] = [:] - /// Any additional flags to be added. These flags are expected to be computed during build planning. var additionalFlags: [String] = [] @@ -161,8 +158,6 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription args += ["-F", self.buildParameters.buildPath.pathString] } - self.providedLibraries.forEach { args += ["-L", $1.pathString, "-l", $0] } - args += ["-L", self.buildParameters.buildPath.pathString] args += try ["-o", binaryPath.pathString] args += ["-module-name", self.product.name.spm_mangledToC99ExtendedIdentifier()] diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift index 3f9d39a200f..fa55fba17e0 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift @@ -427,10 +427,8 @@ extension LLBuildManifestBuilder { if target.underlying is SystemLibraryModule { return } // Ignore Binary Modules. if target.underlying is BinaryModule { return } - // Ignore Plugin Targets. + // Ignore Plugin Modules. if target.underlying is PluginModule { return } - // Ignore Provided Libraries. - if target.underlying is ProvidedLibraryModule { return } // Depend on the binary for executable targets. if target.type == .executable && prepareForIndexing == .off { diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 254be762d41..d6e8e313184 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -411,7 +411,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // TODO: Currently this function will only match frameworks. func detectUnexpressedDependencies( - availableLibraries: [ProvidedLibrary], + availableLibraries: [LibraryMetadata], targetDependencyMap: [String: [String]]? ) { // Ensure we only emit these once, regardless of how many builds are being done. @@ -421,8 +421,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS Self.didEmitUnexpressedDependencies = true let availableFrameworks = Dictionary(uniqueKeysWithValues: availableLibraries.compactMap { - if let identity = Set($0.metadata.identities.map(\.identity)).spm_only { - return ("\($0.metadata.productName).framework", identity) + if let identity = Set($0.identities.map(\.identity)).spm_only { + return ("\($0.productName!).framework", identity) } else { return nil } diff --git a/Sources/Build/BuildPlan/BuildPlan+Product.swift b/Sources/Build/BuildPlan/BuildPlan+Product.swift index 9782103e689..1f2a511d6f8 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Product.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Product.swift @@ -116,8 +116,6 @@ extension BuildPlan { } buildProduct.libraryBinaryPaths = dependencies.libraryBinaryPaths - buildProduct.providedLibraries = dependencies.providedLibraries - buildProduct.availableTools = dependencies.availableTools } @@ -130,7 +128,6 @@ extension BuildPlan { staticTargets: [ResolvedModule], systemModules: [ResolvedModule], libraryBinaryPaths: Set, - providedLibraries: [String: AbsolutePath], availableTools: [String: AbsolutePath] ) { /* Prior to tools-version 5.9, we used to erroneously recursively traverse executable/plugin dependencies and statically include their @@ -208,7 +205,6 @@ extension BuildPlan { var staticTargets = [ResolvedModule]() var systemModules = [ResolvedModule]() var libraryBinaryPaths: Set = [] - var providedLibraries = [String: AbsolutePath]() var availableTools = [String: AbsolutePath]() for dependency in allTargets { @@ -262,8 +258,6 @@ extension BuildPlan { } case .plugin: continue - case .providedLibrary: - providedLibraries[target.name] = target.underlying.path } case .product(let product, _): @@ -279,7 +273,7 @@ extension BuildPlan { staticTargets.append(contentsOf: derivedTestTargets) } - return (linkLibraries, staticTargets, systemModules, libraryBinaryPaths, providedLibraries, availableTools) + return (linkLibraries, staticTargets, systemModules, libraryBinaryPaths, availableTools) } /// Extracts the artifacts from an artifactsArchive diff --git a/Sources/Build/BuildPlan/BuildPlan+Swift.swift b/Sources/Build/BuildPlan/BuildPlan+Swift.swift index 297a20ef36c..9a56e5732c5 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Swift.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Swift.swift @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// import struct Basics.InternalError + import class PackageModel.BinaryModule import class PackageModel.ClangModule import class PackageModel.SystemLibraryModule -import class PackageModel.ProvidedLibraryModule extension BuildPlan { func plan(swiftTarget: SwiftModuleBuildDescription) throws { @@ -49,10 +49,6 @@ extension BuildPlan { swiftTarget.libraryBinaryPaths.insert(library.libraryPath) } } - case let target as ProvidedLibraryModule: - swiftTarget.additionalFlags += [ - "-I", target.path.pathString - ] default: break } diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift index d49842fdfea..fd3a18c5277 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -455,7 +455,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { toolsVersion: toolsVersion, fileSystem: fileSystem )) - case is SystemLibraryModule, is BinaryModule, is ProvidedLibraryModule: + case is SystemLibraryModule, is BinaryModule: break default: throw InternalError("unhandled \(target.underlying)") diff --git a/Sources/Commands/PackageCommands/EditCommands.swift b/Sources/Commands/PackageCommands/EditCommands.swift index ff199a05101..42195f7037d 100644 --- a/Sources/Commands/PackageCommands/EditCommands.swift +++ b/Sources/Commands/PackageCommands/EditCommands.swift @@ -72,6 +72,7 @@ extension SwiftPackageCommand { packageName: packageName, forceRemove: shouldForceRemove, root: swiftCommandState.getWorkspaceRoot(), + availableLibraries: swiftCommandState.getHostToolchain().providedLibraries, observabilityScope: swiftCommandState.observabilityScope ) } diff --git a/Sources/Commands/PackageCommands/Update.swift b/Sources/Commands/PackageCommands/Update.swift index 90622a8ccdb..50a325ab660 100644 --- a/Sources/Commands/PackageCommands/Update.swift +++ b/Sources/Commands/PackageCommands/Update.swift @@ -71,7 +71,7 @@ extension SwiftPackageCommand { case .removed: report += "\n" report += "- \(package.identity) \(currentVersion)" - case .unchanged, .usesLibrary: + case .unchanged: continue } } diff --git a/Sources/Commands/Snippets/Cards/TopCard.swift b/Sources/Commands/Snippets/Cards/TopCard.swift index 40f60c54118..d85a4a0f905 100644 --- a/Sources/Commands/Snippets/Cards/TopCard.swift +++ b/Sources/Commands/Snippets/Cards/TopCard.swift @@ -151,8 +151,6 @@ fileprivate extension Module.Kind { return "snippets" case .macro: return "macros" - case .providedLibrary: - return "provided libraries" } } } diff --git a/Sources/PackageGraph/BoundVersion.swift b/Sources/PackageGraph/BoundVersion.swift index 459dee7f956..7aa90a33ff6 100644 --- a/Sources/PackageGraph/BoundVersion.swift +++ b/Sources/PackageGraph/BoundVersion.swift @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// -import struct PackageModel.ProvidedLibrary import struct TSCUtility.Version /// A bound version for a package within an assignment. @@ -23,7 +22,7 @@ public enum BoundVersion: Equatable, Hashable { case excluded /// The version of the package to include. - case version(Version, library: ProvidedLibrary? = nil) + case version(Version) /// The package assignment is unversioned. case unversioned @@ -37,7 +36,7 @@ extension BoundVersion: CustomStringConvertible { switch self { case .excluded: return "excluded" - case .version(let version, _): + case .version(let version): return version.description case .unversioned: return "unversioned" diff --git a/Sources/PackageGraph/ModulesGraph+Loading.swift b/Sources/PackageGraph/ModulesGraph+Loading.swift index 15019bfb904..de5c11a18dc 100644 --- a/Sources/PackageGraph/ModulesGraph+Loading.swift +++ b/Sources/PackageGraph/ModulesGraph+Loading.swift @@ -34,6 +34,7 @@ extension ModulesGraph { customPlatformsRegistry: PlatformRegistry? = .none, customXCTestMinimumDeploymentTargets: [PackageModel.Platform: PlatformVersion]? = .none, testEntryPointPath: AbsolutePath? = nil, + availableLibraries: [LibraryMetadata], fileSystem: FileSystem, observabilityScope: ObservabilityScope, productsFilter: ((Product) -> Bool)? = nil, @@ -248,6 +249,7 @@ extension ModulesGraph { unsafeAllowedPackages: unsafeAllowedPackages, platformRegistry: customPlatformsRegistry ?? .default, platformVersionProvider: platformVersionProvider, + availableLibraries: [], fileSystem: fileSystem, observabilityScope: observabilityScope, productsFilter: productsFilter, @@ -379,6 +381,7 @@ private func createResolvedPackages( unsafeAllowedPackages: Set, platformRegistry: PlatformRegistry, platformVersionProvider: PlatformVersionProvider, + availableLibraries: [LibraryMetadata], fileSystem: FileSystem, observabilityScope: ObservabilityScope, productsFilter: ((Product) -> Bool)?, @@ -681,26 +684,32 @@ private func createResolvedPackages( t.name != productRef.name } - // Find a product name from the available product dependencies that is most similar to the required product name. - let bestMatchedProductName = bestMatch(for: productRef.name, from: Array(allModuleNames)) - var packageContainingBestMatchedProduct: String? - if let bestMatchedProductName, productRef.name == bestMatchedProductName { - let dependentPackages = packageBuilder.dependencies.map(\.package) - for p in dependentPackages where p.modules.contains(where: { $0.name == bestMatchedProductName }) { - packageContainingBestMatchedProduct = p.identity.description - break + let identitiesAvailableInSDK = availableLibraries.flatMap { $0.identities.map { $0.identity } } + // TODO: Do we have to care about "name" vs. identity here? + if let name = productRef.package, identitiesAvailableInSDK.contains(PackageIdentity.plain(name)) { + // Do not emit any diagnostic. + } else { + // Find a product name from the available product dependencies that is most similar to the required product name. + let bestMatchedProductName = bestMatch(for: productRef.name, from: Array(allModuleNames)) + var packageContainingBestMatchedProduct: String? + if let bestMatchedProductName, productRef.name == bestMatchedProductName { + let dependentPackages = packageBuilder.dependencies.map(\.package) + for p in dependentPackages where p.modules.contains(where: { $0.name == bestMatchedProductName }) { + packageContainingBestMatchedProduct = p.identity.description + break + } } + let error = PackageGraphError.productDependencyNotFound( + package: package.identity.description, + moduleName: moduleBuilder.module.name, + dependencyProductName: productRef.name, + dependencyPackageName: productRef.package, + dependencyProductInDecl: !declProductsAsDependency.isEmpty, + similarProductName: bestMatchedProductName, + packageContainingSimilarProduct: packageContainingBestMatchedProduct + ) + packageObservabilityScope.emit(error) } - let error = PackageGraphError.productDependencyNotFound( - package: package.identity.description, - moduleName: moduleBuilder.module.name, - dependencyProductName: productRef.name, - dependencyPackageName: productRef.package, - dependencyProductInDecl: !declProductsAsDependency.isEmpty, - similarProductName: bestMatchedProductName, - packageContainingSimilarProduct: packageContainingBestMatchedProduct - ) - packageObservabilityScope.emit(error) } continue } diff --git a/Sources/PackageGraph/ModulesGraph.swift b/Sources/PackageGraph/ModulesGraph.swift index 7b12624a2fe..5237de38b2d 100644 --- a/Sources/PackageGraph/ModulesGraph.swift +++ b/Sources/PackageGraph/ModulesGraph.swift @@ -553,6 +553,7 @@ public func loadModulesGraph( shouldCreateMultipleTestProducts: shouldCreateMultipleTestProducts, createREPLProduct: createREPLProduct, customXCTestMinimumDeploymentTargets: customXCTestMinimumDeploymentTargets, + availableLibraries: [], fileSystem: fileSystem, observabilityScope: observabilityScope, productsFilter: nil, diff --git a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift index c20021d3642..d73e41ffdf9 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift @@ -97,7 +97,6 @@ final class ContainerProvider { ) { result in let result = result.tryMap { container -> PubGrubPackageContainer in let pubGrubContainer = PubGrubPackageContainer(underlying: container, pins: self.pins) - // only cache positive results self.containersCache[package] = pubGrubContainer return pubGrubContainer @@ -108,9 +107,12 @@ final class ContainerProvider { } /// Starts prefetching the given containers. - func prefetch(containers identifiers: [PackageReference]) { + func prefetch(containers identifiers: [PackageReference], availableLibraries: [LibraryMetadata]) { + let filteredIdentifiers = identifiers.filter { + $0.matchingPrebuiltLibrary(in: availableLibraries) == nil + } // Process each container. - for identifier in identifiers { + for identifier in filteredIdentifiers { var needsFetching = false self.prefetches.memoize(identifier) { let group = DispatchGroup() diff --git a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift index 37bfea4d8a9..a6379fd3b6c 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift @@ -105,7 +105,7 @@ public struct PubGrubDependencyResolver { private let pins: PinsStore.Pins /// The packages that are available in a prebuilt form in SDK or a toolchain - private let availableLibraries: [ProvidedLibrary] + private let availableLibraries: [LibraryMetadata] /// The container provider used to load package containers. private let provider: ContainerProvider @@ -125,7 +125,7 @@ public struct PubGrubDependencyResolver { public init( provider: PackageContainerProvider, pins: PinsStore.Pins = [:], - availableLibraries: [ProvidedLibrary] = [], + availableLibraries: [LibraryMetadata] = [], skipDependenciesUpdates: Bool = false, prefetchBasedOnResolvedFile: Bool = false, observabilityScope: ObservabilityScope, @@ -203,7 +203,7 @@ public struct PubGrubDependencyResolver { let pins = self.pins.values .map(\.packageRef) .filter { !inputs.overriddenPackages.keys.contains($0) } - self.provider.prefetch(containers: pins) + self.provider.prefetch(containers: pins, availableLibraries: self.availableLibraries) } let state = State(root: root, overriddenPackages: inputs.overriddenPackages) @@ -236,27 +236,28 @@ public struct PubGrubDependencyResolver { let boundVersion: BoundVersion switch assignment.term.requirement { case .exact(let version): - if let library = package.matchingPrebuiltLibrary(in: availableLibraries), - version == library.version - { - boundVersion = .version(version, library: library) - } else { - boundVersion = .version(version) - } + boundVersion = .version(version) case .range, .any, .empty, .ranges: throw InternalError("unexpected requirement value for assignment \(assignment.term)") } + // Strip packages that have prebuilt libraries only if they match library version. + // + // FIXME: This is built on assumption that libraries are part of the SDK and are + // always available in include/library paths, but what happens if they are + // part of a toolchain instead? Builder needs an indicator that certain path + // has to be included when building packages that depend on prebuilt libraries. + if let library = package.matchingPrebuiltLibrary(in: availableLibraries), + boundVersion == .version(.init(stringLiteral: library.version)) + { + continue + } + let products = assignment.term.node.productFilter - let updatePackage: PackageReference - 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) - } + // 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: boundVersion) if var existing = flattenedAssignments[updatePackage] { guard existing.binding == boundVersion else { @@ -497,9 +498,8 @@ public struct PubGrubDependencyResolver { // initiate prefetch of known packages that will be used to make the decision on the next step self.provider.prefetch( - containers: state.solution.undecided.map(\.node.package).filter { - $0.matchingPrebuiltLibrary(in: self.availableLibraries) == nil - } + containers: state.solution.undecided.map(\.node.package), + availableLibraries: self.availableLibraries ) // If decision making determines that no more decisions are to be @@ -745,13 +745,11 @@ public struct PubGrubDependencyResolver { continue } - if pkgTerm.requirement.contains(library.version) { - self.delegate?.didResolve( - term: pkgTerm, - version: library.version, - duration: start.distance(to: .now()) - ) - state.decide(pkgTerm.node, at: library.version) + let version = Version(stringLiteral: library.version) + + if pkgTerm.requirement.contains(version) { + self.delegate?.didResolve(term: pkgTerm, version: version, duration: start.distance(to: .now())) + state.decide(pkgTerm.node, at: version) return completion(.success(pkgTerm.node)) } } @@ -897,14 +895,14 @@ extension PackageRequirement { } extension PackageReference { - public func matchingPrebuiltLibrary(in availableLibraries: [ProvidedLibrary]) -> ProvidedLibrary? { + public func matchingPrebuiltLibrary(in availableLibraries: [LibraryMetadata]) -> LibraryMetadata? { switch self.kind { case .fileSystem, .localSourceControl, .root: - nil // can never match a prebuilt library + return nil // can never match a prebuilt library case .registry(let identity): if let registryIdentity = identity.registry { - availableLibraries.first( - where: { $0.metadata.identities.contains( + return availableLibraries.first( + where: { $0.identities.contains( where: { $0 == .packageIdentity( scope: registryIdentity.scope.description, name: registryIdentity.name.description @@ -914,11 +912,11 @@ extension PackageReference { } ) } else { - nil + return nil } case .remoteSourceControl(let url): - availableLibraries.first(where: { - $0.metadata.identities.contains(where: { $0 == .sourceControl(url: url) }) + return availableLibraries.first(where: { + $0.identities.contains(where: { $0 == .sourceControl(url: url) }) }) } } diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index 5607c6a993f..b563c89224f 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -557,16 +557,6 @@ public final class PackageBuilder { throw ModuleError.artifactNotFound(moduleName: target.name, expectedArtifactName: target.name) } return artifact.path - } else if let targetPath = target.path, target.type == .providedLibrary { - guard let path = try? AbsolutePath(validating: targetPath) else { - throw ModuleError.invalidCustomPath(moduleName: target.name, path: targetPath) - } - - if !self.fileSystem.isDirectory(path) { - throw ModuleError.unsupportedTargetPath(targetPath) - } - - return path } else if let subpath = target.path { // If there is a custom path defined, use that. if subpath == "" || subpath == "." { return self.packagePath @@ -880,11 +870,6 @@ public final class PackageBuilder { path: potentialModule.path, origin: artifactOrigin ) - } else if potentialModule.type == .providedLibrary { - return ProvidedLibraryModule( - name: potentialModule.name, - path: potentialModule.path - ) } // Check for duplicate target dependencies diff --git a/Sources/PackageModel/CMakeLists.txt b/Sources/PackageModel/CMakeLists.txt index 98d57705a08..7f9198f5ddc 100644 --- a/Sources/PackageModel/CMakeLists.txt +++ b/Sources/PackageModel/CMakeLists.txt @@ -31,7 +31,6 @@ add_library(PackageModel Module/BinaryModule.swift Module/ClangModule.swift Module/PluginModule.swift - Module/ProvidedLibraryModule.swift Module/SwiftModule.swift Module/SystemLibraryModule.swift Module/Module.swift diff --git a/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift b/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift index 858c1a8f837..a0c96815c92 100644 --- a/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift +++ b/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift @@ -11,19 +11,10 @@ //===----------------------------------------------------------------------===// import Basics -import struct TSCUtility.Version +import Foundation -public struct ProvidedLibrary: Hashable { - public let location: AbsolutePath - public let metadata: LibraryMetadata - - public var version: Version { - .init(stringLiteral: metadata.version) - } -} - -public struct LibraryMetadata: Hashable, Decodable { - public enum Identity: Hashable, Decodable { +public struct LibraryMetadata: Decodable { + public enum Identity: Equatable, Decodable { case packageIdentity(scope: String, name: String) case sourceControl(url: SourceControlURL) } @@ -33,7 +24,7 @@ public struct LibraryMetadata: Hashable, Decodable { /// The version that was built (e.g., 509.0.2) public let version: String /// The product name, if it differs from the module name (e.g., SwiftParser). - public let productName: String + public let productName: String? let schemaVersion: Int } diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index 703688c7799..ab1acdc886f 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -560,51 +560,3 @@ extension Manifest: Encodable { try container.encode(self.packageKind, forKey: .packageKind) } } - -extension Manifest { - package static func forProvidedLibrary( - fileSystem: FileSystem, - package: PackageReference, - libraryPath: AbsolutePath, - version: Version - ) throws -> Manifest { - let names = try fileSystem.getDirectoryContents(libraryPath).filter { - $0.hasSuffix("swiftmodule") - }.map { - let components = $0.split(separator: ".") - return String(components[0]) - } - - let products: [ProductDescription] = try names.map { - try .init(name: $0, type: .library(.automatic), targets: [$0]) - } - - let targets: [TargetDescription] = try names.map { - try .init( - name: $0, - path: libraryPath.pathString, - type: .providedLibrary - ) - } - - return .init( - displayName: package.identity.description, - path: libraryPath.appending(component: "provided-library.json"), - packageKind: package.kind, - packageLocation: package.locationString, - defaultLocalization: nil, - platforms: [], - version: version, - revision: nil, - toolsVersion: .v6_0, - pkgConfig: nil, - providers: nil, - cLanguageStandard: nil, - cxxLanguageStandard: nil, - swiftLanguageVersions: nil, - products: products, - targets: targets, - traits: [] - ) - } -} diff --git a/Sources/PackageModel/Manifest/TargetDescription.swift b/Sources/PackageModel/Manifest/TargetDescription.swift index d2f1d7b1c97..2760b470e62 100644 --- a/Sources/PackageModel/Manifest/TargetDescription.swift +++ b/Sources/PackageModel/Manifest/TargetDescription.swift @@ -24,7 +24,6 @@ public struct TargetDescription: Hashable, Encodable, Sendable { case binary case plugin case `macro` - case providedLibrary } /// Represents a target's dependency on another entity. @@ -237,19 +236,6 @@ public struct TargetDescription: Hashable, Encodable, Sendable { if pkgConfig != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pkgConfig") } if providers != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "providers") } if pluginCapability != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pluginCapability") } - case .providedLibrary: - if path == nil { throw Error.providedLibraryTargetRequiresPath(targetName: name) } - if url != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "url") } - if !dependencies.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "dependencies") } - if !exclude.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "exclude") } - if sources != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "sources") } - if !resources.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "resources") } - if publicHeadersPath != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "publicHeadersPath") } - if pkgConfig != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pkgConfig") } - if providers != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "providers") } - if pluginCapability != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pluginCapability") } - if !settings.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "settings") } - if pluginUsages != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pluginUsages") } } self.name = name @@ -398,16 +384,13 @@ import protocol Foundation.LocalizedError private enum Error: LocalizedError, Equatable { case binaryTargetRequiresEitherPathOrURL(targetName: String) case disallowedPropertyInTarget(targetName: String, propertyName: String) - case providedLibraryTargetRequiresPath(targetName: String) - + var errorDescription: String? { switch self { case .binaryTargetRequiresEitherPathOrURL(let targetName): return "binary target '\(targetName)' neither defines neither path nor URL for its artifacts" case .disallowedPropertyInTarget(let targetName, let propertyName): return "target '\(targetName)' contains a value for disallowed property '\(propertyName)'" - case .providedLibraryTargetRequiresPath(let targetName): - return "provided library target '\(targetName)' does not define a path to the library" } } } diff --git a/Sources/PackageModel/ManifestSourceGeneration.swift b/Sources/PackageModel/ManifestSourceGeneration.swift index 4957a27b5c6..9fdfc82492d 100644 --- a/Sources/PackageModel/ManifestSourceGeneration.swift +++ b/Sources/PackageModel/ManifestSourceGeneration.swift @@ -317,8 +317,6 @@ fileprivate extension SourceCodeFragment { self.init(enum: "plugin", subnodes: params, multiline: true) case .macro: self.init(enum: "macro", subnodes: params, multiline: true) - case .providedLibrary: - self.init(enum: "providedLibrary", subnodes: params, multiline: true) } } diff --git a/Sources/PackageModel/Module/Module.swift b/Sources/PackageModel/Module/Module.swift index a90436865bc..023033344f2 100644 --- a/Sources/PackageModel/Module/Module.swift +++ b/Sources/PackageModel/Module/Module.swift @@ -28,7 +28,6 @@ public class Module { case plugin case snippet case `macro` - case providedLibrary } /// A group a module belongs to that allows customizing access boundaries. A module is treated as diff --git a/Sources/PackageModel/Module/ProvidedLibraryModule.swift b/Sources/PackageModel/Module/ProvidedLibraryModule.swift deleted file mode 100644 index 34d80f43fba..00000000000 --- a/Sources/PackageModel/Module/ProvidedLibraryModule.swift +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift 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 the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import struct Basics.AbsolutePath - -@available(*, deprecated, renamed: "ProvidedLibraryModule") -public typealias ProvidedLibraryTarget = ProvidedLibraryModule - -/// Represents a library module that comes from a toolchain in prebuilt form. -public final class ProvidedLibraryModule: Module { - public init( - name: String, - path: AbsolutePath - ) { - let sources = Sources(paths: [], root: path) - super.init( - name: name, - type: .providedLibrary, - path: sources.root, - sources: sources, - dependencies: [], - packageAccess: false, - buildSettings: .init(), - buildSettingsDescription: [], - pluginUsages: [], - usesUnsafeFlags: false - ) - } -} diff --git a/Sources/PackageModel/PackageReference.swift b/Sources/PackageModel/PackageReference.swift index d4cec83d3ac..ff6b448101c 100644 --- a/Sources/PackageModel/PackageReference.swift +++ b/Sources/PackageModel/PackageReference.swift @@ -203,7 +203,7 @@ extension PackageReference: CustomStringConvertible { extension PackageReference.Kind: Encodable { private enum CodingKeys: String, CodingKey { - case root, fileSystem, localSourceControl, remoteSourceControl, registry, providedLibrary + case root, fileSystem, localSourceControl, remoteSourceControl, registry } public func encode(to encoder: Encoder) throws { diff --git a/Sources/PackageModel/Toolchain.swift b/Sources/PackageModel/Toolchain.swift index 7f8c6171397..96bc353db65 100644 --- a/Sources/PackageModel/Toolchain.swift +++ b/Sources/PackageModel/Toolchain.swift @@ -38,7 +38,7 @@ public protocol Toolchain { var installedSwiftPMConfiguration: InstalledSwiftPMConfiguration { get } /// Metadata for libraries provided by the used toolchain. - var providedLibraries: [ProvidedLibrary] { get } + var providedLibraries: [LibraryMetadata] { get } /// The root path to the Swift SDK used by this toolchain. var sdkRootPath: AbsolutePath? { get } diff --git a/Sources/PackageModel/UserToolchain.swift b/Sources/PackageModel/UserToolchain.swift index acb18db35df..b1f0a79aec2 100644 --- a/Sources/PackageModel/UserToolchain.swift +++ b/Sources/PackageModel/UserToolchain.swift @@ -88,7 +88,7 @@ public final class UserToolchain: Toolchain { public let installedSwiftPMConfiguration: InstalledSwiftPMConfiguration - public let providedLibraries: [ProvidedLibrary] + public let providedLibraries: [LibraryMetadata] /// Returns the runtime library for the given sanitizer. public func runtimeLibrary(for sanitizer: Sanitizer) throws -> AbsolutePath { @@ -546,7 +546,7 @@ public final class UserToolchain: Toolchain { searchStrategy: SearchStrategy = .default, customLibrariesLocation: ToolchainConfiguration.SwiftPMLibrariesLocation? = nil, customInstalledSwiftPMConfiguration: InstalledSwiftPMConfiguration? = nil, - customProvidedLibraries: [ProvidedLibrary]? = nil, + customProvidedLibraries: [LibraryMetadata]? = nil, fileSystem: any FileSystem = localFileSystem ) throws { self.swiftSDK = swiftSDK @@ -596,15 +596,7 @@ public final class UserToolchain: Toolchain { self.providedLibraries = try Self.loadJSONResource( config: path, type: [LibraryMetadata].self, - default: [] - ).map { - .init( - location: path.parentDirectory.appending(component: $0.productName), - metadata: $0 - ) - }.filter { - localFileSystem.isDirectory($0.location) - } + default: []) } // Use the triple from Swift SDK or compute the host triple using swiftc. diff --git a/Sources/PackageModelSyntax/AddTarget.swift b/Sources/PackageModelSyntax/AddTarget.swift index 4f9ce3013c4..5f51112e946 100644 --- a/Sources/PackageModelSyntax/AddTarget.swift +++ b/Sources/PackageModelSyntax/AddTarget.swift @@ -100,7 +100,7 @@ public struct AddTarget { ) let outerDirectory: String? = switch target.type { - case .binary, .plugin, .system, .providedLibrary: nil + case .binary, .plugin, .system: nil case .executable, .regular, .macro: "Sources" case .test: "Tests" } @@ -228,7 +228,7 @@ public struct AddTarget { } let sourceFileText: SourceFileSyntax = switch target.type { - case .binary, .plugin, .system, .providedLibrary: + case .binary, .plugin, .system: fatalError("should have exited above") case .macro: diff --git a/Sources/PackageModelSyntax/TargetDescription+Syntax.swift b/Sources/PackageModelSyntax/TargetDescription+Syntax.swift index 5081932bed8..f47f6590f06 100644 --- a/Sources/PackageModelSyntax/TargetDescription+Syntax.swift +++ b/Sources/PackageModelSyntax/TargetDescription+Syntax.swift @@ -27,7 +27,6 @@ extension TargetDescription: ManifestSyntaxRepresentable { case .regular: "target" case .system: "systemLibrary" case .test: "testTarget" - case .providedLibrary: "providedLibrary" } } diff --git a/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift b/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift index 730cbff15da..2f1dafe6268 100644 --- a/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift +++ b/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift @@ -281,7 +281,7 @@ fileprivate extension WireInput.Target.TargetInfo.SourceModuleKind { self = .test case .macro: self = .macro - case .binary, .plugin, .systemModule, .providedLibrary: + case .binary, .plugin, .systemModule: throw StringError("unexpected target kind \(kind) for source module") } } diff --git a/Sources/Workspace/ManagedDependency.swift b/Sources/Workspace/ManagedDependency.swift index 5f2fd75cfc5..b771f37221c 100644 --- a/Sources/Workspace/ManagedDependency.swift +++ b/Sources/Workspace/ManagedDependency.swift @@ -34,9 +34,6 @@ extension Workspace { /// The dependency is downloaded from a registry. case registryDownload(version: Version) - /// The dependency is part of the toolchain in a binary form. - case providedLibrary(at: AbsolutePath, version: Version) - /// The dependency is in edited state. /// /// If the path is non-nil, the dependency is managed by a user and is @@ -54,8 +51,6 @@ extension Workspace { return "sourceControlCheckout (\(checkoutState))" case .registryDownload(let version): return "registryDownload (\(version))" - case .providedLibrary(let path, let version): - return "library (\(path) @ \(version)" case .edited: return "edited" case .custom: @@ -151,17 +146,6 @@ extension Workspace { ) } - public static func providedLibrary( - packageRef: PackageReference, - library: ProvidedLibrary - ) throws -> ManagedDependency { - ManagedDependency( - packageRef: packageRef, - state: .providedLibrary(at: library.location, version: library.version), - subpath: try RelativePath(validating: packageRef.identity.description) - ) - } - /// Create an edited dependency public static func edited( packageRef: PackageReference, diff --git a/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift b/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift index 03f48dd0120..6e634df9fd4 100644 --- a/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift +++ b/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift @@ -354,7 +354,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri let revision: Revision var version: Version? switch boundVersion { - case .version(let v, _): + case .version(let v): guard let tag = try self.knownVersions()[v] else { throw StringError("unknown tag \(v)") } diff --git a/Sources/Workspace/Workspace+Dependencies.swift b/Sources/Workspace/Workspace+Dependencies.swift index 2e99b7d2107..5ece297dc4a 100644 --- a/Sources/Workspace/Workspace+Dependencies.swift +++ b/Sources/Workspace/Workspace+Dependencies.swift @@ -37,7 +37,7 @@ import class PackageGraph.PinsStore import struct PackageGraph.PubGrubDependencyResolver import struct PackageGraph.Term import class PackageLoading.ManifestLoader -import struct PackageModel.ProvidedLibrary +import struct PackageModel.LibraryMetadata import enum PackageModel.PackageDependency import struct PackageModel.PackageIdentity import struct PackageModel.PackageReference @@ -57,6 +57,7 @@ extension Workspace { root: PackageGraphRootInput, packages: [String] = [], dryRun: Bool = false, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> [(PackageReference, Workspace.PackageStateChange)]? { let start = DispatchTime.now() @@ -87,6 +88,7 @@ extension Workspace { ) let currentManifests = try self.loadDependencyManifests( root: graphRoot, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -121,6 +123,7 @@ extension Workspace { // Resolve the dependencies. let resolver = try self.createResolver( pins: pins, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) self.activeResolver = resolver @@ -163,6 +166,7 @@ extension Workspace { // Load the updated manifests. let updatedDependencyManifests = try self.loadDependencyManifests( root: graphRoot, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) // If we have missing packages, something is fundamentally wrong with the resolution of the graph @@ -196,6 +200,7 @@ extension Workspace { func _resolve( root: PackageGraphRootInput, explicitProduct: String?, + availableLibraries: [LibraryMetadata], resolvedFileStrategy: ResolvedFileStrategy, observabilityScope: ObservabilityScope ) throws -> DependencyManifests { @@ -211,6 +216,7 @@ extension Workspace { return try self._resolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) case .update(let forceResolution): @@ -247,6 +253,7 @@ extension Workspace { let (manifests, precomputationResult) = try self.tryResolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) switch precomputationResult { @@ -270,6 +277,7 @@ extension Workspace { return try self.resolveAndUpdateResolvedFile( root: root, explicitProduct: explicitProduct, + availableLibraries: availableLibraries, forceResolution: forceResolution, constraints: [], observabilityScope: observabilityScope @@ -296,11 +304,13 @@ extension Workspace { func _resolveBasedOnResolvedVersionsFile( root: PackageGraphRootInput, explicitProduct: String?, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> DependencyManifests { let (manifests, precomputationResult) = try self.tryResolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) switch precomputationResult { @@ -333,6 +343,7 @@ extension Workspace { fileprivate func tryResolveBasedOnResolvedVersionsFile( root: PackageGraphRootInput, explicitProduct: String?, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> (DependencyManifests, ResolutionPrecomputationResult) { // Ensure the cache path exists. @@ -359,6 +370,7 @@ extension Workspace { return try ( self.loadDependencyManifests( root: graphRoot, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ), .notRequired @@ -371,20 +383,6 @@ extension Workspace { // automatically manage the parallelism. let group = DispatchGroup() for pin in pinsStore.pins.values { - // Provided library doesn't have a container, we need to inject a special depedency. - if let library = pin.packageRef.matchingPrebuiltLibrary(in: self.providedLibraries), - case .version(library.version, _) = pin.state - { - try self.state.dependencies.add( - .providedLibrary( - packageRef: pin.packageRef, - library: library - ) - ) - try self.state.save() - continue - } - group.enter() let observabilityScope = observabilityScope.makeChildScope( description: "requesting package containers", @@ -432,8 +430,6 @@ extension Workspace { return !pin.state.equals(checkoutState) case .registryDownload(let version): return !pin.state.equals(version) - case .providedLibrary: - return false case .edited, .fileSystem, .custom: return true } @@ -467,6 +463,7 @@ extension Workspace { let currentManifests = try self.loadDependencyManifests( root: graphRoot, automaticallyAddManagedDependencies: true, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -481,6 +478,7 @@ extension Workspace { dependencyManifests: currentManifests, pinsStore: pinsStore, constraints: [], + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -497,6 +495,7 @@ extension Workspace { func resolveAndUpdateResolvedFile( root: PackageGraphRootInput, explicitProduct: String? = nil, + availableLibraries: [LibraryMetadata], forceResolution: Bool, constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope @@ -524,6 +523,7 @@ extension Workspace { ) let currentManifests = try self.loadDependencyManifests( root: graphRoot, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) guard !observabilityScope.errorsReported else { @@ -560,6 +560,7 @@ extension Workspace { dependencyManifests: currentManifests, pinsStore: pinsStore, constraints: constraints, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -595,6 +596,7 @@ extension Workspace { // Perform dependency resolution. let resolver = try self.createResolver( pins: pinsStore.pins, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) self.activeResolver = resolver @@ -625,6 +627,7 @@ extension Workspace { // Update the pinsStore. let updatedDependencyManifests = try self.loadDependencyManifests( root: graphRoot, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) // If we still have missing packages, something is fundamentally wrong with the resolution of the graph @@ -687,7 +690,7 @@ extension Workspace { metadata: packageRef.diagnosticsMetadata ).trap { switch state { - case .added, .updated, .unchanged, .usesLibrary: + case .added, .updated, .unchanged: break case .removed: try self.remove(package: packageRef) @@ -716,27 +719,12 @@ extension Workspace { productFilter: state.products, observabilityScope: observabilityScope ) - case .removed, .unchanged, .usesLibrary: + case .removed, .unchanged: break } } } - // Handle provided libraries - for (packageRef, state) in packageStateChanges { - observabilityScope.makeChildScope( - description: "adding provided libraries", - metadata: packageRef.diagnosticsMetadata - ).trap { - if case .usesLibrary(let library) = state { - try self.state.dependencies.add( - .providedLibrary(packageRef: packageRef, library: library) - ) - try self.state.save() - } - } - } - // Inform the delegate if nothing was updated. if packageStateChanges.filter({ $0.1 == .unchanged }).count == packageStateChanges.count { delegate?.dependenciesUpToDate() @@ -848,6 +836,7 @@ extension Workspace { dependencyManifests: DependencyManifests, pinsStore: PinsStore, constraints: [PackageContainerConstraint], + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> ResolutionPrecomputationResult { let computedConstraints = @@ -864,7 +853,7 @@ extension Workspace { let resolver = PubGrubDependencyResolver( provider: precomputationProvider, pins: pinsStore.pins, - availableLibraries: self.providedLibraries, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) let result = resolver.solve(constraints: computedConstraints) @@ -977,9 +966,6 @@ extension Workspace { /// The package is updated. case updated(State) - /// The package is replaced with a prebuilt library - case usesLibrary(ProvidedLibrary) - public var description: String { switch self { case .added(let requirement): @@ -990,17 +976,15 @@ extension Workspace { return "unchanged" case .updated(let requirement): return "updated(\(requirement))" - case .usesLibrary(let library): - return "usesLibrary(\(library.metadata.productName))" } } public var isAddedOrUpdated: Bool { switch self { case .added, .updated: - true - case .unchanged, .removed, .usesLibrary: - false + return true + case .unchanged, .removed: + return false } } } @@ -1049,8 +1033,6 @@ extension Workspace { packageStateChanges[binding.package.identity] = (binding.package, .updated(newState)) case .registryDownload: throw InternalError("Unexpected unversioned binding for downloaded dependency") - case .providedLibrary: - throw InternalError("Unexpected unversioned binding for library dependency") case .custom: throw InternalError("Unexpected unversioned binding for custom dependency") } @@ -1118,20 +1100,15 @@ extension Workspace { packageStateChanges[binding.package.identity] = (binding.package, .added(newState)) } - case .version(let version, let library): - let stateChange: PackageStateChange = switch currentDependency?.state { - case .sourceControlCheckout(.version(version, _)), - .registryDownload(version), - .providedLibrary(_, version: version), - .custom(version, _): - library.flatMap { .usesLibrary($0) } ?? .unchanged - case .edited, .fileSystem, .sourceControlCheckout, .registryDownload, .providedLibrary, .custom: - .updated(.init(requirement: .version(version), products: binding.products)) + case .version(let version): + let stateChange: PackageStateChange + switch currentDependency?.state { + case .sourceControlCheckout(.version(version, _)), .registryDownload(version), .custom(version, _): + stateChange = .unchanged + case .edited, .fileSystem, .sourceControlCheckout, .registryDownload, .custom: + stateChange = .updated(.init(requirement: .version(version), products: binding.products)) case nil: - library.flatMap { .usesLibrary($0) } ?? .added(.init( - requirement: .version(version), - products: binding.products - )) + stateChange = .added(.init(requirement: .version(version), products: binding.products)) } packageStateChanges[binding.package.identity] = (binding.package, stateChange) } @@ -1149,6 +1126,7 @@ extension Workspace { /// Creates resolver for the workspace. fileprivate func createResolver( pins: PinsStore.Pins, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> PubGrubDependencyResolver { var delegate: DependencyResolverDelegate @@ -1165,7 +1143,7 @@ extension Workspace { return PubGrubDependencyResolver( provider: packageContainerProvider, pins: pins, - availableLibraries: self.providedLibraries, + availableLibraries: availableLibraries, skipDependenciesUpdates: self.configuration.skipDependenciesUpdates, prefetchBasedOnResolvedFile: self.configuration.prefetchBasedOnResolvedFile, observabilityScope: observabilityScope, diff --git a/Sources/Workspace/Workspace+Editing.swift b/Sources/Workspace/Workspace+Editing.swift index c2220479695..a58d641befd 100644 --- a/Sources/Workspace/Workspace+Editing.swift +++ b/Sources/Workspace/Workspace+Editing.swift @@ -16,7 +16,7 @@ import class Basics.ObservabilityScope import struct Basics.RelativePath import func Basics.temp_await import struct PackageGraph.PackageGraphRootInput -import struct PackageModel.ProvidedLibrary +import struct PackageModel.LibraryMetadata import struct SourceControl.Revision extension Workspace { @@ -52,9 +52,6 @@ extension Workspace { case .registryDownload: observabilityScope.emit(error: "registry dependency '\(dependency.packageRef.identity)' can't be edited") return - case .providedLibrary: - observabilityScope.emit(error: "library dependency '\(dependency.packageRef.identity)' can't be edited") - return case .custom: observabilityScope.emit(error: "custom dependency '\(dependency.packageRef.identity)' can't be edited") return @@ -173,6 +170,7 @@ extension Workspace { dependency: ManagedDependency, forceRemove: Bool, root: PackageGraphRootInput? = nil, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws { // Compute if we need to force remove. @@ -237,6 +235,7 @@ extension Workspace { try self._resolve( root: root, explicitProduct: .none, + availableLibraries: availableLibraries, resolvedFileStrategy: .update(forceResolution: false), observabilityScope: observabilityScope ) diff --git a/Sources/Workspace/Workspace+Manifests.swift b/Sources/Workspace/Workspace+Manifests.swift index b1fde04a014..97994d61b3e 100644 --- a/Sources/Workspace/Workspace+Manifests.swift +++ b/Sources/Workspace/Workspace+Manifests.swift @@ -29,7 +29,7 @@ import struct PackageGraph.PackageGraphRoot import class PackageLoading.ManifestLoader import struct PackageLoading.ManifestValidator import struct PackageLoading.ToolsVersionParser -import struct PackageModel.ProvidedLibrary +import struct PackageModel.LibraryMetadata import class PackageModel.Manifest import struct PackageModel.PackageIdentity import struct PackageModel.PackageReference @@ -62,6 +62,8 @@ extension Workspace { private let workspace: Workspace + private let availableLibraries: [LibraryMetadata] + private let observabilityScope: ObservabilityScope private let _dependencies: LoadableResult<( @@ -80,17 +82,20 @@ extension Workspace { fileSystem: FileSystem )], workspace: Workspace, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) { self.root = root self.dependencies = dependencies self.workspace = workspace + self.availableLibraries = availableLibraries self.observabilityScope = observabilityScope self._dependencies = LoadableResult { try Self.computeDependencies( root: root, dependencies: dependencies, workspace: workspace, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -147,7 +152,7 @@ extension Workspace { result.insert(packageRef) } - case .registryDownload, .edited, .providedLibrary, .custom: + case .registryDownload, .edited, .custom: continue case .fileSystem: result.insert(dependency.packageRef) @@ -169,6 +174,7 @@ extension Workspace { fileSystem: FileSystem )], workspace: Workspace, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> ( @@ -199,6 +205,17 @@ extension Workspace { return PackageReference(identity: $0.key, kind: $0.1.packageKind) }) + let identitiesAvailableInSDK = availableLibraries.flatMap { + $0.identities.map { + $0.ref + }.filter { + // We "trust the process" here, if an identity from the SDK is available, filter it. + !availableIdentities.contains($0) + }.map { + $0.identity + } + } + var inputIdentities: OrderedCollections.OrderedSet = [] let inputNodes: [GraphLoadingNode] = try root.packages.map { identity, package in inputIdentities.append(package.reference) @@ -282,6 +299,11 @@ extension Workspace { } requiredIdentities = inputIdentities.union(requiredIdentities) + let identitiesToFilter = requiredIdentities.filter { + return identitiesAvailableInSDK.contains($0.identity) + } + requiredIdentities = requiredIdentities.subtracting(identitiesToFilter) + // We should never have loaded a manifest we don't need. assert( availableIdentities.isSubset(of: requiredIdentities), @@ -328,7 +350,7 @@ extension Workspace { products: productFilter ) allConstraints.append(constraint) - case .sourceControlCheckout, .registryDownload, .fileSystem, .providedLibrary, .custom: + case .sourceControlCheckout, .registryDownload, .fileSystem, .custom: break } allConstraints += try externalManifest.dependencyConstraints(productFilter: productFilter) @@ -343,7 +365,7 @@ extension Workspace { for (_, managedDependency, productFilter, _) in dependencies { switch managedDependency.state { - case .sourceControlCheckout, .registryDownload, .fileSystem, .providedLibrary, .custom: continue + case .sourceControlCheckout, .registryDownload, .fileSystem, .custom: continue case .edited: break } // FIXME: We shouldn't need to construct a new package reference object here. @@ -379,8 +401,6 @@ extension Workspace { return path ?? self.location.editSubdirectory(for: dependency) case .fileSystem(let path): return path - case .providedLibrary(let path, _): - return path case .custom(_, let path): return path } @@ -423,6 +443,7 @@ extension Workspace { public func loadDependencyManifests( root: PackageGraphRoot, automaticallyAddManagedDependencies: Bool = false, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> DependencyManifests { let prepopulateManagedDependencies: ([PackageReference]) throws -> Void = { refs in @@ -465,6 +486,7 @@ extension Workspace { // Validates that all the managed dependencies are still present in the file system. self.fixManagedDependencies( + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) guard !observabilityScope.errorsReported else { @@ -473,6 +495,7 @@ extension Workspace { root: root, dependencies: [], workspace: self, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -591,6 +614,7 @@ extension Workspace { root: root, dependencies: dependencies, workspace: self, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -651,14 +675,6 @@ extension Workspace { case .registryDownload(let downloadedVersion): packageKind = managedDependency.packageRef.kind packageVersion = downloadedVersion - case .providedLibrary(let path, let version): - let manifest: Manifest? = try? .forProvidedLibrary( - fileSystem: fileSystem, - package: managedDependency.packageRef, - libraryPath: path, - version: version - ) - return completion(manifest) case .custom(let availableVersion, _): packageKind = managedDependency.packageRef.kind packageVersion = availableVersion @@ -791,6 +807,7 @@ extension Workspace { /// If some edited dependency is removed from the file system, mark it as unedited and /// fallback on the original checkout. private func fixManagedDependencies( + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) { // Reset managed dependencies if the state file was removed during the lifetime of the Workspace object. @@ -864,16 +881,13 @@ extension Workspace { try self.unedit( dependency: dependency, forceRemove: true, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) observabilityScope .emit(.editedDependencyMissing(packageName: dependency.packageRef.identity.description)) - case .providedLibrary(_, version: _): - // TODO: If the dependency is not available we can turn it into a source control dependency - break - case .fileSystem: self.state.dependencies.remove(dependency.packageRef.identity) try self.state.save() diff --git a/Sources/Workspace/Workspace+Pinning.swift b/Sources/Workspace/Workspace+Pinning.swift index 6a652a937ad..b51e69fb04f 100644 --- a/Sources/Workspace/Workspace+Pinning.swift +++ b/Sources/Workspace/Workspace+Pinning.swift @@ -145,7 +145,7 @@ extension PinsStore.Pin { packageRef: dependency.packageRef, state: .version(version, revision: .none) ) - case .edited, .fileSystem, .providedLibrary, .custom: + case .edited, .fileSystem, .custom: // NOOP return nil } diff --git a/Sources/Workspace/Workspace+State.swift b/Sources/Workspace/Workspace+State.swift index ebb21c45c07..88fbaea6661 100644 --- a/Sources/Workspace/Workspace+State.swift +++ b/Sources/Workspace/Workspace+State.swift @@ -256,15 +256,6 @@ extension WorkspaceStateStorage { let version = try container.decode(String.self, forKey: .version) return try self .init(underlying: .registryDownload(version: TSCUtility.Version(versionString: version))) - case "providedLibrary": - let path = try container.decode(AbsolutePath.self, forKey: .path) - let version = try container.decode(String.self, forKey: .version) - return try self.init( - underlying: .providedLibrary( - at: path, - version: TSCUtility.Version(versionString: version) - ) - ) case "edited": let path = try container.decode(AbsolutePath?.self, forKey: .path) return try self.init(underlying: .edited( @@ -295,10 +286,6 @@ extension WorkspaceStateStorage { case .registryDownload(let version): try container.encode("registryDownload", forKey: .name) try container.encode(version, forKey: .version) - case .providedLibrary(let path, let version): - try container.encode("providedLibrary", forKey: .name) - try container.encode(path, forKey: .path) - try container.encode(version, forKey: .version) case .edited(_, let path): try container.encode("edited", forKey: .name) try container.encode(path, forKey: .path) @@ -625,15 +612,6 @@ extension WorkspaceStateStorage { let version = try container.decode(String.self, forKey: .version) return try self .init(underlying: .registryDownload(version: TSCUtility.Version(versionString: version))) - case "providedLibrary": - let path = try container.decode(AbsolutePath.self, forKey: .path) - let version = try container.decode(String.self, forKey: .version) - return try self.init( - underlying: .providedLibrary( - at: path, - version: TSCUtility.Version(versionString: version) - ) - ) case "edited": let path = try container.decode(AbsolutePath?.self, forKey: .path) return try self.init(underlying: .edited( @@ -664,10 +642,6 @@ extension WorkspaceStateStorage { case .registryDownload(let version): try container.encode("registryDownload", forKey: .name) try container.encode(version, forKey: .version) - case .providedLibrary(let path, let version): - try container.encode("providedLibrary", forKey: .name) - try container.encode(path, forKey: .path) - try container.encode(version, forKey: .version) case .edited(_, let path): try container.encode("edited", forKey: .name) try container.encode(path, forKey: .path) diff --git a/Sources/Workspace/Workspace.swift b/Sources/Workspace/Workspace.swift index 07a78116841..d0f4c14218a 100644 --- a/Sources/Workspace/Workspace.swift +++ b/Sources/Workspace/Workspace.swift @@ -586,9 +586,9 @@ public class Workspace { ) } - var providedLibraries: [ProvidedLibrary] { + fileprivate var providedLibraries: [LibraryMetadata] { // Note: Eventually, we should get these from the individual SDKs, but the first step is providing the metadata centrally in the toolchain. - self.hostToolchain.providedLibraries + return self.hostToolchain.providedLibraries } } @@ -640,6 +640,7 @@ extension Workspace { packageName: String, forceRemove: Bool, root: PackageGraphRootInput, + availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws { guard let dependency = self.state.dependencies[.plain(packageName)] else { @@ -656,6 +657,7 @@ extension Workspace { dependency: dependency, forceRemove: forceRemove, root: root, + availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -676,6 +678,7 @@ extension Workspace { try self._resolve( root: root, explicitProduct: explicitProduct, + availableLibraries: self.providedLibraries, resolvedFileStrategy: forceResolvedVersions ? .lockFile : forceResolution ? .update(forceResolution: true) : .bestEffort, observabilityScope: observabilityScope @@ -719,8 +722,6 @@ extension Workspace { defaultRequirement = checkoutState.requirement case .registryDownload(let version), .custom(let version, _): defaultRequirement = .versionSet(.exact(version)) - case .providedLibrary(_, version: let version): - defaultRequirement = .versionSet(.exact(version)) case .fileSystem: throw StringError("local dependency '\(dependency.packageRef.identity)' can't be resolved") case .edited: @@ -749,6 +750,7 @@ extension Workspace { // Run the resolution. try self.resolveAndUpdateResolvedFile( root: root, + availableLibraries: self.providedLibraries, forceResolution: false, constraints: [constraint], observabilityScope: observabilityScope @@ -766,6 +768,7 @@ extension Workspace { try self._resolveBasedOnResolvedVersionsFile( root: root, explicitProduct: .none, + availableLibraries: self.providedLibraries, observabilityScope: observabilityScope ) } @@ -876,6 +879,7 @@ extension Workspace { root: root, packages: packages, dryRun: dryRun, + availableLibraries: self.providedLibraries, observabilityScope: observabilityScope ) } @@ -887,6 +891,7 @@ extension Workspace { forceResolvedVersions: Bool = false, customXCTestMinimumDeploymentTargets: [PackageModel.Platform: PlatformVersion]? = .none, testEntryPointPath: AbsolutePath? = nil, + availableLibraries: [LibraryMetadata], expectedSigningEntities: [PackageIdentity: RegistryReleaseMetadata.SigningEntity] = [:], observabilityScope: ObservabilityScope ) throws -> ModulesGraph { @@ -929,6 +934,7 @@ extension Workspace { let manifests = try self._resolve( root: root, explicitProduct: explicitProduct, + availableLibraries: [], resolvedFileStrategy: forceResolvedVersions ? .lockFile : .bestEffort, observabilityScope: observabilityScope ) @@ -1391,8 +1397,6 @@ extension Workspace { } case .registryDownload(let version)?, .custom(let version, _): result.append("resolved to '\(version)'") - case .providedLibrary(_, version: let version): - result.append("resolved to '\(version)'") case .edited?: result.append("edited") case .fileSystem?: diff --git a/Sources/XCBuildSupport/PIFBuilder.swift b/Sources/XCBuildSupport/PIFBuilder.swift index d734f59b97d..356e68fa919 100644 --- a/Sources/XCBuildSupport/PIFBuilder.swift +++ b/Sources/XCBuildSupport/PIFBuilder.swift @@ -409,9 +409,6 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { case .macro: // Macros are not supported when using XCBuild, similar to package plugins. return - case .providedLibrary: - // Provided libraries don't need to be built. - return } } diff --git a/Sources/_InternalTestSupport/MockBuildTestHelper.swift b/Sources/_InternalTestSupport/MockBuildTestHelper.swift index 1efc7cea47f..2f2f5cd84d2 100644 --- a/Sources/_InternalTestSupport/MockBuildTestHelper.swift +++ b/Sources/_InternalTestSupport/MockBuildTestHelper.swift @@ -39,7 +39,6 @@ public struct MockToolchain: PackageModel.Toolchain { public let sdkRootPath: AbsolutePath? = nil public let extraFlags = PackageModel.BuildFlags() public let installedSwiftPMConfiguration = InstalledSwiftPMConfiguration.default - public let providedLibraries = [ProvidedLibrary]() public let swiftPMLibrariesLocation = ToolchainConfiguration.SwiftPMLibrariesLocation( manifestLibraryPath: AbsolutePath("/fake/manifestLib/path"), pluginLibraryPath: AbsolutePath("/fake/pluginLibrary/path") ) diff --git a/Sources/_InternalTestSupport/MockWorkspace.swift b/Sources/_InternalTestSupport/MockWorkspace.swift index a70725f9b84..1fc13e8bbc8 100644 --- a/Sources/_InternalTestSupport/MockWorkspace.swift +++ b/Sources/_InternalTestSupport/MockWorkspace.swift @@ -403,6 +403,7 @@ public final class MockWorkspace { packageName: packageName, forceRemove: forceRemove, root: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) } @@ -501,6 +502,7 @@ public final class MockWorkspace { let graph = try workspace.loadPackageGraph( rootInput: rootInput, forceResolvedVersions: forceResolvedVersions, + availableLibraries: [], // assume no provided libraries for testing. expectedSigningEntities: expectedSigningEntities, observabilityScope: observability.topScope ) @@ -539,6 +541,7 @@ public final class MockWorkspace { try workspace.loadPackageGraph( rootInput: rootInput, forceResolvedVersions: forceResolvedVersions, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) } @@ -564,6 +567,7 @@ public final class MockWorkspace { let dependencyManifests = try workspace.loadDependencyManifests( root: root, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) @@ -572,6 +576,7 @@ public final class MockWorkspace { dependencyManifests: dependencyManifests, pinsStore: pinsStore, constraints: [], + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) @@ -782,6 +787,7 @@ public final class MockWorkspace { let graphRoot = PackageGraphRoot(input: rootInput, manifests: rootManifests, observabilityScope: observability.topScope) let manifests = try workspace.loadDependencyManifests( root: graphRoot, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) result(manifests, observability.diagnostics) diff --git a/Sources/swift-bootstrap/main.swift b/Sources/swift-bootstrap/main.swift index fe3eb29f662..d14faf5e16a 100644 --- a/Sources/swift-bootstrap/main.swift +++ b/Sources/swift-bootstrap/main.swift @@ -393,6 +393,7 @@ struct SwiftBootstrapBuildTool: ParsableCommand { partial[item.key] = (manifest: item.value, fs: self.fileSystem) }, binaryArtifacts: [:], + availableLibraries: [], // assume no provided libraries during bootstrap fileSystem: fileSystem, observabilityScope: observabilityScope, // Plugins can't be used in bootstrap builds, exclude those. diff --git a/Tests/BuildTests/BuildOperationTests.swift b/Tests/BuildTests/BuildOperationTests.swift index ac23499816a..585f900d88c 100644 --- a/Tests/BuildTests/BuildOperationTests.swift +++ b/Tests/BuildTests/BuildOperationTests.swift @@ -75,15 +75,12 @@ final class BuildOperationTests: XCTestCase { buildOp.detectUnexpressedDependencies( availableLibraries: [ .init( - location: "/foo", - metadata: .init( - identities: [ - .sourceControl(url: .init("https://example.com/org/foo")) - ], - version: "1.0.0", - productName: "Best", - schemaVersion: 1 - ) + identities: [ + .sourceControl(url: .init("https://example.com/org/foo")) + ], + version: "1.0.0", + productName: "Best", + schemaVersion: 1 ) ], targetDependencyMap: ["Lunch": []] diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 587ec472f2a..0b203f92282 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -6433,113 +6433,6 @@ final class BuildPlanTests: XCTestCase { XCTAssertEqual(dylibs, ["BarLogging", "FooLogging"]) } - func testSwiftPackageWithProvidedLibraries() throws { - let fs = InMemoryFileSystem( - emptyFiles: - "/A/Sources/ATarget/main.swift", - "/Libraries/B/BTarget.swiftmodule", - "/Libraries/C/CTarget.swiftmodule" - ) - - let observability = ObservabilitySystem.makeForTesting() - let graph = try loadModulesGraph( - fileSystem: fs, - manifests: [ - Manifest.createRootManifest( - displayName: "A", - path: "/A", - dependencies: [ - .localSourceControl(path: "/B", requirement: .upToNextMajor(from: "1.0.0")), - .localSourceControl(path: "/C", requirement: .upToNextMajor(from: "1.0.0")), - ], - products: [ - ProductDescription( - name: "A", - type: .executable, - targets: ["ATarget"] - ) - ], - targets: [ - TargetDescription(name: "ATarget", dependencies: ["BLibrary", "CLibrary"]) - ] - ), - Manifest.createFileSystemManifest( - displayName: "B", - path: "/B", - products: [ - ProductDescription(name: "BLibrary", type: .library(.automatic), targets: ["BTarget"]), - ], - targets: [ - TargetDescription( - name: "BTarget", - path: "/Libraries/B", - type: .providedLibrary - ) - ] - ), - Manifest.createFileSystemManifest( - displayName: "C", - path: "/C", - products: [ - ProductDescription(name: "CLibrary", type: .library(.automatic), targets: ["CTarget"]), - ], - targets: [ - TargetDescription( - name: "CTarget", - path: "/Libraries/C", - type: .providedLibrary - ) - ] - ), - ], - observabilityScope: observability.topScope - ) - - XCTAssertNoDiagnostics(observability.diagnostics) - - let plan = try mockBuildPlan( - graph: graph, - fileSystem: fs, - observabilityScope: observability.topScope - ) - let result = try BuildPlanResult(plan: plan) - - result.checkProductsCount(1) - result.checkTargetsCount(1) - - XCTAssertMatch( - try result.moduleBuildDescription(for: "ATarget").swift().compileArguments(), - [ - .anySequence, - "-I", "/Libraries/C", - "-I", "/Libraries/B", - .anySequence - ] - ) - - let linkerArgs = try result.buildProduct(for: "A").linkArguments() - - XCTAssertMatch( - linkerArgs, - [ - .anySequence, - "-L", "/Libraries/B", - "-l", "BTarget", - .anySequence - ] - ) - - XCTAssertMatch( - linkerArgs, - [ - .anySequence, - "-L", "/Libraries/C", - "-l", "CTarget", - .anySequence - ] - ) - } - func testDefaultVersions() throws { let fs = InMemoryFileSystem(emptyFiles: "/Pkg/Sources/foo/foo.swift" diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 257dca901d3..8a940486ea2 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -3401,6 +3401,7 @@ final class PackageCommandTests: CommandsTestCase { // Load the package graph. let _ = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) diff --git a/Tests/FunctionalTests/PluginTests.swift b/Tests/FunctionalTests/PluginTests.swift index 7fa033572e9..56528c187fb 100644 --- a/Tests/FunctionalTests/PluginTests.swift +++ b/Tests/FunctionalTests/PluginTests.swift @@ -447,6 +447,7 @@ final class PluginTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -634,6 +635,7 @@ final class PluginTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -731,6 +733,7 @@ final class PluginTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -1047,6 +1050,7 @@ final class PluginTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssert(packageGraph.packages.count == 4, "\(packageGraph.packages)") diff --git a/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift b/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift index 849b6790f71..a974cf67c5a 100644 --- a/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift +++ b/Tests/PackageGraphPerformanceTests/DependencyResolverPerfTests.swift @@ -69,7 +69,7 @@ class DependencyResolverRealWorldPerfTests: XCTestCasePerf { 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 { + guard case .version(let version) = $0.boundVersion else { XCTFail("Unexpected result") return nil } diff --git a/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift b/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift index a6e086edec0..b7fed7598bf 100644 --- a/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift +++ b/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift @@ -95,6 +95,7 @@ final class PackageGraphPerfTests: XCTestCasePerf { identityResolver: identityResolver, externalManifests: externalManifests, binaryArtifacts: [:], + availableLibraries: [], // assume no provided libraries for testing. fileSystem: fs, observabilityScope: observability.topScope ) diff --git a/Tests/PackageGraphTests/PubgrubTests.swift b/Tests/PackageGraphTests/PubgrubTests.swift index 66759152546..76e46b3f935 100644 --- a/Tests/PackageGraphTests/PubgrubTests.swift +++ b/Tests/PackageGraphTests/PubgrubTests.swift @@ -2021,16 +2021,13 @@ final class PubGrubTestsBasicGraphs: XCTestCase { try builder.serve(fooRef, at: .version(.init(stringLiteral: "1.2.0"))) try builder.serve(fooRef, at: .version(.init(stringLiteral: "2.0.0"))) - let availableLibraries: [ProvidedLibrary] = [ + let availableLibraries: [LibraryMetadata] = [ .init( - location: .init("/foo"), - metadata: .init( - identities: [.sourceControl(url: "https://example.com/org/foo")], - version: "1.0.0", - productName: "foo", - schemaVersion: 1 - ) - ) + identities: [.sourceControl(url: "https://example.com/org/foo")], + version: "1.0.0", + productName: nil, + schemaVersion: 1 + ), ] let resolver = builder.create(availableLibraries: availableLibraries) @@ -2042,10 +2039,8 @@ final class PubGrubTestsBasicGraphs: XCTestCase { ]) let result = resolver.solve(constraints: dependencies1) - print(try result.get()) - AssertResult(result, [ - ("foo", .version(.init(stringLiteral: "1.0.0"), library: availableLibraries.first!)), - ]) + // Available libraries are filtered from the resolver results, so this is expected to be empty. + AssertResult(result, []) let result2 = resolver.solve(constraints: dependencies2) AssertResult(result2, [ @@ -2083,16 +2078,13 @@ final class PubGrubTestsBasicGraphs: XCTestCase { try builder.serve("target", at: "1.0.0") try builder.serve("target", at: "2.0.0") - let availableLibraries: [ProvidedLibrary] = [ + let availableLibraries: [LibraryMetadata] = [ .init( - location: .init("/foo"), - metadata: .init( - identities: [.sourceControl(url: "https://example.com/org/foo")], - version: "1.1.0", - productName: "foo", - schemaVersion: 1 - ) - ) + identities: [.sourceControl(url: "https://example.com/org/foo")], + version: "1.1.0", + productName: nil, + schemaVersion: 1 + ), ] let resolver = builder.create(availableLibraries: availableLibraries) @@ -2101,14 +2093,13 @@ final class PubGrubTestsBasicGraphs: XCTestCase { "target": (.versionSet(.range(.upToNextMajor(from: "2.0.0"))), .everything), ]) - // This behavior requires an explanation - "foo" is selected to be 1.1.0 because its - // prebuilt matches "root" requirements but without prebuilt library the solver would - // pick "1.0.0" because "foo" 1.1.0 dependency version requirements are incompatible - // with "target" 2.0.0. + // This behavior requires an explanation - "foo" is elided because 1.1.0 is prebuilt. + // It matches "root" requirements but without prebuilt library the solver would 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) AssertResult(result, [ - ("foo", .version(.init(stringLiteral: "1.1.0"), library: availableLibraries.first!)), ("target", .version(.init(stringLiteral: "2.0.0"))), ]) } @@ -2133,16 +2124,13 @@ final class PubGrubTestsBasicGraphs: XCTestCase { "bar": [fooRef: (.versionSet(.range(.upToNextMinor(from: "2.0.0"))), .everything)], ]) - let availableLibraries: [ProvidedLibrary] = [ + let availableLibraries: [LibraryMetadata] = [ .init( - location: .init("/foo"), - metadata: .init( - identities: [.sourceControl(url: "https://example.com/org/foo")], - version: "1.0.0", - productName: "foo", - schemaVersion: 1 - ) - ) + identities: [.sourceControl(url: "https://example.com/org/foo")], + version: "1.0.0", + productName: nil, + schemaVersion: 1 + ), ] let resolver = builder.create(availableLibraries: availableLibraries) @@ -3315,9 +3303,7 @@ private func AssertBindings( ) } for package in packages { - guard let binding = bindings.first(where: { - $0.package.identity == package.identity - }) else { + guard let binding = bindings.first(where: { $0.package.identity == package.identity }) else { XCTFail("No binding found for \(package.identity).", file: file, line: line) continue } @@ -3341,12 +3327,7 @@ private func AssertResult( ) { switch result { case .success(let bindings): - AssertBindings( - bindings, - packages.map { (PackageIdentity($0.identifier), $0.version) }, - file: file, - line: line - ) + 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) } @@ -3393,7 +3374,7 @@ public class MockContainer: PackageContainer { public func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { var versions: [Version] = [] for version in self._versions.reversed() { - guard case .version(let v, _) = version else { continue } + guard case .version(let v) = version else { continue } versions.append(v) } return versions @@ -3402,7 +3383,7 @@ public class MockContainer: PackageContainer { public func versionsAscending() throws -> [Version] { var versions: [Version] = [] for version in self._versions { - guard case .version(let v, _) = version else { continue } + guard case .version(let v) = version else { continue } versions.append(v) } return versions @@ -3469,7 +3450,7 @@ public class MockContainer: PackageContainer { self._versions.append(version) self._versions = self._versions .sorted(by: { lhs, rhs -> Bool in - guard case .version(let lv, _) = lhs, case .version(let rv, _) = rhs else { + guard case .version(let lv) = lhs, case .version(let rv) = rhs else { return true } return lv < rv @@ -3524,7 +3505,7 @@ public class MockContainer: PackageContainer { let versions = dependencies.keys.compactMap(Version.init(_:)) self._versions = versions .sorted() - .map { .version($0) } + .map(BoundVersion.version) } } @@ -3683,7 +3664,7 @@ class DependencyGraphBuilder { let container = self .containers[packageReference.identity.description] ?? MockContainer(package: packageReference) - if case .version(let v, _) = version { + if case .version(let v) = version { container.versionsToolsVersions[v] = toolsVersion ?? container.toolsVersion } @@ -3721,7 +3702,7 @@ class DependencyGraphBuilder { func create( pins: PinsStore.Pins = [:], - availableLibraries: [ProvidedLibrary] = [], + availableLibraries: [LibraryMetadata] = [], delegate: DependencyResolverDelegate? = .none ) -> PubGrubDependencyResolver { defer { diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index 123fa44f784..9883c016fdb 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -319,6 +319,7 @@ final class PluginInvocationTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -699,6 +700,7 @@ final class PluginInvocationTests: XCTestCase { // Load the package graph. XCTAssertThrowsError(try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope )) { error in var diagnosed = false @@ -778,6 +780,7 @@ final class PluginInvocationTests: XCTestCase { // Load the package graph. XCTAssertThrowsError(try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope)) { error in var diagnosed = false if let realError = error as? PackageGraphError, @@ -887,6 +890,7 @@ final class PluginInvocationTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -1081,6 +1085,7 @@ final class PluginInvocationTests: XCTestCase { let graph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) let dict = try await workspace.loadPluginImports(packageGraph: graph) @@ -1228,6 +1233,7 @@ final class PluginInvocationTests: XCTestCase { // Load the package graph. let packageGraph = try workspace.loadPackageGraph( rootInput: rootInput, + availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) From ea2c11825ef9c8b3a2ef90e35720f6e5c1c9156b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 Jul 2024 15:42:34 -0700 Subject: [PATCH 2/4] Revert "[PubGrub] Avoid resolving package versions twice in presence of prebuilt libraries (#7436)" This reverts commit f4ab9a43f3cfbb8f184043435f925b67b0070f36. --- Sources/PackageGraph/CMakeLists.txt | 1 + .../PrebuiltPackageContainer.swift | 69 + .../PubGrub/ContainerProvider.swift | 35 +- .../PubGrub/PubGrubDependencyResolver.swift | 235 +-- .../ResolverPrecomputationProvider.swift | 58 +- .../Workspace/Workspace+Dependencies.swift | 46 +- Tests/PackageGraphTests/PubgrubTests.swift | 1480 ++++++----------- 7 files changed, 764 insertions(+), 1160 deletions(-) create mode 100644 Sources/PackageGraph/PrebuiltPackageContainer.swift diff --git a/Sources/PackageGraph/CMakeLists.txt b/Sources/PackageGraph/CMakeLists.txt index 2fcc29a6279..f22cc9fbf31 100644 --- a/Sources/PackageGraph/CMakeLists.txt +++ b/Sources/PackageGraph/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(PackageGraph PackageGraphRoot.swift PackageModel+Extensions.swift PackageRequirement.swift + PrebuiltPackageContainer.swift PinsStore.swift TraitConfiguration.swift Resolution/PubGrub/Assignment.swift diff --git a/Sources/PackageGraph/PrebuiltPackageContainer.swift b/Sources/PackageGraph/PrebuiltPackageContainer.swift new file mode 100644 index 00000000000..870487d1781 --- /dev/null +++ b/Sources/PackageGraph/PrebuiltPackageContainer.swift @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 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 the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Basics +import PackageModel +import struct TSCUtility.Version + +/// A package container that can represent a prebuilt library from a package. +public struct PrebuiltPackageContainer: PackageContainer { + private let chosenIdentity: LibraryMetadata.Identity + private let metadata: LibraryMetadata + + public init(metadata: LibraryMetadata) throws { + self.metadata = metadata + + // FIXME: Unclear what is supposed to happen if we have multiple identities. + if let identity = metadata.identities.first { + self.chosenIdentity = identity + } else { + let name = metadata.productName.map { "'\($0)' " } ?? "" + throw InternalError("provided library \(name)does not specifiy any identities") + } + } + + public var package: PackageReference { + return .init(identity: chosenIdentity.identity, kind: chosenIdentity.kind) + } + + public func isToolsVersionCompatible(at version: Version) -> Bool { + return true + } + + public func toolsVersion(for version: Version) throws -> ToolsVersion { + return .v4 + } + + public func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { + return try versionsAscending() + } + + public func versionsAscending() throws -> [Version] { + return [.init(stringLiteral: metadata.version)] + } + + public func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { + return [] + } + + public func getDependencies(at revision: String, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { + return [] + } + + public func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint] { + return [] + } + + public func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { + return package + } +} diff --git a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift index d73e41ffdf9..74735c9ccf9 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift @@ -49,8 +49,8 @@ final class ContainerProvider { } func removeCachedContainers(for packages: [PackageReference]) { - for package in packages { - self.containersCache[package] = nil + packages.forEach { + self.containersCache[$0] = nil } } @@ -65,6 +65,7 @@ final class ContainerProvider { /// Get the container for the given identifier, loading it if necessary. func getContainer( for package: PackageReference, + availableLibraries: [LibraryMetadata], completion: @escaping (Result) -> Void ) { // Return the cached container, if available. @@ -72,6 +73,17 @@ final class ContainerProvider { return completion(.success(container)) } + if let metadata = package.matchingPrebuiltLibrary(in: availableLibraries) { + do { + let prebuiltPackageContainer = try PrebuiltPackageContainer(metadata: metadata) + let pubGrubContainer = PubGrubPackageContainer(underlying: prebuiltPackageContainer, pins: self.pins) + self.containersCache[package] = pubGrubContainer + return completion(.success(pubGrubContainer)) + } catch { + return completion(.failure(error)) + } + } + if let prefetchSync = self.prefetches[package] { // If this container is already being prefetched, wait for that to complete prefetchSync.notify(queue: .sharedConcurrent) { @@ -81,7 +93,7 @@ final class ContainerProvider { } else { // if prefetch failed, remove from list of prefetches and try again self.prefetches[package] = nil - return self.getContainer(for: package, completion: completion) + return self.getContainer(for: package, availableLibraries: availableLibraries, completion: completion) } } } else { @@ -89,10 +101,7 @@ final class ContainerProvider { self.underlying.getContainer( for: package, updateStrategy: self.skipUpdate ? .never : .always, // TODO: make this more elaborate - observabilityScope: self.observabilityScope.makeChildScope( - description: "getting package container", - metadata: package.diagnosticsMetadata - ), + observabilityScope: self.observabilityScope.makeChildScope(description: "getting package container", metadata: package.diagnosticsMetadata), on: .sharedConcurrent ) { result in let result = result.tryMap { container -> PubGrubPackageContainer in @@ -109,7 +118,7 @@ final class ContainerProvider { /// Starts prefetching the given containers. func prefetch(containers identifiers: [PackageReference], availableLibraries: [LibraryMetadata]) { let filteredIdentifiers = identifiers.filter { - $0.matchingPrebuiltLibrary(in: availableLibraries) == nil + return $0.matchingPrebuiltLibrary(in: availableLibraries) == nil } // Process each container. for identifier in filteredIdentifiers { @@ -124,19 +133,13 @@ final class ContainerProvider { self.underlying.getContainer( for: identifier, updateStrategy: self.skipUpdate ? .never : .always, // TODO: make this more elaborate - observabilityScope: self.observabilityScope.makeChildScope( - description: "prefetching package container", - metadata: identifier.diagnosticsMetadata - ), + observabilityScope: self.observabilityScope.makeChildScope(description: "prefetching package container", metadata: identifier.diagnosticsMetadata), on: .sharedConcurrent ) { result in defer { self.prefetches[identifier]?.leave() } // only cache positive results if case .success(let container) = result { - self.containersCache[identifier] = PubGrubPackageContainer( - underlying: container, - pins: self.pins - ) + self.containersCache[identifier] = PubGrubPackageContainer(underlying: container, pins: self.pins) } } } diff --git a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift index a6379fd3b6c..94b590cf96c 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift @@ -25,7 +25,7 @@ public struct PubGrubDependencyResolver { public typealias Constraint = PackageContainerConstraint /// the mutable state that get computed - final class State { + internal final class State { /// The root package reference. let root: DependencyResolutionNode @@ -43,11 +43,10 @@ public struct PubGrubDependencyResolver { private let lock = NSLock() - init( - root: DependencyResolutionNode, - overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)] = [:], - solution: PartialSolution = PartialSolution() - ) { + init(root: DependencyResolutionNode, + overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)] = [:], + solution: PartialSolution = PartialSolution()) + { self.root = root self.overriddenPackages = overriddenPackages self.solution = solution @@ -104,9 +103,6 @@ public struct PubGrubDependencyResolver { /// Reference to the pins store, if provided. private let pins: PinsStore.Pins - /// The packages that are available in a prebuilt form in SDK or a toolchain - private let availableLibraries: [LibraryMetadata] - /// The container provider used to load package containers. private let provider: ContainerProvider @@ -125,7 +121,6 @@ public struct PubGrubDependencyResolver { public init( provider: PackageContainerProvider, pins: PinsStore.Pins = [:], - availableLibraries: [LibraryMetadata] = [], skipDependenciesUpdates: Bool = false, prefetchBasedOnResolvedFile: Bool = false, observabilityScope: ObservabilityScope, @@ -133,7 +128,6 @@ public struct PubGrubDependencyResolver { ) { self.packageContainerProvider = provider self.pins = pins - self.availableLibraries = availableLibraries self.skipDependenciesUpdates = skipDependenciesUpdates self.prefetchBasedOnResolvedFile = prefetchBasedOnResolvedFile self.provider = ContainerProvider( @@ -146,7 +140,11 @@ public struct PubGrubDependencyResolver { } /// Execute the resolution algorithm to find a valid assignment of versions. - public func solve(constraints: [Constraint]) -> Result<[DependencyResolverBinding], Error> { + public func solve(constraints: [Constraint], availableLibraries: [LibraryMetadata], preferPrebuiltLibraries: Bool) -> Result<[DependencyResolverBinding], Error> { + if !preferPrebuiltLibraries { + self.provider.removeCachedContainers(for: availableLibraries.flatMap { $0.identities.map { $0.ref } }) + } + // the graph resolution root let root: DependencyResolutionNode if constraints.count == 1, let constraint = constraints.first, constraint.package.kind.isRoot { @@ -161,13 +159,26 @@ public struct PubGrubDependencyResolver { } do { - let bindings = try self.solve(root: root, constraints: constraints).bindings + // Use empty `availableLibraries` for the rest of resolving if we don't prefer them. + let availableLibraries = preferPrebuiltLibraries ? availableLibraries : [] + // strips state + let bindings = try self.solve(root: root, constraints: constraints, availableLibraries: availableLibraries).bindings.filter { + return $0.package.matchingPrebuiltLibrary(in: availableLibraries) == nil + } return .success(bindings) } catch { // If version solving failing, build the user-facing diagnostic. - if let pubGrubError = error as? PubgrubError, let rootCause = pubGrubError.rootCause, - let incompatibilities = pubGrubError.incompatibilities - { + if let pubGrubError = error as? PubgrubError, let rootCause = pubGrubError.rootCause, let incompatibilities = pubGrubError.incompatibilities { + let incompatiblePackages = incompatibilities.map({ $0.key.package }) + if incompatiblePackages.contains(where: { $0.matchingPrebuiltLibrary(in: availableLibraries) != nil }) { + return .failure( + PubgrubError.potentiallyUnresovableDueToPrebuiltLibrary( + incompatiblePackages, + pubGrubError.description + ) + ) + } + do { var builder = DiagnosticReportBuilder( root: root, @@ -188,12 +199,12 @@ public struct PubGrubDependencyResolver { /// 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 -> ( + internal func solve(root: DependencyResolutionNode, constraints: [Constraint], availableLibraries: [LibraryMetadata] = []) throws -> ( bindings: [DependencyResolverBinding], state: State ) { // first process inputs - let inputs = try self.processInputs(root: root, with: constraints) + let inputs = try self.processInputs(root: root, with: constraints, availableLibraries: availableLibraries) // Prefetch the containers if prefetching is enabled. if self.prefetchBasedOnResolvedFile { @@ -203,7 +214,7 @@ public struct PubGrubDependencyResolver { let pins = self.pins.values .map(\.packageRef) .filter { !inputs.overriddenPackages.keys.contains($0) } - self.provider.prefetch(containers: pins, availableLibraries: self.availableLibraries) + self.provider.prefetch(containers: pins, availableLibraries: availableLibraries) } let state = State(root: root, overriddenPackages: inputs.overriddenPackages) @@ -212,17 +223,14 @@ public struct PubGrubDependencyResolver { state.decide(state.root, at: "1.0.0") // Add the root incompatibility. - state.addIncompatibility( - Incompatibility(terms: [Term(not: root, .exact("1.0.0"))], cause: .root), - at: .topLevel - ) + state.addIncompatibility(Incompatibility(terms: [Term(not: root, .exact("1.0.0"))], cause: .root), at: .topLevel) // Add inputs root incompatibilities. for incompatibility in inputs.rootIncompatibilities { state.addIncompatibility(incompatibility, at: .topLevel) } - try self.run(state: state) + try self.run(state: state, availableLibraries: availableLibraries) let decisions = state.solution.assignments.filter(\.isDecision) var flattenedAssignments: [PackageReference: (binding: BoundVersion, products: ProductFilter)] = [:] @@ -231,8 +239,6 @@ public struct PubGrubDependencyResolver { continue } - let package = assignment.term.node.package - let boundVersion: BoundVersion switch assignment.term.requirement { case .exact(let version): @@ -241,29 +247,15 @@ public struct PubGrubDependencyResolver { throw InternalError("unexpected requirement value for assignment \(assignment.term)") } - // Strip packages that have prebuilt libraries only if they match library version. - // - // FIXME: This is built on assumption that libraries are part of the SDK and are - // always available in include/library paths, but what happens if they are - // part of a toolchain instead? Builder needs an indicator that certain path - // has to be included when building packages that depend on prebuilt libraries. - if let library = package.matchingPrebuiltLibrary(in: availableLibraries), - boundVersion == .version(.init(stringLiteral: library.version)) - { - continue - } - let products = assignment.term.node.productFilter // TODO: replace with async/await when available - let container = try temp_await { self.provider.getContainer(for: package, completion: $0) } + let container = try temp_await { provider.getContainer(for: assignment.term.node.package, availableLibraries: availableLibraries, completion: $0) } let updatePackage = try container.underlying.loadPackageReference(at: boundVersion) if var existing = flattenedAssignments[updatePackage] { guard existing.binding == boundVersion else { - throw InternalError( - "Two products in one package resolved to different versions: \(existing.products)@\(existing.binding) vs \(products)@\(boundVersion)" - ) + throw InternalError("Two products in one package resolved to different versions: \(existing.products)@\(existing.binding) vs \(products)@\(boundVersion)") } existing.products.formUnion(products) flattenedAssignments[updatePackage] = existing @@ -280,12 +272,12 @@ 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 container = try temp_await { provider.getContainer(for: package, availableLibraries: availableLibraries, completion: $0) } let updatePackage = try container.underlying.loadPackageReference(at: override.version) finalAssignments.append(.init( - package: updatePackage, - boundVersion: override.version, - products: override.products + package: updatePackage, + boundVersion: override.version, + products: override.products )) } @@ -296,7 +288,8 @@ public struct PubGrubDependencyResolver { private func processInputs( root: DependencyResolutionNode, - with constraints: [Constraint] + with constraints: [Constraint], + availableLibraries: [LibraryMetadata] ) throws -> ( overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)], rootIncompatibilities: [Incompatibility] @@ -314,10 +307,7 @@ public struct PubGrubDependencyResolver { // The list of version-based references reachable via local and branch-based references. // These are added as top-level incompatibilities since they always need to be satisfied. // Some of these might be overridden as we discover local and branch-based references. - var versionBasedDependencies = OrderedCollections.OrderedDictionary< - DependencyResolutionNode, - [VersionBasedConstraint] - >() + var versionBasedDependencies = OrderedCollections.OrderedDictionary() // Process unversioned constraints in first phase. We go through all of the unversioned packages // and collect them and their dependencies. This gives us the complete list of unversioned @@ -329,9 +319,7 @@ public struct PubGrubDependencyResolver { // Mark the package as overridden. if var existing = overriddenPackages[constraint.package] { guard existing.version == .unversioned else { - throw InternalError( - "Overridden package is not unversioned: \(constraint.package)@\(existing.version)" - ) + throw InternalError("Overridden package is not unversioned: \(constraint.package)@\(existing.version)") } existing.products.formUnion(constraint.products) overriddenPackages[constraint.package] = existing @@ -343,13 +331,11 @@ public struct PubGrubDependencyResolver { // Process dependencies of this package. // // 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 + // be process 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 - .getUnversionedDependencies(productFilter: node.productFilter) - { + let container = try temp_await { provider.getContainer(for: node.package, availableLibraries: availableLibraries, completion: $0) } + for dependency in try container.underlying.getUnversionedDependencies(productFilter: node.productFilter) { if let versionedBasedConstraints = VersionBasedConstraint.constraints(dependency) { for constraint in versionedBasedConstraints { versionBasedDependencies[node, default: []].append(constraint) @@ -384,13 +370,9 @@ public struct PubGrubDependencyResolver { case .revision(let existingRevision, let branch)?: // If this branch-based package was encountered before, ensure the references match. if (branch ?? existingRevision) != revision { - throw PubgrubError - .unresolvable( - "\(package.identity) is required using two different revision-based requirements (\(existingRevision) and \(revision)), which is not supported" - ) + throw PubgrubError.unresolvable("\(package.identity) is required using two different revision-based requirements (\(existingRevision) and \(revision)), which is not supported") } else { - // Otherwise, continue since we've already processed this constraint. Any cycles will be diagnosed - // separately. + // Otherwise, continue since we've already processed this constraint. Any cycles will be diagnosed separately. continue } case nil: @@ -400,7 +382,7 @@ public struct PubGrubDependencyResolver { // Process dependencies of this package, similar to the first phase but branch-based dependencies // are not allowed to contain local/unversioned packages. // TODO: replace with async/await when avail - let container = try temp_await { self.provider.getContainer(for: package, completion: $0) } + let container = try temp_await { provider.getContainer(for: package, availableLibraries: availableLibraries, completion: $0) } // If there is a pin for this revision-based dependency, get // the dependencies at the pinned revision instead of using @@ -411,10 +393,7 @@ public struct PubGrubDependencyResolver { revisionForDependencies = pinRevision // Mark the package as overridden with the pinned revision and record the branch as well. - overriddenPackages[package] = ( - version: .revision(revisionForDependencies, branch: revision), - products: constraint.products - ) + overriddenPackages[package] = (version: .revision(revisionForDependencies, branch: revision), products: constraint.products) } else { revisionForDependencies = revision @@ -435,8 +414,7 @@ public struct PubGrubDependencyResolver { case .versionSet(let req): for node in dependency.nodes() { let versionedBasedConstraint = VersionBasedConstraint(node: node, req: req) - versionBasedDependencies[.root(package: constraint.package), default: []] - .append(versionedBasedConstraint) + versionBasedDependencies[.root(package: constraint.package), default: []].append(versionedBasedConstraint) } case .revision: constraints.append(dependency) @@ -460,15 +438,12 @@ public struct PubGrubDependencyResolver { versionBasedDependencies[root, default: []].append(versionedBasedConstraint) } case .revision, .unversioned: - throw InternalError( - "Unexpected revision/unversioned requirement in the constraints list: \(constraints)" - ) + throw InternalError("Unexpected revision/unversioned requirement in the constraints list: \(constraints)") } } // Finally, compute the root incompatibilities (which will be all version-based). - // note versionBasedDependencies may point to the root package dependencies, or the dependencies of root's - // non-versioned dependencies + // note versionBasedDependencies may point to the root package dependencies, or the dependencies of root's non-versioned dependencies var rootIncompatibilities: [Incompatibility] = [] for (node, constraints) in versionBasedDependencies { for constraint in constraints { @@ -490,7 +465,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, availableLibraries: [LibraryMetadata]) throws { var next: DependencyResolutionNode? = state.root while let nxt = next { @@ -499,13 +474,13 @@ public struct PubGrubDependencyResolver { // initiate prefetch of known packages that will be used to make the decision on the next step self.provider.prefetch( containers: state.solution.undecided.map(\.node.package), - availableLibraries: self.availableLibraries + availableLibraries: availableLibraries ) // 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 temp_await { self.makeDecision(state: state, availableLibraries: availableLibraries, completion: $0) } } } @@ -513,7 +488,7 @@ public struct PubGrubDependencyResolver { /// partial solution. /// If a conflict is found, the conflicting incompatibility is returned to /// resolve the conflict on. - func propagate(state: State, node: DependencyResolutionNode) throws { + internal func propagate(state: State, node: DependencyResolutionNode) throws { var changed: OrderedCollections.OrderedSet = [node] while !changed.isEmpty { @@ -568,6 +543,7 @@ public struct PubGrubDependencyResolver { return .conflict } + state.derive(unsatisfiedTerm.inverse, cause: incompatibility) self.delegate?.derived(term: unsatisfiedTerm.inverse) return .almostSatisfied(node: unsatisfiedTerm.node) @@ -576,7 +552,7 @@ public struct PubGrubDependencyResolver { // Based on: // https://github.com/dart-lang/pub/tree/master/doc/solver.md#conflict-resolution // https://github.com/dart-lang/pub/blob/master/lib/src/solver/version_solver.dart#L201 - func resolve(state: State, conflict: Incompatibility) throws -> Incompatibility { + internal func resolve(state: State, conflict: Incompatibility) throws -> Incompatibility { self.delegate?.conflict(conflict: conflict) var incompatibility = conflict @@ -587,7 +563,7 @@ public struct PubGrubDependencyResolver { let maxIterations = 1000 var iterations = 0 - while !self.isCompleteFailure(incompatibility, root: state.root) { + while !isCompleteFailure(incompatibility, root: state.root) { var mostRecentTerm: Term? var mostRecentSatisfier: Assignment? var difference: Term? @@ -616,10 +592,7 @@ public struct PubGrubDependencyResolver { if mostRecentTerm == term { difference = mostRecentSatisfier?.term.difference(with: term) if let difference { - previousSatisfierLevel = try max( - previousSatisfierLevel, - state.solution.satisfier(for: difference.inverse).decisionLevel - ) + previousSatisfierLevel = max(previousSatisfierLevel, try state.solution.satisfier(for: difference.inverse).decisionLevel) } } } @@ -658,18 +631,9 @@ public struct PubGrubDependencyResolver { if let mostRecentTerm { if let difference { - self.delegate?.partiallySatisfied( - term: mostRecentTerm, - by: _mostRecentSatisfier, - incompatibility: incompatibility, - difference: difference - ) + self.delegate?.partiallySatisfied(term: mostRecentTerm, by: _mostRecentSatisfier, incompatibility: incompatibility, difference: difference) } else { - self.delegate?.satisfied( - term: mostRecentTerm, - by: _mostRecentSatisfier, - incompatibility: incompatibility - ) + self.delegate?.satisfied(term: mostRecentTerm, by: _mostRecentSatisfier, incompatibility: incompatibility) } } @@ -694,6 +658,7 @@ public struct PubGrubDependencyResolver { private func computeCounts( for terms: [Term], + availableLibraries: [LibraryMetadata], completion: @escaping (Result<[Term: Int], Error>) -> Void ) { if terms.isEmpty { @@ -703,26 +668,26 @@ public struct PubGrubDependencyResolver { let sync = DispatchGroup() let results = ThreadSafeKeyValueStore>() - for term in terms { + terms.forEach { term in sync.enter() - self.provider.getContainer(for: term.node.package) { result in + provider.getContainer(for: term.node.package, availableLibraries: availableLibraries) { result in defer { sync.leave() } - results[term] = result - .flatMap { container in Result(catching: { try container.versionCount(term.requirement) }) } + results[term] = result.flatMap { container in Result(catching: { try container.versionCount(term.requirement) }) } } } sync.notify(queue: .sharedConcurrent) { do { - try completion(.success(results.mapValues { try $0.get() })) + completion(.success(try results.mapValues { try $0.get() })) } catch { completion(.failure(error)) } } } - func makeDecision( + internal func makeDecision( state: State, + availableLibraries: [LibraryMetadata] = [], completion: @escaping (Result) -> Void ) { // If there are no more undecided terms, version solving is complete. @@ -731,33 +696,9 @@ public struct PubGrubDependencyResolver { return completion(.success(nil)) } - // If prebuilt libraries are available, let's attempt their versions first before going for - // the latest viable version in the package. This way we archive multiple goals - prioritize - // prebuilt libraries if they satisfy all requirements, avoid counting and building package - // manifests and avoid (re-)building packages. - // - // Since the conflict resolution learns from incorrect terms this wouldn't be re-attempted. - if !self.availableLibraries.isEmpty { - let start = DispatchTime.now() - for pkgTerm in undecided { - let package = pkgTerm.node.package - guard let library = package.matchingPrebuiltLibrary(in: self.availableLibraries) else { - continue - } - - let version = Version(stringLiteral: library.version) - - if pkgTerm.requirement.contains(version) { - self.delegate?.didResolve(term: pkgTerm, version: version, duration: start.distance(to: .now())) - state.decide(pkgTerm.node, at: version) - return completion(.success(pkgTerm.node)) - } - } - } - // 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 + self.computeCounts(for: undecided, availableLibraries: availableLibraries) { result in do { let start = DispatchTime.now() let counts = try result.get() @@ -769,10 +710,7 @@ public struct PubGrubDependencyResolver { // 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 - ) + state.addIncompatibility(try Incompatibility(pkgTerm, root: state.root, cause: .noAvailableVersion), at: .decisionMaking) return completion(.success(pkgTerm.node)) } @@ -813,24 +751,27 @@ public struct PubGrubDependencyResolver { } } -enum LogLocation: String { +internal enum LogLocation: String { case topLevel = "top level" case unitPropagation = "unit propagation" case decisionMaking = "decision making" case conflictResolution = "conflict resolution" } -extension PubGrubDependencyResolver { - public enum PubgrubError: Swift.Error, CustomStringConvertible { +public extension PubGrubDependencyResolver { + enum PubgrubError: Swift.Error, CustomStringConvertible { case _unresolvable(Incompatibility, [DependencyResolutionNode: [Incompatibility]]) case unresolvable(String) + case potentiallyUnresovableDueToPrebuiltLibrary([PackageReference], String) public var description: String { switch self { case ._unresolvable(let rootCause, _): rootCause.description case .unresolvable(let error): - error + return error + case .potentiallyUnresovableDueToPrebuiltLibrary(_, let error): + return error } } @@ -839,7 +780,9 @@ extension PubGrubDependencyResolver { case ._unresolvable(let rootCause, _): rootCause case .unresolvable: - nil + return nil + case .potentiallyUnresovableDueToPrebuiltLibrary: + return nil } } @@ -848,7 +791,9 @@ extension PubGrubDependencyResolver { case ._unresolvable(_, let incompatibilities): incompatibilities case .unresolvable: - nil + return nil + case .potentiallyUnresovableDueToPrebuiltLibrary: + return nil } } } @@ -864,7 +809,7 @@ extension PubGrubDependencyResolver { self.requirement = req } - static func constraints(_ constraint: Constraint) -> [VersionBasedConstraint]? { + internal static func constraints(_ constraint: Constraint) -> [VersionBasedConstraint]? { switch constraint.requirement { case .versionSet(let req): constraint.nodes().map { VersionBasedConstraint(node: $0, req: req) } @@ -883,8 +828,8 @@ private enum PropagationResult { case none } -extension PackageRequirement { - fileprivate var isRevision: Bool { +private extension PackageRequirement { + var isRevision: Bool { switch self { case .versionSet, .unversioned: false @@ -907,10 +852,8 @@ extension PackageReference { scope: registryIdentity.scope.description, name: registryIdentity.name.description ) - } - ) - } - ) + }) + }) } else { return nil } diff --git a/Sources/Workspace/ResolverPrecomputationProvider.swift b/Sources/Workspace/ResolverPrecomputationProvider.swift index 7308bbcfcac..3d9803adea7 100644 --- a/Sources/Workspace/ResolverPrecomputationProvider.swift +++ b/Sources/Workspace/ResolverPrecomputationProvider.swift @@ -44,14 +44,19 @@ struct ResolverPrecomputationProvider: PackageContainerProvider { /// The tools version currently in use. let currentToolsVersion: ToolsVersion + /// The available libraries in the SDK. + let availableLibraries: [LibraryMetadata] + init( root: PackageGraphRoot, dependencyManifests: Workspace.DependencyManifests, - currentToolsVersion: ToolsVersion = ToolsVersion.current + currentToolsVersion: ToolsVersion = ToolsVersion.current, + availableLibraries: [LibraryMetadata] ) { self.root = root self.dependencyManifests = dependencyManifests self.currentToolsVersion = currentToolsVersion + self.availableLibraries = availableLibraries } func getContainer( @@ -63,9 +68,7 @@ struct ResolverPrecomputationProvider: PackageContainerProvider { ) { queue.async { // Start by searching manifests from the Workspace's resolved dependencies. - if let manifest = self.dependencyManifests.dependencies - .first(where: { _, managed, _, _ in managed.packageRef == package }) - { + if let manifest = self.dependencyManifests.dependencies.first(where: { _, managed, _, _ in managed.packageRef == package }) { let container = LocalPackageContainer( package: package, manifest: manifest.manifest, @@ -86,6 +89,15 @@ struct ResolverPrecomputationProvider: PackageContainerProvider { return completion(.success(container)) } + // Match against available prebuilt libraries. + if let matchingPrebuiltLibrary = package.matchingPrebuiltLibrary(in: availableLibraries) { + do { + return completion(.success(try PrebuiltPackageContainer(metadata: matchingPrebuiltLibrary))) + } catch { + return completion(.failure(error)) + } + } + // As we don't have anything else locally, error out. completion(.failure(ResolverPrecomputationError.missingPackage(package: package))) } @@ -101,7 +113,7 @@ private struct LocalPackageContainer: PackageContainer { let shouldInvalidatePinnedVersions = false func versionsAscending() throws -> [Version] { - switch self.dependency?.state { + switch dependency?.state { case .sourceControlCheckout(.version(let version, revision: _)): return [version] case .registryDownload(let version): @@ -113,10 +125,7 @@ private struct LocalPackageContainer: PackageContainer { func isToolsVersionCompatible(at version: Version) -> Bool { do { - try self.manifest.toolsVersion.validateToolsVersion( - self.currentToolsVersion, - packageIdentity: .plain("unknown") - ) + try manifest.toolsVersion.validateToolsVersion(currentToolsVersion, packageIdentity: .plain("unknown")) return true } catch { return false @@ -124,36 +133,31 @@ private struct LocalPackageContainer: PackageContainer { } func toolsVersion(for version: Version) throws -> ToolsVersion { - self.currentToolsVersion + return currentToolsVersion } func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { - try self.versionsDescending() + return try self.versionsDescending() } func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { // Because of the implementation of `reversedVersions`, we should only get the exact same version. - switch self.dependency?.state { + switch dependency?.state { case .sourceControlCheckout(.version(version, revision: _)): - return try self.manifest.dependencyConstraints(productFilter: productFilter) + return try manifest.dependencyConstraints(productFilter: productFilter) case .registryDownload(version: version): - return try self.manifest.dependencyConstraints(productFilter: productFilter) + return try manifest.dependencyConstraints(productFilter: productFilter) default: - throw InternalError( - "expected version based state, but state was \(String(describing: self.dependency?.state))" - ) + throw InternalError("expected version based state, but state was \(String(describing: dependency?.state))") } } - func getDependencies( - at revisionString: String, - productFilter: ProductFilter - ) throws -> [PackageContainerConstraint] { + func getDependencies(at revisionString: String, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { let revision = Revision(identifier: revisionString) - switch self.dependency?.state { + switch dependency?.state { case .sourceControlCheckout(.branch(_, revision: revision)), .sourceControlCheckout(.revision(revision)): // Return the dependencies if the checkout state matches the revision. - return try self.manifest.dependencyConstraints(productFilter: productFilter) + return try manifest.dependencyConstraints(productFilter: productFilter) default: // Throw an error when the dependency is not revision based to fail resolution. throw ResolverPrecomputationError.differentRequirement( @@ -165,14 +169,14 @@ private struct LocalPackageContainer: PackageContainer { } func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint] { - switch self.dependency?.state { + switch dependency?.state { case .none, .fileSystem, .edited: - return try self.manifest.dependencyConstraints(productFilter: productFilter) + return try manifest.dependencyConstraints(productFilter: productFilter) default: // Throw an error when the dependency is not unversioned to fail resolution. throw ResolverPrecomputationError.differentRequirement( - package: self.package, - state: self.dependency?.state, + package: package, + state: dependency?.state, requirement: .unversioned ) } diff --git a/Sources/Workspace/Workspace+Dependencies.swift b/Sources/Workspace/Workspace+Dependencies.swift index 5ece297dc4a..3157260e268 100644 --- a/Sources/Workspace/Workspace+Dependencies.swift +++ b/Sources/Workspace/Workspace+Dependencies.swift @@ -121,15 +121,12 @@ extension Workspace { } // Resolve the dependencies. - let resolver = try self.createResolver( - pins: pins, - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ) + let resolver = try self.createResolver(pins: pins, observabilityScope: observabilityScope) self.activeResolver = resolver let updateResults = self.resolveDependencies( resolver: resolver, + availableLibraries: availableLibraries, constraints: updateConstraints, observabilityScope: observabilityScope ) @@ -594,15 +591,12 @@ extension Workspace { computedConstraints += try graphRoot.constraints() + constraints // Perform dependency resolution. - let resolver = try self.createResolver( - pins: pinsStore.pins, - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ) + let resolver = try self.createResolver(pins: pinsStore.pins, observabilityScope: observabilityScope) self.activeResolver = resolver let result = self.resolveDependencies( resolver: resolver, + availableLibraries: availableLibraries, constraints: computedConstraints, observabilityScope: observabilityScope ) @@ -848,15 +842,19 @@ extension Workspace { let precomputationProvider = ResolverPrecomputationProvider( root: root, - dependencyManifests: dependencyManifests + dependencyManifests: dependencyManifests, + availableLibraries: availableLibraries ) let resolver = PubGrubDependencyResolver( provider: precomputationProvider, pins: pinsStore.pins, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) - let result = resolver.solve(constraints: computedConstraints) + let result = resolver.solve( + constraints: computedConstraints, + availableLibraries: availableLibraries, + preferPrebuiltLibraries: true + ) guard !observabilityScope.errorsReported else { return .required(reason: .errorsPreviouslyReported) @@ -1053,9 +1051,7 @@ extension Workspace { completion: $0 ) }) as? SourceControlPackageContainer else { - throw InternalError( - "invalid container for \(binding.package) expected a SourceControlPackageContainer" - ) + throw InternalError("invalid container for \(binding.package) expected a SourceControlPackageContainer") } var revision = try container.getRevision(forIdentifier: identifier) let branch = branch ?? (identifier == revision.identifier ? nil : identifier) @@ -1126,7 +1122,6 @@ extension Workspace { /// Creates resolver for the workspace. fileprivate func createResolver( pins: PinsStore.Pins, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> PubGrubDependencyResolver { var delegate: DependencyResolverDelegate @@ -1143,7 +1138,6 @@ extension Workspace { return PubGrubDependencyResolver( provider: packageContainerProvider, pins: pins, - availableLibraries: availableLibraries, skipDependenciesUpdates: self.configuration.skipDependenciesUpdates, prefetchBasedOnResolvedFile: self.configuration.prefetchBasedOnResolvedFile, observabilityScope: observabilityScope, @@ -1154,12 +1148,24 @@ extension Workspace { /// Runs the dependency resolver based on constraints provided and returns the results. fileprivate func resolveDependencies( resolver: PubGrubDependencyResolver, + availableLibraries: [LibraryMetadata], constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope ) -> [DependencyResolverBinding] { os_signpost(.begin, name: SignpostName.pubgrub) - let result = resolver.solve(constraints: constraints) - + var result = resolver.solve( + constraints: constraints, + availableLibraries: availableLibraries, + preferPrebuiltLibraries: true + ) + // If the initial resolution failed due to prebuilt libraries, we try to resolve again without prebuilt libraries. + if case let Result.failure(error as PubGrubDependencyResolver.PubgrubError) = result, case .potentiallyUnresovableDueToPrebuiltLibrary = error { + result = resolver.solve( + constraints: constraints, + availableLibraries: availableLibraries, + preferPrebuiltLibraries: false + ) + } os_signpost(.end, name: SignpostName.pubgrub) // Take an action based on the result. diff --git a/Tests/PackageGraphTests/PubgrubTests.swift b/Tests/PackageGraphTests/PubgrubTests.swift index 76e46b3f935..9f6fa7549ca 100644 --- a/Tests/PackageGraphTests/PubgrubTests.swift +++ b/Tests/PackageGraphTests/PubgrubTests.swift @@ -52,11 +52,11 @@ private let v1_1: Version = "1.1.0" private let v1_5: Version = "1.5.0" private let v2: Version = "2.0.0" private let v3: Version = "3.0.0" -private let v1Range: VersionSetSpecifier = .range(v1 ..< v2) -private let v1_1Range: VersionSetSpecifier = .range(v1_1 ..< v2) -private let v1_5Range: VersionSetSpecifier = .range(v1_5 ..< v2) -private let v1to3Range: VersionSetSpecifier = .range(v1 ..< v3) -private let v2Range: VersionSetSpecifier = .range(v2 ..< v3) +private let v1Range: VersionSetSpecifier = .range(v1..=1.0.0 <1.5.0 XCTAssertEqual( Term("a^1.0.0").intersect(with: Term("¬a@1.5.0")), - Term("a-1.0.0-1.5.0") - ) + Term("a-1.0.0-1.5.0")) // a^1.0.0 ∩ a >=1.5.0 <3.0.0 → a^1.5.0 XCTAssertEqual( Term("a^1.0.0").intersect(with: Term("a-1.5.0-3.0.0")), - Term("a^1.5.0") - ) + Term("a^1.5.0")) // ¬a^1.0.0 ∩ ¬a >=1.5.0 <3.0.0 → ¬a >=1.0.0 <3.0.0 XCTAssertEqual( Term("¬a^1.0.0").intersect(with: Term("¬a-1.5.0-3.0.0")), - Term("¬a-1.0.0-3.0.0") - ) + Term("¬a-1.0.0-3.0.0")) XCTAssertEqual( Term("a^1.0.0").intersect(with: Term("a^1.0.0")), - Term("a^1.0.0") - ) + Term("a^1.0.0")) XCTAssertEqual( Term("¬a^1.0.0").intersect(with: Term("¬a^1.0.0")), - Term("¬a^1.0.0") - ) + Term("¬a^1.0.0")) XCTAssertNil(Term("a^1.0.0").intersect(with: Term("¬a^1.0.0"))) XCTAssertNil(Term("a@1.0.0").difference(with: Term("a@1.0.0"))) XCTAssertEqual( Term("¬a^1.0.0").intersect(with: Term("a^2.0.0")), - Term("a^2.0.0") - ) + Term("a^2.0.0")) XCTAssertEqual( Term("a^2.0.0").intersect(with: Term("¬a^1.0.0")), - Term("a^2.0.0") - ) + Term("a^2.0.0")) XCTAssertEqual( Term("¬a^1.0.0").intersect(with: Term("¬a^1.0.0")), - Term("¬a^1.0.0") - ) + Term("¬a^1.0.0")) XCTAssertEqual( Term("¬a@1.0.0").intersect(with: Term("¬a@1.0.0")), - Term("¬a@1.0.0") - ) + Term("¬a@1.0.0")) // Check difference. let anyA = Term(.empty(package: "a"), .any) @@ -191,7 +182,7 @@ final class PubgrubTests: XCTestCase { func testTermIsValidDecision() { let solution100_150 = PartialSolution(assignments: [ .derivation("a^1.0.0", cause: _cause, decisionLevel: 1), - .derivation("a^1.5.0", cause: _cause, decisionLevel: 2), + .derivation("a^1.5.0", cause: _cause, decisionLevel: 2) ]) let allSatisfied = Term("a@1.6.0") @@ -201,33 +192,26 @@ final class PubgrubTests: XCTestCase { } func testIncompatibilityNormalizeTermsOnInit() throws { - let i1 = try Incompatibility( - Term("a^1.0.0"), - Term("a^1.5.0"), - Term("¬b@1.0.0"), - root: rootNode - ) + let i1 = try Incompatibility(Term("a^1.0.0"), Term("a^1.5.0"), Term("¬b@1.0.0"), + root: rootNode) XCTAssertEqual(i1.terms.count, 2) let a1 = i1.terms.first { $0.node.package == "a" } let b1 = i1.terms.first { $0.node.package == "b" } XCTAssertEqual(a1?.requirement, v1_5Range) XCTAssertEqual(b1?.requirement, .exact(v1)) - let i2 = try Incompatibility( - Term("¬a^1.0.0"), - Term("a^2.0.0"), - root: rootNode - ) + let i2 = try Incompatibility(Term("¬a^1.0.0"), Term("a^2.0.0"), + root: rootNode) XCTAssertEqual(i2.terms.count, 1) let a2 = i2.terms.first XCTAssertEqual(a2?.requirement, v2Range) } func testSolutionPositive() { - let s1 = PartialSolution(assignments: [ + let s1 = PartialSolution(assignments:[ .derivation("a^1.5.0", cause: _cause, decisionLevel: 0), .derivation("b@2.0.0", cause: _cause, decisionLevel: 0), - .derivation("a^1.0.0", cause: _cause, decisionLevel: 0), + .derivation("a^1.0.0", cause: _cause, decisionLevel: 0) ]) let a1 = s1._positive.first { $0.key.package.identity == PackageIdentity("a") }?.value XCTAssertEqual(a1?.requirement, v1_5Range) @@ -236,10 +220,10 @@ final class PubgrubTests: XCTestCase { let s2 = PartialSolution(assignments: [ .derivation("¬a^1.5.0", cause: _cause, decisionLevel: 0), - .derivation("a^1.0.0", cause: _cause, decisionLevel: 0), + .derivation("a^1.0.0", cause: _cause, decisionLevel: 0) ]) let a2 = s2._positive.first { $0.key.package.identity == PackageIdentity("a") }?.value - XCTAssertEqual(a2?.requirement, .range(v1 ..< v1_5)) + XCTAssertEqual(a2?.requirement, .range(v1.. non-versioned -> version func testHappyPath2() throws { try builder.serve("foo", at: v1_1, with: ["foo": ["config": (.versionSet(v1Range), .specific(["config"]))]]) - try 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 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) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.unversioned, .specific(["bar"])), + "bar": (.unversioned, .specific(["bar"])) ]) let result = resolver.solve(constraints: dependencies) @@ -1089,18 +995,14 @@ final class PubgrubTests: XCTestCase { 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( - "baz", - at: .unversioned, - with: ["baz": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] - ) + try 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) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.unversioned, .specific(["bar"])), + "bar": (.unversioned, .specific(["bar"])) ]) let result = resolver.solve(constraints: dependencies) @@ -1123,7 +1025,7 @@ final class PubgrubTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.versionSet(v1Range), .specific(["foo"])), + "foo": (.versionSet(v1Range), .specific(["foo"])) ]) let result = resolver.solve(constraints: dependencies) @@ -1137,18 +1039,14 @@ final class PubgrubTests: XCTestCase { // root -> version // root -> non-versioned -> version func testHappyPath5() throws { - try builder.serve( - "foo", - at: .unversioned, - with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] - ) + try 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) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), + "foo": (.unversioned, .specific(["foo"])) ]) let result = resolver.solve(constraints: dependencies) @@ -1159,22 +1057,19 @@ 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( - "bar", - at: .unversioned, - with: ["bar": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] - ) + try 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) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), + "foo": (.unversioned, .specific(["foo"])) ]) let result = resolver.solve(constraints: dependencies) @@ -1193,16 +1088,15 @@ final class PubgrubTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.versionSet(v1Range), .specific(["foo"])), - ], - ]) + "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) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = resolver.solve(constraints: dependencies) @@ -1214,6 +1108,7 @@ final class PubgrubTests: XCTestCase { ]) } + // top level package -> version // top level package -> non-versioned -> version func testHappyPath8() throws { @@ -1221,20 +1116,15 @@ final class PubgrubTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), - ], - ]) - try builder.serve( - "foo", - at: .unversioned, - with: ["foo": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] - ) + "foo": (.unversioned, .specific(["foo"])) + ]]) + try 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) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = resolver.solve(constraints: dependencies) @@ -1253,22 +1143,17 @@ final class PubgrubTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), - ], - ]) + "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( - "baz", - at: .unversioned, - with: ["baz": ["config": (.versionSet(v1_1Range), .specific(["config"]))]] - ) + try 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) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = resolver.solve(constraints: dependencies) @@ -1288,19 +1173,10 @@ final class PubgrubTests: XCTestCase { let package = PackageReference.root(identity: .plain("package"), path: .root) try builder.serve(package, at: .unversioned, with: [ "module": [ - "foo": (.versionSet(.range("1.0.0-alpha" ..< "2.0.0")), .specific(["foo"])), - ], - ]) - try builder.serve( - "foo", - at: "1.0.0-alpha.1", - with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] - ) - try builder.serve( - "foo", - at: "1.0.0-alpha.2", - with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] - ) + "foo": (.versionSet(.range("1.0.0-alpha" ..< "2.0.0")), .specific(["foo"])) + ]]) + try builder.serve("foo", at: "1.0.0-alpha.1", with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) + try 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"]))]]) @@ -1310,7 +1186,7 @@ final class PubgrubTests: XCTestCase { let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = resolver.solve(constraints: dependencies) @@ -1318,37 +1194,29 @@ final class PubgrubTests: XCTestCase { AssertResult(result, [ ("package", .unversioned), ("foo", .version("1.0.0-beta.3")), - ("bar", .version(v1_5)), + ("bar", .version(v1_5)) ]) } func testResolutionWithSimpleBranchBasedDependency() throws { - try builder.serve( - "foo", - at: .revision("master"), - with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] - ) + try builder.serve("foo", at: .revision("master"), with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) try 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"])), + "bar": (.versionSet(v1Range), .specific(["bar"])) ]) let result = resolver.solve(constraints: dependencies) AssertResult(result, [ ("foo", .revision("master")), - ("bar", .version(v1)), + ("bar", .version(v1)) ]) } func testResolutionWithSimpleBranchBasedDependency2() throws { - try builder.serve( - "foo", - at: .revision("master"), - with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] - ) + try builder.serve("foo", at: .revision("master"), with: ["foo": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) try builder.serve("bar", at: v1) let resolver = builder.create() @@ -1359,7 +1227,7 @@ final class PubgrubTests: XCTestCase { AssertResult(result, [ ("foo", .revision("master")), - ("bar", .version(v1)), + ("bar", .version(v1)) ]) } @@ -1377,7 +1245,7 @@ final class PubgrubTests: XCTestCase { AssertResult(result, [ ("foo", .revision("master")), - ("bar", .version(v1)), + ("bar", .version(v1)) ]) } @@ -1394,25 +1262,17 @@ final class PubgrubTests: XCTestCase { AssertResult(result, [ ("foo", .revision("master")), - ("bar", .version(v1)), + ("bar", .version(v1)) ]) } func testResolutionWithOverridingBranchBasedDependency3() throws { - try builder.serve( - "foo", - at: .revision("master"), - with: ["foo": ["bar": (.revision("master"), .specific(["bar"]))]] - ) + try 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 builder.serve( - "baz", - at: .revision("master"), - with: ["baz": ["bar": (.versionSet(v1Range), .specific(["bar"]))]] - ) + try builder.serve("baz", at: .revision("master"), with: ["baz": ["bar": (.versionSet(v1Range), .specific(["bar"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -1433,7 +1293,7 @@ final class PubgrubTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "foo": (.revision("master"), .specific(["foo"])), + "foo": (.revision("master"), .specific(["foo"])) ]) let result = resolver.solve(constraints: dependencies) @@ -1441,11 +1301,7 @@ final class PubgrubTests: XCTestCase { } func testResolutionWithRevisionConflict() throws { - try builder.serve( - "foo", - at: .revision("master"), - with: ["foo": ["bar": (.revision("master"), .specific(["bar"]))]] - ) + try 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")) @@ -1483,7 +1339,7 @@ final class PubgrubTests: XCTestCase { AssertResult(result, [ ("swift-nio-ssl", .revision("master")), ("swift-nio", .revision("master")), - ("foo", .version(v1)), + ("foo", .version(v1)) ]) } @@ -1497,13 +1353,13 @@ final class PubgrubTests: XCTestCase { "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: [ "http-client": [ "swift-nio": (.versionSet(v1Range), .specific(["swift-nio"])), "boring-ssl": (.versionSet(v1Range), .specific(["boring-ssl"])), - ], + ] ]) try builder.serve("boring-ssl", at: v1, with: [ "boring-ssl": ["swift-nio": (.versionSet(v1Range), .specific(["swift-nio"]))], @@ -1528,7 +1384,7 @@ final class PubgrubTests: XCTestCase { func testNonVersionDependencyInVersionDependency2() throws { try builder.serve("foo", at: v1_1, with: [ - "foo": ["bar": (.revision("master"), .specific(["bar"]))], + "foo": ["bar": (.revision("master"), .specific(["bar"]))] ]) try builder.serve("foo", at: v1) let resolver = builder.create() @@ -1562,15 +1418,12 @@ final class PubgrubTests: XCTestCase { let result = try 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( - "a", - package: builder.reference(for: "a") - ))![0] + let aIncompat = result.state.positiveIncompatibilities(for: .product("a", package: try builder.reference(for: "a")))![0] XCTAssertEqual(aIncompat.terms[0].requirement, .exact("1.0.0")) AssertResult(Result.success(result.bindings), [ ("a", .version(v1)), - ("b", .version(v1)), + ("b", .version(v1)) ]) } @@ -1581,7 +1434,7 @@ final class PubgrubTests: XCTestCase { 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 builder.serve("c", at: v1, with: ["c": ["b": (.versionSet(.range(v1_1..= 1.0.0 practically depends on 'baz' 3.0.0..<4.0.0. - 'bar' >= 2.0.0 practically depends on 'baz' 3.0.0..<4.0.0 because 'bar' 2.0.0 depends on 'baz' 3.0.0..<4.0.0 and no versions of 'bar' match the requirement 2.0.1..<3.0.0. - 'foo' >= 1.0.0 practically depends on 'bar' 2.0.0..<3.0.0 because 'foo' 1.0.0 depends on 'bar' 2.0.0..<3.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'baz' 3.0.0..<4.0.0. + 'bar' >= 2.0.0 practically depends on 'baz' 3.0.0..<4.0.0 because 'bar' 2.0.0 depends on 'baz' 3.0.0..<4.0.0 and no versions of 'bar' match the requirement 2.0.1..<3.0.0. + 'foo' >= 1.0.0 practically depends on 'bar' 2.0.0..<3.0.0 because 'foo' 1.0.0 depends on 'bar' 2.0.0..<3.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. + """) } func testResolutionBranchingErrorReporting() throws { try builder.serve("foo", at: v1, with: [ "foo": [ "a": (.versionSet(v1Range), .specific(["a"])), - "b": (.versionSet(v1Range), .specific(["b"])), - ], + "b": (.versionSet(v1Range), .specific(["b"])) + ] ]) try builder.serve("foo", at: v1_1, with: [ "foo": [ "x": (.versionSet(v1Range), .specific(["x"])), - "y": (.versionSet(v1Range), .specific(["y"])), - ], + "y": (.versionSet(v1Range), .specific(["y"])) + ] ]) try builder.serve("a", at: v1, with: ["a": ["b": (.versionSet(v2Range), .specific(["b"]))]]) try builder.serve("b", at: v1) @@ -2301,14 +2045,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { print(result.errorMsg!) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0. - 'foo' >= 1.0.0 cannot be used because 'foo' {1.0.0..<1.1.0, 1.1.1..<2.0.0} cannot be used (1). - 'foo' 1.1.0 cannot be used because 'foo' 1.1.0 depends on 'x' 1.0.0..<2.0.0 and 'foo' 1.1.0 depends on 'y' 1.0.0..<2.0.0. - 'x' >= 1.0.0 practically depends on 'y' 2.0.0..<3.0.0 because 'x' 1.0.0 depends on 'y' 2.0.0..<3.0.0 and no versions of 'x' match the requirement 1.0.1..<2.0.0. - 'foo' 1.0.0 practically depends on 'b' 2.0.0..<3.0.0 because 'foo' 1.0.0 depends on 'a' 1.0.0..<2.0.0. - 'a' >= 1.0.0 practically depends on 'b' 2.0.0..<3.0.0 because 'a' 1.0.0 depends on 'b' 2.0.0..<3.0.0 and no versions of 'a' match the requirement 1.0.1..<2.0.0. - (1) As a result, 'foo' {1.0.0..<1.1.0, 1.1.1..<2.0.0} cannot be used because 'foo' 1.0.0 depends on 'b' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement {1.0.1..<1.1.0, 1.1.1..<2.0.0}. - """) + Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0. + 'foo' >= 1.0.0 cannot be used because 'foo' {1.0.0..<1.1.0, 1.1.1..<2.0.0} cannot be used (1). + 'foo' 1.1.0 cannot be used because 'foo' 1.1.0 depends on 'x' 1.0.0..<2.0.0 and 'foo' 1.1.0 depends on 'y' 1.0.0..<2.0.0. + 'x' >= 1.0.0 practically depends on 'y' 2.0.0..<3.0.0 because 'x' 1.0.0 depends on 'y' 2.0.0..<3.0.0 and no versions of 'x' match the requirement 1.0.1..<2.0.0. + 'foo' 1.0.0 practically depends on 'b' 2.0.0..<3.0.0 because 'foo' 1.0.0 depends on 'a' 1.0.0..<2.0.0. + 'a' >= 1.0.0 practically depends on 'b' 2.0.0..<3.0.0 because 'a' 1.0.0 depends on 'b' 2.0.0..<3.0.0 and no versions of 'a' match the requirement 1.0.1..<2.0.0. + (1) As a result, 'foo' {1.0.0..<1.1.0, 1.1.1..<2.0.0} cannot be used because 'foo' 1.0.0 depends on 'b' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement {1.0.1..<1.1.0, 1.1.1..<2.0.0}. + """) } func testConflict1() throws { @@ -2320,15 +2064,15 @@ final class PubGrubDiagnosticsTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.versionSet(v1Range), .specific(["bar"])), + "bar": (.versionSet(v1Range), .specific(["bar"])) ]) let result = 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. - 'bar' is incompatible with 'foo' because 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. - 'bar' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'bar' match the requirement 1.0.1..<2.0.0 and 'bar' 1.0.0 depends on 'config' 2.0.0..<3.0.0. - """) + 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. + 'bar' is incompatible with 'foo' because 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. + 'bar' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'bar' match the requirement 1.0.1..<2.0.0 and 'bar' 1.0.0 depends on 'config' 2.0.0..<3.0.0. + """) } func testConflict2() throws { @@ -2347,9 +2091,9 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result1 = 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. - 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0. + """) let dependencies2 = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), @@ -2360,9 +2104,9 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result2 = 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. - 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. + """) } func testConflict3() throws { @@ -2377,16 +2121,16 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = 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. - """) + 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: [ - "foo": ["shared": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["shared"]))], + "foo": ["shared": (.versionSet(.range("2.0.0"..<"3.0.0")), .specific(["shared"]))], ]) try builder.serve("bar", at: v1, with: [ - "bar": ["shared": (.versionSet(.range("2.9.0" ..< "4.0.0")), .specific(["shared"]))], + "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") @@ -2400,10 +2144,10 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = 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. - 'foo' is incompatible with 'bar' because 'foo' 1.0.0 depends on 'shared' 2.0.0..<3.0.0. - 'bar' 1.0.0 practically depends on 'shared' 3.0.0..<4.0.0 because 'bar' 1.0.0 depends on 'shared' 2.9.0..<4.0.0 and no versions of 'shared' match the requirement 2.9.0..<3.0.0. - """) + Dependencies could not be resolved because root depends on 'bar' 1.0.0 and root depends on 'foo' 1.0.0. + 'foo' is incompatible with 'bar' because 'foo' 1.0.0 depends on 'shared' 2.0.0..<3.0.0. + 'bar' 1.0.0 practically depends on 'shared' 3.0.0..<4.0.0 because 'bar' 1.0.0 depends on 'shared' 2.9.0..<4.0.0 and no versions of 'shared' match the requirement 2.9.0..<3.0.0. + """) } func testConflict5() throws { @@ -2422,19 +2166,19 @@ final class PubGrubDiagnosticsTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "b": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["b"])), - "a": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["a"])), + "b": (.versionSet(.range("0.0.0"..<"5.0.0")), .specific(["b"])), + "a": (.versionSet(.range("0.0.0"..<"5.0.0")), .specific(["a"])), ]) let result = resolver.solve(constraints: dependencies) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because root depends on 'a' 0.0.0..<5.0.0. - 'a' cannot be used. - 'a' 2.0.0 cannot be used because 'b' 2.0.0 depends on 'a' 1.0.0 and 'a' 2.0.0 depends on 'b' 2.0.0. - 'a' {0.0.0..<2.0.0, 2.0.1..<5.0.0} cannot be used because 'b' 1.0.0 depends on 'a' 2.0.0. - 'a' {0.0.0..<2.0.0, 2.0.1..<5.0.0} practically depends on 'b' 1.0.0 because no versions of 'a' match the requirement {0.0.0..<1.0.0, 1.0.1..<2.0.0, 2.0.1..<5.0.0} and 'a' 1.0.0 depends on 'b' 1.0.0. - """) + Dependencies could not be resolved because root depends on 'a' 0.0.0..<5.0.0. + 'a' cannot be used. + 'a' 2.0.0 cannot be used because 'b' 2.0.0 depends on 'a' 1.0.0 and 'a' 2.0.0 depends on 'b' 2.0.0. + 'a' {0.0.0..<2.0.0, 2.0.1..<5.0.0} cannot be used because 'b' 1.0.0 depends on 'a' 2.0.0. + 'a' {0.0.0..<2.0.0, 2.0.1..<5.0.0} practically depends on 'b' 1.0.0 because no versions of 'a' match the requirement {0.0.0..<1.0.0, 1.0.1..<2.0.0, 2.0.1..<5.0.0} and 'a' 1.0.0 depends on 'b' 1.0.0. + """) } // root -> version -> version @@ -2448,42 +2192,38 @@ final class PubGrubDiagnosticsTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.versionSet(v1Range), .specific(["bar"])), + "bar": (.versionSet(v1Range), .specific(["bar"])) ]) let result = 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. - 'bar' is incompatible with 'foo' because 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. - 'bar' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'bar' match the requirement 1.0.1..<2.0.0 and 'bar' 1.0.0 depends on 'config' 2.0.0..<3.0.0. - """) + 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. + 'bar' is incompatible with 'foo' because 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0 and no versions of 'foo' match the requirement 1.0.1..<2.0.0. + 'bar' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'bar' match the requirement 1.0.1..<2.0.0 and 'bar' 1.0.0 depends on 'config' 2.0.0..<3.0.0. + """) } // 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( - "bar", - at: .unversioned, - with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("bar", at: .unversioned, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) try builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.unversioned, .specific(["bar"])), + "bar": (.unversioned, .specific(["bar"])) ]) let result = 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. - 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0. + """) } // root -> version -> version @@ -2491,97 +2231,81 @@ final class PubGrubDiagnosticsTests: XCTestCase { 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( - "baz", - at: .unversioned, - with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) try builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.unversioned, .specific(["bar"])), + "bar": (.unversioned, .specific(["bar"])) ]) let result = 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. - 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'config' 1.0.0..<2.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 1.0.0..<2.0.0. + """) } // 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( - "bar", - at: .unversioned, - with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("bar", at: .unversioned, with: ["bar": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "foo": (.versionSet(v1Range), .specific(["foo"])), - "bar": (.unversioned, .specific(["bar"])), + "bar": (.unversioned, .specific(["bar"])) ]) let result = 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. - """) + 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. + """) } // root -> version // root -> non-versioned -> conflicting version func testConflict10() throws { - try builder.serve( - "foo", - at: .unversioned, - with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) try builder.serve("config", at: v2) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), + "foo": (.unversioned, .specific(["foo"])) ]) let result = 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. - """) + 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. + """) } // root -> version // root -> non-versioned -> non-existing version func testConflict11() throws { - try builder.serve( - "foo", - at: .unversioned, - with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), + "foo": (.unversioned, .specific(["foo"])) ]) let result = 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. - """) + 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. + """) } // root -> version @@ -2589,24 +2313,20 @@ final class PubGrubDiagnosticsTests: XCTestCase { 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( - "baz", - at: .unversioned, - with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), + "foo": (.unversioned, .specific(["foo"])) ]) let result = 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. - """) + 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. + """) } // top level package -> version @@ -2616,24 +2336,23 @@ final class PubGrubDiagnosticsTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.versionSet(v1Range), .specific(["foo"])), - ], - ]) + "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) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = 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. - 'foo' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 2.0.0..<3.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 2.0.0..<3.0.0. + """) } // top level package -> version @@ -2643,23 +2362,22 @@ final class PubGrubDiagnosticsTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.versionSet(v1Range), .specific(["foo"])), - ], - ]) + "foo": (.versionSet(v1Range), .specific(["foo"])) + ]]) try builder.serve("foo", at: v1, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = 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. - 'foo' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 2.0.0..<3.0.0. - """) + 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. + 'foo' >= 1.0.0 practically depends on 'config' 2.0.0..<3.0.0 because no versions of 'foo' match the requirement 1.0.1..<2.0.0 and 'foo' 1.0.0 depends on 'config' 2.0.0..<3.0.0. + """) } // top level package -> version @@ -2669,27 +2387,22 @@ final class PubGrubDiagnosticsTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), - ], - ]) - try builder.serve( - "foo", - at: .unversioned, - with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + "foo": (.unversioned, .specific(["foo"])) + ]]) + try builder.serve("foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) try builder.serve("config", at: v2) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = 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. - """) + 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. + """) } // top level package -> version @@ -2699,26 +2412,21 @@ final class PubGrubDiagnosticsTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), - ], - ]) - try builder.serve( - "foo", - at: .unversioned, - with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + "foo": (.unversioned, .specific(["foo"])) + ]]) + try builder.serve("foo", at: .unversioned, with: ["foo": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = 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. - """) + 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. + """) } // top level package -> version @@ -2728,65 +2436,49 @@ final class PubGrubDiagnosticsTests: XCTestCase { try builder.serve(package, at: .unversioned, with: [ "module": [ "config": (.versionSet(v1Range), .specific(["config"])), - "foo": (.unversioned, .specific(["foo"])), - ], - ]) + "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( - "baz", - at: .unversioned, - with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]] - ) + try builder.serve("baz", at: .unversioned, with: ["baz": ["config": (.versionSet(v2Range), .specific(["config"]))]]) try builder.serve("config", at: v1) try builder.serve("config", at: v2) let resolver = builder.create() let dependencies = builder.create(dependencies: [ - package: (.unversioned, .everything), + package: (.unversioned, .everything) ]) let result = 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. - """) + 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: [ - "bar": ["foo": (.unversioned, .specific(["foo"]))], + "bar": ["foo": (.unversioned, .specific(["foo"]))] ]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "bar": (.revision("master"), .specific(["bar"])), + "bar": (.revision("master"), .specific(["bar"])) ]) let result = resolver.solve(constraints: dependencies) - XCTAssertEqual( - result.errorMsg, - "package 'bar' is required using a revision-based requirement and it depends on local package 'foo', which is not supported" - ) + XCTAssertEqual(result.errorMsg, "package 'bar' is required using a revision-based requirement and it depends on local package 'foo', which is not supported") } func testResolutionWithOverridingBranchBasedDependency4() throws { - try builder.serve( - "foo", - at: .revision("master"), - with: ["foo": ["bar": (.revision("master"), .specific(["bar"]))]] - ) + try 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 builder.serve( - "baz", - at: .revision("master"), - with: ["baz": ["bar": (.revision("develop"), .specific(["baz"]))]] - ) + try builder.serve("baz", at: .revision("master"), with: ["baz": ["bar": (.revision("develop"), .specific(["baz"]))]]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ @@ -2795,15 +2487,12 @@ final class PubGrubDiagnosticsTests: XCTestCase { ]) let result = resolver.solve(constraints: dependencies) - XCTAssertEqual( - result.errorMsg, - "bar is required using two different revision-based requirements (master and develop), which is not supported" - ) + XCTAssertEqual(result.errorMsg, "bar is required using two different revision-based requirements (master and develop), which is not supported") } func testNonVersionDependencyInVersionDependency1() throws { try builder.serve("foo", at: v1_1, with: [ - "foo": ["bar": (.revision("master"), .specific(["bar"]))], + "foo": ["bar": (.revision("master"), .specific(["bar"]))] ]) try builder.serve("bar", at: .revision("master")) @@ -2814,14 +2503,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = resolver.solve(constraints: dependencies) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0. - 'foo' cannot be used because no versions of 'foo' match the requirement {1.0.0..<1.1.0, 1.1.1..<2.0.0} and package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar'. - """) + Dependencies could not be resolved because root depends on 'foo' 1.0.0..<2.0.0. + 'foo' cannot be used because no versions of 'foo' match the requirement {1.0.0..<1.1.0, 1.1.1..<2.0.0} and package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar'. + """) } func testNonVersionDependencyInVersionDependency2() throws { try builder.serve("foo", at: v1, with: [ - "foo": ["bar": (.unversioned, .specific(["bar"]))], + "foo": ["bar": (.unversioned, .specific(["bar"]))] ]) try builder.serve("bar", at: .unversioned) @@ -2832,19 +2521,19 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = 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. - """) + 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: [ - "foo": ["bar": (.revision("master"), .specific(["bar"]))], + "foo": ["bar": (.revision("master"), .specific(["bar"]))] ]) try builder.serve("foo", at: "1.0.0-beta.2", with: [ - "foo": ["bar": (.revision("master"), .specific(["bar"]))], + "foo": ["bar": (.revision("master"), .specific(["bar"]))] ]) try builder.serve("foo", at: "1.0.0-beta.3", with: [ - "foo": ["bar": (.revision("master"), .specific(["bar"]))], + "foo": ["bar": (.revision("master"), .specific(["bar"]))] ]) try builder.serve("bar", at: .revision("master")) @@ -2855,10 +2544,10 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = 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. - 'foo' {1.0.0-beta..<1.0.0-beta.3, 1.0.0-beta.3.0..<2.0.0} cannot be used because package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar'. - 'foo' {1.0.0-beta..<1.0.0-beta.2, 1.0.0-beta.2.0..<1.0.0-beta.3, 1.0.0-beta.3.0..<2.0.0} cannot be used because no versions of 'foo' match the requirement {1.0.0-beta..<1.0.0-beta.1, 1.0.0-beta.1.0..<1.0.0-beta.2, 1.0.0-beta.2.0..<1.0.0-beta.3, 1.0.0-beta.3.0..<2.0.0} and package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar'. - """) + 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. + 'foo' {1.0.0-beta..<1.0.0-beta.3, 1.0.0-beta.3.0..<2.0.0} cannot be used because package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar'. + 'foo' {1.0.0-beta..<1.0.0-beta.2, 1.0.0-beta.2.0..<1.0.0-beta.3, 1.0.0-beta.3.0..<2.0.0} cannot be used because no versions of 'foo' match the requirement {1.0.0-beta..<1.0.0-beta.1, 1.0.0-beta.1.0..<1.0.0-beta.2, 1.0.0-beta.2.0..<1.0.0-beta.3, 1.0.0-beta.3.0..<2.0.0} and package 'foo' is required using a stable-version but 'foo' depends on an unstable-version package 'bar'. + """) } func testIncompatibleToolsVersion1() throws { @@ -2872,17 +2561,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = resolver.solve(constraints: dependencies) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because root depends on 'a' 1.0.0..<2.0.0. - 'a' >= 1.0.0 cannot be used because no versions of 'a' match the requirement 1.0.1..<2.0.0 and 'a' 1.0.0 contains incompatible tools version (\( - ToolsVersion - .v5 - )). - """) + Dependencies could not be resolved because root depends on 'a' 1.0.0..<2.0.0. + 'a' >= 1.0.0 cannot be used because no versions of 'a' match the requirement 1.0.1..<2.0.0 and 'a' 1.0.0 contains incompatible tools version (\(ToolsVersion.v5)). + """) } func testIncompatibleToolsVersion3() throws { try builder.serve("a", at: v1_1, with: [ - "a": ["b": (.versionSet(v1Range), .specific(["b"]))], + "a": ["b": (.versionSet(v1Range), .specific(["b"]))] ]) try builder.serve("a", at: v1, toolsVersion: .v4) @@ -2898,13 +2584,10 @@ final class PubGrubDiagnosticsTests: XCTestCase { let result = 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. - 'a' >= 1.0.0 practically depends on 'b' 1.0.0..<2.0.0 because 'a' 1.1.0 depends on 'b' 1.0.0..<2.0.0. - 'a' {1.0.0..<1.1.0, 1.1.1..<2.0.0} cannot be used because no versions of 'a' match the requirement {1.0.1..<1.1.0, 1.1.1..<2.0.0} and 'a' 1.0.0 contains incompatible tools version (\( - ToolsVersion - .v4 - )). - """) + 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. + 'a' >= 1.0.0 practically depends on 'b' 1.0.0..<2.0.0 because 'a' 1.1.0 depends on 'b' 1.0.0..<2.0.0. + 'a' {1.0.0..<1.1.0, 1.1.1..<2.0.0} cannot be used because no versions of 'a' match the requirement {1.0.1..<1.1.0, 1.1.1..<2.0.0} and 'a' 1.0.0 contains incompatible tools version (\(ToolsVersion.v4)). + """) } func testIncompatibleToolsVersion4() throws { @@ -2914,17 +2597,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("3.2.0" ..< "4.0.0")), .specific(["a"])), + "a": (.versionSet(.range("3.2.0"..<"4.0.0")), .specific(["a"])), ]) let result = resolver.solve(constraints: dependencies) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because 'a' contains incompatible tools version (\( - ToolsVersion - .v3 - )) and root depends on 'a' 3.2.0..<4.0.0. - """) + Dependencies could not be resolved because 'a' contains incompatible tools version (\(ToolsVersion.v3)) and root depends on 'a' 3.2.0..<4.0.0. + """) } func testIncompatibleToolsVersion5() throws { @@ -2934,17 +2614,14 @@ final class PubGrubDiagnosticsTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("3.2.0" ..< "4.0.0")), .specific(["a"])), + "a": (.versionSet(.range("3.2.0"..<"4.0.0")), .specific(["a"])), ]) let result = resolver.solve(constraints: dependencies) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because 'a' contains incompatible tools version (\( - ToolsVersion - .v5 - )) and root depends on 'a' 3.2.0..<4.0.0. - """) + Dependencies could not be resolved because 'a' contains incompatible tools version (\(ToolsVersion.v5)) and root depends on 'a' 3.2.0..<4.0.0. + """) } func testIncompatibleToolsVersion6() throws { @@ -2957,53 +2634,47 @@ final class PubGrubDiagnosticsTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("3.2.0" ..< "4.0.0")), .specific(["a"])), + "a": (.versionSet(.range("3.2.0"..<"4.0.0")), .specific(["a"])), ]) let result = resolver.solve(constraints: dependencies) XCTAssertEqual(result.errorMsg, """ - Dependencies could not be resolved because 'a' >= 3.2.1 contains incompatible tools version (\( - ToolsVersion - .v4 - )) and root depends on 'a' 3.2.0..<4.0.0. - 'a' 3.2.0 cannot be used because 'a' 3.2.0 depends on 'b' 1.0.0..<2.0.0. - 'b' >= 1.0.0 cannot be used because 'b' 1.0.0 contains incompatible tools version (\( - ToolsVersion - .v3 - )) and no versions of 'b' match the requirement 1.0.1..<2.0.0. - """) + Dependencies could not be resolved because 'a' >= 3.2.1 contains incompatible tools version (\(ToolsVersion.v4)) and root depends on 'a' 3.2.0..<4.0.0. + 'a' 3.2.0 cannot be used because 'a' 3.2.0 depends on 'b' 1.0.0..<2.0.0. + 'b' >= 1.0.0 cannot be used because 'b' 1.0.0 contains incompatible tools version (\(ToolsVersion.v3)) and no versions of 'b' match the requirement 1.0.1..<2.0.0. + """) } func testProductsCannotResolveToDifferentVersions() throws { try builder.serve("package", at: .unversioned, with: [ "package": [ "intermediate_a": (.versionSet(v1Range), .specific(["Intermediate A"])), - "intermediate_b": (.versionSet(v1Range), .specific(["Intermediate B"])), - ], + "intermediate_b": (.versionSet(v1Range), .specific(["Intermediate B"])) + ] ]) try builder.serve("intermediate_a", at: v1, with: [ "Intermediate A": [ - "transitive": (.versionSet(.exact(v1)), .specific(["Product A"])), - ], + "transitive": (.versionSet(.exact(v1)), .specific(["Product A"])) + ] ]) try builder.serve("intermediate_b", at: v1, with: [ "Intermediate B": [ - "transitive": (.versionSet(.exact(v1_1)), .specific(["Product B"])), - ], + "transitive": (.versionSet(.exact(v1_1)), .specific(["Product B"])) + ] ]) try builder.serve("transitive", at: v1, with: [ "Product A": [:], - "Product B": [:], + "Product B": [:] ]) try builder.serve("transitive", at: v1_1, with: [ "Product A": [:], - "Product B": [:], + "Product B": [:] ]) let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "package": (.unversioned, .everything), + "package": (.unversioned, .everything) ]) let result = resolver.solve(constraints: dependencies) @@ -3032,7 +2703,7 @@ final class PubGrubBacktrackTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["a"])), + "a": (.versionSet(.range("1.0.0"..<"3.0.0")), .specific(["a"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3045,14 +2716,14 @@ final class PubGrubBacktrackTests: XCTestCase { func testBacktrack2() throws { try builder.serve("a", at: v1) try builder.serve("a", at: "2.0.0", with: [ - "a": ["c": (.versionSet(.range("1.0.0" ..< "2.0.0")), .specific(["c"]))], + "a": ["c": (.versionSet(.range("1.0.0"..<"2.0.0")), .specific(["c"]))], ]) try builder.serve("b", at: "1.0.0", with: [ - "b": ["c": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["c"]))], + "b": ["c": (.versionSet(.range("2.0.0"..<"3.0.0")), .specific(["c"]))], ]) try builder.serve("b", at: "2.0.0", with: [ - "b": ["c": (.versionSet(.range("3.0.0" ..< "4.0.0")), .specific(["c"]))], + "b": ["c": (.versionSet(.range("3.0.0"..<"4.0.0")), .specific(["c"]))], ]) try builder.serve("c", at: "1.0.0") @@ -3061,8 +2732,8 @@ final class PubGrubBacktrackTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["a"])), - "b": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["b"])), + "a": (.versionSet(.range("1.0.0"..<"3.0.0")), .specific(["a"])), + "b": (.versionSet(.range("1.0.0"..<"3.0.0")), .specific(["b"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3076,18 +2747,18 @@ final class PubGrubBacktrackTests: XCTestCase { func testBacktrack3() throws { try builder.serve("a", at: "1.0.0", with: [ - "a": ["x": (.versionSet(.range("1.0.0" ..< "5.0.0")), .specific(["x"]))], + "a": ["x": (.versionSet(.range("1.0.0"..<"5.0.0")), .specific(["x"]))], ]) try builder.serve("b", at: "1.0.0", with: [ - "b": ["x": (.versionSet(.range("0.0.0" ..< "2.0.0")), .specific(["x"]))], + "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: [ "c": [ - "a": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["a"])), - "b": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["b"])), - ], + "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") @@ -3101,8 +2772,8 @@ final class PubGrubBacktrackTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "c": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["c"])), - "y": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["y"])), + "c": (.versionSet(.range("1.0.0"..<"3.0.0")), .specific(["c"])), + "y": (.versionSet(.range("2.0.0"..<"3.0.0")), .specific(["y"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3115,18 +2786,18 @@ final class PubGrubBacktrackTests: XCTestCase { func testBacktrack4() throws { try builder.serve("a", at: "1.0.0", with: [ - "a": ["x": (.versionSet(.range("1.0.0" ..< "5.0.0")), .specific(["x"]))], + "a": ["x": (.versionSet(.range("1.0.0"..<"5.0.0")), .specific(["x"]))], ]) try builder.serve("b", at: "1.0.0", with: [ - "b": ["x": (.versionSet(.range("0.0.0" ..< "2.0.0")), .specific(["x"]))], + "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: [ "c": [ - "a": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["a"])), - "b": (.versionSet(.range("0.0.0" ..< "5.0.0")), .specific(["b"])), - ], + "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") @@ -3140,8 +2811,8 @@ final class PubGrubBacktrackTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "c": (.versionSet(.range("1.0.0" ..< "3.0.0")), .specific(["c"])), - "y": (.versionSet(.range("2.0.0" ..< "3.0.0")), .specific(["y"])), + "c": (.versionSet(.range("1.0.0"..<"3.0.0")), .specific(["c"])), + "y": (.versionSet(.range("2.0.0"..<"3.0.0")), .specific(["y"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3164,7 +2835,7 @@ final class PubGrubBacktrackTests: XCTestCase { ]) try builder.serve("bar", at: "1.0.0", with: [ - "bar": ["baz": (.versionSet(.range("0.0.0" ..< "3.0.0")), .specific(["baz"]))], + "bar": ["baz": (.versionSet(.range("0.0.0"..<"3.0.0")), .specific(["baz"]))], ]) try builder.serve("bar", at: "2.0.0", with: [ "bar": ["baz": (.versionSet(.exact("3.0.0")), .specific(["baz"]))], @@ -3177,7 +2848,7 @@ final class PubGrubBacktrackTests: XCTestCase { let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "foo": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["foo"])), + "foo": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["foo"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3196,16 +2867,16 @@ final class PubGrubBacktrackTests: XCTestCase { "b": ["a": (.versionSet(.exact("1.0.0")), .specific(["a"]))], ]) try builder.serve("c", at: "1.0.0", with: [ - "c": ["b": (.versionSet(.range("0.0.0" ..< "3.0.0")), .specific(["b"]))], + "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") let resolver = builder.create() let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["a"])), - "c": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["c"])), - "d": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["d"])), + "a": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["a"])), + "c": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["c"])), + "d": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["d"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3225,21 +2896,18 @@ final class PubGrubBacktrackTests: XCTestCase { "b": ["a": (.versionSet(.exact("1.0.0")), .specific(["a"]))], ]) try builder.serve("c", at: "1.5.2", with: [ - "c": ["b": (.versionSet(.range("0.0.0" ..< "3.0.0")), .specific(["b"]))], + "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") let observability = ObservabilitySystem.makeForTesting() - let resolver = builder.create( - pins: [:], - delegate: ObservabilityDependencyResolverDelegate(observabilityScope: observability.topScope) - ) + let resolver = builder.create(pins: [:], delegate: ObservabilityDependencyResolverDelegate(observabilityScope: observability.topScope)) let dependencies = try builder.create(dependencies: [ - "a": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["a"])), - "c": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["c"])), - "d": (.versionSet(.range("1.0.0" ..< "4.0.0")), .specific(["d"])), + "a": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["a"])), + "c": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["c"])), + "d": (.versionSet(.range("1.0.0"..<"4.0.0")), .specific(["d"])), ]) let result = resolver.solve(constraints: dependencies) @@ -3253,28 +2921,16 @@ final class PubGrubBacktrackTests: XCTestCase { observability.diagnostics.forEach { print("\($0)") } - XCTAssertTrue( - observability.diagnostics - .contains(where: { $0.message == "[DependencyResolver] resolved 'a' @ '1.0.0'" }) - ) - XCTAssertTrue( - observability.diagnostics - .contains(where: { $0.message == "[DependencyResolver] resolved 'b' @ '1.0.1'" }) - ) - XCTAssertTrue( - observability.diagnostics - .contains(where: { $0.message == "[DependencyResolver] resolved 'c' @ '1.5.2'" }) - ) - XCTAssertTrue( - observability.diagnostics - .contains(where: { $0.message == "[DependencyResolver] resolved 'd' @ '2.3.0'" }) - ) + XCTAssertTrue(observability.diagnostics.contains(where: { $0.message == "[DependencyResolver] resolved 'a' @ '1.0.0'" })) + XCTAssertTrue(observability.diagnostics.contains(where: { $0.message == "[DependencyResolver] resolved 'b' @ '1.0.1'" })) + XCTAssertTrue(observability.diagnostics.contains(where: { $0.message == "[DependencyResolver] resolved 'c' @ '1.5.2'" })) + XCTAssertTrue(observability.diagnostics.contains(where: { $0.message == "[DependencyResolver] resolved 'd' @ '2.3.0'" })) } } -extension PinsStore.PinState { +fileprivate extension PinsStore.PinState { /// Creates a checkout state with the given version and a mocked revision. - fileprivate static func version(_ version: Version) -> Self { + static func version(_ version: Version) -> Self { .version(version, revision: .none) } } @@ -3294,13 +2950,9 @@ private func AssertBindings( pkg.identity != binding.package.identity }) } - .map(\.package.identity) + .map { $0.package.identity } - XCTFail( - "Unexpected binding(s) found for \(unexpectedBindings.map(\.description).joined(separator: ", ")).", - file: file, - line: line - ) + XCTFail("Unexpected binding(s) found for \(unexpectedBindings.map { $0.description }.joined(separator: ", ")).", file: file, line: line) } for package in packages { guard let binding = bindings.first(where: { $0.package.identity == package.identity }) else { @@ -3309,11 +2961,7 @@ private func AssertBindings( } if binding.boundVersion != package.version { - XCTFail( - "Expected \(package.version) for \(package.identity), found \(binding.boundVersion) instead.", - file: file, - line: line - ) + XCTFail("Expected \(package.version) for \(package.identity), found \(binding.boundVersion) instead.", file: file, line: line) } } } @@ -3351,11 +2999,7 @@ private func AssertError( // FIXME: this is not thread-safe public class MockContainer: PackageContainer { - public typealias Dependency = ( - container: PackageReference, - requirement: PackageRequirement, - productFilter: ProductFilter - ) + public typealias Dependency = (container: PackageReference, requirement: PackageRequirement, productFilter: ProductFilter) public var package: PackageReference var manifestName: PackageReference? @@ -3365,7 +3009,7 @@ public class MockContainer: PackageContainer { public var unversionedDeps: [PackageContainerConstraint] = [] /// The list of versions that have incompatible tools version. - var toolsVersion: ToolsVersion = .current + var toolsVersion: ToolsVersion = ToolsVersion.current var versionsToolsVersions = [Version: ToolsVersion]() private var _versions: [BoundVersion] @@ -3380,7 +3024,7 @@ public class MockContainer: PackageContainer { return versions } - public func versionsAscending() throws -> [Version] { + public func versionsAscending() throws -> [Version] { var versions: [Version] = [] for version in self._versions { guard case .version(let v) = version else { continue } @@ -3407,17 +3051,11 @@ public class MockContainer: PackageContainer { return version } - public func getDependencies( - at version: Version, - productFilter: ProductFilter - ) throws -> [PackageContainerConstraint] { - try self.getDependencies(at: version.description, productFilter: productFilter) + public func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { + return try getDependencies(at: version.description, productFilter: productFilter) } - public func getDependencies( - at revision: String, - productFilter: ProductFilter - ) throws -> [PackageContainerConstraint] { + public func getDependencies(at revision: String, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { guard let revisionDependencies = dependencies[revision] else { throw _MockLoadingError.unknownRevision } @@ -3425,18 +3063,18 @@ public class MockContainer: PackageContainer { for (product, productDependencies) in revisionDependencies where productFilter.contains(product) { filteredDependencies.append(contentsOf: productDependencies) } - return filteredDependencies.map { value in + return filteredDependencies.map({ value in let (package, requirement, filter) = value return PackageContainerConstraint(package: package, requirement: requirement, products: filter) - } + }) } public func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint] { // FIXME: This is messy, remove unversionedDeps property. - if !self.unversionedDeps.isEmpty { - return self.unversionedDeps + if !unversionedDeps.isEmpty { + return unversionedDeps } - return try self.getDependencies(at: PackageRequirement.unversioned.description, productFilter: productFilter) + return try getDependencies(at: PackageRequirement.unversioned.description, productFilter: productFilter) } public func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { @@ -3459,19 +3097,11 @@ public class MockContainer: PackageContainer { public convenience init( package: PackageReference, - unversionedDependencies: [( - package: PackageReference, - requirement: PackageRequirement, - productFilter: ProductFilter - )] + unversionedDependencies: [(package: PackageReference, requirement: PackageRequirement, productFilter: ProductFilter)] ) { self.init(package: package) self.unversionedDeps = unversionedDependencies - .map { PackageContainerConstraint( - package: $0.package, - requirement: $0.requirement, - products: $0.productFilter - ) } + .map { PackageContainerConstraint(package: $0.package, requirement: $0.requirement, products: $0.productFilter) } } public convenience init( @@ -3480,17 +3110,16 @@ public class MockContainer: PackageContainer { package: PackageReference, requirement: VersionSetSpecifier, productFilter: ProductFilter - )]]] - ) { + )]]]) { var dependencies: [String: [String: [Dependency]]] = [:] for (version, productDependencies) in dependenciesByVersion { if dependencies[version.description] == nil { dependencies[version.description] = [:] } for (product, deps) in productDependencies { - dependencies[version.description, default: [:]][product] = deps.map { + dependencies[version.description, default: [:]][product] = deps.map({ ($0.package, .versionSet($0.requirement), $0.productFilter) - } + }) } } self.init(package: package, dependencies: dependencies) @@ -3515,12 +3144,13 @@ public enum _MockLoadingError: Error { } public struct MockProvider: PackageContainerProvider { + public let containers: [MockContainer] public let containersByIdentifier: [PackageReference: MockContainer] public init(containers: [MockContainer]) { self.containers = containers - self.containersByIdentifier = Dictionary(uniqueKeysWithValues: containers.map { ($0.package, $0) }) + self.containersByIdentifier = Dictionary(uniqueKeysWithValues: containers.map({ ($0.package, $0) })) } public func getContainer( @@ -3528,15 +3158,11 @@ public struct MockProvider: PackageContainerProvider { 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) - ) + completion(self.containersByIdentifier[package].map{ .success($0) } ?? + .failure(_MockLoadingError.unknownModule)) } } } @@ -3549,10 +3175,7 @@ class DependencyGraphBuilder { if let reference = self.references[packageName] { return reference } - let newReference = try PackageReference.localSourceControl( - identity: .plain(packageName), - path: .init(validating: "/\(packageName)") - ) + let newReference = PackageReference.localSourceControl(identity: .plain(packageName), path: try .init(validating: "/\(packageName)")) self.references[packageName] = newReference return newReference } @@ -3560,12 +3183,9 @@ class DependencyGraphBuilder { func create( dependencies: OrderedCollections.OrderedDictionary ) throws -> [PackageContainerConstraint] { - var refDependencies = OrderedCollections.OrderedDictionary< - PackageReference, - (PackageRequirement, ProductFilter) - >() + var refDependencies = OrderedCollections.OrderedDictionary() for dependency in dependencies { - try refDependencies[self.reference(for: dependency.key)] = dependency.value + try refDependencies[reference(for: dependency.key)] = dependency.value } return self.create(dependencies: refDependencies) } @@ -3573,7 +3193,7 @@ class DependencyGraphBuilder { func create( dependencies: OrderedCollections.OrderedDictionary ) -> [PackageContainerConstraint] { - dependencies.map { + return dependencies.map { PackageContainerConstraint(package: $0, requirement: $1.0, products: $1.1) } } @@ -3582,22 +3202,16 @@ class DependencyGraphBuilder { _ package: String, at versions: [Version], toolsVersion: ToolsVersion? = nil, - with dependencies: KeyValuePairs< - String, - OrderedCollections.OrderedDictionary - > = [:] + with dependencies: KeyValuePairs> = [:] ) throws { - try self.serve(package, at: versions.map { .version($0) }, toolsVersion: toolsVersion, with: dependencies) + try self.serve(package, at: versions.map{ .version($0) }, toolsVersion: toolsVersion, with: dependencies) } func serve( _ package: String, at version: Version, toolsVersion: ToolsVersion? = nil, - with dependencies: KeyValuePairs< - String, - OrderedCollections.OrderedDictionary - > = [:] + with dependencies: KeyValuePairs> = [:] ) throws { try self.serve(package, at: .version(version), toolsVersion: toolsVersion, with: dependencies) } @@ -3606,10 +3220,7 @@ class DependencyGraphBuilder { _ package: String, at versions: [BoundVersion], toolsVersion: ToolsVersion? = nil, - with dependencies: KeyValuePairs< - String, - OrderedCollections.OrderedDictionary - > = [:] + with dependencies: KeyValuePairs> = [:] ) throws { let packageReference = try reference(for: package) try self.serve( @@ -3624,10 +3235,7 @@ class DependencyGraphBuilder { _ package: String, at version: BoundVersion, toolsVersion: ToolsVersion? = nil, - with dependencies: KeyValuePairs< - String, - OrderedCollections.OrderedDictionary - > = [:] + with dependencies: KeyValuePairs> = [:] ) throws { let packageReference = try reference(for: package) try self.serve( @@ -3642,13 +3250,10 @@ class DependencyGraphBuilder { _ packageReference: PackageReference, at versions: [BoundVersion], toolsVersion: ToolsVersion? = nil, - with dependencies: KeyValuePairs< - String, - OrderedCollections.OrderedDictionary - > = [:] + with dependencies: KeyValuePairs> = [:] ) throws { for version in versions { - try self.serve(packageReference, at: version, toolsVersion: toolsVersion, with: dependencies) + try serve(packageReference, at: version, toolsVersion: toolsVersion, with: dependencies) } } @@ -3656,13 +3261,9 @@ class DependencyGraphBuilder { _ packageReference: PackageReference, at version: BoundVersion, toolsVersion: ToolsVersion? = nil, - with dependencies: KeyValuePairs< - String, - OrderedCollections.OrderedDictionary - > = [:] + with dependencies: KeyValuePairs> = [:] ) throws { - let container = self - .containers[packageReference.identity.description] ?? MockContainer(package: packageReference) + let container = self.containers[packageReference.identity.description] ?? MockContainer(package: packageReference) if case .version(let v) = version { container.versionsToolsVersions[v] = toolsVersion ?? container.toolsVersion @@ -3674,8 +3275,8 @@ class DependencyGraphBuilder { container.dependencies[version.description] = [:] } for (product, filteredDependencies) in dependencies { - let packageDependencies: [MockContainer.Dependency] = filteredDependencies.map { - (container: $0, requirement: $1.0, productFilter: $1.1) + let packageDependencies: [MockContainer.Dependency] = try filteredDependencies.map { + (container: try reference(for: $0), requirement: $1.0, productFilter: $1.1) } container.dependencies[version.description, default: [:]][product, default: []] += packageDependencies } @@ -3685,38 +3286,24 @@ class DependencyGraphBuilder { /// Creates a pins store with the given pins. func create(pinsStore pins: [String: (PinsStore.PinState, ProductFilter)]) throws -> PinsStore { let fs = InMemoryFileSystem() - let store = try! PinsStore( - pinsFile: "/tmp/Package.resolved", - workingDirectory: .root, - fileSystem: fs, - mirrors: .init() - ) + let store = try! PinsStore(pinsFile: "/tmp/Package.resolved", workingDirectory: .root, fileSystem: fs, mirrors: .init()) for (package, pin) in pins { - try store.pin(packageRef: self.reference(for: package), state: pin.0) + store.pin(packageRef: try reference(for: package), state: pin.0) } try! store.saveState(toolsVersion: ToolsVersion.current, originHash: .none) return store } - func create( - pins: PinsStore.Pins = [:], - availableLibraries: [LibraryMetadata] = [], - delegate: DependencyResolverDelegate? = .none - ) -> PubGrubDependencyResolver { + + func create(pins: PinsStore.Pins = [:], delegate: DependencyResolverDelegate? = .none) -> PubGrubDependencyResolver { defer { self.containers = [:] self.references = [:] } let provider = MockProvider(containers: Array(self.containers.values)) - return PubGrubDependencyResolver( - provider: provider, - pins: pins, - availableLibraries: availableLibraries, - observabilityScope: ObservabilitySystem.NOOP, - delegate: delegate - ) + return PubGrubDependencyResolver(provider :provider, pins: pins, observabilityScope: ObservabilitySystem.NOOP, delegate: delegate) } } @@ -3745,35 +3332,26 @@ extension Term { } else if value.contains("^") { components = value.split(separator: "^").map(String.init) let upperMajor = Int(String(components[1].split(separator: ".").first!))! + 1 - requirement = - .versionSet(.range( - Version(stringLiteral: components[1]) ..< - Version(stringLiteral: "\(upperMajor).0.0") - )) + requirement = .versionSet(.range(Version(stringLiteral: components[1]).. Date: Fri, 19 Jul 2024 15:44:13 -0700 Subject: [PATCH 3/4] Revert "Make `PackageModel` resources optional (#7348)" This reverts commit 9c6493f76dbcb57f5482d39140aba06bfcf5a1e4. --- Package.swift | 17 +++----------- Sources/PackageModel/UserToolchain.swift | 29 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Package.swift b/Package.swift index 32684b2293c..e804f4dbac0 100644 --- a/Package.swift +++ b/Package.swift @@ -82,18 +82,6 @@ let systemSQLitePkgConfig: String? = "sqlite3" */ let autoProducts = [swiftPMProduct, swiftPMDataModelProduct] -let packageModelResourcesSettings: [SwiftSetting] -let packageModelResources: [Resource] -if ProcessInfo.processInfo.environment["SWIFTPM_USE_LIBRARIES_METADATA"] == nil { - packageModelResources = [] - packageModelResourcesSettings = [.define("SKIP_RESOURCE_SUPPORT")] -} else { - packageModelResources = [ - .copy("InstalledLibrariesSupport/provided-libraries.json"), - ] - packageModelResourcesSettings = [] -} - let package = Package( name: "SwiftPM", platforms: [ @@ -246,8 +234,9 @@ let package = Package( name: "PackageModel", dependencies: ["Basics"], exclude: ["CMakeLists.txt", "README.md"], - resources: packageModelResources, - swiftSettings: packageModelResourcesSettings + resources: [ + .copy("InstalledLibrariesSupport/provided-libraries.json"), + ] ), .target( diff --git a/Sources/PackageModel/UserToolchain.swift b/Sources/PackageModel/UserToolchain.swift index b1f0a79aec2..77e3ec9631a 100644 --- a/Sources/PackageModel/UserToolchain.swift +++ b/Sources/PackageModel/UserToolchain.swift @@ -590,13 +590,28 @@ public final class UserToolchain: Toolchain { if let customProvidedLibraries { self.providedLibraries = customProvidedLibraries } else { - let path = swiftCompilerPath.parentDirectory.parentDirectory.appending(components: [ - "share", "pm", "provided-libraries.json", - ]) - self.providedLibraries = try Self.loadJSONResource( - config: path, - type: [LibraryMetadata].self, - default: []) + // When building with CMake, we need to skip resource support. + #if SKIP_RESOURCE_SUPPORT + let path = self.swiftCompilerPath.parentDirectory.parentDirectory.appending(components: ["share", "pm", "provided-libraries.json"]) + #else + let path: AbsolutePath + if let developmentPath = Bundle.module.path(forResource: "provided-libraries", ofType: "json") { + // During development, we should be able to find the metadata file using `Bundle.module`. + path = try AbsolutePath(validating: developmentPath) + } else { + // When deployed, we can find the metadata file in the toolchain. + path = self.swiftCompilerPath.parentDirectory.parentDirectory.appending(components: ["share", "pm", "provided-libraries.json"]) + } + #endif + if localFileSystem.exists(path) { + self.providedLibraries = try JSONDecoder.makeWithDefaults().decode( + path: path, + fileSystem: localFileSystem, + as: [LibraryMetadata].self + ) + } else { + self.providedLibraries = [] + } } // Use the triple from Swift SDK or compute the host triple using swiftc. From 6aad8c541e4261a033fdc7b04185e4a99fdd8770 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 Jul 2024 16:14:07 -0700 Subject: [PATCH 4/4] Revert "Support for prebuilt packages in the SDK (#7337)" This reverts commit cae580e9a2c7d32ece1ad08c7e802c3bc27dc32a. --- Package.swift | 5 +- Sources/Build/BuildOperation.swift | 91 --------------- Sources/CMakeLists.txt | 1 - .../PackageCommands/EditCommands.swift | 1 - Sources/CoreCommands/BuildSystemSupport.swift | 2 - Sources/CoreCommands/SwiftCommandState.swift | 3 +- Sources/PackageGraph/CMakeLists.txt | 1 - .../PackageGraph/ModulesGraph+Loading.swift | 45 +++----- Sources/PackageGraph/ModulesGraph.swift | 1 - .../PrebuiltPackageContainer.swift | 69 ----------- .../PubGrub/ContainerProvider.swift | 27 +---- .../PubGrub/PubGrubDependencyResolver.swift | 109 ++++-------------- Sources/PackageModel/CMakeLists.txt | 1 - .../LibraryMetadata.swift | 54 --------- Sources/PackageModel/Toolchain.swift | 3 - Sources/PackageModel/UserToolchain.swift | 30 ----- .../ResolverPrecomputationProvider.swift | 16 +-- .../Workspace/Workspace+Dependencies.swift | 60 +--------- Sources/Workspace/Workspace+Editing.swift | 3 - Sources/Workspace/Workspace+Manifests.swift | 72 +++--------- Sources/Workspace/Workspace.swift | 13 --- .../_InternalTestSupport/MockWorkspace.swift | 23 +--- Sources/swift-bootstrap/main.swift | 3 - Tests/BuildTests/BuildOperationTests.swift | 43 ------- Tests/CommandsTests/PackageCommandTests.swift | 6 +- Tests/FunctionalTests/PluginTests.swift | 24 +--- .../PackageGraphPerfTests.swift | 1 - Tests/PackageGraphTests/PubgrubTests.swift | 41 ------- .../PluginInvocationTests.swift | 35 +----- Utilities/provided-libraries.json | 16 --- 30 files changed, 83 insertions(+), 716 deletions(-) delete mode 100644 Sources/PackageGraph/PrebuiltPackageContainer.swift delete mode 100644 Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift delete mode 100644 Utilities/provided-libraries.json diff --git a/Package.swift b/Package.swift index e804f4dbac0..accacb33534 100644 --- a/Package.swift +++ b/Package.swift @@ -233,10 +233,7 @@ let package = Package( /** Primitive Package model objects */ name: "PackageModel", dependencies: ["Basics"], - exclude: ["CMakeLists.txt", "README.md"], - resources: [ - .copy("InstalledLibrariesSupport/provided-libraries.json"), - ] + exclude: ["CMakeLists.txt", "README.md"] ), .target( diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index d6e8e313184..a38c95c3cac 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -195,12 +195,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS /// Alternative path to search for pkg-config `.pc` files. private let pkgConfigDirectories: [AbsolutePath] - /// Map of dependency package identities by root packages that depend on them. - private let dependenciesByRootPackageIdentity: [PackageIdentity: [PackageIdentity]] - - /// Map of root package identities by target names which are declared in them. - private let rootPackageIdentityByTargetName: [String: PackageIdentity] - public convenience init( productsBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters, @@ -210,8 +204,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS scratchDirectory: AbsolutePath, additionalFileRules: [FileRuleDescription], pkgConfigDirectories: [AbsolutePath], - dependenciesByRootPackageIdentity: [PackageIdentity: [PackageIdentity]], - targetsByRootPackageIdentity: [PackageIdentity: [String]], outputStream: OutputByteStream, logLevel: Basics.Diagnostic.Severity, fileSystem: Basics.FileSystem, @@ -227,8 +219,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS traitConfiguration: nil, additionalFileRules: additionalFileRules, pkgConfigDirectories: pkgConfigDirectories, - dependenciesByRootPackageIdentity: dependenciesByRootPackageIdentity, - targetsByRootPackageIdentity: targetsByRootPackageIdentity, outputStream: outputStream, logLevel: logLevel, fileSystem: fileSystem, @@ -246,8 +236,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS traitConfiguration: TraitConfiguration?, additionalFileRules: [FileRuleDescription], pkgConfigDirectories: [AbsolutePath], - dependenciesByRootPackageIdentity: [PackageIdentity: [PackageIdentity]], - targetsByRootPackageIdentity: [PackageIdentity: [String]], outputStream: OutputByteStream, logLevel: Basics.Diagnostic.Severity, fileSystem: Basics.FileSystem, @@ -276,8 +264,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS self.additionalFileRules = additionalFileRules self.pluginConfiguration = pluginConfiguration self.pkgConfigDirectories = pkgConfigDirectories - self.dependenciesByRootPackageIdentity = dependenciesByRootPackageIdentity - self.rootPackageIdentityByTargetName = (try? Dictionary(throwingUniqueKeysWithValues: targetsByRootPackageIdentity.lazy.flatMap { e in e.value.map { ($0, e.key) } })) ?? [:] } public func getPackageGraph() throws -> ModulesGraph { @@ -399,81 +385,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS } } - private static var didEmitUnexpressedDependencies = false - - private func detectUnexpressedDependencies() { - return self.detectUnexpressedDependencies( - // Note: once we switch from the toolchain global metadata, we will have to ensure we can match the right metadata used during the build. - availableLibraries: self.config.toolchain(for: .target).providedLibraries, - targetDependencyMap: self.buildDescription.targetDependencyMap - ) - } - - // TODO: Currently this function will only match frameworks. - func detectUnexpressedDependencies( - availableLibraries: [LibraryMetadata], - targetDependencyMap: [String: [String]]? - ) { - // Ensure we only emit these once, regardless of how many builds are being done. - guard !Self.didEmitUnexpressedDependencies else { - return - } - Self.didEmitUnexpressedDependencies = true - - let availableFrameworks = Dictionary(uniqueKeysWithValues: availableLibraries.compactMap { - if let identity = Set($0.identities.map(\.identity)).spm_only { - return ("\($0.productName!).framework", identity) - } else { - return nil - } - }) - - targetDependencyMap?.keys.forEach { targetName in - let c99name = targetName.spm_mangledToC99ExtendedIdentifier() - // Since we're analysing post-facto, we don't know which parameters are the correct ones. - let possibleTempsPaths = [BuildParameters.Destination]([.target, .host]).map { - self.config.buildPath(for: $0).appending(component: "\(c99name).build") - } - - let usedSDKDependencies: [String] = Set(possibleTempsPaths).flatMap { possibleTempsPath in - guard let contents = try? self.fileSystem.readFileContents( - possibleTempsPath.appending(component: "\(c99name).d") - ) else { - return [String]() - } - - // FIXME: We need a real makefile deps parser here... - let deps = contents.description.split(whereSeparator: { $0.isWhitespace }) - return deps.filter { - !$0.hasPrefix(possibleTempsPath.parentDirectory.pathString) - }.compactMap { - try? AbsolutePath(validating: String($0)) - }.compactMap { - return $0.components.first(where: { $0.hasSuffix(".framework") }) - } - } - - let dependencies: [PackageIdentity] - if let rootPackageIdentity = self.rootPackageIdentityByTargetName[targetName] { - dependencies = self.dependenciesByRootPackageIdentity[rootPackageIdentity] ?? [] - } else { - dependencies = [] - } - - Set(usedSDKDependencies).forEach { - if availableFrameworks.keys.contains($0) { - if let availableFrameworkPackageIdentity = availableFrameworks[$0], !dependencies.contains( - availableFrameworkPackageIdentity - ) { - observabilityScope.emit( - warning: "target '\(targetName)' has an unexpressed depedency on '\(availableFrameworkPackageIdentity)'" - ) - } - } - } - } - } - /// Perform a build using the given build description and subset. public func build(subset: BuildSubset) throws { guard !self.config.shouldSkipBuilding(for: .target) else { @@ -514,8 +425,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS let duration = buildStartTime.distance(to: .now()) - self.detectUnexpressedDependencies() - let subsetDescriptor: String? switch subset { case .product(let productName, _): diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 279084bb5c0..e0354016188 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -6,7 +6,6 @@ # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for Swift project authors -add_compile_definitions(SKIP_RESOURCE_SUPPORT) add_compile_definitions(USE_IMPL_ONLY_IMPORTS) add_subdirectory(Basics) diff --git a/Sources/Commands/PackageCommands/EditCommands.swift b/Sources/Commands/PackageCommands/EditCommands.swift index 42195f7037d..ff199a05101 100644 --- a/Sources/Commands/PackageCommands/EditCommands.swift +++ b/Sources/Commands/PackageCommands/EditCommands.swift @@ -72,7 +72,6 @@ extension SwiftPackageCommand { packageName: packageName, forceRemove: shouldForceRemove, root: swiftCommandState.getWorkspaceRoot(), - availableLibraries: swiftCommandState.getHostToolchain().providedLibraries, observabilityScope: swiftCommandState.observabilityScope ) } diff --git a/Sources/CoreCommands/BuildSystemSupport.swift b/Sources/CoreCommands/BuildSystemSupport.swift index 3ea89cf2f49..ced95ea1148 100644 --- a/Sources/CoreCommands/BuildSystemSupport.swift +++ b/Sources/CoreCommands/BuildSystemSupport.swift @@ -56,8 +56,6 @@ private struct NativeBuildSystemFactory: BuildSystemFactory { traitConfiguration: traitConfiguration, additionalFileRules: FileRuleDescription.swiftpmFileTypes, pkgConfigDirectories: self.swiftCommandState.options.locations.pkgConfigDirectories, - dependenciesByRootPackageIdentity: rootPackageInfo.dependencies, - targetsByRootPackageIdentity: rootPackageInfo.targets, outputStream: outputStream ?? self.swiftCommandState.outputStream, logLevel: logLevel ?? self.swiftCommandState.logLevel, fileSystem: self.swiftCommandState.fileSystem, diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index 5e838d45cad..0d838e9afa1 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -53,7 +53,7 @@ import var TSCBasic.stderrStream import class TSCBasic.TerminalController import class TSCBasic.ThreadSafeOutputByteStream -import TSCUtility // cannot be scoped because of `String.spm_mangleToC99ExtendedIdentifier()` +import var TSCUtility.verbosity typealias Diagnostic = Basics.Diagnostic @@ -503,6 +503,7 @@ public final class SwiftCommandState { return (identities, targets) } + private func getEditsDirectory() throws -> AbsolutePath { // TODO: replace multiroot-data-file with explicit overrides if let multiRootPackageDataFile = options.locations.multirootPackageDataFile { diff --git a/Sources/PackageGraph/CMakeLists.txt b/Sources/PackageGraph/CMakeLists.txt index f22cc9fbf31..2fcc29a6279 100644 --- a/Sources/PackageGraph/CMakeLists.txt +++ b/Sources/PackageGraph/CMakeLists.txt @@ -19,7 +19,6 @@ add_library(PackageGraph PackageGraphRoot.swift PackageModel+Extensions.swift PackageRequirement.swift - PrebuiltPackageContainer.swift PinsStore.swift TraitConfiguration.swift Resolution/PubGrub/Assignment.swift diff --git a/Sources/PackageGraph/ModulesGraph+Loading.swift b/Sources/PackageGraph/ModulesGraph+Loading.swift index de5c11a18dc..063e44badb0 100644 --- a/Sources/PackageGraph/ModulesGraph+Loading.swift +++ b/Sources/PackageGraph/ModulesGraph+Loading.swift @@ -34,7 +34,6 @@ extension ModulesGraph { customPlatformsRegistry: PlatformRegistry? = .none, customXCTestMinimumDeploymentTargets: [PackageModel.Platform: PlatformVersion]? = .none, testEntryPointPath: AbsolutePath? = nil, - availableLibraries: [LibraryMetadata], fileSystem: FileSystem, observabilityScope: ObservabilityScope, productsFilter: ((Product) -> Bool)? = nil, @@ -249,7 +248,6 @@ extension ModulesGraph { unsafeAllowedPackages: unsafeAllowedPackages, platformRegistry: customPlatformsRegistry ?? .default, platformVersionProvider: platformVersionProvider, - availableLibraries: [], fileSystem: fileSystem, observabilityScope: observabilityScope, productsFilter: productsFilter, @@ -381,7 +379,6 @@ private func createResolvedPackages( unsafeAllowedPackages: Set, platformRegistry: PlatformRegistry, platformVersionProvider: PlatformVersionProvider, - availableLibraries: [LibraryMetadata], fileSystem: FileSystem, observabilityScope: ObservabilityScope, productsFilter: ((Product) -> Bool)?, @@ -684,32 +681,26 @@ private func createResolvedPackages( t.name != productRef.name } - let identitiesAvailableInSDK = availableLibraries.flatMap { $0.identities.map { $0.identity } } - // TODO: Do we have to care about "name" vs. identity here? - if let name = productRef.package, identitiesAvailableInSDK.contains(PackageIdentity.plain(name)) { - // Do not emit any diagnostic. - } else { - // Find a product name from the available product dependencies that is most similar to the required product name. - let bestMatchedProductName = bestMatch(for: productRef.name, from: Array(allModuleNames)) - var packageContainingBestMatchedProduct: String? - if let bestMatchedProductName, productRef.name == bestMatchedProductName { - let dependentPackages = packageBuilder.dependencies.map(\.package) - for p in dependentPackages where p.modules.contains(where: { $0.name == bestMatchedProductName }) { - packageContainingBestMatchedProduct = p.identity.description - break - } + // Find a product name from the available product dependencies that is most similar to the required product name. + let bestMatchedProductName = bestMatch(for: productRef.name, from: Array(allModuleNames)) + var packageContainingBestMatchedProduct: String? + if let bestMatchedProductName, productRef.name == bestMatchedProductName { + let dependentPackages = packageBuilder.dependencies.map(\.package) + for p in dependentPackages where p.modules.contains(where: { $0.name == bestMatchedProductName }) { + packageContainingBestMatchedProduct = p.identity.description + break } - let error = PackageGraphError.productDependencyNotFound( - package: package.identity.description, - moduleName: moduleBuilder.module.name, - dependencyProductName: productRef.name, - dependencyPackageName: productRef.package, - dependencyProductInDecl: !declProductsAsDependency.isEmpty, - similarProductName: bestMatchedProductName, - packageContainingSimilarProduct: packageContainingBestMatchedProduct - ) - packageObservabilityScope.emit(error) } + let error = PackageGraphError.productDependencyNotFound( + package: package.identity.description, + moduleName: moduleBuilder.module.name, + dependencyProductName: productRef.name, + dependencyPackageName: productRef.package, + dependencyProductInDecl: !declProductsAsDependency.isEmpty, + similarProductName: bestMatchedProductName, + packageContainingSimilarProduct: packageContainingBestMatchedProduct + ) + packageObservabilityScope.emit(error) } continue } diff --git a/Sources/PackageGraph/ModulesGraph.swift b/Sources/PackageGraph/ModulesGraph.swift index 5237de38b2d..7b12624a2fe 100644 --- a/Sources/PackageGraph/ModulesGraph.swift +++ b/Sources/PackageGraph/ModulesGraph.swift @@ -553,7 +553,6 @@ public func loadModulesGraph( shouldCreateMultipleTestProducts: shouldCreateMultipleTestProducts, createREPLProduct: createREPLProduct, customXCTestMinimumDeploymentTargets: customXCTestMinimumDeploymentTargets, - availableLibraries: [], fileSystem: fileSystem, observabilityScope: observabilityScope, productsFilter: nil, diff --git a/Sources/PackageGraph/PrebuiltPackageContainer.swift b/Sources/PackageGraph/PrebuiltPackageContainer.swift deleted file mode 100644 index 870487d1781..00000000000 --- a/Sources/PackageGraph/PrebuiltPackageContainer.swift +++ /dev/null @@ -1,69 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 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 the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import Basics -import PackageModel -import struct TSCUtility.Version - -/// A package container that can represent a prebuilt library from a package. -public struct PrebuiltPackageContainer: PackageContainer { - private let chosenIdentity: LibraryMetadata.Identity - private let metadata: LibraryMetadata - - public init(metadata: LibraryMetadata) throws { - self.metadata = metadata - - // FIXME: Unclear what is supposed to happen if we have multiple identities. - if let identity = metadata.identities.first { - self.chosenIdentity = identity - } else { - let name = metadata.productName.map { "'\($0)' " } ?? "" - throw InternalError("provided library \(name)does not specifiy any identities") - } - } - - public var package: PackageReference { - return .init(identity: chosenIdentity.identity, kind: chosenIdentity.kind) - } - - public func isToolsVersionCompatible(at version: Version) -> Bool { - return true - } - - public func toolsVersion(for version: Version) throws -> ToolsVersion { - return .v4 - } - - public func toolsVersionsAppropriateVersionsDescending() throws -> [Version] { - return try versionsAscending() - } - - public func versionsAscending() throws -> [Version] { - return [.init(stringLiteral: metadata.version)] - } - - public func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { - return [] - } - - public func getDependencies(at revision: String, productFilter: ProductFilter) throws -> [PackageContainerConstraint] { - return [] - } - - public func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint] { - return [] - } - - public func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference { - return package - } -} diff --git a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift index 74735c9ccf9..f952a066a99 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/ContainerProvider.swift @@ -48,12 +48,6 @@ final class ContainerProvider { self.observabilityScope = observabilityScope } - func removeCachedContainers(for packages: [PackageReference]) { - packages.forEach { - self.containersCache[$0] = nil - } - } - /// Get a cached container for the given identifier, asserting / throwing if not found. func getCachedContainer(for package: PackageReference) throws -> PubGrubPackageContainer { guard let container = self.containersCache[package] else { @@ -65,7 +59,6 @@ final class ContainerProvider { /// Get the container for the given identifier, loading it if necessary. func getContainer( for package: PackageReference, - availableLibraries: [LibraryMetadata], completion: @escaping (Result) -> Void ) { // Return the cached container, if available. @@ -73,17 +66,6 @@ final class ContainerProvider { return completion(.success(container)) } - if let metadata = package.matchingPrebuiltLibrary(in: availableLibraries) { - do { - let prebuiltPackageContainer = try PrebuiltPackageContainer(metadata: metadata) - let pubGrubContainer = PubGrubPackageContainer(underlying: prebuiltPackageContainer, pins: self.pins) - self.containersCache[package] = pubGrubContainer - return completion(.success(pubGrubContainer)) - } catch { - return completion(.failure(error)) - } - } - if let prefetchSync = self.prefetches[package] { // If this container is already being prefetched, wait for that to complete prefetchSync.notify(queue: .sharedConcurrent) { @@ -93,7 +75,7 @@ final class ContainerProvider { } else { // if prefetch failed, remove from list of prefetches and try again self.prefetches[package] = nil - return self.getContainer(for: package, availableLibraries: availableLibraries, completion: completion) + return self.getContainer(for: package, completion: completion) } } } else { @@ -116,12 +98,9 @@ final class ContainerProvider { } /// Starts prefetching the given containers. - func prefetch(containers identifiers: [PackageReference], availableLibraries: [LibraryMetadata]) { - let filteredIdentifiers = identifiers.filter { - return $0.matchingPrebuiltLibrary(in: availableLibraries) == nil - } + func prefetch(containers identifiers: [PackageReference]) { // Process each container. - for identifier in filteredIdentifiers { + for identifier in identifiers { var needsFetching = false self.prefetches.memoize(identifier) { let group = DispatchGroup() diff --git a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift index 94b590cf96c..a627efba510 100644 --- a/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift +++ b/Sources/PackageGraph/Resolution/PubGrub/PubGrubDependencyResolver.swift @@ -140,11 +140,7 @@ public struct PubGrubDependencyResolver { } /// Execute the resolution algorithm to find a valid assignment of versions. - public func solve(constraints: [Constraint], availableLibraries: [LibraryMetadata], preferPrebuiltLibraries: Bool) -> Result<[DependencyResolverBinding], Error> { - if !preferPrebuiltLibraries { - self.provider.removeCachedContainers(for: availableLibraries.flatMap { $0.identities.map { $0.ref } }) - } - + public func solve(constraints: [Constraint]) -> Result<[DependencyResolverBinding], Error> { // the graph resolution root let root: DependencyResolutionNode if constraints.count == 1, let constraint = constraints.first, constraint.package.kind.isRoot { @@ -159,26 +155,11 @@ public struct PubGrubDependencyResolver { } do { - // Use empty `availableLibraries` for the rest of resolving if we don't prefer them. - let availableLibraries = preferPrebuiltLibraries ? availableLibraries : [] // strips state - let bindings = try self.solve(root: root, constraints: constraints, availableLibraries: availableLibraries).bindings.filter { - return $0.package.matchingPrebuiltLibrary(in: availableLibraries) == nil - } - return .success(bindings) + return .success(try 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, let incompatibilities = pubGrubError.incompatibilities { - let incompatiblePackages = incompatibilities.map({ $0.key.package }) - if incompatiblePackages.contains(where: { $0.matchingPrebuiltLibrary(in: availableLibraries) != nil }) { - return .failure( - PubgrubError.potentiallyUnresovableDueToPrebuiltLibrary( - incompatiblePackages, - pubGrubError.description - ) - ) - } - do { var builder = DiagnosticReportBuilder( root: root, @@ -199,12 +180,9 @@ public struct PubGrubDependencyResolver { /// 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. - internal func solve(root: DependencyResolutionNode, constraints: [Constraint], availableLibraries: [LibraryMetadata] = []) throws -> ( - bindings: [DependencyResolverBinding], - state: State - ) { + internal func solve(root: DependencyResolutionNode, constraints: [Constraint]) throws -> (bindings: [DependencyResolverBinding], state: State) { // first process inputs - let inputs = try self.processInputs(root: root, with: constraints, availableLibraries: availableLibraries) + let inputs = try self.processInputs(root: root, with: constraints) // Prefetch the containers if prefetching is enabled. if self.prefetchBasedOnResolvedFile { @@ -214,7 +192,7 @@ public struct PubGrubDependencyResolver { let pins = self.pins.values .map(\.packageRef) .filter { !inputs.overriddenPackages.keys.contains($0) } - self.provider.prefetch(containers: pins, availableLibraries: availableLibraries) + self.provider.prefetch(containers: pins) } let state = State(root: root, overriddenPackages: inputs.overriddenPackages) @@ -230,7 +208,7 @@ public struct PubGrubDependencyResolver { state.addIncompatibility(incompatibility, at: .topLevel) } - try self.run(state: state, availableLibraries: availableLibraries) + try self.run(state: state) let decisions = state.solution.assignments.filter(\.isDecision) var flattenedAssignments: [PackageReference: (binding: BoundVersion, products: ProductFilter)] = [:] @@ -250,7 +228,7 @@ public struct PubGrubDependencyResolver { let products = assignment.term.node.productFilter // TODO: replace with async/await when available - let container = try temp_await { provider.getContainer(for: assignment.term.node.package, availableLibraries: availableLibraries, completion: $0) } + let container = try temp_await { provider.getContainer(for: assignment.term.node.package, completion: $0) } let updatePackage = try container.underlying.loadPackageReference(at: boundVersion) if var existing = flattenedAssignments[updatePackage] { @@ -272,7 +250,7 @@ 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 { provider.getContainer(for: package, availableLibraries: availableLibraries, completion: $0) } + let container = try temp_await { provider.getContainer(for: package, completion: $0) } let updatePackage = try container.underlying.loadPackageReference(at: override.version) finalAssignments.append(.init( package: updatePackage, @@ -288,8 +266,7 @@ public struct PubGrubDependencyResolver { private func processInputs( root: DependencyResolutionNode, - with constraints: [Constraint], - availableLibraries: [LibraryMetadata] + with constraints: [Constraint] ) throws -> ( overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)], rootIncompatibilities: [Incompatibility] @@ -334,7 +311,7 @@ public struct PubGrubDependencyResolver { // be process 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 { provider.getContainer(for: node.package, availableLibraries: availableLibraries, completion: $0) } + let container = try temp_await { provider.getContainer(for: node.package, completion: $0) } for dependency in try container.underlying.getUnversionedDependencies(productFilter: node.productFilter) { if let versionedBasedConstraints = VersionBasedConstraint.constraints(dependency) { for constraint in versionedBasedConstraints { @@ -382,7 +359,7 @@ public struct PubGrubDependencyResolver { // Process dependencies of this package, similar to the first phase but branch-based dependencies // are not allowed to contain local/unversioned packages. // TODO: replace with async/await when avail - let container = try temp_await { provider.getContainer(for: package, availableLibraries: availableLibraries, completion: $0) } + let container = try temp_await { provider.getContainer(for: package, completion: $0) } // If there is a pin for this revision-based dependency, get // the dependencies at the pinned revision instead of using @@ -465,22 +442,19 @@ 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, availableLibraries: [LibraryMetadata]) throws { + private func run(state: State) throws { var next: DependencyResolutionNode? = state.root while let nxt = next { try self.propagate(state: state, node: nxt) // initiate prefetch of known packages that will be used to make the decision on the next step - self.provider.prefetch( - containers: state.solution.undecided.map(\.node.package), - availableLibraries: availableLibraries - ) + self.provider.prefetch(containers: state.solution.undecided.map(\.node.package)) // 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, availableLibraries: availableLibraries, completion: $0) } + next = try temp_await { self.makeDecision(state: state, completion: $0) } } } @@ -656,11 +630,7 @@ public struct PubGrubDependencyResolver { incompatibility.terms.isEmpty || (incompatibility.terms.count == 1 && incompatibility.terms.first?.node == root) } - private func computeCounts( - for terms: [Term], - availableLibraries: [LibraryMetadata], - completion: @escaping (Result<[Term: Int], Error>) -> Void - ) { + private func computeCounts(for terms: [Term], completion: @escaping (Result<[Term: Int], Error>) -> Void) { if terms.isEmpty { return completion(.success([:])) } @@ -670,7 +640,7 @@ public struct PubGrubDependencyResolver { terms.forEach { term in sync.enter() - provider.getContainer(for: term.node.package, availableLibraries: availableLibraries) { result in + provider.getContainer(for: term.node.package) { result in defer { sync.leave() } results[term] = result.flatMap { container in Result(catching: { try container.versionCount(term.requirement) }) } } @@ -685,11 +655,7 @@ public struct PubGrubDependencyResolver { } } - internal func makeDecision( - state: State, - availableLibraries: [LibraryMetadata] = [], - completion: @escaping (Result) -> Void - ) { + internal func makeDecision(state: State, completion: @escaping (Result) -> Void) { // If there are no more undecided terms, version solving is complete. let undecided = state.solution.undecided guard !undecided.isEmpty else { @@ -698,7 +664,7 @@ 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, availableLibraries: availableLibraries) { result in + self.computeCounts(for: undecided) { result in do { let start = DispatchTime.now() let counts = try result.get() @@ -762,16 +728,13 @@ public extension PubGrubDependencyResolver { enum PubgrubError: Swift.Error, CustomStringConvertible { case _unresolvable(Incompatibility, [DependencyResolutionNode: [Incompatibility]]) case unresolvable(String) - case potentiallyUnresovableDueToPrebuiltLibrary([PackageReference], String) public var description: String { switch self { case ._unresolvable(let rootCause, _): rootCause.description case .unresolvable(let error): - return error - case .potentiallyUnresovableDueToPrebuiltLibrary(_, let error): - return error + error } } @@ -780,9 +743,7 @@ public extension PubGrubDependencyResolver { case ._unresolvable(let rootCause, _): rootCause case .unresolvable: - return nil - case .potentiallyUnresovableDueToPrebuiltLibrary: - return nil + nil } } @@ -791,9 +752,7 @@ public extension PubGrubDependencyResolver { case ._unresolvable(_, let incompatibilities): incompatibilities case .unresolvable: - return nil - case .potentiallyUnresovableDueToPrebuiltLibrary: - return nil + nil } } } @@ -838,29 +797,3 @@ private extension PackageRequirement { } } } - -extension PackageReference { - public func matchingPrebuiltLibrary(in availableLibraries: [LibraryMetadata]) -> LibraryMetadata? { - switch self.kind { - case .fileSystem, .localSourceControl, .root: - return nil // can never match a prebuilt library - case .registry(let identity): - if let registryIdentity = identity.registry { - return availableLibraries.first( - where: { $0.identities.contains( - where: { $0 == .packageIdentity( - scope: registryIdentity.scope.description, - name: registryIdentity.name.description - ) - }) - }) - } else { - return nil - } - case .remoteSourceControl(let url): - return availableLibraries.first(where: { - $0.identities.contains(where: { $0 == .sourceControl(url: url) }) - }) - } - } -} diff --git a/Sources/PackageModel/CMakeLists.txt b/Sources/PackageModel/CMakeLists.txt index 7f9198f5ddc..aa978e3f181 100644 --- a/Sources/PackageModel/CMakeLists.txt +++ b/Sources/PackageModel/CMakeLists.txt @@ -15,7 +15,6 @@ add_library(PackageModel DependencyMapper.swift Diagnostics.swift IdentityResolver.swift - InstalledLibrariesSupport/LibraryMetadata.swift InstalledSwiftPMConfiguration.swift Manifest/Manifest.swift Manifest/PackageConditionDescription.swift diff --git a/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift b/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift deleted file mode 100644 index a0c96815c92..00000000000 --- a/Sources/PackageModel/InstalledLibrariesSupport/LibraryMetadata.swift +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 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 the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import Basics -import Foundation - -public struct LibraryMetadata: Decodable { - public enum Identity: Equatable, Decodable { - case packageIdentity(scope: String, name: String) - case sourceControl(url: SourceControlURL) - } - - /// The package from which it was built (e.g., the URL https://github.com/swiftlang/swift-syntax.git) - public let identities: [Identity] - /// The version that was built (e.g., 509.0.2) - public let version: String - /// The product name, if it differs from the module name (e.g., SwiftParser). - public let productName: String? - - let schemaVersion: Int -} - -extension LibraryMetadata.Identity { - public var identity: PackageIdentity { - switch self { - case .packageIdentity(let scope, let name): - return PackageIdentity.plain("\(scope)/\(name)") - case .sourceControl(let url): - return PackageIdentity(url: url) - } - } - - public var kind: PackageReference.Kind { - switch self { - case .packageIdentity: - return .registry(self.identity) - case .sourceControl(let url): - return .remoteSourceControl(.init(url.absoluteString)) - } - } - - public var ref: PackageReference { - return PackageReference(identity: self.identity, kind: self.kind) - } -} diff --git a/Sources/PackageModel/Toolchain.swift b/Sources/PackageModel/Toolchain.swift index 96bc353db65..e0d995043e5 100644 --- a/Sources/PackageModel/Toolchain.swift +++ b/Sources/PackageModel/Toolchain.swift @@ -37,9 +37,6 @@ public protocol Toolchain { /// Configuration from the used toolchain. var installedSwiftPMConfiguration: InstalledSwiftPMConfiguration { get } - /// Metadata for libraries provided by the used toolchain. - var providedLibraries: [LibraryMetadata] { get } - /// The root path to the Swift SDK used by this toolchain. var sdkRootPath: AbsolutePath? { get } diff --git a/Sources/PackageModel/UserToolchain.swift b/Sources/PackageModel/UserToolchain.swift index 77e3ec9631a..803f7c654ff 100644 --- a/Sources/PackageModel/UserToolchain.swift +++ b/Sources/PackageModel/UserToolchain.swift @@ -88,8 +88,6 @@ public final class UserToolchain: Toolchain { public let installedSwiftPMConfiguration: InstalledSwiftPMConfiguration - public let providedLibraries: [LibraryMetadata] - /// Returns the runtime library for the given sanitizer. public func runtimeLibrary(for sanitizer: Sanitizer) throws -> AbsolutePath { // FIXME: This is only for SwiftPM development time support. It is OK @@ -546,7 +544,6 @@ public final class UserToolchain: Toolchain { searchStrategy: SearchStrategy = .default, customLibrariesLocation: ToolchainConfiguration.SwiftPMLibrariesLocation? = nil, customInstalledSwiftPMConfiguration: InstalledSwiftPMConfiguration? = nil, - customProvidedLibraries: [LibraryMetadata]? = nil, fileSystem: any FileSystem = localFileSystem ) throws { self.swiftSDK = swiftSDK @@ -587,33 +584,6 @@ public final class UserToolchain: Toolchain { default: InstalledSwiftPMConfiguration.default) } - if let customProvidedLibraries { - self.providedLibraries = customProvidedLibraries - } else { - // When building with CMake, we need to skip resource support. - #if SKIP_RESOURCE_SUPPORT - let path = self.swiftCompilerPath.parentDirectory.parentDirectory.appending(components: ["share", "pm", "provided-libraries.json"]) - #else - let path: AbsolutePath - if let developmentPath = Bundle.module.path(forResource: "provided-libraries", ofType: "json") { - // During development, we should be able to find the metadata file using `Bundle.module`. - path = try AbsolutePath(validating: developmentPath) - } else { - // When deployed, we can find the metadata file in the toolchain. - path = self.swiftCompilerPath.parentDirectory.parentDirectory.appending(components: ["share", "pm", "provided-libraries.json"]) - } - #endif - if localFileSystem.exists(path) { - self.providedLibraries = try JSONDecoder.makeWithDefaults().decode( - path: path, - fileSystem: localFileSystem, - as: [LibraryMetadata].self - ) - } else { - self.providedLibraries = [] - } - } - // Use the triple from Swift SDK or compute the host triple using swiftc. var triple = try swiftSDK.targetTriple ?? Triple.getHostTriple(usingSwiftCompiler: swiftCompilers.compile) diff --git a/Sources/Workspace/ResolverPrecomputationProvider.swift b/Sources/Workspace/ResolverPrecomputationProvider.swift index 3d9803adea7..c5eaca741e8 100644 --- a/Sources/Workspace/ResolverPrecomputationProvider.swift +++ b/Sources/Workspace/ResolverPrecomputationProvider.swift @@ -44,19 +44,14 @@ struct ResolverPrecomputationProvider: PackageContainerProvider { /// The tools version currently in use. let currentToolsVersion: ToolsVersion - /// The available libraries in the SDK. - let availableLibraries: [LibraryMetadata] - init( root: PackageGraphRoot, dependencyManifests: Workspace.DependencyManifests, - currentToolsVersion: ToolsVersion = ToolsVersion.current, - availableLibraries: [LibraryMetadata] + currentToolsVersion: ToolsVersion = ToolsVersion.current ) { self.root = root self.dependencyManifests = dependencyManifests self.currentToolsVersion = currentToolsVersion - self.availableLibraries = availableLibraries } func getContainer( @@ -89,15 +84,6 @@ struct ResolverPrecomputationProvider: PackageContainerProvider { return completion(.success(container)) } - // Match against available prebuilt libraries. - if let matchingPrebuiltLibrary = package.matchingPrebuiltLibrary(in: availableLibraries) { - do { - return completion(.success(try PrebuiltPackageContainer(metadata: matchingPrebuiltLibrary))) - } catch { - return completion(.failure(error)) - } - } - // As we don't have anything else locally, error out. completion(.failure(ResolverPrecomputationError.missingPackage(package: package))) } diff --git a/Sources/Workspace/Workspace+Dependencies.swift b/Sources/Workspace/Workspace+Dependencies.swift index 3157260e268..7c62fc49fcf 100644 --- a/Sources/Workspace/Workspace+Dependencies.swift +++ b/Sources/Workspace/Workspace+Dependencies.swift @@ -37,7 +37,6 @@ import class PackageGraph.PinsStore import struct PackageGraph.PubGrubDependencyResolver import struct PackageGraph.Term import class PackageLoading.ManifestLoader -import struct PackageModel.LibraryMetadata import enum PackageModel.PackageDependency import struct PackageModel.PackageIdentity import struct PackageModel.PackageReference @@ -57,7 +56,6 @@ extension Workspace { root: PackageGraphRootInput, packages: [String] = [], dryRun: Bool = false, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> [(PackageReference, Workspace.PackageStateChange)]? { let start = DispatchTime.now() @@ -86,11 +84,7 @@ extension Workspace { dependencyMapper: self.dependencyMapper, observabilityScope: observabilityScope ) - let currentManifests = try self.loadDependencyManifests( - root: graphRoot, - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ) + let currentManifests = try self.loadDependencyManifests(root: graphRoot, observabilityScope: observabilityScope) // Abort if we're unable to load the pinsStore or have any diagnostics. guard let pinsStore = observabilityScope.trap({ try self.pinsStore.load() }) else { return nil } @@ -126,7 +120,6 @@ extension Workspace { let updateResults = self.resolveDependencies( resolver: resolver, - availableLibraries: availableLibraries, constraints: updateConstraints, observabilityScope: observabilityScope ) @@ -163,7 +156,6 @@ extension Workspace { // Load the updated manifests. let updatedDependencyManifests = try self.loadDependencyManifests( root: graphRoot, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) // If we have missing packages, something is fundamentally wrong with the resolution of the graph @@ -197,7 +189,6 @@ extension Workspace { func _resolve( root: PackageGraphRootInput, explicitProduct: String?, - availableLibraries: [LibraryMetadata], resolvedFileStrategy: ResolvedFileStrategy, observabilityScope: ObservabilityScope ) throws -> DependencyManifests { @@ -213,7 +204,6 @@ extension Workspace { return try self._resolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) case .update(let forceResolution): @@ -250,7 +240,6 @@ extension Workspace { let (manifests, precomputationResult) = try self.tryResolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) switch precomputationResult { @@ -274,7 +263,6 @@ extension Workspace { return try self.resolveAndUpdateResolvedFile( root: root, explicitProduct: explicitProduct, - availableLibraries: availableLibraries, forceResolution: forceResolution, constraints: [], observabilityScope: observabilityScope @@ -301,13 +289,11 @@ extension Workspace { func _resolveBasedOnResolvedVersionsFile( root: PackageGraphRootInput, explicitProduct: String?, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> DependencyManifests { let (manifests, precomputationResult) = try self.tryResolveBasedOnResolvedVersionsFile( root: root, explicitProduct: explicitProduct, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) switch precomputationResult { @@ -340,7 +326,6 @@ extension Workspace { fileprivate func tryResolveBasedOnResolvedVersionsFile( root: PackageGraphRootInput, explicitProduct: String?, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> (DependencyManifests, ResolutionPrecomputationResult) { // Ensure the cache path exists. @@ -365,11 +350,7 @@ extension Workspace { !observabilityScope.errorsReported else { return try ( - self.loadDependencyManifests( - root: graphRoot, - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ), + self.loadDependencyManifests(root: graphRoot, observabilityScope: observabilityScope), .notRequired ) } @@ -460,7 +441,6 @@ extension Workspace { let currentManifests = try self.loadDependencyManifests( root: graphRoot, automaticallyAddManagedDependencies: true, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -475,7 +455,6 @@ extension Workspace { dependencyManifests: currentManifests, pinsStore: pinsStore, constraints: [], - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -492,7 +471,6 @@ extension Workspace { func resolveAndUpdateResolvedFile( root: PackageGraphRootInput, explicitProduct: String? = nil, - availableLibraries: [LibraryMetadata], forceResolution: Bool, constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope @@ -518,11 +496,7 @@ extension Workspace { dependencyMapper: self.dependencyMapper, observabilityScope: observabilityScope ) - let currentManifests = try self.loadDependencyManifests( - root: graphRoot, - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ) + let currentManifests = try self.loadDependencyManifests(root: graphRoot, observabilityScope: observabilityScope) guard !observabilityScope.errorsReported else { return currentManifests } @@ -557,7 +531,6 @@ extension Workspace { dependencyManifests: currentManifests, pinsStore: pinsStore, constraints: constraints, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) @@ -596,7 +569,6 @@ extension Workspace { let result = self.resolveDependencies( resolver: resolver, - availableLibraries: availableLibraries, constraints: computedConstraints, observabilityScope: observabilityScope ) @@ -621,7 +593,6 @@ extension Workspace { // Update the pinsStore. let updatedDependencyManifests = try self.loadDependencyManifests( root: graphRoot, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) // If we still have missing packages, something is fundamentally wrong with the resolution of the graph @@ -830,7 +801,6 @@ extension Workspace { dependencyManifests: DependencyManifests, pinsStore: PinsStore, constraints: [PackageContainerConstraint], - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> ResolutionPrecomputationResult { let computedConstraints = @@ -842,19 +812,14 @@ extension Workspace { let precomputationProvider = ResolverPrecomputationProvider( root: root, - dependencyManifests: dependencyManifests, - availableLibraries: availableLibraries + dependencyManifests: dependencyManifests ) let resolver = PubGrubDependencyResolver( provider: precomputationProvider, pins: pinsStore.pins, observabilityScope: observabilityScope ) - let result = resolver.solve( - constraints: computedConstraints, - availableLibraries: availableLibraries, - preferPrebuiltLibraries: true - ) + let result = resolver.solve(constraints: computedConstraints) guard !observabilityScope.errorsReported else { return .required(reason: .errorsPreviouslyReported) @@ -1148,24 +1113,11 @@ extension Workspace { /// Runs the dependency resolver based on constraints provided and returns the results. fileprivate func resolveDependencies( resolver: PubGrubDependencyResolver, - availableLibraries: [LibraryMetadata], constraints: [PackageContainerConstraint], observabilityScope: ObservabilityScope ) -> [DependencyResolverBinding] { os_signpost(.begin, name: SignpostName.pubgrub) - var result = resolver.solve( - constraints: constraints, - availableLibraries: availableLibraries, - preferPrebuiltLibraries: true - ) - // If the initial resolution failed due to prebuilt libraries, we try to resolve again without prebuilt libraries. - if case let Result.failure(error as PubGrubDependencyResolver.PubgrubError) = result, case .potentiallyUnresovableDueToPrebuiltLibrary = error { - result = resolver.solve( - constraints: constraints, - availableLibraries: availableLibraries, - preferPrebuiltLibraries: false - ) - } + let result = resolver.solve(constraints: constraints) os_signpost(.end, name: SignpostName.pubgrub) // Take an action based on the result. diff --git a/Sources/Workspace/Workspace+Editing.swift b/Sources/Workspace/Workspace+Editing.swift index a58d641befd..96368b804c3 100644 --- a/Sources/Workspace/Workspace+Editing.swift +++ b/Sources/Workspace/Workspace+Editing.swift @@ -16,7 +16,6 @@ import class Basics.ObservabilityScope import struct Basics.RelativePath import func Basics.temp_await import struct PackageGraph.PackageGraphRootInput -import struct PackageModel.LibraryMetadata import struct SourceControl.Revision extension Workspace { @@ -170,7 +169,6 @@ extension Workspace { dependency: ManagedDependency, forceRemove: Bool, root: PackageGraphRootInput? = nil, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws { // Compute if we need to force remove. @@ -235,7 +233,6 @@ extension Workspace { try self._resolve( root: root, explicitProduct: .none, - availableLibraries: availableLibraries, resolvedFileStrategy: .update(forceResolution: false), observabilityScope: observabilityScope ) diff --git a/Sources/Workspace/Workspace+Manifests.swift b/Sources/Workspace/Workspace+Manifests.swift index 97994d61b3e..6f56120085d 100644 --- a/Sources/Workspace/Workspace+Manifests.swift +++ b/Sources/Workspace/Workspace+Manifests.swift @@ -29,7 +29,6 @@ import struct PackageGraph.PackageGraphRoot import class PackageLoading.ManifestLoader import struct PackageLoading.ManifestValidator import struct PackageLoading.ToolsVersionParser -import struct PackageModel.LibraryMetadata import class PackageModel.Manifest import struct PackageModel.PackageIdentity import struct PackageModel.PackageReference @@ -62,8 +61,6 @@ extension Workspace { private let workspace: Workspace - private let availableLibraries: [LibraryMetadata] - private let observabilityScope: ObservabilityScope private let _dependencies: LoadableResult<( @@ -82,20 +79,17 @@ extension Workspace { fileSystem: FileSystem )], workspace: Workspace, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) { self.root = root self.dependencies = dependencies self.workspace = workspace - self.availableLibraries = availableLibraries self.observabilityScope = observabilityScope self._dependencies = LoadableResult { try Self.computeDependencies( root: root, dependencies: dependencies, workspace: workspace, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -174,7 +168,6 @@ extension Workspace { fileSystem: FileSystem )], workspace: Workspace, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> ( @@ -190,32 +183,6 @@ extension Workspace { } ) - let availableIdentities: Set = try Set(manifestsMap.map { - // FIXME: adding this guard to ensure refactoring is correct 9/21 - // we only care about remoteSourceControl for this validation. it would otherwise trigger for - // a dependency is put into edit mode, which we want to deprecate anyways - if case .remoteSourceControl = $0.1.packageKind { - let effectiveURL = workspace.mirrors.effective(for: $0.1.packageLocation) - guard effectiveURL == $0.1.packageKind.locationString else { - throw InternalError( - "effective url for \($0.1.packageLocation) is \(effectiveURL), different from expected \($0.1.packageKind.locationString)" - ) - } - } - return PackageReference(identity: $0.key, kind: $0.1.packageKind) - }) - - let identitiesAvailableInSDK = availableLibraries.flatMap { - $0.identities.map { - $0.ref - }.filter { - // We "trust the process" here, if an identity from the SDK is available, filter it. - !availableIdentities.contains($0) - }.map { - $0.identity - } - } - var inputIdentities: OrderedCollections.OrderedSet = [] let inputNodes: [GraphLoadingNode] = try root.packages.map { identity, package in inputIdentities.append(package.reference) @@ -299,11 +266,20 @@ extension Workspace { } requiredIdentities = inputIdentities.union(requiredIdentities) - let identitiesToFilter = requiredIdentities.filter { - return identitiesAvailableInSDK.contains($0.identity) - } - requiredIdentities = requiredIdentities.subtracting(identitiesToFilter) - + let availableIdentities: Set = try Set(manifestsMap.map { + // FIXME: adding this guard to ensure refactoring is correct 9/21 + // we only care about remoteSourceControl for this validation. it would otherwise trigger for + // a dependency is put into edit mode, which we want to deprecate anyways + if case .remoteSourceControl = $0.1.packageKind { + let effectiveURL = workspace.mirrors.effective(for: $0.1.packageLocation) + guard effectiveURL == $0.1.packageKind.locationString else { + throw InternalError( + "effective url for \($0.1.packageLocation) is \(effectiveURL), different from expected \($0.1.packageKind.locationString)" + ) + } + } + return PackageReference(identity: $0.key, kind: $0.1.packageKind) + }) // We should never have loaded a manifest we don't need. assert( availableIdentities.isSubset(of: requiredIdentities), @@ -443,7 +419,6 @@ extension Workspace { public func loadDependencyManifests( root: PackageGraphRoot, automaticallyAddManagedDependencies: Bool = false, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws -> DependencyManifests { let prepopulateManagedDependencies: ([PackageReference]) throws -> Void = { refs in @@ -485,17 +460,13 @@ extension Workspace { } // Validates that all the managed dependencies are still present in the file system. - self.fixManagedDependencies( - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ) + self.fixManagedDependencies(observabilityScope: observabilityScope) guard !observabilityScope.errorsReported else { // return partial results return DependencyManifests( root: root, dependencies: [], workspace: self, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -614,7 +585,6 @@ extension Workspace { root: root, dependencies: dependencies, workspace: self, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -806,10 +776,7 @@ extension Workspace { /// If some checkout dependency is removed form the file system, clone it again. /// If some edited dependency is removed from the file system, mark it as unedited and /// fallback on the original checkout. - private func fixManagedDependencies( - availableLibraries: [LibraryMetadata], - observabilityScope: ObservabilityScope - ) { + private func fixManagedDependencies(observabilityScope: ObservabilityScope) { // 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() @@ -878,12 +845,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( - dependency: dependency, - forceRemove: true, - availableLibraries: availableLibraries, - observabilityScope: observabilityScope - ) + try self.unedit(dependency: dependency, forceRemove: true, observabilityScope: observabilityScope) observabilityScope .emit(.editedDependencyMissing(packageName: dependency.packageRef.identity.description)) diff --git a/Sources/Workspace/Workspace.swift b/Sources/Workspace/Workspace.swift index d0f4c14218a..c9dc05f9c9e 100644 --- a/Sources/Workspace/Workspace.swift +++ b/Sources/Workspace/Workspace.swift @@ -585,11 +585,6 @@ public class Workspace { initializationWarningHandler: initializationWarningHandler ) } - - fileprivate var providedLibraries: [LibraryMetadata] { - // Note: Eventually, we should get these from the individual SDKs, but the first step is providing the metadata centrally in the toolchain. - return self.hostToolchain.providedLibraries - } } // MARK: - Public API @@ -640,7 +635,6 @@ extension Workspace { packageName: String, forceRemove: Bool, root: PackageGraphRootInput, - availableLibraries: [LibraryMetadata], observabilityScope: ObservabilityScope ) throws { guard let dependency = self.state.dependencies[.plain(packageName)] else { @@ -657,7 +651,6 @@ extension Workspace { dependency: dependency, forceRemove: forceRemove, root: root, - availableLibraries: availableLibraries, observabilityScope: observabilityScope ) } @@ -678,7 +671,6 @@ extension Workspace { try self._resolve( root: root, explicitProduct: explicitProduct, - availableLibraries: self.providedLibraries, resolvedFileStrategy: forceResolvedVersions ? .lockFile : forceResolution ? .update(forceResolution: true) : .bestEffort, observabilityScope: observabilityScope @@ -750,7 +742,6 @@ extension Workspace { // Run the resolution. try self.resolveAndUpdateResolvedFile( root: root, - availableLibraries: self.providedLibraries, forceResolution: false, constraints: [constraint], observabilityScope: observabilityScope @@ -768,7 +759,6 @@ extension Workspace { try self._resolveBasedOnResolvedVersionsFile( root: root, explicitProduct: .none, - availableLibraries: self.providedLibraries, observabilityScope: observabilityScope ) } @@ -879,7 +869,6 @@ extension Workspace { root: root, packages: packages, dryRun: dryRun, - availableLibraries: self.providedLibraries, observabilityScope: observabilityScope ) } @@ -891,7 +880,6 @@ extension Workspace { forceResolvedVersions: Bool = false, customXCTestMinimumDeploymentTargets: [PackageModel.Platform: PlatformVersion]? = .none, testEntryPointPath: AbsolutePath? = nil, - availableLibraries: [LibraryMetadata], expectedSigningEntities: [PackageIdentity: RegistryReleaseMetadata.SigningEntity] = [:], observabilityScope: ObservabilityScope ) throws -> ModulesGraph { @@ -934,7 +922,6 @@ extension Workspace { let manifests = try self._resolve( root: root, explicitProduct: explicitProduct, - availableLibraries: [], resolvedFileStrategy: forceResolvedVersions ? .lockFile : .bestEffort, observabilityScope: observabilityScope ) diff --git a/Sources/_InternalTestSupport/MockWorkspace.swift b/Sources/_InternalTestSupport/MockWorkspace.swift index 1fc13e8bbc8..16ec0783da2 100644 --- a/Sources/_InternalTestSupport/MockWorkspace.swift +++ b/Sources/_InternalTestSupport/MockWorkspace.swift @@ -399,13 +399,7 @@ public final class MockWorkspace { observability.topScope.trap { let rootInput = PackageGraphRootInput(packages: try rootPaths(for: roots)) let ws = try self.getOrCreateWorkspace() - try ws.unedit( - packageName: packageName, - forceRemove: forceRemove, - root: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + try ws.unedit(packageName: packageName, forceRemove: forceRemove, root: rootInput, observabilityScope: observability.topScope) } result(observability.diagnostics) } @@ -502,7 +496,6 @@ public final class MockWorkspace { let graph = try workspace.loadPackageGraph( rootInput: rootInput, forceResolvedVersions: forceResolvedVersions, - availableLibraries: [], // assume no provided libraries for testing. expectedSigningEntities: expectedSigningEntities, observabilityScope: observability.topScope ) @@ -541,7 +534,6 @@ public final class MockWorkspace { try workspace.loadPackageGraph( rootInput: rootInput, forceResolvedVersions: forceResolvedVersions, - availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) } @@ -565,18 +557,13 @@ public final class MockWorkspace { ) let root = PackageGraphRoot(input: rootInput, manifests: rootManifests, observabilityScope: observability.topScope) - let dependencyManifests = try workspace.loadDependencyManifests( - root: root, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let dependencyManifests = try workspace.loadDependencyManifests(root: root, observabilityScope: observability.topScope) let result = try workspace.precomputeResolution( root: root, dependencyManifests: dependencyManifests, pinsStore: pinsStore, constraints: [], - availableLibraries: [], // assume no provided libraries for testing. observabilityScope: observability.topScope ) @@ -785,11 +772,7 @@ public final class MockWorkspace { ) let rootManifests = try temp_await { workspace.loadRootManifests(packages: rootInput.packages, observabilityScope: observability.topScope, completion: $0) } let graphRoot = PackageGraphRoot(input: rootInput, manifests: rootManifests, observabilityScope: observability.topScope) - let manifests = try workspace.loadDependencyManifests( - root: graphRoot, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let manifests = try workspace.loadDependencyManifests(root: graphRoot, observabilityScope: observability.topScope) result(manifests, observability.diagnostics) } diff --git a/Sources/swift-bootstrap/main.swift b/Sources/swift-bootstrap/main.swift index d14faf5e16a..baee0b59475 100644 --- a/Sources/swift-bootstrap/main.swift +++ b/Sources/swift-bootstrap/main.swift @@ -327,8 +327,6 @@ struct SwiftBootstrapBuildTool: ParsableCommand { traitConfiguration: nil, additionalFileRules: [], pkgConfigDirectories: [], - dependenciesByRootPackageIdentity: [:], - targetsByRootPackageIdentity: [:], outputStream: TSCBasic.stdoutStream, logLevel: logLevel, fileSystem: self.fileSystem, @@ -393,7 +391,6 @@ struct SwiftBootstrapBuildTool: ParsableCommand { partial[item.key] = (manifest: item.value, fs: self.fileSystem) }, binaryArtifacts: [:], - availableLibraries: [], // assume no provided libraries during bootstrap fileSystem: fileSystem, observabilityScope: observabilityScope, // Plugins can't be used in bootstrap builds, exclude those. diff --git a/Tests/BuildTests/BuildOperationTests.swift b/Tests/BuildTests/BuildOperationTests.swift index 585f900d88c..214fcdfc27a 100644 --- a/Tests/BuildTests/BuildOperationTests.swift +++ b/Tests/BuildTests/BuildOperationTests.swift @@ -41,8 +41,6 @@ private func mockBuildOperation( scratchDirectory: scratchDirectory, additionalFileRules: [], pkgConfigDirectories: [], - dependenciesByRootPackageIdentity: [:], - targetsByRootPackageIdentity: [:], outputStream: BufferedOutputByteStream(), logLevel: .info, fileSystem: fs, @@ -51,47 +49,6 @@ private func mockBuildOperation( } final class BuildOperationTests: XCTestCase { - func testDetectUnexpressedDependencies() throws { - let scratchDirectory = AbsolutePath("/path/to/build") - let triple = hostTriple - let targetBuildParameters = mockBuildParameters( - destination: .target, - buildPath: scratchDirectory.appending(triple.tripleString), - shouldDisableLocalRpath: false, - triple: triple - ) - - let fs = InMemoryFileSystem(files: [ - "\(targetBuildParameters.dataPath)/debug/Lunch.build/Lunch.d" : "/Best.framework" - ]) - - let observability = ObservabilitySystem.makeForTesting() - let buildOp = mockBuildOperation( - productsBuildParameters: targetBuildParameters, - toolsBuildParameters: mockBuildParameters(destination: .host, shouldDisableLocalRpath: false), - scratchDirectory: scratchDirectory, - fs: fs, observabilityScope: observability.topScope - ) - buildOp.detectUnexpressedDependencies( - availableLibraries: [ - .init( - identities: [ - .sourceControl(url: .init("https://example.com/org/foo")) - ], - version: "1.0.0", - productName: "Best", - schemaVersion: 1 - ) - ], - targetDependencyMap: ["Lunch": []] - ) - - XCTAssertEqual( - observability.diagnostics.map { $0.message }, - ["target 'Lunch' has an unexpressed depedency on 'foo'"] - ) - } - func testDetectProductTripleChange() throws { let observability = ObservabilitySystem.makeForTesting() let fs = InMemoryFileSystem( diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 8a940486ea2..2ca71c71e58 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -3399,11 +3399,7 @@ final class PackageCommandTests: CommandsTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let _ = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let _ = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) } } diff --git a/Tests/FunctionalTests/PluginTests.swift b/Tests/FunctionalTests/PluginTests.swift index 56528c187fb..76293b2e798 100644 --- a/Tests/FunctionalTests/PluginTests.swift +++ b/Tests/FunctionalTests/PluginTests.swift @@ -445,11 +445,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) XCTAssert(packageGraph.packages.count == 2, "\(packageGraph.packages)") XCTAssert(packageGraph.rootPackages.count == 1, "\(packageGraph.rootPackages)") @@ -633,11 +629,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) // Make sure that the use of plugins doesn't bleed into the use of plugins by tools. @@ -731,11 +723,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) XCTAssert(packageGraph.packages.count == 1, "\(packageGraph.packages)") XCTAssert(packageGraph.rootPackages.count == 1, "\(packageGraph.rootPackages)") @@ -1048,11 +1036,7 @@ final class PluginTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssert(packageGraph.packages.count == 4, "\(packageGraph.packages)") XCTAssert(packageGraph.rootPackages.count == 1, "\(packageGraph.rootPackages)") diff --git a/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift b/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift index b7fed7598bf..a6e086edec0 100644 --- a/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift +++ b/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift @@ -95,7 +95,6 @@ final class PackageGraphPerfTests: XCTestCasePerf { identityResolver: identityResolver, externalManifests: externalManifests, binaryArtifacts: [:], - availableLibraries: [], // assume no provided libraries for testing. fileSystem: fs, observabilityScope: observability.topScope ) diff --git a/Tests/PackageGraphTests/PubgrubTests.swift b/Tests/PackageGraphTests/PubgrubTests.swift index 9f6fa7549ca..ae7950bdd6f 100644 --- a/Tests/PackageGraphTests/PubgrubTests.swift +++ b/Tests/PackageGraphTests/PubgrubTests.swift @@ -1851,47 +1851,6 @@ final class PubGrubTestsBasicGraphs: XCTestCase { ("bar", .version(v1)), ]) } - - func testAvailableLibraries() throws { - let ref: PackageReference = .remoteSourceControl( - identity: .plain("foo"), - url: .init("https://example.com/org/foo") - ) - try builder.serve(ref, at: .version(.init(stringLiteral: "1.0.0"))) - try builder.serve(ref, at: .version(.init(stringLiteral: "1.2.0"))) - try builder.serve(ref, at: .version(.init(stringLiteral: "2.0.0"))) - - let resolver = builder.create() - let dependencies = try builder.create(dependencies: [ - "foo": (.versionSet(.range("1.0.0"..<"2.0.0")), .specific(["foo"])), - ]) - - let availableLibraries: [LibraryMetadata] = [ - .init( - identities: [.sourceControl(url: "https://example.com/org/foo")], - version: "1.0.0", - productName: nil, - schemaVersion: 1 - ) - ] - - let result = resolver.solve( - constraints: dependencies, - availableLibraries: availableLibraries, - preferPrebuiltLibraries: true - ) - // Available libraries are filtered from the resolver results, so this is expected to be empty. - AssertResult(result, []) - - let result2 = resolver.solve( - constraints: dependencies, - availableLibraries: availableLibraries, - preferPrebuiltLibraries: false - ) - AssertResult(result2, [ - ("foo", .version(.init(stringLiteral: "1.2.0"))), - ]) - } } final class PubGrubDiagnosticsTests: XCTestCase { diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index 9883c016fdb..6f857245271 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -317,11 +317,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) XCTAssert(packageGraph.packages.count == 1, "\(packageGraph.packages)") @@ -698,11 +694,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - XCTAssertThrowsError(try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - )) { error in + XCTAssertThrowsError(try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope)) { error in var diagnosed = false if let realError = error as? PackageGraphError, realError.description == "plugin 'MyPlugin' cannot depend on 'FooLib' of type 'library' from package 'foopackage'; this dependency is unsupported" { @@ -778,10 +770,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - XCTAssertThrowsError(try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope)) { error in + XCTAssertThrowsError(try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope)) { error in var diagnosed = false if let realError = error as? PackageGraphError, realError.description == "plugin 'MyPlugin' cannot depend on 'MyLibrary' of type 'library'; this dependency is unsupported" { @@ -888,11 +877,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) XCTAssert(packageGraph.packages.count == 1, "\(packageGraph.packages)") @@ -1083,11 +1068,7 @@ final class PluginInvocationTests: XCTestCase { ) XCTAssert(rootManifests.count == 1, "\(rootManifests)") - let graph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let graph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) let dict = try await workspace.loadPluginImports(packageGraph: graph) var count = 0 @@ -1231,11 +1212,7 @@ final class PluginInvocationTests: XCTestCase { XCTAssert(rootManifests.count == 1, "\(rootManifests)") // Load the package graph. - let packageGraph = try workspace.loadPackageGraph( - rootInput: rootInput, - availableLibraries: [], // assume no provided libraries for testing. - observabilityScope: observability.topScope - ) + let packageGraph = try workspace.loadPackageGraph(rootInput: rootInput, observabilityScope: observability.topScope) XCTAssertNoDiagnostics(observability.diagnostics) // Find the build tool plugin. diff --git a/Utilities/provided-libraries.json b/Utilities/provided-libraries.json deleted file mode 100644 index 02d798442b7..00000000000 --- a/Utilities/provided-libraries.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "identities": - [ - { - "sourceControl": - { - "url": {"urlString": "https://github.com/apple/swift-testing.git"} - } - } - ], - "productName": "Testing", - "version": "0.4.0", - "schemaVersion": 1 - } -]