childprocess 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +23 -0
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile +0 -14
  5. data/README.md +3 -20
  6. data/childprocess.gemspec +1 -1
  7. data/lib/childprocess/abstract_process.rb +1 -1
  8. data/lib/childprocess/errors.rb +0 -21
  9. data/lib/childprocess/process_spawn_process.rb +127 -0
  10. data/lib/childprocess/unix/process.rb +3 -64
  11. data/lib/childprocess/unix.rb +2 -4
  12. data/lib/childprocess/version.rb +1 -1
  13. data/lib/childprocess/windows/process.rb +13 -116
  14. data/lib/childprocess/windows.rb +0 -29
  15. data/lib/childprocess.rb +16 -53
  16. data/spec/childprocess_spec.rb +40 -16
  17. data/spec/io_spec.rb +2 -2
  18. data/spec/spec_helper.rb +3 -18
  19. data/spec/unix_spec.rb +3 -7
  20. metadata +6 -24
  21. data/.travis.yml +0 -37
  22. data/appveyor.yml +0 -36
  23. data/lib/childprocess/jruby/io.rb +0 -16
  24. data/lib/childprocess/jruby/process.rb +0 -184
  25. data/lib/childprocess/jruby/pump.rb +0 -53
  26. data/lib/childprocess/jruby.rb +0 -56
  27. data/lib/childprocess/tools/generator.rb +0 -146
  28. data/lib/childprocess/unix/fork_exec_process.rb +0 -78
  29. data/lib/childprocess/unix/lib.rb +0 -186
  30. data/lib/childprocess/unix/platform/i386-linux.rb +0 -12
  31. data/lib/childprocess/unix/platform/i386-solaris.rb +0 -11
  32. data/lib/childprocess/unix/platform/x86_64-linux.rb +0 -12
  33. data/lib/childprocess/unix/platform/x86_64-macosx.rb +0 -11
  34. data/lib/childprocess/unix/posix_spawn_process.rb +0 -134
  35. data/lib/childprocess/windows/handle.rb +0 -91
  36. data/lib/childprocess/windows/lib.rb +0 -416
  37. data/lib/childprocess/windows/process_builder.rb +0 -178
  38. data/lib/childprocess/windows/structs.rb +0 -149
  39. data/spec/jruby_spec.rb +0 -24
data/lib/childprocess.rb CHANGED
@@ -2,6 +2,7 @@ require 'childprocess/version'
2
2
  require 'childprocess/errors'
3
3
  require 'childprocess/abstract_process'
4
4
  require 'childprocess/abstract_io'
5
+ require 'childprocess/process_spawn_process'
5
6
  require "fcntl"
6
7
  require 'logger'
7
8
 
@@ -15,15 +16,9 @@ module ChildProcess
15
16
  def new(*args)
16
17
  case os
17
18
  when :macosx, :linux, :solaris, :bsd, :cygwin, :aix
18
- if posix_spawn?
19
- Unix::PosixSpawnProcess.new(args)
20
- elsif jruby?
21
- JRuby::Process.new(args)
22
- else
23
- Unix::ForkExecProcess.new(args)
24
- end
19
+ Unix::Process.new(*args)
25
20
  when :windows
26
- Windows::Process.new(args)
21
+ Windows::Process.new(*args)
27
22
  else
28
23
  raise Error, "unsupported platform #{platform_name.inspect}"
29
24
  end
@@ -40,13 +35,7 @@ module ChildProcess
40
35
  end
41
36
 
42
37
  def platform
43
- if RUBY_PLATFORM == "java"
44
- :jruby
45
- elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == "ironruby"
46
- :ironruby
47
- else
48
- os
49
- end
38
+ os
50
39
  end
51
40
 
52
41
  def platform_name
@@ -62,35 +51,18 @@ module ChildProcess
62
51
  end
63
52
 
64
53
  def jruby?
65
- platform == :jruby
54
+ RUBY_ENGINE == 'jruby'
66
55
  end
67
56
 
68
57
  def windows?
69
58
  os == :windows
70
59
  end
71
60
 
72
- def posix_spawn?
73
- enabled = @posix_spawn || %w[1 true].include?(ENV['CHILDPROCESS_POSIX_SPAWN'])
74
- return false unless enabled
75
-
76
- begin
77
- require 'ffi'
78
- rescue LoadError
79
- raise ChildProcess::MissingFFIError
80
- end
81
-
82
- begin
83
- require "childprocess/unix/platform/#{ChildProcess.platform_name}"
84
- rescue LoadError
85
- raise ChildProcess::MissingPlatformError
86
- end
87
-
88
- require "childprocess/unix/lib"
89
- require 'childprocess/unix/posix_spawn_process'
61
+ def posix_spawn_chosen_explicitly?
62
+ @posix_spawn || %w[1 true].include?(ENV['CHILDPROCESS_POSIX_SPAWN'])
63
+ end
90
64
 
91
- true
92
- rescue ChildProcess::MissingPlatformError => ex
93
- warn_once ex.message
65
+ def posix_spawn?
94
66
  false
95
67
  end
96
68
 
@@ -103,6 +75,8 @@ module ChildProcess
103
75
  end
104
76
 
105
77
  def os
78
+ return :windows if ENV['FAKE_WINDOWS'] == 'true'
79
+
106
80
  @os ||= (
107
81
  require "rbconfig"
108
82
  host_os = RbConfig::CONFIG['host_os'].downcase
@@ -158,17 +132,6 @@ module ChildProcess
158
132
  def close_on_exec(file)
159
133
  if file.respond_to?(:close_on_exec=)
160
134
  file.close_on_exec = true
161
- elsif file.respond_to?(:fcntl) && defined?(Fcntl::FD_CLOEXEC)
162
- file.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
163
-
164
- if jruby? && posix_spawn?
165
- # on JRuby, the fcntl call above apparently isn't enough when
166
- # we're launching the process through posix_spawn.
167
- fileno = JRuby.posix_fileno_for(file)
168
- Unix::Lib.fcntl fileno, Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
169
- end
170
- elsif windows?
171
- Windows::Lib.dont_inherit file
172
135
  else
173
136
  raise Error, "not sure how to set close-on-exec for #{file.inspect} on #{platform_name.inspect}"
174
137
  end
@@ -203,8 +166,8 @@ module ChildProcess
203
166
  end # class << self
204
167
  end # ChildProcess
205
168
 
206
- require 'jruby' if ChildProcess.jruby?
207
-
208
- require 'childprocess/unix' if ChildProcess.unix?
209
- require 'childprocess/windows' if ChildProcess.windows?
210
- require 'childprocess/jruby' if ChildProcess.jruby?
169
+ if ChildProcess.windows?
170
+ require 'childprocess/windows'
171
+ else
172
+ require 'childprocess/unix'
173
+ end
@@ -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
- mock_ui = Gem::MockGemUi.new
15
- Gem::DefaultUserInteraction.use_ui(mock_ui) { gemspec.validate }
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
- expect(mock_ui.error).to_not match(/warn/i)
18
- end
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
- # We can't detect failure to execve() when using posix_spawn() on Linux
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 current process" do
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
@@ -195,7 +217,7 @@ describe ChildProcess do
195
217
 
196
218
  Tempfile.open('grandparent_out') do |gp_file|
197
219
  # Create a parent and detached child process that will spit out their PID. Make sure that the child process lasts longer than the parent.
198
- p_process = ruby("require 'childprocess' ; c_process = ChildProcess.build('ruby', '-e', 'puts \\\"Child PID: \#{Process.pid}\\\" ; sleep 5') ; c_process.io.inherit! ; c_process.detach = true ; c_process.start ; puts \"Child PID: \#{c_process.pid}\" ; puts \"Parent PID: \#{Process.pid}\"")
220
+ p_process = ruby("$: << 'lib'; require 'childprocess' ; c_process = ChildProcess.build('ruby', '-e', 'puts \\\"Child PID: \#{Process.pid}\\\" ; sleep 5') ; c_process.io.inherit! ; c_process.detach = true ; c_process.start ; puts \"Child PID: \#{c_process.pid}\" ; puts \"Parent PID: \#{Process.pid}\"")
199
221
  p_process.io.stdout = p_process.io.stderr = gp_file
200
222
 
201
223
  # Let the parent process die
@@ -277,7 +299,7 @@ describe ChildProcess do
277
299
  }
278
300
  end
279
301
 
280
- it 'kills the full process tree', :process_builder => false do
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
@@ -138,7 +138,7 @@ describe ChildProcess do
138
138
 
139
139
  stdin.close
140
140
  process.poll_for_exit(exit_timeout)
141
- ensure
141
+ ensure
142
142
  out_receiver.close
143
143
  out.close
144
144
  end
@@ -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", :process_builder => false do
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
- if ChildProcess.windows?
214
- ChildProcess::Windows::Lib.alive?(pid)
215
- else
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? && !ChildProcess.jruby? && !ChildProcess.posix_spawn?
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(process).to receive(:fork).and_return('fakepid')
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(process).to receive(:fork).and_return('fakepid')
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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: childprocess
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jari Bakken
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-06-18 00:00:00.000000000 Z
13
+ date: 2024-01-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -64,54 +64,37 @@ 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/jruby.rb
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/i386-linux.rb
91
- - lib/childprocess/unix/platform/i386-solaris.rb
92
- - lib/childprocess/unix/platform/x86_64-linux.rb
93
- - lib/childprocess/unix/platform/x86_64-macosx.rb
94
- - lib/childprocess/unix/posix_spawn_process.rb
95
83
  - lib/childprocess/unix/process.rb
96
84
  - lib/childprocess/version.rb
97
85
  - lib/childprocess/windows.rb
98
- - lib/childprocess/windows/handle.rb
99
86
  - lib/childprocess/windows/io.rb
100
- - lib/childprocess/windows/lib.rb
101
87
  - lib/childprocess/windows/process.rb
102
- - lib/childprocess/windows/process_builder.rb
103
- - lib/childprocess/windows/structs.rb
104
88
  - spec/abstract_io_spec.rb
105
89
  - spec/childprocess_spec.rb
106
90
  - spec/get_env.ps1
107
91
  - spec/io_spec.rb
108
- - spec/jruby_spec.rb
109
92
  - spec/pid_behavior.rb
110
93
  - spec/platform_detection_spec.rb
111
94
  - spec/spec_helper.rb
112
95
  - spec/unix_spec.rb
113
96
  - spec/windows_spec.rb
114
- homepage: http://github.com/enkessler/childprocess
97
+ homepage: https://github.com/enkessler/childprocess
115
98
  licenses:
116
99
  - MIT
117
100
  metadata: {}
@@ -130,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
113
  - !ruby/object:Gem::Version
131
114
  version: '0'
132
115
  requirements: []
133
- rubygems_version: 3.1.1
116
+ rubygems_version: 3.0.3.1
134
117
  signing_key:
135
118
  specification_version: 4
136
119
  summary: A simple and reliable solution for controlling external programs running
@@ -140,7 +123,6 @@ test_files:
140
123
  - spec/childprocess_spec.rb
141
124
  - spec/get_env.ps1
142
125
  - spec/io_spec.rb
143
- - spec/jruby_spec.rb
144
126
  - spec/pid_behavior.rb
145
127
  - spec/platform_detection_spec.rb
146
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