@@ -52,28 +52,26 @@ struct GRPCProtobufGeneratorCommandPlugin {
52
52
tool: ( String ) throws -> PluginContext . Tool ,
53
53
pluginWorkDirectoryURL: URL
54
54
) throws {
55
- let groups = arguments. split ( separator: " -- " )
56
55
let flagsAndOptions : [ String ]
57
56
let inputFiles : [ String ]
58
- switch groups. count {
59
- case 0 :
60
- OptionsAndFlags . printHelp ( requested: false )
61
- return
62
-
63
- case 1 :
64
- inputFiles = Array ( groups [ 0 ] )
65
- flagsAndOptions = [ ]
66
57
67
- var argExtractor = ArgumentExtractor ( inputFiles)
58
+ let separatorCount = arguments. filter { $0 == CommandConfig . parameterGroupSeparator } . count
59
+ switch separatorCount {
60
+ case 0 :
61
+ var argExtractor = ArgumentExtractor ( arguments)
68
62
// check if help requested
69
63
if argExtractor. extractFlag ( named: OptionsAndFlags . help. rawValue) > 0 {
70
64
OptionsAndFlags . printHelp ( requested: true )
71
65
return
72
66
}
73
67
74
- case 2 :
75
- flagsAndOptions = Array ( groups [ 0 ] )
76
- inputFiles = Array ( groups [ 1 ] )
68
+ inputFiles = arguments
69
+ flagsAndOptions = [ ]
70
+
71
+ case 1 :
72
+ let splitIndex = arguments. firstIndex ( of: CommandConfig . parameterGroupSeparator) !
73
+ flagsAndOptions = Array ( arguments [ ..< splitIndex] )
74
+ inputFiles = Array ( arguments [ ( splitIndex) . advanced ( by: 1 ) ... ] )
77
75
78
76
default :
79
77
throw CommandPluginError . tooManyParameterSeparators
@@ -126,21 +124,15 @@ struct GRPCProtobufGeneratorCommandPlugin {
126
124
outputDirectory: outputDirectory
127
125
)
128
126
129
- if commandConfig. verbose || commandConfig. dryRun {
130
- printProtocInvocation ( protocPath, arguments)
131
- }
127
+ try executeProtocInvocation (
128
+ executableURL: protocPath,
129
+ arguments: arguments,
130
+ verbose: commandConfig. verbose,
131
+ dryRun: commandConfig. dryRun
132
+ )
133
+
132
134
if !commandConfig. dryRun {
133
- let process = try Process . run ( protocPath, arguments: arguments)
134
- process. waitUntilExit ( )
135
-
136
- if process. terminationReason == . exit, process. terminationStatus == 0 {
137
- if commandConfig. verbose {
138
- Stderr . print ( " Generated gRPC Swift files for \( inputFiles. joined ( separator: " , " ) ) . " )
139
- }
140
- } else {
141
- let problem = " \( process. terminationReason) : \( process. terminationStatus) "
142
- throw CommandPluginError . generationFailure
143
- }
135
+ Stderr . print ( " Generated gRPC Swift files for \( inputFiles. joined ( separator: " , " ) ) . " )
144
136
}
145
137
}
146
138
@@ -155,31 +147,102 @@ struct GRPCProtobufGeneratorCommandPlugin {
155
147
outputDirectory: outputDirectory
156
148
)
157
149
158
- if commandConfig. verbose || commandConfig. dryRun {
159
- printProtocInvocation ( protocPath, arguments)
160
- }
150
+ let completionStatus = try executeProtocInvocation (
151
+ executableURL: protocPath,
152
+ arguments: arguments,
153
+ verbose: commandConfig. verbose,
154
+ dryRun: commandConfig. dryRun
155
+ )
156
+
161
157
if !commandConfig. dryRun {
162
- let process = try Process . run ( protocPath, arguments: arguments)
163
- process. waitUntilExit ( )
164
-
165
- if process. terminationReason == . exit, process. terminationStatus == 0 {
166
- Stderr . print (
167
- " Generated protobuf message Swift files for \( inputFiles. joined ( separator: " , " ) ) . "
168
- )
169
- } else {
170
- let problem = " \( process. terminationReason) : \( process. terminationStatus) "
171
- throw CommandPluginError . generationFailure
172
- }
158
+ Stderr . print (
159
+ " Generated protobuf message Swift files for \( inputFiles. joined ( separator: " , " ) ) . "
160
+ )
173
161
}
174
162
}
175
163
}
176
164
}
177
165
178
- /// Print a single invocation of `protoc`
166
+ /// Execute a single invocation of `protoc`, printing output and if in verbose mode the invocation
179
167
/// - Parameters:
180
168
/// - executableURL: The path to the `protoc` executable.
181
169
/// - arguments: The arguments to be passed to `protoc`.
182
- func printProtocInvocation( _ executableURL: URL , _ arguments: [ String ] ) {
183
- Stderr . print ( " \( executableURL. absoluteStringNoScheme) \\ " )
184
- Stderr . print ( " \( arguments. joined ( separator: " \\ \n " ) ) " )
170
+ /// - verbose: Whether or not to print verbose output
171
+ /// - dryRun: If this invocation is a dry-run, i.e. will not actually be executed
172
+
173
+ func executeProtocInvocation(
174
+ executableURL: URL ,
175
+ arguments: [ String ] ,
176
+ verbose: Bool ,
177
+ dryRun: Bool
178
+ ) throws {
179
+ if verbose {
180
+ Stderr . print ( " \( executableURL. absoluteStringNoScheme) \\ " )
181
+ Stderr . print ( " \( arguments. joined ( separator: " \\ \n " ) ) " )
182
+ }
183
+
184
+ if dryRun {
185
+ return
186
+ }
187
+
188
+ let process = Process ( )
189
+ process. executableURL = executableURL
190
+ process. arguments = arguments
191
+
192
+ let outputPipe = Pipe ( )
193
+ let errorPipe = Pipe ( )
194
+ process. standardOutput = outputPipe
195
+ process. standardError = errorPipe
196
+
197
+ do {
198
+ try process. run ( )
199
+ } catch {
200
+ try printProtocOutput ( outputPipe, verbose: verbose)
201
+ let stdErr : String ?
202
+ if let errorData = try errorPipe. fileHandleForReading. readToEnd ( ) {
203
+ stdErr = String ( decoding: errorData, as: UTF8 . self)
204
+ } else {
205
+ stdErr = nil
206
+ }
207
+ throw CommandPluginError . generationFailure (
208
+ errorDescription: " \( error) " ,
209
+ executable: executableURL. absoluteStringNoScheme,
210
+ arguments: arguments,
211
+ stdErr: stdErr
212
+ )
213
+ }
214
+ process. waitUntilExit ( )
215
+
216
+ try printProtocOutput ( outputPipe, verbose: verbose)
217
+
218
+ guard process. terminationReason == . exit && process. terminationStatus == 0 else {
219
+ let stdErr : String ?
220
+ if let errorData = try errorPipe. fileHandleForReading. readToEnd ( ) {
221
+ stdErr = String ( decoding: errorData, as: UTF8 . self)
222
+ } else {
223
+ stdErr = nil
224
+ }
225
+ let problem = " \( process. terminationReason) : \( process. terminationStatus) "
226
+ throw CommandPluginError . generationFailure (
227
+ errorDescription: problem,
228
+ executable: executableURL. absoluteStringNoScheme,
229
+ arguments: arguments,
230
+ stdErr: stdErr
231
+ )
232
+ }
233
+
234
+ return
235
+ }
236
+
237
+ func printProtocOutput( _ stdOut: Pipe , verbose: Bool ) throws {
238
+ let prefix = " \t "
239
+
240
+ if verbose, let outputData = try stdOut. fileHandleForReading. readToEnd ( ) {
241
+ let output = String ( decoding: outputData, as: UTF8 . self)
242
+ let lines = output. split { $0. isNewline }
243
+ print ( " protoc output: " )
244
+ for line in lines {
245
+ print ( " \( prefix) \( line) " )
246
+ }
247
+ }
185
248
}
0 commit comments