Class: Sprout::Executable::Session

Inherits:
Base
  • Object
show all
Defined in:
sprout/lib/sprout/executable/session.rb

Overview

The Sprout::Daemon class exposes the Domain Specific Language provided by the Sprout::Executable, along with enhancements (and modifications) to support long-lived processes (like FDB and FCSH).

##
# The Foo class extends Sprout::Daemon
class Foo < Sprout::Daemon

  ##
  # Keep in mind that we're still working
  # with Executable, so add_param is available
  # for the initialization of the process.
  add_param :input, File

  ##
  # Expose the do_something action after
  # the process is started.
  add_action :do_something

  ##
  # Expose the do_something_else action after
  # the process is started.
  add_action :do_something_else
end

You can also create a globally-accessible rake task to use your new Daemon instance by creating a method like the following:

def foo *args, &block
  foo_tool = Foo.new
  foo_tool.to_rake *args, &block
end

The previous Rake task could be used like:

foo 'Bar.txt' do |t|
  t.do_something
  t.do_something_else
end

Direct Known Subclasses

FlashSDK::FCSH, FlashSDK::FDB

Constant Summary

Constants included from Sprout::Executable

DEFAULT_FILE_EXPRESSION, DEFAULT_PREFIX, DEFAULT_SHORT_PREFIX

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods inherited from Base

add_param, add_param_alias, #binary_path, #binary_path=, #default_file_expression, #execute_delegate, #from_hash, #initialize, #library_added, #parse!, #parse_extra_options!, #parse_rake_task_arg, #prepare, set, static_default_value_collection, static_parameter_collection, #stderr, #stderr=, #stdout, #stdout=, #to_hash, #to_help, #to_rake, #to_shell

Methods included from Concern

#append_features, extended, #included

Constructor Details

This class inherits a constructor from Sprout::Executable::Base

Instance Attribute Details

- (Object) process_runner (readonly)

The Sprout::ProcessRunner that delegates to the long-running process, via stdin, stdout and stderr.



147
148
149
# File 'sprout/lib/sprout/executable/session.rb', line 147

def process_runner
  @process_runner
end

- (Object) process_thread (readonly)

The Thread that contains the forked running process.



151
152
153
# File 'sprout/lib/sprout/executable/session.rb', line 151

def process_thread
  @process_thread
end

- (Regexp) prompt

The prompt expression for this daemon process.

When executing a series of commands, the wrapper will wait until it matches this expression on stdout before continuing the series.

For FDB, this value is set like:

set :prompt, /^\(fdb\) /

Most processes can trigger a variety of different prompts, these can be expressed here using the | (or) operator.

FDB actually uses the following:

set :prompt, /^\(fdb\) |\(y or n\) /

Returns:

  • (Regexp)


141
142
143
# File 'sprout/lib/sprout/executable/session.rb', line 141

def prompt
  @prompt
end

Class Method Details

+ (nil) add_action(name, arguments = nil, options = nil)

Add an action that can be called while the long-lived process is active.

This method should raise a Sprout::Errors::UsageError if the provided action name is already defined for the provided instance.

Parameters:

  • (Symbol, String) name

    The name of the method.

  • (Array<Object>) arguments (defaults to: nil)

    An array of arguments that the method accepts.

  • (Hash) options (defaults to: nil)

    The options hash is reserved for future use.

    class Foo < Sprout::Daemon

    add_action :continue
    
    add_action :quit

    end

Returns:

  • (nil)


70
71
72
73
74
75
76
# File 'sprout/lib/sprout/executable/session.rb', line 70

def add_action name, arguments=nil, options=nil
  options ||= {}
  options[:name] = name
  options[:arguments] = arguments
  create_action_method options
  nil
end

+ (nil) add_action_alias(alias_name, source_name)

Create an (often shorter) alias to an existing action name.

Returns:

  • (nil)

See Also:



85
86
87
88
89
90
# File 'sprout/lib/sprout/executable/session.rb', line 85

def add_action_alias alias_name, source_name
  define_method(alias_name) do |*params|
    self.send(source_name, params)
  end
  nil
end

Instance Method Details

- (Array<Hash>) action_stack

Return or create a new array.

Returns:

  • (Array<Hash>)

    Return or create a new array.



155
156
157
# File 'sprout/lib/sprout/executable/session.rb', line 155

def action_stack
  @action_stack ||= []
end

- (Rake::Task) create_outer_task(*args) (protected)

This is the override of the underlying Sprout::Executable template method so that we create a 'task' instead of a 'file' task.

Returns:



249
250
251
252
253
# File 'sprout/lib/sprout/executable/session.rb', line 249

def create_outer_task *args
  task *args do
    execute
  end
end

- (Object) execute(should_wait = true)

Execute the Daemon executable, followed by the collection of stored actions in the order they were called.

If none of the stored actions result in terminating the process, the underlying daemon will be connected to the terminal for user (manual) input.

You can also send wait=false to connect to a daemon process from Ruby and execute actions over time. This might look like:

fdb = FlashSDK::FDB.new
fdb.execute false

# Do something else while FDB
# is open, then:

fdb.run
fdb.break "AsUnitRunner:12"
fdb.continue
fdb.kill
fdb.confirm
fdb.quit

Parameters:

  • (Boolean) wait

    default true. Send false to connect to a daemon from Ruby code.



195
196
197
198
199
200
201
# File 'sprout/lib/sprout/executable/session.rb', line 195

def execute should_wait=true
  @process_runner = super()
  @process_launched = true
  wait_for_prompt
  execute_actions
  handle_user_input if should_wait
end

- (Object) handle_user_input

Expose the running process to manual input on the terminal, and write stdout back to the user.



224
225
226
227
228
229
230
231
232
233
234
235
# File 'sprout/lib/sprout/executable/session.rb', line 224

def handle_user_input
  while true
    begin
      break if !wait_for_prompt
      input = $stdin.gets.chomp!
      execute_action(input, true)
    rescue SignalException => e
      return false
    end
  end
  wait
end

- (Boolean) process_launched? (protected)

Returns:



239
240
241
# File 'sprout/lib/sprout/executable/session.rb', line 239

def process_launched?
  @process_launched
end

- (Boolean) prompted?

If executable is awaiting input.

Returns:

  • (Boolean)

    If executable is awaiting input.



161
162
163
# File 'sprout/lib/sprout/executable/session.rb', line 161

def prompted?
  @prompted
end

- (Thread) system_execute(binary, params) (protected)

This is the override of the underlying Sprout::Executable template method so that we create the process in a thread in order to read and write to it.

Returns:

  • (Thread)


273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'sprout/lib/sprout/executable/session.rb', line 273

def system_execute binary, params
  # Combine the stderr and stdout for long-lived
  # processes so that they are both written to
  # stdout, this allows us to collect these streams
  # without threads or blocking eternally.
  #
  # Thanks to https://github.com/apinstein for this
  # solution.
  #params = "#{params} " + '2>&1'
  @process_thread = Sprout.current_system.execute_thread binary, params, prompt do |message|
    Sprout.stdout.printf message
    @prompted = true if prompt.match message
  end
  @process_runner = process_thread['runner']
end

- (String) update_rake_task_name_from_args(*args) (protected)

This is the override of the underlying Sprout::Executable template method so that we are NOT added to the CLEAN collection. (Work performed in the Executable)

Returns:



262
263
264
# File 'sprout/lib/sprout/executable/session.rb', line 262

def update_rake_task_name_from_args *args
  self.rake_task_name = parse_rake_task_arg args.last
end

- (Object) wait



203
204
205
206
# File 'sprout/lib/sprout/executable/session.rb', line 203

def wait
  Process.wait process_runner.pid
rescue Errno::ECHILD
end

- (Object) wait_for_prompt

Wait for the underlying process to present an input prompt, so that another action can be submitted, or user input can be collected.



213
214
215
216
217
218
# File 'sprout/lib/sprout/executable/session.rb', line 213

def wait_for_prompt
  while process_thread.alive? && !prompted?
    sleep 0.2
  end
  process_thread.alive?
end