rubysh 0.0.10 → 0.0.11

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.
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
- variables. (You should still always think twice before putting
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
- - Support for environment variables
116
- - Finer-grained IO control
115
+ - Better support for streaming output
117
116
  - Subshell syntax (`cat <(ls)`, `echo $(ls)`)
@@ -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
- @parallel_io.run_once until state[:buffer].length != state[:read_pos]
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
- private
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
@@ -1,3 +1,3 @@
1
1
  module Rubysh
2
- VERSION = '0.0.10'
2
+ VERSION = '0.0.11'
3
3
  end
@@ -3,5 +3,3 @@ require File.expand_path('../_lib', File.dirname(__FILE__))
3
3
  module RubyshTest::Functional
4
4
  class FunctionalTest < RubyshTest::Test; end
5
5
  end
6
-
7
- MiniTest::Unit.runner = MiniTest::Unit.new
@@ -1,7 +1,7 @@
1
1
  require File.expand_path('../_lib', File.dirname(__FILE__))
2
2
 
3
3
  module RubyshTest::Functional
4
- class TripleLessThanTest < FunctionalTest
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
@@ -3,5 +3,3 @@ require File.expand_path('../_lib', File.dirname(__FILE__))
3
3
  module RubyshTest::Integration
4
4
  class IntegrationTest < RubyshTest::Test; end
5
5
  end
6
-
7
- MiniTest::Unit.runner = MiniTest::Unit.new
data/test/unit/_lib.rb CHANGED
@@ -3,5 +3,3 @@ require File.expand_path('../_lib', File.dirname(__FILE__))
3
3
  module RubyshTest::Unit
4
4
  class UnitTest < RubyshTest::Test; end
5
5
  end
6
-
7
- MiniTest::Unit.runner = MiniTest::Unit.new
@@ -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.10
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-10-13 00:00:00.000000000 Z
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: 1275881591566036262
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: 1275881591566036262
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