Class: CommandExec::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/command_exec/command.rb

Overview

Run commands

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, opts = {}) ⇒ Command

Create a new command to execute

Parameters:

  • name (Symbol)

    name of command

  • opts (optional, Hash) (defaults to: {})

    options for the command

Options Hash (opts):

  • :options (String) — default: ''

    options for the command

  • :working_directory (String) — default: current working directory

    working_directory for the command

  • :log_file (String) — default: ''

    log file of the command

  • :search_paths (String, Array) — default: $PATH

    where to search for the command (please mind the 's' at the end.

  • :error_detection_on (String, Array) — default: :return_code

    what information should be considered for error detection, available options are :return_code, :stderr, :stdout, :log_file. You can use one or more of them.

  • :error_indicators (Hash)

    what keywords etc. should be considered as errors.

    You can define allowed or forbidden keywords or exit codes. To search for errors in a log file you need to provide one.

    For each option you can provide a single word or an Array of words.

    :allowed_return_code => [0],
    :forbidden_return_code => [],
    :allowed_words_in_stderr => [],
    :forbidden_words_in_stderr => [],
    :allowed_words_in_stdout => [],
    :forbidden_words_in_stdout => [],
    :allowed_words_in_log_file => [],
    :forbidden_words_in_log_file => [],
    
  • :on_error_do (Symbol)

    Oh, an error happend, what to do next? Raise an error (:raise_error), Throw an error (:throw_error) or do nothing at all (:nothing, default).

  • :run_via (Symbol)

    Which runner should be used to execute the command: :open3 (default) or :system.

  • :lib_logger (Logger)

    The logger which is used to output information generated by the library. The logger which is provided needs to be compatible with api of the Ruby Logger-class.

  • :lib_log_level (Symbol)

    What information should handled by the logger: :debug, :info, :warn, :error, :fatal, :unknown. Additionally the :silent-option is understood: do not output anything (@see README for further information).



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/command_exec/command.rb', line 90

def initialize(name,opts={})

  @name = name
  @opts = {
    :options => '',
    :parameter => '',
    :working_directory => Dir.pwd,
    :log_file => '',
    :search_paths => ENV['PATH'].split(':'),
    :error_detection_on => [:return_code],
    :error_indicators => {
      :allowed_return_code => [0],
      :forbidden_return_code => [],
      #
      :allowed_words_in_stderr => [],
      :forbidden_words_in_stderr => [],
      #
      :allowed_words_in_stdout => [],
      :forbidden_words_in_stdout => [],
      #
      :allowed_words_in_log_file => [],
      :forbidden_words_in_log_file => [],
    },
    :on_error_do => :nothing,
    :run_via => :open3,
    :lib_logger => Logger.new($stderr),
    :lib_log_level => :info,
  }.deep_merge opts

  @logger = @opts[:lib_logger] 
  configure_logging 

  @logger.debug @opts

  @options = @opts[:options]
  @path = resolve_path @name, @opts[:search_paths]
  @parameter = @opts[:parameter]
  @log_file = @opts[:log_file]

  *@error_detection_on = @opts[:error_detection_on]
  @error_indicators = @opts[:error_indicators]
  @on_error_do = @opts[:on_error_do]

  @run_via = @opts[:run_via]

  @working_directory = @opts[:working_directory] 
  @result = nil
end

Instance Attribute Details

#log_fileObject

Set/Get log file for command



16
17
18
# File 'lib/command_exec/command.rb', line 16

def log_file
  @log_file
end

#optionsObject

Set/Get options for the command



16
# File 'lib/command_exec/command.rb', line 16

attr_accessor :log_file, :options , :parameter

#parameterObject

Set/Get parameter for the command



16
# File 'lib/command_exec/command.rb', line 16

attr_accessor :log_file, :options , :parameter

#pathObject (readonly)

Return path to the executable of the command



26
# File 'lib/command_exec/command.rb', line 26

attr_reader :result, :path, :working_directory

#resultObject (readonly)

Return the result of command execution



26
27
28
# File 'lib/command_exec/command.rb', line 26

def result
  @result
end

#working_directoryObject (readonly)

Returns the value of attribute working_directory.



26
# File 'lib/command_exec/command.rb', line 26

attr_reader :result, :path, :working_directory

Class Method Details

.execute(name, opts = {}) ⇒ Object

Run a command

See Also:



394
395
396
397
398
399
# File 'lib/command_exec/command.rb', line 394

def self.execute(name,opts={})
  command = new(name,opts)
  command.run

  command
end

Instance Method Details

#error_occured?(forbidden_word, exception, data) ⇒ Boolean

Find error in data

Parameters:

  • forbidden_word (Array, String)

    what are the forbidden words which indidcate an error

  • exception (Array, String)

    Is there any exception from that forbidden words, maybe a string which contains the forbidden word, but is no error?

  • data (Array, String)

    Where to look for errors.

Returns:

  • (Boolean)

    Returns true if it finds an error



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/command_exec/command.rb', line 365

def error_occured?(forbidden_word, exception, data )
  error_found = false
  *forbidden_word = forbidden_word
  *exception = exception
  *data = data

  return false if forbidden_word.blank?
  return false if data.blank?

  forbidden_word.each do |word|
    data.each do |line|
      line.strip!

      #line includes word -> error
      #exception does not include line/substring of line -> error, if
      #  includes line/substring of line -> no error
      if line.include? word and exception.find{ |e| line[e] }.blank?
        error_found = true
        break
      end
    end
  end

  error_found
end

#executable?True, False

Is the command executable

Returns:

  • (True, False)

    result of check



232
233
234
# File 'lib/command_exec/command.rb', line 232

def executable?
  File.executable? @path
end

#exists?True, False

Does the command exist?

Returns:

  • (True, False)

    result of check



225
226
227
# File 'lib/command_exec/command.rb', line 225

def exists?
  File.exists? @path
end

#file?True, False

Is the provided string a file

Returns:

  • (True, False)

    result of check



239
240
241
# File 'lib/command_exec/command.rb', line 239

def file?
  File.file? @path
end

#runObject

Run the program

Raises:

Throw:

  • (:command_execution_failed)

    if an error occured and command_exec should throw an error (which you can catch) in the case of an error



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/command_exec/command.rb', line 265

def run
  process = CommandExec::Process.new(:lib_logger => @logger)
  process.log_file = @log_file if @log_file
  process.status = :success

  check_path

  process.start_time = Time.now

  case @run_via
  when :open3
    Open3::popen3(to_s, :chdir => @working_directory) do |stdin, stdout, stderr, wait_thr|
      process.stdout = stdout.readlines.map(&:chomp)
      process.stderr = stderr.readlines.map(&:chomp)
      process.pid = wait_thr.pid
      process.return_code = wait_thr.value.exitstatus
    end
  when :system
    Dir.chdir(@working_directory) do
      system(to_s)
      process.stdout = []
      process.stderr = []
      process.pid = $?.pid
      process.return_code = $?.exitstatus
    end
  else
    Open3::popen3(to_s, :chdir => @working_directory) do |stdin, stdout, stderr, wait_thr|
      process.stdout = stdout.readlines.map(&:chomp)
      process.stderr = stderr.readlines.map(&:chomp)
      process.pid = wait_thr.pid
      process.return_code = wait_thr.value.exitstatus
    end
  end

  process.end_time = Time.now

    if @error_detection_on.include?(:return_code)
      if not @error_indicators[:allowed_return_code].include? process.return_code or 
             @error_indicators[:forbidden_return_code].include? process.return_code

        @logger.debug "Error detection on return code found an error"
        process.status = :failed 
        process.reason_for_failure = :return_code
      end
    end

    if @error_detection_on.include?(:stderr) and not process.status == :failed
      if error_occured?( @error_indicators[:forbidden_words_in_stderr], @error_indicators[:allowed_words_in_stderr], process.stderr)
        @logger.debug "Error detection on stderr found an error"
        process.status = :failed 
        process.reason_for_failure = :stderr
      end
    end

    if @error_detection_on.include?(:stdout) and not process.status == :failed
      if error_occured?( @error_indicators[:forbidden_words_in_stdout], @error_indicators[:allowed_words_in_stdout], process.stdout)
        @logger.debug "Error detection on stdout found an error"
        process.status = :failed 
        process.reason_for_failure = :stdout
      end
    end

    if @error_detection_on.include?(:log_file) and not process.status == :failed
      if error_occured?( @error_indicators[:forbidden_words_in_log_file], @error_indicators[:allowed_words_in_log_file], process.log_file)
        @logger.debug "Error detection on log file found an error"
        process.status = :failed 
        process.reason_for_failure = :log_file
      end
    end

    @logger.debug "Result of command run #{process.status}"

  @result = process
  if process.status == :failed
    case @on_error_do
    when :nothing
      #nothing
    when :raise_error
      raise CommandExec::Exceptions::CommandExecutionFailed, "An error occured. Please check for reason via command.reason_for_failure and/or command.stdout, comand.stderr, command.log_file, command.return_code"
    when :throw_error
      throw :command_execution_failed 
    else
      #nothing
    end
  end
end

#to_sString

Output the textual representation of a command

Returns:

  • (String)

    command in text form



246
247
248
249
250
251
252
253
254
255
# File 'lib/command_exec/command.rb', line 246

def to_s
  cmd = ''
  cmd += @path
  cmd += @options.blank? ? "" : " #{@options}"
  cmd += @parameter.blank? ? "" : " #{@parameter}"

  @logger.debug cmd

  cmd
end

#valid?Boolean

Is executable valid

Returns:

  • (Boolean)


218
219
220
# File 'lib/command_exec/command.rb', line 218

def valid?
  exists? and executable? and file?
end