From f3e1f57496f050933b15b2032fe8d9fc6c74346c Mon Sep 17 00:00:00 2001 From: Joe Diragi Date: Tue, 18 Jun 2024 16:27:19 -0400 Subject: [PATCH] Add support for `rswift.json` config to BuildToolPlugins --- .../RswiftGenerateInternalResources.swift | 88 +++++++++++++++++-- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/Plugins/RswiftGenerateInternalResources/RswiftGenerateInternalResources.swift b/Plugins/RswiftGenerateInternalResources/RswiftGenerateInternalResources.swift index bdefb5b9..6d6cdcdc 100644 --- a/Plugins/RswiftGenerateInternalResources/RswiftGenerateInternalResources.swift +++ b/Plugins/RswiftGenerateInternalResources/RswiftGenerateInternalResources.swift @@ -8,6 +8,19 @@ import Foundation import PackagePlugin +struct RSwiftConfig: Codable { + enum Generator: String, Codable { + case image, string, color + case file, font, nib + case segue, storyboard, reuseIdentifier + case entitlements, info, id + } + + let generators: [Generator]? + let rswiftignorePath: String? + let additionalArguments: [String]? +} + @main struct RswiftGenerateInternalResources: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { @@ -29,7 +42,21 @@ struct RswiftGenerateInternalResources: BuildToolPlugin { let bundleSource = target.kind == .generic ? "module" : "finder" let description = "\(target.kind) module \(target.name)" - + + var additionalArguments: [String] = [] + if let config = getConfig(from: target) { + if let generators = config.generators { + let generators = generators.map(\.rawValue).joined(separator: ",") + additionalArguments += ["--generators", generators] + } + if let rswiftignorePath = config.rswiftignorePath { + additionalArguments += ["--rswiftignore", rswiftignorePath] + } + if let other = config.additionalArguments { + additionalArguments += other + } + } + return [ .buildCommand( displayName: "R.swift generate resources for \(description)", @@ -38,11 +65,34 @@ struct RswiftGenerateInternalResources: BuildToolPlugin { "generate", rswiftPath.string, "--input-type", "input-files", "--bundle-source", bundleSource, - ] + inputFilesArguments, + ] + inputFilesArguments + additionalArguments, outputFiles: [rswiftPath] ), ] } + + func getConfig(from target: SourceModuleTarget) -> RSwiftConfig? { + guard let path = locateConfig(in: target) else { + return nil + } + return decodeConfig(at: path) + } + + func locateConfig(in target: SourceModuleTarget) -> Path? { + let rootConfig = target.directory.appending(["rswift.json"]) + if FileManager.default.fileExists(atPath: rootConfig.string) { + return rootConfig + } + return target.sourceFiles.map(\.path).first(where: { $0.lastComponent == "rswift.json" }) + } + + func decodeConfig(at path: Path) -> RSwiftConfig? { + guard let config = URL(string: "file://\(path.string)"), + let data = try? Data(contentsOf: config) else { + return nil + } + return try? JSONDecoder().decode(RSwiftConfig.self, from: data) + } } #if canImport(XcodeProjectPlugin) @@ -50,7 +100,6 @@ import XcodeProjectPlugin extension RswiftGenerateInternalResources: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { - let resourcesDirectoryPath = context.pluginWorkDirectory .appending(subpath: target.displayName) .appending(subpath: "Resources") @@ -65,6 +114,20 @@ extension RswiftGenerateInternalResources: XcodeBuildToolPlugin { } else { description = target.displayName } + + var additionalArguments: [String] = [] + if let config = getConfig(from: context.xcodeProject) { + if let generators = config.generators { + let generators = generators.map(\.rawValue).joined(separator: ",") + additionalArguments += ["--generators", generators] + } + if let rswiftignorePath = config.rswiftignorePath { + additionalArguments += ["--rswiftignore", rswiftignorePath] + } + if let other = config.additionalArguments { + additionalArguments += other + } + } return [ .buildCommand( @@ -74,12 +137,27 @@ extension RswiftGenerateInternalResources: XcodeBuildToolPlugin { "generate", rswiftPath.string, "--target", target.displayName, "--input-type", "xcodeproj", - "--bundle-source", "finder", - ], + "--bundle-source", "finder" + ] + additionalArguments, outputFiles: [rswiftPath] ), ] } + + func getConfig(from xcodeProject: XcodeProject) -> RSwiftConfig? { + guard let path = locateConfig(in: xcodeProject) else { + return nil + } + return decodeConfig(at: path) + } + + func locateConfig(in xcodeProject: XcodeProject) -> Path? { + let rootConfig = xcodeProject.directory.appending(["rswift.json"]) + if FileManager.default.fileExists(atPath: rootConfig.string) { + return rootConfig + } + return xcodeProject.filePaths.first(where: { $0.lastComponent == "rswift.json" }) + } } #endif