rubysh 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -3
- data/lib/rubysh/command.rb +4 -0
- data/lib/rubysh/runner.rb +17 -2
- data/lib/rubysh/subprocess/pid_aware_parallel_io.rb +7 -0
- data/lib/rubysh/version.rb +1 -1
- data/test/functional/_lib.rb +0 -2
- data/test/functional/lib/env.rb +1 -1
- data/test/functional/lib/kill.rb +25 -0
- data/test/functional/lib/read.rb +18 -0
- data/test/integration/_lib.rb +0 -2
- data/test/unit/_lib.rb +0 -2
- data/test/unit/lib/rubysh/command.rb +4 -0
- metadata +8 -4
data/README.md
CHANGED
@@ -92,7 +92,7 @@ the `AliasRubysh` helper:
|
|
92
92
|
Rubysh takes a splatted array argument as a command specification. In
|
93
93
|
particular, it doesn't convert it back and forth a command-line
|
94
94
|
string, meaning you don't have to worry about spaces in
|
95
|
-
|
95
|
+
arguments. (You should still always think twice before putting
|
96
96
|
untrusted arguments into a shell argument.)
|
97
97
|
|
98
98
|
## Installation
|
@@ -112,6 +112,5 @@ Patches welcome! I'm happy to merge pull requests.
|
|
112
112
|
|
113
113
|
## Future features
|
114
114
|
|
115
|
-
-
|
116
|
-
- Finer-grained IO control
|
115
|
+
- Better support for streaming output
|
117
116
|
- Subshell syntax (`cat <(ls)`, `echo $(ls)`)
|
data/lib/rubysh/command.rb
CHANGED
@@ -3,6 +3,10 @@ module Rubysh
|
|
3
3
|
attr_accessor :raw_args, :directives, :args
|
4
4
|
|
5
5
|
def initialize(args)
|
6
|
+
if args.length == 1 && args[0].kind_of?(Array)
|
7
|
+
raise "It looks like you created a Rubysh::Command with a singleton nested array: #{args.inspect}. That'll never be runnable, and probably indicates you forgot a splat somewhere."
|
8
|
+
end
|
9
|
+
|
6
10
|
@raw_args = args
|
7
11
|
@directives = []
|
8
12
|
@args = nil
|
data/lib/rubysh/runner.rb
CHANGED
@@ -56,9 +56,15 @@ module Rubysh
|
|
56
56
|
case how = opts[:how]
|
57
57
|
when :partial
|
58
58
|
# Read until we get some bytes
|
59
|
-
|
59
|
+
while state[:buffer].length == state[:read_pos]
|
60
|
+
# If everything's exited, just return nil
|
61
|
+
return nil if @parallel_io.finalized
|
62
|
+
@parallel_io.run_once
|
63
|
+
end
|
60
64
|
when :nonblock
|
61
65
|
@parallel_io.read_available(state[:target])
|
66
|
+
# Return nil unless we have something new
|
67
|
+
return nil if state[:buffer].length == state[:read_pos]
|
62
68
|
when nil
|
63
69
|
communicate if @runner_state == :started
|
64
70
|
else
|
@@ -203,13 +209,22 @@ module Rubysh
|
|
203
209
|
target_state
|
204
210
|
end
|
205
211
|
|
206
|
-
|
212
|
+
def kill(signal='TERM')
|
213
|
+
my_pid = pid
|
214
|
+
unless my_pid
|
215
|
+
raise Rubysh::Error::BaseError.new("You haven't started this runner yet.")
|
216
|
+
end
|
217
|
+
Rubysh.log.debug("Sending #{signal} to #{my_pid}")
|
218
|
+
Process.kill(signal, my_pid)
|
219
|
+
end
|
207
220
|
|
208
221
|
def wait
|
209
222
|
run_io
|
210
223
|
do_wait
|
211
224
|
end
|
212
225
|
|
226
|
+
private
|
227
|
+
|
213
228
|
def targets_by_fd_numbers
|
214
229
|
@targets.inject({}) do |hash, (_, target_state)|
|
215
230
|
fd_num = target_state[:subprocess_fd_number]
|
@@ -58,10 +58,13 @@ class Rubysh::Subprocess
|
|
58
58
|
Signal.trap('CHLD', @old_sigchld_handler)
|
59
59
|
end
|
60
60
|
|
61
|
+
attr_reader :finalized
|
62
|
+
|
61
63
|
# readers/writers should be hashes mapping {fd => name}
|
62
64
|
def initialize(readers, writers, subprocesses)
|
63
65
|
@breaker_reader, @breaker_writer = IO.pipe
|
64
66
|
@subprocesses = subprocesses
|
67
|
+
@finalized = false
|
65
68
|
|
66
69
|
readers = readers.dup
|
67
70
|
readers[@breaker_reader] = nil
|
@@ -75,6 +78,8 @@ class Rubysh::Subprocess
|
|
75
78
|
end
|
76
79
|
|
77
80
|
def run_once(timeout=nil)
|
81
|
+
return if @finalized
|
82
|
+
|
78
83
|
@subprocesses.each do |subprocess|
|
79
84
|
subprocess.wait(true)
|
80
85
|
end
|
@@ -98,6 +103,8 @@ class Rubysh::Subprocess
|
|
98
103
|
available_readers.each {|reader| reader.close}
|
99
104
|
available_writers.each {|writer| writer.close}
|
100
105
|
self.class.deregister_parallel_io(self)
|
106
|
+
|
107
|
+
@finalized = true
|
101
108
|
end
|
102
109
|
end
|
103
110
|
end
|
data/lib/rubysh/version.rb
CHANGED
data/test/functional/_lib.rb
CHANGED
data/test/functional/lib/env.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path('../_lib', File.dirname(__FILE__))
|
2
2
|
|
3
3
|
module RubyshTest::Functional
|
4
|
-
class
|
4
|
+
class EnvTest < FunctionalTest
|
5
5
|
describe 'when using <<< string' do
|
6
6
|
it 'the string is delivered on stdin' do
|
7
7
|
ENV['TEST1'] = '1'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path('../_lib', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module RubyshTest::Functional
|
4
|
+
class KillTest < FunctionalTest
|
5
|
+
describe 'when killing' do
|
6
|
+
it 'delivers a sigterm by default' do
|
7
|
+
result = Rubysh.run_async('ruby', '-e', 'sleep 10', Rubysh.>)
|
8
|
+
result.kill
|
9
|
+
result.wait
|
10
|
+
|
11
|
+
assert_equal(nil, result.exitstatus)
|
12
|
+
assert_equal(Signal.list['TERM'], result.full_status.termsig)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'delivers the specified signal otherwise' do
|
16
|
+
result = Rubysh.run_async('ruby', '-e', 'sleep 10', Rubysh.>)
|
17
|
+
result.kill('KILL')
|
18
|
+
result.wait
|
19
|
+
|
20
|
+
assert_equal(nil, result.exitstatus)
|
21
|
+
assert_equal(Signal.list['KILL'], result.full_status.termsig)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../_lib', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module RubyshTest::Functional
|
4
|
+
class ReadTest < FunctionalTest
|
5
|
+
describe 'when reading with :how => :partial' do
|
6
|
+
it 'returns nil once the process is dead' do
|
7
|
+
runner = Rubysh('ruby', '-e', 'puts "hi"', Rubysh.>).run_async
|
8
|
+
|
9
|
+
# Pump stdout
|
10
|
+
while runner.read(:how => :partial)
|
11
|
+
end
|
12
|
+
|
13
|
+
runner.wait
|
14
|
+
assert_equal(nil, runner.read(:how => :partial))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/integration/_lib.rb
CHANGED
data/test/unit/_lib.rb
CHANGED
@@ -15,6 +15,10 @@ module RubyshTest::Unit
|
|
15
15
|
command = Rubysh::Command.new(['ls', '/tmp', directive, '/foo'])
|
16
16
|
assert_equal('Command: ls /tmp 2>&1 /foo', command.to_s)
|
17
17
|
end
|
18
|
+
|
19
|
+
it 'raises an error when given an unsplatted array' do
|
20
|
+
assert_raises(RuntimeError) {Rubysh::Command.new([['ls', 'stuff']])}
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
describe 'when calling #run_async' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubysh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-11-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -110,7 +110,9 @@ files:
|
|
110
110
|
- test/functional/_lib.rb
|
111
111
|
- test/functional/lib/env.rb
|
112
112
|
- test/functional/lib/fd-lister
|
113
|
+
- test/functional/lib/kill.rb
|
113
114
|
- test/functional/lib/leaked_fds.rb
|
115
|
+
- test/functional/lib/read.rb
|
114
116
|
- test/functional/lib/redirect_ordering.rb
|
115
117
|
- test/functional/lib/triple_less_than.rb
|
116
118
|
- test/integration/_lib.rb
|
@@ -138,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
140
|
version: '0'
|
139
141
|
segments:
|
140
142
|
- 0
|
141
|
-
hash:
|
143
|
+
hash: 3386670358533092265
|
142
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
145
|
none: false
|
144
146
|
requirements:
|
@@ -147,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
149
|
version: '0'
|
148
150
|
segments:
|
149
151
|
- 0
|
150
|
-
hash:
|
152
|
+
hash: 3386670358533092265
|
151
153
|
requirements: []
|
152
154
|
rubyforge_project:
|
153
155
|
rubygems_version: 1.8.23
|
@@ -162,7 +164,9 @@ test_files:
|
|
162
164
|
- test/functional/_lib.rb
|
163
165
|
- test/functional/lib/env.rb
|
164
166
|
- test/functional/lib/fd-lister
|
167
|
+
- test/functional/lib/kill.rb
|
165
168
|
- test/functional/lib/leaked_fds.rb
|
169
|
+
- test/functional/lib/read.rb
|
166
170
|
- test/functional/lib/redirect_ordering.rb
|
167
171
|
- test/functional/lib/triple_less_than.rb
|
168
172
|
- test/integration/_lib.rb
|