methadone 0.5.1 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +1 -0
- data/README.rdoc +59 -1
- data/Rakefile +2 -2
- data/bin/methadone +7 -5
- data/features/bootstrap.feature +1 -0
- data/features/step_definitions/bootstrap_steps.rb +9 -0
- data/features/step_definitions/version_steps.rb +1 -1
- data/features/support/env.rb +5 -0
- data/features/version.feature +0 -1
- data/lib/methadone.rb +7 -0
- data/lib/methadone/error.rb +12 -0
- data/lib/methadone/execution_strategy/base.rb +37 -0
- data/lib/methadone/execution_strategy/jvm.rb +30 -0
- data/lib/methadone/execution_strategy/mri.rb +14 -0
- data/lib/methadone/execution_strategy/open_3.rb +11 -0
- data/lib/methadone/execution_strategy/open_4.rb +16 -0
- data/lib/methadone/execution_strategy/rbx_open_4.rb +10 -0
- data/lib/methadone/sh.rb +143 -0
- data/lib/methadone/version.rb +1 -1
- data/methadone.gemspec +1 -0
- data/test/command_for_tests.rb +5 -0
- data/test/execution_strategy/test_base.rb +24 -0
- data/test/execution_strategy/test_jvm.rb +77 -0
- data/test/execution_strategy/test_mri.rb +32 -0
- data/test/execution_strategy/test_open_3.rb +47 -0
- data/test/execution_strategy/test_open_4.rb +57 -0
- data/test/execution_strategy/test_rbx_open_4.rb +25 -0
- data/test/test_sh.rb +269 -0
- metadata +171 -84
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -12,6 +12,7 @@ Currently, this library is under development and has the following to offer:
|
|
12
12
|
|
13
13
|
* Bootstrapping a new CLI app
|
14
14
|
* Lightweight DSL to structure your bin file
|
15
|
+
* Simple wrapper for running external commands with good logging
|
15
16
|
* Utility Classes
|
16
17
|
* Methadone::CLILogger - a logger subclass that sends messages to standard error standard out as appropriate
|
17
18
|
* Methadone::CLILogging - a module that, when included in any class, provides easy access to a shared logger
|
@@ -22,7 +23,18 @@ Currently, this library is under development and has the following to offer:
|
|
22
23
|
* {Source on Github}[http://github.com/davetron5000/methadone]
|
23
24
|
* RDoc[http://rdoc.info/github/davetron5000/methadone/master/frames]
|
24
25
|
|
25
|
-
==
|
26
|
+
== Platforms
|
27
|
+
|
28
|
+
* Works completely on:
|
29
|
+
* MRI Ruby 1.9.2
|
30
|
+
* MRI Ruby 1.9.3
|
31
|
+
* MRI Ruby Head
|
32
|
+
* MRI Ruby 1.8.7
|
33
|
+
* RBX
|
34
|
+
* REE
|
35
|
+
* For JRuby, everything works but aruba; aruba just doesn't work on JRuby for some reason, though this library *is* being used in production under JRuby 1.6.6
|
36
|
+
|
37
|
+
== Bootstrapping a new CLI App
|
26
38
|
|
27
39
|
The +methadone+ command-line app will bootstrap a new command-line app, setting up a proper gem structure, unit tests, and cucumber-based tests with aruba:
|
28
40
|
|
@@ -112,6 +124,52 @@ don't accept options, <tt>[options]</tt> won't appear in the help. The names of
|
|
112
124
|
will appear in proper order and <tt>:optional</tt> ones will be in square brackets. You don't have to
|
113
125
|
touch a thing.
|
114
126
|
|
127
|
+
== Wrapper for running external commands with good logging
|
128
|
+
|
129
|
+
While backtick and <tt>%x[]</tt> are nice for compact, bash-like scripting, they have some failings:
|
130
|
+
|
131
|
+
* You have to check the return value via <tt>$?</tt>
|
132
|
+
* You have no access to the standard error
|
133
|
+
* You really want to log: the command, the output, and the error so that for cron-like tasks, you can sort out what happened
|
134
|
+
|
135
|
+
Enter Methadone::SH
|
136
|
+
|
137
|
+
include Methadone::SH
|
138
|
+
|
139
|
+
sh 'cp foo.txt /tmp'
|
140
|
+
# => logs the command to DEBUG, executes the command, logs its output to DEBUG and its
|
141
|
+
# error output to WARN, returns 0
|
142
|
+
|
143
|
+
sh 'cp non_existent_file.txt /nowhere_good'
|
144
|
+
# => logs the command to DEBUG, executes thecommand, logs its output to INFO and
|
145
|
+
# its error output to WARN, returns the nonzero exit status of the underlying command
|
146
|
+
|
147
|
+
sh! 'cp non_existent_file.txt /nowhere_good'
|
148
|
+
# => same as above, EXCEPT, raises a Methadone::FailedCommandError
|
149
|
+
|
150
|
+
With this, you can easily script external commands in *almost* as expedient a fashion as with +bash+, however you get sensible logging along the way. By default, this uses the logger provided by Methadone::CLILogging (which is *not* mixed in when you mix in Methadone::SH). If you want to use a different logger, or don't want to mix in Methadone::CLILogging, simply call +set_sh_logger+ with your preferred logger.
|
151
|
+
|
152
|
+
But that's not all! You can run code when the command succeed by passing a block:
|
153
|
+
|
154
|
+
sh 'cp foo.txt /tmp' do
|
155
|
+
# Behaves exactly as before, but this block is called after
|
156
|
+
end
|
157
|
+
|
158
|
+
sh 'cp non_existent_file.txt /nowhere_good' do
|
159
|
+
# This block isn't called, since the command failed
|
160
|
+
end
|
161
|
+
|
162
|
+
The <tt>sh!</tt> form works this way as well. The block form is also how you can access the standard output or error of the command that ran. Simply have your block accept one or two aguments:
|
163
|
+
|
164
|
+
sh 'ls -l /tmp/' do |stdout|
|
165
|
+
# stdout contains the output of the command
|
166
|
+
end
|
167
|
+
sh 'ls -l /tmp/ /non_existent_dir' do |stdout,stderr|
|
168
|
+
# stdout contains the output of the command,
|
169
|
+
# stderr contains the standard error output.
|
170
|
+
end
|
171
|
+
|
172
|
+
This isn't a replacement for Open3 or ChildProcess, but a way to easily "do the right thing" for most cases.
|
115
173
|
|
116
174
|
== Utility Classes
|
117
175
|
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ Rake::TestTask.new do |t|
|
|
15
15
|
t.libs << "lib"
|
16
16
|
t.libs << "test"
|
17
17
|
t.ruby_opts << "-rrubygems"
|
18
|
-
t.test_files = FileList['test/test_*.rb']
|
18
|
+
t.test_files = FileList['test/test_*.rb'] + FileList['test/execution_strategy/test_*.rb']
|
19
19
|
end
|
20
20
|
|
21
21
|
desc 'build rdoc'
|
@@ -43,5 +43,5 @@ Cucumber::Rake::Task.new('features:wip') do |t|
|
|
43
43
|
end
|
44
44
|
|
45
45
|
CLEAN << "coverage"
|
46
|
-
|
46
|
+
CLOBBER << FileList['**/*.rbc']
|
47
47
|
task :default => [:test, :features]
|
data/bin/methadone
CHANGED
@@ -8,6 +8,7 @@ require 'methadone/cli'
|
|
8
8
|
include FileUtils
|
9
9
|
include Methadone::Main
|
10
10
|
include Methadone::CLI
|
11
|
+
include Methadone::SH
|
11
12
|
|
12
13
|
main do |app_name|
|
13
14
|
check_and_prepare_basedir!(app_name,options[:force])
|
@@ -20,7 +21,7 @@ main do |app_name|
|
|
20
21
|
|
21
22
|
chdir File.dirname(app_name)
|
22
23
|
|
23
|
-
|
24
|
+
sh! "bundle gem #{gemname}"
|
24
25
|
|
25
26
|
chdir gemname
|
26
27
|
|
@@ -50,11 +51,12 @@ main do |app_name|
|
|
50
51
|
copy_file "features/step_definitions/executable_steps.rb", :as => "#{gemname}_steps.rb"
|
51
52
|
copy_file "bin/executable", :as => gemname, :executable => true, :binding => binding
|
52
53
|
|
54
|
+
gem_variable = File.open("#{gemname}.gemspec") { |x| x.read }.match(/(\w+)\.executables/)[1]
|
53
55
|
add_to_file "#{gemname}.gemspec", [
|
54
|
-
"
|
55
|
-
"
|
56
|
-
"
|
57
|
-
"
|
56
|
+
" #{gem_variable}.add_development_dependency('rdoc')",
|
57
|
+
" #{gem_variable}.add_development_dependency('aruba')",
|
58
|
+
" #{gem_variable}.add_development_dependency('rake','~> 0.9.2')",
|
59
|
+
" #{gem_variable}.add_dependency('methadone')",
|
58
60
|
], :before => /^end\s*$/
|
59
61
|
end
|
60
62
|
|
data/features/bootstrap.feature
CHANGED
@@ -35,6 +35,7 @@ Feature: Bootstrap a new command-line app
|
|
35
35
|
And the file "tmp/newgem/newgem.gemspec" should match /add_development_dependency\('rdoc'/
|
36
36
|
And the file "tmp/newgem/newgem.gemspec" should match /add_development_dependency\('rake','~> 0.9.2'/
|
37
37
|
And the file "tmp/newgem/newgem.gemspec" should match /add_dependency\('methadone'/
|
38
|
+
And the file "tmp/newgem/newgem.gemspec" should use the same block variable throughout
|
38
39
|
Given I cd to "tmp/newgem"
|
39
40
|
And my app's name is "newgem"
|
40
41
|
When I successfully run `bin/newgem --help` with "lib" in the library path
|
@@ -10,6 +10,15 @@ Given /^my app's name is "([^"]*)"$/ do |app_name|
|
|
10
10
|
@app_name = app_name
|
11
11
|
end
|
12
12
|
|
13
|
+
Then /^the file "([^"]*)" should use the same block variable throughout$/ do |file|
|
14
|
+
prep_for_fs_check do
|
15
|
+
content = IO.read(file)
|
16
|
+
from_bundler = content.match(/(\w+)\.authors/)[1]
|
17
|
+
added_by_methadone = content.match(/(\w+).add_development_dependency\('rdoc'/)[1]
|
18
|
+
from_bundler.should == added_by_methadone
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
13
22
|
Then /^the stderr should match \/([^\/]*)\/$/ do |expected|
|
14
23
|
assert_matching_output(expected, all_stderr)
|
15
24
|
end
|
@@ -1,4 +1,4 @@
|
|
1
1
|
When /^I successfully run `([^`]*)` with "([^"]*)" in the library path$/ do |command,dir|
|
2
|
-
ENV["RUBYOPT"] = "-I" + File.join(Dir.pwd,ARUBA_DIR,'tmp','newgem',dir)
|
2
|
+
ENV["RUBYOPT"] = (ENV["RUBYOPT"] || '') + " -I" + File.join(Dir.pwd,ARUBA_DIR,'tmp','newgem',dir)
|
3
3
|
step %(I successfully run `#{command}`)
|
4
4
|
end
|
data/features/support/env.rb
CHANGED
@@ -9,13 +9,18 @@ Before do
|
|
9
9
|
@puts = true
|
10
10
|
@aruba_timeout_seconds = 60
|
11
11
|
@original_rubylib = ENV['RUBYLIB']
|
12
|
+
@original_rubyopt = ENV['RUBYOPT']
|
12
13
|
|
13
14
|
# We want to use, hopefully, the methadone from this codebase and not
|
14
15
|
# the gem, so we put it in the RUBYLIB
|
15
16
|
ENV['RUBYLIB'] = File.join(PROJECT_ROOT,'lib') + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
17
|
+
|
18
|
+
# We need -rubygems here so that 1.8-style rubies work AND travis-ci doesn't barf with it in the shebang line
|
19
|
+
ENV['RUBYOPT'] = (ENV['RUBYOPT'] || '') + ' -rubygems'
|
16
20
|
end
|
17
21
|
|
18
22
|
After do
|
19
23
|
# Put back how it was
|
20
24
|
ENV['RUBYLIB'] = @original_rubylib
|
25
|
+
ENV['RUBYOPT'] = @original_rubyopt
|
21
26
|
end
|
data/features/version.feature
CHANGED
data/lib/methadone.rb
CHANGED
@@ -3,4 +3,11 @@ require 'methadone/cli_logger'
|
|
3
3
|
require 'methadone/cli_logging'
|
4
4
|
require 'methadone/main'
|
5
5
|
require 'methadone/error'
|
6
|
+
require 'methadone/execution_strategy/base'
|
7
|
+
require 'methadone/execution_strategy/mri'
|
8
|
+
require 'methadone/execution_strategy/open_3'
|
9
|
+
require 'methadone/execution_strategy/open_4'
|
10
|
+
require 'methadone/execution_strategy/rbx_open_4'
|
11
|
+
require 'methadone/execution_strategy/jvm'
|
12
|
+
require 'methadone/sh'
|
6
13
|
# Note: DO NOT require cli.rb OR cucumber.rb here
|
data/lib/methadone/error.rb
CHANGED
@@ -9,4 +9,16 @@ module Methadone
|
|
9
9
|
@exit_code = exit_code
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
# Thrown by certain methods when an externally-called command exits nonzero
|
14
|
+
class FailedCommandError < Error
|
15
|
+
|
16
|
+
# The command that caused the failure
|
17
|
+
attr_reader :command
|
18
|
+
|
19
|
+
def initialize(exit_code,command)
|
20
|
+
super(exit_code,"Command '#{command}' exited #{exit_code}")
|
21
|
+
@command = command
|
22
|
+
end
|
23
|
+
end
|
12
24
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Methadone
|
2
|
+
# Module to contain ExecutionStrategy implementations.
|
3
|
+
# To build your own simply implement two methods:
|
4
|
+
#
|
5
|
+
# <tt>exception_meaning_command_not_found</tt>:: return the class that, if caught, means that the underlying command
|
6
|
+
# couldn't be found. This is needed because currently impelmentations
|
7
|
+
# throw an exception, but they don't all throw the same one.
|
8
|
+
module ExecutionStrategy
|
9
|
+
# Base for any ExecutionStrategy implementation. Currently, this is nothing more than an interface
|
10
|
+
# specification.
|
11
|
+
class Base
|
12
|
+
# Executes the command and returns the results back.
|
13
|
+
# This should do no logging or other logic other than to execute the command
|
14
|
+
# and return the required results.
|
15
|
+
#
|
16
|
+
# command:: the command-line to run, as a String
|
17
|
+
#
|
18
|
+
# Returns an array of size 3:
|
19
|
+
# <tt>[0]</tt>:: The standard output of the command as a String, never nil
|
20
|
+
# <tt>[1]</tt>:: The standard error output of the command as a String, never nil
|
21
|
+
# <tt>[2]</tt>:: A Process::Status-like objects that responds to <tt>exitstatus</tt> which returns
|
22
|
+
# the exit code of the command (e.g. 0 for success).
|
23
|
+
def run_command(command)
|
24
|
+
subclass_must_impelment!
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the class that, if caught by calling #run_command, represents the underlying command
|
28
|
+
# not existing. For example, in MRI Ruby, if you try to execute a non-existent command,
|
29
|
+
# you get a Errno::ENOENT.
|
30
|
+
def exception_meaning_command_not_found
|
31
|
+
subclass_must_impelment!
|
32
|
+
end
|
33
|
+
protected
|
34
|
+
def subclass_must_impelment!; raise "subclass must implement"; end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Methadone
|
2
|
+
module ExecutionStrategy
|
3
|
+
# Methadone::ExecutionStrategy for the JVM that uses JVM classes to run the command and get its results.
|
4
|
+
class JVM < Base
|
5
|
+
def run_command(command)
|
6
|
+
process = java.lang.Runtime.get_runtime.exec(command)
|
7
|
+
process.get_output_stream.close
|
8
|
+
stdout = input_stream_to_string(process.get_input_stream)
|
9
|
+
stderr = input_stream_to_string(process.get_error_stream)
|
10
|
+
exitstatus = process.wait_for
|
11
|
+
[stdout.chomp,stderr.chomp,OpenStruct.new(:exitstatus => exitstatus)]
|
12
|
+
end
|
13
|
+
|
14
|
+
def exception_meaning_command_not_found
|
15
|
+
NativeException
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def input_stream_to_string(is)
|
20
|
+
''.tap do |string|
|
21
|
+
ch = is.read
|
22
|
+
while ch != -1
|
23
|
+
string << ch
|
24
|
+
ch = is.read
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Methadone
|
2
|
+
module ExecutionStrategy
|
3
|
+
# Implementation for modern Rubies that uses the built-in Open3 library
|
4
|
+
class Open_3 < MRI
|
5
|
+
def run_command(command)
|
6
|
+
stdout,stderr,status = Open3.capture3(command)
|
7
|
+
[stdout.chomp,stderr.chomp,status]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Methadone
|
2
|
+
module ExecutionStrategy
|
3
|
+
# ExecutionStrategy for non-modern Rubies that must rely on
|
4
|
+
# Open4 to get access to the standard output AND error.
|
5
|
+
class Open_4 < MRI
|
6
|
+
def run_command(command)
|
7
|
+
pid, stdin_io, stdout_io, stderr_io = Open4::popen4(command)
|
8
|
+
stdin_io.close
|
9
|
+
stdout = stdout_io.read
|
10
|
+
stderr = stderr_io.read
|
11
|
+
_ , status = Process::waitpid2(pid)
|
12
|
+
[stdout.chomp,stderr.chomp,status]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/methadone/sh.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
require 'java'
|
3
|
+
require 'ostruct'
|
4
|
+
elsif RUBY_VERSION =~ /^1.8/
|
5
|
+
require 'open4'
|
6
|
+
else
|
7
|
+
require 'open3'
|
8
|
+
end
|
9
|
+
|
10
|
+
module Methadone
|
11
|
+
# Module with various helper methods for executing external commands.
|
12
|
+
# In most cases, you can use #sh to run commands and have decent logging
|
13
|
+
# done. You will likely use this in a class that also mixes-in
|
14
|
+
# Methadone::CLILogging. If you *don't*, you must provide a logger
|
15
|
+
# via #set_sh_logger.
|
16
|
+
#
|
17
|
+
# In order to work on as many Rubies as possible, this class defers the actual execution
|
18
|
+
# to an execution strategy. See #set_execution_strategy if you think you'd like to override
|
19
|
+
# that, or just want to know how it works.
|
20
|
+
#
|
21
|
+
# This is not intended to be a complete replacement for Open3, but instead of make common cases
|
22
|
+
# and good practice easy to accomplish.
|
23
|
+
module SH
|
24
|
+
# Run a shell command, capturing and logging its output.
|
25
|
+
# If the command completed successfully, it's output is logged at DEBUG.
|
26
|
+
# If not, its output as logged at INFO. In either case, its
|
27
|
+
# error output is logged at WARN.
|
28
|
+
#
|
29
|
+
# command:: the command to run
|
30
|
+
# block:: if provided, will be called if the command exited nonzero. The block may take 0, 1, or 2 arguments.
|
31
|
+
# The arguments provided are the standard output as a string and the standard error as a string,
|
32
|
+
# You should be safe to pass in a lambda instead of a block, as long as your
|
33
|
+
# lambda doesn't take more than two arguments
|
34
|
+
#
|
35
|
+
# Example
|
36
|
+
#
|
37
|
+
# sh "cp foo /tmp"
|
38
|
+
# sh "ls /tmp" do |stdout|
|
39
|
+
# # stdout contains the output of ls /tmp
|
40
|
+
# end
|
41
|
+
# sh "ls -l /tmp foobar" do |stdout,stderr|
|
42
|
+
# # ...
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# Returns the exit status of the command. Note that if the command doesn't exist, this returns 127.
|
46
|
+
def sh(command,&block)
|
47
|
+
sh_logger.debug("Executing '#{command}'")
|
48
|
+
|
49
|
+
stdout,stderr,status = execution_strategy.run_command(command)
|
50
|
+
|
51
|
+
sh_logger.warn("Error output of '#{command}': #{stderr}") unless stderr.strip.length == 0
|
52
|
+
|
53
|
+
if status.exitstatus != 0
|
54
|
+
sh_logger.info("Output of '#{command}': #{stdout}")
|
55
|
+
sh_logger.warn("Error running '#{command}'")
|
56
|
+
else
|
57
|
+
sh_logger.debug("Output of '#{command}': #{stdout}")
|
58
|
+
call_block(block,stdout,stderr) unless block.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
status.exitstatus
|
62
|
+
rescue exception_meaning_command_not_found => ex
|
63
|
+
sh_logger.error("Error running '#{command}': #{ex.message}")
|
64
|
+
127
|
65
|
+
end
|
66
|
+
|
67
|
+
# Run a command, throwing an exception if the command exited nonzero.
|
68
|
+
# Otherwise, behaves exactly like #sh.
|
69
|
+
#
|
70
|
+
# Raises Methadone::FailedCommandError if the command exited nonzero.
|
71
|
+
def sh!(command,&block)
|
72
|
+
sh(command,&block).tap do |exitstatus|
|
73
|
+
raise Methadone::FailedCommandError.new(exitstatus,command) if exitstatus != 0
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Override the default logger (which is the one provided by CLILogging).
|
78
|
+
# You would do this if you want a custom logger or you aren't mixing-in
|
79
|
+
# CLILogging.
|
80
|
+
#
|
81
|
+
# Note that this method is *not* called <tt>sh_logger=</tt> to avoid annoying situations
|
82
|
+
# where Ruby thinks you are setting a local variable
|
83
|
+
def set_sh_logger(logger)
|
84
|
+
@sh_logger = logger
|
85
|
+
end
|
86
|
+
|
87
|
+
# Set the strategy to use for executing commands. In general, you don't need to set this
|
88
|
+
# since this module chooses an appropriate implementation based on your Ruby platform:
|
89
|
+
#
|
90
|
+
# 1.8 Rubies, including 1.8, and REE:: Open4 is used via Methadone::ExecutionStrategy::Open_4
|
91
|
+
# Rubinius:: Open4 is used, but we handle things a bit differently; see Methadone::ExecutionStrategy::RBXOpen_4
|
92
|
+
# JRuby:: Use JVM calls to +Runtime+ via Methadone::ExecutionStrategy::JVM
|
93
|
+
# Windows:: Currently no support for Windows
|
94
|
+
# All others:: we use Open3 from the standard library, via Methadone::ExecutionStrategy::Open_3
|
95
|
+
#
|
96
|
+
# See Methadone::ExecutionStrategy::Base for how to implement your own.
|
97
|
+
def set_execution_strategy(strategy)
|
98
|
+
@execution_strategy = strategy
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def exception_meaning_command_not_found
|
104
|
+
execution_strategy.exception_meaning_command_not_found
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.default_execution_strategy_class
|
108
|
+
if RUBY_PLATFORM == 'java'
|
109
|
+
Methadone::ExecutionStrategy::JVM
|
110
|
+
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
111
|
+
Methadone::ExecutionStrategy::RBXOpen_4
|
112
|
+
elsif RUBY_VERSION =~ /^1.8/
|
113
|
+
Methadone::ExecutionStrategy::Open_4
|
114
|
+
else
|
115
|
+
Methadone::ExecutionStrategy::Open_3
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def execution_strategy
|
120
|
+
@execution_strategy ||= SH.default_execution_strategy_class.new
|
121
|
+
end
|
122
|
+
|
123
|
+
def sh_logger
|
124
|
+
@sh_logger ||= self.logger
|
125
|
+
end
|
126
|
+
|
127
|
+
# Safely call our block, even if the user passed in a lambda
|
128
|
+
def call_block(block,stdout,stderr)
|
129
|
+
# blocks that take no arguments have arity -1. Or 0. Ugh.
|
130
|
+
if block.arity > 0
|
131
|
+
case block.arity
|
132
|
+
when 1
|
133
|
+
block.call(stdout)
|
134
|
+
else
|
135
|
+
# Let it fail for lambdas
|
136
|
+
block.call(stdout,stderr)
|
137
|
+
end
|
138
|
+
else
|
139
|
+
block.call
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|