@@ -17,6 +17,7 @@ import PackageModel
1717import PackageRegistry
1818import SourceControl
1919
20+ import struct Foundation. Date
2021import struct Foundation. URL
2122import struct TSCBasic. AbsolutePath
2223import 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