module Rcodetools::Fork

Constants

DEFAULT_SETTINGS

'

PORT
PWD_FILE

Contains $PWD of rct-fork server. Exists only while running.

USAGE_HELP

Public Class Methods

add_env_args(opts, settings) click to toggle source
# File lib/rcodetools/fork.rb, line 64
def self.add_env_args(opts, settings)
  opts.separator ''
  opts.separator 'Process environment options:'

  opts.separator ''
  opts.on('-e CODE', 'Execute CODE in parent process.',
          'May be specified multiple times.') do |code|
    settings[:code] << code
  end

  opts.separator ''
  opts.on('-I DIRECTORY', 'Adds DIRECTORY to $LOAD_PATH.',
          'May be specified multiple times.') do |dir|
    settings[:extra_paths] << dir
  end

  opts.separator ''
  opts.on('-r LIBRARY', 'Require LIBRARY in the parent process.',
          'May be specified multiple times.') do |lib|
    settings[:requires] << lib
  end
end
chdir_fork_directory() click to toggle source
# File lib/rcodetools/fork_config.rb, line 9
def self.chdir_fork_directory
  if run?
    Dir.chdir File.read(PWD_FILE)
  else
    raise "rct-fork is not running."
  end
end
daemonize(io = File.open('/dev/null', 'r+')) { || ... } click to toggle source
# File lib/rcodetools/fork.rb, line 87
def self.daemonize(io = File.open('/dev/null', 'r+'))
  fork and exit!
  Process.setsid
  fork and exit!

  STDIN.reopen io
  STDOUT.reopen io
  STDERR.reopen io

  yield if block_given?
end
parse_client_args(args) click to toggle source
# File lib/rcodetools/fork.rb, line 99
def self.parse_client_args(args)
  settings = Marshal.load Marshal.dump(DEFAULT_SETTINGS)

  opts = OptionParser.new do |opts|
    opts.banner = "Usage: #{$0} [options]\n#{USAGE_HELP}"

    opts.separator ''
    opts.on('-p', '--port PORT',
            'Listen for connections on PORT.',
            "Default: #{settings[:port]}") do |port|
      settings[:port] = port.to_i
            end

    opts.separator ''
    opts.on('-h', '--help', 'You\re looking at it.') do
      $stderr.puts opts
      exit 1
    end

    add_env_args opts, settings
  end

  opts.parse! args

  return settings
end
parse_server_args(args) click to toggle source
# File lib/rcodetools/fork.rb, line 126
def self.parse_server_args(args)
  settings = Marshal.load Marshal.dump(DEFAULT_SETTINGS)

  opts = OptionParser.new do |opts|
    opts.banner = "Usage: #{$0} [options]\n#{USAGE_HELP}"

    opts.separator ''
    opts.on('-p', '--port PORT',
            'Listen for connections on PORT.',
            "Default: #{settings[:port]}") do |port|
      settings[:port] = port.to_i
    end

    opts.separator ''
    opts.on('-h', '--help', 'You\re looking at it.') do
      $stderr.puts opts
      exit 1
    end

    add_env_args opts, settings
  end

  opts.parse! args

  return settings
end
run?() click to toggle source
# File lib/rcodetools/fork_config.rb, line 21
def self.run?
  File.file? PWD_FILE
end
setup_environment(settings) click to toggle source
# File lib/rcodetools/fork.rb, line 213
def self.setup_environment(settings)
  settings[:extra_paths].map! { |dir| dir.split ':' }
  settings[:extra_paths].flatten!
  settings[:extra_paths].each { |dir| $:.unshift dir }

  begin
    settings[:requires].each { |file| require file }
    settings[:code].each { |code| eval code, TOPLEVEL_BINDING }
  rescue Exception
    $@.reject! {|s| s =~ %rrcodetools/fork\.rb!}
    raise
  end
end
start_client(args = ARGV) click to toggle source
# File lib/rcodetools/fork.rb, line 153
def self.start_client(args = ARGV)
  trap 'INT' do exit 1 end # Exit gracefully

  settings = parse_client_args args

  args = Marshal.dump [settings, ARGV]

  socket = TCPSocket.new 'localhost', settings[:port]

  socket.puts args.length
  socket.write args
  socket.close_write

  until socket.eof?
    $stdout.puts socket.gets
  end
end
start_server(args = ARGV) click to toggle source
# File lib/rcodetools/fork.rb, line 171
def self.start_server(args = ARGV)
  begin
    require 'rubygems'
  rescue LoadError
  end
  write_pwd
  settings = parse_server_args args
  setup_environment settings

  server = TCPServer.new 'localhost', settings[:port]

  $stderr.puts "#{$0} Running as PID #{$$} on #{settings[:port]}"

  loop do
    Thread.new server.accept do |socket|
      begin
        args_length = socket.gets.to_i
        args = socket.read args_length
        settings, argv = Marshal.load args

        fork do
          daemonize socket do
            ARGV.replace argv
            setup_environment settings
            socket.close
          end
        end

        socket.close # close my copy.
      rescue => e
        socket.close if socket
      end
    end
  end
rescue Interrupt, SystemExit
  File.unlink PWD_FILE
rescue Exception => e
  File.unlink PWD_FILE
  puts "Failed to catch #{e.class}:#{e.message}"
  puts "\t#{e.backtrace.join "\n\t"}"
end
write_pwd() click to toggle source
# File lib/rcodetools/fork_config.rb, line 17
def self.write_pwd
  open(PWD_FILE, "w"){|f| f.print Dir.pwd }
end