class Necro::Commander

Constants

LABEL_COLORS
MAX_PROCESS_COUNT

Attributes

open_pipes[RW]
reactor[RW]
thread_group[RW]
workers[RW]

Public Class Methods

new() click to toggle source
# File lib/necro/commander.rb, line 10
def initialize
  # mapping between open pipes and worker classes
  @open_pipes = {}

  # mapping between command label and worker classes
  @workers = {}
  
  @thread_group = ThreadGroup.new()
  @worker_mutex = Mutex.new()
  @reactor = Necro::Reactor.new
  Thread.abort_on_exception = true
end

Public Instance Methods

add_command(process_info) click to toggle source
# File lib/necro/commander.rb, line 33
def add_command(process_info)
  m, s = PTY.open
  s.raw! # disable newline conversion.

  pid = run_command(process_info, s)

  s.close()

  selected_color = LABEL_COLORS.shift()
  LABEL_COLORS.push(selected_color)
  worker = Necro::CommandWorker.new(process_info.label, m, pid, selected_color)

  add_worker(worker)
  wait_on_pid(process_info.label,pid)
end
add_command_by_label(command_label) click to toggle source
# File lib/necro/commander.rb, line 49
def add_command_by_label(command_label)
  process_info = Necro::CONFIG.processes.detect {|pconfig|
    pconfig.label == command_label
  }
  if process_info
    add_command(process_info)
  end
end
get_worker_from_fd(fd) click to toggle source
# File lib/necro/commander.rb, line 73
def get_worker_from_fd(fd)
  open_pipes[fd.fileno]
end
get_worker_from_label(label) click to toggle source
# File lib/necro/commander.rb, line 77
def get_worker_from_label(label)
  workers[label]
end
reload_command(command_label) click to toggle source
# File lib/necro/commander.rb, line 58
def reload_command(command_label)
  remove_command(command_label)
  add_command_by_label(command_label)
end
remove_command(command_label, rest_args) click to toggle source
# File lib/necro/commander.rb, line 63
def remove_command(command_label, rest_args)
  worker = workers[command_label]
  signal_to_use = rest_args ? Array(rest_args).first : 'INT'

  if worker
    $stdout.puts("Removing #{command_label} with signal #{signal_to_use}".red)
    process_kill(worker.pid, signal_to_use)
  end
end
start_manager() click to toggle source
# File lib/necro/commander.rb, line 23
def start_manager
  if !Necro::CONFIG.processes || Necro::CONFIG.processes.empty?
    raise Necro::Errors::InvalidConfig.new("No processes configured in config file")
  end
  unix_server_thread = Thread.new { Necro::CommandListener::Server.new() }
  thread_group.add(unix_server_thread)
  Necro::CONFIG.processes.each { |process_info| add_command(process_info) }
  reactor.start
end

Private Instance Methods

add_worker(worker) click to toggle source

add worker to global collections

# File lib/necro/commander.rb, line 103
def add_worker(worker)
  @worker_mutex.synchronize do
    @open_pipes[worker.pipe_end.fileno] = worker
    @workers[worker.command_label] = worker
    @reactor.add_to_monitor(worker.pipe_end)
  end
end
check_and_notify_with_terminal_notifier(message) click to toggle source
# File lib/necro/commander.rb, line 147
def check_and_notify_with_terminal_notifier(message)
  return unless RUBY_PLATFORM.downcase.include?("darwin")

  command_path = `which terminal-notifier`
  if command_path && !command_path.empty?
    system("terminal-notifier -message '#{message}' -title Necro")
  end
end
notify_user(message) click to toggle source
# File lib/necro/commander.rb, line 137
def notify_user(message)
  if defined?(Bundler)
    Bundler.with_clean_env do
      check_and_notify_with_terminal_notifier(message)
    end
  else
    check_and_notify_with_terminal_notifier(message)
  end
end
process_kill(pid, signal_to_use) click to toggle source
# File lib/necro/commander.rb, line 82
def process_kill(pid, signal_to_use)
  if signal_to_use.to_i == 0
    Process.kill(signal_to_use, pid)
  else
    Process.kill(signal_to_use.to_i, pid)
  end
end
remove_worker(command_label) click to toggle source

Remove worker from all collections

# File lib/necro/commander.rb, line 91
def remove_worker(command_label)
  @worker_mutex.synchronize do
    worker = @workers[command_label]
    if worker
      @open_pipes.delete(worker.pipe_end.fileno)
      @reactor.remove_from_monitoring(worker.pipe_end)
      @workers.delete(command_label)
    end
  end
end
run_command(process_info, write_pipe) click to toggle source
# File lib/necro/commander.rb, line 111
def run_command(process_info, write_pipe)
  if defined?(Bundler)
    Bundler.with_clean_env do
      spawn(process_info.cmd, 
        :chdir => process_info.dir || "/", :out => write_pipe, :err => write_pipe
      )
    end
  else
    spawn(process_info.cmd, 
      :chdir => process_info.dir || "/", :out => write_pipe, :err => write_pipe
    )
  end
end
wait_on_pid(command_label,pid) click to toggle source
# File lib/necro/commander.rb, line 125
def wait_on_pid(command_label,pid)
  raise Necro::Errors::ToomanyOpenConnections if @thread_group.enclosed?
  thread = Thread.new do
    Process.wait(pid)
    message = "Process with command #{command_label} exited with status #{$?.exitstatus}"
    $stdout.puts("\n#{message}".red)
    notify_user(message)
    remove_worker(command_label)
  end
  @thread_group.add(thread)
end