<commit_before>module Invoker
  # Class is responsible for managing all the processes Invoker is supposed
  # to manage. Takes care of starting, stopping and restarting processes.
  class ProcessManager
    LABEL_COLORS = [:green, :yellow, :blue, :magenta, :cyan]
    attr_accessor :open_pipes, :workers

    def initialize
      @open_pipes = {}
      @workers = {}
      @worker_mutex = Mutex.new
      @thread_group = ThreadGroup.new
    end

    def start_process(process_info)
      m, s = PTY.open
      s.raw! # disable newline conversion.

      pid = run_command(process_info, s)

      s.close

      worker = CommandWorker.new(process_info.label, m, pid, select_color)

      add_worker(worker)
      wait_on_pid(process_info.label, pid)
    end

    # Start a process given their name
    # @param process_name [String] Command label of process specified in config file.
    def start_process_by_name(process_name)
      if process_running?(process_name)
        Invoker::Logger.puts "\nProcess '#{process_name}' is already running".color(:red)
        return false
      end

      process_info = Invoker.config.process(process_name)
      start_process(process_info) if process_info
    end

    # Remove a process from list of processes managed by invoker supervisor.It also
    # kills the process before removing it from the list.
    #
    # @param remove_message [Invoker::IPC::Message::Remove]
    # @return [Boolean] if process existed and was removed else false
    def stop_process(remove_message)
      worker = workers[remove_message.process_name]
      command_label = remove_message.process_name
      return false unless worker
      signal_to_use = remove_message.signal || 'INT'

      Invoker::Logger.puts("Removing #{command_label} with signal #{signal_to_use}".color(:red))
      kill_or_remove_process(worker.pid, signal_to_use, command_label)
    end

    # Receive a message from user to restart a Process
    # @param [Invoker::IPC::Message::Reload]
    def restart_process(reload_message)
      command_label = reload_message.process_name
      if stop_process(reload_message.remove_message)
        Invoker.commander.schedule_event(command_label, :worker_removed) do
          start_process_by_name(command_label)
        end
      else
        start_process_by_name(command_label)
      end
    end

    def run_power_server
      return unless Invoker.can_run_balancer?(false)

      powerup_id = Invoker::Power::Powerup.fork_and_start
      wait_on_pid("powerup_manager", powerup_id)
      at_exit do
        begin
          Process.kill("INT", powerup_id)
        rescue Errno::ESRCH; end
      end
    end

    # Given a file descriptor returns the worker object
    #
    # @param fd [IO] an IO object with valid file descriptor
    # @return [Invoker::CommandWorker] The worker object which is associated with this fd
    def get_worker_from_fd(fd)
      open_pipes[fd.fileno]
    end

    def load_env(directory = nil)
      directory ||= ENV['PWD']<commit_msg>Fix minor bug with pwd not existing in certain envs<commit_after>module Invoker
  # Class is responsible for managing all the processes Invoker is supposed
  # to manage. Takes care of starting, stopping and restarting processes.
  class ProcessManager
    LABEL_COLORS = [:green, :yellow, :blue, :magenta, :cyan]
    attr_accessor :open_pipes, :workers

    def initialize
      @open_pipes = {}
      @workers = {}
      @worker_mutex = Mutex.new
      @thread_group = ThreadGroup.new
    end

    def start_process(process_info)
      m, s = PTY.open
      s.raw! # disable newline conversion.

      pid = run_command(process_info, s)

      s.close

      worker = CommandWorker.new(process_info.label, m, pid, select_color)

      add_worker(worker)
      wait_on_pid(process_info.label, pid)
    end

    # Start a process given their name
    # @param process_name [String] Command label of process specified in config file.
    def start_process_by_name(process_name)
      if process_running?(process_name)
        Invoker::Logger.puts "\nProcess '#{process_name}' is already running".color(:red)
        return false
      end

      process_info = Invoker.config.process(process_name)
      start_process(process_info) if process_info
    end

    # Remove a process from list of processes managed by invoker supervisor.It also
    # kills the process before removing it from the list.
    #
    # @param remove_message [Invoker::IPC::Message::Remove]
    # @return [Boolean] if process existed and was removed else false
    def stop_process(remove_message)
      worker = workers[remove_message.process_name]
      command_label = remove_message.process_name
      return false unless worker
      signal_to_use = remove_message.signal || 'INT'

      Invoker::Logger.puts("Removing #{command_label} with signal #{signal_to_use}".color(:red))
      kill_or_remove_process(worker.pid, signal_to_use, command_label)
    end

    # Receive a message from user to restart a Process
    # @param [Invoker::IPC::Message::Reload]
    def restart_process(reload_message)
      command_label = reload_message.process_name
      if stop_process(reload_message.remove_message)
        Invoker.commander.schedule_event(command_label, :worker_removed) do
          start_process_by_name(command_label)
        end
      else
        start_process_by_name(command_label)
      end
    end

    def run_power_server
      return unless Invoker.can_run_balancer?(false)

      powerup_id = Invoker::Power::Powerup.fork_and_start
      wait_on_pid("powerup_manager", powerup_id)
      at_exit do
        begin
          Process.kill("INT", powerup_id)
        rescue Errno::ESRCH; end
      end
    end

    # Given a file descriptor returns the worker object
    #
    # @param fd [IO] an IO object with valid file descriptor
    # @return [Invoker::CommandWorker] The worker object which is associated with this fd
    def get_worker_from_fd(fd)
      open_pipes[fd.fileno]
    end

    def load_env(directory = nil)
      directory ||= ENV['PWD']

      if !directory || directory.empty? || !Dir.exist?(directory)
        return {}
      end

{'fraction_non_alphanumeric': 0.07772357723577236, 'fraction_numerical': 0.0, 'mean_word_length': 3.170169491525424, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4714445', 'n_tokens_mistral': 1835, 'n_tokens_neox': 1804, 'n_words': 494}