class Spring::Server

def self.boot

def self.boot
  new.boot
end

def boot

def boot
  Spring.verify_environment
  write_pidfile
  set_pgid
  ignore_signals
  set_exit_hook
  set_process_title
  start_server
end

def ignore_signals

will kill the server/application.
Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line
def ignore_signals
  IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
end

def initialize(env = Env.new)

def initialize(env = Env.new)
  @env          = env
  @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k) }
  @pidfile      = env.pidfile_path.open('a')
  @mutex        = Mutex.new
end

def log(message)

def log(message)
  env.log "[server] #{message}"
end

def rails_env_for(args, default_rails_env)

def rails_env_for(args, default_rails_env)
  Spring.command(args.first).env(args.drop(1)) || default_rails_env
end

def redirect_output

would keep the stdout FD open.)
`spring rake -T | grep db` would hang forever because the server
keep the original FDs open which would break piping. (e.g.
We need to redirect STDOUT and STDERR, otherwise the server will
def redirect_output
  [STDOUT, STDERR].each { |stream| stream.reopen(env.log_file) }
end

def serve(client)

def serve(client)
  log "accepted client"
  client.puts env.version
  app_client = client.recv_io
  command    = JSON.load(client.read(client.gets.to_i))
  args, default_rails_env = command.values_at('args', 'default_rails_env')
  if Spring.command?(args.first)
    log "running command #{args.first}"
    client.puts
    client.puts @applications[rails_env_for(args, default_rails_env)].run(app_client)
  else
    log "command not found #{args.first}"
    client.close
  end
rescue SocketError => e
  raise e unless client.eof?
ensure
  redirect_output
end

def set_exit_hook

def set_exit_hook
  server_pid = Process.pid
  # We don't want this hook to run in any forks of the current process
  at_exit { shutdown if Process.pid == server_pid }
end

def set_pgid

ends (i.e. when the user closes their terminal).
This will cause it to be automatically killed once the session
Boot the server into the process group of the current session.
def set_pgid
  Process.setpgid(0, SID.pgid)
end

def set_process_title

def set_process_title
  ProcessTitleUpdater.run { |distance|
    "spring server | #{env.app_name} | started #{distance} ago"
  }
end

def shutdown

def shutdown
  log "shutting down"
  [env.socket_path, env.pidfile_path].each do |path|
    if path.exist?
      path.unlink rescue nil
    end
  end
  @applications.values.map { |a| Thread.new { a.stop } }.map(&:join)
end

def start_server

def start_server
  server = UNIXServer.open(env.socket_name)
  log "started on #{env.socket_name}"
  loop { serve server.accept }
end

def write_pidfile

def write_pidfile
  if @pidfile.flock(File::LOCK_EX | File::LOCK_NB)
    @pidfile.truncate(0)
    @pidfile.write("#{Process.pid}\n")
    @pidfile.fsync
  else
    exit 1
  end
end