docker_toolkit 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -1
- data/Gemfile.lock +1 -1
- data/bin/terminator.rb +56 -0
- data/docker/Dockerfile +4 -1
- data/docker_toolkit.gemspec +1 -0
- data/lib/docker_toolkit/childprocess/abstract_io.rb +38 -0
- data/lib/docker_toolkit/childprocess/abstract_process.rb +194 -0
- data/lib/docker_toolkit/childprocess/errors.rb +28 -0
- data/lib/docker_toolkit/childprocess/jruby/io.rb +17 -0
- data/lib/docker_toolkit/childprocess/jruby/process.rb +161 -0
- data/lib/docker_toolkit/childprocess/jruby/pump.rb +55 -0
- data/lib/docker_toolkit/childprocess/jruby.rb +58 -0
- data/lib/docker_toolkit/childprocess/tools/generator.rb +148 -0
- data/lib/docker_toolkit/childprocess/unix/fork_exec_process.rb +72 -0
- data/lib/docker_toolkit/childprocess/unix/io.rb +22 -0
- data/lib/docker_toolkit/childprocess/unix/lib.rb +188 -0
- data/lib/docker_toolkit/childprocess/unix/platform/i386-linux.rb +14 -0
- data/lib/docker_toolkit/childprocess/unix/platform/i386-solaris.rb +13 -0
- data/lib/docker_toolkit/childprocess/unix/platform/x86_64-linux.rb +14 -0
- data/lib/docker_toolkit/childprocess/unix/platform/x86_64-macosx.rb +13 -0
- data/lib/docker_toolkit/childprocess/unix/posix_spawn_process.rb +135 -0
- data/lib/docker_toolkit/childprocess/unix/process.rb +91 -0
- data/lib/docker_toolkit/childprocess/unix.rb +11 -0
- data/lib/docker_toolkit/childprocess/version.rb +5 -0
- data/lib/docker_toolkit/childprocess/windows/handle.rb +93 -0
- data/lib/docker_toolkit/childprocess/windows/io.rb +25 -0
- data/lib/docker_toolkit/childprocess/windows/lib.rb +418 -0
- data/lib/docker_toolkit/childprocess/windows/process.rb +132 -0
- data/lib/docker_toolkit/childprocess/windows/process_builder.rb +177 -0
- data/lib/docker_toolkit/childprocess/windows/structs.rb +151 -0
- data/lib/docker_toolkit/childprocess/windows.rb +35 -0
- data/lib/docker_toolkit/childprocess.rb +208 -0
- data/lib/docker_toolkit/version.rb +1 -1
- data/lib/docker_toolkit/watcher.rb +188 -0
- data/lib/docker_toolkit.rb +5 -0
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37e19e4995dbe0cc868b51fdae6fc18b69d26e12c85a68b8364113e19b7efdf8
|
4
|
+
data.tar.gz: 243fb2286022970786e1cdde0bffafacf35f6d5b9dd33fb9c1f1ea1b433e5626
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0553be938e83e0d9359181234499cf1cb10cf0fe0152eab1d29c8bd33f805810da1a8eb67bc0dd0e302cacd73a1eaa02f023c82827b66cc92efc5f7e21a91d20
|
7
|
+
data.tar.gz: 38a0e77028d94411d4da7ceccf40a34f8b2fa87f4147842e95cbc0340b211733af572e8e817d8f4ec281557d83f80db5cf53917fd9a2b9837744916bfe61a628
|
data/.travis.yml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
4
|
- 2.0
|
@@ -8,8 +9,16 @@ services:
|
|
8
9
|
|
9
10
|
stage: test
|
10
11
|
|
12
|
+
before_install:
|
13
|
+
- sudo apt-get install -y libxml2-dev unzip curl
|
14
|
+
|
11
15
|
script:
|
12
|
-
-
|
16
|
+
- gem build `ls | grep gemspec`
|
17
|
+
- gem install `ls | grep -e '.gem$'`
|
18
|
+
- curl -sSLo /tmp/consul.zip https://releases.hashicorp.com/consul/1.2.1/consul_1.2.1_linux_amd64.zip
|
19
|
+
- sudo unzip -d /bin /tmp/consul.zip
|
20
|
+
- bundle exec rspec
|
21
|
+
|
13
22
|
|
14
23
|
jobs:
|
15
24
|
include:
|
data/Gemfile.lock
CHANGED
data/bin/terminator.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
STDOUT.sync = true
|
6
|
+
STDERR.sync = true
|
7
|
+
|
8
|
+
@opts = {
|
9
|
+
code: 0,
|
10
|
+
sleep: 1,
|
11
|
+
term_code: 0
|
12
|
+
}
|
13
|
+
|
14
|
+
parser = OptionParser.new do |o|
|
15
|
+
o.banner = 'Usage: term.rb [options]'
|
16
|
+
|
17
|
+
o.on("--exit code=#{@opts[:code]}", 'set exit code') do |code|
|
18
|
+
@opts[:code] = code.to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
o.on("--sleep sec=#{@opts[:sleep]}", 'Sleep before exit') do |sec|
|
22
|
+
@opts[:sleep] = sec.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
o.on('--term', 'SIGTERM self') do
|
26
|
+
@opts[:term] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
o.on("--term-code=#{@opts[:term_code]}", 'exit code when SIGTERM catched') do |code|
|
30
|
+
@opts[:term_code] = code.to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
o.on('--kill', 'SIGKILL self') do
|
34
|
+
@opts[:kill] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
parser.parse!
|
39
|
+
|
40
|
+
def log msg
|
41
|
+
puts "[terminator]: #{msg}"
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
%w[INT TERM].each do |sig|
|
46
|
+
trap(sig) do
|
47
|
+
exit(@opts[:term_code])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
sleep @opts[:sleep]
|
52
|
+
|
53
|
+
::Process.kill('KILL', $$) if @opts[:kill]
|
54
|
+
::Process.kill('TERM', $$) if @opts[:term]
|
55
|
+
|
56
|
+
exit @opts[:code]
|
data/docker/Dockerfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
FROM ruby
|
1
|
+
FROM mayok/alpine-ruby
|
2
2
|
MAINTAINER Firmhouse "kinnalru@gmail.com"
|
3
3
|
|
4
4
|
WORKDIR /home/app
|
@@ -46,6 +46,9 @@ RUN set -ex \
|
|
46
46
|
|
47
47
|
ADD . /home/app
|
48
48
|
|
49
|
+
RUN set -ex \
|
50
|
+
&& gem build `ls | grep gemspec` \
|
51
|
+
&& gem install `ls | grep -e '.gem$'`
|
49
52
|
|
50
53
|
|
51
54
|
SHELL ["/bin/sh", "-c", "-l"]
|
data/docker_toolkit.gemspec
CHANGED
@@ -5,6 +5,7 @@ require 'docker_toolkit/version'
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'docker_toolkit'
|
7
7
|
spec.version = DockerToolkit::VERSION
|
8
|
+
spec.license = 'MIT'
|
8
9
|
spec.authors = ['Godko Ivan', 'Samoilenko Yuri']
|
9
10
|
spec.email = ['igodko@rnds.pro', 'kinnalru@gmail.com']
|
10
11
|
spec.homepage = 'https://github.com/RnD-Soft/docker_toolkit'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module DockerToolkit
|
2
|
+
module ChildProcess
|
3
|
+
class AbstractIO
|
4
|
+
attr_reader :stderr, :stdout, :stdin
|
5
|
+
|
6
|
+
def inherit!
|
7
|
+
@stdout = STDOUT
|
8
|
+
@stderr = STDERR
|
9
|
+
end
|
10
|
+
|
11
|
+
def stderr=(io)
|
12
|
+
check_type io
|
13
|
+
@stderr = io
|
14
|
+
end
|
15
|
+
|
16
|
+
def stdout=(io)
|
17
|
+
check_type io
|
18
|
+
@stdout = io
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
|
25
|
+
def _stdin=(io)
|
26
|
+
check_type io
|
27
|
+
@stdin = io
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def check_type(io)
|
33
|
+
raise SubclassResponsibility, "check_type"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module DockerToolkit
|
2
|
+
module ChildProcess
|
3
|
+
class AbstractProcess
|
4
|
+
POLL_INTERVAL = 0.1
|
5
|
+
|
6
|
+
attr_reader :exit_code
|
7
|
+
|
8
|
+
#
|
9
|
+
# Set this to true if you do not care about when or if the process quits.
|
10
|
+
#
|
11
|
+
attr_accessor :detach
|
12
|
+
|
13
|
+
#
|
14
|
+
# Set this to true if you want to write to the process' stdin (process.io.stdin)
|
15
|
+
#
|
16
|
+
attr_accessor :duplex
|
17
|
+
|
18
|
+
#
|
19
|
+
# Modify the child's environment variables
|
20
|
+
#
|
21
|
+
attr_reader :environment
|
22
|
+
|
23
|
+
#
|
24
|
+
# Set the child's current working directory.
|
25
|
+
#
|
26
|
+
attr_accessor :cwd
|
27
|
+
|
28
|
+
#
|
29
|
+
# Set this to true to make the child process the leader of a new process group
|
30
|
+
#
|
31
|
+
# This can be used to make sure that all grandchildren are killed
|
32
|
+
# when the child process dies.
|
33
|
+
#
|
34
|
+
attr_accessor :leader
|
35
|
+
|
36
|
+
#
|
37
|
+
# Create a new process with the given args.
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
# @see ChildProcess.build
|
41
|
+
#
|
42
|
+
|
43
|
+
def initialize(args)
|
44
|
+
unless args.all? { |e| e.kind_of?(String) }
|
45
|
+
raise ArgumentError, "all arguments must be String: #{args.inspect}"
|
46
|
+
end
|
47
|
+
|
48
|
+
@args = args
|
49
|
+
@started = false
|
50
|
+
@exit_code = nil
|
51
|
+
@io = nil
|
52
|
+
@cwd = nil
|
53
|
+
@detach = false
|
54
|
+
@duplex = false
|
55
|
+
@leader = false
|
56
|
+
@environment = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Returns a ChildProcess::AbstractIO subclass to configure the child's IO streams.
|
61
|
+
#
|
62
|
+
|
63
|
+
def io
|
64
|
+
raise SubclassResponsibility, "io"
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# @return [Integer] the pid of the process after it has started
|
69
|
+
#
|
70
|
+
|
71
|
+
def pid
|
72
|
+
raise SubclassResponsibility, "pid"
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Launch the child process
|
77
|
+
#
|
78
|
+
# @return [AbstractProcess] self
|
79
|
+
#
|
80
|
+
|
81
|
+
def start
|
82
|
+
launch_process
|
83
|
+
@started = true
|
84
|
+
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Forcibly terminate the process, using increasingly harsher methods if possible.
|
90
|
+
#
|
91
|
+
# @param [Integer] timeout (3) Seconds to wait before trying the next method.
|
92
|
+
#
|
93
|
+
|
94
|
+
def stop(timeout = 3)
|
95
|
+
raise SubclassResponsibility, "stop"
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Block until the process has been terminated.
|
100
|
+
#
|
101
|
+
# @return [Integer] The exit status of the process
|
102
|
+
#
|
103
|
+
|
104
|
+
def wait
|
105
|
+
raise SubclassResponsibility, "wait"
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Did the process exit?
|
110
|
+
#
|
111
|
+
# @return [Boolean]
|
112
|
+
#
|
113
|
+
|
114
|
+
def exited?
|
115
|
+
raise SubclassResponsibility, "exited?"
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Has the process started?
|
120
|
+
#
|
121
|
+
# @return [Boolean]
|
122
|
+
#
|
123
|
+
|
124
|
+
def started?
|
125
|
+
@started
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Is this process running?
|
130
|
+
#
|
131
|
+
# @return [Boolean]
|
132
|
+
#
|
133
|
+
|
134
|
+
def alive?
|
135
|
+
started? && !exited?
|
136
|
+
end
|
137
|
+
|
138
|
+
#
|
139
|
+
# Returns true if the process has exited and the exit code was not 0.
|
140
|
+
#
|
141
|
+
# @return [Boolean]
|
142
|
+
#
|
143
|
+
|
144
|
+
def crashed?
|
145
|
+
exited? && @exit_code != 0
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# Wait for the process to exit, raising a ChildProcess::TimeoutError if
|
150
|
+
# the timeout expires.
|
151
|
+
#
|
152
|
+
|
153
|
+
def poll_for_exit(timeout)
|
154
|
+
log "polling #{timeout} seconds for exit"
|
155
|
+
|
156
|
+
end_time = Time.now + timeout
|
157
|
+
until (ok = exited?) || Time.now > end_time
|
158
|
+
sleep POLL_INTERVAL
|
159
|
+
end
|
160
|
+
|
161
|
+
unless ok
|
162
|
+
raise TimeoutError, "process still alive after #{timeout} seconds"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def launch_process
|
169
|
+
raise SubclassResponsibility, "launch_process"
|
170
|
+
end
|
171
|
+
|
172
|
+
def detach?
|
173
|
+
@detach
|
174
|
+
end
|
175
|
+
|
176
|
+
def duplex?
|
177
|
+
@duplex
|
178
|
+
end
|
179
|
+
|
180
|
+
def leader?
|
181
|
+
@leader
|
182
|
+
end
|
183
|
+
|
184
|
+
def log(*args)
|
185
|
+
ChildProcess.logger.debug "#{self.inspect} : #{args.inspect}"
|
186
|
+
end
|
187
|
+
|
188
|
+
def assert_started
|
189
|
+
raise Error, "process not started" unless started?
|
190
|
+
end
|
191
|
+
|
192
|
+
end # AbstractProcess
|
193
|
+
end # ChildProcess
|
194
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module DockerToolkit
|
2
|
+
module ChildProcess
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class TimeoutError < Error
|
7
|
+
end
|
8
|
+
|
9
|
+
class SubclassResponsibility < Error
|
10
|
+
end
|
11
|
+
|
12
|
+
class InvalidEnvironmentVariable < Error
|
13
|
+
end
|
14
|
+
|
15
|
+
class LaunchError < Error
|
16
|
+
end
|
17
|
+
|
18
|
+
class MissingPlatformError < Error
|
19
|
+
def initialize
|
20
|
+
message = "posix_spawn is not yet supported on #{ChildProcess.platform_name} (#{RUBY_PLATFORM}), falling back to default implementation. " +
|
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
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DockerToolkit
|
2
|
+
module ChildProcess
|
3
|
+
module JRuby
|
4
|
+
class IO < AbstractIO
|
5
|
+
private
|
6
|
+
|
7
|
+
def check_type(output)
|
8
|
+
unless output.respond_to?(:to_outputstream) && output.respond_to?(:write)
|
9
|
+
raise ArgumentError, "expected #{output.inspect} to respond to :to_outputstream"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end # IO
|
14
|
+
end # Unix
|
15
|
+
end # ChildProcess
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require "java"
|
2
|
+
|
3
|
+
module DockerToolkit
|
4
|
+
module ChildProcess
|
5
|
+
module JRuby
|
6
|
+
class Process < AbstractProcess
|
7
|
+
def initialize(args)
|
8
|
+
super(args)
|
9
|
+
|
10
|
+
@pumps = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def io
|
14
|
+
@io ||= JRuby::IO.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def exited?
|
18
|
+
return true if @exit_code
|
19
|
+
|
20
|
+
assert_started
|
21
|
+
@exit_code = @process.exitValue
|
22
|
+
stop_pumps
|
23
|
+
|
24
|
+
true
|
25
|
+
rescue java.lang.IllegalThreadStateException => ex
|
26
|
+
log(ex.class => ex.message)
|
27
|
+
false
|
28
|
+
ensure
|
29
|
+
log(:exit_code => @exit_code)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop(timeout = nil)
|
33
|
+
assert_started
|
34
|
+
|
35
|
+
@process.destroy
|
36
|
+
wait # no way to actually use the timeout here..
|
37
|
+
end
|
38
|
+
|
39
|
+
def wait
|
40
|
+
if exited?
|
41
|
+
exit_code
|
42
|
+
else
|
43
|
+
@process.waitFor
|
44
|
+
|
45
|
+
stop_pumps
|
46
|
+
@exit_code = @process.exitValue
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Only supported in JRuby on a Unix operating system, thanks to limitations
|
52
|
+
# in Java's classes
|
53
|
+
#
|
54
|
+
# @return [Integer] the pid of the process after it has started
|
55
|
+
# @raise [NotImplementedError] when trying to access pid on non-Unix platform
|
56
|
+
#
|
57
|
+
def pid
|
58
|
+
if @process.getClass.getName != "java.lang.UNIXProcess"
|
59
|
+
raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
|
60
|
+
end
|
61
|
+
|
62
|
+
# About the best way we can do this is with a nasty reflection-based impl
|
63
|
+
# Thanks to Martijn Courteaux
|
64
|
+
# http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
|
65
|
+
field = @process.getClass.getDeclaredField("pid")
|
66
|
+
field.accessible = true
|
67
|
+
field.get(@process)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def launch_process(&blk)
|
73
|
+
pb = java.lang.ProcessBuilder.new(@args)
|
74
|
+
|
75
|
+
pb.directory java.io.File.new(@cwd || Dir.pwd)
|
76
|
+
set_env pb.environment
|
77
|
+
|
78
|
+
begin
|
79
|
+
@process = pb.start
|
80
|
+
rescue java.io.IOException => ex
|
81
|
+
raise LaunchError, ex.message
|
82
|
+
end
|
83
|
+
|
84
|
+
setup_io
|
85
|
+
end
|
86
|
+
|
87
|
+
def setup_io
|
88
|
+
if @io
|
89
|
+
redirect(@process.getErrorStream, @io.stderr)
|
90
|
+
redirect(@process.getInputStream, @io.stdout)
|
91
|
+
else
|
92
|
+
@process.getErrorStream.close
|
93
|
+
@process.getInputStream.close
|
94
|
+
end
|
95
|
+
|
96
|
+
if duplex?
|
97
|
+
io._stdin = create_stdin
|
98
|
+
else
|
99
|
+
@process.getOutputStream.close
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def redirect(input, output)
|
104
|
+
if output.nil?
|
105
|
+
input.close
|
106
|
+
return
|
107
|
+
end
|
108
|
+
|
109
|
+
@pumps << Pump.new(input, output.to_outputstream).run
|
110
|
+
end
|
111
|
+
|
112
|
+
def stop_pumps
|
113
|
+
@pumps.each { |pump| pump.stop }
|
114
|
+
end
|
115
|
+
|
116
|
+
def set_env(env)
|
117
|
+
merged = ENV.to_hash
|
118
|
+
|
119
|
+
@environment.each { |k, v| merged[k.to_s] = v }
|
120
|
+
|
121
|
+
merged.each do |k, v|
|
122
|
+
if v
|
123
|
+
env.put(k, v.to_s)
|
124
|
+
elsif env.has_key? k
|
125
|
+
env.remove(k)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
removed_keys = env.key_set.to_a - merged.keys
|
130
|
+
removed_keys.each { |k| env.remove(k) }
|
131
|
+
end
|
132
|
+
|
133
|
+
def create_stdin
|
134
|
+
output_stream = @process.getOutputStream
|
135
|
+
|
136
|
+
stdin = output_stream.to_io
|
137
|
+
stdin.sync = true
|
138
|
+
stdin.instance_variable_set(:@childprocess_java_stream, output_stream)
|
139
|
+
|
140
|
+
class << stdin
|
141
|
+
# The stream provided is a BufferedeOutputStream, so we
|
142
|
+
# have to flush it to make the bytes flow to the process
|
143
|
+
def __childprocess_flush__
|
144
|
+
@childprocess_java_stream.flush
|
145
|
+
end
|
146
|
+
|
147
|
+
[:flush, :print, :printf, :putc, :puts, :write, :write_nonblock].each do |m|
|
148
|
+
define_method(m) do |*args|
|
149
|
+
super(*args)
|
150
|
+
self.__childprocess_flush__
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
stdin
|
156
|
+
end
|
157
|
+
|
158
|
+
end # Process
|
159
|
+
end # JRuby
|
160
|
+
end # ChildProcess
|
161
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module DockerToolkit
|
2
|
+
module ChildProcess
|
3
|
+
module JRuby
|
4
|
+
class Pump
|
5
|
+
BUFFER_SIZE = 2048
|
6
|
+
|
7
|
+
def initialize(input, output)
|
8
|
+
@input = input
|
9
|
+
@output = output
|
10
|
+
@stop = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop
|
14
|
+
@stop = true
|
15
|
+
@thread && @thread.join
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
@thread = Thread.new { pump }
|
20
|
+
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def pump
|
27
|
+
buffer = Java.byte[BUFFER_SIZE].new
|
28
|
+
|
29
|
+
until @stop && (@input.available == 0)
|
30
|
+
read, avail = 0, 0
|
31
|
+
|
32
|
+
while read != -1
|
33
|
+
avail = [@input.available, 1].max
|
34
|
+
avail = BUFFER_SIZE if avail > BUFFER_SIZE
|
35
|
+
read = @input.read(buffer, 0, avail)
|
36
|
+
|
37
|
+
if read > 0
|
38
|
+
@output.write(buffer, 0, read)
|
39
|
+
@output.flush
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
sleep 0.1
|
44
|
+
end
|
45
|
+
|
46
|
+
@output.flush
|
47
|
+
rescue java.io.IOException => ex
|
48
|
+
ChildProcess.logger.debug ex.message
|
49
|
+
ChildProcess.logger.debug ex.backtrace
|
50
|
+
end
|
51
|
+
|
52
|
+
end # Pump
|
53
|
+
end # JRuby
|
54
|
+
end # ChildProcess
|
55
|
+
end
|
@@ -0,0 +1,58 @@
|
|
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 DockerToolkit
|
17
|
+
module ChildProcess
|
18
|
+
module JRuby
|
19
|
+
def self.posix_fileno_for(obj)
|
20
|
+
channel = ::JRuby.reference(obj).channel
|
21
|
+
begin
|
22
|
+
channel.getFDVal
|
23
|
+
rescue NoMethodError
|
24
|
+
fileno = channel.fd
|
25
|
+
if fileno.kind_of?(Java::JavaIo::FileDescriptor)
|
26
|
+
fileno = fileno.fd
|
27
|
+
end
|
28
|
+
|
29
|
+
fileno == -1 ? obj.fileno : fileno
|
30
|
+
end
|
31
|
+
rescue
|
32
|
+
# fall back
|
33
|
+
obj.fileno
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.windows_handle_for(obj)
|
37
|
+
channel = ::JRuby.reference(obj).channel
|
38
|
+
fileno = obj.fileno
|
39
|
+
|
40
|
+
begin
|
41
|
+
fileno = channel.getFDVal
|
42
|
+
rescue NoMethodError
|
43
|
+
fileno = channel.fd if channel.respond_to?(:fd)
|
44
|
+
end
|
45
|
+
|
46
|
+
if fileno.kind_of? Java::JavaIo::FileDescriptor
|
47
|
+
fileno.handle
|
48
|
+
else
|
49
|
+
Windows::Lib.handle_for fileno
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
require "docker_toolkit/childprocess/jruby/pump"
|
57
|
+
require "docker_toolkit/childprocess/jruby/io"
|
58
|
+
require "docker_toolkit/childprocess/jruby/process"
|