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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -1
  3. data/Gemfile.lock +1 -1
  4. data/bin/terminator.rb +56 -0
  5. data/docker/Dockerfile +4 -1
  6. data/docker_toolkit.gemspec +1 -0
  7. data/lib/docker_toolkit/childprocess/abstract_io.rb +38 -0
  8. data/lib/docker_toolkit/childprocess/abstract_process.rb +194 -0
  9. data/lib/docker_toolkit/childprocess/errors.rb +28 -0
  10. data/lib/docker_toolkit/childprocess/jruby/io.rb +17 -0
  11. data/lib/docker_toolkit/childprocess/jruby/process.rb +161 -0
  12. data/lib/docker_toolkit/childprocess/jruby/pump.rb +55 -0
  13. data/lib/docker_toolkit/childprocess/jruby.rb +58 -0
  14. data/lib/docker_toolkit/childprocess/tools/generator.rb +148 -0
  15. data/lib/docker_toolkit/childprocess/unix/fork_exec_process.rb +72 -0
  16. data/lib/docker_toolkit/childprocess/unix/io.rb +22 -0
  17. data/lib/docker_toolkit/childprocess/unix/lib.rb +188 -0
  18. data/lib/docker_toolkit/childprocess/unix/platform/i386-linux.rb +14 -0
  19. data/lib/docker_toolkit/childprocess/unix/platform/i386-solaris.rb +13 -0
  20. data/lib/docker_toolkit/childprocess/unix/platform/x86_64-linux.rb +14 -0
  21. data/lib/docker_toolkit/childprocess/unix/platform/x86_64-macosx.rb +13 -0
  22. data/lib/docker_toolkit/childprocess/unix/posix_spawn_process.rb +135 -0
  23. data/lib/docker_toolkit/childprocess/unix/process.rb +91 -0
  24. data/lib/docker_toolkit/childprocess/unix.rb +11 -0
  25. data/lib/docker_toolkit/childprocess/version.rb +5 -0
  26. data/lib/docker_toolkit/childprocess/windows/handle.rb +93 -0
  27. data/lib/docker_toolkit/childprocess/windows/io.rb +25 -0
  28. data/lib/docker_toolkit/childprocess/windows/lib.rb +418 -0
  29. data/lib/docker_toolkit/childprocess/windows/process.rb +132 -0
  30. data/lib/docker_toolkit/childprocess/windows/process_builder.rb +177 -0
  31. data/lib/docker_toolkit/childprocess/windows/structs.rb +151 -0
  32. data/lib/docker_toolkit/childprocess/windows.rb +35 -0
  33. data/lib/docker_toolkit/childprocess.rb +208 -0
  34. data/lib/docker_toolkit/version.rb +1 -1
  35. data/lib/docker_toolkit/watcher.rb +188 -0
  36. data/lib/docker_toolkit.rb +5 -0
  37. metadata +33 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9065c8bb330bb661236077890a09b9e29231a7962ac51c907a5ad734bd952d5
4
- data.tar.gz: 290f4cb58b9dbea44f6e409f624911ca9f0c661468fa937484ad151d788f82ef
3
+ metadata.gz: 37e19e4995dbe0cc868b51fdae6fc18b69d26e12c85a68b8364113e19b7efdf8
4
+ data.tar.gz: 243fb2286022970786e1cdde0bffafacf35f6d5b9dd33fb9c1f1ea1b433e5626
5
5
  SHA512:
6
- metadata.gz: abb75dc06309b0b09ea590e0e4e1bf444d9c546695ab68706cb84694355ea655ce4405243d1eaf11617123243dd64406a26c3ae02a3a8419fef073bc2ac80717
7
- data.tar.gz: 5ae23825dbd86459d5a2e117e46ff8e15bec266077be420ce69dd5efde75d4b0ab65e92fa91fbe9e9d4e71519bc59dc5fca0fa5117b8bc8f1280b4c11a80c420
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
- - cd docker && ./run_tests.sh
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- docker_toolkit (0.1.2)
4
+ docker_toolkit (0.1.3)
5
5
  diplomat
6
6
  json
7
7
 
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:2.5.0-alpine
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"]
@@ -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"