From 5bcbf3959dc2b9e070db788b19d3a1dd375321e8 Mon Sep 17 00:00:00 2001 From: "freddi(Yuki Aki)" Date: Thu, 15 Feb 2024 19:31:42 +0900 Subject: [PATCH] Fix crash bundle (#1448) * create availableModule to avoid crash on Bundle loading * remove unnecessary line --- Sources/XcodeGenKit/SettingsBuilder.swift | 47 ++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index 81047de7..b65079b9 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -249,7 +249,7 @@ extension SettingsPresetFile { symlink.parent() + relativePath, ] + possibleSettingsPaths } - if let moduleResourcePath = Bundle.module.path(forResource: "SettingPresets", ofType: nil) { + if let moduleResourcePath = Bundle.availableModule?.path(forResource: "SettingPresets", ofType: nil) { possibleSettingsPaths.append(Path(moduleResourcePath) + "\(path).yml") } @@ -272,3 +272,48 @@ extension SettingsPresetFile { return buildSettings } } + +private class BundleFinder {} + +/// The default SPM generated `Bundle.module` crashes on runtime if there is no .bundle file. +/// Below implementation modified from generated `Bundle.module` code which call `fatalError` if .bundle file not found. +private extension Bundle { + /// Returns the resource bundle associated with the current Swift module. + static let availableModule: Bundle? = { + let bundleName = "XcodeGen_XcodeGenKit" + + let overrides: [URL] + #if DEBUG + // The 'PACKAGE_RESOURCE_BUNDLE_PATH' name is preferred since the expected value is a path. The + // check for 'PACKAGE_RESOURCE_BUNDLE_URL' will be removed when all clients have switched over. + // This removal is tracked by rdar://107766372. + if let override = ProcessInfo.processInfo.environment["PACKAGE_RESOURCE_BUNDLE_PATH"] + ?? ProcessInfo.processInfo.environment["PACKAGE_RESOURCE_BUNDLE_URL"] { + overrides = [URL(fileURLWithPath: override)] + } else { + overrides = [] + } + #else + overrides = [] + #endif + + let candidates = overrides + [ + // Bundle should be present here when the package is linked into an App. + Bundle.main.resourceURL, + + // Bundle should be present here when the package is linked into a framework. + Bundle(for: BundleFinder.self).resourceURL, + + // For command-line tools. + Bundle.main.bundleURL, + ] + + for candidate in candidates { + let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle") + if let bundle = bundlePath.flatMap(Bundle.init(url:)) { + return bundle + } + } + return nil + }() +}