@@ -20,6 +20,7 @@ import PackagePlugin
20
20
struct CommandConfig {
21
21
var common : GenerationConfig
22
22
23
+ var verbose : Bool
23
24
var dryRun : Bool
24
25
25
26
static let defaults = Self (
@@ -33,97 +34,103 @@ struct CommandConfig {
33
34
importPaths: [ ] ,
34
35
outputPath: " "
35
36
) ,
37
+ verbose: false ,
36
38
dryRun: false
37
39
)
38
40
}
39
41
40
42
extension CommandConfig {
43
+ static func helpRequested(
44
+ argumentExtractor: inout ArgumentExtractor ,
45
+ ) -> Bool {
46
+ let help = argumentExtractor. extractFlag ( named: OptionsAndFlags . help. rawValue)
47
+ return help != 0
48
+ }
49
+
41
50
static func parse(
42
- arguments : [ String ] ,
51
+ argumentExtractor argExtractor : inout ArgumentExtractor ,
43
52
pluginWorkDirectory: URL
44
53
) throws -> ( CommandConfig , [ String ] ) {
45
54
var config = CommandConfig . defaults
46
55
47
- var argExtractor = ArgumentExtractor ( arguments)
48
-
49
- for flag in Flag . allCases {
56
+ for flag in OptionsAndFlags . allCases {
50
57
switch flag {
51
58
case . accessLevel:
52
59
let accessLevel = argExtractor. extractOption ( named: flag. rawValue)
53
- if let value = accessLevel. first {
54
- switch value. lowercased ( ) {
55
- case " internal " :
56
- config. common. accessLevel = . `internal`
57
- case " public " :
58
- config. common. accessLevel = . `public`
59
- case " package " :
60
- config. common. accessLevel = . `package`
61
- default :
62
- Diagnostics . error ( " Unknown accessLevel \( value) " )
60
+ if let value = extractSingleValue ( flag, values: accessLevel) {
61
+ if let accessLevel = GenerationConfig . AccessLevel ( rawValue: value) {
62
+ config. common. accessLevel = accessLevel
63
63
}
64
- }
65
- case . servers:
66
- let servers = argExtractor. extractOption ( named: flag. rawValue)
67
- if let value = servers. first {
68
- guard let servers = Bool ( value) else {
69
- throw CommandPluginError . invalidArgumentValue ( value)
64
+ else {
65
+ Diagnostics . error ( " Unknown access level '-- \( flag. rawValue) ' \( value) " )
70
66
}
71
- config. common. servers = servers
72
67
}
73
- case . clients :
74
- let clients = argExtractor . extractOption ( named : flag . rawValue )
75
- if let value = clients . first {
76
- guard let clients = Bool ( value ) else {
77
- throw CommandPluginError . invalidArgumentValue ( value )
78
- }
79
- config. common. clients = clients
68
+
69
+ case . servers , . noServers :
70
+ if flag == . noServers { continue } // only process this once
71
+ let servers = argExtractor . extractFlag ( named : OptionsAndFlags . servers . rawValue )
72
+ let noServers = argExtractor . extractFlag ( named : OptionsAndFlags . noServers . rawValue )
73
+ if noServers > servers {
74
+ config. common. servers = false
80
75
}
81
- case . messages:
82
- let messages = argExtractor. extractOption ( named: flag. rawValue)
83
- if let value = messages. first {
84
- guard let messages = Bool ( value) else {
85
- throw CommandPluginError . invalidArgumentValue ( value)
86
- }
87
- config. common. messages = messages
76
+
77
+ case . clients, . noClients:
78
+ if flag == . noClients { continue } // only process this once
79
+ let clients = argExtractor. extractFlag ( named: OptionsAndFlags . clients. rawValue)
80
+ let noClients = argExtractor. extractFlag ( named: OptionsAndFlags . noClients. rawValue)
81
+ if noClients > clients {
82
+ config. common. clients = false
83
+ }
84
+
85
+ case . messages, . noMessages:
86
+ if flag == . noMessages { continue } // only process this once
87
+ let messages = argExtractor. extractFlag ( named: OptionsAndFlags . messages. rawValue)
88
+ let noMessages = argExtractor. extractFlag ( named: OptionsAndFlags . noMessages. rawValue)
89
+ if noMessages > messages {
90
+ config. common. messages = false
88
91
}
92
+
89
93
case . fileNaming:
90
94
let fileNaming = argExtractor. extractOption ( named: flag. rawValue)
91
- if let value = fileNaming. first {
92
- switch value. lowercased ( ) {
93
- case " fullPath " :
94
- config. common. fileNaming = . fullPath
95
- case " pathToUnderscores " :
96
- config. common. fileNaming = . pathToUnderscores
97
- case " dropPath " :
98
- config. common. fileNaming = . dropPath
99
- default :
100
- Diagnostics . error ( " Unknown file naming strategy \( value) " )
95
+ if let value = extractSingleValue ( flag, values: fileNaming) {
96
+ if let fileNaming = GenerationConfig . FileNaming ( rawValue: value) {
97
+ config. common. fileNaming = fileNaming
98
+ }
99
+ else {
100
+ Diagnostics . error ( " Unknown file naming strategy '-- \( flag. rawValue) ' \( value) " )
101
101
}
102
102
}
103
+
103
104
case . accessLevelOnImports:
104
105
let accessLevelOnImports = argExtractor. extractOption ( named: flag. rawValue)
105
- if let value = accessLevelOnImports. first {
106
+ if let value = extractSingleValue ( flag , values : accessLevelOnImports) {
106
107
guard let accessLevelOnImports = Bool ( value) else {
107
- throw CommandPluginError . invalidArgumentValue ( value)
108
+ throw CommandPluginError . invalidArgumentValue ( name : flag . rawValue , value : value)
108
109
}
109
110
config. common. accessLevelOnImports = accessLevelOnImports
110
111
}
112
+
111
113
case . importPath:
112
114
config. common. importPaths = argExtractor. extractOption ( named: flag. rawValue)
115
+
113
116
case . protocPath:
114
117
let protocPath = argExtractor. extractOption ( named: flag. rawValue)
115
- config. common. protocPath = protocPath. first
118
+ config. common. protocPath = extractSingleValue ( flag, values: protocPath)
119
+
116
120
case . output:
117
121
let output = argExtractor. extractOption ( named: flag. rawValue)
118
- config. common. outputPath = output. first ?? pluginWorkDirectory. absoluteStringNoScheme
122
+ config. common. outputPath = extractSingleValue ( flag, values: output) ?? pluginWorkDirectory. absoluteStringNoScheme
123
+
124
+ case . verbose:
125
+ let verbose = argExtractor. extractFlag ( named: flag. rawValue)
126
+ config. verbose = verbose != 0
127
+
119
128
case . dryRun:
120
129
let dryRun = argExtractor. extractFlag ( named: flag. rawValue)
121
130
config. dryRun = dryRun != 0
131
+
122
132
case . help:
123
- let help = argExtractor. extractFlag ( named: flag. rawValue)
124
- if help != 0 {
125
- throw CommandPluginError . helpRequested
126
- }
133
+ ( ) // handled elsewhere
127
134
}
128
135
}
129
136
@@ -141,19 +148,30 @@ extension CommandConfig {
141
148
}
142
149
}
143
150
151
+ func extractSingleValue( _ flag: OptionsAndFlags , values: [ String ] ) -> String ? {
152
+ if values. count > 1 {
153
+ Stderr . print ( " Warning: '-- \( flag. rawValue) ' was unexpectedly repeated, the first value will be used. " )
154
+ }
155
+ return values. first
156
+ }
157
+
144
158
/// All valid input options/flags
145
- enum Flag : CaseIterable , RawRepresentable {
159
+ enum OptionsAndFlags : CaseIterable , RawRepresentable {
146
160
typealias RawValue = String
147
161
148
162
case servers
163
+ case noServers
149
164
case clients
165
+ case noClients
150
166
case messages
167
+ case noMessages
151
168
case fileNaming
152
169
case accessLevel
153
170
case accessLevelOnImports
154
171
case importPath
155
172
case protocPath
156
173
case output
174
+ case verbose
157
175
case dryRun
158
176
159
177
case help
@@ -162,22 +180,30 @@ enum Flag: CaseIterable, RawRepresentable {
162
180
switch rawValue {
163
181
case " servers " :
164
182
self = . servers
183
+ case " no-servers " :
184
+ self = . noServers
165
185
case " clients " :
166
186
self = . clients
187
+ case " no-clients " :
188
+ self = . noClients
167
189
case " messages " :
168
190
self = . messages
191
+ case " no-messages " :
192
+ self = . noMessages
169
193
case " file-naming " :
170
194
self = . fileNaming
171
195
case " access-level " :
172
196
self = . accessLevel
173
- case " use- access-level-on-imports" :
197
+ case " access-level-on-imports " :
174
198
self = . accessLevelOnImports
175
199
case " import-path " :
176
200
self = . importPath
177
201
case " protoc-path " :
178
202
self = . protocPath
179
203
case " output " :
180
204
self = . output
205
+ case " verbose " :
206
+ self = . verbose
181
207
case " dry-run " :
182
208
self = . dryRun
183
209
case " help " :
@@ -192,10 +218,16 @@ enum Flag: CaseIterable, RawRepresentable {
192
218
switch self {
193
219
case . servers:
194
220
" servers "
221
+ case . noServers:
222
+ " no-servers "
195
223
case . clients:
196
224
" clients "
225
+ case . noClients:
226
+ " no-clients "
197
227
case . messages:
198
228
" messages "
229
+ case . noMessages:
230
+ " no-messages "
199
231
case . fileNaming:
200
232
" file-naming "
201
233
case . accessLevel:
@@ -208,6 +240,8 @@ enum Flag: CaseIterable, RawRepresentable {
208
240
" protoc-path "
209
241
case . output:
210
242
" output "
243
+ case . verbose:
244
+ " verbose "
211
245
case . dryRun:
212
246
" dry-run "
213
247
case . help:
@@ -216,15 +250,21 @@ enum Flag: CaseIterable, RawRepresentable {
216
250
}
217
251
}
218
252
219
- extension Flag {
253
+ extension OptionsAndFlags {
220
254
func usageDescription( ) -> String {
221
255
switch self {
222
256
case . servers:
223
- return " Whether server code is generated. Defaults to true. "
257
+ return " Indicate that server code is to be generated. Generated by default. "
258
+ case . noServers:
259
+ return " Indicate that server code is not to be generated. Generated by default. "
224
260
case . clients:
225
- return " Whether client code is generated. Defaults to true. "
261
+ return " Indicate that client code is to be generated. Generated by default. "
262
+ case . noClients:
263
+ return " Indicate that client code is not to be generated. Generated by default. "
226
264
case . messages:
227
- return " Whether message code is generated. Defaults to true. "
265
+ return " Indicate that message code is to be generated. Generated by default. "
266
+ case . noMessages:
267
+ return " Indicate that message code is not to be generated. Generated by default. "
228
268
case . fileNaming:
229
269
return
230
270
" The naming scheme for output files [fullPath/pathToUnderscores/dropPath]. Defaults to fullPath. "
@@ -236,27 +276,36 @@ extension Flag {
236
276
case . importPath:
237
277
return " The directory in which to search for imports. "
238
278
case . protocPath:
239
- return " The path to the ` protoc` binary. "
279
+ return " The path to the protoc binary. "
240
280
case . dryRun:
241
281
return " Print but do not execute the protoc commands. "
242
282
case . output:
243
283
return " The path into which the generated source files are created. "
284
+ case . verbose:
285
+ return " Emit verbose output. "
244
286
case . help:
245
287
return " Print this help. "
246
288
}
247
289
}
248
290
249
- static func printHelp( ) {
250
- print ( " Usage: swift package generate-grpc-code-from-protos [flags] [input files] " )
251
- print ( " " )
252
- print ( " Flags: " )
253
- print ( " " )
291
+ static func printHelp( requested: Bool ) {
292
+ let printMessage : ( String ) -> Void
293
+ if requested {
294
+ printMessage = { message in print ( message) }
295
+ } else {
296
+ printMessage = Stderr . print
297
+ }
298
+
299
+ printMessage ( " Usage: swift package generate-grpc-code-from-protos [flags] [input files] " )
300
+ printMessage ( " " )
301
+ printMessage ( " Flags: " )
302
+ printMessage ( " " )
254
303
255
304
let spacing = 3
256
305
let maxLength =
257
- ( Flag . allCases. map ( \. rawValue) . max ( by: { $0. count < $1. count } ) ? . count ?? 0 ) + spacing
258
- for flag in Flag . allCases {
259
- print (
306
+ ( OptionsAndFlags . allCases. map ( \. rawValue) . max ( by: { $0. count < $1. count } ) ? . count ?? 0 ) + spacing
307
+ for flag in OptionsAndFlags . allCases {
308
+ printMessage (
260
309
" -- \( flag. rawValue. padding ( toLength: maxLength, withPad: " " , startingAt: 0 ) ) \( flag. usageDescription ( ) ) "
261
310
)
262
311
}
0 commit comments