Skip to content

Commit 0236774

Browse files
committed
[Collections] Add search provider abstraction
Add `PackageSearchProvider` abstraction to make it easier to introduce other ways of searching for packages in the future.
1 parent 67f5bbd commit 0236774

File tree

5 files changed

+162
-25
lines changed

5 files changed

+162
-25
lines changed

Sources/PackageCollections/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ add_library(PackageCollections
1717
Providers/JSONPackageCollectionProvider.swift
1818
Providers/PackageCollectionProvider.swift
1919
Providers/PackageMetadataProvider.swift
20+
Providers/PackageSearchProvider.swift
21+
Providers/StorageBackedPackageSearchProvider.swift
2022
Storage/FilePackageCollectionsSourcesStorage.swift
2123
Storage/PackageCollectionsSourcesStorage.swift
2224
Storage/PackageCollectionsStorage.swift

Sources/PackageCollections/Model/Package.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -142,34 +142,13 @@ extension PackageCollectionsModel.Package {
142142

143143
/// Package version description
144144
public let summary: String?
145-
146-
// TODO: remove (replaced by manifests)
147-
public var packageName: String { self.defaultManifest!.packageName }
148-
149-
// TODO: remove (replaced by manifests)
150-
public var targets: [Target] { self.defaultManifest!.targets }
151-
152-
// TODO: remove (replaced by manifests)
153-
public var products: [Product] { self.defaultManifest!.products }
154-
155-
// TODO: remove (replaced by manifests)
156-
public var toolsVersion: ToolsVersion { self.defaultManifest!.toolsVersion }
157-
158-
// TODO: remove (replaced by manifests)
159-
public var minimumPlatformVersions: [SupportedPlatform]? { nil }
160-
145+
161146
/// Manifests by tools version
162147
public let manifests: [ToolsVersion: Manifest]
163148

164149
/// Tools version of the default manifest
165150
public let defaultToolsVersion: ToolsVersion
166151

167-
// TODO: remove (replaced by verifiedCompatibility)
168-
public var verifiedPlatforms: [PackageModel.Platform]? { nil }
169-
170-
// TODO: remove (replaced by verifiedCompatibility)
171-
public var verifiedSwiftVersions: [SwiftLanguageVersion]? { nil }
172-
173152
/// An array of compatible platforms and Swift versions that has been tested and verified for.
174153
public let verifiedCompatibility: [PackageCollectionsModel.Compatibility]?
175154

@@ -178,6 +157,27 @@ extension PackageCollectionsModel.Package {
178157

179158
/// When the package version was created
180159
public let createdAt: Date?
160+
161+
@available(*, deprecated, message: "use manifests instead")
162+
public var packageName: String { self.defaultManifest!.packageName }
163+
164+
@available(*, deprecated, message: "use manifests instead")
165+
public var targets: [Target] { self.defaultManifest!.targets }
166+
167+
@available(*, deprecated, message: "use manifests instead")
168+
public var products: [Product] { self.defaultManifest!.products }
169+
170+
@available(*, deprecated, message: "use manifests instead")
171+
public var toolsVersion: ToolsVersion { self.defaultManifest!.toolsVersion }
172+
173+
@available(*, deprecated, message: "use manifests instead")
174+
public var minimumPlatformVersions: [SupportedPlatform]? { nil }
175+
176+
@available(*, deprecated, message: "use verifiedCompatibility instead")
177+
public var verifiedPlatforms: [PackageModel.Platform]? { nil }
178+
179+
@available(*, deprecated, message: "use verifiedCompatibility instead")
180+
public var verifiedSwiftVersions: [SwiftLanguageVersion]? { nil }
181181

182182
public struct Manifest: Equatable, Codable {
183183
/// The Swift tools version specified in `Package.swift`.

Sources/PackageCollections/PackageCollections.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public struct PackageCollections: PackageCollectionsProtocol {
2626
private let storageContainer: (storage: Storage, owned: Bool)
2727
private let collectionProviders: [Model.CollectionSourceType: PackageCollectionProvider]
2828
let metadataProvider: PackageMetadataProvider
29+
let searchProvider: PackageSearchProvider
2930

3031
private var storage: Storage {
3132
self.storageContainer.storage
@@ -46,25 +47,30 @@ public struct PackageCollections: PackageCollectionsProtocol {
4647
configuration: .init(authTokens: configuration.authTokens),
4748
observabilityScope: observabilityScope
4849
)
50+
51+
let searchProvider = StorageBackedPackageSearchProvider(storage: storage.collections)
4952

5053
self.configuration = configuration
5154
self.observabilityScope = observabilityScope
5255
self.storageContainer = (storage, true)
5356
self.collectionProviders = collectionProviders
5457
self.metadataProvider = metadataProvider
58+
self.searchProvider = searchProvider
5559
}
5660

5761
// internal initializer for testing
5862
init(configuration: Configuration = .init(),
5963
observabilityScope: ObservabilityScope,
6064
storage: Storage,
6165
collectionProviders: [Model.CollectionSourceType: PackageCollectionProvider],
62-
metadataProvider: PackageMetadataProvider) {
66+
metadataProvider: PackageMetadataProvider,
67+
searchProvider: PackageSearchProvider? = nil) {
6368
self.configuration = configuration
6469
self.observabilityScope = observabilityScope
6570
self.storageContainer = (storage, false)
6671
self.collectionProviders = collectionProviders
6772
self.metadataProvider = metadataProvider
73+
self.searchProvider = searchProvider ?? StorageBackedPackageSearchProvider(storage: storage.collections)
6874
}
6975

7076
public func shutdown() throws {
@@ -308,7 +314,7 @@ public struct PackageCollections: PackageCollectionsProtocol {
308314
if identifiers.isEmpty {
309315
return callback(.success(Model.PackageSearchResult(items: [])))
310316
}
311-
self.storage.collections.searchPackages(identifiers: identifiers, query: query, callback: callback)
317+
self.searchProvider.searchPackages(query, collections: Set(identifiers), callback: callback)
312318
}
313319
}
314320
}
@@ -466,7 +472,7 @@ public struct PackageCollections: PackageCollectionsProtocol {
466472
if identifiers.isEmpty {
467473
return callback(.success(.init(items: [])))
468474
}
469-
self.storage.collections.searchTargets(identifiers: identifiers, query: query, type: searchType, callback: callback)
475+
self.searchProvider.searchTargets(query, searchType: searchType, collections: Set(identifiers), callback: callback)
470476
}
471477
}
472478
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2021 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import PackageModel
12+
13+
import TSCBasic
14+
15+
/// Package search API provider
16+
protocol PackageSearchProvider: Closable {
17+
/// The name of the provider
18+
var name: String { get }
19+
20+
/// Searches for packages using the given query. Packages in the result must belong to an imported package collection.
21+
///
22+
/// - Parameters:
23+
/// - query: The search query.
24+
/// - collections: Optional. The identifiers of the `PackageCollection`s to filter results on.
25+
/// - callback: The closure to invoke when result becomes available.
26+
func searchPackages(
27+
_ query: String,
28+
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
29+
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult, Error>) -> Void
30+
)
31+
32+
/// Searches for packages using the given query. Packages in the result do not have to belong to an imported package collection.
33+
/// In other words, collection-related information in the result can be missing or empty.
34+
///
35+
/// - Parameters:
36+
/// - query: The search query.
37+
/// - callback: The closure to invoke when result becomes available.
38+
func searchPackages(
39+
_ query: String,
40+
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult, Error>) -> Void
41+
)
42+
43+
/// Finds targets by name and returns the corresponding packages, which must belong to an imported package collection.
44+
///
45+
/// This API's result items will be aggregated by target then package, with the
46+
/// package's versions list filtered to only include those that contain the target.
47+
///
48+
/// - Parameters:
49+
/// - query: The search query
50+
/// - searchType: Target names must either match exactly or contain the prefix.
51+
/// For more flexibility, use the `searchPackages` API instead.
52+
/// - collections: Optional. The identifiers of the `PackageCollection`s to filter results on.
53+
/// - callback: The closure to invoke when result becomes available
54+
func searchTargets(
55+
_ query: String,
56+
searchType: PackageCollectionsModel.TargetSearchType,
57+
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
58+
callback: @escaping (Result<PackageCollectionsModel.TargetSearchResult, Error>) -> Void
59+
)
60+
61+
/// Finds targets by name and returns the corresponding packages. Packages do not have to belong to an imported package collection.
62+
/// In other words, collection-related information in the result can be missing or empty.
63+
///
64+
/// - Parameters:
65+
/// - query: The search query
66+
/// - searchType: Target names must either match exactly or contain the prefix.
67+
/// For more flexibility, use the `searchPackages` API instead.
68+
/// - callback: The closure to invoke when result becomes available
69+
func searchTargets(
70+
_ query: String,
71+
searchType: PackageCollectionsModel.TargetSearchType,
72+
callback: @escaping (Result<PackageCollectionsModel.TargetSearchResult, Error>) -> Void
73+
)
74+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2021 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
/// A `PackageSearchProvider` backed by `PackageCollectionsStorage`.
12+
///
13+
/// Implicitly, packages in search results must belong to an imported collection since that is
14+
/// the only way for a package to be added to storage.
15+
struct StorageBackedPackageSearchProvider: PackageSearchProvider {
16+
private let storage: PackageCollectionsStorage
17+
18+
let name: String = "Storage-Backed"
19+
20+
init(storage: PackageCollectionsStorage) {
21+
self.storage = storage
22+
}
23+
24+
/// Searches for packages in specific imported package collections.
25+
func searchPackages(_ query: String,
26+
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
27+
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult, Error>) -> Void) {
28+
self.storage.searchPackages(identifiers: collections.map(Array.init), query: query, callback: callback)
29+
}
30+
31+
/// Searches for packages in all imported package collections.
32+
func searchPackages(_ query: String,
33+
callback: @escaping (Result<PackageCollectionsModel.PackageSearchResult, Error>) -> Void) {
34+
self.searchPackages(query, collections: nil, callback: callback)
35+
}
36+
37+
/// Searches for targets in specific imported package collections.
38+
func searchTargets(_ query: String,
39+
searchType: PackageCollectionsModel.TargetSearchType,
40+
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
41+
callback: @escaping (Result<PackageCollectionsModel.TargetSearchResult, Error>) -> Void) {
42+
self.storage.searchTargets(identifiers: collections.map(Array.init), query: query, type: searchType, callback: callback)
43+
}
44+
45+
/// Searches for packages in all imported package collections.
46+
func searchTargets(_ query: String,
47+
searchType: PackageCollectionsModel.TargetSearchType,
48+
callback: @escaping (Result<PackageCollectionsModel.TargetSearchResult, Error>) -> Void) {
49+
self.searchTargets(query, searchType: searchType, collections: nil, callback: callback)
50+
}
51+
52+
func close() throws {
53+
// No need to do anything
54+
}
55+
}

0 commit comments

Comments
 (0)