module ExecSimple
Constants
- VERSION
Public Class Methods
run(cmd, log: nil, timeout: nil)
click to toggle source
Run a command. Optionally log results from stadard output and error with a logger object. Optionally set a timeout as a maximum time to wait until the process is killed. @param [String] cmd The command to run @param [Logging::Logger] log An optional logger object to use for output @param [Int] timeout An optional timeout to wait until the process is killed. @returny [Array] Either return an array of [output, error, exit_code] or just the exit_code if a log-object was provided
# File lib/exec-simple.rb, line 16 def self.run cmd, log: nil, timeout: nil # run the command concurrently to manage timeouts out = "" err = "" stdin, stdout, stderr, wait_thr = Open3.popen3(cmd) # we don't need stdin stdin.close # run readers on stdin and stderr op = Concurrent::Promise.execute do while( not stdout.eof? ) #stdout.wait_readable #cur = stdout.read cur = stdout.readpartial(4096) if log.nil? then out << cur else log.info cur.chomp end end end ep = Concurrent::Promise.execute do while( not stderr.eof? ) #stdout.wait_readable #cur = stdout.read cur = stderr.readpartial(4096) if log.nil? then err << cur else log.error cur.chomp end end end # pid = wait_thr[:pid] future = Concurrent::Future.execute do wait_thr.value end # get the future's value exit_code = future.value(timeout) exitstatus = if exit_code.nil? then nil else exit_code.exitstatus end # if we didn't yet get a value, kill the process if wait_thr.alive? Process.kill('TERM', pid) sleep 1 # check if it terminated successfully if wait_thr.alive? # if not give it some more time sleep 3 # and then kill it Process.kill('KILL', pid) if wait_thr.alive? end end # finishing up stdout.close stderr.close # get the results return exitstatus if not log.nil? [out, err, exitstatus] end