@@ -189,13 +189,14 @@ def initialize(env, binary_path, global_opts, logger)
189189 #
190190 # @raise [Git::TimeoutError] if the command times out
191191 #
192- def run ( *args , out :, err :, normalize :, chomp :, merge :, chdir : nil , timeout : nil )
192+ def run ( *args , out : nil , err : nil , normalize :, chomp :, merge :, chdir : nil , timeout : nil )
193193 git_cmd = build_git_cmd ( args )
194- out ||= StringIO . new
195- err ||= ( merge ? out : StringIO . new )
196- status = execute ( git_cmd , out , err , chdir : ( chdir || :not_set ) , timeout : timeout )
197-
198- process_result ( git_cmd , status , out , err , normalize , chomp , timeout )
194+ begin
195+ result = ProcessExecuter . run ( env , *git_cmd , out : out , err : err , merge :, chdir : ( chdir || :not_set ) , timeout : timeout , raise_errors : false )
196+ rescue ProcessExecuter ::Command ::ProcessIOError => e
197+ raise Git ::ProcessIOError . new ( e . message ) , cause : e . exception . cause
198+ end
199+ process_result ( result , normalize , chomp , timeout )
199200 end
200201
201202 private
@@ -210,121 +211,12 @@ def build_git_cmd(args)
210211 [ binary_path , *global_opts , *args ] . map { |e | e . to_s }
211212 end
212213
213- # Determine the output to return in the `CommandLineResult`
214- #
215- # If the writer can return the output by calling `#string` (such as a StringIO),
216- # then return the result of normalizing the encoding and chomping the output
217- # as requested.
218- #
219- # If the writer does not support `#string`, then return nil. The output is
220- # assumed to be collected by the writer itself such as when the writer
221- # is a file instead of a StringIO.
222- #
223- # @param writer [#string] the writer to post-process
224- #
225- # @return [String, nil]
226- #
227- # @api private
228- #
229- def post_process ( writer , normalize , chomp )
230- if writer . respond_to? ( :string )
231- output = writer . string . dup
232- output = output . lines . map { |l | Git ::EncodingUtils . normalize_encoding ( l ) } . join if normalize
233- output . chomp! if chomp
234- output
235- else
236- nil
237- end
238- end
239-
240- # Post-process all writers and return an array of the results
241- #
242- # @param writers [Array<#write>] the writers to post-process
243- # @param normalize [Boolean] whether to normalize the output of each writer
244- # @param chomp [Boolean] whether to chomp the output of each writer
245- #
246- # @return [Array<String, nil>] the output of each writer that supports `#string`
247- #
248- # @api private
249- #
250- def post_process_all ( writers , normalize , chomp )
251- Array . new . tap do |result |
252- writers . each { |writer | result << post_process ( writer , normalize , chomp ) }
253- end
254- end
255-
256- # Raise an error when there was exception while collecting the subprocess output
257- #
258- # @param git_cmd [Array<String>] the git command that was executed
259- # @param pipe_name [Symbol] the name of the pipe that raised the exception
260- # @param pipe [ProcessExecuter::MonitoredPipe] the pipe that raised the exception
261- #
262- # @raise [Git::ProcessIOError]
263- #
264- # @return [void] this method always raises an error
265- #
266- # @api private
267- #
268- def raise_pipe_error ( git_cmd , pipe_name , pipe )
269- raise Git ::ProcessIOError . new ( "Pipe Exception for #{ git_cmd } : #{ pipe_name } " ) , cause : pipe . exception
270- end
271-
272- # Execute the git command and collect the output
273- #
274- # @param cmd [Array<String>] the git command to execute
275- # @param chdir [String] the directory to run the command in
276- # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
277- #
278- # If timeout is zero of nil, the command will not time out. If the command
279- # times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
280- #
281- # If the command does not respond to SIGKILL, it will hang this method.
282- #
283- # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
284- # @raise [Git::TimeoutError] if the command times out
285- #
286- # @return [ProcessExecuter::Status] the status of the completed subprocess
287- #
288- # @api private
289- #
290- def spawn ( cmd , out_writers , err_writers , chdir :, timeout :)
291- out_pipe = ProcessExecuter ::MonitoredPipe . new ( *out_writers , chunk_size : 10_000 )
292- err_pipe = ProcessExecuter ::MonitoredPipe . new ( *err_writers , chunk_size : 10_000 )
293- ProcessExecuter . spawn ( env , *cmd , out : out_pipe , err : err_pipe , chdir : chdir , timeout : timeout )
294- ensure
295- out_pipe . close
296- err_pipe . close
297- raise_pipe_error ( cmd , :stdout , out_pipe ) if out_pipe . exception
298- raise_pipe_error ( cmd , :stderr , err_pipe ) if err_pipe . exception
299- end
300-
301- # The writers that will be used to collect stdout and stderr
302- #
303- # Additional writers could be added here if you wanted to tee output
304- # or send output to the terminal.
305- #
306- # @param out [#write] the object to write stdout to
307- # @param err [#write] the object to write stderr to
308- #
309- # @return [Array<Array<#write>, Array<#write>>] the writers for stdout and stderr
310- #
311- # @api private
312- #
313- def writers ( out , err )
314- out_writers = [ out ]
315- err_writers = [ err ]
316- [ out_writers , err_writers ]
317- end
318-
319214 # Process the result of the command and return a Git::CommandLineResult
320215 #
321216 # Post process output, log the command and result, and raise an error if the
322217 # command failed.
323218 #
324- # @param git_cmd [Array<String>] the git command that was executed
325- # @param status [Process::Status] the status of the completed subprocess
326- # @param out [#write] the object that stdout was written to
327- # @param err [#write] the object that stderr was written to
219+ # @param result [ProcessExecuter::Command::Result] the result it is a Process::Status and include command, stdout, and stderr
328220 # @param normalize [Boolean] whether to normalize the output of each writer
329221 # @param chomp [Boolean] whether to chomp the output of each writer
330222 # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
@@ -338,40 +230,58 @@ def writers(out, err)
338230 #
339231 # @api private
340232 #
341- def process_result ( git_cmd , status , out , err , normalize , chomp , timeout )
342- out_str , err_str = post_process_all ( [ out , err ] , normalize , chomp )
343- logger . info { "#{ git_cmd } exited with status #{ status } " }
344- logger . debug { "stdout:\n #{ out_str . inspect } \n stderr:\n #{ err_str . inspect } " }
345- Git ::CommandLineResult . new ( git_cmd , status , out_str , err_str ) . tap do |result |
346- raise Git ::TimeoutError . new ( result , timeout ) if status . timeout?
347- raise Git ::SignaledError . new ( result ) if status . signaled?
348- raise Git ::FailedError . new ( result ) unless status . success?
233+ def process_result ( result , normalize , chomp , timeout )
234+ command = result . command
235+ processed_out , processed_err = post_process_all ( [ result . stdout , result . stderr ] , normalize , chomp )
236+ logger . info { "#{ command } exited with status #{ result } " }
237+ logger . debug { "stdout:\n #{ processed_out . inspect } \n stderr:\n #{ processed_err . inspect } " }
238+ Git ::CommandLineResult . new ( command , result , processed_out , processed_err ) . tap do |processed_result |
239+ raise Git ::TimeoutError . new ( processed_result , timeout ) if result . timeout?
240+ raise Git ::SignaledError . new ( processed_result ) if result . signaled?
241+ raise Git ::FailedError . new ( processed_result ) unless result . success?
349242 end
350243 end
351244
352- # Execute the git command and write the command output to out and err
245+ # Post-process command output and return an array of the results
353246 #
354- # @param git_cmd [Array<String>] the git command to execute
355- # @param out [#write] the object to write stdout to
356- # @param err [#write] the object to write stderr to
357- # @param chdir [String] the directory to run the command in
358- # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
247+ # @param raw_outputs [Array] the output to post-process
248+ # @param normalize [Boolean] whether to normalize the output of each writer
249+ # @param chomp [Boolean] whether to chomp the output of each writer
359250 #
360- # If timeout is zero of nil, the command will not time out. If the command
361- # times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
251+ # @return [Array<String, nil>] the processed output of each command output object that supports `#string`
362252 #
363- # If the command does not respond to SIGKILL, it will hang this method.
253+ # @api private
364254 #
365- # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
366- # @raise [Git::TimeoutError] if the command times out
255+ def post_process_all ( raw_outputs , normalize , chomp )
256+ Array . new . tap do |result |
257+ raw_outputs . each { |raw_output | result << post_process ( raw_output , normalize , chomp ) }
258+ end
259+ end
260+
261+ # Determine the output to return in the `CommandLineResult`
367262 #
368- # @return [Git::CommandLineResult] the result of the command to return to the caller
263+ # If the writer can return the output by calling `#string` (such as a StringIO),
264+ # then return the result of normalizing the encoding and chomping the output
265+ # as requested.
266+ #
267+ # If the writer does not support `#string`, then return nil. The output is
268+ # assumed to be collected by the writer itself such as when the writer
269+ # is a file instead of a StringIO.
270+ #
271+ # @param raw_output [#string] the output to post-process
272+ # @return [String, nil]
369273 #
370274 # @api private
371275 #
372- def execute ( git_cmd , out , err , chdir :, timeout :)
373- out_writers , err_writers = writers ( out , err )
374- spawn ( git_cmd , out_writers , err_writers , chdir : chdir , timeout : timeout )
276+ def post_process ( raw_output , normalize , chomp )
277+ if raw_output . respond_to? ( :string )
278+ output = raw_output . string . dup
279+ output = output . lines . map { |l | Git ::EncodingUtils . normalize_encoding ( l ) } . join if normalize
280+ output . chomp! if chomp
281+ output
282+ else
283+ nil
284+ end
375285 end
376286 end
377287end
0 commit comments