Skip to content

Commit dedda2e

Browse files
committed
Add support for looking up spec resources in a toolchain install
1 parent 3027a82 commit dedda2e

File tree

18 files changed

+65
-37
lines changed

18 files changed

+65
-37
lines changed

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func swiftSettings(languageMode: SwiftLanguageMode) -> [SwiftSetting] {
4545

4646
.swiftLanguageMode(.v5),
4747

48-
.define("USE_STATIC_PLUGIN_INITIALIZATION")
48+
.define("USE_STATIC_PLUGIN_INITIALIZATION"),
4949
]
5050
case .v6:
5151
return [
@@ -55,7 +55,7 @@ func swiftSettings(languageMode: SwiftLanguageMode) -> [SwiftSetting] {
5555

5656
.swiftLanguageMode(.v6),
5757

58-
.define("USE_STATIC_PLUGIN_INITIALIZATION")
58+
.define("USE_STATIC_PLUGIN_INITIALIZATION"),
5959
]
6060
default:
6161
fatalError("unexpected language mode")

Sources/SWBAndroidPlatform/Plugin.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import Foundation
2424
}
2525

2626
struct AndroidPlatformSpecsExtension: SpecificationsExtension {
27-
func specificationFiles() -> Bundle? {
28-
.module
27+
func specificationFiles(resourceSearchPaths: [Path]) -> Bundle? {
28+
findResourceBundle(nameWhenInstalledInToolchain: "SwiftBuild_SWBAndroidPlatform", resourceSearchPaths: resourceSearchPaths, defaultBundle: Bundle.module)
2929
}
3030

3131
func specificationDomains() -> [String : [String]] {

Sources/SWBApplePlatform/Plugin.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ struct ApplePlatformSpecsExtension: SpecificationsExtension {
9898
]
9999
}
100100

101-
func specificationFiles() -> Bundle? {
102-
.module
101+
func specificationFiles(resourceSearchPaths: [Path]) -> Bundle? {
102+
findResourceBundle(nameWhenInstalledInToolchain: "SwiftBuild_SWBApplePlatform", resourceSearchPaths: resourceSearchPaths, defaultBundle: Bundle.module)
103103
}
104104

105105
func specificationDomains() -> [String : [String]] {

Sources/SWBBuildService/BuildService.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ package class BuildService: Service, @unchecked Sendable {
157157
/// Get a shared core instance.
158158
///
159159
/// We use an explicit cache so that we can minimize the number of cores we load while still keeping a flexible public interface that doesn't require all clients to provide all possible required parameters for core initialization (which is useful for testing and debug purposes).
160-
func sharedCore(developerPath: Path?, inferiorProducts: Path? = nil, environment: [String: String] = [:]) async -> (Core?, [Diagnostic]) {
160+
func sharedCore(developerPath: Path?, resourceSearchPaths: [Path] = [], inferiorProducts: Path? = nil, environment: [String: String] = [:]) async -> (Core?, [Diagnostic]) {
161161
let key = CoreCacheKey(developerPath: developerPath, inferiorProducts: inferiorProducts, environment: environment)
162162
return await sharedCoreCacheLock.withLock {
163163
if let existing = sharedCoreCache[key] {
@@ -191,7 +191,7 @@ package class BuildService: Service, @unchecked Sendable {
191191
}
192192
}
193193
let delegate = Delegate()
194-
let (core, diagnostics) = await (Core.getInitializedCore(delegate, pluginManager: pluginManager, developerPath: developerPath, inferiorProductsPath: inferiorProducts, environment: environment, buildServiceModTime: buildServiceModTime, connectionMode: connectionMode), delegate.diagnostics)
194+
let (core, diagnostics) = await (Core.getInitializedCore(delegate, pluginManager: pluginManager, developerPath: developerPath, resourceSearchPaths: resourceSearchPaths, inferiorProductsPath: inferiorProducts, environment: environment, buildServiceModTime: buildServiceModTime, connectionMode: connectionMode), delegate.diagnostics)
195195
delegate.freeze()
196196
sharedCoreCache[key] = (core, diagnostics)
197197
return (core, diagnostics)

Sources/SWBBuildService/Messages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ private struct CreateSessionHandler: MessageHandler {
124124
let service = request.buildService
125125
let (core, diagnostics) = await service.sharedCore(
126126
developerPath: message.effectiveDeveloperPath,
127+
resourceSearchPaths: message.resourceSearchPaths ?? [],
127128
inferiorProducts: message.inferiorProductsPath,
128129
environment: message.environment ?? [:]
129130
)

Sources/SWBCore/Core.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public final class Core: Sendable {
4040
/// Get a configured instance of the core.
4141
///
4242
/// - returns: An initialized Core instance on which all discovery and loading will have been completed. If there are errors during that process, they will be logged to `stderr` and no instance will be returned. Otherwise, the initialized object is returned.
43-
public static func getInitializedCore(_ delegate: any CoreDelegate, pluginManager: PluginManager, developerPath: Path? = nil, inferiorProductsPath: Path? = nil, extraPluginRegistration: @PluginExtensionSystemActor (_ pluginPaths: [Path]) -> Void = { _ in }, additionalContentPaths: [Path] = [], environment: [String:String] = [:], buildServiceModTime: Date, connectionMode: ServiceHostConnectionMode) async -> Core? {
43+
public static func getInitializedCore(_ delegate: any CoreDelegate, pluginManager: PluginManager, developerPath: Path? = nil, resourceSearchPaths: [Path] = [], inferiorProductsPath: Path? = nil, extraPluginRegistration: @PluginExtensionSystemActor (_ pluginPaths: [Path]) -> Void = { _ in }, additionalContentPaths: [Path] = [], environment: [String:String] = [:], buildServiceModTime: Date, connectionMode: ServiceHostConnectionMode) async -> Core? {
4444
// Enable macro expression interning during loading.
4545
return await MacroNamespace.withExpressionInterningEnabled {
4646
let hostOperatingSystem: OperatingSystem
@@ -73,7 +73,7 @@ public final class Core: Sendable {
7373

7474
let core: Core
7575
do {
76-
core = try await Core(delegate: delegate, hostOperatingSystem: hostOperatingSystem, pluginManager: pluginManager, developerPath: resolvedDeveloperPath, inferiorProductsPath: inferiorProductsPath, additionalContentPaths: additionalContentPaths, environment: environment, buildServiceModTime: buildServiceModTime, connectionMode: connectionMode)
76+
core = try await Core(delegate: delegate, hostOperatingSystem: hostOperatingSystem, pluginManager: pluginManager, developerPath: resolvedDeveloperPath, resourceSearchPaths: resourceSearchPaths, inferiorProductsPath: inferiorProductsPath, additionalContentPaths: additionalContentPaths, environment: environment, buildServiceModTime: buildServiceModTime, connectionMode: connectionMode)
7777
} catch {
7878
delegate.error("\(error)")
7979
return nil
@@ -147,6 +147,9 @@ public final class Core: Sendable {
147147
/// The path to the "Developer" directory.
148148
public let developerPath: Path
149149

150+
/// Additional search paths to be used when looking up resource bundles.
151+
public let resourceSearchPaths: [Path]
152+
150153
/// The path to the inferior Xcode build directory, if used.
151154
public let inferiorProductsPath: Path?
152155

@@ -177,11 +180,12 @@ public final class Core: Sendable {
177180

178181
public let connectionMode: ServiceHostConnectionMode
179182

180-
@_spi(Testing) public init(delegate: any CoreDelegate, hostOperatingSystem: OperatingSystem, pluginManager: PluginManager, developerPath: String, inferiorProductsPath: Path?, additionalContentPaths: [Path], environment: [String:String], buildServiceModTime: Date, connectionMode: ServiceHostConnectionMode) async throws {
183+
@_spi(Testing) public init(delegate: any CoreDelegate, hostOperatingSystem: OperatingSystem, pluginManager: PluginManager, developerPath: String, resourceSearchPaths: [Path], inferiorProductsPath: Path?, additionalContentPaths: [Path], environment: [String:String], buildServiceModTime: Date, connectionMode: ServiceHostConnectionMode) async throws {
181184
self.delegate = delegate
182185
self.hostOperatingSystem = hostOperatingSystem
183186
self.pluginManager = pluginManager
184187
self.developerPath = Path(developerPath)
188+
self.resourceSearchPaths = resourceSearchPaths
185189
self.inferiorProductsPath = inferiorProductsPath
186190
self.additionalContentPaths = additionalContentPaths
187191
self.buildServiceModTime = buildServiceModTime
@@ -402,7 +406,7 @@ public final class Core: Sendable {
402406

403407
// Find all plugin provided specs.
404408
for ext in await self.pluginManager.extensions(of: SpecificationsExtensionPoint.self) {
405-
if let bundle = ext.specificationFiles() {
409+
if let bundle = ext.specificationFiles(resourceSearchPaths: resourceSearchPaths) {
406410
for url in bundle.urls(forResourcesWithExtension: "xcspec", subdirectory: nil) ?? [] {
407411
do {
408412
try searchPaths.append(((url as URL).filePath, ""))

Sources/SWBCore/Extensions/SpecificationsExtension.swift

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,34 @@ public struct SpecificationsExtensionPoint: ExtensionPoint {
5050

5151
public protocol SpecificationsExtension: Sendable {
5252
/// Returns the bundle containing the `.xcspec` files.
53-
func specificationFiles() -> Bundle?
53+
func specificationFiles(resourceSearchPaths: [Path]) -> Bundle?
5454
func specificationDomains() -> [String: [String]]
5555
func specificationTypes() -> [any SpecType.Type]
5656
func specificationClasses() -> [any SpecIdentifierType.Type]
5757
func specificationClassesClassic() -> [any SpecClassType.Type]
5858
func specificationImplementations() -> [any SpecImplementationType.Type]
5959

6060
/// Returns the search paths for two use cases: finding the sole remaining `.xcbuildrules` file, and finding executable scripts next to `.xcspec` files.
61-
func specificationSearchPaths() -> [URL]
61+
func specificationSearchPaths(resourceSearchPaths: [Path]) -> [URL]
6262
}
6363

6464
extension SpecificationsExtension {
65-
public func specificationFiles() -> Bundle? { nil }
65+
public func specificationFiles(resourceSearchPaths: [Path]) -> Bundle? { nil }
6666
public func specificationDomains() -> [String: [String]] { [:] }
6767
public func specificationTypes() -> [any SpecType.Type] { [] }
6868
public func specificationClasses() -> [any SpecIdentifierType.Type] { [] }
6969
public func specificationClassesClassic() -> [any SpecClassType.Type] { [] }
7070
public func specificationImplementations() -> [any SpecImplementationType.Type] { [] }
71-
public func specificationSearchPaths() -> [URL] { [] }
71+
public func specificationSearchPaths(resourceSearchPaths: [Path]) -> [URL] { [] }
72+
73+
public func findResourceBundle(nameWhenInstalledInToolchain: String, resourceSearchPaths: [Path], defaultBundle: @autoclosure () -> Bundle?) -> Bundle? {
74+
for searchPath in resourceSearchPaths {
75+
for bundleBasename in ["\(nameWhenInstalledInToolchain).bundle", "\(nameWhenInstalledInToolchain).resources"] {
76+
if let bundle = Bundle(path: searchPath.join(bundleBasename).str) {
77+
return bundle
78+
}
79+
}
80+
}
81+
return defaultBundle()
82+
}
7283
}

Sources/SWBCore/Settings/Settings.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ fileprivate struct PreOverridesSettings {
348348

349349
@preconcurrency @PluginExtensionSystemActor func searchPaths() -> [Path] {
350350
core.pluginManager.extensions(of: SpecificationsExtensionPoint.self).flatMap { ext in
351-
ext.specificationSearchPaths().compactMap { try? $0.filePath }
351+
ext.specificationSearchPaths(resourceSearchPaths: core.resourceSearchPaths).compactMap { try? $0.filePath }
352352
}.sorted()
353353
}
354354

@@ -999,7 +999,7 @@ extension WorkspaceContext {
999999

10001000
@preconcurrency @PluginExtensionSystemActor func searchPaths() -> [Path] {
10011001
core.pluginManager.extensions(of: SpecificationsExtensionPoint.self).flatMap { ext in
1002-
ext.specificationSearchPaths().compactMap { try? $0.filePath }
1002+
ext.specificationSearchPaths(resourceSearchPaths: core.resourceSearchPaths).compactMap { try? $0.filePath }
10031003
}.sorted()
10041004
}
10051005

Sources/SWBCore/SpecImplementations/RegisterSpecs.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public struct BuiltinSpecsExtension: SpecificationsExtension {
143143
]
144144
}
145145

146-
public func specificationFiles() -> Bundle? {
147-
.module
146+
public func specificationFiles(resourceSearchPaths: [SWBUtil.Path]) -> Bundle? {
147+
findResourceBundle(nameWhenInstalledInToolchain: "SwiftBuild_SWBCore", resourceSearchPaths: resourceSearchPaths, defaultBundle: Bundle.module)
148148
}
149149
}

Sources/SWBGenericUnixPlatform/Plugin.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import Foundation
1919
}
2020

2121
struct GenericUnixPlatformSpecsExtension: SpecificationsExtension {
22-
func specificationFiles() -> Bundle? {
23-
.module
22+
func specificationFiles(resourceSearchPaths: [Path]) -> Bundle? {
23+
findResourceBundle(nameWhenInstalledInToolchain: "SwiftBuild_SWBGenericUnixPlatform", resourceSearchPaths: resourceSearchPaths, defaultBundle: Bundle.module)
2424
}
2525

2626
func specificationDomains() -> [String: [String]] {

0 commit comments

Comments
 (0)