Class: Unobtainium::Support::Runner Private

Inherits:
Object
  • Object
show all
Defined in:
lib/unobtainium/support/runner.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Runs a shell command and detaches. Offers methods for managing the process lifetime. Implements #destroy, so you can use it with the Runtime class to kill the shell command upon script end.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id, *command) ⇒ Runner

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize with a shell command, but do not run yet.

Parameters:

  • id (String)

    a unique ID for the command. This is to differentiate multiple similar commands from each other.

  • command (Array)

    the remaining parameters are the command and its arguments.



45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/unobtainium/support/runner.rb', line 45

def initialize(id, *command)
  if command.empty?
    raise ArgumentError, "Command may not be empty!"
  end

  @id = id
  @command = command
  @pid = nil
  @stdout = nil
  @stderr = nil
  @wout = nil
  @werr = nil
end

Instance Attribute Details

#commandArray (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the command passed to the constructor.

Returns:

  • (Array)

    the command passed to the constructor



24
25
26
# File 'lib/unobtainium/support/runner.rb', line 24

def command
  @command
end

#idString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the ID passed to the constructor.

Returns:

  • (String)

    the ID passed to the constructor



21
22
23
# File 'lib/unobtainium/support/runner.rb', line 21

def id
  @id
end

#pidInteger (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns if the command is started, the pid of the process, or nil otherwise.

Returns:

  • (Integer)

    if the command is started, the pid of the process, or nil otherwise.



28
29
30
# File 'lib/unobtainium/support/runner.rb', line 28

def pid
  @pid
end

#stderrIO (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns if the command is started, an IO object to read the commands error output from, or nil otherwise.

Returns:

  • (IO)

    if the command is started, an IO object to read the commands error output from, or nil otherwise.



36
37
38
# File 'lib/unobtainium/support/runner.rb', line 36

def stderr
  @stderr
end

#stdoutIO (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns if the command is started, an IO object to read the commands output from, or nil otherwise.

Returns:

  • (IO)

    if the command is started, an IO object to read the commands output from, or nil otherwise.



32
33
34
# File 'lib/unobtainium/support/runner.rb', line 32

def stdout
  @stdout
end

Instance Method Details

#destroyObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Send the “KILL” signal to the command process and all its children Use together with Runtime class to clean up any commands at exit.



149
150
151
152
# File 'lib/unobtainium/support/runner.rb', line 149

def destroy
  kill
  reset
end

#killObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Send the “KILL” signal to the command process and all its children



101
102
103
104
# File 'lib/unobtainium/support/runner.rb', line 101

def kill
  signal("KILL", scope: :all)
  cleanup
end

#resetObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Resets stdout, stderr, etc. - does not kill a process, see #kill instead.



86
87
88
# File 'lib/unobtainium/support/runner.rb', line 86

def reset
  cleanup(true)
end

#signal(signal, scope: :self) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Send the given signal to the process, and/or it’s children.

Parameters:

  • signal (String)

    the signal to send

  • scope (Symbol) (defaults to: :self)

    one of :self (the command process), :children (it’s children *only) or :all (the process and its children.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/unobtainium/support/runner.rb', line 112

def signal(signal, scope: :self)
  if @pid.nil?
    raise "No command is running!"
  end

  if not [:self, :children, :all].include?(scope)
    raise ArgumentError, "The :scope argument must be one of :self, "\
        ":children or :all!"
  end

  # Figure out which pids to send the signal to. That is usually @pid,
  # but possibly its children.
  to_send = []
  if [:self, :all].include?(scope)
    to_send << @pid
  end

  if [:children, :all].include?(scope)
    children = ::Sys::ProcTable.ps.select { |p| p.ppid == @pid }
    to_send += children.collect(&:pid)
  end

  # Alright, send the signal!
  to_send.each do |pid|
    # rubocop:disable Lint/HandleExceptions
    begin
      Process.kill(signal, pid)
    rescue
      # If the kill didn't work, we don't really care.
    end
    # rubocop:enable Lint/HandleExceptions
  end
end

#startInteger

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Start the command. Afterwards, #pid, #stdout, and #stderr should be non-nil.

Returns:

  • (Integer)

    the pid of the command process



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/unobtainium/support/runner.rb', line 63

def start
  if not @pid.nil?
    raise "Command already running!"
  end

  # Reset everything
  reset

  # Capture options; pipes for stdout and stderr
  @stdout, @wout = IO.pipe
  @stderr, @werr = IO.pipe
  opts = {
    out: @wout,
    err: @werr,
  }

  @pid = spawn({}, *@command, opts)
  return @pid
end

#waitProcess::Status

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Wait for the command to exit.

Returns:

  • (Process::Status)

    exit status of the command.



93
94
95
96
97
# File 'lib/unobtainium/support/runner.rb', line 93

def wait
  _, status = Process.wait2(@pid)
  cleanup
  return status
end