childprocess 0.8.0 → 2.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 +5 -5
- data/.document +6 -6
- data/.gitignore +28 -28
- data/.rspec +1 -1
- data/.travis.yml +42 -36
- data/CHANGELOG.md +67 -44
- data/Gemfile +18 -15
- data/LICENSE +20 -20
- data/README.md +216 -192
- data/Rakefile +61 -61
- data/appveyor.yml +42 -43
- data/childprocess.gemspec +32 -30
- data/ext/mkrf_conf.rb +24 -0
- data/lib/childprocess/abstract_io.rb +36 -36
- data/lib/childprocess/abstract_process.rb +192 -192
- data/lib/childprocess/errors.rb +37 -26
- data/lib/childprocess/jruby/io.rb +16 -16
- data/lib/childprocess/jruby/process.rb +184 -159
- data/lib/childprocess/jruby/pump.rb +53 -53
- data/lib/childprocess/jruby.rb +56 -56
- data/lib/childprocess/tools/generator.rb +145 -145
- data/lib/childprocess/unix/fork_exec_process.rb +78 -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 +90 -89
- data/lib/childprocess/unix.rb +9 -9
- data/lib/childprocess/version.rb +3 -3
- data/lib/childprocess/windows/handle.rb +91 -91
- data/lib/childprocess/windows/io.rb +25 -25
- data/lib/childprocess/windows/lib.rb +416 -416
- data/lib/childprocess/windows/process.rb +130 -130
- data/lib/childprocess/windows/process_builder.rb +178 -175
- data/lib/childprocess/windows/structs.rb +148 -148
- data/lib/childprocess/windows.rb +33 -33
- data/lib/childprocess.rb +210 -205
- data/spec/abstract_io_spec.rb +12 -12
- data/spec/childprocess_spec.rb +447 -391
- data/spec/get_env.ps1 +13 -0
- data/spec/io_spec.rb +228 -228
- data/spec/jruby_spec.rb +24 -24
- data/spec/pid_behavior.rb +12 -12
- data/spec/platform_detection_spec.rb +86 -86
- data/spec/spec_helper.rb +270 -261
- data/spec/unix_spec.rb +57 -57
- data/spec/windows_spec.rb +23 -23
- metadata +18 -33
@@ -1,146 +1,146 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
module ChildProcess
|
4
|
-
module Tools
|
5
|
-
class Generator
|
6
|
-
EXE_NAME = "childprocess-sizeof-generator"
|
7
|
-
TMP_PROGRAM = "childprocess-sizeof-generator.c"
|
8
|
-
DEFAULT_INCLUDES = %w[stdio.h stddef.h]
|
9
|
-
|
10
|
-
def self.generate
|
11
|
-
new.generate
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@cc = ENV['CC'] || 'gcc'
|
16
|
-
@out = File.expand_path("../../unix/platform/#{ChildProcess.platform_name}.rb", __FILE__)
|
17
|
-
@sizeof = {}
|
18
|
-
@constants = {}
|
19
|
-
end
|
20
|
-
|
21
|
-
def generate
|
22
|
-
fetch_size 'posix_spawn_file_actions_t', :include => "spawn.h"
|
23
|
-
fetch_size 'posix_spawnattr_t', :include => "spawn.h"
|
24
|
-
fetch_size 'sigset_t', :include => "signal.h"
|
25
|
-
|
26
|
-
fetch_constant 'POSIX_SPAWN_RESETIDS', :include => 'spawn.h'
|
27
|
-
fetch_constant 'POSIX_SPAWN_SETPGROUP', :include => 'spawn.h'
|
28
|
-
fetch_constant 'POSIX_SPAWN_SETSIGDEF', :include => 'spawn.h'
|
29
|
-
fetch_constant 'POSIX_SPAWN_SETSIGMASK', :include => 'spawn.h'
|
30
|
-
|
31
|
-
if ChildProcess.linux?
|
32
|
-
fetch_constant 'POSIX_SPAWN_USEVFORK', :include => 'spawn.h', :define => {'_GNU_SOURCE' => nil}
|
33
|
-
end
|
34
|
-
|
35
|
-
write
|
36
|
-
end
|
37
|
-
|
38
|
-
def write
|
39
|
-
FileUtils.mkdir_p(File.dirname(@out))
|
40
|
-
File.open(@out, 'w') do |io|
|
41
|
-
io.puts result
|
42
|
-
end
|
43
|
-
|
44
|
-
puts "wrote #{@out}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def fetch_size(type_name, opts = {})
|
48
|
-
print "sizeof(#{type_name}): "
|
49
|
-
src = <<-EOF
|
50
|
-
int main() {
|
51
|
-
printf("%d", (unsigned int)sizeof(#{type_name}));
|
52
|
-
return 0;
|
53
|
-
}
|
54
|
-
EOF
|
55
|
-
|
56
|
-
output = execute(src, opts)
|
57
|
-
|
58
|
-
if output.to_i < 1
|
59
|
-
raise "sizeof(#{type_name}) == #{output.to_i} (output=#{output})"
|
60
|
-
end
|
61
|
-
|
62
|
-
size = output.to_i
|
63
|
-
@sizeof[type_name] = size
|
64
|
-
|
65
|
-
puts size
|
66
|
-
end
|
67
|
-
|
68
|
-
def fetch_constant(name, opts)
|
69
|
-
print "#{name}: "
|
70
|
-
src = <<-EOF
|
71
|
-
int main() {
|
72
|
-
printf("%d", (unsigned int)#{name});
|
73
|
-
return 0;
|
74
|
-
}
|
75
|
-
EOF
|
76
|
-
|
77
|
-
output = execute(src, opts)
|
78
|
-
value = Integer(output)
|
79
|
-
@constants[name] = value
|
80
|
-
|
81
|
-
puts value
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
def execute(src, opts)
|
86
|
-
program = Array(opts[:define]).map do |key, value|
|
87
|
-
<<-SRC
|
88
|
-
#ifndef #{key}
|
89
|
-
#define #{key} #{value}
|
90
|
-
#endif
|
91
|
-
SRC
|
92
|
-
end.join("\n")
|
93
|
-
program << "\n"
|
94
|
-
|
95
|
-
includes = Array(opts[:include]) + DEFAULT_INCLUDES
|
96
|
-
program << includes.map { |include| "#include <#{include}>" }.join("\n")
|
97
|
-
program << "\n#{src}"
|
98
|
-
|
99
|
-
File.open(TMP_PROGRAM, 'w') do |file|
|
100
|
-
file << program
|
101
|
-
end
|
102
|
-
|
103
|
-
cmd = "#{@cc} #{TMP_PROGRAM} -o #{EXE_NAME}"
|
104
|
-
system cmd
|
105
|
-
unless $?.success?
|
106
|
-
raise "failed to compile program: #{cmd.inspect}\n#{program}"
|
107
|
-
end
|
108
|
-
|
109
|
-
output = `./#{EXE_NAME} 2>&1`
|
110
|
-
|
111
|
-
unless $?.success?
|
112
|
-
raise "failed to run program: #{cmd.inspect}\n#{output}"
|
113
|
-
end
|
114
|
-
|
115
|
-
output.chomp
|
116
|
-
ensure
|
117
|
-
File.delete TMP_PROGRAM if File.exist?(TMP_PROGRAM)
|
118
|
-
File.delete EXE_NAME if File.exist?(EXE_NAME)
|
119
|
-
end
|
120
|
-
|
121
|
-
def result
|
122
|
-
if @sizeof.empty? && @constants.empty?
|
123
|
-
raise "no data collected, nothing to do"
|
124
|
-
end
|
125
|
-
|
126
|
-
out = ['module ChildProcess::Unix::Platform']
|
127
|
-
out << ' SIZEOF = {'
|
128
|
-
|
129
|
-
max = @sizeof.keys.map { |e| e.length }.max
|
130
|
-
@sizeof.each_with_index do |(type, size), idx|
|
131
|
-
out << " :#{type.ljust max} => #{size}#{',' unless idx == @sizeof.size - 1}"
|
132
|
-
end
|
133
|
-
out << ' }'
|
134
|
-
|
135
|
-
max = @constants.keys.map { |e| e.length }.max
|
136
|
-
@constants.each do |name, val|
|
137
|
-
out << " #{name.ljust max} = #{val}"
|
138
|
-
end
|
139
|
-
out << 'end'
|
140
|
-
|
141
|
-
out.join "\n"
|
142
|
-
end
|
143
|
-
|
144
|
-
end
|
145
|
-
end
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module ChildProcess
|
4
|
+
module Tools
|
5
|
+
class Generator
|
6
|
+
EXE_NAME = "childprocess-sizeof-generator"
|
7
|
+
TMP_PROGRAM = "childprocess-sizeof-generator.c"
|
8
|
+
DEFAULT_INCLUDES = %w[stdio.h stddef.h]
|
9
|
+
|
10
|
+
def self.generate
|
11
|
+
new.generate
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@cc = ENV['CC'] || 'gcc'
|
16
|
+
@out = File.expand_path("../../unix/platform/#{ChildProcess.platform_name}.rb", __FILE__)
|
17
|
+
@sizeof = {}
|
18
|
+
@constants = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate
|
22
|
+
fetch_size 'posix_spawn_file_actions_t', :include => "spawn.h"
|
23
|
+
fetch_size 'posix_spawnattr_t', :include => "spawn.h"
|
24
|
+
fetch_size 'sigset_t', :include => "signal.h"
|
25
|
+
|
26
|
+
fetch_constant 'POSIX_SPAWN_RESETIDS', :include => 'spawn.h'
|
27
|
+
fetch_constant 'POSIX_SPAWN_SETPGROUP', :include => 'spawn.h'
|
28
|
+
fetch_constant 'POSIX_SPAWN_SETSIGDEF', :include => 'spawn.h'
|
29
|
+
fetch_constant 'POSIX_SPAWN_SETSIGMASK', :include => 'spawn.h'
|
30
|
+
|
31
|
+
if ChildProcess.linux?
|
32
|
+
fetch_constant 'POSIX_SPAWN_USEVFORK', :include => 'spawn.h', :define => {'_GNU_SOURCE' => nil}
|
33
|
+
end
|
34
|
+
|
35
|
+
write
|
36
|
+
end
|
37
|
+
|
38
|
+
def write
|
39
|
+
FileUtils.mkdir_p(File.dirname(@out))
|
40
|
+
File.open(@out, 'w') do |io|
|
41
|
+
io.puts result
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "wrote #{@out}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch_size(type_name, opts = {})
|
48
|
+
print "sizeof(#{type_name}): "
|
49
|
+
src = <<-EOF
|
50
|
+
int main() {
|
51
|
+
printf("%d", (unsigned int)sizeof(#{type_name}));
|
52
|
+
return 0;
|
53
|
+
}
|
54
|
+
EOF
|
55
|
+
|
56
|
+
output = execute(src, opts)
|
57
|
+
|
58
|
+
if output.to_i < 1
|
59
|
+
raise "sizeof(#{type_name}) == #{output.to_i} (output=#{output})"
|
60
|
+
end
|
61
|
+
|
62
|
+
size = output.to_i
|
63
|
+
@sizeof[type_name] = size
|
64
|
+
|
65
|
+
puts size
|
66
|
+
end
|
67
|
+
|
68
|
+
def fetch_constant(name, opts)
|
69
|
+
print "#{name}: "
|
70
|
+
src = <<-EOF
|
71
|
+
int main() {
|
72
|
+
printf("%d", (unsigned int)#{name});
|
73
|
+
return 0;
|
74
|
+
}
|
75
|
+
EOF
|
76
|
+
|
77
|
+
output = execute(src, opts)
|
78
|
+
value = Integer(output)
|
79
|
+
@constants[name] = value
|
80
|
+
|
81
|
+
puts value
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def execute(src, opts)
|
86
|
+
program = Array(opts[:define]).map do |key, value|
|
87
|
+
<<-SRC
|
88
|
+
#ifndef #{key}
|
89
|
+
#define #{key} #{value}
|
90
|
+
#endif
|
91
|
+
SRC
|
92
|
+
end.join("\n")
|
93
|
+
program << "\n"
|
94
|
+
|
95
|
+
includes = Array(opts[:include]) + DEFAULT_INCLUDES
|
96
|
+
program << includes.map { |include| "#include <#{include}>" }.join("\n")
|
97
|
+
program << "\n#{src}"
|
98
|
+
|
99
|
+
File.open(TMP_PROGRAM, 'w') do |file|
|
100
|
+
file << program
|
101
|
+
end
|
102
|
+
|
103
|
+
cmd = "#{@cc} #{TMP_PROGRAM} -o #{EXE_NAME}"
|
104
|
+
system cmd
|
105
|
+
unless $?.success?
|
106
|
+
raise "failed to compile program: #{cmd.inspect}\n#{program}"
|
107
|
+
end
|
108
|
+
|
109
|
+
output = `./#{EXE_NAME} 2>&1`
|
110
|
+
|
111
|
+
unless $?.success?
|
112
|
+
raise "failed to run program: #{cmd.inspect}\n#{output}"
|
113
|
+
end
|
114
|
+
|
115
|
+
output.chomp
|
116
|
+
ensure
|
117
|
+
File.delete TMP_PROGRAM if File.exist?(TMP_PROGRAM)
|
118
|
+
File.delete EXE_NAME if File.exist?(EXE_NAME)
|
119
|
+
end
|
120
|
+
|
121
|
+
def result
|
122
|
+
if @sizeof.empty? && @constants.empty?
|
123
|
+
raise "no data collected, nothing to do"
|
124
|
+
end
|
125
|
+
|
126
|
+
out = ['module ChildProcess::Unix::Platform']
|
127
|
+
out << ' SIZEOF = {'
|
128
|
+
|
129
|
+
max = @sizeof.keys.map { |e| e.length }.max
|
130
|
+
@sizeof.each_with_index do |(type, size), idx|
|
131
|
+
out << " :#{type.ljust max} => #{size}#{',' unless idx == @sizeof.size - 1}"
|
132
|
+
end
|
133
|
+
out << ' }'
|
134
|
+
|
135
|
+
max = @constants.keys.map { |e| e.length }.max
|
136
|
+
@constants.each do |name, val|
|
137
|
+
out << " #{name.ljust max} = #{val}"
|
138
|
+
end
|
139
|
+
out << 'end'
|
140
|
+
|
141
|
+
out.join "\n"
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
146
|
end
|
@@ -1,70 +1,78 @@
|
|
1
|
-
module ChildProcess
|
2
|
-
module Unix
|
3
|
-
class ForkExecProcess < Process
|
4
|
-
private
|
5
|
-
|
6
|
-
def launch_process
|
7
|
-
if @io
|
8
|
-
stdout = @io.stdout
|
9
|
-
stderr = @io.stderr
|
10
|
-
end
|
11
|
-
|
12
|
-
# pipe used to detect exec() failure
|
13
|
-
exec_r, exec_w = ::IO.pipe
|
14
|
-
ChildProcess.close_on_exec exec_w
|
15
|
-
|
16
|
-
if duplex?
|
17
|
-
reader, writer = ::IO.pipe
|
18
|
-
end
|
19
|
-
|
20
|
-
@pid = Kernel.fork {
|
21
|
-
# Children of the forked process will inherit its process group
|
22
|
-
# This is to make sure that all grandchildren dies when this Process instance is killed
|
23
|
-
::Process.setpgid 0, 0 if leader?
|
24
|
-
|
25
|
-
if @cwd
|
26
|
-
Dir.chdir(@cwd)
|
27
|
-
end
|
28
|
-
|
29
|
-
exec_r.close
|
30
|
-
set_env
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
1
|
+
module ChildProcess
|
2
|
+
module Unix
|
3
|
+
class ForkExecProcess < Process
|
4
|
+
private
|
5
|
+
|
6
|
+
def launch_process
|
7
|
+
if @io
|
8
|
+
stdout = @io.stdout
|
9
|
+
stderr = @io.stderr
|
10
|
+
end
|
11
|
+
|
12
|
+
# pipe used to detect exec() failure
|
13
|
+
exec_r, exec_w = ::IO.pipe
|
14
|
+
ChildProcess.close_on_exec exec_w
|
15
|
+
|
16
|
+
if duplex?
|
17
|
+
reader, writer = ::IO.pipe
|
18
|
+
end
|
19
|
+
|
20
|
+
@pid = Kernel.fork {
|
21
|
+
# Children of the forked process will inherit its process group
|
22
|
+
# This is to make sure that all grandchildren dies when this Process instance is killed
|
23
|
+
::Process.setpgid 0, 0 if leader?
|
24
|
+
|
25
|
+
if @cwd
|
26
|
+
Dir.chdir(@cwd)
|
27
|
+
end
|
28
|
+
|
29
|
+
exec_r.close
|
30
|
+
set_env
|
31
|
+
|
32
|
+
if stdout
|
33
|
+
STDOUT.reopen(stdout)
|
34
|
+
else
|
35
|
+
STDOUT.reopen("/dev/null", "a+")
|
36
|
+
end
|
37
|
+
if stderr
|
38
|
+
STDERR.reopen(stderr)
|
39
|
+
else
|
40
|
+
STDERR.reopen("/dev/null", "a+")
|
41
|
+
end
|
42
|
+
|
43
|
+
if duplex?
|
44
|
+
STDIN.reopen(reader)
|
45
|
+
writer.close
|
46
|
+
end
|
47
|
+
|
48
|
+
executable, *args = @args
|
49
|
+
|
50
|
+
begin
|
51
|
+
Kernel.exec([executable, executable], *args)
|
52
|
+
rescue SystemCallError => ex
|
53
|
+
exec_w << ex.message
|
54
|
+
end
|
55
|
+
}
|
56
|
+
|
57
|
+
exec_w.close
|
58
|
+
|
59
|
+
if duplex?
|
60
|
+
io._stdin = writer
|
61
|
+
reader.close
|
62
|
+
end
|
63
|
+
|
64
|
+
# if we don't eventually get EOF, exec() failed
|
65
|
+
unless exec_r.eof?
|
66
|
+
raise LaunchError, exec_r.read || "executing command with #{@args.inspect} failed"
|
67
|
+
end
|
68
|
+
|
69
|
+
::Process.detach(@pid) if detach?
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_env
|
73
|
+
@environment.each { |k, v| ENV[k.to_s] = v.nil? ? nil : v.to_s }
|
74
|
+
end
|
75
|
+
|
76
|
+
end # Process
|
77
|
+
end # Unix
|
78
|
+
end # ChildProcess
|
data/lib/childprocess/unix/io.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
module ChildProcess
|
2
|
-
module Unix
|
3
|
-
class IO < AbstractIO
|
4
|
-
private
|
5
|
-
|
6
|
-
def check_type(io)
|
7
|
-
unless io.respond_to? :to_io
|
8
|
-
raise ArgumentError, "expected #{io.inspect} to respond to :to_io"
|
9
|
-
end
|
10
|
-
|
11
|
-
result = io.to_io
|
12
|
-
unless result && result.kind_of?(::IO)
|
13
|
-
raise TypeError, "expected IO, got #{result.inspect}:#{result.class}"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
end # IO
|
18
|
-
end # Unix
|
19
|
-
end # ChildProcess
|
20
|
-
|
21
|
-
|
1
|
+
module ChildProcess
|
2
|
+
module Unix
|
3
|
+
class IO < AbstractIO
|
4
|
+
private
|
5
|
+
|
6
|
+
def check_type(io)
|
7
|
+
unless io.respond_to? :to_io
|
8
|
+
raise ArgumentError, "expected #{io.inspect} to respond to :to_io"
|
9
|
+
end
|
10
|
+
|
11
|
+
result = io.to_io
|
12
|
+
unless result && result.kind_of?(::IO)
|
13
|
+
raise TypeError, "expected IO, got #{result.inspect}:#{result.class}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end # IO
|
18
|
+
end # Unix
|
19
|
+
end # ChildProcess
|
20
|
+
|
21
|
+
|