childprocess 4.1.0 → 5.0.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/.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
|