Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the ability to specify options, or default arguments, for plugin invocations #899

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ let package = Package(
],
targets: [
.target(name: "RswiftResources"),
.target(name: "RswiftShared"),
.target(name: "RswiftGenerators", dependencies: ["RswiftResources"]),
.target(name: "RswiftParsers", dependencies: ["RswiftResources", "XcodeEdit"]),
.target(name: "RswiftParsers", dependencies: ["RswiftResources", "RswiftShared", "XcodeEdit"]),

.testTarget(name: "RswiftGeneratorsTests", dependencies: ["RswiftGenerators"]),
.testTarget(name: "RswiftParsersTests", dependencies: ["RswiftParsers"]),
Expand All @@ -33,6 +34,7 @@ let package = Package(
.executableTarget(name: "rswift", dependencies: [
.target(name: "RswiftParsers"),
.target(name: "RswiftGenerators"),
.target(name: "RswiftShared"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,56 @@ struct RswiftGenerateInternalResources: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
guard let target = target as? SourceModuleTarget else { return [] }

let outputDirectoryPath = context.pluginWorkDirectory
.appending(subpath: target.name)
let defaultOutputDirectoryPath = context.pluginWorkDirectory.appending(subpath: target.name)
let rswiftPath = defaultOutputDirectoryPath.appending(subpath: "R.generated.swift")

try FileManager.default.createDirectory(atPath: outputDirectoryPath.string, withIntermediateDirectories: true)
let optionsFile = URL(fileURLWithPath: target.directory.appending(subpath: ".rswiftoptions").string)

let rswiftPath = outputDirectoryPath.appending(subpath: "R.generated.swift")
// Our base set of options contains only an access level of `internal` given that
// this is the "internal" resources plugin, hence the access level should always be
// `internal`.
let options = RswiftOptions(accessLevel: .internalLevel)

let sourceFiles = target.sourceFiles
// Next we load and merge any options that may be present in an options file. These
// options don't override any of the previous options provided, but supplements
// those options.
.merging(with: try .init(contentsOf: optionsFile))

// Lastly, we provide a fallback bundle source and output file to ensure that these
// values are always set should no other values be provided
.merging(with: .init(bundleSource: target.kind == .generic ? .module : .finder,
outputPath: rswiftPath.string))

// Get a concrete reference to the file we'll be writing out to
let outputPath = options.outputPath.map { $0.hasPrefix("/") ? Path($0) : defaultOutputDirectoryPath.appending(subpath: $0) } ?? rswiftPath

// Create the output directory, if needed
try FileManager.default.createDirectory(atPath: outputPath.removingLastComponent().string,
withIntermediateDirectories: true)

// Get the input files for the current target being processed
let sourceFiles: [String] = target.sourceFiles
.filter { $0.type == .resource || $0.type == .unknown }
.map(\.path.string)

let inputFilesArguments = sourceFiles
let inputFilesArguments: [String] = sourceFiles
.flatMap { ["--input-files", $0 ] }

let bundleSource = target.kind == .generic ? "module" : "finder"
let description = "\(target.kind) module \(target.name)"
// Lastly, convert the options struct into an array of arguments, subsequently
// appending the input type and files, all of which will be provided to the
// `rswift` utility that we'll invoke.
let arguments: [String] =
options.makeArguments(sourceDirectory: URL(fileURLWithPath: target.directory.string),
outputDirectory: URL(fileURLWithPath: outputPath.removingLastComponent().string)) +
["--input-type", "input-files"] + inputFilesArguments

// Return the build command to execute
return [
.buildCommand(
displayName: "R.swift generate resources for \(description)",
displayName: "R.swift generate resources for \(target.kind) module \(target.name)",
executable: try context.tool(named: "rswift").path,
arguments: [
"generate", rswiftPath.string,
"--input-type", "input-files",
"--bundle-source", bundleSource,
] + inputFilesArguments,
outputFiles: [rswiftPath]
arguments: arguments,
outputFiles: [outputPath]
),
]
}
Expand All @@ -51,13 +74,50 @@ import XcodeProjectPlugin
extension RswiftGenerateInternalResources: XcodeBuildToolPlugin {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {

let resourcesDirectoryPath = context.pluginWorkDirectory
let defaultOutputDirectoryPath = context.pluginWorkDirectory
.appending(subpath: target.displayName)
.appending(subpath: "Resources")

try FileManager.default.createDirectory(atPath: resourcesDirectoryPath.string, withIntermediateDirectories: true)
let rswiftPath = defaultOutputDirectoryPath.appending(subpath: "R.generated.swift")

let projectOptionsFile = URL(fileURLWithPath: context.xcodeProject.directory.appending(subpath: ".rswiftoptions").string)
let targetOptionsFile = URL(fileURLWithPath: context.xcodeProject.directory.appending(subpath: target.displayName).appending(subpath: ".rswiftoptions").string)

// Our base set of options contains an access level of `internal` given that this
// is the "internal" resources plugin, hence the access level should always be
// `internal`, as well as the bundle source, which is always `finder` for Xcode
// projects.
let options = RswiftOptions(accessLevel: .internalLevel,
bundleSource: .finder)

// Next we load and merge any options that may be present in an options file
// specific to the target being processed. These options don't override any of the
// previous options provided, but supplements those options.
.merging(with: try .init(contentsOf: targetOptionsFile))

// Next we load and merge any options that may be present in an options file that
// applies to the entire project. These options don't override any of the previous
// options provided, but supplements those options.
.merging(with: try .init(contentsOf: projectOptionsFile))

// Lastly, we provide a fallback bundle source and output file to ensure that these
// values are always set should no other values be provided
.merging(with: .init(outputPath: rswiftPath.string))

// Get a concrete reference to the file we'll be writing out to
let outputPath = options.outputPath.map { $0.hasPrefix("/") ? Path($0) : defaultOutputDirectoryPath.appending(subpath: $0) } ?? rswiftPath

// Create the output directory, if needed
try FileManager.default.createDirectory(atPath: outputPath.removingLastComponent().string,
withIntermediateDirectories: true)

let rswiftPath = resourcesDirectoryPath.appending(subpath: "R.generated.swift")
// Lastly, convert the options struct into an array of arguments, subsequently
// appending the input type and files, all of which will be provided to the
// `rswift` utility that we'll invoke.
let arguments: [String] =
options.makeArguments(sourceDirectory: URL(fileURLWithPath: context.xcodeProject.directory.string),
outputDirectory: URL(fileURLWithPath: outputPath.removingLastComponent().string)) +
["--input-type", "xcodeproj"]

let description: String
if let product = target.product {
Expand All @@ -66,17 +126,13 @@ extension RswiftGenerateInternalResources: XcodeBuildToolPlugin {
description = target.displayName
}

// Return the build command to execute
return [
.buildCommand(
displayName: "R.swift generate resources for \(description)",
executable: try context.tool(named: "rswift").path,
arguments: [
"generate", rswiftPath.string,
"--target", target.displayName,
"--input-type", "xcodeproj",
"--bundle-source", "finder",
],
outputFiles: [rswiftPath]
arguments: arguments,
outputFiles: [outputPath]
),
]
}
Expand Down
1 change: 1 addition & 0 deletions Plugins/RswiftGenerateInternalResources/RswiftShared
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,56 @@ struct RswiftGeneratePublicResources: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
guard let target = target as? SourceModuleTarget else { return [] }

let outputDirectoryPath = context.pluginWorkDirectory
.appending(subpath: target.name)
let defaultOutputDirectoryPath = context.pluginWorkDirectory.appending(subpath: target.name)
let rswiftPath = defaultOutputDirectoryPath.appending(subpath: "R.generated.swift")

try FileManager.default.createDirectory(atPath: outputDirectoryPath.string, withIntermediateDirectories: true)
let optionsFile = URL(fileURLWithPath: target.directory.appending(subpath: ".rswiftoptions").string)

let rswiftPath = outputDirectoryPath.appending(subpath: "R.generated.swift")
// Our base set of options contains only an access level of `public` given that
// this is the "public" resources plugin, hence the access level should always be
// `public`.
let options = RswiftOptions(accessLevel: .publicLevel)

let sourceFiles = target.sourceFiles
// Next we load and merge any options that may be present in an options file. These
// options don't override any of the previous options provided, but supplements
// those options.
.merging(with: try .init(contentsOf: optionsFile))

// Lastly, we provide a fallback bundle source and output file to ensure that these
// values are always set should no other values be provided
.merging(with: .init(bundleSource: target.kind == .generic ? .module : .finder,
outputPath: rswiftPath.string))

// Get a concrete reference to the file we'll be writing out to
let outputPath = options.outputPath.map { $0.hasPrefix("/") ? Path($0) : defaultOutputDirectoryPath.appending(subpath: $0) } ?? rswiftPath

// Create the output directory, if needed
try FileManager.default.createDirectory(atPath: outputPath.removingLastComponent().string,
withIntermediateDirectories: true)

// Get the input files for the current target being processed
let sourceFiles: [String] = target.sourceFiles
.filter { $0.type == .resource || $0.type == .unknown }
.map(\.path.string)

let inputFilesArguments = sourceFiles
let inputFilesArguments: [String] = sourceFiles
.flatMap { ["--input-files", $0 ] }

let bundleSource = target.kind == .generic ? "module" : "finder"
let description = "\(target.kind) module \(target.name)"
// Lastly, convert the options struct into an array of arguments, subsequently
// appending the input type and files, all of which will be provided to the
// `rswift` utility that we'll invoke.
let arguments: [String] =
options.makeArguments(sourceDirectory: URL(fileURLWithPath: target.directory.string),
outputDirectory: URL(fileURLWithPath: outputPath.removingLastComponent().string)) +
["--input-type", "input-files"] + inputFilesArguments

// Return the build command to execute
return [
.buildCommand(
displayName: "R.swift generate resources for \(description)",
displayName: "R.swift generate resources for \(target.kind) module \(target.name)",
executable: try context.tool(named: "rswift").path,
arguments: [
"generate", rswiftPath.string,
"--input-type", "input-files",
"--bundle-source", bundleSource,
"--access-level", "public",
] + inputFilesArguments,
outputFiles: [rswiftPath]
arguments: arguments,
outputFiles: [outputPath]
),
]
}
Expand All @@ -52,13 +74,49 @@ import XcodeProjectPlugin
extension RswiftGeneratePublicResources: XcodeBuildToolPlugin {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {

let resourcesDirectoryPath = context.pluginWorkDirectory
let defaultOutputDirectoryPath = context.pluginWorkDirectory
.appending(subpath: target.displayName)
.appending(subpath: "Resources")

try FileManager.default.createDirectory(atPath: resourcesDirectoryPath.string, withIntermediateDirectories: true)
let rswiftPath = defaultOutputDirectoryPath.appending(subpath: "R.generated.swift")

let projectOptionsFile = URL(fileURLWithPath: context.xcodeProject.directory.appending(subpath: ".rswiftoptions").string)
let targetOptionsFile = URL(fileURLWithPath: context.xcodeProject.directory.appending(subpath: target.displayName).appending(subpath: ".rswiftoptions").string)

// Our base set of options contains an access level of `public` given that this is
// the "public" resources plugin, hence the access level should always be `public`,
// as well as the bundle source, which is always `finder` for Xcode projects.
let options = RswiftOptions(accessLevel: .publicLevel,
bundleSource: .finder)

// Next we load and merge any options that may be present in an options file
// specific to the target being processed. These options don't override any of the
// previous options provided, but supplements those options.
.merging(with: try .init(contentsOf: targetOptionsFile))

// Next we load and merge any options that may be present in an options file that
// applies to the entire project. These options don't override any of the previous
// options provided, but supplements those options.
.merging(with: try .init(contentsOf: projectOptionsFile))

// Lastly, we provide a fallback bundle source and output file to ensure that these
// values are always set should no other values be provided
.merging(with: .init(outputPath: rswiftPath.string))

// Get a concrete reference to the file we'll be writing out to
let outputPath = options.outputPath.map { $0.hasPrefix("/") ? Path($0) : defaultOutputDirectoryPath.appending(subpath: $0) } ?? rswiftPath

// Create the output directory, if needed
try FileManager.default.createDirectory(atPath: outputPath.removingLastComponent().string,
withIntermediateDirectories: true)

let rswiftPath = resourcesDirectoryPath.appending(subpath: "R.generated.swift")
// Lastly, convert the options struct into an array of arguments, subsequently
// appending the input type and files, all of which will be provided to the
// `rswift` utility that we'll invoke.
let arguments: [String] =
options.makeArguments(sourceDirectory: URL(fileURLWithPath: context.xcodeProject.directory.string),
outputDirectory: URL(fileURLWithPath: outputPath.removingLastComponent().string)) +
["--input-type", "xcodeproj"]

let description: String
if let product = target.product {
Expand All @@ -67,18 +125,13 @@ extension RswiftGeneratePublicResources: XcodeBuildToolPlugin {
description = target.displayName
}

// Return the build command to execute
return [
.buildCommand(
displayName: "R.swift generate resources for \(description)",
executable: try context.tool(named: "rswift").path,
arguments: [
"generate", rswiftPath.string,
"--target", target.displayName,
"--input-type", "xcodeproj",
"--bundle-source", "finder",
"--access-level", "public",
],
outputFiles: [rswiftPath]
arguments: arguments,
outputFiles: [outputPath]
),
]
}
Expand Down
1 change: 1 addition & 0 deletions Plugins/RswiftGeneratePublicResources/RswiftShared
Loading