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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b5d923affd397c31cc2193e6dc9d6e1a6d32e485f3721210e65caf72b9ee138
|
4
|
+
data.tar.gz: '06896c2aa64a9c521b45206d1a0638a8aa63e433a013c261909a920fab135c75'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0a5d3cfee92a6e4896eaf557dbf4fc50d54b54d42c43033776165991b1b606f12ccd1e17d0dbe26963b7d002482ee40877b3ea024765b371393e4a0cbd0343f
|
7
|
+
data.tar.gz: 6814491e59bbb30b61393670ca84d5da9d61ea5cb5dbc54a45599ef9cb7318bbf82751fddaf5c7ee5ef501718d7cad4a08636fab3a379148899af3acd0303bd4
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: CI
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
strategy:
|
6
|
+
fail-fast: false
|
7
|
+
matrix:
|
8
|
+
os: [ ubuntu, macos, windows ]
|
9
|
+
ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', jruby, truffleruby ]
|
10
|
+
exclude:
|
11
|
+
- { os: windows, ruby: truffleruby }
|
12
|
+
# fails to load rspec: RuntimeError: CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before false -> after true
|
13
|
+
- { os: windows, ruby: jruby }
|
14
|
+
runs-on: ${{ matrix.os }}-latest
|
15
|
+
env:
|
16
|
+
CHILDPROCESS_UNSET: should-be-unset
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: ${{ matrix.ruby }}
|
22
|
+
bundler-cache: true
|
23
|
+
- run: bundle exec rake spec
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### Version 5.0.0 / 2024-01-06
|
2
|
+
|
3
|
+
* [#175](https://github.com/enkessler/childprocess/pull/175): Replace all backends by `Process.spawn` for portability, reliability and simplicity.
|
4
|
+
* [#185](https://github.com/enkessler/childprocess/pull/185): Add support for Ruby 3.x
|
5
|
+
|
1
6
|
### Version 4.1.0 / 2021-06-08
|
2
7
|
|
3
8
|
* [#170](https://github.com/enkessler/childprocess/pull/170): Update gem homepage to use `https://`
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -16,8 +16,6 @@ a standalone library.
|
|
16
16
|
|
17
17
|
* Ruby 2.4+, JRuby 9+
|
18
18
|
|
19
|
-
Windows users **must** ensure the `ffi` gem (`>= 1.0.11`) is installed in order to use ChildProcess.
|
20
|
-
|
21
19
|
# Usage
|
22
20
|
|
23
21
|
The object returned from `ChildProcess.build` will implement `ChildProcess::AbstractProcess`.
|
@@ -73,9 +71,9 @@ begin
|
|
73
71
|
process = ChildProcess.build("sh" , "-c",
|
74
72
|
"for i in {1..3}; do echo $i; sleep 1; done")
|
75
73
|
process.io.stdout = w
|
76
|
-
process.start # This results in a
|
74
|
+
process.start # This results in a subprocess inheriting the write end of the pipe.
|
77
75
|
|
78
|
-
# Close parent's copy of the write end of the pipe so when the
|
76
|
+
# Close parent's copy of the write end of the pipe so when the child
|
79
77
|
# process closes its write end of the pipe the parent receives EOF when
|
80
78
|
# attempting to read from it. If the parent leaves its write end open, it
|
81
79
|
# will not detect EOF.
|
@@ -138,17 +136,6 @@ search.io.stdin.close
|
|
138
136
|
search.wait
|
139
137
|
```
|
140
138
|
|
141
|
-
#### Prefer posix_spawn on *nix
|
142
|
-
|
143
|
-
If the parent process is using a lot of memory, `fork+exec` can be very expensive. The `posix_spawn()` API removes this overhead.
|
144
|
-
|
145
|
-
```ruby
|
146
|
-
ChildProcess.posix_spawn = true
|
147
|
-
process = ChildProcess.build(*args)
|
148
|
-
```
|
149
|
-
|
150
|
-
To be able to use this, please make sure that you have the `ffi` gem installed.
|
151
|
-
|
152
139
|
### Ensure entire process tree dies
|
153
140
|
|
154
141
|
By default, the child process does not create a new process group. This means there's no guarantee that the entire process tree will die when the child process is killed. To solve this:
|
@@ -195,11 +182,7 @@ ChildProcess.logger = logger
|
|
195
182
|
|
196
183
|
# Implementation
|
197
184
|
|
198
|
-
|
199
|
-
|
200
|
-
* Unix : `fork + exec` (or `posix_spawn` if enabled)
|
201
|
-
* Windows : `CreateProcess()` and friends
|
202
|
-
* JRuby : `java.lang.{Process,ProcessBuilder}`
|
185
|
+
ChildProcess 5+ uses `Process.spawn` from the Ruby core library for maximum portability.
|
203
186
|
|
204
187
|
# Note on Patches/Pull Requests
|
205
188
|
|
data/lib/childprocess/errors.rb
CHANGED
@@ -13,25 +13,4 @@ module ChildProcess
|
|
13
13
|
|
14
14
|
class LaunchError < Error
|
15
15
|
end
|
16
|
-
|
17
|
-
class MissingFFIError < Error
|
18
|
-
def initialize
|
19
|
-
message = "FFI is a required pre-requisite for Windows or posix_spawn support in the ChildProcess gem. " +
|
20
|
-
"Ensure the `ffi` gem is installed. " +
|
21
|
-
"If you believe this is an error, please file a bug at http://github.com/enkessler/childprocess/issues"
|
22
|
-
|
23
|
-
super(message)
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
class MissingPlatformError < Error
|
29
|
-
def initialize
|
30
|
-
message = "posix_spawn is not yet supported on #{ChildProcess.platform_name} (#{RUBY_PLATFORM}), falling back to default implementation. " +
|
31
|
-
"If you believe this is an error, please file a bug at http://github.com/enkessler/childprocess/issues"
|
32
|
-
|
33
|
-
super(message)
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
16
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require_relative 'abstract_process'
|
2
|
+
|
3
|
+
module ChildProcess
|
4
|
+
class ProcessSpawnProcess < AbstractProcess
|
5
|
+
attr_reader :pid
|
6
|
+
|
7
|
+
def exited?
|
8
|
+
return true if @exit_code
|
9
|
+
|
10
|
+
assert_started
|
11
|
+
pid, status = ::Process.waitpid2(@pid, ::Process::WNOHANG | ::Process::WUNTRACED)
|
12
|
+
pid = nil if pid == 0 # may happen on jruby
|
13
|
+
|
14
|
+
log(:pid => pid, :status => status)
|
15
|
+
|
16
|
+
if pid
|
17
|
+
set_exit_code(status)
|
18
|
+
end
|
19
|
+
|
20
|
+
!!pid
|
21
|
+
rescue Errno::ECHILD
|
22
|
+
# may be thrown for detached processes
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait
|
27
|
+
assert_started
|
28
|
+
|
29
|
+
if exited?
|
30
|
+
exit_code
|
31
|
+
else
|
32
|
+
_, status = ::Process.waitpid2(@pid)
|
33
|
+
|
34
|
+
set_exit_code(status)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def launch_process
|
41
|
+
environment = {}
|
42
|
+
@environment.each_pair do |key, value|
|
43
|
+
key = key.to_s
|
44
|
+
value = value.nil? ? nil : value.to_s
|
45
|
+
|
46
|
+
if key.include?("\0") || key.include?("=") || value.to_s.include?("\0")
|
47
|
+
raise InvalidEnvironmentVariable, "#{key.inspect} => #{value.to_s.inspect}"
|
48
|
+
end
|
49
|
+
environment[key] = value
|
50
|
+
end
|
51
|
+
|
52
|
+
options = {}
|
53
|
+
|
54
|
+
options[:out] = io.stdout ? io.stdout.fileno : File::NULL
|
55
|
+
options[:err] = io.stderr ? io.stderr.fileno : File::NULL
|
56
|
+
|
57
|
+
if duplex?
|
58
|
+
reader, writer = ::IO.pipe
|
59
|
+
options[:in] = reader.fileno
|
60
|
+
unless ChildProcess.windows?
|
61
|
+
options[writer.fileno] = :close
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if leader?
|
66
|
+
if ChildProcess.windows?
|
67
|
+
options[:new_pgroup] = true
|
68
|
+
else
|
69
|
+
options[:pgroup] = true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
options[:chdir] = @cwd if @cwd
|
74
|
+
|
75
|
+
if @args.size == 1
|
76
|
+
# When given a single String, Process.spawn would think it should use the shell
|
77
|
+
# if there is any special character in it. However, ChildProcess should never
|
78
|
+
# use the shell. So we use the [cmdname, argv0] form to force no shell.
|
79
|
+
arg = @args[0]
|
80
|
+
args = [[arg, arg]]
|
81
|
+
else
|
82
|
+
args = @args
|
83
|
+
end
|
84
|
+
|
85
|
+
begin
|
86
|
+
@pid = ::Process.spawn(environment, *args, options)
|
87
|
+
rescue SystemCallError => e
|
88
|
+
raise LaunchError, e.message
|
89
|
+
end
|
90
|
+
|
91
|
+
if duplex?
|
92
|
+
io._stdin = writer
|
93
|
+
reader.close
|
94
|
+
end
|
95
|
+
|
96
|
+
::Process.detach(@pid) if detach?
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_exit_code(status)
|
100
|
+
@exit_code = status.exitstatus || status.termsig
|
101
|
+
end
|
102
|
+
|
103
|
+
def send_term
|
104
|
+
send_signal 'TERM'
|
105
|
+
end
|
106
|
+
|
107
|
+
def send_kill
|
108
|
+
send_signal 'KILL'
|
109
|
+
end
|
110
|
+
|
111
|
+
def send_signal(sig)
|
112
|
+
assert_started
|
113
|
+
|
114
|
+
log "sending #{sig}"
|
115
|
+
if leader?
|
116
|
+
if ChildProcess.unix?
|
117
|
+
::Process.kill sig, -@pid # negative pid == process group
|
118
|
+
else
|
119
|
+
output = `taskkill /F /T /PID #{@pid}`
|
120
|
+
log output
|
121
|
+
end
|
122
|
+
else
|
123
|
+
::Process.kill sig, @pid
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
+
require_relative '../process_spawn_process'
|
2
|
+
|
1
3
|
module ChildProcess
|
2
4
|
module Unix
|
3
|
-
class Process <
|
4
|
-
attr_reader :pid
|
5
|
-
|
5
|
+
class Process < ProcessSpawnProcess
|
6
6
|
def io
|
7
7
|
@io ||= Unix::IO.new
|
8
8
|
end
|
@@ -24,67 +24,6 @@ module ChildProcess
|
|
24
24
|
# and send_kill
|
25
25
|
true
|
26
26
|
end
|
27
|
-
|
28
|
-
def exited?
|
29
|
-
return true if @exit_code
|
30
|
-
|
31
|
-
assert_started
|
32
|
-
pid, status = ::Process.waitpid2(@pid, ::Process::WNOHANG | ::Process::WUNTRACED)
|
33
|
-
pid = nil if pid == 0 # may happen on jruby
|
34
|
-
|
35
|
-
log(:pid => pid, :status => status)
|
36
|
-
|
37
|
-
if pid
|
38
|
-
set_exit_code(status)
|
39
|
-
end
|
40
|
-
|
41
|
-
!!pid
|
42
|
-
rescue Errno::ECHILD
|
43
|
-
# may be thrown for detached processes
|
44
|
-
true
|
45
|
-
end
|
46
|
-
|
47
|
-
def wait
|
48
|
-
assert_started
|
49
|
-
|
50
|
-
if exited?
|
51
|
-
exit_code
|
52
|
-
else
|
53
|
-
_, status = ::Process.waitpid2(@pid)
|
54
|
-
|
55
|
-
set_exit_code(status)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def send_term
|
62
|
-
send_signal 'TERM'
|
63
|
-
end
|
64
|
-
|
65
|
-
def send_kill
|
66
|
-
send_signal 'KILL'
|
67
|
-
end
|
68
|
-
|
69
|
-
def send_signal(sig)
|
70
|
-
assert_started
|
71
|
-
|
72
|
-
log "sending #{sig}"
|
73
|
-
::Process.kill sig, _pid
|
74
|
-
end
|
75
|
-
|
76
|
-
def set_exit_code(status)
|
77
|
-
@exit_code = status.exitstatus || status.termsig
|
78
|
-
end
|
79
|
-
|
80
|
-
def _pid
|
81
|
-
if leader?
|
82
|
-
-@pid # negative pid == process group
|
83
|
-
else
|
84
|
-
@pid
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
27
|
end # Process
|
89
28
|
end # Unix
|
90
29
|
end # ChildProcess
|
data/lib/childprocess/unix.rb
CHANGED
@@ -3,7 +3,5 @@ module ChildProcess
|
|
3
3
|
end
|
4
4
|
end
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
require "childprocess/unix/fork_exec_process"
|
9
|
-
# PosixSpawnProcess + ffi is required on demand.
|
6
|
+
require_relative "unix/io"
|
7
|
+
require_relative "unix/process"
|
data/lib/childprocess/version.rb
CHANGED
@@ -1,131 +1,28 @@
|
|
1
|
+
require_relative '../process_spawn_process'
|
2
|
+
|
1
3
|
module ChildProcess
|
2
4
|
module Windows
|
3
|
-
class Process <
|
4
|
-
|
5
|
-
attr_reader :pid
|
6
|
-
|
5
|
+
class Process < ProcessSpawnProcess
|
7
6
|
def io
|
8
7
|
@io ||= Windows::IO.new
|
9
8
|
end
|
10
9
|
|
11
10
|
def stop(timeout = 3)
|
12
11
|
assert_started
|
12
|
+
send_kill
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
ensure
|
19
|
-
close_handle
|
20
|
-
close_job_if_necessary
|
21
|
-
end
|
22
|
-
|
23
|
-
def wait
|
24
|
-
if exited?
|
25
|
-
exit_code
|
26
|
-
else
|
27
|
-
@handle.wait
|
28
|
-
@exit_code = @handle.exit_code
|
29
|
-
|
30
|
-
close_handle
|
31
|
-
close_job_if_necessary
|
32
|
-
|
33
|
-
@exit_code
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def exited?
|
38
|
-
return true if @exit_code
|
39
|
-
assert_started
|
40
|
-
|
41
|
-
code = @handle.exit_code
|
42
|
-
exited = code != PROCESS_STILL_ACTIVE
|
43
|
-
|
44
|
-
log(:exited? => exited, :code => code)
|
45
|
-
|
46
|
-
if exited
|
47
|
-
@exit_code = code
|
48
|
-
close_handle
|
49
|
-
close_job_if_necessary
|
50
|
-
end
|
51
|
-
|
52
|
-
exited
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def launch_process
|
58
|
-
builder = ProcessBuilder.new(@args)
|
59
|
-
builder.leader = leader?
|
60
|
-
builder.detach = detach?
|
61
|
-
builder.duplex = duplex?
|
62
|
-
builder.environment = @environment unless @environment.empty?
|
63
|
-
builder.cwd = @cwd
|
64
|
-
|
65
|
-
if @io
|
66
|
-
builder.stdout = @io.stdout
|
67
|
-
builder.stderr = @io.stderr
|
68
|
-
end
|
69
|
-
|
70
|
-
@pid = builder.start
|
71
|
-
@handle = Handle.open @pid
|
72
|
-
|
73
|
-
if leader?
|
74
|
-
@job = Job.new(detach?, true)
|
75
|
-
@job << @handle
|
76
|
-
end
|
77
|
-
|
78
|
-
if duplex?
|
79
|
-
raise Error, "no stdin stream" unless builder.stdin
|
80
|
-
io._stdin = builder.stdin
|
81
|
-
end
|
82
|
-
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
def close_handle
|
87
|
-
@handle.close
|
88
|
-
end
|
89
|
-
|
90
|
-
def close_job_if_necessary
|
91
|
-
@job.close if leader?
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
class Job
|
96
|
-
def initialize(detach, leader)
|
97
|
-
@pointer = Lib.create_job_object(nil, nil)
|
98
|
-
|
99
|
-
if @pointer.nil? || @pointer.null?
|
100
|
-
raise Error, "unable to create job object"
|
101
|
-
end
|
102
|
-
|
103
|
-
basic = JobObjectBasicLimitInformation.new
|
104
|
-
basic[:LimitFlags] |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE if !detach
|
105
|
-
basic[:LimitFlags] |= JOB_OBJECT_LIMIT_BREAKAWAY_OK if leader
|
106
|
-
|
107
|
-
extended = JobObjectExtendedLimitInformation.new
|
108
|
-
extended[:BasicLimitInformation] = basic
|
109
|
-
|
110
|
-
ret = Lib.set_information_job_object(
|
111
|
-
@pointer,
|
112
|
-
JOB_OBJECT_EXTENDED_LIMIT_INFORMATION,
|
113
|
-
extended,
|
114
|
-
extended.size
|
115
|
-
)
|
116
|
-
|
117
|
-
Lib.check_error ret
|
118
|
-
end
|
119
|
-
|
120
|
-
def <<(handle)
|
121
|
-
Lib.check_error Lib.assign_process_to_job_object(@pointer, handle.pointer)
|
14
|
+
begin
|
15
|
+
return poll_for_exit(timeout)
|
16
|
+
rescue TimeoutError
|
17
|
+
# try next
|
122
18
|
end
|
123
19
|
|
124
|
-
|
125
|
-
|
126
|
-
|
20
|
+
wait
|
21
|
+
rescue Errno::ECHILD, Errno::ESRCH
|
22
|
+
# handle race condition where process dies between timeout
|
23
|
+
# and send_kill
|
24
|
+
true
|
127
25
|
end
|
128
|
-
|
129
26
|
end # Process
|
130
27
|
end # Windows
|
131
28
|
end # ChildProcess
|
data/lib/childprocess/windows.rb
CHANGED
@@ -1,38 +1,9 @@
|
|
1
1
|
require "rbconfig"
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'ffi'
|
5
|
-
rescue LoadError
|
6
|
-
raise ChildProcess::MissingFFIError
|
7
|
-
end
|
8
|
-
|
9
3
|
module ChildProcess
|
10
4
|
module Windows
|
11
|
-
module Lib
|
12
|
-
extend FFI::Library
|
13
|
-
|
14
|
-
def self.msvcrt_name
|
15
|
-
host_part = RbConfig::CONFIG['host_os'].split("_")[1]
|
16
|
-
manifest = File.join(RbConfig::CONFIG['bindir'], 'ruby.exe.manifest')
|
17
|
-
|
18
|
-
if host_part && host_part.to_i > 80 && File.exists?(manifest)
|
19
|
-
"msvcr#{host_part}"
|
20
|
-
else
|
21
|
-
"msvcrt"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
ffi_lib "kernel32", msvcrt_name
|
26
|
-
ffi_convention :stdcall
|
27
|
-
|
28
|
-
|
29
|
-
end # Library
|
30
5
|
end # Windows
|
31
6
|
end # ChildProcess
|
32
7
|
|
33
|
-
require "childprocess/windows/lib"
|
34
|
-
require "childprocess/windows/structs"
|
35
|
-
require "childprocess/windows/handle"
|
36
8
|
require "childprocess/windows/io"
|
37
|
-
require "childprocess/windows/process_builder"
|
38
9
|
require "childprocess/windows/process"
|
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
|
-
|
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
|
-
|
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
|
-
|
54
|
+
RUBY_ENGINE == 'jruby'
|
66
55
|
end
|
67
56
|
|
68
57
|
def windows?
|
69
58
|
os == :windows
|
70
59
|
end
|
71
60
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
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
|
-
|
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
|
-
|
207
|
-
|
208
|
-
|
209
|
-
require 'childprocess/
|
210
|
-
|
169
|
+
if ChildProcess.windows?
|
170
|
+
require 'childprocess/windows'
|
171
|
+
else
|
172
|
+
require 'childprocess/unix'
|
173
|
+
end
|