@@ -18,7 +18,7 @@ import SwiftSyntax
18
18
import SwiftSyntaxBuilder
19
19
20
20
/// Add a target plugin to a manifest's source code.
21
- public struct AddTargetPlugin {
21
+ public enum AddTargetPlugin {
22
22
/// The set of argument labels that can occur after the "plugins"
23
23
/// argument in the various target initializers.
24
24
///
@@ -54,19 +54,33 @@ public struct AddTargetPlugin {
54
54
}
55
55
56
56
guard let stringLiteral = nameArgument. expression. as ( StringLiteralExprSyntax . self) ,
57
- let literalValue = stringLiteral. representedLiteralValue else {
57
+ let literalValue = stringLiteral. representedLiteralValue
58
+ else {
58
59
return false
59
60
}
60
61
61
62
return literalValue == targetName
62
63
}
63
64
64
- guard let targetCall = FunctionCallExprSyntax . findFirst ( in: targetArray, matching: matchesTargetCall) else {
65
+ guard let targetCall = FunctionCallExprSyntax . findFirst (
66
+ in: targetArray,
67
+ matching: matchesTargetCall
68
+ ) else {
65
69
throw ManifestEditError . cannotFindTarget ( targetName: targetName)
66
70
}
67
71
72
+ guard try ! self . pluginAlreadyAdded (
73
+ plugin,
74
+ to: targetName,
75
+ in: targetCall
76
+ )
77
+ else {
78
+ return PackageEditResult ( manifestEdits: [ ] )
79
+ }
80
+
68
81
let newTargetCall = try addTargetPluginLocal (
69
- plugin, to: targetCall
82
+ plugin,
83
+ to: targetCall
70
84
)
71
85
72
86
return PackageEditResult (
@@ -76,16 +90,76 @@ public struct AddTargetPlugin {
76
90
)
77
91
}
78
92
79
- /// Implementation of adding a target dependency to an existing call.
93
+ private static func pluginAlreadyAdded(
94
+ _ plugin: TargetDescription . PluginUsage ,
95
+ to targetName: String ,
96
+ in packageCall: FunctionCallExprSyntax
97
+ ) throws -> Bool {
98
+ let pluginSyntax = plugin. asSyntax ( )
99
+ guard let pluginFnSyntax = pluginSyntax. as ( FunctionCallExprSyntax . self)
100
+ else {
101
+ throw ManifestEditError . cannotFindPackage
102
+ }
103
+
104
+ guard let id = pluginFnSyntax. arguments. first ( where: {
105
+ $0. label? . text == " name "
106
+ } )
107
+ else {
108
+ throw InternalError ( " Missing 'name' argument in plugin syntax " )
109
+ }
110
+
111
+ if let existingPlugins = packageCall. findArgument ( labeled: " plugins " ) {
112
+ // If we have an existing plugins array, we need to check if
113
+ if let expr = existingPlugins. expression. as ( ArrayExprSyntax . self) {
114
+ // Iterate through existing plugins and look for an argument that matches
115
+ // the `name` argument of the new plugin.
116
+ let existingArgument = expr. elements. first { elem in
117
+ if let funcExpr = elem. expression. as (
118
+ FunctionCallExprSyntax . self
119
+ ) {
120
+ return funcExpr. arguments. contains {
121
+ $0. with ( \. trailingComma, nil ) . trimmedDescription ==
122
+ id. with ( \. trailingComma, nil ) . trimmedDescription
123
+ }
124
+ }
125
+ return true
126
+ }
127
+
128
+ if let existingArgument {
129
+ let normalizedExistingArgument = existingArgument. detached. with ( \. trailingComma, nil )
130
+ // This exact plugin already exists, return false to indicate we should do nothing.
131
+ if normalizedExistingArgument. trimmedDescription == pluginSyntax. trimmedDescription {
132
+ return true
133
+ }
134
+ throw ManifestEditError . existingPlugin (
135
+ pluginName: plugin. identifier,
136
+ taget: targetName
137
+ )
138
+ }
139
+ }
140
+ }
141
+
142
+ return false
143
+ }
144
+
145
+ /// Implementation of adding a target plugin to an existing call.
80
146
static func addTargetPluginLocal(
81
147
_ plugin: TargetDescription . PluginUsage ,
82
148
to targetCall: FunctionCallExprSyntax
83
149
) throws -> FunctionCallExprSyntax {
84
150
try targetCall. appendingToArrayArgument (
85
151
label: " plugins " ,
86
- trailingLabels: Self . argumentLabelsAfterDependencies,
152
+ trailingLabels: self . argumentLabelsAfterDependencies,
87
153
newElement: plugin. asSyntax ( )
88
154
)
89
155
}
90
156
}
91
157
158
+ extension TargetDescription . PluginUsage {
159
+ fileprivate var identifier : String {
160
+ switch self {
161
+ case . plugin( let name, _) :
162
+ name
163
+ }
164
+ }
165
+ }
0 commit comments