class GenericCommand
Generic command executor that holds the code shared by all the command executors.
Properties:
-
code
: integer holding the exit code. Read-only -
stdout
: string of the standard output. Read-only -
stderr
: string of the standard error. Read-only -
command
: command to execute. Read-only
The protocol for scripts to log is as follows:
-
Log messages will be sent to STDOUT
-
The script will return 0 if it succeded or any other value if there was a failure
-
In case of failure the cause of the error will be written to STDERR wrapped by start and end marks as follows:
ERROR MESSAGE --8<------ error message for the failure ERROR MESSAGE ------>8--
Constants
- ERROR_CLOSE
- ERROR_OPEN
Attributes
Public Class Methods
Creates the new command: command
: string with the command to
be executed logger
: proc that takes a message parameter and
logs it
# File lib/CommandManager.rb, line 61 def initialize(command, logger=nil, stdin=nil, timeout=nil) @command = command @logger = logger @stdin = stdin @timeout = timeout end
Creates a command and runs it
# File lib/CommandManager.rb, line 52 def self.run(command, logger=nil, stdin=nil, timeout=nil) cmd = self.new(command, logger, stdin, timeout) cmd.run cmd end
Public Instance Methods
Parses error message from stderr
output
# File lib/CommandManager.rb, line 133 def get_error_message tmp=@stderr.scan(/^#{ERROR_OPEN}\n(.*?)#{ERROR_CLOSE}$/m) return "-" if !tmp[0] tmp[0].join(' ').strip end
# File lib/CommandManager.rb, line 73 def kill(pid) # executed processes now have its own process group to be able # to kill all children pgid = Process.getpgid(pid) # Kill all processes belonging to process group Process.kill("HUP", pgid * -1) end
Sends a log message to the logger proc
# File lib/CommandManager.rb, line 69 def log(message, all=true) @logger.call(message, all) if @logger end
Runs the command
# File lib/CommandManager.rb, line 83 def run std = nil process = Proc.new do std = execute # Close standard IO descriptors if @stdin std[0] << @stdin std[0].flush end std[0].close if !std[0].closed? @stdout=std[1].read std[1].close if !std[1].closed? @stderr=std[2].read std[2].close if !std[2].closed? @code=get_exit_code(@stderr) if @code!=0 log("Command execution fail: #{command}") log(@stderr) end end begin if @timeout Timeout.timeout(@timeout, nil, &process) else process.call end rescue Timeout::Error error_message = "Timeout executing #{command}" log(error_message) @stderr = ERROR_OPEN + "\n" + error_message + "\n" + ERROR_CLOSE 3.times {|n| std[n].close if !std[n].closed? } pid = std[-1].pid self.kill(pid) @code = 255 end return @code end
Private Instance Methods
Low level command execution. This method has to be redefined for each kind
of command execution. Returns an array with stdin
,
stdout
and stderr
handlers of the command
execution.
# File lib/CommandManager.rb, line 151 def execute puts "About to execute \"#{@command}\"" [StringIO.new, StringIO.new, StringIO.new] end
Gets exit code from STDERR
# File lib/CommandManager.rb, line 142 def get_exit_code(str) tmp=str.scan(/^ExitCode: (\d*)$/) return nil if !tmp[0] tmp[0][0].to_i end