Class: JustRun
- Inherits:
-
Object
- Object
- JustRun
- Defined in:
- lib/justrun.rb
Overview
TODO: Run multiple commands at the same time
Defined Under Namespace
Classes: CommandTimeout, Writer
Class Method Summary collapse
Class Method Details
.command(command, timeout: 0, block_size: 4096*4, buffer_output: false, chdir: Dir.pwd, init: ->(writer) {}, env: ENV, &block) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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 |
# File 'lib/justrun.rb', line 9 def self.command(command, timeout: 0, block_size: 4096*4, buffer_output: false, chdir: Dir.pwd, init: ->(writer) {}, env: ENV, &block) ret_code = -1 buffers = { stdout: [], stderr: [], all: [] } beginning_time = Time.now Open3.popen3 env, command, chdir: chdir do |stdin, stdout, stderr, wait_thr| writer = JustRun::Writer.new stdin init.call writer line_handler = -> line, name { if buffer_output buffers[name].push line buffers[:all].push line end if block block.call line, name, writer end } fileno_lines = {} begin files = [stdout, stderr] fileno2name = { stdout.fileno => :stdout, stderr.fileno => :stderr } was_eof = [] until was_eof[stdout.fileno] && was_eof[stderr.fileno] do ready = IO.select files, stdin.closed? ? [] : [stdin], [], 0.1 if timeout > 0 && (Time.now - beginning_time) > timeout `kill -9 #{wait_thr.pid}` # note: Process.kill does not work raise CommandTimeout, "Command: '#{command}' timed out with timeout #{timeout}s" end if ready readable = ready[0] readable.each do |f| fileno = f.fileno fileno_lines[fileno] ||= [] lines = fileno_lines[fileno] name = fileno2name[fileno] begin data = f.read_nonblock block_size lines_new = data.lines if lines.length > 0 and lines[-1] !~ /\n\r?$/ lines[-1] = lines[-1] + lines_new.shift end lines.push(*lines_new) while lines[0] =~ /\n\r?/ line = lines.shift.chomp line_handler.call line, name end rescue EOFError => e was_eof[fileno] = true end end writable = ready[1] writable.each { |stdin| writer.process } end end fileno_lines.each do |fileno, lines| name = fileno2name[fileno] if lines.length > 0 line_handler.call lines.shift.chomp, name end end rescue IOError => e raise e end ret_code = wait_thr.value end if buffer_output { code: ret_code.exitstatus, stderr: buffers[:stderr], stdout: buffers[:stdout], all: buffers[:all] } else ret_code.exitstatus end end |