Skip to content

Commit 5e91c76

Browse files
committed
Implement package registry support
Add PackageRegistry module target Add PackageRegistryTests module target Add --enable-package-registry command-line option Cache registry managers by base URL Set _useLegacyIdentities in SwiftTool initialization Incorporate review feedback for use of tsc_await Reuse HTTP clients in registry manager Remove custom userAgent This is already provided by HTTPClient Add internal archiverFactory to RegistryManager for DI Add queue parameter to RegistryManager.discover Add diagnosticsEngine parameter to RegistryManager Replace MockPackageRegistryURLProtocol with HTTPClient handlers Remove use of tsc_await in RegistryManager.discover Stash progress
1 parent d9ca2fc commit 5e91c76

17 files changed

+1151
-88
lines changed

Diff for: Package.swift

+12-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ let package = Package(
4343
"PackageModel",
4444
"PackageLoading",
4545
"PackageGraph",
46+
"PackageRegistry",
4647
"Build",
4748
"Xcodeproj",
4849
"Workspace"
@@ -58,6 +59,7 @@ let package = Package(
5859
"PackageModel",
5960
"PackageLoading",
6061
"PackageGraph",
62+
"PackageRegistry",
6163
"Build",
6264
"Xcodeproj",
6365
"Workspace"
@@ -111,10 +113,16 @@ let package = Package(
111113
name: "LLBuildManifest",
112114
dependencies: ["SwiftToolsSupport-auto", "Basics"]),
113115

116+
.target(
117+
/** Package registry support */
118+
name: "PackageRegistry",
119+
dependencies: ["SwiftToolsSupport-auto", "Basics", "PackageLoading", "PackageModel"]),
120+
114121
.target(
115122
/** Source control operations */
116123
name: "SourceControl",
117124
dependencies: ["SwiftToolsSupport-auto", "Basics"]),
125+
118126
.target(
119127
/** Shim for llbuild library */
120128
name: "SPMLLBuild",
@@ -136,7 +144,7 @@ let package = Package(
136144
.target(
137145
/** Data structures and support for complete package graphs */
138146
name: "PackageGraph",
139-
dependencies: ["SwiftToolsSupport-auto", "Basics", "PackageLoading", "PackageModel", "SourceControl"]),
147+
dependencies: ["SwiftToolsSupport-auto", "Basics", "PackageLoading", "PackageModel", "PackageRegistry", "SourceControl"]),
140148

141149
// MARK: Package Collections
142150

@@ -252,6 +260,9 @@ let package = Package(
252260
.testTarget(
253261
name: "PackageCollectionsTests",
254262
dependencies: ["SPMTestSupport", "PackageCollections"]),
263+
.testTarget(
264+
name: "PackageRegistryTests",
265+
dependencies: ["SPMTestSupport", "PackageRegistry"]),
255266
.testTarget(
256267
name: "SourceControlTests",
257268
dependencies: ["SourceControl", "SPMTestSupport"]),

Diff for: Sources/Basics/HTPClient+URLSession.swift

+1-9
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,7 @@ extension URLSessionHTTPClient.TaskDelegate: URLSessionDataDelegate {
8181
newRequest request: URLRequest,
8282
completionHandler: @escaping (URLRequest?) -> Void)
8383
{
84-
if configuration.followRedirects {
85-
completionHandler(request)
86-
} else {
87-
completionHandler(nil)
88-
89-
configuration.callbackQueue.async {
90-
self.callback(.success(response.response(body: nil)))
91-
}
92-
}
84+
completionHandler(configuration.followRedirects ? request : nil)
9385
}
9486

9587
public func urlSession(_ session: URLSession,

Diff for: Sources/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_subdirectory(PackageDescription)
1515
add_subdirectory(PackageGraph)
1616
add_subdirectory(PackageLoading)
1717
add_subdirectory(PackageModel)
18+
add_subdirectory(PackageRegistry)
1819
add_subdirectory(SPMBuildCore)
1920
add_subdirectory(SPMLLBuild)
2021
add_subdirectory(SourceControl)

Diff for: Sources/Commands/Options.swift

+4
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ public struct SwiftToolOptions: ParsableArguments {
244244
@Flag(name: .customLong("trace-resolver"))
245245
var enableResolverTrace: Bool = false
246246

247+
@Flag(name: .customLong("enable-package-registry"),
248+
help: "Enable dependency resolution using package registries when available")
249+
var enablePackageRegistry: Bool = false
250+
247251
/// The number of jobs for llbuild to start (aka the number of schedulerLanes)
248252
@Option(name: .shortAndLong, help: "The number of jobs to spawn in parallel during the build process")
249253
var jobs: UInt32?

Diff for: Sources/Commands/SwiftTool.swift

+19-12
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
156156
case .unversioned:
157157
self.stdoutStream <<< "unversioned"
158158
}
159+
case .downloaded(let version):
160+
self.stdoutStream <<< "resolved to '\(version)'"
159161
case .edited?:
160162
self.stdoutStream <<< "edited"
161163
case .local?:
@@ -228,7 +230,7 @@ private final class DiagnosticsEngineHandler {
228230

229231
protocol SwiftCommand: ParsableCommand {
230232
var swiftOptions: SwiftToolOptions { get }
231-
233+
232234
func run(_ swiftTool: SwiftTool) throws
233235
}
234236

@@ -312,7 +314,7 @@ public class SwiftTool {
312314
do {
313315
try Self.postprocessArgParserResult(options: options, diagnostics: diagnostics)
314316
self.options = options
315-
317+
316318
// Honor package-path option is provided.
317319
if let packagePath = options.packagePath ?? options.chdir {
318320
try ProcessEnv.chdir(packagePath)
@@ -370,29 +372,33 @@ public class SwiftTool {
370372
self.buildPath = getEnvBuildPath(workingDir: cwd) ??
371373
customBuildPath ??
372374
(packageRoot ?? cwd).appending(component: ".build")
373-
375+
376+
if options.enablePackageRegistry {
377+
PackageModel._useLegacyIdentities = false
378+
}
379+
374380
// Setup the globals.
375381
verbosity = Verbosity(rawValue: options.verbosity)
376382
Process.verbose = verbosity != .concise
377383
}
378-
384+
379385
static func postprocessArgParserResult(options: SwiftToolOptions, diagnostics: DiagnosticsEngine) throws {
380386
if options.chdir != nil {
381387
diagnostics.emit(warning: "'--chdir/-C' option is deprecated; use '--package-path' instead")
382388
}
383-
389+
384390
if options.multirootPackageDataFile != nil {
385391
diagnostics.emit(.unsupportedFlag("--multiroot-data-file"))
386392
}
387-
393+
388394
if options.useExplicitModuleBuild && !options.useIntegratedSwiftDriver {
389395
diagnostics.emit(error: "'--experimental-explicit-module-build' option requires '--use-integrated-swift-driver'")
390396
}
391-
397+
392398
if !options.archs.isEmpty && options.customCompileTriple != nil {
393399
diagnostics.emit(.mutuallyExclusiveArgumentsError(arguments: ["--arch", "--triple"]))
394400
}
395-
401+
396402
if options.netrcFilePath != nil {
397403
// --netrc-file option only supported on macOS >=10.13
398404
#if os(macOS)
@@ -405,7 +411,7 @@ public class SwiftTool {
405411
diagnostics.emit(error: "'--netrc-file' option is only supported on macOS >=10.13")
406412
#endif
407413
}
408-
414+
409415
if options.enableTestDiscovery {
410416
diagnostics.emit(warning: "'--enable-test-discovery' option is deprecated; tests are automatically discovered on all platforms")
411417
}
@@ -444,12 +450,12 @@ public class SwiftTool {
444450
private lazy var _swiftpmConfig: Result<Workspace.Configuration, Swift.Error> = {
445451
return Result(catching: { try Workspace.Configuration(path: try configFilePath()) })
446452
}()
447-
453+
448454
func resolvedNetrcFilePath() throws -> AbsolutePath? {
449455
guard options.netrc ||
450456
options.netrcFilePath != nil ||
451457
options.netrcOptional else { return nil }
452-
458+
453459
let resolvedPath: AbsolutePath = options.netrcFilePath ?? AbsolutePath("\(NSHomeDirectory())/.netrc")
454460
guard localFileSystem.exists(resolvedPath) else {
455461
if !options.netrcOptional {
@@ -493,7 +499,8 @@ public class SwiftTool {
493499
isResolverPrefetchingEnabled: options.shouldEnableResolverPrefetching,
494500
skipUpdate: options.skipDependencyUpdate,
495501
enableResolverTrace: options.enableResolverTrace,
496-
cachePath: cachePath
502+
cachePath: cachePath,
503+
enablePackageRegistry: options.enablePackageRegistry
497504
)
498505
_workspace = workspace
499506
return workspace

Diff for: Sources/PackageGraph/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
add_library(PackageGraph
1010
BoundVersion.swift
1111
CheckoutState.swift
12+
CompositePackageContainerProvider.swift
1213
DependencyMirrors.swift
1314
DependencyResolutionNode.swift
1415
DependencyResolver.swift
@@ -27,6 +28,7 @@ add_library(PackageGraph
2728
Pubgrub/PartialSolution.swift
2829
Pubgrub/PubgrubDependencyResolver.swift
2930
Pubgrub/Term.swift
31+
RegistryPackageContainer.swift
3032
RepositoryPackageContainer.swift
3133
ResolvedPackage.swift
3234
ResolvedProduct.swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Dispatch
12+
13+
import PackageLoading
14+
import PackageModel
15+
import PackageRegistry
16+
import SourceControl
17+
18+
import TSCBasic
19+
import TSCUtility
20+
21+
public class CompositePackageContainerProvider: PackageContainerProvider {
22+
let manifestLoader: ManifestLoaderProtocol
23+
let repositoryManager: RepositoryManager
24+
let mirrors: DependencyMirrors
25+
26+
/// The tools version currently in use. Only the container versions less than and equal to this will be provided by
27+
/// the container.
28+
let currentToolsVersion: ToolsVersion
29+
30+
/// The tools version loader.
31+
let toolsVersionLoader: ToolsVersionLoaderProtocol
32+
33+
let fileSystem: FileSystem
34+
35+
/// Create a repository-based package provider.
36+
///
37+
/// - Parameters:
38+
/// - repositoryManager: The repository manager responsible for providing repositories.
39+
/// - manifestLoader: The manifest loader instance.
40+
/// - currentToolsVersion: The current tools version in use.
41+
/// - toolsVersionLoader: The tools version loader.
42+
public init(
43+
repositoryManager: RepositoryManager,
44+
mirrors: DependencyMirrors = DependencyMirrors(),
45+
manifestLoader: ManifestLoaderProtocol,
46+
currentToolsVersion: ToolsVersion = ToolsVersion.currentToolsVersion,
47+
toolsVersionLoader: ToolsVersionLoaderProtocol = ToolsVersionLoader(),
48+
fileSystem: FileSystem = localFileSystem
49+
) {
50+
self.repositoryManager = repositoryManager
51+
self.mirrors = mirrors
52+
self.manifestLoader = manifestLoader
53+
self.currentToolsVersion = currentToolsVersion
54+
self.toolsVersionLoader = toolsVersionLoader
55+
self.fileSystem = fileSystem
56+
}
57+
58+
public func getContainer(
59+
for reference: PackageReference,
60+
skipUpdate: Bool,
61+
on queue: DispatchQueue,
62+
completion: @escaping (Result<PackageContainer, Swift.Error>) -> Void
63+
) {
64+
// For remote package references, attempt to load from registry before falling back to respository access.
65+
if reference.kind == .remote {
66+
let provider = RegistryPackageContainerProvider(mirrors: mirrors, manifestLoader: manifestLoader, currentToolsVersion: currentToolsVersion, toolsVersionLoader: toolsVersionLoader)
67+
provider.getContainer(for: reference, skipUpdate: skipUpdate, on: queue) { result in
68+
guard case .failure = result else {
69+
return queue.async {
70+
completion(result)
71+
}
72+
}
73+
74+
let provider = RepositoryPackageContainerProvider(repositoryManager: self.repositoryManager, mirrors: self.mirrors, manifestLoader: self.manifestLoader, currentToolsVersion: self.currentToolsVersion, toolsVersionLoader: self.toolsVersionLoader)
75+
provider.getContainer(for: reference, skipUpdate: skipUpdate, on: queue, completion: completion)
76+
}
77+
} else {
78+
let provider = LocalPackageContainerProvider(mirrors: self.mirrors, manifestLoader: self.manifestLoader, currentToolsVersion: self.currentToolsVersion, toolsVersionLoader: self.toolsVersionLoader, fileSystem: self.fileSystem)
79+
provider.getContainer(for: reference, skipUpdate: skipUpdate, on: queue, completion: completion)
80+
}
81+
}
82+
}

Diff for: Sources/PackageGraph/LocalPackageContainer.swift

+52-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
See http://swift.org/LICENSE.txt for license information
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9-
*/
9+
*/
1010

1111
import Dispatch
1212

13-
import TSCBasic
1413
import PackageLoading
1514
import PackageModel
1615
import SourceControl
16+
import TSCBasic
1717
import TSCUtility
1818

1919
/// Local package container.
@@ -111,3 +111,53 @@ extension LocalPackageContainer: CustomStringConvertible {
111111
return "LocalPackageContainer(\(identifier.path))"
112112
}
113113
}
114+
115+
public class LocalPackageContainerProvider: PackageContainerProvider {
116+
let manifestLoader: ManifestLoaderProtocol
117+
let mirrors: DependencyMirrors
118+
119+
/// The tools version currently in use. Only the container versions less than and equal to this will be provided by
120+
/// the container.
121+
let currentToolsVersion: ToolsVersion
122+
123+
/// The tools version loader.
124+
let toolsVersionLoader: ToolsVersionLoaderProtocol
125+
126+
let fileSystem: FileSystem
127+
128+
public init(
129+
mirrors: DependencyMirrors = DependencyMirrors(),
130+
manifestLoader: ManifestLoaderProtocol,
131+
currentToolsVersion: ToolsVersion = ToolsVersion.currentToolsVersion,
132+
toolsVersionLoader: ToolsVersionLoaderProtocol = ToolsVersionLoader(),
133+
fileSystem: FileSystem = localFileSystem
134+
) {
135+
self.mirrors = mirrors
136+
self.manifestLoader = manifestLoader
137+
self.currentToolsVersion = currentToolsVersion
138+
self.toolsVersionLoader = toolsVersionLoader
139+
self.fileSystem = fileSystem
140+
}
141+
142+
public func getContainer(
143+
for identifier: PackageReference,
144+
skipUpdate: Bool,
145+
on queue: DispatchQueue,
146+
completion: @escaping (Result<PackageContainer, Swift.Error>) -> Void)
147+
{
148+
assert(identifier.kind != .remote)
149+
150+
let container = LocalPackageContainer(
151+
identifier,
152+
mirrors: self.mirrors,
153+
manifestLoader: self.manifestLoader,
154+
toolsVersionLoader: self.toolsVersionLoader,
155+
currentToolsVersion: self.currentToolsVersion,
156+
fs: self.fileSystem
157+
)
158+
159+
queue.async {
160+
completion(.success(container))
161+
}
162+
}
163+
}

Diff for: Sources/PackageGraph/PackageContainer.swift

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Dispatch
1212
import PackageLoading
1313
import PackageModel
1414
import SourceControl
15+
import Dispatch
1516
import struct TSCUtility.Version
1617

1718
/// A container of packages.

Diff for: Sources/PackageGraph/Pubgrub/PubgrubDependencyResolver.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -1468,10 +1468,13 @@ private final class ContainerProvider {
14681468
if self.prefetches[identifier] != nil {
14691469
continue
14701470
}
1471-
self.prefetches[identifier] = DispatchGroup()
1472-
self.prefetches[identifier]?.enter()
1471+
1472+
let sync = DispatchGroup()
1473+
self.prefetches[identifier] = sync
1474+
1475+
sync.enter()
14731476
self.provider.getContainer(for: identifier, skipUpdate: skipUpdate, on: self.queue) { result in
1474-
defer { self.prefetches[identifier]?.leave() }
1477+
defer { sync.leave() }
14751478
// only cache positive results
14761479
if case .success(let container) = result {
14771480
self.containersCache[identifier] = PubGrubPackageContainer(underlying: container, pinsMap: self.pinsMap, queue: self.queue)

0 commit comments

Comments
 (0)