diff --git a/lib/svi/svn_runner.rb b/lib/svi/svn_runner.rb index 156ea99..058cd88 100644 --- a/lib/svi/svn_runner.rb +++ b/lib/svi/svn_runner.rb @@ -4,87 +4,91 @@ module Svi # Exception class to indicate an error with executing svn. class SvnExecError < RuntimeError; end - # Run Subversion and yield results linewise. - # - # @param subcommand [String, nil] - # The svn subcommand to execute (e.g. "ls"). - # @param args [Array] - # The svn subcommand arguments. - # @param options [Hash] - # Optional arguments. - # @option options [Array] :global_args - # Global svn arguments to place before the subcommand. - # - # @yield [line] - # If a block is given, each line that the Subversion command writes to - # standard output will be yielded to the calling block. - # @yieldparam line [String] - # Line of standard output. - # @return [String] - # The standard output from svn. - # @raise [SvnExecError] - # If the svn command errors out this exception is raised. - def run_svn(subcommand, args, options = {}, &block) - command = [ - "svn", - *(options[:global_args] || []), - subcommand, - *args, - ].compact + class << self - # Create pipes for standard output and standard error. - stdout_rd, stdout_wr = IO.pipe - stderr_rd, stderr_wr = IO.pipe + # Run Subversion and yield results linewise. + # + # @param subcommand [String, nil] + # The svn subcommand to execute (e.g. "ls"). + # @param args [Array] + # The svn subcommand arguments. + # @param options [Hash] + # Optional arguments. + # @option options [Array] :global_args + # Global svn arguments to place before the subcommand. + # + # @yield [line] + # If a block is given, each line that the Subversion command writes to + # standard output will be yielded to the calling block. + # @yieldparam line [String] + # Line of standard output. + # @return [String] + # The standard output from svn. + # @raise [SvnExecError] + # If the svn command errors out this exception is raised. + def run_svn(subcommand, args, options = {}, &block) + command = [ + "svn", + *(options[:global_args] || []), + subcommand, + *args, + ].compact - # Launch the svn subprocess using the pipes. - spawn_options = { - out: stdout_wr, - err: stderr_wr, - close_others: true, - } - spawn_options[:in] = :close unless options[:allow_interactive] - svn_pid = Process.spawn(*command, spawn_options) + # Create pipes for standard output and standard error. + stdout_rd, stdout_wr = IO.pipe + stderr_rd, stderr_wr = IO.pipe - # Close write side of the pipes in the parent process. - stdout_wr.close - stderr_wr.close + # Launch the svn subprocess using the pipes. + spawn_options = { + out: stdout_wr, + err: stderr_wr, + close_others: true, + } + spawn_options[:in] = :close unless options[:allow_interactive] + svn_pid = Process.spawn(*command, spawn_options) - stdout = "" - stderr = "" - stdout_yield = "" + # Close write side of the pipes in the parent process. + stdout_wr.close + stderr_wr.close - loop do - so = stdout_rd.read_nonblock(exception: false) - if so.is_a?(String) - stdout += so - stdout_yield += so - end - se = stderr_rd.read_nonblock(exception: false) - if se.is_a?(String) - stderr += se - end - if so.nil? and se.nil? - break - end - if block - loop do - index = stdout_yield.index("\n") - break unless index - line = stdout_yield[0, index] - block[line] - stdout_yield = stdout_yield[index + 1, stdout_yield.size] + stdout = "" + stderr = "" + stdout_yield = "" + + loop do + so = stdout_rd.read_nonblock(100000, exception: false) + if so.is_a?(String) + stdout += so + stdout_yield += so end + se = stderr_rd.read_nonblock(100000, exception: false) + if se.is_a?(String) + stderr += se + end + if so.nil? and se.nil? + break + end + if block + loop do + index = stdout_yield.index("\n") + break unless index + line = stdout_yield[0, index] + block[line] + stdout_yield = stdout_yield[index + 1, stdout_yield.size] + end + end + IO.select([stdout_rd, stderr_rd]) end - IO.select([stdout_rd, stderr_rd]) + + Process.waitpid(svn_pid) + + if stderr != "" + raise SvnExecError.new(stderr) + end + + stdout end - Process.waitpid(svn_pid) - - if stderr != "" - raise SvnExecError.new(stderr) - end - - stdout end end