docker_toolkit 0.1.2 → 0.1.3
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/.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"
|