diff --git a/lib/sprout/executable/session.rb b/lib/sprout/executable/session.rb index f6ccc2da..05a3025f 100644 --- a/lib/sprout/executable/session.rb +++ b/lib/sprout/executable/session.rb @@ -146,6 +146,10 @@ def accessor_can_be_defined_at name # via stdin, stdout and stderr. attr_reader :process_runner + ## + # The Thread that contains the forked running process. + attr_reader :process_thread + ## # @return [Array] Return or create a new array. def action_stack @@ -207,9 +211,10 @@ def wait # can be submitted, or user input can be # collected. def wait_for_prompt - while !prompted? + while process_thread.alive? && !prompted? sleep 0.2 end + process_thread.alive? end ## @@ -219,15 +224,12 @@ def wait_for_prompt def handle_user_input while true begin - wait_for_prompt + break if !wait_for_prompt input = $stdin.gets.chomp! + execute_action(input, true) rescue SignalException => e return false end - execute_action(input, true) - - # TODO: Figure out if you should CONTINUE - # or NOT.... end wait end @@ -277,10 +279,11 @@ def system_execute binary, params # Thanks to https://github.com/apinstein for this # solution. #params = "#{params} " + '2>&1' - Sprout.current_system.execute_thread binary, params, prompt do |message| + @process_thread = Sprout.current_system.execute_thread binary, params, prompt do |message| Sprout.stdout.printf message @prompted = true end + @process_runner = process_thread['runner'] end private @@ -297,11 +300,12 @@ def execute_actions ## # Execute a single action. def execute_action action, silence=false - wait_for_prompt - action = action.strip - stdout.puts(action) unless silence - @prompted = false - process_runner.puts action + if wait_for_prompt + action = action.strip + stdout.puts(action) unless silence + @prompted = false + process_runner.puts action + end end end diff --git a/lib/sprout/system/base_system.rb b/lib/sprout/system/base_system.rb index 60c7b6de..5d62199c 100644 --- a/lib/sprout/system/base_system.rb +++ b/lib/sprout/system/base_system.rb @@ -105,23 +105,23 @@ def execute_silent(tool, options='') # @yield [String] Message that was received from the process, called when #prompt is encountered. # def execute_thread tool, options='', prompt=nil, &block - runner = nil - Thread.new do + t = Thread.new do Thread.current.abort_on_exception = true runner = execute_silent(tool, options) + Thread.current['runner'] = runner + out = read_from runner.r, prompt, &block + err = read_from runner.e, prompt, &block + out.join && err.kill end # Wait for the runner to be created # before returning a nil reference # that never gets populated... - while runner.nil? do + while t['runner'].nil? do sleep(0.1) end - read_from runner.r, prompt, &block - read_from runner.e, prompt, &block - - runner + t end def read_from pipe, prompt, &block @@ -129,13 +129,14 @@ def read_from pipe, prompt, &block Thread.current.abort_on_exception = true lines = '' line = '' + pipe.sync = true pipe.each_char do |char| - line << char break if pipe.closed? + line << char if line.match prompt + yield line if block_given? lines << line - yield lines if block_given? lines = '' line = '' next @@ -143,18 +144,13 @@ def read_from pipe, prompt, &block if char == "\n" lines << line + yield line if block_given? line = '' end end - - should_continue_reading? line, pipe end end - def should_continue_reading? line, pipe - return !(line == '' && pipe.eof?) - end - ## # Clean the provided +path+ String for the current # operating system. diff --git a/test/unit/executable_session_test.rb b/test/unit/executable_session_test.rb index 10225bfe..50c6d518 100644 --- a/test/unit/executable_session_test.rb +++ b/test/unit/executable_session_test.rb @@ -26,10 +26,11 @@ class ExecutableSessionTest < Test::Unit::TestCase @fdb.wait_for_prompt @fdb.break "AsUnitRunner:12" - @fdb.handle_user_input #@fdb.continue #@fdb.continue + + @fdb.handle_user_input #@fdb.quit end