Skip to content

Commit

Permalink
Refactor Runner avilability checking
Browse files Browse the repository at this point in the history
* Allows tests to run on JRuby
* Adds a query method to know if the Runner is available
* Uses the query method to determind best_runner
* Puts query method on class because it's not instance's responsibility
  • Loading branch information
Jon Yurek committed Aug 30, 2013
1 parent 4aaf834 commit 20670a4
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 95 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
rvm:
- 1.9.2
- 1.9.3
- 2.0.0
- jruby-19mode

matrix:
allow_failures:
- rvm: jruby-19mode
- rvm: rbx-19mode
19 changes: 7 additions & 12 deletions lib/cocaine/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ def path=(supplemental_path)
@supplemental_environment['PATH'] = (Array(supplemental_path) + [ENV['PATH']]).join(File::PATH_SEPARATOR)
end

def posix_spawn_available?
@posix_spawn_available ||= begin
require 'posix/spawn'
true
rescue LoadError => e
false
end
end

def environment
@supplemental_environment ||= {}
end
Expand All @@ -40,12 +31,16 @@ def unfake!
@runner = nil
end

def java?
RUBY_PLATFORM =~ /java/
end

private

def best_runner
return PosixRunner.new if posix_spawn_available?
return ProcessRunner.new if Process.respond_to?(:spawn)
BackticksRunner.new
[PosixRunner, ProcessRunner, BackticksRunner].detect do |runner|
runner.supported?
end.new
end
end

Expand Down
7 changes: 7 additions & 0 deletions lib/cocaine/command_line/runners/backticks_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
module Cocaine
class CommandLine
class BackticksRunner
def self.supported?
true
end

def supported?
self.class.supported?
end

def call(command, env = {})
with_modified_environment(env) do
Expand Down
7 changes: 7 additions & 0 deletions lib/cocaine/command_line/runners/fake_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
module Cocaine
class CommandLine
class FakeRunner
def self.supported?
false
end

def supported?
self.class.supported?
end

attr_reader :commands

Expand Down
8 changes: 8 additions & 0 deletions lib/cocaine/command_line/runners/popen_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
module Cocaine
class CommandLine
class PopenRunner
def self.supported?
true
end

def supported?
self.class.supported?
end

def call(command, env = {})
with_modified_environment(env) do
IO.popen(command, "r") do |pipe|
Expand Down
50 changes: 32 additions & 18 deletions lib/cocaine/command_line/runners/posix_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,45 @@
module Cocaine
class CommandLine
class PosixRunner
if Cocaine::CommandLine.posix_spawn_available?

def call(command, env = {})
input, output = IO.pipe
pid = spawn(env, command, :out => output)
output.close
result = ""
while partial_result = input.read(8192)
result << partial_result
end
waitpid(pid)
result
def self.available?
begin
require 'posix/spawn'
true
rescue LoadError => e
false
end
end

private
def self.supported?
available? && !Cocaine::CommandLine.java?
end

def spawn(*args)
POSIX::Spawn.spawn(*args)
end
def supported?
self.class.supported?
end

def waitpid(pid)
Process.waitpid(pid)
def call(command, env = {})
input, output = IO.pipe
pid = spawn(env, command, :out => output)
output.close
result = ""
while partial_result = input.read(8192)
result << partial_result
end
waitpid(pid)
result
end

private

def spawn(*args)
POSIX::Spawn.spawn(*args)
end

def waitpid(pid)
Process.waitpid(pid)
end

end
end
end
52 changes: 30 additions & 22 deletions lib/cocaine/command_line/runners/process_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,41 @@
module Cocaine
class CommandLine
class ProcessRunner
if Process.respond_to?(:spawn)

def call(command, env = {})
input, output = IO.pipe
pid = spawn(env, command, :out => output)
output.close
result = input.read
waitpid(pid)
result
end
def self.available?
Process.respond_to?(:spawn)
end

private
def self.supported?
available? && !Cocaine::CommandLine.java?
end

def spawn(*args)
Process.spawn(*args)
end
def supported?
self.class.supported?
end

def waitpid(pid)
begin
Process.waitpid(pid)
rescue Errno::ECHILD => e
# In JRuby, waiting on a finished pid raises.
end
end
def call(command, env = {})
input, output = IO.pipe
pid = spawn(env, command, :out => output)
output.close
result = input.read
waitpid(pid)
result
end

private

def spawn(*args)
Process.spawn(*args)
end

def waitpid(pid)
begin
Process.waitpid(pid)
rescue Errno::ECHILD => e
# In JRuby, waiting on a finished pid raises.
end
end

end
end
end

6 changes: 3 additions & 3 deletions lib/cocaine/exceptions.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# coding: UTF-8

module Cocaine
class CommandLineError < StandardError; end
class CommandLineError < StandardError; end
class CommandNotFoundError < CommandLineError; end
class ExitStatusError < CommandLineError; end
class InterpolationError < CommandLineError; end
class ExitStatusError < CommandLineError; end
class InterpolationError < CommandLineError; end
end
26 changes: 14 additions & 12 deletions spec/cocaine/command_line/runners/backticks_runner_spec.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
require 'spec_helper'

describe Cocaine::CommandLine::BackticksRunner do
it_behaves_like 'a command that does not block'
if Cocaine::CommandLine::BackticksRunner.supported?
it_behaves_like 'a command that does not block'

it 'runs the command given' do
subject.call("echo hello").should == "hello\n"
end
it 'runs the command given' do
subject.call("echo hello").should == "hello\n"
end

it 'modifies the environment and runs the command given' do
subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
end
it 'modifies the environment and runs the command given' do
subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
end

it 'sets the exitstatus when a command completes' do
subject.call("ruby -e 'exit 0'")
$?.exitstatus.should == 0
subject.call("ruby -e 'exit 5'")
$?.exitstatus.should == 5
it 'sets the exitstatus when a command completes' do
subject.call("ruby -e 'exit 0'")
$?.exitstatus.should == 0
subject.call("ruby -e 'exit 5'")
$?.exitstatus.should == 5
end
end
end
27 changes: 14 additions & 13 deletions spec/cocaine/command_line/runners/popen_runner_spec.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
require 'spec_helper'

describe Cocaine::CommandLine::PopenRunner do
it_behaves_like 'a command that does not block'
if Cocaine::CommandLine::PopenRunner.supported?
it_behaves_like 'a command that does not block'

it 'runs the command given' do
subject.call("echo hello").should == "hello\n"
end
it 'runs the command given' do
subject.call("echo hello").should == "hello\n"
end

it 'modifies the environment and runs the command given' do
subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
end
it 'modifies the environment and runs the command given' do
subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
end

it 'sets the exitstatus when a command completes' do
subject.call("ruby -e 'exit 0'")
$?.exitstatus.should == 0
subject.call("ruby -e 'exit 5'")
$?.exitstatus.should == 5
it 'sets the exitstatus when a command completes' do
subject.call("ruby -e 'exit 0'")
$?.exitstatus.should == 0
subject.call("ruby -e 'exit 5'")
$?.exitstatus.should == 5
end
end
end

3 changes: 1 addition & 2 deletions spec/cocaine/command_line/runners/posix_runner_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'spec_helper'

describe Cocaine::CommandLine::PosixRunner do
if Cocaine::CommandLine::posix_spawn_available?
if Cocaine::CommandLine::PosixRunner.supported?
it_behaves_like 'a command that does not block'

it 'runs the command given' do
Expand All @@ -20,4 +20,3 @@
end
end
end

2 changes: 1 addition & 1 deletion spec/cocaine/command_line/runners/process_runner_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'spec_helper'

describe Cocaine::CommandLine::ProcessRunner do
if Process.respond_to?(:spawn)
if Cocaine::CommandLine::ProcessRunner.supported?
it_behaves_like "a command that does not block"

it 'runs the command given' do
Expand Down
21 changes: 11 additions & 10 deletions spec/cocaine/command_line_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -238,38 +238,39 @@

describe "command execution" do
it "uses the BackticksRunner by default" do
Process.stubs(:respond_to?).with(:spawn).returns(false)
Cocaine::CommandLine.stubs(:posix_spawn_available?).returns(false)
Cocaine::CommandLine::ProcessRunner.stubs(:supported?).returns(false)
Cocaine::CommandLine::PosixRunner.stubs(:supported?).returns(false)

cmd = Cocaine::CommandLine.new("echo", "hello")

cmd.runner.class.should == Cocaine::CommandLine::BackticksRunner
end

it "uses the ProcessRunner on 1.9 and it's available" do
Process.stubs(:respond_to?).with(:spawn).returns(true)
Cocaine::CommandLine.stubs(:posix_spawn_available?).returns(false)
Cocaine::CommandLine::ProcessRunner.stubs(:supported?).returns(true)
Cocaine::CommandLine::PosixRunner.stubs(:supported?).returns(false)

cmd = Cocaine::CommandLine.new("echo", "hello")
cmd.runner.class.should == Cocaine::CommandLine::ProcessRunner
end

it "uses the PosixRunner if the posix-spawn gem is available" do
Cocaine::CommandLine.stubs(:posix_spawn_available?).returns(true)
it "uses the PosixRunner if the PosixRunner is available" do
Cocaine::CommandLine::PosixRunner.stubs(:supported?).returns(true)

cmd = Cocaine::CommandLine.new("echo", "hello")
cmd.runner.class.should == Cocaine::CommandLine::PosixRunner
end

it "uses the BackticksRunner if the posix-spawn gem is available, but we told it to use Backticks all the time" do
Cocaine::CommandLine.stubs(:posix_spawn_available?).returns(true)
it "uses the BackticksRunner if the PosixRunner is available, but we told it to use Backticks all the time" do
Cocaine::CommandLine::PosixRunner.stubs(:supported?).returns(true)
Cocaine::CommandLine.runner = Cocaine::CommandLine::BackticksRunner.new

cmd = Cocaine::CommandLine.new("echo", "hello")
cmd.runner.class.should == Cocaine::CommandLine::BackticksRunner
end

it "uses the BackticksRunner if the posix-spawn gem is available, but we told it to use Backticks" do
Cocaine::CommandLine.stubs(:posix_spawn_available?).returns(true)
it "uses the BackticksRunner if the PosixRunner is available, but we told it to use Backticks" do
Cocaine::CommandLine::PosixRunner.stubs(:supported?).returns(true)

cmd = Cocaine::CommandLine.new("echo", "hello", :runner => Cocaine::CommandLine::BackticksRunner.new)
cmd.runner.class.should == Cocaine::CommandLine::BackticksRunner
Expand Down

0 comments on commit 20670a4

Please sign in to comment.