command-runner 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +12 -3
- data/lib/command/runner.rb +37 -13
- data/lib/command/runner/backends/backticks.rb +12 -2
- data/lib/command/runner/backends/fake.rb +18 -2
- data/lib/command/runner/backends/posix_spawn.rb +2 -2
- data/lib/command/runner/backends/spawn.rb +4 -4
- data/lib/command/runner/backends/ssh.rb +6 -1
- data/lib/command/runner/version.rb +1 -1
- data/spec/backticks_spec.rb +5 -2
- data/spec/messenger_spec.rb +55 -14
- data/spec/spawn_spec.rb +12 -3
- metadata +64 -73
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 35d339b7a9ec8370365504412a82dfb2e18523b3
|
4
|
+
data.tar.gz: 2ed783e009554db92e0374534ebe10dadc6e05de
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d038c4a0686d3dd7f484bc2a6f3f3eef464c6c1b1b2bab19d2a607ad21cc940d068229ce0af4f21380da9735f0d649f90dfee0ae88f2f8d7a212ab8f8dfff08f
|
7
|
+
data.tar.gz: 7578cae4033ef1491a4d9c3534507d5bda162dcb81711325de219e447ab060610d5fcb0f9852d75cb540cad1578632034205a229efd5f7061393a8c963e0d732
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# Command Runner
|
1
|
+
# Command Runner
|
2
|
+
[](https://travis-ci.org/redjazz96/command-runner) [](https://codeclimate.com/github/redjazz96/command-runner)
|
3
|
+
|
2
4
|
Runs commands.
|
3
5
|
|
4
6
|
```Ruby
|
@@ -34,6 +36,7 @@ unless you don't want it to.
|
|
34
36
|
|
35
37
|
```Ruby
|
36
38
|
line = Command::Runner.new("echo", "{{interpolation}}")
|
39
|
+
line.force_unsafe!
|
37
40
|
message = line.pass(:interpolation => "`uname -a`")
|
38
41
|
message.stdout # => "Linux Hyperion 3.8.0-25-generic #37-Ubuntu SMP Thu Jun 6 20:47:07 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux\n"
|
39
42
|
message.line # => "echo `uname -a`"
|
@@ -74,10 +77,16 @@ and return the value.
|
|
74
77
|
## Compatibility
|
75
78
|
It works on
|
76
79
|
|
80
|
+
- 2.1.0
|
77
81
|
- 2.0.0
|
78
82
|
- 1.9.3
|
79
83
|
- 1.8.7
|
80
|
-
-
|
81
|
-
- JRuby (1.
|
84
|
+
- JRuby (2.0 Mode)
|
85
|
+
- JRuby (1.9 Mode)
|
86
|
+
|
82
87
|
|
83
88
|
unless the travis build fails.
|
89
|
+
|
90
|
+
|
91
|
+
[](https://bitdeli.com/free "Bitdeli Badge")
|
92
|
+
|
data/lib/command/runner.rb
CHANGED
@@ -23,10 +23,10 @@ module Command
|
|
23
23
|
# Returns the best backend for messenger to use.
|
24
24
|
#
|
25
25
|
# @return [#call] a backend to use.
|
26
|
-
def best_backend
|
27
|
-
if Backends::PosixSpawn.available?
|
26
|
+
def best_backend(force_unsafe = false)
|
27
|
+
if Backends::PosixSpawn.available? && !force_unsafe
|
28
28
|
Backends::PosixSpawn.new
|
29
|
-
elsif Backends::Spawn.available?
|
29
|
+
elsif Backends::Spawn.available? && !force_unsafe
|
30
30
|
Backends::Spawn.new
|
31
31
|
elsif Backends::Backticks.available?
|
32
32
|
Backends::Backticks.new
|
@@ -98,7 +98,7 @@ module Command
|
|
98
98
|
# @return [Message, Object] message if no block was given, the
|
99
99
|
# return value of the block otherwise.
|
100
100
|
def pass!(interops = {}, options = {}, &block)
|
101
|
-
backend.call(*[contents(interops), options.delete(:env) || {}, options].flatten, &block)
|
101
|
+
backend.call(*[contents(interops), options.delete(:env) || {}, options].flatten(1), &block)
|
102
102
|
|
103
103
|
rescue Errno::ENOENT
|
104
104
|
raise NoCommandError, @command
|
@@ -128,6 +128,16 @@ module Command
|
|
128
128
|
|
129
129
|
alias_method :run, :pass
|
130
130
|
|
131
|
+
# Whether or not to force an unsafe backend. This should only be
|
132
|
+
# used in cases where the developer wants the arguments passed to
|
133
|
+
# a shell, so that the unsafe interpolated arguments can be
|
134
|
+
# shell'd.
|
135
|
+
#
|
136
|
+
# @return [void]
|
137
|
+
def force_unsafe!
|
138
|
+
@backend = self.class.best_backend(true)
|
139
|
+
end
|
140
|
+
|
131
141
|
# The command line being run by the runner. Interpolates the
|
132
142
|
# arguments with the given interpolations.
|
133
143
|
#
|
@@ -147,27 +157,41 @@ module Command
|
|
147
157
|
#
|
148
158
|
# @param string [String] the string to interpolate.
|
149
159
|
# @param interops [Hash] the interpolations to make.
|
150
|
-
# @return [String] the interpolated string.
|
160
|
+
# @return [Array<String>] the interpolated string.
|
151
161
|
def interpolate(string, interops = {})
|
152
162
|
interops = interops.to_a.map { |(k, v)| { k.to_s => v } }.inject(&:merge) || {}
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
163
|
+
results = [*string.shellsplit]
|
164
|
+
|
165
|
+
results.map do |part|
|
166
|
+
if part =~ /(\{{1,2})([0-9a-zA-Z_\-]+)(\}{1,2})/
|
167
|
+
if interops.key?($2) && $1.length == $3.length
|
168
|
+
if $1.length == 1
|
169
|
+
escape interops[$2].to_s
|
170
|
+
else
|
171
|
+
interops[$2].to_s.shellsplit
|
172
|
+
end
|
173
|
+
else
|
174
|
+
part
|
175
|
+
end
|
157
176
|
else
|
158
|
-
|
177
|
+
part
|
159
178
|
end
|
160
|
-
end
|
179
|
+
end.flatten
|
161
180
|
end
|
162
181
|
|
163
182
|
private
|
164
183
|
|
165
|
-
# Escape the given string for a shell
|
184
|
+
# Escape the given string for a shell if the backend is unsafe,
|
185
|
+
# otherwise it just returns the string.
|
166
186
|
#
|
167
187
|
# @param string [String] the string to escape.
|
168
188
|
# @return [String] the escaped string.
|
169
189
|
def escape(string)
|
170
|
-
|
190
|
+
if backend.unsafe?
|
191
|
+
Shellwords.escape(string)
|
192
|
+
else
|
193
|
+
string
|
194
|
+
end
|
171
195
|
end
|
172
196
|
|
173
197
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
1
3
|
module Command
|
2
4
|
class Runner
|
3
5
|
module Backends
|
@@ -11,6 +13,10 @@ module Command
|
|
11
13
|
true
|
12
14
|
end
|
13
15
|
|
16
|
+
def self.unsafe?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
14
20
|
# Initialize the fake backend.
|
15
21
|
def initialize
|
16
22
|
super
|
@@ -36,10 +42,14 @@ module Command
|
|
36
42
|
|
37
43
|
with_modified_env(env) do
|
38
44
|
start_time = Time.now
|
39
|
-
output << `#{command} #{arguments}`
|
45
|
+
output << `#{command} #{arguments.join(' ')}`
|
40
46
|
end_time = Time.now
|
41
47
|
end
|
42
48
|
|
49
|
+
if $?.exitstatus == 127
|
50
|
+
raise NoCommandError
|
51
|
+
end
|
52
|
+
|
43
53
|
message = Message.new :process_id => $?.pid,
|
44
54
|
:exit_code => $?.exitstatus,
|
45
55
|
:finished => true,
|
@@ -47,7 +57,7 @@ module Command
|
|
47
57
|
:env => env,
|
48
58
|
:options => {},
|
49
59
|
:stdout => output,
|
50
|
-
:line => [command, arguments].join(' '),
|
60
|
+
:line => [command, arguments].flatten.join(' '),
|
51
61
|
:executed => true,
|
52
62
|
:status => $?
|
53
63
|
|
@@ -16,6 +16,17 @@ module Command
|
|
16
16
|
true
|
17
17
|
end
|
18
18
|
|
19
|
+
# A backend is considered unsafe when the arguments are
|
20
|
+
# exposed directly to the shell. This is a vulnerability, so
|
21
|
+
# we mark the class as unsafe and when we're about to pass
|
22
|
+
# the arguments to the backend, escape the safe
|
23
|
+
# interpolations.
|
24
|
+
#
|
25
|
+
# @return [Boolean]
|
26
|
+
def self.unsafe?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
19
30
|
# Initialize the fake backend.
|
20
31
|
def initialize
|
21
32
|
@ran = []
|
@@ -41,7 +52,7 @@ module Command
|
|
41
52
|
@ran << [command, arguments]
|
42
53
|
|
43
54
|
message = Message.new :env => env, :options => options, :line =>
|
44
|
-
[command, arguments].join(' ')
|
55
|
+
[command, *arguments].join(' ')
|
45
56
|
end
|
46
57
|
|
47
58
|
# Determines whether or not the given command and arguments were
|
@@ -52,7 +63,12 @@ module Command
|
|
52
63
|
# @param arguments [String]
|
53
64
|
# @return [Boolean]
|
54
65
|
def ran?(command, arguments)
|
55
|
-
@ran.include?([command, arguments])
|
66
|
+
@ran.include?([command, *arguments])
|
67
|
+
end
|
68
|
+
|
69
|
+
# (see ::unsafe?)
|
70
|
+
def unsafe?
|
71
|
+
self.class.unsafe?
|
56
72
|
end
|
57
73
|
|
58
74
|
end
|
@@ -26,8 +26,8 @@ module Command
|
|
26
26
|
#
|
27
27
|
# @see Spawn#spawn
|
28
28
|
# @return [Numeric]
|
29
|
-
def spawn(env,
|
30
|
-
POSIX::Spawn.spawn(env,
|
29
|
+
def spawn(env, command, arguments, options)
|
30
|
+
POSIX::Spawn.spawn(env, command, *[arguments, options].flatten)
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
@@ -44,10 +44,10 @@ module Command
|
|
44
44
|
|
45
45
|
stdin_w.close
|
46
46
|
|
47
|
-
line = [command, arguments].join(' ')
|
47
|
+
line = [command, *arguments].join(' ')
|
48
48
|
|
49
49
|
start_time = Time.now
|
50
|
-
process_id = spawn(env,
|
50
|
+
process_id = spawn(env, command, arguments, new_options)
|
51
51
|
|
52
52
|
future do
|
53
53
|
_, status = wait2(process_id)
|
@@ -80,8 +80,8 @@ module Command
|
|
80
80
|
#
|
81
81
|
# @see Process.spawn
|
82
82
|
# @return [Numeric] the process id
|
83
|
-
def spawn(env,
|
84
|
-
Process.spawn(env,
|
83
|
+
def spawn(env, command, arguments, options)
|
84
|
+
Process.spawn(env, command, *[arguments, options].flatten)
|
85
85
|
end
|
86
86
|
|
87
87
|
# Waits for the given process, and returns the process id and the
|
@@ -19,6 +19,10 @@ module Command
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.unsafe?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
22
26
|
# Initializes the backend.
|
23
27
|
#
|
24
28
|
# @param host [String] the host to connect to.
|
@@ -36,7 +40,8 @@ module Command
|
|
36
40
|
channel = @net_ssh.open_channel do |ch|
|
37
41
|
|
38
42
|
|
39
|
-
ch.exec "#{command}
|
43
|
+
ch.exec "#{command} " \
|
44
|
+
"#{arguments.join(" ").shellescape}" do |sch, success|
|
40
45
|
raise Errno::ENOENT unless success
|
41
46
|
|
42
47
|
env.each do |k, v|
|
data/spec/backticks_spec.rb
CHANGED
@@ -4,13 +4,16 @@ describe Command::Runner::Backends::Backticks do
|
|
4
4
|
Command::Runner::Backends::Backticks.should be_available
|
5
5
|
end
|
6
6
|
|
7
|
+
its(:unsafe?) { should be_true }
|
8
|
+
|
7
9
|
it "returns a message" do
|
8
|
-
value = subject.call("echo", "hello")
|
10
|
+
value = subject.call("echo", ["hello"])
|
9
11
|
value.should be_instance_of Command::Runner::Message
|
10
12
|
value.should be_executed
|
11
13
|
end
|
12
14
|
|
13
15
|
it "gives the correct time" do
|
14
|
-
subject.call("sleep", "0.5").time.should be_within(0.1).of(0.5)
|
16
|
+
subject.call("sleep", ["0.5"]).time.should be_within(0.1).of(0.5)
|
15
17
|
end
|
18
|
+
|
16
19
|
end
|
data/spec/messenger_spec.rb
CHANGED
@@ -8,46 +8,58 @@ describe Command::Runner do
|
|
8
8
|
Command::Runner.new(command, arguments)
|
9
9
|
end
|
10
10
|
|
11
|
-
context "interpolating
|
11
|
+
context "when interpolating" do
|
12
12
|
let(:command) { "echo" }
|
13
13
|
let(:arguments) { "some {interpolation}" }
|
14
14
|
|
15
15
|
it "interpolates correctly" do
|
16
|
-
|
16
|
+
expect(
|
17
|
+
subject.contents(:interpolation => "test")
|
18
|
+
).to eq ["echo", ["some", "test"]]
|
17
19
|
end
|
18
20
|
|
19
21
|
it "escapes bad values" do
|
20
|
-
|
22
|
+
expect(
|
23
|
+
subject.contents(:interpolation => "`bad value`")
|
24
|
+
).to eq ["echo", ["some", "`bad value`"]]
|
21
25
|
end
|
22
26
|
|
23
27
|
it "doesn't interpolate interpolation values" do
|
24
|
-
|
28
|
+
expect(
|
29
|
+
subject.contents(:interpolation => "{other}", :other => "hi")
|
30
|
+
).to eq ["echo", ["some", "{other}"]]
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
28
|
-
context "double
|
34
|
+
context "when interpolating double strings" do
|
29
35
|
let(:command) { "echo" }
|
30
36
|
let(:arguments) { "some {{interpolation}}" }
|
31
37
|
|
32
38
|
it "interpolates correctly" do
|
33
|
-
|
39
|
+
expect(
|
40
|
+
subject.contents(:interpolation => "test")
|
41
|
+
).to eq ["echo", ["some", "test"]]
|
34
42
|
end
|
35
43
|
|
36
44
|
it "doesn't escape bad values" do
|
37
|
-
|
45
|
+
expect(
|
46
|
+
subject.contents(:interpolation => "`bad value`")
|
47
|
+
).to eq ["echo", ["some", "`bad", "value`"]]
|
38
48
|
end
|
39
49
|
end
|
40
50
|
|
41
|
-
context "misinterpolated strings" do
|
51
|
+
context "when interpolating misinterpolated strings" do
|
42
52
|
let(:command) { "echo" }
|
43
53
|
let(:arguments) { "some {{interpolation}" }
|
44
54
|
|
45
55
|
it "doesn't interpolate" do
|
46
|
-
|
56
|
+
expect(
|
57
|
+
subject.contents(:interpolation => "test")
|
58
|
+
).to eq ["echo", ["some", "{{interpolation}"]]
|
47
59
|
end
|
48
60
|
end
|
49
61
|
|
50
|
-
context "selecting backends" do
|
62
|
+
context "when selecting backends" do
|
51
63
|
it "selects the best backend" do
|
52
64
|
Command::Runner::Backends::PosixSpawn.stub(:available?).and_return(false)
|
53
65
|
Command::Runner::Backends::Spawn.stub(:available?).and_return(true)
|
@@ -56,9 +68,13 @@ describe Command::Runner do
|
|
56
68
|
Command::Runner::Backends::PosixSpawn.stub(:available?).and_return(true)
|
57
69
|
Command::Runner.best_backend.should be_instance_of Command::Runner::Backends::PosixSpawn
|
58
70
|
end
|
71
|
+
|
72
|
+
it "takes into account unsafe backends" do
|
73
|
+
Command::Runner.best_backend(true).should be_unsafe
|
74
|
+
end
|
59
75
|
end
|
60
76
|
|
61
|
-
context "bad commands" do
|
77
|
+
context "when given bad commands" do
|
62
78
|
let(:command) { "some-non-existant-command" }
|
63
79
|
let(:arguments) { "" }
|
64
80
|
|
@@ -69,12 +85,37 @@ describe Command::Runner do
|
|
69
85
|
its(:pass) { should be_no_command }
|
70
86
|
|
71
87
|
it "calls the block given" do
|
72
|
-
subject.backend = Command::Runner::Backends::Backticks.new
|
73
88
|
subject.pass do |message|
|
74
|
-
message.should be_no_command
|
75
89
|
|
76
|
-
message.line.
|
90
|
+
expect(message.line).to eq "some-non-existant-command "
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when passing commands" do
|
96
|
+
let(:command) { "echo" }
|
97
|
+
let(:arguments) { "{interpolation}" }
|
98
|
+
|
99
|
+
before :each do
|
100
|
+
subject.backend = Command::Runner::Backends::Backticks.new
|
101
|
+
end
|
102
|
+
|
103
|
+
it "escapes bad values" do
|
104
|
+
subject.pass(:interpolation => "`uname -a`") do |message|
|
105
|
+
expect(message.stdout).to eq "`uname -a`\n"
|
77
106
|
end
|
78
107
|
end
|
108
|
+
|
109
|
+
it "returns the last value in the block" do
|
110
|
+
expect(
|
111
|
+
subject.pass(:interpolation => "hi") { |m| m.stdout }
|
112
|
+
).to eq "hi\n"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns a message" do
|
116
|
+
expect(
|
117
|
+
subject.pass
|
118
|
+
).to be_a Command::Runner::Message
|
119
|
+
end
|
79
120
|
end
|
80
121
|
end
|
data/spec/spawn_spec.rb
CHANGED
@@ -2,23 +2,31 @@ describe Command::Runner::Backends::Spawn do
|
|
2
2
|
|
3
3
|
next unless Process.respond_to?(:spawn) && !(RUBY_PLATFORM == "java" && RUBY_VERSION =~ /\A1\.9/)
|
4
4
|
|
5
|
+
its(:unsafe?) { should be_false }
|
6
|
+
|
5
7
|
it "is available" do
|
6
8
|
Command::Runner::Backends::Spawn.should be_available
|
7
9
|
end
|
8
10
|
|
9
11
|
it "returns a message" do
|
10
|
-
value = subject.call("echo", "hello")
|
12
|
+
value = subject.call("echo", ["hello"])
|
11
13
|
value.should be_instance_of Command::Runner::Message
|
12
14
|
value.should be_executed
|
13
15
|
end
|
14
16
|
|
15
17
|
it "doesn't block" do
|
16
18
|
start_time = Time.now
|
17
|
-
value = subject.call("sleep", "0.5")
|
19
|
+
value = subject.call("sleep", ["0.5"])
|
18
20
|
end_time = Time.now
|
19
21
|
|
20
22
|
(end_time - start_time).should be_within((1.0/100)).of(0)
|
21
|
-
value.time.should be_within((
|
23
|
+
value.time.should be_within((3.0/100)).of(0.5)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "doesn't expose arguments to the shell" do
|
27
|
+
value = subject.call("echo", ["`uname -a`"])
|
28
|
+
|
29
|
+
expect(value.stdout).to eq "`uname -a`\n"
|
22
30
|
end
|
23
31
|
|
24
32
|
it "can not be available" do
|
@@ -28,4 +36,5 @@ describe Command::Runner::Backends::Spawn do
|
|
28
36
|
Command::Runner::Backends::Spawn.new
|
29
37
|
}.to raise_error(Command::Runner::NotAvailableBackendError)
|
30
38
|
end
|
39
|
+
|
31
40
|
end
|
metadata
CHANGED
@@ -1,108 +1,99 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: command-runner
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.1
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Jeremy Rodi
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
|
12
|
+
date: 2014-01-05 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
15
|
name: promise
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0.3'
|
22
|
-
type: :runtime
|
23
16
|
prerelease: false
|
24
|
-
|
25
|
-
|
26
|
-
requirements:
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
27
19
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: "0.3"
|
22
|
+
type: :runtime
|
23
|
+
version_requirements: *id001
|
24
|
+
- !ruby/object:Gem::Dependency
|
31
25
|
name: rspec
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
38
|
-
type: :development
|
39
26
|
prerelease: false
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version:
|
46
|
-
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- &id003
|
30
|
+
- ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id002
|
35
|
+
- !ruby/object:Gem::Dependency
|
47
36
|
name: yard
|
48
|
-
|
49
|
-
|
50
|
-
requirements:
|
51
|
-
-
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- *id003
|
54
41
|
type: :development
|
42
|
+
version_requirements: *id004
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: fuubar
|
55
45
|
prerelease: false
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
description: ! " Runs a command or two in the shell with arguments that can be\n
|
63
|
-
\ interpolated with the interpolation syntax.\n"
|
46
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- *id003
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id005
|
51
|
+
description: " Runs a command or two in the shell with arguments that can be\n interpolated with the interpolation syntax.\n"
|
64
52
|
email: redjazz96@gmail.com
|
65
53
|
executables: []
|
54
|
+
|
66
55
|
extensions: []
|
56
|
+
|
67
57
|
extra_rdoc_files: []
|
68
|
-
|
58
|
+
|
59
|
+
files:
|
69
60
|
- README.md
|
70
|
-
- lib/command/runner
|
71
|
-
- lib/command/runner/exceptions.rb
|
72
|
-
- lib/command/runner/backends.rb
|
61
|
+
- lib/command/runner.rb
|
73
62
|
- lib/command/runner/message.rb
|
74
|
-
- lib/command/runner/backends/fake.rb
|
75
|
-
- lib/command/runner/backends/backticks.rb
|
76
|
-
- lib/command/runner/backends/ssh.rb
|
77
63
|
- lib/command/runner/backends/posix_spawn.rb
|
64
|
+
- lib/command/runner/backends/ssh.rb
|
65
|
+
- lib/command/runner/backends/backticks.rb
|
66
|
+
- lib/command/runner/backends/fake.rb
|
78
67
|
- lib/command/runner/backends/spawn.rb
|
79
|
-
- lib/command/runner.rb
|
80
|
-
-
|
68
|
+
- lib/command/runner/exceptions.rb
|
69
|
+
- lib/command/runner/backends.rb
|
70
|
+
- lib/command/runner/version.rb
|
81
71
|
- spec/spawn_spec.rb
|
72
|
+
- spec/messenger_spec.rb
|
82
73
|
- spec/backticks_spec.rb
|
83
74
|
homepage: http://github.com/redjazz96/command-runner
|
84
75
|
licenses: []
|
76
|
+
|
77
|
+
metadata: {}
|
78
|
+
|
85
79
|
post_install_message:
|
86
80
|
rdoc_options: []
|
87
|
-
|
81
|
+
|
82
|
+
require_paths:
|
88
83
|
- lib
|
89
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
-
none: false
|
97
|
-
requirements:
|
98
|
-
- - ! '>='
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
version: '0'
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- *id003
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- *id003
|
101
90
|
requirements: []
|
91
|
+
|
102
92
|
rubyforge_project:
|
103
|
-
rubygems_version:
|
93
|
+
rubygems_version: 2.0.14
|
104
94
|
signing_key:
|
105
|
-
specification_version:
|
95
|
+
specification_version: 4
|
106
96
|
summary: Runs commands.
|
107
97
|
test_files: []
|
98
|
+
|
108
99
|
has_rdoc: false
|