rubysh 0.0.5 → 0.0.6
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/Gemfile +5 -1
- data/README.md +2 -2
- data/Rakefile +7 -3
- data/lib/rubysh/subprocess/pipe_wrapper.rb +7 -9
- data/lib/rubysh/version.rb +1 -1
- data/lib/rubysh.rb +3 -3
- data/rubysh.gemspec +9 -7
- data/test/functional/lib/leaked_fds.rb +40 -31
- data/test/functional/lib/triple_less_than.rb +1 -1
- metadata +45 -7
data/Gemfile
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# Execute bundler hook if present
|
2
|
+
['~/.', '/etc/'].any? do |file|
|
3
|
+
File.lstat(path = File.expand_path(file + 'bundle-gemfile-hook')) rescue next
|
4
|
+
eval(File.read(path), binding, path); break true
|
5
|
+
end || source('https://rubygems.org/')
|
2
6
|
|
3
7
|
# Specify your gem's dependencies in rubysh.gemspec
|
4
8
|
gemspec
|
data/README.md
CHANGED
@@ -55,8 +55,8 @@ are arbitrary symbols):
|
|
55
55
|
|
56
56
|
command = Rubysh('echo', 'hi', Rubysh.stdout > :stdout, Rubysh.stderr > :stderr)
|
57
57
|
runner = command.run
|
58
|
-
runner.
|
59
|
-
runner.
|
58
|
+
runner.read(:stdout) # "hi\n"
|
59
|
+
runner.read(:stderr) # ""
|
60
60
|
|
61
61
|
## Controlled input
|
62
62
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'chalk-rake/gem_tasks'
|
3
5
|
require 'rake/testtask'
|
4
6
|
|
5
7
|
Rake::TestTask.new do |t|
|
6
|
-
t.libs = [
|
8
|
+
t.libs = ['lib']
|
7
9
|
# t.warning = true
|
8
10
|
t.verbose = true
|
9
|
-
t.test_files = FileList['test/**/*.rb']
|
11
|
+
t.test_files = FileList['test/**/*.rb'].reject do |file|
|
12
|
+
file.end_with?('_lib.rb') || file.include?('/_lib/')
|
13
|
+
end
|
10
14
|
end
|
@@ -50,12 +50,10 @@ class Rubysh::Subprocess
|
|
50
50
|
|
51
51
|
def dump_json_and_close(msg)
|
52
52
|
dumped = SERIALIZER.dump(msg)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
Rubysh.assert(@reader.closed?, "Reader should already be closed")
|
58
|
-
end
|
53
|
+
@writer.write(dumped)
|
54
|
+
ensure
|
55
|
+
@writer.close
|
56
|
+
Rubysh.assert(@reader.closed?, "Reader should already be closed")
|
59
57
|
end
|
60
58
|
|
61
59
|
def load_json_and_close
|
@@ -68,10 +66,10 @@ class Rubysh::Subprocess
|
|
68
66
|
# e.g. ArgumentError: syntax error on line 0, col 2: `' (could
|
69
67
|
# happen if the subprocess was killed while writing a message)
|
70
68
|
raise Rubysh::Error::BaseError.new("Invalid message read from pipe: #{e}")
|
71
|
-
ensure
|
72
|
-
@reader.close
|
73
|
-
Rubysh.assert(@writer.closed?, "Writer should already be closed")
|
74
69
|
end
|
70
|
+
ensure
|
71
|
+
@reader.close
|
72
|
+
Rubysh.assert(@writer.closed?, "Writer should already be closed")
|
75
73
|
end
|
76
74
|
end
|
77
75
|
end
|
data/lib/rubysh/version.rb
CHANGED
data/lib/rubysh.rb
CHANGED
@@ -135,7 +135,7 @@ module Rubysh
|
|
135
135
|
opts = target
|
136
136
|
target = nil
|
137
137
|
end
|
138
|
-
target
|
138
|
+
target ||= :stdout
|
139
139
|
|
140
140
|
Redirect.new(1, '>', target, opts)
|
141
141
|
end
|
@@ -145,7 +145,7 @@ module Rubysh
|
|
145
145
|
opts = target
|
146
146
|
target = nil
|
147
147
|
end
|
148
|
-
target
|
148
|
+
target ||= :stdout
|
149
149
|
|
150
150
|
Redirect.new(1, '>>', target, opts)
|
151
151
|
end
|
@@ -155,7 +155,7 @@ module Rubysh
|
|
155
155
|
opts = target
|
156
156
|
target = nil
|
157
157
|
end
|
158
|
-
target
|
158
|
+
target ||= :stdin
|
159
159
|
|
160
160
|
Redirect.new(0, '<', target, opts)
|
161
161
|
end
|
data/rubysh.gemspec
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
require File.expand_path('../lib/rubysh/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = [
|
6
|
-
gem.email = [
|
7
|
-
gem.description =
|
5
|
+
gem.authors = ['Greg Brockman']
|
6
|
+
gem.email = ['gdb@gregbrockman.com']
|
7
|
+
gem.description = 'Rubysh: Ruby subprocesses made easy'
|
8
8
|
gem.summary = "Rubysh makes shelling out easy with a __sh__-like syntax layer for Ruby:
|
9
9
|
|
10
10
|
irb -r rubysh
|
@@ -12,15 +12,17 @@ Gem::Specification.new do |gem|
|
|
12
12
|
>> command.run
|
13
13
|
hello-from-Rubysh
|
14
14
|
=> Rubysh::Runner: echo hello-from-Rubysh | grep --color Rubysh (exitstatus: 0)"
|
15
|
-
gem.homepage =
|
15
|
+
gem.homepage = ''
|
16
16
|
|
17
17
|
gem.files = `git ls-files`.split($\)
|
18
18
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
19
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
-
gem.name =
|
21
|
-
gem.require_paths = [
|
20
|
+
gem.name = 'rubysh'
|
21
|
+
gem.require_paths = ['lib']
|
22
22
|
gem.version = Rubysh::VERSION
|
23
23
|
|
24
|
-
gem.add_development_dependency '
|
24
|
+
gem.add_development_dependency 'rake'
|
25
25
|
gem.add_development_dependency 'mocha'
|
26
|
+
gem.add_development_dependency 'chalk-rake'
|
27
|
+
gem.add_development_dependency 'minitest', '3.1.0'
|
26
28
|
end
|
@@ -3,20 +3,6 @@ require 'shellwords'
|
|
3
3
|
|
4
4
|
module RubyshTest::Functional
|
5
5
|
class LeakedFDsTest < FunctionalTest
|
6
|
-
# Try to remove inteference from other tests
|
7
|
-
def close_high_fds
|
8
|
-
begin
|
9
|
-
(3..20).each do |fd|
|
10
|
-
begin
|
11
|
-
io = IO.new(fd)
|
12
|
-
rescue Errno::EBADF
|
13
|
-
else
|
14
|
-
io.close
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
6
|
def parse_lsof(stdout)
|
21
7
|
pids = []
|
22
8
|
stdout.split("\n").each do |line|
|
@@ -25,58 +11,81 @@ module RubyshTest::Functional
|
|
25
11
|
pids
|
26
12
|
end
|
27
13
|
|
28
|
-
|
29
|
-
|
14
|
+
def original_fds
|
15
|
+
output = `lsof -p "#{$$}" -F f`
|
16
|
+
parse_lsof(output)
|
30
17
|
end
|
31
18
|
|
19
|
+
def expected_fd_count(original, pids)
|
20
|
+
# MRI 1.9 reserves FDs 3, 4 for itself.
|
21
|
+
#
|
22
|
+
# TODO: I don't fully understand what FDs MRI decides it needs,
|
23
|
+
# but some typical output here is that pids is [0, 1, 2, 5, 6,
|
24
|
+
# 8, 255] while original is [0, 1, 2, 3, 4, 5, 6, 7, 8].
|
25
|
+
#
|
26
|
+
# That may actually indicate a bug in Rubysh somewhere, but I
|
27
|
+
# think it means MRI likes opening FDs.
|
28
|
+
if RUBY_VERSION =~ /\A1.9\./
|
29
|
+
assert_equal(pids.length, original.length - 2, "Pids is #{pids.inspect} while original is #{original.inspect}")
|
30
|
+
else
|
31
|
+
assert_equal(pids.length, original.length, "Pids is #{pids.inspect} while original is #{original.inspect}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
32
36
|
describe 'when spawning with no pipe' do
|
33
37
|
it 'has no unexpected FDs, post-exec' do
|
34
|
-
|
38
|
+
original = original_fds
|
39
|
+
cmd = Rubysh(File.expand_path('../fd-lister', __FILE__), Rubysh.stdout > :stdout, Rubysh.stderr > '/dev/null')
|
35
40
|
result = cmd.run
|
36
41
|
|
37
|
-
stdout = result.
|
42
|
+
stdout = result.read(:stdout)
|
38
43
|
pids = parse_lsof(stdout)
|
39
|
-
|
44
|
+
expected_fd_count(original, pids)
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
48
|
describe 'when spawning with a redirect' do
|
44
49
|
it 'has no unexpected FDs, post-exec' do
|
45
|
-
|
50
|
+
original = original_fds
|
51
|
+
cmd = Rubysh(File.expand_path('../fd-lister', __FILE__), Rubysh.stderr > '/dev/null', Rubysh.stdout > :stdout)
|
46
52
|
result = cmd.run
|
47
53
|
|
48
|
-
stdout = result.
|
54
|
+
stdout = result.read(:stdout)
|
49
55
|
pids = parse_lsof(stdout)
|
50
|
-
|
56
|
+
expected_fd_count(original, pids)
|
51
57
|
end
|
52
58
|
end
|
53
59
|
|
54
60
|
describe 'when spawning with a pipe' do
|
55
61
|
it 'has no unexpected FDs, post-fork' do
|
56
|
-
|
62
|
+
original = original_fds
|
63
|
+
cmd = Rubysh(File.expand_path('../fd-lister', __FILE__)) | Rubysh('cat', Rubysh.stdout > :stdout)
|
57
64
|
result = cmd.run
|
58
65
|
|
59
|
-
stdout = result.
|
66
|
+
stdout = result.read(:stdout)
|
60
67
|
pids = parse_lsof(stdout)
|
61
|
-
|
68
|
+
expected_fd_count(original, pids)
|
62
69
|
end
|
63
70
|
|
64
71
|
it 'has no unexpected FDs, post-fork, when on the right side of a pipe' do
|
65
|
-
|
72
|
+
original = original_fds
|
73
|
+
cmd = Rubysh('echo') | Rubysh(File.expand_path('../fd-lister', __FILE__), Rubysh.stdout > :stdout)
|
66
74
|
result = cmd.run
|
67
75
|
|
68
|
-
stdout = result.
|
76
|
+
stdout = result.read(:stdout)
|
69
77
|
pids = parse_lsof(stdout)
|
70
|
-
|
78
|
+
expected_fd_count(original, pids)
|
71
79
|
end
|
72
80
|
|
73
81
|
it 'has no unexpected FDs, post-fork, when in the middle of two pipes' do
|
74
|
-
|
82
|
+
original = original_fds
|
83
|
+
cmd = Rubysh('echo') | Rubysh(File.expand_path('../fd-lister', __FILE__)) | Rubysh('cat', Rubysh.stdout > :stdout)
|
75
84
|
result = cmd.run
|
76
85
|
|
77
|
-
stdout = result.
|
86
|
+
stdout = result.read(:stdout)
|
78
87
|
pids = parse_lsof(stdout)
|
79
|
-
|
88
|
+
expected_fd_count(original, pids)
|
80
89
|
end
|
81
90
|
end
|
82
91
|
end
|
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.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: rake
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- - '
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- - '
|
27
|
+
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: mocha
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -43,6 +43,38 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: chalk-rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.1.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.1.0
|
46
78
|
description: ! 'Rubysh: Ruby subprocesses made easy'
|
47
79
|
email:
|
48
80
|
- gdb@gregbrockman.com
|
@@ -103,12 +135,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
135
|
- - ! '>='
|
104
136
|
- !ruby/object:Gem::Version
|
105
137
|
version: '0'
|
138
|
+
segments:
|
139
|
+
- 0
|
140
|
+
hash: 1492953900327640253
|
106
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
142
|
none: false
|
108
143
|
requirements:
|
109
144
|
- - ! '>='
|
110
145
|
- !ruby/object:Gem::Version
|
111
146
|
version: '0'
|
147
|
+
segments:
|
148
|
+
- 0
|
149
|
+
hash: 1492953900327640253
|
112
150
|
requirements: []
|
113
151
|
rubyforge_project:
|
114
152
|
rubygems_version: 1.8.23
|