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
@@ -0,0 +1,132 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ module Windows
4
+ class Process < AbstractProcess
5
+
6
+ attr_reader :pid
7
+
8
+ def io
9
+ @io ||= Windows::IO.new
10
+ end
11
+
12
+ def stop(timeout = 3)
13
+ assert_started
14
+
15
+ log "sending KILL"
16
+ @handle.send(WIN_SIGKILL)
17
+
18
+ poll_for_exit(timeout)
19
+ ensure
20
+ close_handle
21
+ close_job_if_necessary
22
+ end
23
+
24
+ def wait
25
+ if exited?
26
+ exit_code
27
+ else
28
+ @handle.wait
29
+ @exit_code = @handle.exit_code
30
+
31
+ close_handle
32
+ close_job_if_necessary
33
+
34
+ @exit_code
35
+ end
36
+ end
37
+
38
+ def exited?
39
+ return true if @exit_code
40
+ assert_started
41
+
42
+ code = @handle.exit_code
43
+ exited = code != PROCESS_STILL_ACTIVE
44
+
45
+ log(:exited? => exited, :code => code)
46
+
47
+ if exited
48
+ @exit_code = code
49
+ close_handle
50
+ close_job_if_necessary
51
+ end
52
+
53
+ exited
54
+ end
55
+
56
+ private
57
+
58
+ def launch_process
59
+ builder = ProcessBuilder.new(@args)
60
+ builder.leader = leader?
61
+ builder.detach = detach?
62
+ builder.duplex = duplex?
63
+ builder.environment = @environment unless @environment.empty?
64
+ builder.cwd = @cwd
65
+
66
+ if @io
67
+ builder.stdout = @io.stdout
68
+ builder.stderr = @io.stderr
69
+ end
70
+
71
+ @pid = builder.start
72
+ @handle = Handle.open @pid
73
+
74
+ if leader?
75
+ @job = Job.new
76
+ @job << @handle
77
+ end
78
+
79
+ if duplex?
80
+ raise Error, "no stdin stream" unless builder.stdin
81
+ io._stdin = builder.stdin
82
+ end
83
+
84
+ self
85
+ end
86
+
87
+ def close_handle
88
+ @handle.close
89
+ end
90
+
91
+ def close_job_if_necessary
92
+ @job.close if leader?
93
+ end
94
+
95
+
96
+ class Job
97
+ def initialize
98
+ @pointer = Lib.create_job_object(nil, nil)
99
+
100
+ if @pointer.nil? || @pointer.null?
101
+ raise Error, "unable to create job object"
102
+ end
103
+
104
+ basic = JobObjectBasicLimitInformation.new
105
+ basic[:LimitFlags] = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK
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)
122
+ end
123
+
124
+ def close
125
+ Lib.close_handle @pointer
126
+ end
127
+ end
128
+
129
+ end # Process
130
+ end # Windows
131
+ end # ChildProcess
132
+ end
@@ -0,0 +1,177 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ module Windows
4
+ class ProcessBuilder
5
+ attr_accessor :leader, :detach, :duplex, :environment, :stdout, :stderr, :cwd
6
+ attr_reader :stdin
7
+
8
+ def initialize(args)
9
+ @args = args
10
+
11
+ @detach = false
12
+ @duplex = false
13
+ @environment = nil
14
+ @cwd = nil
15
+
16
+ @stdout = nil
17
+ @stderr = nil
18
+ @stdin = nil
19
+
20
+ @flags = 0
21
+ @job_ptr = nil
22
+ @cmd_ptr = nil
23
+ @env_ptr = nil
24
+ @cwd_ptr = nil
25
+ end
26
+
27
+ def start
28
+ create_command_pointer
29
+ create_environment_pointer
30
+ create_cwd_pointer
31
+
32
+ setup_flags
33
+ setup_io
34
+
35
+ pid = create_process
36
+ close_handles
37
+
38
+ pid
39
+ end
40
+
41
+ private
42
+
43
+ def create_command_pointer
44
+ string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join ' '
45
+ @cmd_ptr = FFI::MemoryPointer.from_string string
46
+ end
47
+
48
+ def create_environment_pointer
49
+ return unless @environment.kind_of?(Hash) && @environment.any?
50
+
51
+ strings = []
52
+
53
+ ENV.to_hash.merge(@environment).each do |key, val|
54
+ next if val.nil?
55
+
56
+ if key.to_s =~ /=|\0/ || val.to_s.include?("\0")
57
+ raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.inspect}"
58
+ end
59
+
60
+ strings << "#{key}=#{val}\0"
61
+ end
62
+
63
+ strings << "\0" # terminate the env block
64
+ env_str = strings.join
65
+
66
+ @env_ptr = FFI::MemoryPointer.new(:long, env_str.bytesize)
67
+ @env_ptr.put_bytes 0, env_str, 0, env_str.bytesize
68
+ end
69
+
70
+ def create_cwd_pointer
71
+ @cwd_ptr = FFI::MemoryPointer.from_string(@cwd || Dir.pwd)
72
+ end
73
+
74
+ def create_process
75
+ ok = Lib.create_process(
76
+ nil, # application name
77
+ @cmd_ptr, # command line
78
+ nil, # process attributes
79
+ nil, # thread attributes
80
+ true, # inherit handles
81
+ @flags, # creation flags
82
+ @env_ptr, # environment
83
+ @cwd_ptr, # current directory
84
+ startup_info, # startup info
85
+ process_info # process info
86
+ )
87
+
88
+ ok or raise LaunchError, Lib.last_error_message
89
+
90
+ process_info[:dwProcessId]
91
+ end
92
+
93
+ def startup_info
94
+ @startup_info ||= StartupInfo.new
95
+ end
96
+
97
+ def process_info
98
+ @process_info ||= ProcessInfo.new
99
+ end
100
+
101
+ def setup_flags
102
+ @flags |= DETACHED_PROCESS if @detach
103
+ @flags |= CREATE_BREAKAWAY_FROM_JOB if @leader
104
+ end
105
+
106
+ def setup_io
107
+ startup_info[:dwFlags] ||= 0
108
+ startup_info[:dwFlags] |= STARTF_USESTDHANDLES
109
+
110
+ if @stdout
111
+ startup_info[:hStdOutput] = std_stream_handle_for(@stdout)
112
+ end
113
+
114
+ if @stderr
115
+ startup_info[:hStdError] = std_stream_handle_for(@stderr)
116
+ end
117
+
118
+ if @duplex
119
+ read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
120
+ write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
121
+ sa = SecurityAttributes.new(:inherit => true)
122
+
123
+ ok = Lib.create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
124
+ Lib.check_error ok
125
+
126
+ @read_pipe = read_pipe_ptr.read_pointer
127
+ @write_pipe = write_pipe_ptr.read_pointer
128
+
129
+ Lib.set_handle_inheritance @read_pipe, true
130
+ Lib.set_handle_inheritance @write_pipe, false
131
+
132
+ startup_info[:hStdInput] = @read_pipe
133
+ else
134
+ startup_info[:hStdInput] = std_stream_handle_for(STDIN)
135
+ end
136
+ end
137
+
138
+ def std_stream_handle_for(io)
139
+ handle = Lib.handle_for(io)
140
+
141
+ begin
142
+ Lib.set_handle_inheritance handle, true
143
+ rescue ChildProcess::Error
144
+ # If the IO was set to close on exec previously, this call will fail.
145
+ # That's probably OK, since the user explicitly asked for it to be
146
+ # closed (at least I have yet to find other cases where this will
147
+ # happen...)
148
+ end
149
+
150
+ handle
151
+ end
152
+
153
+ def close_handles
154
+ Lib.close_handle process_info[:hProcess]
155
+ Lib.close_handle process_info[:hThread]
156
+
157
+ if @duplex
158
+ @stdin = Lib.io_for(Lib.duplicate_handle(@write_pipe), File::WRONLY)
159
+ Lib.close_handle @read_pipe
160
+ Lib.close_handle @write_pipe
161
+ end
162
+ end
163
+
164
+ def quote_if_necessary(str)
165
+ quote = str.start_with?('"') ? "'" : '"'
166
+
167
+ case str
168
+ when /[\s\\'"]/
169
+ [quote, str, quote].join
170
+ else
171
+ str
172
+ end
173
+ end
174
+ end # ProcessBuilder
175
+ end # Windows
176
+ end # ChildProcess
177
+ end
@@ -0,0 +1,151 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ module Windows
4
+ # typedef struct _STARTUPINFO {
5
+ # DWORD cb;
6
+ # LPTSTR lpReserved;
7
+ # LPTSTR lpDesktop;
8
+ # LPTSTR lpTitle;
9
+ # DWORD dwX;
10
+ # DWORD dwY;
11
+ # DWORD dwXSize;
12
+ # DWORD dwYSize;
13
+ # DWORD dwXCountChars;
14
+ # DWORD dwYCountChars;
15
+ # DWORD dwFillAttribute;
16
+ # DWORD dwFlags;
17
+ # WORD wShowWindow;
18
+ # WORD cbReserved2;
19
+ # LPBYTE lpReserved2;
20
+ # HANDLE hStdInput;
21
+ # HANDLE hStdOutput;
22
+ # HANDLE hStdError;
23
+ # } STARTUPINFO, *LPSTARTUPINFO;
24
+
25
+ class StartupInfo < FFI::Struct
26
+ layout :cb, :ulong,
27
+ :lpReserved, :pointer,
28
+ :lpDesktop, :pointer,
29
+ :lpTitle, :pointer,
30
+ :dwX, :ulong,
31
+ :dwY, :ulong,
32
+ :dwXSize, :ulong,
33
+ :dwYSize, :ulong,
34
+ :dwXCountChars, :ulong,
35
+ :dwYCountChars, :ulong,
36
+ :dwFillAttribute, :ulong,
37
+ :dwFlags, :ulong,
38
+ :wShowWindow, :ushort,
39
+ :cbReserved2, :ushort,
40
+ :lpReserved2, :pointer,
41
+ :hStdInput, :pointer, # void ptr
42
+ :hStdOutput, :pointer, # void ptr
43
+ :hStdError, :pointer # void ptr
44
+ end
45
+
46
+ #
47
+ # typedef struct _PROCESS_INFORMATION {
48
+ # HANDLE hProcess;
49
+ # HANDLE hThread;
50
+ # DWORD dwProcessId;
51
+ # DWORD dwThreadId;
52
+ # } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
53
+ #
54
+
55
+ class ProcessInfo < FFI::Struct
56
+ layout :hProcess, :pointer, # void ptr
57
+ :hThread, :pointer, # void ptr
58
+ :dwProcessId, :ulong,
59
+ :dwThreadId, :ulong
60
+ end
61
+
62
+ #
63
+ # typedef struct _SECURITY_ATTRIBUTES {
64
+ # DWORD nLength;
65
+ # LPVOID lpSecurityDescriptor;
66
+ # BOOL bInheritHandle;
67
+ # } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
68
+ #
69
+
70
+ class SecurityAttributes < FFI::Struct
71
+ layout :nLength, :ulong,
72
+ :lpSecurityDescriptor, :pointer, # void ptr
73
+ :bInheritHandle, :int
74
+
75
+ def initialize(opts = {})
76
+ super()
77
+
78
+ self[:nLength] = self.class.size
79
+ self[:lpSecurityDescriptor] = nil
80
+ self[:bInheritHandle] = opts[:inherit] ? 1 : 0
81
+ end
82
+ end
83
+
84
+ #
85
+ # typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
86
+ # LARGE_INTEGER PerProcessUserTimeLimit;
87
+ # LARGE_INTEGER PerJobUserTimeLimit;
88
+ # DWORD LimitFlags;
89
+ # SIZE_T MinimumWorkingSetSize;
90
+ # SIZE_T MaximumWorkingSetSize;
91
+ # DWORD ActiveProcessLimit;
92
+ # ULONG_PTR Affinity;
93
+ # DWORD PriorityClass;
94
+ # DWORD SchedulingClass;
95
+ # } JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;
96
+ #
97
+ class JobObjectBasicLimitInformation < FFI::Struct
98
+ layout :PerProcessUserTimeLimit, :int64,
99
+ :PerJobUserTimeLimit, :int64,
100
+ :LimitFlags, :ulong,
101
+ :MinimumWorkingSetSize, :size_t,
102
+ :MaximumWorkingSetSize, :size_t,
103
+ :ActiveProcessLimit, :ulong,
104
+ :Affinity, :pointer,
105
+ :PriorityClass, :ulong,
106
+ :SchedulingClass, :ulong
107
+ end
108
+
109
+ #
110
+ # typedef struct _IO_COUNTERS {
111
+ # ULONGLONG ReadOperationCount;
112
+ # ULONGLONG WriteOperationCount;
113
+ # ULONGLONG OtherOperationCount;
114
+ # ULONGLONG ReadTransferCount;
115
+ # ULONGLONG WriteTransferCount;
116
+ # ULONGLONG OtherTransferCount;
117
+ # } IO_COUNTERS, *PIO_COUNTERS;
118
+ #
119
+
120
+ class IoCounters < FFI::Struct
121
+ layout :ReadOperationCount, :ulong_long,
122
+ :WriteOperationCount, :ulong_long,
123
+ :OtherOperationCount, :ulong_long,
124
+ :ReadTransferCount, :ulong_long,
125
+ :WriteTransferCount, :ulong_long,
126
+ :OtherTransferCount, :ulong_long
127
+ end
128
+ #
129
+ # typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
130
+ # JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
131
+ # IO_COUNTERS IoInfo;
132
+ # SIZE_T ProcessMemoryLimit;
133
+ # SIZE_T JobMemoryLimit;
134
+ # SIZE_T PeakProcessMemoryUsed;
135
+ # SIZE_T PeakJobMemoryUsed;
136
+ # } JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;
137
+ #
138
+
139
+ class JobObjectExtendedLimitInformation < FFI::Struct
140
+ layout :BasicLimitInformation, JobObjectBasicLimitInformation,
141
+ :IoInfo, IoCounters,
142
+ :ProcessMemoryLimit, :size_t,
143
+ :JobMemoryLimit, :size_t,
144
+ :PeakProcessMemoryUsed, :size_t,
145
+ :PeakJobMemoryUsed, :size_t
146
+ end
147
+
148
+
149
+ end # Windows
150
+ end # ChildProcess
151
+ end
@@ -0,0 +1,35 @@
1
+ require "ffi"
2
+ require "rbconfig"
3
+
4
+ module DockerToolkit
5
+ module ChildProcess
6
+ module Windows
7
+ module Lib
8
+ extend FFI::Library
9
+
10
+ def self.msvcrt_name
11
+ host_part = RbConfig::CONFIG['host_os'].split("_")[1]
12
+ manifest = File.join(RbConfig::CONFIG['bindir'], 'ruby.exe.manifest')
13
+
14
+ if host_part && host_part.to_i > 80 && File.exists?(manifest)
15
+ "msvcr#{host_part}"
16
+ else
17
+ "msvcrt"
18
+ end
19
+ end
20
+
21
+ ffi_lib "kernel32", msvcrt_name
22
+ ffi_convention :stdcall
23
+
24
+
25
+ end # Library
26
+ end # Windows
27
+ end # ChildProcess
28
+ end DockerToolkit
29
+
30
+ require "docker_toolkit/childprocess/windows/lib"
31
+ require "docker_toolkit/childprocess/windows/structs"
32
+ require "docker_toolkit/childprocess/windows/handle"
33
+ require "docker_toolkit/childprocess/windows/io"
34
+ require "docker_toolkit/childprocess/windows/process_builder"
35
+ require "docker_toolkit/childprocess/windows/process"
@@ -0,0 +1,208 @@
1
+ require 'docker_toolkit/childprocess/version'
2
+ require 'docker_toolkit/childprocess/errors'
3
+ require 'docker_toolkit/childprocess/abstract_process'
4
+ require 'docker_toolkit/childprocess/abstract_io'
5
+ require "fcntl"
6
+ require 'logger'
7
+
8
+ module DockerToolkit
9
+
10
+ module ChildProcess
11
+
12
+ @posix_spawn = false
13
+
14
+ class << self
15
+ attr_writer :logger
16
+
17
+ def new(*args)
18
+ case os
19
+ when :macosx, :linux, :solaris, :bsd, :cygwin, :aix
20
+ if posix_spawn?
21
+ Unix::PosixSpawnProcess.new(args)
22
+ elsif jruby?
23
+ JRuby::Process.new(args)
24
+ else
25
+ Unix::ForkExecProcess.new(args)
26
+ end
27
+ when :windows
28
+ Windows::Process.new(args)
29
+ else
30
+ raise Error, "unsupported platform #{platform_name.inspect}"
31
+ end
32
+ end
33
+ alias_method :build, :new
34
+
35
+ def logger
36
+ return @logger if defined?(@logger) and @logger
37
+
38
+ @logger = Logger.new($stderr)
39
+ @logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO
40
+
41
+ @logger
42
+ end
43
+
44
+ def platform
45
+ if RUBY_PLATFORM == "java"
46
+ :jruby
47
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == "ironruby"
48
+ :ironruby
49
+ else
50
+ os
51
+ end
52
+ end
53
+
54
+ def platform_name
55
+ @platform_name ||= "#{arch}-#{os}"
56
+ end
57
+
58
+ def unix?
59
+ !windows?
60
+ end
61
+
62
+ def linux?
63
+ os == :linux
64
+ end
65
+
66
+ def jruby?
67
+ platform == :jruby
68
+ end
69
+
70
+ def windows?
71
+ os == :windows
72
+ end
73
+
74
+ def posix_spawn?
75
+ enabled = @posix_spawn || %w[1 true].include?(ENV['CHILDPROCESS_POSIX_SPAWN'])
76
+ return false unless enabled
77
+
78
+ require 'ffi'
79
+ begin
80
+ require "childprocess/unix/platform/#{ChildProcess.platform_name}"
81
+ rescue LoadError
82
+ raise ChildProcess::MissingPlatformError
83
+ end
84
+
85
+ require "childprocess/unix/lib"
86
+ require 'childprocess/unix/posix_spawn_process'
87
+
88
+ true
89
+ rescue ChildProcess::MissingPlatformError => ex
90
+ warn_once ex.message
91
+ false
92
+ end
93
+
94
+ #
95
+ # Set this to true to enable experimental use of posix_spawn.
96
+ #
97
+
98
+ def posix_spawn=(bool)
99
+ @posix_spawn = bool
100
+ end
101
+
102
+ def os
103
+ @os ||= (
104
+ require "rbconfig"
105
+ host_os = RbConfig::CONFIG['host_os'].downcase
106
+
107
+ case host_os
108
+ when /linux/
109
+ :linux
110
+ when /darwin|mac os/
111
+ :macosx
112
+ when /mswin|msys|mingw32/
113
+ :windows
114
+ when /cygwin/
115
+ :cygwin
116
+ when /solaris|sunos/
117
+ :solaris
118
+ when /bsd|dragonfly/
119
+ :bsd
120
+ when /aix/
121
+ :aix
122
+ else
123
+ raise Error, "unknown os: #{host_os.inspect}"
124
+ end
125
+ )
126
+ end
127
+
128
+ def arch
129
+ @arch ||= (
130
+ host_cpu = RbConfig::CONFIG['host_cpu'].downcase
131
+ case host_cpu
132
+ when /i[3456]86/
133
+ if workaround_older_macosx_misreported_cpu?
134
+ # Workaround case: older 64-bit Darwin Rubies misreported as i686
135
+ "x86_64"
136
+ else
137
+ "i386"
138
+ end
139
+ when /amd64|x86_64/
140
+ "x86_64"
141
+ when /ppc|powerpc/
142
+ "powerpc"
143
+ else
144
+ host_cpu
145
+ end
146
+ )
147
+ end
148
+
149
+ #
150
+ # By default, a child process will inherit open file descriptors from the
151
+ # parent process. This helper provides a cross-platform way of making sure
152
+ # that doesn't happen for the given file/io.
153
+ #
154
+
155
+ def close_on_exec(file)
156
+ if file.respond_to?(:close_on_exec=)
157
+ file.close_on_exec = true
158
+ elsif file.respond_to?(:fcntl) && defined?(Fcntl::FD_CLOEXEC)
159
+ file.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
160
+
161
+ if jruby? && posix_spawn?
162
+ # on JRuby, the fcntl call above apparently isn't enough when
163
+ # we're launching the process through posix_spawn.
164
+ fileno = JRuby.posix_fileno_for(file)
165
+ Unix::Lib.fcntl fileno, Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
166
+ end
167
+ elsif windows?
168
+ Windows::Lib.dont_inherit file
169
+ else
170
+ raise Error, "not sure how to set close-on-exec for #{file.inspect} on #{platform_name.inspect}"
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ def warn_once(msg)
177
+ @warnings ||= {}
178
+
179
+ unless @warnings[msg]
180
+ @warnings[msg] = true
181
+ logger.warn msg
182
+ end
183
+ end
184
+
185
+ # Workaround: detect the situation that an older Darwin Ruby is actually
186
+ # 64-bit, but is misreporting cpu as i686, which would imply 32-bit.
187
+ #
188
+ # @return [Boolean] `true` if:
189
+ # (a) on Mac OS X
190
+ # (b) actually running in 64-bit mode
191
+ def workaround_older_macosx_misreported_cpu?
192
+ os == :macosx && is_64_bit?
193
+ end
194
+
195
+ # @return [Boolean] `true` if this Ruby represents `1` in 64 bits (8 bytes).
196
+ def is_64_bit?
197
+ 1.size == 8
198
+ end
199
+
200
+ end # class << self
201
+ end # ChildProcess
202
+ end # DockerToolkit
203
+
204
+ require 'jruby' if DockerToolkit::ChildProcess.jruby?
205
+
206
+ require 'docker_toolkit/childprocess/unix' if DockerToolkit::ChildProcess.unix?
207
+ require 'docker_toolkit/childprocess/windows' if DockerToolkit::ChildProcess.windows?
208
+ require 'docker_toolkit/childprocess/jruby' if DockerToolkit::ChildProcess.jruby?
@@ -1,5 +1,5 @@
1
1
  module DockerToolkit
2
2
 
3
- VERSION = '0.1.2'.freeze
3
+ VERSION = '0.1.3'.freeze
4
4
 
5
5
  end