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
 
| 
         @@ -0,0 +1,148 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 4 
     | 
    
         
            +
            module ChildProcess
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Tools
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Generator
         
     | 
| 
      
 7 
     | 
    
         
            +
                  EXE_NAME         = "childprocess-sizeof-generator"
         
     | 
| 
      
 8 
     | 
    
         
            +
                  TMP_PROGRAM      = "childprocess-sizeof-generator.c"
         
     | 
| 
      
 9 
     | 
    
         
            +
                  DEFAULT_INCLUDES = %w[stdio.h stddef.h]
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def self.generate
         
     | 
| 
      
 12 
     | 
    
         
            +
                    new.generate
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @cc        = ENV['CC'] || 'gcc'
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @out       = File.expand_path("../../unix/platform/#{ChildProcess.platform_name}.rb", __FILE__)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @sizeof    = {}
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @constants = {}
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def generate
         
     | 
| 
      
 23 
     | 
    
         
            +
                    fetch_size 'posix_spawn_file_actions_t', :include => "spawn.h"
         
     | 
| 
      
 24 
     | 
    
         
            +
                    fetch_size 'posix_spawnattr_t', :include => "spawn.h"
         
     | 
| 
      
 25 
     | 
    
         
            +
                    fetch_size 'sigset_t', :include => "signal.h"
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    fetch_constant 'POSIX_SPAWN_RESETIDS',   :include  => 'spawn.h'
         
     | 
| 
      
 28 
     | 
    
         
            +
                    fetch_constant 'POSIX_SPAWN_SETPGROUP',  :include  => 'spawn.h'
         
     | 
| 
      
 29 
     | 
    
         
            +
                    fetch_constant 'POSIX_SPAWN_SETSIGDEF',  :include  => 'spawn.h'
         
     | 
| 
      
 30 
     | 
    
         
            +
                    fetch_constant 'POSIX_SPAWN_SETSIGMASK', :include  => 'spawn.h'
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    if ChildProcess.linux?
         
     | 
| 
      
 33 
     | 
    
         
            +
                      fetch_constant 'POSIX_SPAWN_USEVFORK', :include => 'spawn.h', :define => {'_GNU_SOURCE' => nil}
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    write
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def write
         
     | 
| 
      
 40 
     | 
    
         
            +
                    FileUtils.mkdir_p(File.dirname(@out))
         
     | 
| 
      
 41 
     | 
    
         
            +
                    File.open(@out, 'w') do |io|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      io.puts result
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    puts "wrote #{@out}"
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  def fetch_size(type_name, opts = {})
         
     | 
| 
      
 49 
     | 
    
         
            +
                    print "sizeof(#{type_name}): "
         
     | 
| 
      
 50 
     | 
    
         
            +
                    src = <<-EOF
         
     | 
| 
      
 51 
     | 
    
         
            +
            int main() {
         
     | 
| 
      
 52 
     | 
    
         
            +
              printf("%d", (unsigned int)sizeof(#{type_name}));
         
     | 
| 
      
 53 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 54 
     | 
    
         
            +
            }
         
     | 
| 
      
 55 
     | 
    
         
            +
                    EOF
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    output = execute(src, opts)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    if output.to_i < 1
         
     | 
| 
      
 60 
     | 
    
         
            +
                      raise "sizeof(#{type_name}) == #{output.to_i} (output=#{output})"
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                    size = output.to_i
         
     | 
| 
      
 64 
     | 
    
         
            +
                    @sizeof[type_name] = size
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    puts size
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  def fetch_constant(name, opts)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    print "#{name}: "
         
     | 
| 
      
 71 
     | 
    
         
            +
                    src = <<-EOF
         
     | 
| 
      
 72 
     | 
    
         
            +
            int main() {
         
     | 
| 
      
 73 
     | 
    
         
            +
              printf("%d", (unsigned int)#{name});
         
     | 
| 
      
 74 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 75 
     | 
    
         
            +
            }
         
     | 
| 
      
 76 
     | 
    
         
            +
                    EOF
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    output = execute(src, opts)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    value  = Integer(output)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    @constants[name] = value
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    puts value
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  def execute(src, opts)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    program = Array(opts[:define]).map do |key, value|
         
     | 
| 
      
 88 
     | 
    
         
            +
                      <<-SRC
         
     | 
| 
      
 89 
     | 
    
         
            +
            #ifndef #{key}
         
     | 
| 
      
 90 
     | 
    
         
            +
            #define #{key} #{value}
         
     | 
| 
      
 91 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 92 
     | 
    
         
            +
                      SRC
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end.join("\n")
         
     | 
| 
      
 94 
     | 
    
         
            +
                    program << "\n"
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    includes = Array(opts[:include]) + DEFAULT_INCLUDES
         
     | 
| 
      
 97 
     | 
    
         
            +
                    program << includes.map { |include| "#include <#{include}>" }.join("\n")
         
     | 
| 
      
 98 
     | 
    
         
            +
                    program << "\n#{src}"
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                    File.open(TMP_PROGRAM, 'w') do |file|
         
     | 
| 
      
 101 
     | 
    
         
            +
                      file << program
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    cmd = "#{@cc} #{TMP_PROGRAM} -o #{EXE_NAME}"
         
     | 
| 
      
 105 
     | 
    
         
            +
                    system cmd
         
     | 
| 
      
 106 
     | 
    
         
            +
                    unless $?.success?
         
     | 
| 
      
 107 
     | 
    
         
            +
                      raise "failed to compile program: #{cmd.inspect}\n#{program}"
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                    output = `./#{EXE_NAME} 2>&1`
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    unless $?.success?
         
     | 
| 
      
 113 
     | 
    
         
            +
                      raise "failed to run program: #{cmd.inspect}\n#{output}"
         
     | 
| 
      
 114 
     | 
    
         
            +
                    end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    output.chomp
         
     | 
| 
      
 117 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 118 
     | 
    
         
            +
                    File.delete TMP_PROGRAM if File.exist?(TMP_PROGRAM)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    File.delete EXE_NAME if File.exist?(EXE_NAME)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  def result
         
     | 
| 
      
 123 
     | 
    
         
            +
                    if @sizeof.empty? && @constants.empty?
         
     | 
| 
      
 124 
     | 
    
         
            +
                      raise "no data collected, nothing to do"
         
     | 
| 
      
 125 
     | 
    
         
            +
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                    out =  ['module ChildProcess::Unix::Platform']
         
     | 
| 
      
 128 
     | 
    
         
            +
                    out << '  SIZEOF = {'
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    max = @sizeof.keys.map { |e| e.length }.max
         
     | 
| 
      
 131 
     | 
    
         
            +
                    @sizeof.each_with_index do |(type, size), idx|
         
     | 
| 
      
 132 
     | 
    
         
            +
                      out << "     :#{type.ljust max} => #{size}#{',' unless idx == @sizeof.size - 1}"
         
     | 
| 
      
 133 
     | 
    
         
            +
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
                    out << '  }'
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                    max = @constants.keys.map { |e| e.length }.max
         
     | 
| 
      
 137 
     | 
    
         
            +
                    @constants.each do |name, val|
         
     | 
| 
      
 138 
     | 
    
         
            +
                      out << "  #{name.ljust max} = #{val}"
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
      
 140 
     | 
    
         
            +
                    out << 'end'
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                    out.join "\n"
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
              end
         
     | 
| 
      
 147 
     | 
    
         
            +
            end
         
     | 
| 
      
 148 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess
         
     | 
| 
      
 3 
     | 
    
         
            +
              module Unix
         
     | 
| 
      
 4 
     | 
    
         
            +
                class ForkExecProcess < Process
         
     | 
| 
      
 5 
     | 
    
         
            +
                  private
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def launch_process
         
     | 
| 
      
 8 
     | 
    
         
            +
                    if @io
         
     | 
| 
      
 9 
     | 
    
         
            +
                      stdout = @io.stdout
         
     | 
| 
      
 10 
     | 
    
         
            +
                      stderr = @io.stderr
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    # pipe used to detect exec() failure
         
     | 
| 
      
 14 
     | 
    
         
            +
                    exec_r, exec_w = ::IO.pipe
         
     | 
| 
      
 15 
     | 
    
         
            +
                    ChildProcess.close_on_exec exec_w
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    if duplex?
         
     | 
| 
      
 18 
     | 
    
         
            +
                      reader, writer = ::IO.pipe
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    @pid = Kernel.fork {
         
     | 
| 
      
 22 
     | 
    
         
            +
                      # Children of the forked process will inherit its process group
         
     | 
| 
      
 23 
     | 
    
         
            +
                      # This is to make sure that all grandchildren dies when this Process instance is killed
         
     | 
| 
      
 24 
     | 
    
         
            +
                      ::Process.setpgid 0, 0 if leader?
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                      if @cwd
         
     | 
| 
      
 27 
     | 
    
         
            +
                        Dir.chdir(@cwd)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                      exec_r.close
         
     | 
| 
      
 31 
     | 
    
         
            +
                      set_env
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      STDOUT.reopen(stdout || "/dev/null")
         
     | 
| 
      
 34 
     | 
    
         
            +
                      STDERR.reopen(stderr || "/dev/null")
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                      if duplex?
         
     | 
| 
      
 37 
     | 
    
         
            +
                        STDIN.reopen(reader)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        writer.close
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      executable, *args = @args
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 44 
     | 
    
         
            +
                        Kernel.exec([executable, executable], *args)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      rescue SystemCallError => ex
         
     | 
| 
      
 46 
     | 
    
         
            +
                        exec_w << ex.message
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
                    }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    exec_w.close
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    if duplex?
         
     | 
| 
      
 53 
     | 
    
         
            +
                      io._stdin = writer
         
     | 
| 
      
 54 
     | 
    
         
            +
                      reader.close
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    # if we don't eventually get EOF, exec() failed
         
     | 
| 
      
 58 
     | 
    
         
            +
                    unless exec_r.eof?
         
     | 
| 
      
 59 
     | 
    
         
            +
                      raise LaunchError, exec_r.read || "executing command with #{@args.inspect} failed"
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    ::Process.detach(@pid) if detach?
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def set_env
         
     | 
| 
      
 66 
     | 
    
         
            +
                    @environment.each { |k, v| ENV[k.to_s] = v.nil? ? nil : v.to_s }
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                end # Process
         
     | 
| 
      
 70 
     | 
    
         
            +
              end # Unix
         
     | 
| 
      
 71 
     | 
    
         
            +
            end # ChildProcess
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess
         
     | 
| 
      
 3 
     | 
    
         
            +
              module Unix
         
     | 
| 
      
 4 
     | 
    
         
            +
                class IO < AbstractIO
         
     | 
| 
      
 5 
     | 
    
         
            +
                  private
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def check_type(io)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    unless io.respond_to? :to_io
         
     | 
| 
      
 9 
     | 
    
         
            +
                      raise ArgumentError, "expected #{io.inspect} to respond to :to_io"
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    result = io.to_io
         
     | 
| 
      
 13 
     | 
    
         
            +
                    unless result && result.kind_of?(::IO)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      raise TypeError, "expected IO, got #{result.inspect}:#{result.class}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                end # IO
         
     | 
| 
      
 19 
     | 
    
         
            +
              end # Unix
         
     | 
| 
      
 20 
     | 
    
         
            +
            end # ChildProcess
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,188 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess
         
     | 
| 
      
 3 
     | 
    
         
            +
              module Unix
         
     | 
| 
      
 4 
     | 
    
         
            +
                module Lib
         
     | 
| 
      
 5 
     | 
    
         
            +
                  extend FFI::Library
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ffi_lib FFI::Library::LIBC
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  if ChildProcess.os == :macosx
         
     | 
| 
      
 9 
     | 
    
         
            +
                    attach_function :_NSGetEnviron, [], :pointer
         
     | 
| 
      
 10 
     | 
    
         
            +
                    def self.environ
         
     | 
| 
      
 11 
     | 
    
         
            +
                      _NSGetEnviron().read_pointer
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  elsif respond_to? :attach_variable
         
     | 
| 
      
 14 
     | 
    
         
            +
                    attach_variable :environ, :pointer
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  attach_function :strerror, [:int], :string
         
     | 
| 
      
 18 
     | 
    
         
            +
                  attach_function :chdir, [:string], :int
         
     | 
| 
      
 19 
     | 
    
         
            +
                  attach_function :fcntl, [:int, :int, :int], :int # fcntl actually takes varags, but we only need this version.
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # int posix_spawnp(
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   pid_t *restrict pid,
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   const char *restrict file,
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   const posix_spawn_file_actions_t *file_actions,
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   const posix_spawnattr_t *restrict attrp,
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   char *const argv[restrict],
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #   char *const envp[restrict]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # );
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  attach_function :posix_spawnp, [
         
     | 
| 
      
 31 
     | 
    
         
            +
                    :pointer,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    :string,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    :pointer,
         
     | 
| 
      
 34 
     | 
    
         
            +
                    :pointer,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    :pointer,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    :pointer
         
     | 
| 
      
 37 
     | 
    
         
            +
                  ], :int
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions);
         
     | 
| 
      
 40 
     | 
    
         
            +
                  attach_function :posix_spawn_file_actions_init, [:pointer], :int
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  # int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions);
         
     | 
| 
      
 43 
     | 
    
         
            +
                  attach_function :posix_spawn_file_actions_destroy, [:pointer], :int
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  # int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, int filedes);
         
     | 
| 
      
 46 
     | 
    
         
            +
                  attach_function :posix_spawn_file_actions_addclose, [:pointer, :int], :int
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  # int posix_spawn_file_actions_addopen(
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   posix_spawn_file_actions_t *restrict file_actions,
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #   int filedes,
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #   const char *restrict path,
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #   int oflag,
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #   mode_t mode
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # );
         
     | 
| 
      
 55 
     | 
    
         
            +
                  attach_function :posix_spawn_file_actions_addopen, [:pointer, :int, :string, :int, :mode_t], :int
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # int posix_spawn_file_actions_adddup2(
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   posix_spawn_file_actions_t *file_actions,
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   int filedes,
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   int newfiledes
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # );
         
     | 
| 
      
 62 
     | 
    
         
            +
                  attach_function :posix_spawn_file_actions_adddup2, [:pointer, :int, :int], :int
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  # int posix_spawnattr_init(posix_spawnattr_t *attr);
         
     | 
| 
      
 65 
     | 
    
         
            +
                  attach_function :posix_spawnattr_init, [:pointer], :int
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  # int posix_spawnattr_destroy(posix_spawnattr_t *attr);
         
     | 
| 
      
 68 
     | 
    
         
            +
                  attach_function :posix_spawnattr_destroy, [:pointer], :int
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  # int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
         
     | 
| 
      
 71 
     | 
    
         
            +
                  attach_function :posix_spawnattr_setflags, [:pointer, :short], :int
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # int posix_spawnattr_getflags(const posix_spawnattr_t *restrict attr, short *restrict flags);
         
     | 
| 
      
 74 
     | 
    
         
            +
                  attach_function :posix_spawnattr_getflags, [:pointer, :pointer], :int
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  # int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
         
     | 
| 
      
 77 
     | 
    
         
            +
                  attach_function :posix_spawnattr_setpgroup, [:pointer, :pid_t], :int
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  # int posix_spawnattr_getpgroup(const posix_spawnattr_t *restrict attr, pid_t *restrict pgroup);
         
     | 
| 
      
 80 
     | 
    
         
            +
                  attach_function :posix_spawnattr_getpgroup, [:pointer, :pointer], :int
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  # int posix_spawnattr_setsigdefault(posix_spawnattr_t *restrict attr, const sigset_t *restrict sigdefault);
         
     | 
| 
      
 83 
     | 
    
         
            +
                  attach_function :posix_spawnattr_setsigdefault, [:pointer, :pointer], :int
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  # int posix_spawnattr_getsigdefault(const posix_spawnattr_t *restrict attr, sigset_t *restrict sigdefault);
         
     | 
| 
      
 86 
     | 
    
         
            +
                  attach_function :posix_spawnattr_getsigdefault, [:pointer, :pointer], :int
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  # int posix_spawnattr_setsigmask(posix_spawnattr_t *restrict attr, const sigset_t *restrict sigmask);
         
     | 
| 
      
 89 
     | 
    
         
            +
                  attach_function :posix_spawnattr_setsigmask, [:pointer, :pointer], :int
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  # int posix_spawnattr_getsigmask(const posix_spawnattr_t *restrict attr, sigset_t *restrict sigmask);
         
     | 
| 
      
 92 
     | 
    
         
            +
                  attach_function :posix_spawnattr_getsigmask, [:pointer, :pointer], :int
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  def self.check(errno)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    if errno != 0
         
     | 
| 
      
 96 
     | 
    
         
            +
                      raise Error, Lib.strerror(FFI.errno)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  class FileActions
         
     | 
| 
      
 101 
     | 
    
         
            +
                    def initialize
         
     | 
| 
      
 102 
     | 
    
         
            +
                      @ptr = FFI::MemoryPointer.new(1, Platform::SIZEOF.fetch(:posix_spawn_file_actions_t), false)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      Lib.check Lib.posix_spawn_file_actions_init(@ptr)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    def add_close(fileno)
         
     | 
| 
      
 107 
     | 
    
         
            +
                      Lib.check Lib.posix_spawn_file_actions_addclose(
         
     | 
| 
      
 108 
     | 
    
         
            +
                        @ptr,
         
     | 
| 
      
 109 
     | 
    
         
            +
                        fileno
         
     | 
| 
      
 110 
     | 
    
         
            +
                      )
         
     | 
| 
      
 111 
     | 
    
         
            +
                    end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                    def add_open(fileno, path, oflag, mode)
         
     | 
| 
      
 114 
     | 
    
         
            +
                      Lib.check Lib.posix_spawn_file_actions_addopen(
         
     | 
| 
      
 115 
     | 
    
         
            +
                        @ptr,
         
     | 
| 
      
 116 
     | 
    
         
            +
                        fileno,
         
     | 
| 
      
 117 
     | 
    
         
            +
                        path,
         
     | 
| 
      
 118 
     | 
    
         
            +
                        oflag,
         
     | 
| 
      
 119 
     | 
    
         
            +
                        mode
         
     | 
| 
      
 120 
     | 
    
         
            +
                      )
         
     | 
| 
      
 121 
     | 
    
         
            +
                    end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    def add_dup(fileno, new_fileno)
         
     | 
| 
      
 124 
     | 
    
         
            +
                      Lib.check Lib.posix_spawn_file_actions_adddup2(
         
     | 
| 
      
 125 
     | 
    
         
            +
                        @ptr,
         
     | 
| 
      
 126 
     | 
    
         
            +
                        fileno,
         
     | 
| 
      
 127 
     | 
    
         
            +
                        new_fileno
         
     | 
| 
      
 128 
     | 
    
         
            +
                      )
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                    def free
         
     | 
| 
      
 132 
     | 
    
         
            +
                      Lib.check Lib.posix_spawn_file_actions_destroy(@ptr)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      @ptr = nil
         
     | 
| 
      
 134 
     | 
    
         
            +
                    end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                    def to_ptr
         
     | 
| 
      
 137 
     | 
    
         
            +
                      @ptr
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end # FileActions
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  class Attrs
         
     | 
| 
      
 142 
     | 
    
         
            +
                    def initialize
         
     | 
| 
      
 143 
     | 
    
         
            +
                      @ptr = FFI::MemoryPointer.new(1, Platform::SIZEOF.fetch(:posix_spawnattr_t), false)
         
     | 
| 
      
 144 
     | 
    
         
            +
                      Lib.check Lib.posix_spawnattr_init(@ptr)
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                    def free
         
     | 
| 
      
 148 
     | 
    
         
            +
                      Lib.check Lib.posix_spawnattr_destroy(@ptr)
         
     | 
| 
      
 149 
     | 
    
         
            +
                      @ptr = nil
         
     | 
| 
      
 150 
     | 
    
         
            +
                    end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                    def flags=(flags)
         
     | 
| 
      
 153 
     | 
    
         
            +
                      Lib.check Lib.posix_spawnattr_setflags(@ptr, flags)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                    def flags
         
     | 
| 
      
 157 
     | 
    
         
            +
                      ptr = FFI::MemoryPointer.new(:short)
         
     | 
| 
      
 158 
     | 
    
         
            +
                      Lib.check Lib.posix_spawnattr_getflags(@ptr, ptr)
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                      ptr.read_short
         
     | 
| 
      
 161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                    def pgroup=(pid)
         
     | 
| 
      
 164 
     | 
    
         
            +
                      self.flags |= Platform::POSIX_SPAWN_SETPGROUP
         
     | 
| 
      
 165 
     | 
    
         
            +
                      Lib.check Lib.posix_spawnattr_setpgroup(@ptr, pid)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                    def to_ptr
         
     | 
| 
      
 169 
     | 
    
         
            +
                      @ptr
         
     | 
| 
      
 170 
     | 
    
         
            +
                    end
         
     | 
| 
      
 171 
     | 
    
         
            +
                  end # Attrs
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
              end
         
     | 
| 
      
 175 
     | 
    
         
            +
            end
         
     | 
| 
      
 176 
     | 
    
         
            +
            end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
            # missing on rubinius
         
     | 
| 
      
 179 
     | 
    
         
            +
            class FFI::MemoryPointer
         
     | 
| 
      
 180 
     | 
    
         
            +
              unless method_defined?(:from_string)
         
     | 
| 
      
 181 
     | 
    
         
            +
                def self.from_string(str)
         
     | 
| 
      
 182 
     | 
    
         
            +
                  ptr = new(1, str.bytesize + 1)
         
     | 
| 
      
 183 
     | 
    
         
            +
                  ptr.write_string("#{str}\0")
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                  ptr
         
     | 
| 
      
 186 
     | 
    
         
            +
                end
         
     | 
| 
      
 187 
     | 
    
         
            +
              end
         
     | 
| 
      
 188 
     | 
    
         
            +
            end if defined?(FFI)
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess::Unix::Platform
         
     | 
| 
      
 3 
     | 
    
         
            +
              SIZEOF = {
         
     | 
| 
      
 4 
     | 
    
         
            +
                 :posix_spawn_file_actions_t => 76,
         
     | 
| 
      
 5 
     | 
    
         
            +
                 :posix_spawnattr_t          => 336,
         
     | 
| 
      
 6 
     | 
    
         
            +
                 :sigset_t                   => 128
         
     | 
| 
      
 7 
     | 
    
         
            +
              }
         
     | 
| 
      
 8 
     | 
    
         
            +
              POSIX_SPAWN_RESETIDS   = 1
         
     | 
| 
      
 9 
     | 
    
         
            +
              POSIX_SPAWN_SETPGROUP  = 2
         
     | 
| 
      
 10 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGDEF  = 4
         
     | 
| 
      
 11 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGMASK = 8
         
     | 
| 
      
 12 
     | 
    
         
            +
              POSIX_SPAWN_USEVFORK   = 64
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess::Unix::Platform
         
     | 
| 
      
 3 
     | 
    
         
            +
              SIZEOF = {
         
     | 
| 
      
 4 
     | 
    
         
            +
                 :posix_spawn_file_actions_t => 4,
         
     | 
| 
      
 5 
     | 
    
         
            +
                 :posix_spawnattr_t          => 4,
         
     | 
| 
      
 6 
     | 
    
         
            +
                 :sigset_t                   => 16
         
     | 
| 
      
 7 
     | 
    
         
            +
              }
         
     | 
| 
      
 8 
     | 
    
         
            +
              POSIX_SPAWN_RESETIDS   = 1
         
     | 
| 
      
 9 
     | 
    
         
            +
              POSIX_SPAWN_SETPGROUP  = 2
         
     | 
| 
      
 10 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGDEF  = 4
         
     | 
| 
      
 11 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGMASK = 8
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess::Unix::Platform
         
     | 
| 
      
 3 
     | 
    
         
            +
              SIZEOF = {
         
     | 
| 
      
 4 
     | 
    
         
            +
                 :posix_spawn_file_actions_t => 80,
         
     | 
| 
      
 5 
     | 
    
         
            +
                 :posix_spawnattr_t          => 336,
         
     | 
| 
      
 6 
     | 
    
         
            +
                 :sigset_t                   => 128
         
     | 
| 
      
 7 
     | 
    
         
            +
              }
         
     | 
| 
      
 8 
     | 
    
         
            +
              POSIX_SPAWN_RESETIDS   = 1
         
     | 
| 
      
 9 
     | 
    
         
            +
              POSIX_SPAWN_SETPGROUP  = 2
         
     | 
| 
      
 10 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGDEF  = 4
         
     | 
| 
      
 11 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGMASK = 8
         
     | 
| 
      
 12 
     | 
    
         
            +
              POSIX_SPAWN_USEVFORK   = 64
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 2 
     | 
    
         
            +
            module ChildProcess::Unix::Platform
         
     | 
| 
      
 3 
     | 
    
         
            +
              SIZEOF = {
         
     | 
| 
      
 4 
     | 
    
         
            +
                 :posix_spawn_file_actions_t => 8,
         
     | 
| 
      
 5 
     | 
    
         
            +
                 :posix_spawnattr_t          => 8,
         
     | 
| 
      
 6 
     | 
    
         
            +
                 :sigset_t                   => 4
         
     | 
| 
      
 7 
     | 
    
         
            +
              }
         
     | 
| 
      
 8 
     | 
    
         
            +
              POSIX_SPAWN_RESETIDS   = 1
         
     | 
| 
      
 9 
     | 
    
         
            +
              POSIX_SPAWN_SETPGROUP  = 2
         
     | 
| 
      
 10 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGDEF  = 4
         
     | 
| 
      
 11 
     | 
    
         
            +
              POSIX_SPAWN_SETSIGMASK = 8
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,135 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'thread'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DockerToolkit
         
     | 
| 
      
 4 
     | 
    
         
            +
            module ChildProcess
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Unix
         
     | 
| 
      
 6 
     | 
    
         
            +
                class PosixSpawnProcess < Process
         
     | 
| 
      
 7 
     | 
    
         
            +
                  private
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  @@cwd_lock = Mutex.new
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def launch_process
         
     | 
| 
      
 12 
     | 
    
         
            +
                    pid_ptr = FFI::MemoryPointer.new(:pid_t)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    actions = Lib::FileActions.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                    attrs   = Lib::Attrs.new
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    if io.stdout
         
     | 
| 
      
 17 
     | 
    
         
            +
                      actions.add_dup fileno_for(io.stdout), fileno_for(STDOUT)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    else
         
     | 
| 
      
 19 
     | 
    
         
            +
                      actions.add_open fileno_for(STDOUT), "/dev/null", File::WRONLY, 0644
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    if io.stderr
         
     | 
| 
      
 23 
     | 
    
         
            +
                      actions.add_dup fileno_for(io.stderr), fileno_for(STDERR)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    else
         
     | 
| 
      
 25 
     | 
    
         
            +
                      actions.add_open fileno_for(STDERR), "/dev/null", File::WRONLY, 0644
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    if duplex?
         
     | 
| 
      
 29 
     | 
    
         
            +
                      reader, writer = ::IO.pipe
         
     | 
| 
      
 30 
     | 
    
         
            +
                      actions.add_dup fileno_for(reader), fileno_for(STDIN)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      actions.add_close fileno_for(writer)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    attrs.pgroup = 0 if leader?
         
     | 
| 
      
 35 
     | 
    
         
            +
                    attrs.flags |= Platform::POSIX_SPAWN_USEVFORK if defined? Platform::POSIX_SPAWN_USEVFORK
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    # wrap in helper classes in order to avoid GC'ed pointers
         
     | 
| 
      
 38 
     | 
    
         
            +
                    argv = Argv.new(@args)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    envp = Envp.new(ENV.to_hash.merge(@environment))
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    ret = 0
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @@cwd_lock.synchronize do
         
     | 
| 
      
 43 
     | 
    
         
            +
                      Dir.chdir(@cwd || Dir.pwd) do
         
     | 
| 
      
 44 
     | 
    
         
            +
                        if ChildProcess.jruby?
         
     | 
| 
      
 45 
     | 
    
         
            +
                          # on JRuby, the current working directory is for some reason not inherited.
         
     | 
| 
      
 46 
     | 
    
         
            +
                          # We'll work around it by making a chdir call through FFI.
         
     | 
| 
      
 47 
     | 
    
         
            +
                          # TODO: report this to JRuby
         
     | 
| 
      
 48 
     | 
    
         
            +
                          Lib.chdir Dir.pwd
         
     | 
| 
      
 49 
     | 
    
         
            +
                        end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                        ret = Lib.posix_spawnp(
         
     | 
| 
      
 52 
     | 
    
         
            +
                          pid_ptr,
         
     | 
| 
      
 53 
     | 
    
         
            +
                          @args.first, # TODO: not sure this matches exec() behaviour
         
     | 
| 
      
 54 
     | 
    
         
            +
                          actions,
         
     | 
| 
      
 55 
     | 
    
         
            +
                          attrs,
         
     | 
| 
      
 56 
     | 
    
         
            +
                          argv,
         
     | 
| 
      
 57 
     | 
    
         
            +
                          envp
         
     | 
| 
      
 58 
     | 
    
         
            +
                        )
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    if duplex?
         
     | 
| 
      
 63 
     | 
    
         
            +
                      io._stdin = writer
         
     | 
| 
      
 64 
     | 
    
         
            +
                      reader.close
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    actions.free
         
     | 
| 
      
 68 
     | 
    
         
            +
                    attrs.free
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    if ret != 0
         
     | 
| 
      
 71 
     | 
    
         
            +
                      raise LaunchError, "#{Lib.strerror(ret)} (#{ret})"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    @pid = pid_ptr.read_int
         
     | 
| 
      
 75 
     | 
    
         
            +
                    ::Process.detach(@pid) if detach?
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  if ChildProcess.jruby?
         
     | 
| 
      
 79 
     | 
    
         
            +
                    def fileno_for(obj)
         
     | 
| 
      
 80 
     | 
    
         
            +
                      ChildProcess::JRuby.posix_fileno_for(obj)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  else
         
     | 
| 
      
 83 
     | 
    
         
            +
                    def fileno_for(obj)
         
     | 
| 
      
 84 
     | 
    
         
            +
                      obj.fileno
         
     | 
| 
      
 85 
     | 
    
         
            +
                    end
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  class Argv
         
     | 
| 
      
 89 
     | 
    
         
            +
                    def initialize(args)
         
     | 
| 
      
 90 
     | 
    
         
            +
                      @ptrs = args.map do |e|
         
     | 
| 
      
 91 
     | 
    
         
            +
                        if e.include?("\0")
         
     | 
| 
      
 92 
     | 
    
         
            +
                          raise ArgumentError, "argument cannot contain null bytes: #{e.inspect}"
         
     | 
| 
      
 93 
     | 
    
         
            +
                        end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                        FFI::MemoryPointer.from_string(e.to_s)
         
     | 
| 
      
 96 
     | 
    
         
            +
                      end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                      @ptrs << FFI::Pointer.new(0)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    def to_ptr
         
     | 
| 
      
 102 
     | 
    
         
            +
                      argv = FFI::MemoryPointer.new(:pointer, @ptrs.size)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      argv.put_array_of_pointer(0, @ptrs)
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                      argv
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end # Argv
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  class Envp
         
     | 
| 
      
 110 
     | 
    
         
            +
                    def initialize(env)
         
     | 
| 
      
 111 
     | 
    
         
            +
                      @ptrs = env.map do |key, val|
         
     | 
| 
      
 112 
     | 
    
         
            +
                        next if val.nil?
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                        if key =~ /=|\0/ || val.include?("\0")
         
     | 
| 
      
 115 
     | 
    
         
            +
                          raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.inspect}"
         
     | 
| 
      
 116 
     | 
    
         
            +
                        end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                        FFI::MemoryPointer.from_string("#{key}=#{val}")
         
     | 
| 
      
 119 
     | 
    
         
            +
                      end.compact
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                      @ptrs << FFI::Pointer.new(0)
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                    def to_ptr
         
     | 
| 
      
 125 
     | 
    
         
            +
                      env = FFI::MemoryPointer.new(:pointer, @ptrs.size)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      env.put_array_of_pointer(0, @ptrs)
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                      env
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end # Envp
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
              end
         
     | 
| 
      
 134 
     | 
    
         
            +
            end
         
     | 
| 
      
 135 
     | 
    
         
            +
            end
         
     |