class BinScript

require ‘active_support/core_ext/class/attribute.rb’

Constants

PARAMETER_TYPES

Allowed parameter types. Equivalence aliases with GetoptLong constants.

VERSION

Attributes

exit_status[RW]

Place for store exit status.

logger[RW]

Place for logger object

Public Class Methods

bin_name() click to toggle source
# File lib/bin_script/bin_script.rb, line 88
def bin_name
  script_name.gsub('_script', '')
end
calculate_script_class_filename(parts) click to toggle source

Prepare class name from filename parts

# File lib/bin_script/bin_script.rb, line 120
def calculate_script_class_filename(parts)
  files = []

  # Collect from disk, needed class files
  parts.each do |p|
    off = "app/{bin,bins,models,script,scripts}/**/#{p}_script.rb"
    files += Dir[File.join(RailsStub.root, off)]

    off = "script/**/#{p}_script.rb"
    files += Dir[File.join(RailsStub.root, off)]
  end

  files.reverse
end
calculate_script_class_name(parts) click to toggle source

Prepare class name from filename parts

# File lib/bin_script/bin_script.rb, line 109
def calculate_script_class_name(parts)
  # Calculate class name and paths from source script filename parts
  if(parts.length > 1)
    class_name = parts.map{|p| p.camelize}.join('::') + parts.first.camelize
  else
    class_name = parts.first.camelize
  end
  class_name += "Script"
end
get_argv_values() click to toggle source

Prepare ARGV parameters as hash

# File lib/bin_script/bin_script.rb, line 174
def get_argv_values
  values = {}
  o = GetoptLong.new(*get_getoptlong_params)
  o.quiet = true   # Don't write arg error to STDERR
  o.each { |opt, arg| values[opt[1..-1].to_sym] = arg }
  values
end
get_parameter(key) click to toggle source

Get parameter by key

# File lib/bin_script/bin_script.rb, line 77
def get_parameter(key)
  param = @parameters.find{|p| p[:key] == key || (p[:alias].present? && p[:alias].include?(key))}
  raise "Can't find parameter with key #{key.inspect} for class #{self.inspect}!" if param.nil?
  param
end
new() click to toggle source

Initialize script

# File lib/bin_script/bin_script.rb, line 229
def initialize
  begin
    @source_argv = ARGV.dup
    @overrided_parameters = {}
    @params_values = (RailsStub.env == 'test' ? {} : self.class.get_argv_values)

    # Create logger if logging enabled
    if self.class.enable_logging
      @logger = XLogger.new(:file => log_filename, :dont_touch_rails_logger => (RailsStub.env == 'test'))
      @logger.level = self.class.log_level
    end

  rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument, GetoptLong::NeedlessArgument => e
    usage_exit e.message
  end
end
parse_script_file_name(filename) click to toggle source

Parse script filename. Extract important path parts

# File lib/bin_script/bin_script.rb, line 93
def parse_script_file_name(filename)
  result = {}
  # Prepare important parts of source script filename
  parts = filename.split(File::SEPARATOR)
  parts = parts[parts.index('bin')+1..-1]
  parts.map!{|p| File.basename(p).split('.').first}

  result[:parts] = parts

  result[:class] = calculate_script_class_name(parts)
  result[:files]  = calculate_script_class_filename(parts)

  result
end
remove_parameter(key) click to toggle source

Remove parameter

# File lib/bin_script/bin_script.rb, line 167
def remove_parameter(key)
  new = []
  @parameters.each { |p| new << p if p[:key] != key }
  @parameters = new
end
run_script(filename = $0) click to toggle source

Run script detected by the filename of source script file

# File lib/bin_script/bin_script.rb, line 136
def run_script(filename = $0)
  cfg = parse_script_file_name(Pathname.new(filename).realpath.to_s)
  cfg[:files].each { |f| require f }

  # Create instance and call run! for script class
  klass = cfg[:class].constantize
  script = klass.new
  script.run!

  # Exit with specified exit status
  exit script.exit_status || 0
end
script_name() click to toggle source

Prepare readable script name

# File lib/bin_script/bin_script.rb, line 84
def script_name
  self.to_s.underscore.gsub('/','__')
end
usage(message = nil) click to toggle source

Prepare usage message

# File lib/bin_script/bin_script.rb, line 183
def usage(message = nil)
  usage_msg = ''
  usage_msg += "Error: #{message}\n\n" unless message.nil?
  usage_msg += "Use: ./bin/#{bin_name}.rb [OPTIONS]\n\n"
  usage_msg += "\"#{self.description}\"\n\n" if message.nil? && self.description.present?
  usage_msg += "Availible options:\n\n"

  @parameters.each do |param|
    arg = case param[:type]
      when :required then " v "
      when :optional then "[v]"
      when :noarg    then "   "
    end
    usage_msg += "  #{prefix_key param[:key]}#{arg} #{param[:description]}\n"
  end
  usage_msg += "\n"
  usage_msg
end

Private Class Methods

get_getoptlong_params() click to toggle source

Prepare parameters in Getoptlong lib format

# File lib/bin_script/bin_script.rb, line 205
def get_getoptlong_params
  result = []
  @parameters.each do |param|
    cfg = [prefix_key(param[:key])]
    param[:alias].each{|als| cfg << prefix_key(als) } unless param[:alias].blank?
    cfg << PARAMETER_TYPES[param[:type]]
    result << cfg
  end
  result
end
prefix_key(key) click to toggle source

Prepare argument name with short or long prefix

# File lib/bin_script/bin_script.rb, line 217
def prefix_key(key)
  key = key.to_s
  (key.length > 1 ? "--" : "-") + key
end
prepare_exception_message(e) click to toggle source

Prepare string with exception details

# File lib/bin_script/bin_script.rb, line 401
  def self.prepare_exception_message(e)
<<-EXCEPTION
Exception happend
Type: #{e.class.inspect}
Error occurs: #{e.message}
Backtrace: #{e.backtrace.join("\n")}
EXCEPTION
  end

Public Instance Methods

check_required_params() click to toggle source
# File lib/bin_script/bin_script.rb, line 246
def check_required_params
  self.class.parameters.each do |param|
    if param[:type] == :required && @params_values.has_key?(param[:key])
      if @params_values[param[:key]].nil?
        error "Param #{param[:key]} require value, but not present"
        usage_exit
      end
    end
  end
end
do!() click to toggle source

Dummy for do! method

# File lib/bin_script/bin_script.rb, line 331
def do!; end
lock_filename() click to toggle source

Prepare filename of log file

# File lib/bin_script/bin_script.rb, line 363
def lock_filename
  params(:L).blank? ? File.join(RailsStub.root, 'locks', "#{self.class.script_name}.lock") : params(:L)
end
log_filename() click to toggle source

Prepare filename of log file

# File lib/bin_script/bin_script.rb, line 368
def log_filename
  params(:l).blank? ? File.join(RailsStub.root, 'log', "#{self.class.script_name}#{log_filename_time_part}.log") : params(:l)
end
override_parameters(args) click to toggle source

Override one or more parameters for testing purposes

# File lib/bin_script/bin_script.rb, line 334
def override_parameters(args)
  if args.is_a?(Symbol)
    override_parameter(self.class.get_parameter(args))
  elsif args.is_a?(Hash)
    args.each{|key, value| override_parameter(self.class.get_parameter(key), value)}
  else
    raise "Parameter should be Symbol or Hash"
  end
end
params(key) click to toggle source

Return parameter value by key

# File lib/bin_script/bin_script.rb, line 345
def params(key)
  param = self.class.get_parameter(key)

  # Use dafault key (if call by alias)
  key = param[:key]

  case param[:type]
  when :noarg
    return (@overrided_parameters.has_key?(key) && @overrided_parameters[key]) || !@params_values[key].nil?
  when :optional
    return @overrided_parameters[key] || @params_values[key] || param[:default]
  when :required
    value = @overrided_parameters[key] || @params_values[key] || param[:default]
    return value
  end
end
puts(*arg) click to toggle source
# File lib/bin_script/bin_script.rb, line 223
def puts(*arg)
  return if self.class.disable_puts_for_tests && RailsStub.env == 'test'
  Kernel.puts(*arg)
end
run!() click to toggle source

Create lock file, call script code and unlock file even if error happend.

# File lib/bin_script/bin_script.rb, line 258
def run!

  # Print usage and exit if asked
  usage_exit if params(:h)

  check_required_params

  # Create and check lock file if enabled
  if self.class.enable_locking
    @lock = LockFile.new(lock_filename)
    @lock.quiet = true # Don't write errors to STDERR

    if(@lock.lock)
      msg = "--- Try start. Buy lock file '#{@lock.path}' already open in exclusive mode. Exit! ---"
      # puts msg # puts is not good idea, because cron will mail it, but this is not error
      warn msg
      exit
    end
  end

  begin
    # Log important info and call script job
    info ""

    log_params = {:env => RailsStub.env, :log_level => (self.class.enable_logging ? @logger.level : nil), :lock_file => (self.class.enable_locking ? @lock.path : nil)}

    info "> Script #{self.class.script_name} started! (#{log_params.inspect})"
    info "- Parameters: #{@params_values.inspect}"

    start = Time.now

    # Инкрементируем счетчик запусков этого скрипта
    inc_counter("#{self.class.script_name}_times")

    do!
    duration = Time.now - start
    info "< Script #{self.class.script_name} finished! (#{"%.4f" % duration.to_f} sec)"
    info "Exit status: #{@exit_status}" if @exit_status

    # Инкрементируем время работы э
    inc_counter("#{self.class.script_name}_long", duration)

    # Log benchmarker info if it's not empty
    log_benchmarker_data
  rescue Exception => e
    # Print error info if it's not test env or exit

    exit_mes = (e.class == SystemExit) || (e.class == Interrupt) || (e.class == SignalException) || (RailsStub.env == 'test')
    unless exit_mes
      msg = self.class.prepare_exception_message(e)
      puts "\n" + msg
      fatal msg
      notify_about_error(e)
    else
      error "Get exit message! #{e.message}"
    end

    # Инкрементируем счетчик ошибок этого скрипта
    inc_counter("#{self.class.script_name}_raised")
  ensure
    # Unlock lock file
    @lock.unlock if self.class.enable_locking && @lock
  end
end
usage_exit(message = nil) click to toggle source

Print usage message and exit

# File lib/bin_script/bin_script.rb, line 324
def usage_exit(message = nil)
  error "Exit with error message: #{message}" if message.present?
  Kernel.puts(self.class.usage(message))
  exit
end

Private Instance Methods

inc_counter(id, counter = 1) click to toggle source
# File lib/bin_script/bin_script.rb, line 410
def inc_counter(id, counter = 1)
  # stub
end
log_benchmarker_data() click to toggle source

Print benchmarker statistic to log if its not empty

# File lib/bin_script/bin_script.rb, line 393
def log_benchmarker_data
  benchmark_data = {} #benchmark_get_data
  return if benchmark_data.empty?
  info "Benchmarker data:"
  info benchmark_data.to_yaml
end
log_filename_time_part() click to toggle source

Current time logname part.

# File lib/bin_script/bin_script.rb, line 375
def log_filename_time_part
  Time.now.strftime(self.class.date_log_postfix)
end
notify_about_error(ex) click to toggle source
# File lib/bin_script/bin_script.rb, line 414
def notify_about_error(ex)
  # stub
end
override_parameter(param, value = nil) click to toggle source

Override value for one parameter

# File lib/bin_script/bin_script.rb, line 380
def override_parameter(param, value = nil)
  value = case param[:type]
    when :noarg
      true
    when :optional
      value.to_s
    when :required
      value
  end
  @overrided_parameters[param[:key]] = value
end