childprocess 0.5.9 → 0.6.0
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 +4 -4
- data/.document +6 -6
- data/.gitignore +25 -25
- data/.rspec +1 -1
- data/.travis.yml +20 -18
- data/CHANGELOG.md +8 -0
- data/Gemfile +11 -4
- data/LICENSE +20 -20
- data/README.md +178 -178
- data/Rakefile +61 -61
- data/childprocess.gemspec +30 -29
- data/lib/childprocess.rb +184 -177
- data/lib/childprocess/abstract_io.rb +36 -36
- data/lib/childprocess/abstract_process.rb +187 -187
- data/lib/childprocess/errors.rb +26 -26
- data/lib/childprocess/jruby.rb +56 -56
- data/lib/childprocess/jruby/io.rb +16 -16
- data/lib/childprocess/jruby/process.rb +159 -159
- data/lib/childprocess/jruby/pump.rb +52 -52
- data/lib/childprocess/tools/generator.rb +145 -145
- data/lib/childprocess/unix.rb +9 -9
- data/lib/childprocess/unix/fork_exec_process.rb +70 -70
- data/lib/childprocess/unix/io.rb +21 -21
- data/lib/childprocess/unix/lib.rb +186 -186
- data/lib/childprocess/unix/platform/i386-linux.rb +12 -12
- data/lib/childprocess/unix/platform/i386-solaris.rb +11 -11
- data/lib/childprocess/unix/platform/x86_64-linux.rb +12 -12
- data/lib/childprocess/unix/platform/x86_64-macosx.rb +11 -11
- data/lib/childprocess/unix/posix_spawn_process.rb +134 -134
- data/lib/childprocess/unix/process.rb +89 -89
- data/lib/childprocess/version.rb +3 -3
- data/lib/childprocess/windows.rb +33 -33
- data/lib/childprocess/windows/handle.rb +91 -91
- data/lib/childprocess/windows/io.rb +25 -25
- data/lib/childprocess/windows/lib.rb +415 -415
- data/lib/childprocess/windows/process.rb +129 -129
- data/lib/childprocess/windows/process_builder.rb +174 -174
- data/lib/childprocess/windows/structs.rb +148 -148
- data/spec/abstract_io_spec.rb +12 -12
- data/spec/childprocess_spec.rb +291 -256
- data/spec/io_spec.rb +228 -228
- data/spec/jruby_spec.rb +24 -24
- data/spec/pid_behavior.rb +12 -12
- data/spec/spec_helper.rb +253 -253
- data/spec/unix_spec.rb +57 -57
- data/spec/windows_spec.rb +23 -23
- metadata +47 -45
data/lib/childprocess/jruby.rb
CHANGED
@@ -1,56 +1,56 @@
|
|
1
|
-
require 'java'
|
2
|
-
require 'jruby'
|
3
|
-
|
4
|
-
class Java::SunNioCh::FileChannelImpl
|
5
|
-
field_reader :fd
|
6
|
-
end
|
7
|
-
|
8
|
-
class Java::JavaIo::FileDescriptor
|
9
|
-
if ChildProcess.os == :windows
|
10
|
-
field_reader :handle
|
11
|
-
end
|
12
|
-
|
13
|
-
field_reader :fd
|
14
|
-
end
|
15
|
-
|
16
|
-
module ChildProcess
|
17
|
-
module JRuby
|
18
|
-
def self.posix_fileno_for(obj)
|
19
|
-
channel = ::JRuby.reference(obj).channel
|
20
|
-
begin
|
21
|
-
channel.getFDVal
|
22
|
-
rescue NoMethodError
|
23
|
-
fileno = channel.fd
|
24
|
-
if fileno.kind_of?(Java::JavaIo::FileDescriptor)
|
25
|
-
fileno = fileno.fd
|
26
|
-
end
|
27
|
-
|
28
|
-
fileno == -1 ? obj.fileno : fileno
|
29
|
-
end
|
30
|
-
rescue
|
31
|
-
# fall back
|
32
|
-
obj.fileno
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.windows_handle_for(obj)
|
36
|
-
channel = ::JRuby.reference(obj).channel
|
37
|
-
fileno = obj.fileno
|
38
|
-
|
39
|
-
begin
|
40
|
-
fileno = channel.getFDVal
|
41
|
-
rescue NoMethodError
|
42
|
-
fileno = channel.fd if channel.respond_to?(:fd)
|
43
|
-
end
|
44
|
-
|
45
|
-
if fileno.kind_of? Java::JavaIo::FileDescriptor
|
46
|
-
fileno.handle
|
47
|
-
else
|
48
|
-
Windows::Lib.handle_for fileno
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
require "childprocess/jruby/pump"
|
55
|
-
require "childprocess/jruby/io"
|
56
|
-
require "childprocess/jruby/process"
|
1
|
+
require 'java'
|
2
|
+
require 'jruby'
|
3
|
+
|
4
|
+
class Java::SunNioCh::FileChannelImpl
|
5
|
+
field_reader :fd
|
6
|
+
end
|
7
|
+
|
8
|
+
class Java::JavaIo::FileDescriptor
|
9
|
+
if ChildProcess.os == :windows
|
10
|
+
field_reader :handle
|
11
|
+
end
|
12
|
+
|
13
|
+
field_reader :fd
|
14
|
+
end
|
15
|
+
|
16
|
+
module ChildProcess
|
17
|
+
module JRuby
|
18
|
+
def self.posix_fileno_for(obj)
|
19
|
+
channel = ::JRuby.reference(obj).channel
|
20
|
+
begin
|
21
|
+
channel.getFDVal
|
22
|
+
rescue NoMethodError
|
23
|
+
fileno = channel.fd
|
24
|
+
if fileno.kind_of?(Java::JavaIo::FileDescriptor)
|
25
|
+
fileno = fileno.fd
|
26
|
+
end
|
27
|
+
|
28
|
+
fileno == -1 ? obj.fileno : fileno
|
29
|
+
end
|
30
|
+
rescue
|
31
|
+
# fall back
|
32
|
+
obj.fileno
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.windows_handle_for(obj)
|
36
|
+
channel = ::JRuby.reference(obj).channel
|
37
|
+
fileno = obj.fileno
|
38
|
+
|
39
|
+
begin
|
40
|
+
fileno = channel.getFDVal
|
41
|
+
rescue NoMethodError
|
42
|
+
fileno = channel.fd if channel.respond_to?(:fd)
|
43
|
+
end
|
44
|
+
|
45
|
+
if fileno.kind_of? Java::JavaIo::FileDescriptor
|
46
|
+
fileno.handle
|
47
|
+
else
|
48
|
+
Windows::Lib.handle_for fileno
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require "childprocess/jruby/pump"
|
55
|
+
require "childprocess/jruby/io"
|
56
|
+
require "childprocess/jruby/process"
|
@@ -1,16 +1,16 @@
|
|
1
|
-
module ChildProcess
|
2
|
-
module JRuby
|
3
|
-
class IO < AbstractIO
|
4
|
-
private
|
5
|
-
|
6
|
-
def check_type(output)
|
7
|
-
unless output.respond_to?(:to_outputstream) && output.respond_to?(:write)
|
8
|
-
raise ArgumentError, "expected #{output.inspect} to respond to :to_outputstream"
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
end # IO
|
13
|
-
end # Unix
|
14
|
-
end # ChildProcess
|
15
|
-
|
16
|
-
|
1
|
+
module ChildProcess
|
2
|
+
module JRuby
|
3
|
+
class IO < AbstractIO
|
4
|
+
private
|
5
|
+
|
6
|
+
def check_type(output)
|
7
|
+
unless output.respond_to?(:to_outputstream) && output.respond_to?(:write)
|
8
|
+
raise ArgumentError, "expected #{output.inspect} to respond to :to_outputstream"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end # IO
|
13
|
+
end # Unix
|
14
|
+
end # ChildProcess
|
15
|
+
|
16
|
+
|
@@ -1,159 +1,159 @@
|
|
1
|
-
require "java"
|
2
|
-
|
3
|
-
module ChildProcess
|
4
|
-
module JRuby
|
5
|
-
class Process < AbstractProcess
|
6
|
-
def initialize(args)
|
7
|
-
super(args)
|
8
|
-
|
9
|
-
@pumps = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def io
|
13
|
-
@io ||= JRuby::IO.new
|
14
|
-
end
|
15
|
-
|
16
|
-
def exited?
|
17
|
-
return true if @exit_code
|
18
|
-
|
19
|
-
assert_started
|
20
|
-
@exit_code = @process.exitValue
|
21
|
-
stop_pumps
|
22
|
-
|
23
|
-
true
|
24
|
-
rescue java.lang.IllegalThreadStateException => ex
|
25
|
-
log(ex.class => ex.message)
|
26
|
-
false
|
27
|
-
ensure
|
28
|
-
log(:exit_code => @exit_code)
|
29
|
-
end
|
30
|
-
|
31
|
-
def stop(timeout = nil)
|
32
|
-
assert_started
|
33
|
-
|
34
|
-
@process.destroy
|
35
|
-
wait # no way to actually use the timeout here..
|
36
|
-
end
|
37
|
-
|
38
|
-
def wait
|
39
|
-
if exited?
|
40
|
-
exit_code
|
41
|
-
else
|
42
|
-
@process.waitFor
|
43
|
-
|
44
|
-
stop_pumps
|
45
|
-
@exit_code = @process.exitValue
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
#
|
50
|
-
# Only supported in JRuby on a Unix operating system, thanks to limitations
|
51
|
-
# in Java's classes
|
52
|
-
#
|
53
|
-
# @return [
|
54
|
-
# @raise [NotImplementedError] when trying to access pid on non-Unix platform
|
55
|
-
#
|
56
|
-
def pid
|
57
|
-
if @process.getClass.getName != "java.lang.UNIXProcess"
|
58
|
-
raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
|
59
|
-
end
|
60
|
-
|
61
|
-
# About the best way we can do this is with a nasty reflection-based impl
|
62
|
-
# Thanks to Martijn Courteaux
|
63
|
-
# http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
|
64
|
-
field = @process.getClass.getDeclaredField("pid")
|
65
|
-
field.accessible = true
|
66
|
-
field.get(@process)
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def launch_process(&blk)
|
72
|
-
pb = java.lang.ProcessBuilder.new(@args)
|
73
|
-
|
74
|
-
pb.directory java.io.File.new(@cwd || Dir.pwd)
|
75
|
-
set_env pb.environment
|
76
|
-
|
77
|
-
begin
|
78
|
-
@process = pb.start
|
79
|
-
rescue java.io.IOException => ex
|
80
|
-
raise LaunchError, ex.message
|
81
|
-
end
|
82
|
-
|
83
|
-
setup_io
|
84
|
-
end
|
85
|
-
|
86
|
-
def setup_io
|
87
|
-
if @io
|
88
|
-
redirect(@process.getErrorStream, @io.stderr)
|
89
|
-
redirect(@process.getInputStream, @io.stdout)
|
90
|
-
else
|
91
|
-
@process.getErrorStream.close
|
92
|
-
@process.getInputStream.close
|
93
|
-
end
|
94
|
-
|
95
|
-
if duplex?
|
96
|
-
io._stdin = create_stdin
|
97
|
-
else
|
98
|
-
@process.getOutputStream.close
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def redirect(input, output)
|
103
|
-
if output.nil?
|
104
|
-
input.close
|
105
|
-
return
|
106
|
-
end
|
107
|
-
|
108
|
-
@pumps << Pump.new(input, output.to_outputstream).run
|
109
|
-
end
|
110
|
-
|
111
|
-
def stop_pumps
|
112
|
-
@pumps.each { |pump| pump.stop }
|
113
|
-
end
|
114
|
-
|
115
|
-
def set_env(env)
|
116
|
-
merged = ENV.to_hash
|
117
|
-
|
118
|
-
@environment.each { |k, v| merged[k.to_s] = v }
|
119
|
-
|
120
|
-
merged.each do |k, v|
|
121
|
-
if v
|
122
|
-
env.put(k, v.to_s)
|
123
|
-
elsif env.has_key? k
|
124
|
-
env.remove(k)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
removed_keys = env.key_set.to_a - merged.keys
|
129
|
-
removed_keys.each { |k| env.remove(k) }
|
130
|
-
end
|
131
|
-
|
132
|
-
def create_stdin
|
133
|
-
output_stream = @process.getOutputStream
|
134
|
-
|
135
|
-
stdin = output_stream.to_io
|
136
|
-
stdin.sync = true
|
137
|
-
stdin.instance_variable_set(:@childprocess_java_stream, output_stream)
|
138
|
-
|
139
|
-
class << stdin
|
140
|
-
# The stream provided is a BufferedeOutputStream, so we
|
141
|
-
# have to flush it to make the bytes flow to the process
|
142
|
-
def __childprocess_flush__
|
143
|
-
@childprocess_java_stream.flush
|
144
|
-
end
|
145
|
-
|
146
|
-
[:flush, :print, :printf, :putc, :puts, :write, :write_nonblock].each do |m|
|
147
|
-
define_method(m) do |*args|
|
148
|
-
super(*args)
|
149
|
-
self.__childprocess_flush__
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
stdin
|
155
|
-
end
|
156
|
-
|
157
|
-
end # Process
|
158
|
-
end # JRuby
|
159
|
-
end # ChildProcess
|
1
|
+
require "java"
|
2
|
+
|
3
|
+
module ChildProcess
|
4
|
+
module JRuby
|
5
|
+
class Process < AbstractProcess
|
6
|
+
def initialize(args)
|
7
|
+
super(args)
|
8
|
+
|
9
|
+
@pumps = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def io
|
13
|
+
@io ||= JRuby::IO.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def exited?
|
17
|
+
return true if @exit_code
|
18
|
+
|
19
|
+
assert_started
|
20
|
+
@exit_code = @process.exitValue
|
21
|
+
stop_pumps
|
22
|
+
|
23
|
+
true
|
24
|
+
rescue java.lang.IllegalThreadStateException => ex
|
25
|
+
log(ex.class => ex.message)
|
26
|
+
false
|
27
|
+
ensure
|
28
|
+
log(:exit_code => @exit_code)
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop(timeout = nil)
|
32
|
+
assert_started
|
33
|
+
|
34
|
+
@process.destroy
|
35
|
+
wait # no way to actually use the timeout here..
|
36
|
+
end
|
37
|
+
|
38
|
+
def wait
|
39
|
+
if exited?
|
40
|
+
exit_code
|
41
|
+
else
|
42
|
+
@process.waitFor
|
43
|
+
|
44
|
+
stop_pumps
|
45
|
+
@exit_code = @process.exitValue
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Only supported in JRuby on a Unix operating system, thanks to limitations
|
51
|
+
# in Java's classes
|
52
|
+
#
|
53
|
+
# @return [Integer] the pid of the process after it has started
|
54
|
+
# @raise [NotImplementedError] when trying to access pid on non-Unix platform
|
55
|
+
#
|
56
|
+
def pid
|
57
|
+
if @process.getClass.getName != "java.lang.UNIXProcess"
|
58
|
+
raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
|
59
|
+
end
|
60
|
+
|
61
|
+
# About the best way we can do this is with a nasty reflection-based impl
|
62
|
+
# Thanks to Martijn Courteaux
|
63
|
+
# http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
|
64
|
+
field = @process.getClass.getDeclaredField("pid")
|
65
|
+
field.accessible = true
|
66
|
+
field.get(@process)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def launch_process(&blk)
|
72
|
+
pb = java.lang.ProcessBuilder.new(@args)
|
73
|
+
|
74
|
+
pb.directory java.io.File.new(@cwd || Dir.pwd)
|
75
|
+
set_env pb.environment
|
76
|
+
|
77
|
+
begin
|
78
|
+
@process = pb.start
|
79
|
+
rescue java.io.IOException => ex
|
80
|
+
raise LaunchError, ex.message
|
81
|
+
end
|
82
|
+
|
83
|
+
setup_io
|
84
|
+
end
|
85
|
+
|
86
|
+
def setup_io
|
87
|
+
if @io
|
88
|
+
redirect(@process.getErrorStream, @io.stderr)
|
89
|
+
redirect(@process.getInputStream, @io.stdout)
|
90
|
+
else
|
91
|
+
@process.getErrorStream.close
|
92
|
+
@process.getInputStream.close
|
93
|
+
end
|
94
|
+
|
95
|
+
if duplex?
|
96
|
+
io._stdin = create_stdin
|
97
|
+
else
|
98
|
+
@process.getOutputStream.close
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def redirect(input, output)
|
103
|
+
if output.nil?
|
104
|
+
input.close
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
@pumps << Pump.new(input, output.to_outputstream).run
|
109
|
+
end
|
110
|
+
|
111
|
+
def stop_pumps
|
112
|
+
@pumps.each { |pump| pump.stop }
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_env(env)
|
116
|
+
merged = ENV.to_hash
|
117
|
+
|
118
|
+
@environment.each { |k, v| merged[k.to_s] = v }
|
119
|
+
|
120
|
+
merged.each do |k, v|
|
121
|
+
if v
|
122
|
+
env.put(k, v.to_s)
|
123
|
+
elsif env.has_key? k
|
124
|
+
env.remove(k)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
removed_keys = env.key_set.to_a - merged.keys
|
129
|
+
removed_keys.each { |k| env.remove(k) }
|
130
|
+
end
|
131
|
+
|
132
|
+
def create_stdin
|
133
|
+
output_stream = @process.getOutputStream
|
134
|
+
|
135
|
+
stdin = output_stream.to_io
|
136
|
+
stdin.sync = true
|
137
|
+
stdin.instance_variable_set(:@childprocess_java_stream, output_stream)
|
138
|
+
|
139
|
+
class << stdin
|
140
|
+
# The stream provided is a BufferedeOutputStream, so we
|
141
|
+
# have to flush it to make the bytes flow to the process
|
142
|
+
def __childprocess_flush__
|
143
|
+
@childprocess_java_stream.flush
|
144
|
+
end
|
145
|
+
|
146
|
+
[:flush, :print, :printf, :putc, :puts, :write, :write_nonblock].each do |m|
|
147
|
+
define_method(m) do |*args|
|
148
|
+
super(*args)
|
149
|
+
self.__childprocess_flush__
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
stdin
|
155
|
+
end
|
156
|
+
|
157
|
+
end # Process
|
158
|
+
end # JRuby
|
159
|
+
end # ChildProcess
|