@@ -20,6 +20,7 @@ import PackagePlugin
2020struct CommandConfig {
2121 var common : GenerationConfig
2222
23+ var verbose : Bool
2324 var dryRun : Bool
2425
2526 static let defaults = Self (
@@ -33,97 +34,103 @@ struct CommandConfig {
3334 importPaths: [ ] ,
3435 outputPath: " "
3536 ) ,
37+ verbose: false ,
3638 dryRun: false
3739 )
3840}
3941
4042extension 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+
4150 static func parse(
42- arguments : [ String ] ,
51+ argumentExtractor argExtractor : inout ArgumentExtractor ,
4352 pluginWorkDirectory: URL
4453 ) throws -> ( CommandConfig , [ String ] ) {
4554 var config = CommandConfig . defaults
4655
47- var argExtractor = ArgumentExtractor ( arguments)
48-
49- for flag in Flag . allCases {
56+ for flag in OptionsAndFlags . allCases {
5057 switch flag {
5158 case . accessLevel:
5259 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
6363 }
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) " )
7066 }
71- config. common. servers = servers
7267 }
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
8075 }
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
8891 }
92+
8993 case . fileNaming:
9094 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) " )
101101 }
102102 }
103+
103104 case . accessLevelOnImports:
104105 let accessLevelOnImports = argExtractor. extractOption ( named: flag. rawValue)
105- if let value = accessLevelOnImports. first {
106+ if let value = extractSingleValue ( flag , values : accessLevelOnImports) {
106107 guard let accessLevelOnImports = Bool ( value) else {
107- throw CommandPluginError . invalidArgumentValue ( value)
108+ throw CommandPluginError . invalidArgumentValue ( name : flag . rawValue , value : value)
108109 }
109110 config. common. accessLevelOnImports = accessLevelOnImports
110111 }
112+
111113 case . importPath:
112114 config. common. importPaths = argExtractor. extractOption ( named: flag. rawValue)
115+
113116 case . protocPath:
114117 let protocPath = argExtractor. extractOption ( named: flag. rawValue)
115- config. common. protocPath = protocPath. first
118+ config. common. protocPath = extractSingleValue ( flag, values: protocPath)
119+
116120 case . output:
117121 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+
119128 case . dryRun:
120129 let dryRun = argExtractor. extractFlag ( named: flag. rawValue)
121130 config. dryRun = dryRun != 0
131+
122132 case . help:
123- let help = argExtractor. extractFlag ( named: flag. rawValue)
124- if help != 0 {
125- throw CommandPluginError . helpRequested
126- }
133+ ( ) // handled elsewhere
127134 }
128135 }
129136
@@ -141,19 +148,30 @@ extension CommandConfig {
141148 }
142149}
143150
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+
144158/// All valid input options/flags
145- enum Flag : CaseIterable , RawRepresentable {
159+ enum OptionsAndFlags : CaseIterable , RawRepresentable {
146160 typealias RawValue = String
147161
148162 case servers
163+ case noServers
149164 case clients
165+ case noClients
150166 case messages
167+ case noMessages
151168 case fileNaming
152169 case accessLevel
153170 case accessLevelOnImports
154171 case importPath
155172 case protocPath
156173 case output
174+ case verbose
157175 case dryRun
158176
159177 case help
@@ -162,22 +180,30 @@ enum Flag: CaseIterable, RawRepresentable {
162180 switch rawValue {
163181 case " servers " :
164182 self = . servers
183+ case " no-servers " :
184+ self = . noServers
165185 case " clients " :
166186 self = . clients
187+ case " no-clients " :
188+ self = . noClients
167189 case " messages " :
168190 self = . messages
191+ case " no-messages " :
192+ self = . noMessages
169193 case " file-naming " :
170194 self = . fileNaming
171195 case " access-level " :
172196 self = . accessLevel
173- case " use- access-level-on-imports" :
197+ case " access-level-on-imports " :
174198 self = . accessLevelOnImports
175199 case " import-path " :
176200 self = . importPath
177201 case " protoc-path " :
178202 self = . protocPath
179203 case " output " :
180204 self = . output
205+ case " verbose " :
206+ self = . verbose
181207 case " dry-run " :
182208 self = . dryRun
183209 case " help " :
@@ -192,10 +218,16 @@ enum Flag: CaseIterable, RawRepresentable {
192218 switch self {
193219 case . servers:
194220 " servers "
221+ case . noServers:
222+ " no-servers "
195223 case . clients:
196224 " clients "
225+ case . noClients:
226+ " no-clients "
197227 case . messages:
198228 " messages "
229+ case . noMessages:
230+ " no-messages "
199231 case . fileNaming:
200232 " file-naming "
201233 case . accessLevel:
@@ -208,6 +240,8 @@ enum Flag: CaseIterable, RawRepresentable {
208240 " protoc-path "
209241 case . output:
210242 " output "
243+ case . verbose:
244+ " verbose "
211245 case . dryRun:
212246 " dry-run "
213247 case . help:
@@ -216,15 +250,21 @@ enum Flag: CaseIterable, RawRepresentable {
216250 }
217251}
218252
219- extension Flag {
253+ extension OptionsAndFlags {
220254 func usageDescription( ) -> String {
221255 switch self {
222256 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. "
224260 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. "
226264 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. "
228268 case . fileNaming:
229269 return
230270 " The naming scheme for output files [fullPath/pathToUnderscores/dropPath]. Defaults to fullPath. "
@@ -236,27 +276,36 @@ extension Flag {
236276 case . importPath:
237277 return " The directory in which to search for imports. "
238278 case . protocPath:
239- return " The path to the ` protoc` binary. "
279+ return " The path to the protoc binary. "
240280 case . dryRun:
241281 return " Print but do not execute the protoc commands. "
242282 case . output:
243283 return " The path into which the generated source files are created. "
284+ case . verbose:
285+ return " Emit verbose output. "
244286 case . help:
245287 return " Print this help. "
246288 }
247289 }
248290
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 ( " " )
254303
255304 let spacing = 3
256305 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 (
260309 " -- \( flag. rawValue. padding ( toLength: maxLength, withPad: " " , startingAt: 0 ) ) \( flag. usageDescription ( ) ) "
261310 )
262311 }
0 commit comments