SvnRunner.run_svn should be a class method

This commit is contained in:
Josh Holtrop 2018-02-12 21:22:26 -05:00
parent 50529580c0
commit 94c38ade8f

View File

@ -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<String>]
# The svn subcommand arguments.
# @param options [Hash]
# Optional arguments.
# @option options [Array<String>] :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<String>]
# The svn subcommand arguments.
# @param options [Hash]
# Optional arguments.
# @option options [Array<String>] :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