Skip to content

Commit

Permalink
Switched back from open4 to IO.popen.
Browse files Browse the repository at this point in the history
open4 was added as a dependency when I was trying to parse STDERR and needed to work with STDIN. As it turns out, $stdin is good enough.  Redirecting STDERR to STDOUT seems to be good enough as well.  While open4 is probably still a cleaner approach, its reliance on fork() means it doesn't work on non-JRuby in Windows (echnically it doesn't work in JRuby either, but JRuby has an IO.popen4 special method that does virtually the same thing and we were using that instead).
  • Loading branch information
nirvdrum committed Jun 8, 2014
1 parent d3570dc commit d19b9c8
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 35 deletions.
1 change: 0 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ begin
spec.email = "nirvdrum@gmail.com"
spec.license = 'MIT'
spec.add_development_dependency 'minitest'
spec.add_dependency 'open4'
end
Jeweler::GemcutterTasks.new

Expand Down
45 changes: 11 additions & 34 deletions lib/svn2git/migration.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require 'optparse'
require 'pp'
require 'open4'
require 'timeout'

module Svn2Git
Expand Down Expand Up @@ -374,7 +373,6 @@ def run_command(cmd, exit_on_error=true, printout_output=false)
log "Running command: #{cmd}\n"

ret = ''
@mutex ||= Mutex.new
@stdin_queue ||= Queue.new

# We need to fetch input from the user to pass through to the underlying sub-process. We'll constantly listen
Expand All @@ -386,44 +384,28 @@ def run_command(cmd, exit_on_error=true, printout_output=false)

# Open4 forks, which JRuby doesn't support. But JRuby added a popen4-compatible method on the IO class,
# so we can use that instead.
status = (defined?(JRUBY_VERSION) ? IO : Open4).popen4(cmd) do |pid, stdin, stdout, stderr|
IO.popen("2>&1 #{cmd}") do |output|
threads = []

threads << Thread.new(stdout) do |stdout|
stdout.each do |line|
@mutex.synchronize do
ret << line

if printout_output
$stdout.print line
else
log line
end
end
end
end

threads << Thread.new(stderr) do |stderr|
threads << Thread.new(output) do |output|
# git-svn seems to do all of its prompting for user input via STDERR. When it prompts for input, it will
# not terminate the line with a newline character, so we can't split the input up by newline. It will,
# however, use a space to separate the user input from the prompt. So we split on word boundaries here
# while draining STDERR.
stderr.each(' ') do |word|
@mutex.synchronize do
ret << word

if printout_output
$stdout.print word
else
log word
end
output.each(' ') do |word|
ret << word

if printout_output
$stdout.print word
else
log word
end
end
end

# Simple pass-through thread to take anything the user types via STDIN and passes it through to the
# sub-process's stdin pipe.
Thread.new(stdin) do |stdin|
Thread.new do
loop do
user_reply = @stdin_queue.pop

Expand All @@ -441,12 +423,7 @@ def run_command(cmd, exit_on_error=true, printout_output=false)
@stdin_queue << nil
end

# JRuby's open4 doesn't return a Process::Status object when invoked with a block, but rather returns the
# block expression's value. The Process::Status is stored as $?, so we need to normalize the status
# object if on JRuby.
status = $? if defined?(JRUBY_VERSION)

if exit_on_error && (status.exitstatus != 0)
if exit_on_error && $?.exitstatus != 0
$stderr.puts "command failed:\n#{cmd}"
exit -1
end
Expand Down

0 comments on commit d19b9c8

Please sign in to comment.