Skip to content

Commit 037d075

Browse files
authored
update collections APIs to use package identity (#3743)
motivation: adoption of SE-0292 package registry chnages: * migrate APIs that take PackageRefernec to take PackageIdentity * adjust and update tests rdar://83073308 rdar://82954076
1 parent dc8c3d4 commit 037d075

15 files changed

+245
-180
lines changed

Sources/Commands/SwiftPackageCollectionsTool.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
196196
try JSONEncoder.makeWithDefaults().print(results.items)
197197
} else {
198198
results.items.forEach {
199-
print("\($0.package.repository.url): \($0.package.summary ?? "")")
199+
print("\($0.package.identity): \($0.package.summary ?? "")")
200200
}
201201
}
202202

@@ -208,7 +208,7 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
208208
try JSONEncoder.makeWithDefaults().print(packages)
209209
} else {
210210
packages.forEach {
211-
print("\($0.repository.url): \($0.summary ?? "")")
211+
print("\($0.identity): \($0.summary ?? "")")
212212
}
213213
}
214214
}
@@ -265,10 +265,9 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
265265
mutating func run() throws {
266266
try with { collections in
267267
let identity = PackageIdentity(url: packageURL)
268-
let reference = PackageReference.remote(identity: identity, location: packageURL)
269268

270269
do { // assume URL is for a package in an imported collection
271-
let result = try tsc_await { collections.getPackageMetadata(reference, callback: $0) }
270+
let result = try tsc_await { collections.getPackageMetadata(identity: identity, location: packageURL, callback: $0) }
272271

273272
if let versionString = version {
274273
guard let version = TSCUtility.Version(versionString), let result = result.package.versions.first(where: { $0.version == version }), let printedResult = printVersion(result) else {
@@ -314,7 +313,7 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
314313
let description = optionalRow("Description", collection.overview)
315314
let keywords = optionalRow("Keywords", collection.keywords?.joined(separator: ", "))
316315
let createdAt = optionalRow("Created At", DateFormatter().string(from: collection.createdAt))
317-
let packages = collection.packages.map { "\($0.repository.url)" }.joined(separator: "\n\(indent(levels: 2))")
316+
let packages = collection.packages.map { "\($0.identity)" }.joined(separator: "\n\(indent(levels: 2))")
318317

319318
if jsonOptions.json {
320319
try JSONEncoder.makeWithDefaults().print(collection)

Sources/PackageCollections/API.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public protocol PackageCollectionsProtocol {
111111
/// - Parameters:
112112
/// - reference: The package reference
113113
/// - callback: The closure to invoke when result becomes available
114+
@available(*, deprecated, message: "user getPackageMetadata(identity:) instead")
114115
func getPackageMetadata(
115116
_ reference: PackageReference,
116117
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void
@@ -126,12 +127,46 @@ public protocol PackageCollectionsProtocol {
126127
/// - collections: Optional. If specified, only look for package in these collections. Data from the most recently
127128
/// processed collection will be used.
128129
/// - callback: The closure to invoke when result becomes available
130+
@available(*, deprecated, message: "user getPackageMetadata(identity:) instead")
129131
func getPackageMetadata(
130132
_ reference: PackageReference,
131133
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
132134
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void
133135
)
134136

137+
/// Returns metadata for the package identified by the given `PackageIdentity`, along with the
138+
/// identifiers of `PackageCollection`s where the package is found.
139+
///
140+
/// A failure is returned if the package is not found.
141+
///
142+
/// - Parameters:
143+
/// - identity: The package identity
144+
/// - location: The package location (optional for deduplication)
145+
/// - callback: The closure to invoke when result becomes available
146+
func getPackageMetadata(
147+
identity: PackageIdentity,
148+
location: String?,
149+
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void
150+
)
151+
152+
/// Returns metadata for the package identified by the given `PackageIdentity`, along with the
153+
/// identifiers of `PackageCollection`s where the package is found.
154+
///
155+
/// A failure is returned if the package is not found.
156+
///
157+
/// - Parameters:
158+
/// - identity: The package identity
159+
/// - location: The package location (optional for deduplication)
160+
/// - collections: Optional. If specified, only look for package in these collections. Data from the most recently
161+
/// processed collection will be used.
162+
/// - callback: The closure to invoke when result becomes available
163+
func getPackageMetadata(
164+
identity: PackageIdentity,
165+
location: String?,
166+
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
167+
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void
168+
)
169+
135170
/// Lists packages from the specified collections.
136171
///
137172
/// - Parameters:

Sources/PackageCollections/Model/Package.swift

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import SourceControl
1717
extension PackageCollectionsModel {
1818
/// Package metadata
1919
public struct Package: Codable, Equatable {
20-
/// Package reference
21-
public let reference: PackageReference
20+
/// Package identity
21+
public let identity: PackageIdentity
2222

23-
/// Package's repository address
24-
public let repository: RepositorySpecifier
23+
/// Package location
24+
public let location: String
2525

2626
/// Package description
2727
public let summary: String?
@@ -83,9 +83,20 @@ extension PackageCollectionsModel {
8383
/// The package's programming languages
8484
public let languages: Set<String>?
8585

86+
@available(*, deprecated, message: "use identity and location instead")
87+
public var reference: PackageReference {
88+
return .init(identity: self.identity, kind: .remote, location: self.location, name: nil)
89+
}
90+
91+
@available(*, deprecated, message: "use identity and location instead")
92+
public var repository: RepositorySpecifier {
93+
return .init(url: self.location)
94+
}
95+
8696
/// Initializes a `Package`
8797
init(
88-
repository: RepositorySpecifier,
98+
identity: PackageIdentity,
99+
location: String,
89100
summary: String?,
90101
keywords: [String]?,
91102
versions: [Version],
@@ -95,8 +106,8 @@ extension PackageCollectionsModel {
95106
authors: [Author]?,
96107
languages: Set<String>?
97108
) {
98-
self.reference = .init(repository: repository)
99-
self.repository = repository
109+
self.identity = identity
110+
self.location = location
100111
self.summary = summary
101112
self.keywords = keywords
102113
self.versions = versions
@@ -271,6 +282,6 @@ extension PackageCollectionsModel.Package.Version {
271282

272283
extension Model.Package {
273284
var displayName: String {
274-
self.latestVersion?.packageName ?? self.reference.identity.description
285+
self.latestVersion?.packageName ?? self.identity.description
275286
}
276287
}

Sources/PackageCollections/Model/TargetListResult.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ extension PackageCollectionsModel.TargetListResult {
3333
public struct Package: Hashable, Encodable {
3434
public typealias Version = PackageCollectionsModel.TargetListResult.PackageVersion
3535

36-
/// Package's repository address
37-
public let repository: RepositorySpecifier
36+
/// Package's identity
37+
public let identity: PackageIdentity
38+
39+
/// Package's location
40+
public let location: String
3841

3942
/// Package description
4043
public let summary: String?
@@ -44,6 +47,11 @@ extension PackageCollectionsModel.TargetListResult {
4447

4548
/// Package collections that contain this package and at least one of the `versions`
4649
public let collections: [PackageCollectionsModel.CollectionIdentifier]
50+
51+
@available(*, deprecated, message: "use identity and location instead")
52+
public var repository: RepositorySpecifier {
53+
return .init(url: self.location)
54+
}
4755
}
4856
}
4957

Sources/PackageCollections/PackageCollections.swift

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -314,26 +314,26 @@ public struct PackageCollections: PackageCollectionsProtocol {
314314
case .failure(let error):
315315
callback(.failure(error))
316316
case .success(let collections):
317-
var packageCollections = [PackageReference: (package: Model.Package, collections: Set<Model.CollectionIdentifier>)]()
317+
var packageCollections = [PackageIdentity: (package: Model.Package, collections: Set<Model.CollectionIdentifier>)]()
318318
// Use package data from the most recently processed collection
319319
collections.sorted(by: { $0.lastProcessedAt > $1.lastProcessedAt }).forEach { collection in
320320
collection.packages.forEach { package in
321-
var entry = packageCollections.removeValue(forKey: package.reference)
321+
var entry = packageCollections.removeValue(forKey: package.identity)
322322
if entry == nil {
323323
entry = (package, .init())
324324
}
325325

326326
if var entry = entry {
327327
entry.collections.insert(collection.identifier)
328-
packageCollections[package.reference] = entry
328+
packageCollections[package.identity] = entry
329329
}
330330
}
331331
}
332332

333333
let result = PackageCollectionsModel.PackageSearchResult(
334334
items: packageCollections.sorted { $0.value.package.displayName < $1.value.package.displayName }
335335
.map { entry in
336-
.init(package: entry.value.package, collections: Array(entry.value.collections))
336+
.init(package: entry.value.package, collections: Array(entry.value.collections))
337337
}
338338
)
339339
callback(.success(result))
@@ -343,32 +343,48 @@ public struct PackageCollections: PackageCollectionsProtocol {
343343

344344
// MARK: - Package Metadata
345345

346+
@available(*, deprecated, message: "user identity based API instead")
346347
public func getPackageMetadata(_ reference: PackageReference,
347348
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void) {
348349
self.getPackageMetadata(reference, collections: nil, callback: callback)
349350
}
350351

352+
@available(*, deprecated, message: "user identity based API instead")
351353
public func getPackageMetadata(_ reference: PackageReference,
352354
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
353355
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void) {
356+
self.getPackageMetadata(identity: reference.identity, location: reference.location, collections: .none, callback: callback)
357+
}
358+
359+
public func getPackageMetadata(identity: PackageIdentity,
360+
location: String? = .none,
361+
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void) {
362+
self.getPackageMetadata(identity: identity, location: location, collections: .none, callback: callback)
363+
}
364+
365+
public func getPackageMetadata(identity: PackageIdentity,
366+
location: String? = .none,
367+
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
368+
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void) {
354369
guard Self.isSupportedPlatform else {
355370
return callback(.failure(PackageCollectionError.unsupportedPlatform))
356371
}
357372

358373
// first find in storage
359-
self.findPackage(reference: reference, collections: collections) { result in
374+
self.findPackage(identity: identity, location: location, collections: collections) { result in
360375
switch result {
361376
case .failure(let error):
362377
callback(.failure(error))
363378
case .success(let packageSearchResult):
379+
364380
// then try to get more metadata from provider (optional)
365-
let authTokenType = self.metadataProvider.getAuthTokenType(for: reference)
381+
let authTokenType = self.metadataProvider.getAuthTokenType(for: packageSearchResult.package.location)
366382
let isAuthTokenConfigured = authTokenType.flatMap { self.configuration.authTokens()?[$0] } != nil
367383

368-
self.metadataProvider.get(reference) { result in
384+
self.metadataProvider.get(identity: packageSearchResult.package.identity, location: packageSearchResult.package.location) { result in
369385
switch result {
370386
case .failure(let error):
371-
self.diagnosticsEngine?.emit(warning: "Failed fetching information about \(reference) from \(self.metadataProvider.name): \(error)")
387+
self.diagnosticsEngine?.emit(warning: "Failed fetching information about \(identity) from \(self.metadataProvider.name): \(error)")
372388

373389
let provider: PackageMetadataProviderContext?
374390
switch error {
@@ -517,7 +533,8 @@ public struct PackageCollections: PackageCollectionsProtocol {
517533
}
518534
}
519535

520-
func findPackage(reference: PackageReference,
536+
func findPackage(identity: PackageIdentity,
537+
location: String?,
521538
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
522539
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult.Item, Error>) -> Void) {
523540
self.storage.sources.list { result in
@@ -530,17 +547,23 @@ public struct PackageCollections: PackageCollectionsProtocol {
530547
collectionIdentifiers = collectionIdentifiers.filter { collections.contains($0) }
531548
}
532549
if collectionIdentifiers.isEmpty {
533-
return callback(.failure(NotFoundError("\(reference)")))
550+
return callback(.failure(NotFoundError("\(identity)")))
534551
}
535-
self.storage.collections.findPackage(identifier: reference.identity, collectionIdentifiers: collectionIdentifiers) { findPackageResult in
552+
self.storage.collections.findPackage(identifier: identity, collectionIdentifiers: collectionIdentifiers) { findPackageResult in
536553
switch findPackageResult {
537554
case .failure(let error):
538555
callback(.failure(error))
539556
case .success(let packagesCollections):
540-
// A package identity can be associated with multiple repository URLs
541-
let matches = packagesCollections.packages.filter { $0.reference.canonicalLocation == reference.canonicalLocation }
557+
let matches: [PackageCollectionsModel.Package]
558+
if let location = location {
559+
// A package identity can be associated with multiple repository URLs
560+
matches = packagesCollections.packages.filter { CanonicalPackageIdentity($0.location) == CanonicalPackageIdentity(location) }
561+
}
562+
else {
563+
matches = packagesCollections.packages
564+
}
542565
guard let package = matches.first else {
543-
return callback(.failure(NotFoundError("\(reference)")))
566+
return callback(.failure(NotFoundError("\(identity), \(location ?? "none")")))
544567
}
545568
callback(.success(.init(package: package, collections: packagesCollections.collections)))
546569
}
@@ -550,22 +573,22 @@ public struct PackageCollections: PackageCollectionsProtocol {
550573
}
551574

552575
private func targetListResultFromCollections(_ collections: [Model.Collection]) -> Model.TargetListResult {
553-
var packageCollections = [PackageReference: (package: Model.Package, collections: Set<Model.CollectionIdentifier>)]()
554-
var targetsPackages = [String: (target: Model.Target, packages: Set<PackageReference>)]()
576+
var packageCollections = [PackageIdentity: (package: Model.Package, collections: Set<Model.CollectionIdentifier>)]()
577+
var targetsPackages = [String: (target: Model.Target, packages: Set<PackageIdentity>)]()
555578

556579
collections.forEach { collection in
557580
collection.packages.forEach { package in
558581
// Avoid copy-on-write: remove entry from dictionary before mutating
559-
var entry = packageCollections.removeValue(forKey: package.reference) ?? (package, .init())
582+
var entry = packageCollections.removeValue(forKey: package.identity) ?? (package, .init())
560583
entry.collections.insert(collection.identifier)
561-
packageCollections[package.reference] = entry
584+
packageCollections[package.identity] = entry
562585

563586
package.versions.forEach { version in
564587
version.manifests.values.forEach { manifest in
565588
manifest.targets.forEach { target in
566589
// Avoid copy-on-write: remove entry from dictionary before mutating
567590
var entry = targetsPackages.removeValue(forKey: target.name) ?? (target: target, packages: .init())
568-
entry.packages.insert(package.reference)
591+
entry.packages.insert(package.identity)
569592
targetsPackages[target.name] = entry
570593
}
571594
}
@@ -586,7 +609,8 @@ public struct PackageCollections: PackageCollectionsProtocol {
586609
)
587610
}
588611
}
589-
return .init(repository: pair.package.repository,
612+
return .init(identity: pair.package.identity,
613+
location: pair.package.location,
590614
summary: pair.package.summary,
591615
versions: versions,
592616
collections: Array(pair.collections))
@@ -614,7 +638,8 @@ public struct PackageCollections: PackageCollectionsProtocol {
614638
versions.sort(by: >)
615639

616640
return Model.Package(
617-
repository: package.repository,
641+
identity: package.identity,
642+
location: package.location,
618643
summary: basicMetadata?.summary ?? package.summary,
619644
keywords: basicMetadata?.keywords ?? package.keywords,
620645
versions: versions,
@@ -634,9 +659,3 @@ private struct UnknownProvider: Error {
634659
self.sourceType = sourceType
635660
}
636661
}
637-
638-
private extension PackageReference {
639-
var canonicalLocation: String {
640-
(self.location.hasSuffix(".git") ? String(self.location.dropLast(4)) : self.location).lowercased()
641-
}
642-
}

0 commit comments

Comments
 (0)