<commit_before>require 'shellwords'
require 'pathname'

module Eye::System
  class << self

    # Check that pid realy exits
    # very fast
    def pid_alive?(pid)
      pid ? ::Process.kill(0, pid) && true : false
    rescue Errno::ESRCH
      false
    end

    # Send signal to process (uses for kill)
    # code: TERM(15), KILL(9), QUIT(3), ...
    def send_signal(pid, code = :TERM)
      code = code.to_s.upcase if code.is_a?(String) || code.is_a?(Symbol)

      ::Process.kill(code, pid)
      {:status => :ok}

    rescue Errno::ESRCH    
      {:status => :error, :message => 'process not found'}

    rescue => e
      {:status => :error, :message => "failed signal #{code}: #{e.message}"}
    end

    # Daemonize cmd, and detach
    # options:
    #   :pid_file
    #   :working_dir
    #   :environment
    #   :stdin, :stdout, :stderr
    def daemonize(cmd, cfg = {})
      opts = spawn_options(cfg)
      pid  = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)
      Process.detach(pid)
      {:pid => pid}
      
    rescue Errno::ENOENT, Errno::EACCES => ex
      {:error => ex}
    end

    # Execute cmd with blocking, return status (be careful: inside actor blocks it mailbox, use with defer)
    # options
    #   :working_dir
    #   :environment
    #   :stdin, :stdout, :stderr
    def execute(cmd, cfg = {})
      opts = spawn_options(cfg)
      pid  = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)

      Timeout.timeout(cfg[:timeout] || 1.second) do
        Process.waitpid(pid)
      end

      {:pid => pid}

    rescue Timeout::Error => ex      
      send_signal(pid, 9) if pid # kill it?
      {:error => ex}

    rescue Errno::ENOENT, Errno::EACCES => ex
      {:error => ex}
    end

    # get table
    # {pid => {:rss =>, :cpu =>, :ppid => , :cmd => , :start_time}}
    # slow
    def ps_aux
      cmd = if RUBY_PLATFORM.include?('darwin')
        'ps axo pid,ppid,pcpu,rss,start,command'
      else<commit_msg># fix catch kill Errno::EPERM<commit_after>require 'shellwords'
require 'pathname'

module Eye::System
  class << self

    # Check that pid realy exits
    # very fast
    def pid_alive?(pid)
      pid ? ::Process.kill(0, pid) && true : false
    rescue Errno::ESRCH, Errno::EPERM
      false
    end

    # Send signal to process (uses for kill)
    # code: TERM(15), KILL(9), QUIT(3), ...
    def send_signal(pid, code = :TERM)
      code = code.to_s.upcase if code.is_a?(String) || code.is_a?(Symbol)

      ::Process.kill(code, pid) if pid
      {:status => :ok}

    rescue Errno::ESRCH    
      {:status => :error, :message => 'process not found'}

    rescue Errno::EPERM
      {:status => :error, :message => 'wrong permissions to kill'}

    rescue => e
      {:status => :error, :message => "failed signal #{code}: #{e.message}"}
    end

    # Daemonize cmd, and detach
    # options:
    #   :pid_file
    #   :working_dir
    #   :environment
    #   :stdin, :stdout, :stderr
    def daemonize(cmd, cfg = {})
      opts = spawn_options(cfg)
      pid  = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)
      Process.detach(pid)
      {:pid => pid}
      
    rescue Errno::ENOENT, Errno::EACCES => ex
      {:error => ex}
    end

    # Execute cmd with blocking, return status (be careful: inside actor blocks it mailbox, use with defer)
    # options
    #   :working_dir
    #   :environment
    #   :stdin, :stdout, :stderr
    def execute(cmd, cfg = {})
      opts = spawn_options(cfg)
      pid  = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)

      Timeout.timeout(cfg[:timeout] || 1.second) do
        Process.waitpid(pid)
      end

      {:pid => pid}

    rescue Timeout::Error => ex      
      send_signal(pid, 9)
      {:error => ex}

    rescue Errno::ENOENT, Errno::EACCES => ex
      {:error => ex}
    end

    # get table
    # {pid => {:rss =>, :cpu =>, :ppid => , :cmd => , :start_time}}
    # slow
    def ps_aux
      cmd = if RUBY_PLATFORM.include?('darwin')
        'ps axo pid,ppid,pcpu,rss,start,command'
      else
{'fraction_non_alphanumeric': 0.1467351430667645, 'fraction_numerical': 0.0034238200048911714, 'mean_word_length': 2.4867860187553283, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 43, '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': '7011972', 'n_tokens_mistral': 1438, 'n_tokens_neox': 1412, 'n_words': 355}