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.
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