class Spring::Server

def self.boot(options = {})

def self.boot(options = {})
  new(options).boot
end

def boot

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

def default_env

def default_env
  Env.new(log_file: default_log_file)
end

def default_log_file

def default_log_file
  if foreground? && !ENV["SPRING_LOG"]
    $stdout
  else
    nil
  end
end

def foreground?

def foreground?
  @foreground
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(options = {})

def initialize(options = {})
  @foreground   = options.fetch(:foreground, false)
  @env          = options[:env] || default_env
  @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k, env) }
  @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| Spring.failsafe_thread { 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 }
rescue Interrupt
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