childprocess 4.1.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +23 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +0 -2
- data/README.md +3 -20
- data/lib/childprocess/abstract_process.rb +1 -1
- data/lib/childprocess/errors.rb +0 -21
- data/lib/childprocess/process_spawn_process.rb +127 -0
- data/lib/childprocess/unix/process.rb +3 -64
- data/lib/childprocess/unix.rb +2 -4
- data/lib/childprocess/version.rb +1 -1
- data/lib/childprocess/windows/process.rb +13 -116
- data/lib/childprocess/windows.rb +0 -29
- data/lib/childprocess.rb +16 -53
- data/spec/childprocess_spec.rb +39 -15
- data/spec/io_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -18
- data/spec/unix_spec.rb +3 -7
- metadata +8 -27
- data/.travis.yml +0 -37
- data/appveyor.yml +0 -36
- data/lib/childprocess/jruby/io.rb +0 -16
- data/lib/childprocess/jruby/process.rb +0 -184
- data/lib/childprocess/jruby/pump.rb +0 -53
- data/lib/childprocess/jruby.rb +0 -56
- data/lib/childprocess/tools/generator.rb +0 -146
- data/lib/childprocess/unix/fork_exec_process.rb +0 -78
- data/lib/childprocess/unix/lib.rb +0 -186
- data/lib/childprocess/unix/platform/arm64-macosx.rb +0 -11
- data/lib/childprocess/unix/platform/i386-linux.rb +0 -12
- data/lib/childprocess/unix/platform/i386-solaris.rb +0 -11
- data/lib/childprocess/unix/platform/x86_64-linux.rb +0 -12
- data/lib/childprocess/unix/platform/x86_64-macosx.rb +0 -11
- data/lib/childprocess/unix/posix_spawn_process.rb +0 -134
- data/lib/childprocess/windows/handle.rb +0 -91
- data/lib/childprocess/windows/lib.rb +0 -416
- data/lib/childprocess/windows/process_builder.rb +0 -178
- data/lib/childprocess/windows/structs.rb +0 -149
- data/spec/jruby_spec.rb +0 -24
data/spec/childprocess_spec.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require File.expand_path('../spec_helper', __FILE__)
|
4
|
-
require 'rubygems/mock_gem_ui'
|
5
4
|
|
6
5
|
|
7
6
|
describe ChildProcess do
|
@@ -11,12 +10,17 @@ describe ChildProcess do
|
|
11
10
|
let(:gemspec) { eval(File.read "#{here}/../childprocess.gemspec") }
|
12
11
|
|
13
12
|
it 'validates cleanly' do
|
14
|
-
|
15
|
-
|
13
|
+
if Gem::VERSION >= "3.5.0"
|
14
|
+
expect { gemspec.validate }.not_to output(/warn/i).to_stderr
|
15
|
+
else
|
16
|
+
require 'rubygems/mock_gem_ui'
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
mock_ui = Gem::MockGemUi.new
|
19
|
+
Gem::DefaultUserInteraction.use_ui(mock_ui) { gemspec.validate }
|
19
20
|
|
21
|
+
expect(mock_ui.error).to_not match(/warn/i)
|
22
|
+
end
|
23
|
+
end
|
20
24
|
|
21
25
|
it "returns self when started" do
|
22
26
|
process = sleeping_ruby
|
@@ -25,14 +29,7 @@ describe ChildProcess do
|
|
25
29
|
expect(process).to be_alive
|
26
30
|
end
|
27
31
|
|
28
|
-
|
29
|
-
# without waiting for the child to exit with code 127.
|
30
|
-
#
|
31
|
-
# See e.g. http://repo.or.cz/w/glibc.git/blob/669704fd:/sysdeps/posix/spawni.c#l34
|
32
|
-
#
|
33
|
-
# We could work around this by doing the PATH search ourselves, but not sure
|
34
|
-
# it's worth it.
|
35
|
-
it "raises ChildProcess::LaunchError if the process can't be started", :posix_spawn_on_linux => false do
|
32
|
+
it "raises ChildProcess::LaunchError if the process can't be started" do
|
36
33
|
expect { invalid_process.start }.to raise_error(ChildProcess::LaunchError)
|
37
34
|
end
|
38
35
|
|
@@ -95,7 +92,7 @@ describe ChildProcess do
|
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
98
|
-
it "can override env vars only for the
|
95
|
+
it "can override env vars only for the child process" do
|
99
96
|
Tempfile.open("env-spec") do |file|
|
100
97
|
file.close
|
101
98
|
process = write_env(file.path)
|
@@ -127,6 +124,31 @@ describe ChildProcess do
|
|
127
124
|
end
|
128
125
|
end
|
129
126
|
|
127
|
+
it "can set env vars using Symbol keys and values" do
|
128
|
+
Tempfile.open("env-spec") do |file|
|
129
|
+
process = ruby('puts ENV["SYMBOL_KEY"]')
|
130
|
+
process.environment[:SYMBOL_KEY] = :VALUE
|
131
|
+
process.io.stdout = file
|
132
|
+
process.start
|
133
|
+
process.wait
|
134
|
+
expect(rewind_and_read(file)).to eq "VALUE\n"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "raises ChildProcess::InvalidEnvironmentVariable for invalid env vars" do
|
139
|
+
process = ruby(':OK')
|
140
|
+
process.environment["a\0b"] = '1'
|
141
|
+
expect { process.start }.to raise_error(ChildProcess::InvalidEnvironmentVariable)
|
142
|
+
|
143
|
+
process = ruby(':OK')
|
144
|
+
process.environment["A=1"] = '2'
|
145
|
+
expect { process.start }.to raise_error(ChildProcess::InvalidEnvironmentVariable)
|
146
|
+
|
147
|
+
process = ruby(':OK')
|
148
|
+
process.environment['A'] = "a\0b"
|
149
|
+
expect { process.start }.to raise_error(ChildProcess::InvalidEnvironmentVariable)
|
150
|
+
end
|
151
|
+
|
130
152
|
it "inherits the parent's env vars also when some are overridden" do
|
131
153
|
Tempfile.open("env-spec") do |file|
|
132
154
|
file.close
|
@@ -277,7 +299,7 @@ describe ChildProcess do
|
|
277
299
|
}
|
278
300
|
end
|
279
301
|
|
280
|
-
it 'kills the full process tree'
|
302
|
+
it 'kills the full process tree' do
|
281
303
|
Tempfile.open('kill-process-tree') do |file|
|
282
304
|
process = write_pid_in_sleepy_grand_child(file.path)
|
283
305
|
process.leader = true
|
@@ -288,6 +310,8 @@ describe ChildProcess do
|
|
288
310
|
end
|
289
311
|
|
290
312
|
process.stop
|
313
|
+
expect(process).to be_exited
|
314
|
+
|
291
315
|
wait_until(3) { expect(alive?(pid)).to eql(false) }
|
292
316
|
end
|
293
317
|
end
|
data/spec/io_spec.rb
CHANGED
@@ -151,7 +151,7 @@ describe ChildProcess do
|
|
151
151
|
# http://travis-ci.org/#!/enkessler/childprocess/jobs/487331
|
152
152
|
#
|
153
153
|
|
154
|
-
it "works with pipes"
|
154
|
+
it "works with pipes" do
|
155
155
|
process = ruby(<<-CODE)
|
156
156
|
STDOUT.print "stdout"
|
157
157
|
STDERR.print "stderr"
|
data/spec/spec_helper.rb
CHANGED
@@ -210,16 +210,9 @@ module ChildProcessSpecHelper
|
|
210
210
|
end
|
211
211
|
|
212
212
|
def alive?(pid)
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
begin
|
217
|
-
Process.getpgid pid
|
218
|
-
true
|
219
|
-
rescue Errno::ESRCH
|
220
|
-
false
|
221
|
-
end
|
222
|
-
end
|
213
|
+
!!Process.kill(0, pid)
|
214
|
+
rescue Errno::ESRCH
|
215
|
+
false
|
223
216
|
end
|
224
217
|
|
225
218
|
def capture_std
|
@@ -259,12 +252,4 @@ RSpec.configure do |c|
|
|
259
252
|
c.after(:each) {
|
260
253
|
defined?(@process) && @process.alive? && @process.stop
|
261
254
|
}
|
262
|
-
|
263
|
-
if ChildProcess.jruby? && ChildProcess.new("true").instance_of?(ChildProcess::JRuby::Process)
|
264
|
-
c.filter_run_excluding :process_builder => false
|
265
|
-
end
|
266
|
-
|
267
|
-
if ChildProcess.linux? && ChildProcess.posix_spawn?
|
268
|
-
c.filter_run_excluding :posix_spawn_on_linux => false
|
269
|
-
end
|
270
255
|
end
|
data/spec/unix_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path('../spec_helper', __FILE__)
|
2
2
|
require "pid_behavior"
|
3
3
|
|
4
|
-
if ChildProcess.unix?
|
4
|
+
if ChildProcess.unix?
|
5
5
|
|
6
6
|
describe ChildProcess::Unix::Process do
|
7
7
|
it_behaves_like "a platform that provides the child's pid"
|
@@ -9,7 +9,7 @@ if ChildProcess.unix? && !ChildProcess.jruby? && !ChildProcess.posix_spawn?
|
|
9
9
|
it "handles ECHILD race condition where process dies between timeout and KILL" do
|
10
10
|
process = sleeping_ruby
|
11
11
|
|
12
|
-
allow(
|
12
|
+
allow(Process).to receive(:spawn).and_return('fakepid')
|
13
13
|
allow(process).to receive(:send_term)
|
14
14
|
allow(process).to receive(:poll_for_exit).and_raise(ChildProcess::TimeoutError)
|
15
15
|
allow(process).to receive(:send_kill).and_raise(Errno::ECHILD.new)
|
@@ -18,14 +18,12 @@ if ChildProcess.unix? && !ChildProcess.jruby? && !ChildProcess.posix_spawn?
|
|
18
18
|
expect { process.stop }.not_to raise_error
|
19
19
|
|
20
20
|
allow(process).to receive(:alive?).and_return(false)
|
21
|
-
|
22
|
-
process.send(:send_signal, 'TERM')
|
23
21
|
end
|
24
22
|
|
25
23
|
it "handles ESRCH race condition where process dies between timeout and KILL" do
|
26
24
|
process = sleeping_ruby
|
27
25
|
|
28
|
-
allow(
|
26
|
+
allow(Process).to receive(:spawn).and_return('fakepid')
|
29
27
|
allow(process).to receive(:send_term)
|
30
28
|
allow(process).to receive(:poll_for_exit).and_raise(ChildProcess::TimeoutError)
|
31
29
|
allow(process).to receive(:send_kill).and_raise(Errno::ESRCH.new)
|
@@ -34,8 +32,6 @@ if ChildProcess.unix? && !ChildProcess.jruby? && !ChildProcess.posix_spawn?
|
|
34
32
|
expect { process.stop }.not_to raise_error
|
35
33
|
|
36
34
|
allow(process).to receive(:alive?).and_return(false)
|
37
|
-
|
38
|
-
process.send(:send_signal, 'TERM')
|
39
35
|
end
|
40
36
|
end
|
41
37
|
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: childprocess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jari Bakken
|
8
8
|
- Eric Kessler
|
9
9
|
- Shane da Silva
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2024-01-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -64,49 +64,31 @@ extensions: []
|
|
64
64
|
extra_rdoc_files: []
|
65
65
|
files:
|
66
66
|
- ".document"
|
67
|
+
- ".github/workflows/ci.yml"
|
67
68
|
- ".gitignore"
|
68
69
|
- ".rspec"
|
69
|
-
- ".travis.yml"
|
70
70
|
- CHANGELOG.md
|
71
71
|
- Gemfile
|
72
72
|
- LICENSE
|
73
73
|
- README.md
|
74
74
|
- Rakefile
|
75
|
-
- appveyor.yml
|
76
75
|
- childprocess.gemspec
|
77
76
|
- lib/childprocess.rb
|
78
77
|
- lib/childprocess/abstract_io.rb
|
79
78
|
- lib/childprocess/abstract_process.rb
|
80
79
|
- lib/childprocess/errors.rb
|
81
|
-
- lib/childprocess/
|
82
|
-
- lib/childprocess/jruby/io.rb
|
83
|
-
- lib/childprocess/jruby/process.rb
|
84
|
-
- lib/childprocess/jruby/pump.rb
|
85
|
-
- lib/childprocess/tools/generator.rb
|
80
|
+
- lib/childprocess/process_spawn_process.rb
|
86
81
|
- lib/childprocess/unix.rb
|
87
|
-
- lib/childprocess/unix/fork_exec_process.rb
|
88
82
|
- lib/childprocess/unix/io.rb
|
89
|
-
- lib/childprocess/unix/lib.rb
|
90
|
-
- lib/childprocess/unix/platform/arm64-macosx.rb
|
91
|
-
- lib/childprocess/unix/platform/i386-linux.rb
|
92
|
-
- lib/childprocess/unix/platform/i386-solaris.rb
|
93
|
-
- lib/childprocess/unix/platform/x86_64-linux.rb
|
94
|
-
- lib/childprocess/unix/platform/x86_64-macosx.rb
|
95
|
-
- lib/childprocess/unix/posix_spawn_process.rb
|
96
83
|
- lib/childprocess/unix/process.rb
|
97
84
|
- lib/childprocess/version.rb
|
98
85
|
- lib/childprocess/windows.rb
|
99
|
-
- lib/childprocess/windows/handle.rb
|
100
86
|
- lib/childprocess/windows/io.rb
|
101
|
-
- lib/childprocess/windows/lib.rb
|
102
87
|
- lib/childprocess/windows/process.rb
|
103
|
-
- lib/childprocess/windows/process_builder.rb
|
104
|
-
- lib/childprocess/windows/structs.rb
|
105
88
|
- spec/abstract_io_spec.rb
|
106
89
|
- spec/childprocess_spec.rb
|
107
90
|
- spec/get_env.ps1
|
108
91
|
- spec/io_spec.rb
|
109
|
-
- spec/jruby_spec.rb
|
110
92
|
- spec/pid_behavior.rb
|
111
93
|
- spec/platform_detection_spec.rb
|
112
94
|
- spec/spec_helper.rb
|
@@ -116,7 +98,7 @@ homepage: https://github.com/enkessler/childprocess
|
|
116
98
|
licenses:
|
117
99
|
- MIT
|
118
100
|
metadata: {}
|
119
|
-
post_install_message:
|
101
|
+
post_install_message:
|
120
102
|
rdoc_options: []
|
121
103
|
require_paths:
|
122
104
|
- lib
|
@@ -131,8 +113,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
113
|
- !ruby/object:Gem::Version
|
132
114
|
version: '0'
|
133
115
|
requirements: []
|
134
|
-
rubygems_version: 3.1
|
135
|
-
signing_key:
|
116
|
+
rubygems_version: 3.0.3.1
|
117
|
+
signing_key:
|
136
118
|
specification_version: 4
|
137
119
|
summary: A simple and reliable solution for controlling external programs running
|
138
120
|
in the background on any Ruby / OS combination.
|
@@ -141,7 +123,6 @@ test_files:
|
|
141
123
|
- spec/childprocess_spec.rb
|
142
124
|
- spec/get_env.ps1
|
143
125
|
- spec/io_spec.rb
|
144
|
-
- spec/jruby_spec.rb
|
145
126
|
- spec/pid_behavior.rb
|
146
127
|
- spec/platform_detection_spec.rb
|
147
128
|
- spec/spec_helper.rb
|
data/.travis.yml
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
os:
|
2
|
-
- linux
|
3
|
-
- osx
|
4
|
-
|
5
|
-
rvm:
|
6
|
-
- rbx-3
|
7
|
-
- 2.4
|
8
|
-
- 2.5
|
9
|
-
- 2.6
|
10
|
-
- ruby-head
|
11
|
-
|
12
|
-
sudo: false
|
13
|
-
|
14
|
-
cache: bundler
|
15
|
-
|
16
|
-
before_install:
|
17
|
-
- "echo 'gem: --no-document' > ~/.gemrc"
|
18
|
-
- gem install bundler
|
19
|
-
|
20
|
-
before_script:
|
21
|
-
- 'export JAVA_OPTS="${JAVA_OPTS_FOR_SPECS}"'
|
22
|
-
|
23
|
-
env:
|
24
|
-
global:
|
25
|
-
matrix:
|
26
|
-
- CHILDPROCESS_POSIX_SPAWN=true CHILDPROCESS_UNSET=should-be-unset
|
27
|
-
- CHILDPROCESS_POSIX_SPAWN=false CHILDPROCESS_UNSET=should-be-unset
|
28
|
-
|
29
|
-
matrix:
|
30
|
-
allow_failures:
|
31
|
-
- rvm: rbx-3
|
32
|
-
- rvm: ruby-head
|
33
|
-
- env: "CHILDPROCESS_POSIX_SPAWN=true"
|
34
|
-
include:
|
35
|
-
- rvm: jruby-9.2.5.0
|
36
|
-
jdk: openjdk11
|
37
|
-
env: "JAVA_OPTS_FOR_SPECS='--add-opens java.base/java.io=org.jruby.dist --add-opens java.base/sun.nio.ch=org.jruby.dist'"
|
data/appveyor.yml
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
version: '1.0.{build}'
|
2
|
-
|
3
|
-
environment:
|
4
|
-
matrix:
|
5
|
-
- CHILDPROCESS_POSIX_SPAWN: true
|
6
|
-
CHILDPROCESS_UNSET: should-be-unset
|
7
|
-
RUBY_VERSION: 24-x64
|
8
|
-
- CHILDPROCESS_POSIX_SPAWN: false
|
9
|
-
CHILDPROCESS_UNSET: should-be-unset
|
10
|
-
RUBY_VERSION: 24-x64
|
11
|
-
- CHILDPROCESS_POSIX_SPAWN: true
|
12
|
-
CHILDPROCESS_UNSET: should-be-unset
|
13
|
-
RUBY_VERSION: 25-x64
|
14
|
-
- CHILDPROCESS_POSIX_SPAWN: false
|
15
|
-
CHILDPROCESS_UNSET: should-be-unset
|
16
|
-
RUBY_VERSION: 25-x64
|
17
|
-
- CHILDPROCESS_POSIX_SPAWN: true
|
18
|
-
CHILDPROCESS_UNSET: should-be-unset
|
19
|
-
RUBY_VERSION: 26-x64
|
20
|
-
- CHILDPROCESS_POSIX_SPAWN: false
|
21
|
-
CHILDPROCESS_UNSET: should-be-unset
|
22
|
-
RUBY_VERSION: 26-x64
|
23
|
-
|
24
|
-
install:
|
25
|
-
- set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH%
|
26
|
-
- bundle install
|
27
|
-
|
28
|
-
build: off
|
29
|
-
|
30
|
-
before_test:
|
31
|
-
- ruby -v
|
32
|
-
- gem -v
|
33
|
-
- bundle -v
|
34
|
-
|
35
|
-
test_script:
|
36
|
-
- bundle exec rake
|
@@ -1,16 +0,0 @@
|
|
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,184 +0,0 @@
|
|
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
|
-
# Implementation of ChildProcess::JRuby::Process#pid depends heavily on
|
50
|
-
# what Java SDK is being used; here, we look it up once at load, then
|
51
|
-
# define the method once to avoid runtime overhead.
|
52
|
-
normalised_java_version_major = java.lang.System.get_property("java.version")
|
53
|
-
.slice(/^(1\.)?([0-9]+)/, 2)
|
54
|
-
.to_i
|
55
|
-
if normalised_java_version_major >= 9
|
56
|
-
|
57
|
-
# On modern Javas, we can simply delegate through to `Process#pid`,
|
58
|
-
# which was introduced in Java 9.
|
59
|
-
#
|
60
|
-
# @return [Integer] the pid of the process after it has started
|
61
|
-
# @raise [NotImplementedError] when trying to access pid on platform for
|
62
|
-
# which it is unsupported in Java
|
63
|
-
def pid
|
64
|
-
@process.pid
|
65
|
-
rescue java.lang.UnsupportedOperationException => e
|
66
|
-
raise NotImplementedError, "pid is not supported on this platform: #{e.message}"
|
67
|
-
end
|
68
|
-
|
69
|
-
else
|
70
|
-
|
71
|
-
# On Legacy Javas, fall back to reflection.
|
72
|
-
#
|
73
|
-
# Only supported in JRuby on a Unix operating system, thanks to limitations
|
74
|
-
# in Java's classes
|
75
|
-
#
|
76
|
-
# @return [Integer] the pid of the process after it has started
|
77
|
-
# @raise [NotImplementedError] when trying to access pid on non-Unix platform
|
78
|
-
#
|
79
|
-
def pid
|
80
|
-
if @process.getClass.getName != "java.lang.UNIXProcess"
|
81
|
-
raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
|
82
|
-
end
|
83
|
-
|
84
|
-
# About the best way we can do this is with a nasty reflection-based impl
|
85
|
-
# Thanks to Martijn Courteaux
|
86
|
-
# http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
|
87
|
-
field = @process.getClass.getDeclaredField("pid")
|
88
|
-
field.accessible = true
|
89
|
-
field.get(@process)
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def launch_process(&blk)
|
97
|
-
pb = java.lang.ProcessBuilder.new(@args)
|
98
|
-
|
99
|
-
pb.directory java.io.File.new(@cwd || Dir.pwd)
|
100
|
-
set_env pb.environment
|
101
|
-
|
102
|
-
begin
|
103
|
-
@process = pb.start
|
104
|
-
rescue java.io.IOException => ex
|
105
|
-
raise LaunchError, ex.message
|
106
|
-
end
|
107
|
-
|
108
|
-
setup_io
|
109
|
-
end
|
110
|
-
|
111
|
-
def setup_io
|
112
|
-
if @io
|
113
|
-
redirect(@process.getErrorStream, @io.stderr)
|
114
|
-
redirect(@process.getInputStream, @io.stdout)
|
115
|
-
else
|
116
|
-
@process.getErrorStream.close
|
117
|
-
@process.getInputStream.close
|
118
|
-
end
|
119
|
-
|
120
|
-
if duplex?
|
121
|
-
io._stdin = create_stdin
|
122
|
-
else
|
123
|
-
@process.getOutputStream.close
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def redirect(input, output)
|
128
|
-
if output.nil?
|
129
|
-
input.close
|
130
|
-
return
|
131
|
-
end
|
132
|
-
|
133
|
-
@pumps << Pump.new(input, output.to_outputstream).run
|
134
|
-
end
|
135
|
-
|
136
|
-
def stop_pumps
|
137
|
-
@pumps.each { |pump| pump.stop }
|
138
|
-
end
|
139
|
-
|
140
|
-
def set_env(env)
|
141
|
-
merged = ENV.to_hash
|
142
|
-
|
143
|
-
@environment.each { |k, v| merged[k.to_s] = v }
|
144
|
-
|
145
|
-
merged.each do |k, v|
|
146
|
-
if v
|
147
|
-
env.put(k, v.to_s)
|
148
|
-
elsif env.has_key? k
|
149
|
-
env.remove(k)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
removed_keys = env.key_set.to_a - merged.keys
|
154
|
-
removed_keys.each { |k| env.remove(k) }
|
155
|
-
end
|
156
|
-
|
157
|
-
def create_stdin
|
158
|
-
output_stream = @process.getOutputStream
|
159
|
-
|
160
|
-
stdin = output_stream.to_io
|
161
|
-
stdin.sync = true
|
162
|
-
stdin.instance_variable_set(:@childprocess_java_stream, output_stream)
|
163
|
-
|
164
|
-
class << stdin
|
165
|
-
# The stream provided is a BufferedeOutputStream, so we
|
166
|
-
# have to flush it to make the bytes flow to the process
|
167
|
-
def __childprocess_flush__
|
168
|
-
@childprocess_java_stream.flush
|
169
|
-
end
|
170
|
-
|
171
|
-
[:flush, :print, :printf, :putc, :puts, :write, :write_nonblock].each do |m|
|
172
|
-
define_method(m) do |*args|
|
173
|
-
super(*args)
|
174
|
-
self.__childprocess_flush__
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
stdin
|
180
|
-
end
|
181
|
-
|
182
|
-
end # Process
|
183
|
-
end # JRuby
|
184
|
-
end # ChildProcess
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module ChildProcess
|
2
|
-
module JRuby
|
3
|
-
class Pump
|
4
|
-
BUFFER_SIZE = 2048
|
5
|
-
|
6
|
-
def initialize(input, output)
|
7
|
-
@input = input
|
8
|
-
@output = output
|
9
|
-
@stop = false
|
10
|
-
end
|
11
|
-
|
12
|
-
def stop
|
13
|
-
@stop = true
|
14
|
-
@thread && @thread.join
|
15
|
-
end
|
16
|
-
|
17
|
-
def run
|
18
|
-
@thread = Thread.new { pump }
|
19
|
-
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def pump
|
26
|
-
buffer = Java.byte[BUFFER_SIZE].new
|
27
|
-
|
28
|
-
until @stop && (@input.available == 0)
|
29
|
-
read, avail = 0, 0
|
30
|
-
|
31
|
-
while read != -1
|
32
|
-
avail = [@input.available, 1].max
|
33
|
-
avail = BUFFER_SIZE if avail > BUFFER_SIZE
|
34
|
-
read = @input.read(buffer, 0, avail)
|
35
|
-
|
36
|
-
if read > 0
|
37
|
-
@output.write(buffer, 0, read)
|
38
|
-
@output.flush
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
sleep 0.1
|
43
|
-
end
|
44
|
-
|
45
|
-
@output.flush
|
46
|
-
rescue java.io.IOException => ex
|
47
|
-
ChildProcess.logger.debug ex.message
|
48
|
-
ChildProcess.logger.debug ex.backtrace
|
49
|
-
end
|
50
|
-
|
51
|
-
end # Pump
|
52
|
-
end # JRuby
|
53
|
-
end # ChildProcess
|
data/lib/childprocess/jruby.rb
DELETED
@@ -1,56 +0,0 @@
|
|
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"
|