Class: Aruba::Processes::SpawnProcess

Inherits:
BasicProcess show all
Defined in:
lib/aruba/processes/spawn_process.rb

Overview

Spawn a process for command

SpawnProcess is not meant for direct use - SpawnProcess.new - by users. Only it's public methods are part of the public API of aruba, e.g. #stdin, #stdout.

Direct Known Subclasses

SpawnProcess

Instance Attribute Summary

Attributes inherited from BasicProcess

#environment, #exit_status, #exit_timeout, #io_wait_timeout, #main_class, #startup_wait_time, #working_directory

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BasicProcess

#after_run, #before_run, #commandline, #inspect, #output, #restart, #run!, #started?, #stopped?, #timed_out?

Constructor Details

#initialize(cmd, exit_timeout, io_wait_timeout, working_directory, environment = ENV.to_hash.dup, main_class = nil, stop_signal = nil, startup_wait_time = 0) ⇒ SpawnProcess

Create process

Parameters:

  • cmd (String)

    Command string

  • exit_timeout (Numeric)

    The timeout until we expect the command to be finished

  • io_wait_timeout (Numeric)

    The timeout until we expect the io to be finished

  • working_directory (String)

    The directory where the command will be executed

  • environment (Hash) (defaults to: ENV.to_hash.dup)

    Environment variables

  • main_class (Class) (defaults to: nil)

    E.g. Cli::App::Runner

  • stop_signal (String) (defaults to: nil)

    Name of signal to send to stop process. E.g. 'HUP'.

  • startup_wait_time (Numeric) (defaults to: 0)

    The amount of seconds to wait after Aruba has started a command.



51
52
53
54
55
56
57
# File 'lib/aruba/processes/spawn_process.rb', line 51

def initialize(cmd, exit_timeout, io_wait_timeout, working_directory, environment = ENV.to_hash.dup, main_class = nil, stop_signal = nil, startup_wait_time = 0)
  super

  @process      = nil
  @stdout_cache = nil
  @stderr_cache = nil
end

Class Method Details

.match?(mode) ⇒ Boolean

Use as default launcher

Returns:

  • (Boolean)


22
23
24
# File 'lib/aruba/processes/spawn_process.rb', line 22

def self.match?(mode)
  true
end

Instance Method Details

#close_io(name) ⇒ Object

Close io



175
176
177
178
179
180
181
182
183
# File 'lib/aruba/processes/spawn_process.rb', line 175

def close_io(name)
  return if stopped?

  if RUBY_VERSION < '1.9'
    @process.io.send(name.to_sym).close
  else
    @process.io.public_send(name.to_sym).close
  end
end

#contentString

Content of command

Returns:

  • (String)

    The content of the script/command. This might be binary output as string if your command is a binary executable.



263
264
265
# File 'lib/aruba/processes/spawn_process.rb', line 263

def content
  File.read command_string.to_s
end

#filesystem_statusAruba::Platforms::FilesystemStatus

Return file system stats for the given command

Returns:



254
255
256
# File 'lib/aruba/processes/spawn_process.rb', line 254

def filesystem_status
  Aruba.platform.filesystem_status.new(command_string.to_s)
end

#pidObject

Output pid of process

This is the PID of the spawned process.



234
235
236
# File 'lib/aruba/processes/spawn_process.rb', line 234

def pid
  @process.pid
end

#read_stdoutObject



157
158
159
160
161
162
163
# File 'lib/aruba/processes/spawn_process.rb', line 157

def read_stdout
  # rubocop:disable Metrics/LineLength
  Aruba.platform.deprecated('The use of "#read_stdout" is deprecated. Use "#stdout" instead. To reduce the time to wait for io, pass `:wait_for_io => 0` or some suitable for your use case')
  # rubocop:enable Metrics/LineLength

  stdout(:wait_for_io => 0)
end

#send_signal(signal) ⇒ Object

Send command a signal

Parameters:

  • signal (String)

    The signal, i.e. 'TERM'



242
243
244
245
246
247
248
# File 'lib/aruba/processes/spawn_process.rb', line 242

def send_signal(signal)
  fail CommandAlreadyStoppedError, %(Command "#{commandline}" with PID "#{pid}" has already stopped.) if @process.exited?

  Process.kill signal, pid
rescue Errno::ESRCH
  raise CommandAlreadyStoppedError, %(Command "#{commandline}" with PID "#{pid}" has already stopped.)
end

#start {|SpawnProcess| ... } ⇒ Object

Run the command

rubocop:disable Metrics/MethodLength

Yields:



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
106
107
108
109
# File 'lib/aruba/processes/spawn_process.rb', line 65

def start
  # rubocop:disable Metrics/LineLength
  fail CommandAlreadyStartedError, %(Command "#{commandline}" has already been started. Please `#stop` the command first and `#start` it again. Alternatively use `#restart`.\n#{caller.join("\n")}) if started?
  # rubocop:enable Metrics/LineLength

  @started = true

  @process = ChildProcess.build(*[command_string.to_a, arguments].flatten)
  @stdout_file = Tempfile.new('aruba-stdout-')
  @stderr_file = Tempfile.new('aruba-stderr-')

  @stdout_file.sync = true
  @stderr_file.sync = true

  if RUBY_VERSION >= '1.9'
    @stdout_file.set_encoding('ASCII-8BIT')
    @stderr_file.set_encoding('ASCII-8BIT')
  end

  @exit_status = nil
  @duplex      = true

  before_run

  @process.leader    = true
  @process.io.stdout = @stdout_file
  @process.io.stderr = @stderr_file
  @process.duplex    = @duplex
  @process.cwd       = @working_directory

  @process.environment.update(environment)

  begin
    Aruba.platform.with_environment(environment) do
      @process.start
      sleep startup_wait_time
    end
  rescue ChildProcess::LaunchError => e
    raise LaunchError, "It tried to start #{cmd}. " + e.message
  end

  after_run

  yield self if block_given?
end

#stderr(opts = {}) ⇒ String

Access to stderr of process

Parameters:

  • opts (Hash) (defaults to: {})

    Options

  • [Integer] (Hash)

    a customizable set of options

Returns:

  • (String)

    The content of stderr



148
149
150
151
152
153
154
155
# File 'lib/aruba/processes/spawn_process.rb', line 148

def stderr(opts = {})
  return @stderr_cache if stopped?

  wait_for_io opts.fetch(:wait_for_io, io_wait_timeout) do
    @process.io.stderr.flush
    open(@stderr_file.path).read
  end
end

#stdinObject

Access to stdin of process



113
114
115
116
117
# File 'lib/aruba/processes/spawn_process.rb', line 113

def stdin
  return if @process.exited?

  @process.io.stdin
end

#stdout(opts = {}) ⇒ String

Access to stdout of process

Parameters:

  • opts (Hash) (defaults to: {})

    Options

  • [Integer] (Hash)

    a customizable set of options

Returns:

  • (String)

    The content of stdout



129
130
131
132
133
134
135
136
# File 'lib/aruba/processes/spawn_process.rb', line 129

def stdout(opts = {})
  return @stdout_cache if stopped?

  wait_for_io opts.fetch(:wait_for_io, io_wait_timeout) do
    @process.io.stdout.flush
    open(@stdout_file.path).read
  end
end

#stopObject

Stop command



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/aruba/processes/spawn_process.rb', line 186

def stop(*)
  return @exit_status if stopped?

  begin
    @process.poll_for_exit(@exit_timeout)
  rescue ChildProcess::TimeoutError
    @timed_out = true
  end

  terminate
end

#terminateObject

Terminate command



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/aruba/processes/spawn_process.rb', line 204

def terminate
  return @exit_status if stopped?

  unless @process.exited?
    if @stop_signal
      # send stop signal ...
      send_signal @stop_signal
      # ... and set the exit status
      wait
    else
      @process.stop
    end
  end

  @exit_status  = @process.exit_code

  @stdout_cache = read_temporary_output_file @stdout_file
  @stderr_cache = read_temporary_output_file @stderr_file

  # @stdout_file = nil
  # @stderr_file = nil

  @started = false

  @exit_status
end

#waitObject

Wait for command to finish



199
200
201
# File 'lib/aruba/processes/spawn_process.rb', line 199

def wait
  @process.wait
end

#write(input) ⇒ Object



165
166
167
168
169
170
171
172
# File 'lib/aruba/processes/spawn_process.rb', line 165

def write(input)
  return if stopped?

  @process.io.stdin.write(input)
  @process.io.stdin.flush

  self
end