Class: CommandUtils

Inherits:
Object
  • Object
show all
Defined in:
lib/command_utils.rb,
lib/command_utils/version.rb,
lib/command_utils/line_buffer.rb

Overview

Class to assist calling external commands, while processing its output and return code.

Defined Under Namespace

Classes: LineBuffer, NonZeroExit, Signaled, StatusError, Stopped, Unknown

Constant Summary collapse

VERSION =
'0.5.0'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) {|_self| ... } ⇒ CommandUtils

call-seq:

new([env,] command...)

Takes command in same format supported by Process.spawn.

Yields:

  • (_self)

Yield Parameters:

  • _self (CommandUtils)

    the object that the method was called on


13
14
15
16
17
18
19
20
21
22
23
# File 'lib/command_utils.rb', line 13

def initialize *args
  first = args.first
  if first.respond_to? :to_hash
    @env = args.shift.to_hash
    @command = args
  else
    @env = nil
    @command = args
  end
  yield self if block_given?
end

Class Attribute Details

.debugObject

Output command and its output to STDERR.


135
136
137
# File 'lib/command_utils.rb', line 135

def debug
  @debug
end

Instance Attribute Details

#pidObject (readonly)

PID of currently running process.


7
8
9
# File 'lib/command_utils.rb', line 7

def pid
  @pid
end

Class Method Details

.each_line(*args, &block) ⇒ Object

call-seq:

each_line([env,] command...) { |stream, data| ... }

Wrapper for CommandUtils#each_line


104
105
106
# File 'lib/command_utils.rb', line 104

def self.each_line *args, &block # :yields: stream, data
  self.new(*args).each_line(&block)
end

.each_output(*args, &block) ⇒ Object

call-seq:

each_output([env,] command...) { |stream, data| ... }

Wrapper for CommandUtils#each_output


69
70
71
# File 'lib/command_utils.rb', line 69

def self.each_output *args, &block # :yields: stream, data
  self.new(*args).each_output(&block)
end

.logger_exec(*args, options) ⇒ Object

call-seq:

logger_exec([env,] command..., options)

Wrapper for [email protected]_exec


129
130
131
# File 'lib/command_utils.rb', line 129

def self.logger_exec *args, options
  self.new(*args).logger_exec(options)
end

Instance Method Details

#each_line(&block) ⇒ Object

Execute command, yielding to given block, each time there is a new line available (does line buffering):

stream

either :stdout or :stderr.

data

data read from respective stream.

Raises CommandUtils::StatusError class exception if command execution is not successfull.


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/command_utils.rb', line 77

def each_line &block # :yields: stream, data
  stdout_lb = LineBuffer.new(
    proc do |data|
      block.call :stdout, data
    end
    )
  stderr_lb = LineBuffer.new(
    proc do |data|
      block.call :stderr, data
    end
    )
  each_output do |stream, data|
    case stream
    when :stdout
      stdout_lb.write data
    when :stderr
      stderr_lb.write data
    end
  end
  stdout_lb.flush
  stderr_lb.flush
end

#each_output(&block) ⇒ Object

Execute command, yielding to given block, each time there is output available (not line buffered):

stream

either :stdout or :stderr.

data

data read from respective stream.

Raises CommandUtils::StatusError class exception if command execution is not successfull.


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
# File 'lib/command_utils.rb', line 29

def each_output &block # :yields: stream, data
  spawn
  begin
    loop do
      io_list = [@stdout_read, @stderr_read].keep_if{|io| not io.closed?}
      break if io_list.empty?
      IO.select(io_list).first.each do |io|
        if io.eof?
          io.close
          next
        end
        label = case io
        when @stdout_read
          :stdout
        when @stderr_read
          :stderr
        end
        buffer = ''
        loop do
          begin
            buffer += io.read_nonblock(io.stat.blksize)
          rescue EOFError
            io.close
            break
          rescue IO::EAGAINWaitReadable
            break
          end
        end
        STDERR.puts "#{label}: '#{buffer}'" if self.class.debug
        yield label, buffer
      end
    end
  end
  process_status
end

#logger_exec(options) ⇒ Object

Execute command, logging its output, line buffered, to given Logger object. Must receive a hash, containing at least:

:logger

Logger instance.

:stdout_level

Logger level to log stdout.

:stderr_level

Logger level to log stderr.

and optionally:

:stdout_prefix

Prefix to use for all stdout messages.

:stderr_prefix

Prefix to use for all stderr messages.

Raises CommandUtils::StatusError class exception if command execution is not successfull.


117
118
119
120
121
122
123
# File 'lib/command_utils.rb', line 117

def logger_exec options
  each_line do |stream, data|
    level = options["#{stream}_level".to_sym]
    prefix = options["#{stream}_prefix".to_sym]
    options[:logger].send(level, "#{prefix}#{data}")
  end
end