Method: Libis::Tools::Command.run
- Defined in:
- lib/libis/tools/command.rb
.run(*cmd) ⇒ Hash
Run an external program and return status, stdout and stderr.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 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 |
# File 'lib/libis/tools/command.rb', line 51 def self.run(*cmd) spawn_opts = Hash === cmd.last ? cmd.pop.dup : {} opts = { :stdin_data => spawn_opts.delete(:stdin_data) || '', :binmode => spawn_opts.delete(:binmode) || false, :timeout => spawn_opts.delete(:timeout), :signal => spawn_opts.delete(:signal) || :TERM, :kill_after => spawn_opts.delete(:kill_after), } in_r, in_w = IO.pipe out_r, out_w = IO.pipe err_r, err_w = IO.pipe in_w.sync = true if opts[:binmode] in_w.binmode out_r.binmode err_r.binmode end spawn_opts[:in] = in_r spawn_opts[:out] = out_w spawn_opts[:err] = err_w result = { :pid => nil, :status => nil, :out => [], :err => [], :timeout => false, } out_reader = nil err_reader = nil wait_thr = nil begin Timeout.timeout(opts[:timeout]) do result[:pid] = spawn(*cmd, spawn_opts) wait_thr = Process.detach(result[:pid]) in_r.close out_w.close err_w.close out_reader = Thread.new {out_r.read} err_reader = Thread.new {err_r.read} in_w.write opts[:stdin_data] in_w.close result[:status] = wait_thr.value end rescue Timeout::Error result[:timeout] = true pid = spawn_opts[:pgroup] ? -result[:pid] : result[:pid] Process.kill(opts[:signal], pid) if opts[:kill_after] unless wait_thr.join(opts[:kill_after]) Process.kill(:KILL, pid) end end rescue StandardError => e result[:err] = [e.class.name, e.] ensure result[:status] = wait_thr.value.exitstatus if wait_thr result[:out] += out_reader.value.split("\n").map(&:chomp) if out_reader result[:err] += err_reader.value.split("\n").map(&:chomp) if err_reader out_r.close unless out_r.closed? err_r.close unless err_r.closed? end result end |