module Minicron::CLI

Handles the main CLI interaction of minicron TODO: this class is probably too complicated and should be refactored a bit

Public Class Methods

coloured_output?() click to toggle source

Whether or not coloured output of the rainbox gem is enabled, this is enabled by default

@return [Boolean] whether rainbow is enabled or not

# File lib/minicron/cli.rb, line 168
def self.coloured_output?
  Rainbow.enabled
end
disable_coloured_output!() click to toggle source

Disable coloured terminal output from the rainbow gem, this is enabled by default

@return [Boolean] whether rainbow is enabled or not

# File lib/minicron/cli.rb, line 184
def self.disable_coloured_output!
  Rainbow.enabled = false
end
enable_coloured_output!() click to toggle source

Enable coloured terminal output from the rainbow gem, this is enabled by default

@return [Boolean] whether rainbow is enabled or not

# File lib/minicron/cli.rb, line 176
def self.enable_coloured_output!
  Rainbow.enabled = true
end
parse_config(opts) click to toggle source

Function to the parse the config of the options passed to commands

@param opts [Hash] The Commander provided options hash

# File lib/minicron/cli.rb, line 27
def self.parse_config(opts)
  # Parse the --config file options if it was passed
  Minicron.parse_file_config(opts.config)

  # Parse the cli options
  Minicron.parse_config_hash(
    'verbose' => opts.verbose,
    'trace' => opts.trace,
    'cli' => {
      'mode' => opts.mode,
      'dry_run' => opts.dry_run
    },
    'server' => {
      'host' => opts.host,
      'port' => opts.port,
      'path' => opts.path,
      'debug' => opts.debug,
      'pid_file' => opts.pid_file,
      'cron_file' => opts.cron_file
    }
  )
end
run(argv) { |output| ... } click to toggle source

Sets up an instance of commander and runs it based on the argv param

@param argv [Array] an array of arguments passed to the cli @yieldparam output [String] output from the cli @raise [ArgumentError] if no arguments are passed to the run cli command i.e when the argv param is ['run']. A second option (the command to execute) should be present in the array

# File lib/minicron/cli.rb, line 66
def self.run(argv)
  # replace ARGV with the contents of argv to aid testability
  ARGV.replace(argv)

  # Get an instance of commander
  @cli = Commander::Runner.new

  # Set some default otions on it
  setup

  # Add the run command to the cli
  Minicron::CLI::Commands.add_run_cli_command(@cli) { |output| yield output }

  # Add the server command to the cli
  Minicron::CLI::Commands.add_server_cli_command(@cli)

  # Add the db command to the cli
  Minicron::CLI::Commands.add_db_cli_command(@cli)

  # And off we go!
  @cli.run!
end
run_command(command, options = {}) { |structured :status, "START #{strftime("%Y-%m-%d %H:%M:%S")}"| ... } click to toggle source

Executes a command in a pseudo terminal and yields the output

@param command [String] the command to execute e.g 'ls' @option options [String] mode ('line') the method to yield the command output. Either 'line' by line or 'char' by char. @option options [Boolean] verbose whether or not to output extra information for debugging purposes. @yieldparam output [String] output from the command execution

# File lib/minicron/cli.rb, line 97
def self.run_command(command, options = {})
  # Default the options
  options[:mode] ||= 'line'
  options[:verbose] ||= false

  # Record the start time of the command
  start = Time.now.utc
  subtract_total = 0

  # yield the start time
  subtract = Time.now.utc
  yield structured :status, "START #{start.strftime("%Y-%m-%d %H:%M:%S")}"
  subtract_total += Time.now.utc - subtract

  # Spawn a process to run the command
  begin
    PTY.spawn(command) do |stdout, stdin, pid|

      # Output some debug info
      if options[:verbose]
        subtract = Time.now.utc
        yield structured :verbose, '[minicron]'.colour(:magenta)
        yield structured :verbose, ' started running '.colour(:blue) + "`#{command}`".colour(:yellow) + " at #{start}\n\n".colour(:blue)
        subtract_total += Time.now.utc - subtract
      end

      begin
        # Loop until data is no longer being sent to stdout
        until stdout.eof?
          # One character at a time or one line at a time?
          output = options[:mode] == 'char' ? stdout.read(1) : stdout.readline

          subtract = Time.now.utc
          yield structured :command, output
          subtract_total += Time.now.utc - subtract
        end
      # See https://github.com/ruby/ruby/blob/57fb2199059cb55b632d093c2e64c8a3c60acfbb/ext/pty/pty.c#L519
      rescue Errno::EIO
      ensure
        # Force waiting for the process to finish so we can get the exit status
        Process.wait pid
      end
    end
  rescue Errno::ENOENT
    raise Exception, "Running the command `#{command}` failed, are you sure it exists?"
  ensure
    # Record the time the command finished
    finish = Time.now.utc - subtract_total
    exit_status = $CHILD_STATUS.exitstatus ? $CHILD_STATUS.exitstatus : nil

    # yield the finish time and exit status
    yield structured :status, "FINISH #{finish.strftime("%Y-%m-%d %H:%M:%S")}"
    yield structured :status, "EXIT #{exit_status}"

    # Output some debug info
    if options[:verbose]
      yield structured :verbose, "\n" + '[minicron]'.colour(:magenta)
      yield structured :verbose, ' finished running '.colour(:blue) + "`#{command}`".colour(:yellow) + " at #{start}\n".colour(:blue)
      yield structured :verbose, '[minicron]'.colour(:magenta)
      yield structured :verbose, ' running '.colour(:blue) + "`#{command}`".colour(:yellow) + " took #{finish - start}s\n".colour(:blue)
      yield structured :verbose, '[minicron]'.colour(:magenta)
      yield structured :verbose, " `#{command}`".colour(:yellow) + ' finished with an exit status of '.colour(:blue)
      yield structured :verbose, exit_status == 0 ? "#{exit_status}\n".colour(:green) : "#{exit_status}\n".colour(:red)
    end
  end
end
structured(type, output) click to toggle source

Used as a helper for yielding command output, returns it in a structured hash

@param type [Symbol] The type of command output, currently one of :status, :command and :verbose @param output [String] @return [Hash]

# File lib/minicron/cli.rb, line 55
def self.structured(type, output)
  { :type => type, :output => output }
end

Private Class Methods

setup() click to toggle source

Sets the basic options for a commander cli instance

# File lib/minicron/cli.rb, line 191
def self.setup
  # basic information for the help menu
  @cli.program :name, 'minicron'
  @cli.program :help, 'Author', 'James White <dev.jameswhite+minicron@gmail.com>'
  @cli.program :help, 'License', 'GPL v3'
  @cli.program :version, Minicron::VERSION
  @cli.program :description, 'cli for minicron; a system a to manage and monitor cron jobs'

  # Display the output in a compact format
  @cli.program :help_formatter, Commander::HelpFormatter::TerminalCompact

  # Set the default command to run
  @cli.default_command :help

  # Check if --trace was pased or not
  if @cli.instance_variable_get(:@args).include? '--trace'
    Minicron.config['trace'] = true
  end

  # Add a global option for verbose mode
  @cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['verbose'].to_s}" do
    Minicron.config['verbose'] = true
  end

  # Add a global option for passing the path to a config file
  @cli.global_option '--config FILE', 'Set the config file to use'
end