Skip to content

Commit 73990fb

Browse files
committed
Add publishedAt to PackageSearchClient
1 parent 80b5493 commit 73990fb

File tree

1 file changed

+132
-77
lines changed

1 file changed

+132
-77
lines changed

Sources/PackageMetadata/PackageMetadata.swift

Lines changed: 132 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import PackageModel
1717
import PackageRegistry
1818
import SourceControl
1919

20+
import struct Foundation.Date
2021
import struct Foundation.URL
2122
import struct TSCBasic.AbsolutePath
2223
import protocol TSCBasic.FileSystem
@@ -70,9 +71,24 @@ public struct Package {
7071
public let resources: [Resource]
7172
public let author: Author?
7273
public let description: String?
74+
public let publishedAt: Date?
7375
public let latestVersion: Version?
7476

75-
fileprivate init(identity: PackageIdentity, location: String? = nil, branches: [String] = [], versions: [Version], licenseURL: URL? = nil, readmeURL: URL? = nil, repositoryURLs: [URL]?, resources: [Resource], author: Author?, description: String?, latestVersion: Version? = nil, source: Source) {
77+
fileprivate init(
78+
identity: PackageIdentity,
79+
location: String? = nil,
80+
branches: [String] = [],
81+
versions: [Version],
82+
licenseURL: URL? = nil,
83+
readmeURL: URL? = nil,
84+
repositoryURLs: [URL]?,
85+
resources: [Resource],
86+
author: Author?,
87+
description: String?,
88+
publishedAt: Date?,
89+
latestVersion: Version? = nil,
90+
source: Source
91+
) {
7692
self.identity = identity
7793
self.location = location
7894
self.branches = branches
@@ -83,6 +99,7 @@ public struct Package {
8399
self.resources = resources
84100
self.author = author
85101
self.description = description
102+
self.publishedAt = publishedAt
86103
self.latestVersion = latestVersion
87104
self.source = source
88105
}
@@ -100,20 +117,23 @@ public struct PackageSearchClient {
100117
observabilityScope: ObservabilityScope
101118
) {
102119
self.registryClient = registryClient
103-
self.indexAndCollections = PackageIndexAndCollections(fileSystem: fileSystem, observabilityScope: observabilityScope)
120+
self.indexAndCollections = PackageIndexAndCollections(
121+
fileSystem: fileSystem,
122+
observabilityScope: observabilityScope
123+
)
104124
self.fileSystem = fileSystem
105125
self.observabilityScope = observabilityScope
106126
}
107127

108128
var repositoryProvider: RepositoryProvider {
109-
return GitRepositoryProvider()
129+
GitRepositoryProvider()
110130
}
111131

112132
// FIXME: This matches the current implementation, but we may want be smarter about it?
113133
private func guessReadMeURL(baseURL: URL, defaultBranch: String) -> URL {
114-
return baseURL.appendingPathComponent("raw").appendingPathComponent(defaultBranch).appendingPathComponent("README.md")
134+
baseURL.appendingPathComponent("raw").appendingPathComponent(defaultBranch).appendingPathComponent("README.md")
115135
}
116-
136+
117137
private func guessReadMeURL(alternateLocations: [URL]?) -> URL? {
118138
if let alternateURL = alternateLocations?.first {
119139
// FIXME: This is pretty crude, we should let the registry metadata provide the value instead.
@@ -129,6 +149,7 @@ public struct PackageSearchClient {
129149
public let resources: [Package.Resource]
130150
public let author: Package.Author?
131151
public let description: String?
152+
public let publishedAt: Date?
132153
}
133154

134155
private func getVersionMetadata(
@@ -150,7 +171,8 @@ public struct PackageSearchClient {
150171
repositoryURLs: metadata.repositoryURLs,
151172
resources: metadata.resources.map { .init($0) },
152173
author: metadata.author.map { .init($0) },
153-
description: metadata.description
174+
description: metadata.description,
175+
publishedAt: metadata.publishedAt
154176
)
155177
})
156178
}
@@ -163,24 +185,27 @@ public struct PackageSearchClient {
163185
let identity = PackageIdentity.plain(query)
164186

165187
// Search the package index and collections for a search term.
166-
let search = { (error: Error?) -> Void in
188+
let search = { (error: Error?) in
167189
self.indexAndCollections.findPackages(query) { result in
168190
do {
169191
let packages = try result.get().items.map {
170-
Package(identity: $0.package.identity,
171-
location: $0.package.location,
172-
versions: $0.package.versions.map { $0.version },
173-
licenseURL: nil,
174-
readmeURL: $0.package.readmeURL,
175-
repositoryURLs: nil,
176-
resources: [],
177-
author: nil,
178-
description: nil,
179-
latestVersion: nil, // this only makes sense in connection with providing versioned metadata
180-
source: .indexAndCollections(collections: $0.collections, indexes: $0.indexes)
192+
Package(
193+
identity: $0.package.identity,
194+
location: $0.package.location,
195+
versions: $0.package.versions.map(\.version),
196+
licenseURL: nil,
197+
readmeURL: $0.package.readmeURL,
198+
repositoryURLs: nil,
199+
resources: [],
200+
author: nil,
201+
description: nil,
202+
publishedAt: nil,
203+
latestVersion: nil,
204+
// this only makes sense in connection with providing versioned metadata
205+
source: .indexAndCollections(collections: $0.collections, indexes: $0.indexes)
181206
)
182207
}
183-
if packages.isEmpty, let error = error {
208+
if packages.isEmpty, let error {
184209
// If the search result is empty and we had a previous error, emit it now.
185210
return callback(.failure(error))
186211
} else {
@@ -196,32 +221,48 @@ public struct PackageSearchClient {
196221
// determine the available version tags and branches. If the search term cannot be interpreted
197222
// as a URL or there are any errors during the process, we fall back to searching the configured
198223
// index or package collections.
199-
let fetchStandalonePackageByURL = { (error: Error?) -> Void in
224+
let fetchStandalonePackageByURL = { (error: Error?) in
200225
guard let url = URL(string: query) else {
201226
return search(error)
202227
}
203228

204229
do {
205-
try withTemporaryDirectory(removeTreeOnDeinit: true) { (tempDir: AbsolutePath) -> Void in
230+
try withTemporaryDirectory(removeTreeOnDeinit: true) { (tempDir: AbsolutePath) in
206231
let tempPath = tempDir.appending(component: url.lastPathComponent)
207232
do {
208233
let repositorySpecifier = RepositorySpecifier(url: url)
209-
try self.repositoryProvider.fetch(repository: repositorySpecifier, to: tempPath, progressHandler: nil)
210-
if self.repositoryProvider.isValidDirectory(tempPath), let repository = try self.repositoryProvider.open(repository: repositorySpecifier, at: tempPath) as? GitRepository {
234+
try self.repositoryProvider.fetch(
235+
repository: repositorySpecifier,
236+
to: tempPath,
237+
progressHandler: nil
238+
)
239+
if self.repositoryProvider.isValidDirectory(tempPath),
240+
let repository = try self.repositoryProvider.open(
241+
repository: repositorySpecifier,
242+
at: tempPath
243+
) as? GitRepository
244+
{
211245
let branches = try repository.getBranches()
212246
let versions = try repository.getTags().compactMap { Version($0) }
213-
let package = Package(identity: .init(url: url),
214-
location: url.absoluteString,
215-
branches: branches,
216-
versions: versions,
217-
licenseURL: nil,
218-
readmeURL: self.guessReadMeURL(baseURL: url, defaultBranch: try repository.getDefaultBranch()),
219-
repositoryURLs: nil,
220-
resources: [],
221-
author: nil,
222-
description: nil,
223-
latestVersion: nil, // this only makes sense in connection with providing versioned metadata
224-
source: .sourceControl(url: url))
247+
let package = Package(
248+
identity: .init(url: url),
249+
location: url.absoluteString,
250+
branches: branches,
251+
versions: versions,
252+
licenseURL: nil,
253+
readmeURL: self.guessReadMeURL(
254+
baseURL: url,
255+
defaultBranch: try repository.getDefaultBranch()
256+
),
257+
repositoryURLs: nil,
258+
resources: [],
259+
author: nil,
260+
description: nil,
261+
publishedAt: nil,
262+
latestVersion: nil,
263+
// this only makes sense in connection with providing versioned metadata
264+
source: .sourceControl(url: url)
265+
)
225266
return callback(.success([package]))
226267
}
227268
} catch {
@@ -238,7 +279,11 @@ public struct PackageSearchClient {
238279
// or the search term does not work as a registry identity, we will fall back on
239280
// `fetchStandalonePackageByURL`.
240281
if identity.isRegistry {
241-
return self.registryClient.getPackageMetadata(package: identity, observabilityScope: observabilityScope, callbackQueue: DispatchQueue.sharedConcurrent) { result in
282+
return self.registryClient.getPackageMetadata(
283+
package: identity,
284+
observabilityScope: observabilityScope,
285+
callbackQueue: DispatchQueue.sharedConcurrent
286+
) { result in
242287
do {
243288
let metadata = try result.get()
244289
let versions = metadata.versions.sorted(by: >)
@@ -252,47 +297,55 @@ public struct PackageSearchClient {
252297
let resources: [Package.Resource]
253298
let author: Package.Author?
254299
let description: String?
300+
let publishedAt: Date?
255301
if case .success(let metadata) = result {
256302
licenseURL = metadata.licenseURL
257303
readmeURL = metadata.readmeURL
258304
repositoryURLs = metadata.repositoryURLs
259305
resources = metadata.resources
260306
author = metadata.author
261307
description = metadata.description
308+
publishedAt = metadata.publishedAt
262309
} else {
263310
licenseURL = nil
264311
readmeURL = self.guessReadMeURL(alternateLocations: metadata.alternateLocations)
265312
repositoryURLs = nil
266313
resources = []
267314
author = nil
268315
description = nil
316+
publishedAt = nil
269317
}
270318

271-
return callback(.success([Package(identity: identity,
272-
versions: metadata.versions,
273-
licenseURL: licenseURL,
274-
readmeURL: readmeURL,
275-
repositoryURLs: repositoryURLs,
276-
resources: resources,
277-
author: author,
278-
description: description,
279-
latestVersion: version,
280-
source: .registry(url: metadata.registry.url)
281-
)]))
319+
return callback(.success([Package(
320+
identity: identity,
321+
versions: metadata.versions,
322+
licenseURL: licenseURL,
323+
readmeURL: readmeURL,
324+
repositoryURLs: repositoryURLs,
325+
resources: resources,
326+
author: author,
327+
description: description,
328+
publishedAt: publishedAt,
329+
latestVersion: version,
330+
source: .registry(url: metadata.registry.url)
331+
)]))
282332
}
283333
} else {
284334
let readmeURL: URL? = self.guessReadMeURL(alternateLocations: metadata.alternateLocations)
285-
return callback(.success([Package(identity: identity,
286-
versions: metadata.versions,
287-
licenseURL: nil,
288-
readmeURL: readmeURL,
289-
repositoryURLs: nil,
290-
resources: [],
291-
author: nil,
292-
description: nil,
293-
latestVersion: nil, // this only makes sense in connection with providing versioned metadata
294-
source: .registry(url: metadata.registry.url)
295-
)]))
335+
return callback(.success([Package(
336+
identity: identity,
337+
versions: metadata.versions,
338+
licenseURL: nil,
339+
readmeURL: readmeURL,
340+
repositoryURLs: nil,
341+
resources: [],
342+
author: nil,
343+
description: nil,
344+
publishedAt: nil,
345+
latestVersion: nil,
346+
// this only makes sense in connection with providing versioned metadata
347+
source: .registry(url: metadata.registry.url)
348+
)]))
296349
}
297350
} catch {
298351
return fetchStandalonePackageByURL(error)
@@ -310,7 +363,7 @@ public struct PackageSearchClient {
310363
callbackQueue: DispatchQueue,
311364
completion: @escaping (Result<Set<PackageIdentity>, Error>) -> Void
312365
) {
313-
return registryClient.lookupIdentities(
366+
registryClient.lookupIdentities(
314367
scmURL: scmURL,
315368
timeout: timeout,
316369
observabilityScope: observabilityScope,
@@ -326,43 +379,45 @@ public struct PackageSearchClient {
326379
callbackQueue: DispatchQueue,
327380
completion: @escaping (Result<Set<URL>, Error>) -> Void
328381
) {
329-
return registryClient.getPackageMetadata(
382+
registryClient.getPackageMetadata(
330383
package: package,
331384
timeout: timeout,
332385
observabilityScope: observabilityScope,
333-
callbackQueue: callbackQueue) { result in
334-
do {
335-
let metadata = try result.get()
336-
let alternateLocations = metadata.alternateLocations ?? []
337-
return completion(.success(Set(alternateLocations)))
338-
} catch {
339-
return completion(.failure(error))
340-
}
386+
callbackQueue: callbackQueue
387+
) { result in
388+
do {
389+
let metadata = try result.get()
390+
let alternateLocations = metadata.alternateLocations ?? []
391+
return completion(.success(Set(alternateLocations)))
392+
} catch {
393+
return completion(.failure(error))
341394
}
395+
}
342396
}
343397
}
344398

345-
fileprivate extension Package.Signing {
346-
init(_ signing: RegistryClient.PackageVersionMetadata.Signing) {
399+
extension Package.Signing {
400+
fileprivate init(_ signing: RegistryClient.PackageVersionMetadata.Signing) {
347401
self.init(
348402
signatureBase64Encoded: signing.signatureBase64Encoded,
349403
signatureFormat: signing.signatureFormat
350404
)
351405
}
352406
}
353407

354-
fileprivate extension Package.Resource {
355-
init(_ resource: RegistryClient.PackageVersionMetadata.Resource) {
408+
extension Package.Resource {
409+
fileprivate init(_ resource: RegistryClient.PackageVersionMetadata.Resource) {
356410
self.init(
357411
name: resource.name,
358412
type: resource.type,
359413
checksum: resource.checksum,
360-
signing: resource.signing.map { .init($0) })
414+
signing: resource.signing.map { .init($0) }
415+
)
361416
}
362417
}
363418

364-
fileprivate extension Package.Author {
365-
init(_ author: RegistryClient.PackageVersionMetadata.Author) {
419+
extension Package.Author {
420+
fileprivate init(_ author: RegistryClient.PackageVersionMetadata.Author) {
366421
self.init(
367422
name: author.name,
368423
email: author.email,
@@ -373,8 +428,8 @@ fileprivate extension Package.Author {
373428
}
374429
}
375430

376-
fileprivate extension Package.Organization {
377-
init(_ organization: RegistryClient.PackageVersionMetadata.Organization) {
431+
extension Package.Organization {
432+
fileprivate init(_ organization: RegistryClient.PackageVersionMetadata.Organization) {
378433
self.init(
379434
name: organization.name,
380435
email: organization.email,

0 commit comments

Comments
 (0)