File: command_runner.rb

package info (click to toggle)
ruby-rr 3.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,424 kB
  • sloc: ruby: 11,405; makefile: 7
file content (105 lines) | stat: -rw-r--r-- 2,266 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
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
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
require 'open3'

class CommandRunner
  # http://stackoverflow.com/questions/6407141/how-can-i-have-ruby-logger-log-output-to-stdout-as-well-as-file
  class MultiIO
    def initialize(*targets)
       @targets = targets
    end

    def write(*args)
      @targets.each {|t| t.write(*args) }
    end
    alias_method :<<, :write

    def close
      @targets.each(&:close)
    end
  end

  def self.call(command, options={})
    new(command, options).call
  end

  attr_reader :command, :output, :exit_status

  def initialize(command, options)
    @command = command
    #@command << " 2>&1" unless @command =~ / 2>&1$/
    @output = ""
  end

  def call
    @stdout_buffer = StringIO.new

    puts "Running: #{@command}"

    if defined?(JRUBY_VERSION)
      call_using_popen4
    else
      call_using_spawn
    end

    if RR.debug?
      puts "~ Output from `#{@command}` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
      puts @output
      puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    end

    self
  end

  def success?
    @exit_status == 0
  end

  private

  def call_using_session
    reader, writer = IO.pipe
    require 'session'
    session = Session::Bash.new
    session.execute(@command, :stdout => writer, :stderr => writer)
    writer.close
    @exit_status = session.exit_status
    @output = reader.read
  end

  def call_using_popen4
    reader, writer = IO.pipe

    # Using popen4 here without a block will always result in an Errno::ECHILD
    # error under JRuby: <http://jira.codehaus.org/browse/JRUBY-5684>
    block = lambda { |pid, _, stdout, _| writer.write(stdout.read) }

    if defined?(JRUBY_VERSION)
      IO.popen4("#{@command} 2>&1", &block)
    else
      require 'open4'
      Open4.popen4("#{@command} 2>&1", &block)
    end

    writer.close
    @exit_status = $?.exitstatus
    @output = reader.read
  end

  def call_using_spawn
    reader, writer = IO.pipe
    args = [@command, {[:out, :err] => writer}]
    require 'posix-spawn'
    pid = POSIX::Spawn.spawn(*args)
    Process.waitpid(pid)
    writer.close
    @exit_status = $?.exitstatus
    @output = reader.read
  end

  def build_stdout
    ios = [@stdout_buffer]
    #if RR.debug?
    #  ios << $stdout
    #end
    MultiIO.new(*ios)
  end
end