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

Add arguments to Plugins #7604

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ enum Serialization {
}

enum PluginUsage: Codable {
case plugin(name: String, package: String?)
case plugin(name: String, package: String?, arguments: [String])
}

struct Target: Codable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ extension Serialization.PluginNetworkPermissionScope {
extension Serialization.PluginUsage {
init(_ usage: PackageDescription.Target.PluginUsage) {
switch usage {
case .plugin(let name, let package): self = .plugin(name: name, package: package)
case .plugin(let name, let package, let arguments): self = .plugin(name: name, package: package, arguments: arguments)
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions Sources/PackageDescription/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public final class Target {
/// The plug-in to apply to each target that uses it, and creates commands
/// that run before or during the build of the target.
@available(_PackageDescription, introduced: 5.5)
case buildTool
case buildTool(arguments: [String])

/// Specifies that the plug-in provides a user command capability.
///
Expand Down Expand Up @@ -227,7 +227,7 @@ public final class Target {
/// - Parameters:
/// - name: The name of the plug-in target.
/// - package: The name of the package that defines the plug-in target.
case plugin(name: String, package: String?)
case plugin(name: String, package: String?, arguments: [String])
}

/// Construct a target.
Expand Down Expand Up @@ -1398,7 +1398,7 @@ extension Target.PluginCapability {
/// - Returns: A plug-in capability that defines a build tool.
@available(_PackageDescription, introduced: 5.5)
public static func buildTool() -> Target.PluginCapability {
return .buildTool
return .buildTool(arguments: [])
}
}

Expand Down Expand Up @@ -1507,8 +1507,8 @@ extension Target.PluginUsage {
/// - Parameter name: The name of the plugin target.
/// - Returns: A `PluginUsage` instance.
@available(_PackageDescription, introduced: 5.5)
public static func plugin(name: String) -> Target.PluginUsage {
return .plugin(name: name, package: nil)
public static func plugin(name: String, arguments: [String]) -> Target.PluginUsage {
return .plugin(name: name, package: nil, arguments: arguments)
}
}

Expand All @@ -1535,7 +1535,7 @@ extension Target.PluginUsage: ExpressibleByStringLiteral {
///
/// - Parameter value: A string literal.
public init(stringLiteral value: String) {
self = .plugin(name: value, package: nil)
self = .plugin(name: value, package: nil, arguments: [])
}
}

4 changes: 2 additions & 2 deletions Sources/PackageLoading/ManifestJSONParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,8 @@ extension TargetDescription.PluginNetworkPermissionScope {
extension TargetDescription.PluginUsage {
init(_ usage: Serialization.PluginUsage) {
switch usage {
case .plugin(let name, let package):
self = .plugin(name: name, package: package)
case .plugin(let name, let package, let arguments):
self = .plugin(name: name, package: package, arguments: arguments)
}
}
}
Expand Down
15 changes: 10 additions & 5 deletions Sources/PackageLoading/PackageBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ public final class PackageBuilder {
let potentialModuleMap = Dictionary(potentialModules.map { ($0.name, $0) }, uniquingKeysWith: { $1 })
let successors: (PotentialModule) -> [PotentialModule] = {
// No reference of this target in manifest, i.e. it has no dependencies.
guard let target = self.manifest.targetMap[$0.name] else { return [] }
guard let target: TargetDescription = self.manifest.targetMap[$0.name] else { return [] }
// Collect the successors from declared dependencies.
var successors: [PotentialModule] = target.dependencies.compactMap {
switch $0 {
Expand All @@ -692,9 +692,9 @@ public final class PackageBuilder {
if let pluginUsages = target.pluginUsages {
successors += pluginUsages.compactMap {
switch $0 {
case .plugin(_, .some(_)):
case .plugin(_, .some(_), _):
nil
case .plugin(let name, nil):
case .plugin(let name, nil, _):
if let potentialModule = potentialModuleMap[name] {
potentialModule
} else if let targetName = pluginTargetName(for: name),
Expand Down Expand Up @@ -766,13 +766,17 @@ public final class PackageBuilder {
let pluginUsages: [Target.PluginUsage] = manifestTarget?.pluginUsages.map {
$0.compactMap { usage in
switch usage {
case .plugin(let name, let package):
case .plugin(let name, let package, let arguments):
if let package {
return .product(Target.ProductReference(name: name, package: package), conditions: [])
} else {
if let target = targets[name] {
if let arguments {
(target as? PluginTarget)?.arguments = arguments
}
return .target(target, conditions: [])
} else if let targetName = pluginTargetName(for: name), let target = targets[targetName] {
// TODO: Check
return .target(target, conditions: [])
} else {
self.observabilityScope.emit(.pluginNotFound(name: name))
Expand Down Expand Up @@ -960,7 +964,8 @@ public final class PackageBuilder {
apiVersion: self.manifest.toolsVersion,
pluginCapability: PluginCapability(from: declaredCapability),
dependencies: dependencies,
packageAccess: potentialModule.packageAccess
packageAccess: potentialModule.packageAccess,
arguments: []
)
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/PackageModel/Manifest/Manifest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public final class Manifest: Sendable {

let plugins: [String] = target.pluginUsages?.compactMap { pluginUsage in
switch pluginUsage {
case .plugin(name: let name, package: nil):
case .plugin(name: let name, package: nil, _):
if targetsByName.keys.contains(name) {
return name
} else if let targetName = productsByName[name]?.targets.first {
Expand Down Expand Up @@ -334,7 +334,7 @@ public final class Manifest: Sendable {
referencedBy pluginUsage: TargetDescription.PluginUsage
) -> PackageDependency? {
switch pluginUsage {
case .plugin(_, .some(let package)):
case .plugin(_, .some(let package), _):
return self.packageDependency(referencedBy: package)
default:
return nil
Expand Down Expand Up @@ -433,7 +433,7 @@ public final class Manifest: Sendable {
availablePackages: Set<PackageIdentity>
) {
switch requiredPlugIn {
case .plugin(let name, let package):
case .plugin(let name, let package, _):
if let package {
if !self.register(
product: name,
Expand Down
8 changes: 5 additions & 3 deletions Sources/PackageModel/Manifest/TargetDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public struct TargetDescription: Hashable, Encodable, Sendable {

/// Represents a target's usage of a plugin target or product.
public enum PluginUsage: Hashable, Sendable {
case plugin(name: String, package: String?)
case plugin(name: String, package: String?, arguments: [String]?)
}

public init(
Expand Down Expand Up @@ -357,10 +357,11 @@ extension TargetDescription.PluginUsage: Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case let .plugin(name, package):
case let .plugin(name, package, arguments):
var unkeyedContainer = container.nestedUnkeyedContainer(forKey: .plugin)
try unkeyedContainer.encode(name)
try unkeyedContainer.encode(package)
try unkeyedContainer.encode(arguments)
}
}

Expand All @@ -374,7 +375,8 @@ extension TargetDescription.PluginUsage: Codable {
var unkeyedValues = try values.nestedUnkeyedContainer(forKey: key)
let name = try unkeyedValues.decode(String.self)
let package = try unkeyedValues.decodeIfPresent(String.self)
self = .plugin(name: name, package: package)
let arguments = try? unkeyedValues.decodeIfPresent([String].self)
self = .plugin(name: name, package: package, arguments: arguments)
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion Sources/PackageModel/Target/PluginTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ public final class PluginTarget: Target {
/// API version to use for PackagePlugin API availability.
public let apiVersion: ToolsVersion

public var arguments: [String]

public init(
name: String,
sources: Sources,
apiVersion: ToolsVersion,
pluginCapability: PluginCapability,
dependencies: [Target.Dependency] = [],
packageAccess: Bool
packageAccess: Bool,
arguments: [String]
) {
self.capability = pluginCapability
self.apiVersion = apiVersion
self.arguments = arguments
super.init(
name: name,
type: .plugin,
Expand All @@ -45,19 +49,22 @@ public final class PluginTarget: Target {
private enum CodingKeys: String, CodingKey {
case capability
case apiVersion
case arguments
}

public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.capability, forKey: .capability)
try container.encode(self.apiVersion, forKey: .apiVersion)
try container.encode(self.arguments, forKey: .arguments)
try super.encode(to: encoder)
}

required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.capability = try container.decode(PluginCapability.self, forKey: .capability)
self.apiVersion = try container.decode(ToolsVersion.self, forKey: .apiVersion)
self.arguments = try container.decode([String].self, forKey: .arguments)
try super.init(from: decoder)
}
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/PackagePlugin/Plugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ extension Plugin {
fileprivate static func handleMessage(_ message: HostToPluginMessage) async throws {
switch message {

case .createBuildToolCommands(let wireInput, let rootPackageId, let targetId, let generatedSources, let generatedResources):
case .createBuildToolCommands(let wireInput, let rootPackageId, let targetId, let generatedSources, let generatedResources, let arguments):
// Deserialize the context from the wire input structures. The root
// package is the one we'll set the context's `package` property to.
let context: PluginContext
Expand Down Expand Up @@ -195,7 +195,7 @@ extension Plugin {
}

// Invoke the plugin to create build commands for the target.
let generatedCommands = try await plugin.createBuildCommands(context: context, target: target)
let generatedCommands = try await plugin.createBuildCommands(context: context, target: target, arguments: arguments)

// Send each of the generated commands to the host.
for command in generatedCommands {
Expand Down
3 changes: 2 additions & 1 deletion Sources/PackagePlugin/PluginMessages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ enum HostToPluginMessage: Codable {
rootPackageId: InputContext.Package.Id,
targetId: InputContext.Target.Id,
pluginGeneratedSources: [InputContext.URL.Id],
pluginGeneratedResources: [InputContext.URL.Id]
pluginGeneratedResources: [InputContext.URL.Id],
arguments: [String]
)

/// The host requests that the plugin perform a user command (corresponding to a `.command` capability) on a package in the graph.
Expand Down
3 changes: 2 additions & 1 deletion Sources/PackagePlugin/Protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public protocol BuildToolPlugin: Plugin {
/// that it does not directly run those commands.
func createBuildCommands(
context: PluginContext,
target: Target
target: Target,
arguments: [String]
) async throws -> [Command]
}

Expand Down
14 changes: 9 additions & 5 deletions Sources/SPMBuildCore/Plugins/PluginInvocation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public enum PluginAction {
package: ResolvedPackage,
target: ResolvedModule,
pluginGeneratedSources: [AbsolutePath],
pluginGeneratedResources: [AbsolutePath]
pluginGeneratedResources: [AbsolutePath],
arguments: [String]
)
case performCommand(package: ResolvedPackage, arguments: [String])
}
Expand All @@ -46,7 +47,8 @@ extension PluginTarget {
modulesGraph: ModulesGraph,
observabilityScope: ObservabilityScope,
callbackQueue: DispatchQueue,
delegate: PluginInvocationDelegate
delegate: PluginInvocationDelegate,
arguments: [String]
) async throws -> Bool {
try await safe_async {
self.invoke(
Expand Down Expand Up @@ -142,7 +144,7 @@ extension PluginTarget {
let actionMessage: HostToPluginMessage
switch action {

case .createBuildToolCommands(let package, let target, let pluginGeneratedSources, let pluginGeneratedResources):
case .createBuildToolCommands(let package, let target, let pluginGeneratedSources, let pluginGeneratedResources, let arguments):
let rootPackageId = try serializer.serialize(package: package)
guard let targetId = try serializer.serialize(target: target) else {
throw StringError("unexpectedly was unable to serialize target \(target)")
Expand All @@ -162,7 +164,8 @@ extension PluginTarget {
rootPackageId: rootPackageId,
targetId: targetId,
pluginGeneratedSources: generatedSources,
pluginGeneratedResources: generatedResources
pluginGeneratedResources: generatedResources,
arguments: arguments
)
case .performCommand(let package, let arguments):
let rootPackageId = try serializer.serialize(package: package)
Expand Down Expand Up @@ -561,7 +564,8 @@ extension ModulesGraph {
package: package,
target: target,
pluginGeneratedSources: pluginDerivedSources.paths,
pluginGeneratedResources: pluginDerivedResources.map { $0.path }
pluginGeneratedResources: pluginDerivedResources.map { $0.path },
arguments: pluginTarget.arguments
),
buildEnvironment: buildParameters.buildEnvironment,
scriptRunner: pluginScriptRunner,
Expand Down
3 changes: 2 additions & 1 deletion Tests/FunctionalTests/PluginTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,8 @@ final class PluginTests: XCTestCase {
modulesGraph: packageGraph,
observabilityScope: observability.topScope,
callbackQueue: delegateQueue,
delegate: delegate
delegate: delegate,
arguments: []
)
} onCancel: {
do {
Expand Down
2 changes: 1 addition & 1 deletion Tests/SPMBuildCoreTests/PluginInvocationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final class PluginInvocationTests: XCTestCase {
TargetDescription(
name: "Foo",
type: .regular,
pluginUsages: [.plugin(name: "FooPlugin", package: nil)]
pluginUsages: [.plugin(name: "FooPlugin", package: nil, arguments: ["123", "321"])]
),
TargetDescription(
name: "FooPlugin",
Expand Down