Class: LCR::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/long-command-runner/runner.rb

Overview

This class aims to manage an external process through a parallele excecution thread. This means it will not stop the main thread of your program.

Your process can output a progress indicator of the matching the format of PERCENT_INDICATOR constant.

It is possible to re-launch the same command, the out/err buffers won’t be emptied before running unless asked.

Constant Summary collapse

PERCENT_INDICATOR =

The constant used to get the percetange of completion of the command.

/(.*\s|^)((\d+)([,.]\d*)?)%.*/.freeze
TIMES_INDICATORS =

The constant to match a ‘time -p` output:

/\A(real|user|sys)\s+(\d+\.\d\d)\z/.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command) {|nl_stdout, nl_stderr| ... } ⇒ Runner

Initializer takes the command as a plain string. You can optionaly pass a block that will be called when the command generate outputs:

Yields:

  • (nl_stdout, nl_stderr)

    call when at least a line comes on stdout or stderr.

Yield Parameters:

  • nl_stdout (String | nil)

    The new line without the return line character. This may be nil if only a new line has been found on stderr.

  • nl_stderr (String | nil)

    The new line without the return line character. This may be nil if only a new line has been found on stdout.

Yield Returns:

  • (void)

    It is ignored.



34
35
36
37
38
39
40
41
# File 'lib/long-command-runner/runner.rb', line 34

def initialize(command, &on_input)
  @command = command
  @container = nil
  @launch_lock = Mutex.new
  @on_input = on_input
  @progress = 0.0
  @times = { real: nil, user: nil, sys: nil }
end

Instance Attribute Details

#progressObject (readonly)

Get the mesured progress in percentage. This is just the result of parsing stdout lines with PERCENT_INDICATOR. So this percentage is comming from the thread not this library.



23
24
25
# File 'lib/long-command-runner/runner.rb', line 23

def progress
  @progress
end

Instance Method Details

#kill(signal) ⇒ Integer | nil

Send a signal to the running process.

Returns:

  • (Integer | nil)

    The number of signaled process (= 1) or nil if the Process is no more running.



115
116
117
118
119
120
121
# File 'lib/long-command-runner/runner.rb', line 115

def kill(signal)
  return nil if @container.nil?

  Process.kill(signal, @container.pid)
rescue Errno::ESRCH
  nil
end

#launchObject

Actually launch the process.



56
57
58
59
60
61
62
63
64
# File 'lib/long-command-runner/runner.rb', line 56

def launch
  stderr, stderr_in = IO.pipe
  @container = Container.new("bash -c 'time -p #{@command} 2>&3'", 3 => stderr_in)
  @line_reader = LineReader.new([@container.stdout, stderr, @container.stderr]) do |*new_lines|
    on_newline(*new_lines)
  end
  @reader_thr = Thread.new { @line_reader.read }
  Thread.pass
end

#launched?Boolean

Tells if the command has been launched at least once.

Returns:

  • (Boolean)


51
52
53
# File 'lib/long-command-runner/runner.rb', line 51

def launched?
  !@container.nil?
end

#output(separator = "\n") ⇒ String

Get the output lines as separated lines

Parameters:

  • separator (String) (defaults to: "\n")

    the separator to put between lines. by default it will be ‘“n”`

Returns:

  • (String)


72
73
74
# File 'lib/long-command-runner/runner.rb', line 72

def output(separator = "\n")
  @line_reader[0].join(separator)
end

#output_error(separator = "\n") ⇒ String

Get the error output lines as separated lines

Parameters:

  • separator (String) (defaults to: "\n")

    the separator to put between lines. by default it will be ‘“n”`

Returns:

  • (String)


82
83
84
# File 'lib/long-command-runner/runner.rb', line 82

def output_error(separator = "\n")
  @line_reader[1].join(separator)
end

#pidInteger | nil

Get the pid of the process launched

Returns:

  • (Integer | nil)


89
90
91
# File 'lib/long-command-runner/runner.rb', line 89

def pid
  @container.pid
end

#running?Boolean

Is the last launched command is still running.

Returns:

  • (Boolean)


44
45
46
47
48
# File 'lib/long-command-runner/runner.rb', line 44

def running?
  return false if @container.nil?

  @container.running?
end

#statusProcess:Status?

Get the status of the process without blocking.

Returns:

  • (Process:Status, nil)

    The exit status of the process if it is finished. if the Process isn’t finished it return nil.



105
106
107
108
109
# File 'lib/long-command-runner/runner.rb', line 105

def status
  return nil if @container.nil?

  @container.status
end

#time_realFloat | nil

Get the time really spend (‘real’ part of time command)

Returns:

  • (Float | nil)

    The elapsed seconds (using POSIX.2 standard see ‘time -p` for more information) if the Process isn’t finished it return nil.



127
128
129
# File 'lib/long-command-runner/runner.rb', line 127

def time_real
  @times[:real]
end

#time_sysFloat | nil

Get the time system space spend (‘sys’ part of time command)

Returns:

  • (Float | nil)

    The elapsed seconds (using POSIX.2 standard see ‘time -p` for more information) if the Process isn’t finished it return nil.



143
144
145
# File 'lib/long-command-runner/runner.rb', line 143

def time_sys
  @times[:sys]
end

#time_userFloat | nil

Get the time in user space spend (‘user’ part of time command)

Returns:

  • (Float | nil)

    The elapsed seconds (using POSIX.2 standard see ‘time -p` for more information) if the Process isn’t finished it return nil.



135
136
137
# File 'lib/long-command-runner/runner.rb', line 135

def time_user
  @times[:user]
end

#waitProcess::Status

Wait and return the process exit status. This method is blocking until the process if finished.

Returns:

  • (Process::Status)


97
98
99
# File 'lib/long-command-runner/runner.rb', line 97

def wait
  @container.wait
end