Class: PrettyMultitask::RunCallable

Inherits:
Object
  • Object
show all
Defined in:
lib/pretty_multitask/run_callable.rb

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ RunCallable

Returns a new instance of RunCallable.



4
5
6
# File 'lib/pretty_multitask/run_callable.rb', line 4

def initialize(opts = {})
  @opts = opts
end

Instance Method Details

#consume_and_print(reader, writer, name, error = false) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/pretty_multitask/run_callable.rb', line 66

def consume_and_print(reader, writer, name, error = false)
  Thread.new do
    begin
      fmt = "%#{@padding}s |"
      colored = Color.red format(fmt, name) if error
      colored = Color.green format(fmt, name) unless error
      reader.each_line do |line|
        writer.write "#{colored} #{line}"
        File.open(@opts[:out_file],'a+') do |f|
          f.puts "#{colored} #{line}" if error
          f.puts "#{colored} #{line}" unless error
        end if @opts[:out_file]
      end
    rescue Errno::EIO
      nil
    rescue IOError
      nil
    end
  end
end

#run(opts = @opts) ⇒ Object



8
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
# File 'lib/pretty_multitask/run_callable.rb', line 8

def run(opts = @opts)
  cmd = opts[:cmd]
  name = opts[:name]
  out = opts[:out] || STDOUT
  err = opts[:err] || STDERR
  @padding = opts[:padding]
  master, slave = PTY.open
  err_read, err_write = IO.pipe
  
  r, w = UNIXSocket.pair(:STREAM, 0)
  
  pid = fork do
    STDERR.reopen err_write
    STDOUT.reopen master
    begin
      result = cmd.call
      obj = { result: result, error: nil }
    rescue StandardError => e
      new_error = e.class.new(e.message)
      new_error.set_backtrace e.backtrace
      Logger.new(STDERR).error new_error
      obj = { result: nil, error: new_error }
      File.open('/tmp/error','w+'){|f| f.puts obj.to_yaml}
      w.puts Marshal.dump(obj), 0
    end
    w.puts Marshal.dump(obj), 0
    w.close
  end

  t_out = consume_and_print slave, out, name, false
  t_err = consume_and_print err_read, out, name, true
  
  Process.wait pid
  
  i[slave err_read].each do |e|
    loop { break unless binding.local_variable_get(e).ready? }
  end
  
  begin
    Timeout.timeout(0.1) do
      i[t_out t_err].each { |e| binding.local_variable_get(e).join }
    end
  rescue Timeout::Error
    nil
  end
  
  i[master slave err_read err_write].each { |e| binding.local_variable_get(e).close }
  
  chars = []
  chars << r.getc while r.ready?
  r.close
  
  result = Marshal.load(chars.join)
  raise result[:error] if result[:error]
  
  result[:result]
end