open4 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/open4.rb +19 -2
- data/open4.gemspec +2 -1
- data/test/popen4ext_test.rb +82 -0
- metadata +21 -42
data/lib/open4.rb
CHANGED
@@ -4,7 +4,7 @@ require 'timeout'
|
|
4
4
|
require 'thread'
|
5
5
|
|
6
6
|
module Open4
|
7
|
-
VERSION = '1.
|
7
|
+
VERSION = '1.3.0'
|
8
8
|
def self.version() VERSION end
|
9
9
|
|
10
10
|
class Error < ::StandardError; end
|
@@ -38,7 +38,17 @@ module Open4
|
|
38
38
|
module_function :popen4
|
39
39
|
module_function :open4
|
40
40
|
|
41
|
-
def
|
41
|
+
def popen4ext(closefds=false, *cmd, &b)
|
42
|
+
Open4.do_popen(b, :init, closefds) do |ps_read, ps_write|
|
43
|
+
ps_read.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
44
|
+
ps_write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
45
|
+
exec(*cmd)
|
46
|
+
raise 'forty-two' # Is this really needed?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
module_function :popen4ext
|
50
|
+
|
51
|
+
def self.do_popen(b = nil, exception_propagation_at = nil, closefds=false, &cmd)
|
42
52
|
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
43
53
|
|
44
54
|
verbose = $VERBOSE
|
@@ -46,6 +56,13 @@ module Open4
|
|
46
56
|
$VERBOSE = nil
|
47
57
|
|
48
58
|
cid = fork {
|
59
|
+
if closefds
|
60
|
+
exlist = [0, 1, 2] | [pw,pr,pe,ps].map{|p| [p.first.fileno, p.last.fileno] }.flatten
|
61
|
+
ObjectSpace.each_object(IO){|io|
|
62
|
+
io.close if (not io.closed?) and (not exlist.include? io.fileno)
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
49
66
|
pw.last.close
|
50
67
|
STDIN.reopen pw.first
|
51
68
|
pw.first.close
|
data/open4.gemspec
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
Gem::Specification::new do |spec|
|
5
5
|
spec.name = "open4"
|
6
|
-
spec.version = "1.
|
6
|
+
spec.version = "1.3.0"
|
7
7
|
spec.platform = Gem::Platform::RUBY
|
8
8
|
spec.summary = "open4"
|
9
9
|
spec.description = "description: open4 kicks the ass"
|
@@ -29,6 +29,7 @@ Gem::Specification::new do |spec|
|
|
29
29
|
"test",
|
30
30
|
"test/pfork4_test.rb",
|
31
31
|
"test/popen4_test.rb",
|
32
|
+
"test/popen4ext_test.rb",
|
32
33
|
"test/support",
|
33
34
|
"test/support/test_case.rb",
|
34
35
|
"white_box",
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test_case'
|
2
|
+
|
3
|
+
module Open4
|
4
|
+
|
5
|
+
class POpen4Test < TestCase
|
6
|
+
UNKNOWN_CMD = 'asdfadsfjlkkk'
|
7
|
+
UNKNOWN_CMD_ERRORS = [Errno::ENOENT, Errno::EINVAL]
|
8
|
+
|
9
|
+
def test_unknown_command_propagates_exception
|
10
|
+
err = assert_raises(*UNKNOWN_CMD_ERRORS) { popen4ext true, UNKNOWN_CMD }
|
11
|
+
assert_match /#{UNKNOWN_CMD}/, err.to_s if on_mri?
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_exception_propagation_avoids_zombie_child_process
|
15
|
+
assert_raises(*UNKNOWN_CMD_ERRORS) { popen4ext true, UNKNOWN_CMD }
|
16
|
+
assert_empty Process.waitall
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_exit_failure
|
20
|
+
code = 43
|
21
|
+
cid, _ = popen4ext true, %{ruby -e "exit #{43}"}
|
22
|
+
assert_equal code, wait_status(cid)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_exit_success
|
26
|
+
cid, _ = popen4ext true, %{ruby -e "exit"}
|
27
|
+
assert_equal 0, wait_status(cid)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_passes_child_pid_to_block
|
31
|
+
cmd = %{ruby -e "STDOUT.print Process.pid"}
|
32
|
+
cid_in_block = nil
|
33
|
+
cid_in_fun = nil
|
34
|
+
status = popen4ext(true, cmd) do |cid, _, stdout, _|
|
35
|
+
cid_in_block = cid
|
36
|
+
cid_in_fun = stdout.read.to_i
|
37
|
+
end
|
38
|
+
assert_equal cid_in_fun, cid_in_block
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_io_pipes_without_block
|
42
|
+
via_msg = 'foo'
|
43
|
+
err_msg = 'bar'
|
44
|
+
cmd = <<-END
|
45
|
+
ruby -e "
|
46
|
+
STDOUT.write STDIN.read
|
47
|
+
STDERR.write '#{err_msg}'
|
48
|
+
"
|
49
|
+
END
|
50
|
+
cid, stdin, stdout, stderr = popen4ext true, cmd
|
51
|
+
stdin.write via_msg
|
52
|
+
stdin.close
|
53
|
+
out_actual = stdout.read
|
54
|
+
err_actual = stderr.read
|
55
|
+
assert_equal via_msg, out_actual
|
56
|
+
assert_equal err_msg, err_actual
|
57
|
+
assert_equal 0, wait_status(cid)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_io_pipes_with_block
|
61
|
+
via_msg = 'foo'
|
62
|
+
err_msg = 'bar'
|
63
|
+
out_actual, err_actual = nil
|
64
|
+
cmd = <<-END
|
65
|
+
ruby -e "
|
66
|
+
STDOUT.write STDIN.read
|
67
|
+
STDERR.write '#{err_msg}'
|
68
|
+
"
|
69
|
+
END
|
70
|
+
status = popen4ext(true, cmd) do |_, stdin, stdout, stderr|
|
71
|
+
stdin.write via_msg
|
72
|
+
stdin.close
|
73
|
+
out_actual = stdout.read
|
74
|
+
err_actual = stderr.read
|
75
|
+
end
|
76
|
+
assert_equal via_msg, out_actual
|
77
|
+
assert_equal err_msg, err_actual
|
78
|
+
assert_equal 0, status.exitstatus
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
metadata
CHANGED
@@ -1,32 +1,22 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: open4
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 1.2.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Ara T. Howard
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2011-10-05 00:00:00 Z
|
12
|
+
date: 2011-11-19 00:00:00.000000000 Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
|
-
description: "description: open4 kicks the ass"
|
14
|
+
description: ! 'description: open4 kicks the ass'
|
22
15
|
email: ara.t.howard@gmail.com
|
23
16
|
executables: []
|
24
|
-
|
25
17
|
extensions: []
|
26
|
-
|
27
18
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
files:
|
19
|
+
files:
|
30
20
|
- LICENSE
|
31
21
|
- README
|
32
22
|
- README.erb
|
@@ -44,42 +34,31 @@ files:
|
|
44
34
|
- samples/timeout.rb
|
45
35
|
- test/pfork4_test.rb
|
46
36
|
- test/popen4_test.rb
|
37
|
+
- test/popen4ext_test.rb
|
47
38
|
- test/support/test_case.rb
|
48
39
|
- white_box/leak.rb
|
49
40
|
homepage: https://github.com/ahoward/open4
|
50
41
|
licenses: []
|
51
|
-
|
52
|
-
metadata: {}
|
53
|
-
|
54
42
|
post_install_message:
|
55
43
|
rdoc_options: []
|
56
|
-
|
57
|
-
require_paths:
|
44
|
+
require_paths:
|
58
45
|
- lib
|
59
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
47
|
none: false
|
61
|
-
requirements:
|
62
|
-
- -
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
|
65
|
-
|
66
|
-
- 0
|
67
|
-
version: "0"
|
68
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
53
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
segments:
|
75
|
-
- 0
|
76
|
-
version: "0"
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
77
58
|
requirements: []
|
78
|
-
|
79
59
|
rubyforge_project: codeforpeople
|
80
|
-
rubygems_version: 1.8.
|
60
|
+
rubygems_version: 1.8.11
|
81
61
|
signing_key:
|
82
|
-
specification_version:
|
62
|
+
specification_version: 3
|
83
63
|
summary: open4
|
84
64
|
test_files: []
|
85
|
-
|