Skip to content

Commit 35d9d9e

Browse files
committed
Implement package resolution through a registry
1 parent f25bfc6 commit 35d9d9e

File tree

4 files changed

+125
-39
lines changed

4 files changed

+125
-39
lines changed

Sources/PackageGraph/PackageGraph+Loading.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ private func createResolvedPackages(
231231
var dependenciesByNameForTargetDependencyResolution = [String: ResolvedPackageBuilder]()
232232

233233
// Establish the manifest-declared package dependencies.
234-
package.manifest.dependenciesRequired(for: packageBuilder.productFilter).forEach { dependency in
234+
try package.manifest.dependenciesRequired(for: packageBuilder.productFilter).forEach { dependency in
235235
// FIXME: change this validation logic to use identity instead of location
236236
let dependencyLocation: String
237237
switch dependency {
@@ -244,9 +244,12 @@ private func createResolvedPackages(
244244
case .remote(let url):
245245
dependencyLocation = url.absoluteString
246246
}
247-
case .registry:
248-
// FIXME
249-
fatalError("registry based dependencies not implemented yet")
247+
case .registry(let settings):
248+
guard let _ = settings.identity.scopeAndName else {
249+
throw InternalError("invalid package identifier \(settings.identity)")
250+
}
251+
252+
dependencyLocation = "\(settings.identity)"
250253
}
251254

252255
// Otherwise, look it up by its identity.

Sources/PackageGraph/PackageModel+Extensions.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ extension PackageDependency {
2525
case .remote(let url):
2626
packageKind = .remoteSourceControl(url)
2727
}
28-
case .registry:
29-
// FIXME
30-
fatalError("registry based dependencies not implemented yet")
28+
case .registry(let settings):
29+
packageKind = .registry(settings.identity)
3130
}
31+
3232
return PackageReference(identity: self.identity, kind: packageKind)
3333
}
3434
}

Sources/PackageGraph/PinsStore.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ fileprivate struct PinsStorage {
250250
case .remoteSourceControl(let url):
251251
kind = .remoteSourceControl
252252
location = url.absoluteString
253+
case .registry(let identity):
254+
kind = .registry
255+
location = "\(identity)" // FIXME:
253256
default:
254257
throw StringError("invalid package type \(pin.packageRef.kind)")
255258
}
@@ -265,6 +268,7 @@ fileprivate struct PinsStorage {
265268
enum Kind: String, Codable {
266269
case localSourceControl
267270
case remoteSourceControl
271+
case registry
268272
}
269273
}
270274

@@ -317,10 +321,12 @@ extension PinsStore.Pin {
317321

318322
extension PinsStore.Pin {
319323
fileprivate init(_ pin: PinsStorage.V2.Pin, mirrors: DependencyMirrors) throws {
320-
let packageRef: PackageReference
321324
let identity = pin.identity
325+
322326
// rdar://52529014, rdar://52529011: pin file should store the original location but remap when loading
323327
let location = mirrors.effectiveURL(for: pin.location)
328+
329+
let packageRef: PackageReference
324330
switch pin.kind {
325331
case .localSourceControl:
326332
packageRef = try .localSourceControl(identity: identity, path: AbsolutePath(validating: location))
@@ -329,7 +335,10 @@ extension PinsStore.Pin {
329335
throw StringError("invalid url location: \(location)")
330336
}
331337
packageRef = .remoteSourceControl(identity: identity, url: url)
338+
case .registry:
339+
packageRef = .registry(identity: identity)
332340
}
341+
333342
self.init(
334343
packageRef: packageRef,
335344
state: try .init(pin.state)

Sources/Workspace/Workspace.swift

Lines changed: 105 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,22 +2368,25 @@ extension Workspace {
23682368

23692369
switch requirement {
23702370
case .version(let version):
2371-
// FIXME: We need to get the revision here, and we don't have a
2372-
// way to get it back out of the resolver which is very
2373-
// annoying. Maybe we should make an SPI on the provider for
2374-
// this?
2375-
// FIXME: this should not block
2376-
// FIXME: this should be updated to support registry
2377-
guard let container = (try temp_await {
2378-
self.getContainer(for: package, skipUpdate: true, on: .sharedConcurrent, completion: $0)
2379-
}) as? SourceControlPackageContainer else {
2380-
throw InternalError("invalid container for \(package) expected a RepositoryPackageContainer")
2381-
}
2382-
guard let tag = container.getTag(for: version) else {
2383-
throw InternalError("unable to get tag for \(package) \(version); available versions \(try container.versionsDescending())")
2371+
if let _ = package.identity.scopeAndName {
2372+
checkoutState = .version(version, revision: .init(identifier: "\(version)"))
2373+
} else {
2374+
// FIXME: We need to get the revision here, and we don't have a
2375+
// way to get it back out of the resolver which is very
2376+
// annoying. Maybe we should make an SPI on the provider for
2377+
// this?
2378+
// FIXME: this should not block
2379+
guard let container = (try temp_await {
2380+
self.getContainer(for: package, skipUpdate: true, on: .sharedConcurrent, completion: $0)
2381+
}) as? SourceControlPackageContainer else {
2382+
throw InternalError("invalid container for \(package) expected a SourceControlPackageContainer")
2383+
}
2384+
guard let tag = container.getTag(for: version) else {
2385+
throw InternalError("unable to get tag for \(package) \(version); available versions \(try container.versionsDescending())")
2386+
}
2387+
let revision = try container.getRevision(forTag: tag)
2388+
checkoutState = .version(version, revision: revision)
23842389
}
2385-
let revision = try container.getRevision(forTag: tag)
2386-
checkoutState = .version(version, revision: revision)
23872390

23882391
case .revision(let revision, .none):
23892392
checkoutState = .revision(revision)
@@ -2828,8 +2831,33 @@ extension Workspace: PackageContainerProvider {
28282831
completion(.failure(error))
28292832
}
28302833
}
2831-
case .registry:
2832-
fatalError("registry dependencies are supported at this point")
2834+
case .registry(let identity):
2835+
do {
2836+
guard let registryManager = registryManager else {
2837+
throw InternalError("registry manager not configured")
2838+
}
2839+
2840+
guard let _ = identity.scopeAndName else {
2841+
throw InternalError("cannot get registry container for package \(identity)")
2842+
}
2843+
2844+
let container = RegistryPackageContainer(
2845+
package: package,
2846+
identityResolver: identityResolver,
2847+
manager: registryManager,
2848+
manifestLoader: manifestLoader,
2849+
toolsVersionLoader: toolsVersionLoader,
2850+
currentToolsVersion: currentToolsVersion
2851+
)
2852+
2853+
queue.async {
2854+
completion(.success(container))
2855+
}
2856+
} catch {
2857+
queue.async {
2858+
completion(.failure(error))
2859+
}
2860+
}
28332861
}
28342862
}
28352863

@@ -2846,7 +2874,11 @@ extension Workspace: PackageContainerProvider {
28462874
case .localSourceControl, .remoteSourceControl:
28472875
return try self.checkoutRepository(package: package, at: checkoutState)
28482876
case .registry:
2849-
fatalError("registry dependencies are supported at this point")
2877+
guard case .version(let version, _) = checkoutState else {
2878+
fatalError("cannot download source archive for package \(package) with checkout state \(checkoutState)")
2879+
}
2880+
2881+
return try self.downloadSourceArchive(for: package, at: version)
28502882
}
28512883
}
28522884

@@ -2863,24 +2895,16 @@ extension Workspace: PackageContainerProvider {
28632895
// a local package.
28642896
//
28652897
// Note that we don't actually remove a local package from disk.
2866-
switch dependency.state {
2867-
case .local:
2898+
if case .local = dependency.state {
28682899
self.state.dependencies.remove(package.identity)
28692900
try self.state.save()
28702901
return
2871-
case .checkout, .edited:
2872-
break
2873-
case .downloaded:
2874-
break
28752902
}
28762903

2877-
// Inform the delegate.
2878-
delegate?.removing(repository: dependency.packageRef.location)
2879-
28802904
// Compute the dependency which we need to remove.
28812905
let dependencyToRemove: ManagedDependency
28822906

2883-
if case .edited(let _basedOn, let unmanagedPath) = dependency.state, let basedOn = _basedOn {
2907+
if case .edited(let basedOn?, let unmanagedPath) = dependency.state {
28842908
// Remove the underlying dependency for edited packages.
28852909
dependencyToRemove = basedOn
28862910
let updatedDependency = Workspace.ManagedDependency.edited(
@@ -2895,13 +2919,17 @@ extension Workspace: PackageContainerProvider {
28952919
self.state.dependencies.remove(dependencyToRemove.packageRef.identity)
28962920
}
28972921

2922+
delegate?.removing(repository: dependency.packageRef.location)
2923+
28982924
switch package.kind {
2899-
case .root, .fileSystem:
2900-
fatalError("local dependencies are supported")
2925+
case .root(let path):
2926+
throw InternalError("root dependency \(dependencyToRemove) cannot be removed at \(path)")
2927+
case .fileSystem(let path):
2928+
throw InternalError("local dependency \(dependencyToRemove) cannot be removed at \(path)")
29012929
case .localSourceControl, .remoteSourceControl:
29022930
try self.removeRepository(dependency: dependencyToRemove)
29032931
case .registry:
2904-
fatalError("registry dependencies are supported at this point")
2932+
try self.removeSourceArchive(for: dependencyToRemove)
29052933
}
29062934

29072935
// Save the state.
@@ -3026,6 +3054,52 @@ extension Workspace {
30263054
}
30273055
}
30283056

3057+
// MARK: - Source archive management
3058+
3059+
extension Workspace {
3060+
func downloadSourceArchive(
3061+
for package: PackageReference,
3062+
at version: Version
3063+
) throws -> AbsolutePath {
3064+
guard let registryManager = registryManager else {
3065+
throw InternalError("registry manager not initialized")
3066+
}
3067+
3068+
let path = self.location.sourceArchivesSubdirectory(for: package, at: version)
3069+
3070+
if !localFileSystem.exists(path) {
3071+
_ = try temp_await {
3072+
registryManager.downloadSourceArchive(for: version,
3073+
of: package,
3074+
into: localFileSystem,
3075+
at: path,
3076+
on: .sharedConcurrent,
3077+
completion: $0)
3078+
}
3079+
}
3080+
3081+
self.state.dependencies.add(.downloaded(packageRef: package, version: version))
3082+
try self.state.save()
3083+
3084+
return path
3085+
}
3086+
3087+
func removeSourceArchive(
3088+
for dependency: ManagedDependency
3089+
) throws {
3090+
guard case .downloaded(let version) = dependency.state else {
3091+
throw InternalError("cannot remove source archive for \(dependency) with state \(dependency.state)")
3092+
}
3093+
3094+
let path = self.location.sourceArchivesSubdirectory(for: dependency.packageRef, at: version)
3095+
3096+
try localFileSystem.removeFileTree(path)
3097+
3098+
self.state.dependencies.remove(dependency.packageRef.identity)
3099+
3100+
try self.state.save()
3101+
}
3102+
}
30293103

30303104
// MARK: - Utility extensions
30313105

0 commit comments

Comments
 (0)