Skip to content

Commit 923510e

Browse files
Adopt async/await in PackageCollectionsTests` (#7156)
### Motivation: Move more of the testing to be `async`/`await` native to make it easier to migrate to `async`/`await` in the core libraries ### Modifications: Added an `async` variant of `fixture`, replaced a lot of uses of `temp_await` with `await`. ### Result: Less than 100 uses of `temp_await` in the repo. --------- Co-authored-by: Max Desiatov <[email protected]>
1 parent 8387798 commit 923510e

16 files changed

+1005
-549
lines changed

Sources/Basics/Concurrency/ConcurrencyHelpers.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ extension DispatchQueue {
4848
}
4949

5050
/// Bridges between potentially blocking methods that take a result completion closure and async/await
51-
public func safe_async<T, ErrorType: Error>(_ body: @Sendable @escaping (@Sendable @escaping (Result<T, ErrorType>) -> Void) -> Void) async throws -> T {
51+
public func safe_async<T, ErrorType: Error>(
52+
_ body: @Sendable @escaping (@Sendable @escaping (Result<T, ErrorType>) -> Void) -> Void
53+
) async throws -> T {
5254
try await withCheckedThrowingContinuation { continuation in
53-
// It is possible that body make block indefinitely on a lock, sempahore,
54-
// or similar then synchrously call the completion handler. For full safety
55+
// It is possible that body make block indefinitely on a lock, semaphore,
56+
// or similar then synchronously call the completion handler. For full safety
5557
// it is essential to move the execution off the swift concurrency pool
5658
DispatchQueue.sharedConcurrent.async {
5759
body {

Sources/PackageCollections/API.swift

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import struct Foundation.URL
1414
import PackageModel
1515
import SourceControl
16+
import Basics
1617

1718
// MARK: - Package collection
1819

@@ -27,6 +28,7 @@ public protocol PackageCollectionsProtocol {
2728
/// - Parameters:
2829
/// - identifiers: Optional. If specified, only `PackageCollection`s with matching identifiers will be returned.
2930
/// - callback: The closure to invoke when result becomes available
31+
@available(*, noasync, message: "Use the async alternative")
3032
func listCollections(
3133
identifiers: Set<PackageCollectionsModel.CollectionIdentifier>?,
3234
callback: @escaping (Result<[PackageCollectionsModel.Collection], Error>) -> Void
@@ -36,13 +38,15 @@ public protocol PackageCollectionsProtocol {
3638
///
3739
/// - Parameters:
3840
/// - callback: The closure to invoke after triggering a refresh for the configured package collections.
41+
@available(*, noasync, message: "Use the async alternative")
3942
func refreshCollections(callback: @escaping (Result<[PackageCollectionsModel.CollectionSource], Error>) -> Void)
4043

4144
/// Refreshes a package collection.
4245
///
4346
/// - Parameters:
4447
/// - source: The package collection to be refreshed
4548
/// - callback: The closure to invoke with the refreshed `PackageCollection`
49+
@available(*, noasync, message: "Use the async alternative")
4650
func refreshCollection(
4751
_ source: PackageCollectionsModel.CollectionSource,
4852
callback: @escaping (Result<PackageCollectionsModel.Collection, Error>) -> Void
@@ -56,6 +60,7 @@ public protocol PackageCollectionsProtocol {
5660
/// By default the new collection is appended to the end (i.e., the least relevant order).
5761
/// - trustConfirmationProvider: The closure to invoke when the collection is not signed and user confirmation is required to proceed
5862
/// - callback: The closure to invoke with the newly added `PackageCollection`
63+
@available(*, noasync, message: "Use the async alternative")
5964
func addCollection(
6065
_ source: PackageCollectionsModel.CollectionSource,
6166
order: Int?,
@@ -68,6 +73,7 @@ public protocol PackageCollectionsProtocol {
6873
/// - Parameters:
6974
/// - source: The package collection's source
7075
/// - callback: The closure to invoke with the result becomes available
76+
@available(*, noasync, message: "Use the async alternative")
7177
func removeCollection(
7278
_ source: PackageCollectionsModel.CollectionSource,
7379
callback: @escaping (Result<Void, Error>) -> Void
@@ -79,6 +85,7 @@ public protocol PackageCollectionsProtocol {
7985
/// - source: The source of the `PackageCollection` to be reordered
8086
/// - order: The new order that the `PackageCollection` should be positioned after the move
8187
/// - callback: The closure to invoke with the result becomes available
88+
@available(*, noasync, message: "Use the async alternative")
8289
func moveCollection(
8390
_ source: PackageCollectionsModel.CollectionSource,
8491
to order: Int,
@@ -90,6 +97,7 @@ public protocol PackageCollectionsProtocol {
9097
/// - Parameters:
9198
/// - source: The `PackageCollection` source to be updated
9299
/// - callback: The closure to invoke when result becomes available
100+
@available(*, noasync, message: "Use the async alternative")
93101
func updateCollection(
94102
_ source: PackageCollectionsModel.CollectionSource,
95103
callback: @escaping (Result<PackageCollectionsModel.Collection, Error>) -> Void
@@ -101,6 +109,7 @@ public protocol PackageCollectionsProtocol {
101109
/// - Parameters:
102110
/// - source: The package collection's source
103111
/// - callback: The closure to invoke with the `PackageCollection`
112+
@available(*, noasync, message: "Use the async alternative")
104113
func getCollection(
105114
_ source: PackageCollectionsModel.CollectionSource,
106115
callback: @escaping (Result<PackageCollectionsModel.Collection, Error>) -> Void
@@ -115,6 +124,7 @@ public protocol PackageCollectionsProtocol {
115124
/// - identity: The package identity
116125
/// - location: The package location (optional for deduplication)
117126
/// - callback: The closure to invoke when result becomes available
127+
@available(*, noasync, message: "Use the async alternative")
118128
func getPackageMetadata(
119129
identity: PackageIdentity,
120130
location: String?,
@@ -132,6 +142,7 @@ public protocol PackageCollectionsProtocol {
132142
/// - collections: Optional. If specified, only look for package in these collections. Data from the most recently
133143
/// processed collection will be used.
134144
/// - callback: The closure to invoke when result becomes available
145+
@available(*, noasync, message: "Use the async alternative")
135146
func getPackageMetadata(
136147
identity: PackageIdentity,
137148
location: String?,
@@ -144,6 +155,7 @@ public protocol PackageCollectionsProtocol {
144155
/// - Parameters:
145156
/// - collections: Optional. If specified, only packages in these collections are included.
146157
/// - callback: The closure to invoke when result becomes available
158+
@available(*, noasync, message: "Use the async alternative")
147159
func listPackages(
148160
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
149161
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult, Error>) -> Void
@@ -160,6 +172,7 @@ public protocol PackageCollectionsProtocol {
160172
/// - Parameters:
161173
/// - collections: Optional. If specified, only list targets within these collections.
162174
/// - callback: The closure to invoke when result becomes available
175+
@available(*, noasync, message: "Use the async alternative")
163176
func listTargets(
164177
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
165178
callback: @escaping (Result<PackageCollectionsModel.TargetListResult, Error>) -> Void
@@ -176,6 +189,7 @@ public protocol PackageCollectionsProtocol {
176189
/// - query: The search query
177190
/// - collections: Optional. If specified, only search within these collections.
178191
/// - callback: The closure to invoke when result becomes available
192+
@available(*, noasync, message: "Use the async alternative")
179193
func findPackages(
180194
_ query: String,
181195
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
@@ -193,6 +207,7 @@ public protocol PackageCollectionsProtocol {
193207
/// For more flexibility, use the `findPackages` API instead.
194208
/// - collections: Optional. If specified, only search within these collections.
195209
/// - callback: The closure to invoke when result becomes available
210+
@available(*, noasync, message: "Use the async alternative")
196211
func findTargets(
197212
_ query: String,
198213
searchType: PackageCollectionsModel.TargetSearchType?,
@@ -201,6 +216,159 @@ public protocol PackageCollectionsProtocol {
201216
)
202217
}
203218

219+
public extension PackageCollectionsProtocol {
220+
func listCollections(
221+
identifiers: Set<PackageCollectionsModel.CollectionIdentifier>? = nil
222+
) async throws -> [PackageCollectionsModel.Collection] {
223+
try await safe_async {
224+
self.listCollections(identifiers: identifiers, callback: $0)
225+
}
226+
}
227+
228+
func refreshCollections() async throws -> [PackageCollectionsModel.CollectionSource] {
229+
try await safe_async {
230+
self.refreshCollections(callback: $0)
231+
}
232+
}
233+
234+
func refreshCollection(
235+
_ source: PackageCollectionsModel.CollectionSource
236+
) async throws -> PackageCollectionsModel.Collection {
237+
try await safe_async {
238+
self.refreshCollection(
239+
source,
240+
callback: $0
241+
)
242+
}
243+
}
244+
245+
func addCollection(
246+
_ source: PackageCollectionsModel.CollectionSource,
247+
order: Int? = nil,
248+
trustConfirmationProvider: ((PackageCollectionsModel.Collection, @escaping (Bool) -> Void) -> Void)? = nil
249+
) async throws -> PackageCollectionsModel.Collection {
250+
try await safe_async {
251+
self.addCollection(
252+
source,
253+
order: order,
254+
trustConfirmationProvider:trustConfirmationProvider,
255+
callback: $0
256+
)
257+
}
258+
}
259+
260+
func removeCollection(
261+
_ source: PackageCollectionsModel.CollectionSource
262+
) async throws {
263+
try await safe_async {
264+
self.removeCollection(
265+
source,
266+
callback: $0
267+
)
268+
}
269+
}
270+
271+
func moveCollection(
272+
_ source: PackageCollectionsModel.CollectionSource,
273+
to order: Int
274+
) async throws {
275+
try await safe_async {
276+
self.moveCollection(
277+
source,
278+
to: order,
279+
callback: $0
280+
)
281+
}
282+
}
283+
284+
func updateCollection(
285+
_ source: PackageCollectionsModel.CollectionSource
286+
) async throws -> PackageCollectionsModel.Collection {
287+
try await safe_async {
288+
self.updateCollection(
289+
source,
290+
callback: $0
291+
)
292+
}
293+
}
294+
295+
func getCollection(
296+
_ source: PackageCollectionsModel.CollectionSource
297+
) async throws -> PackageCollectionsModel.Collection {
298+
try await safe_async {
299+
self.getCollection(
300+
source,
301+
callback: $0
302+
)
303+
}
304+
}
305+
306+
func getPackageMetadata(
307+
identity: PackageIdentity,
308+
location: String? = nil,
309+
collections: Set<PackageCollectionsModel.CollectionIdentifier>? = nil
310+
) async throws -> PackageCollectionsModel.PackageMetadata {
311+
try await safe_async {
312+
self.getPackageMetadata(
313+
identity: identity,
314+
location: location,
315+
collections: collections,
316+
callback: $0
317+
)
318+
}
319+
}
320+
321+
func listPackages(
322+
collections: Set<PackageCollectionsModel.CollectionIdentifier>? = nil
323+
) async throws -> PackageCollectionsModel.PackageSearchResult {
324+
try await safe_async {
325+
self.listPackages(
326+
collections: collections,
327+
callback: $0
328+
)
329+
}
330+
}
331+
332+
func listTargets(
333+
collections: Set<PackageCollectionsModel.CollectionIdentifier>? = nil
334+
) async throws -> PackageCollectionsModel.TargetListResult {
335+
try await safe_async {
336+
self.listTargets(
337+
collections: collections,
338+
callback: $0
339+
)
340+
}
341+
}
342+
343+
func findPackages(
344+
_ query: String,
345+
collections: Set<PackageCollectionsModel.CollectionIdentifier>? = nil
346+
) async throws -> PackageCollectionsModel.PackageSearchResult {
347+
try await safe_async {
348+
self.findPackages(
349+
query,
350+
collections: collections,
351+
callback: $0
352+
)
353+
}
354+
}
355+
356+
func findTargets(
357+
_ query: String,
358+
searchType: PackageCollectionsModel.TargetSearchType? = nil,
359+
collections: Set<PackageCollectionsModel.CollectionIdentifier>? = nil
360+
) async throws -> PackageCollectionsModel.TargetSearchResult {
361+
try await safe_async {
362+
self.findTargets(
363+
query,
364+
searchType: searchType,
365+
collections: collections,
366+
callback: $0
367+
)
368+
}
369+
}
370+
}
371+
204372
public enum PackageCollectionError: Equatable, Error {
205373
/// Package collection is not signed and there is no record of user's trust selection
206374
case trustConfirmationRequired
@@ -233,6 +401,7 @@ public protocol PackageIndexProtocol {
233401
/// - identity: The package identity
234402
/// - location: The package location (optional for deduplication)
235403
/// - callback: The closure to invoke when result becomes available
404+
@available(*, noasync, message: "Use the async alternative")
236405
func getPackageMetadata(
237406
identity: PackageIdentity,
238407
location: String?,
@@ -244,6 +413,7 @@ public protocol PackageIndexProtocol {
244413
/// - Parameters:
245414
/// - query: The search query
246415
/// - callback: The closure to invoke when result becomes available
416+
@available(*, noasync, message: "Use the async alternative")
247417
func findPackages(
248418
_ query: String,
249419
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult, Error>) -> Void
@@ -255,13 +425,61 @@ public protocol PackageIndexProtocol {
255425
/// - offset: Offset of the first item in the result
256426
/// - limit: Number of items to return in the result. Implementations might impose a threshold for this.
257427
/// - callback: The closure to invoke when result becomes available
428+
@available(*, noasync, message: "Use the async alternative")
258429
func listPackages(
259430
offset: Int,
260431
limit: Int,
261432
callback: @escaping (Result<PackageCollectionsModel.PaginatedPackageList, Error>) -> Void
262433
)
263434
}
264435

436+
public extension PackageIndexProtocol {
437+
func getPackageMetadata(
438+
identity: PackageIdentity,
439+
location: String?
440+
) async throws -> PackageCollectionsModel.PackageMetadata {
441+
try await safe_async {
442+
self.getPackageMetadata(
443+
identity: identity,
444+
location: location,
445+
callback: $0
446+
)
447+
}
448+
}
449+
450+
/// Finds and returns packages that match the query.
451+
///
452+
/// - Parameters:
453+
/// - query: The search query
454+
/// - callback: The closure to invoke when result becomes available
455+
func findPackages(
456+
_ query: String
457+
) async throws -> PackageCollectionsModel.PackageSearchResult {
458+
try await safe_async {
459+
self.findPackages(query, callback: $0)
460+
}
461+
}
462+
463+
/// A paginated list of packages in the index.
464+
///
465+
/// - Parameters:
466+
/// - offset: Offset of the first item in the result
467+
/// - limit: Number of items to return in the result. Implementations might impose a threshold for this.
468+
/// - callback: The closure to invoke when result becomes available
469+
func listPackages(
470+
offset: Int,
471+
limit: Int
472+
) async throws -> PackageCollectionsModel.PaginatedPackageList {
473+
try await safe_async {
474+
self.listPackages(
475+
offset: offset,
476+
limit: limit,
477+
callback: $0
478+
)
479+
}
480+
}
481+
}
482+
265483
public enum PackageIndexError: Equatable, Error {
266484
/// Package index support is disabled
267485
case featureDisabled

Sources/PackageCollections/PackageCollections.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,11 @@ public struct PackageCollections: PackageCollectionsProtocol, Closable {
489489

490490
// Fetch the collection from the network and store it in local storage
491491
// This helps avoid network access in normal operations
492-
private func refreshCollectionFromSource(source: PackageCollectionsModel.CollectionSource,
493-
trustConfirmationProvider: ((PackageCollectionsModel.Collection, @escaping (Bool) -> Void) -> Void)?,
494-
callback: @escaping (Result<Model.Collection, Error>) -> Void) {
492+
private func refreshCollectionFromSource(
493+
source: PackageCollectionsModel.CollectionSource,
494+
trustConfirmationProvider: ((PackageCollectionsModel.Collection, @escaping (Bool) -> Void) -> Void)?,
495+
callback: @escaping (Result<Model.Collection, Error>) -> Void
496+
) {
495497
guard let provider = self.collectionProviders[source.type] else {
496498
return callback(.failure(UnknownProvider(source.type)))
497499
}

0 commit comments

Comments
 (0)