vagrant/lib/vagrant/action.rb

119 lines
3.7 KiB
Ruby

module Vagrant
# Manages action running and registration. Every Vagrant environment
# has an instance of {Action} to allow for running in the context of
# the environment, which is accessible at {Environment#actions}. Actions
# are the foundation of most functionality in Vagrant, and are implemented
# architecturally as "middleware."
#
# # Registering an Action
#
# The main benefits of registering an action is the ability to retrieve and
# modify that registered action, as well as easily run the action. An example
# of registering an action is shown below, with a simple middleware which just
# outputs to `STDOUT`:
#
# class StdoutMiddleware
# def initialize(app, env)
# @app = app
# end
#
# def call(env)
# puts "HI!"
# @app.call(env)
# end
# end
#
# Vagrant::Action.register(:stdout, StdoutMiddleware)
#
# Then to run a registered action, assuming `env` is a loaded {Environment}:
#
# env.actions.run(:stdout)
#
# Or to retrieve the action class for any reason:
#
# Vagrant::Action[:stdout]
#
# # Running an Action
#
# There are various built-in registered actions such as `start`, `stop`, `up`,
# etc. Actions are built to be run in the context of an environment, so use
# {Environment#actions} to run all actions. Then simply call {#run}:
#
# env.actions.run(:name)
#
# Where `:name` is the name of the registered action.
#
class Action
include Util
@@reported_interrupt = false
class << self
# Returns the list of registered actions.
#
# @return [Array]
def actions
@actions ||= {}
end
# Registers an action and associates it with a symbol. This
# symbol can then be referenced in other action builds and
# callbacks can be registered on that symbol.
#
# @param [Symbol] key
def register(key, callable)
actions[key.to_sym] = callable
end
# Retrieves a registered action by key.
#
# @param [Symbol] key
def [](key)
actions[key.to_sym]
end
end
# The environment to run the actions in.
attr_reader :env
# Initializes the action with the given environment which the actions
# will be run in.
#
# @param [Environment] env
def initialize(env)
@env = env
end
# Runs the given callable object in the context of the environment.
# If a symbol is given as the `callable` parameter, then it is looked
# up in the registered actions list which are registered with {register}.
#
# Any options given are injected into the environment hash.
#
# @param [Object] callable An object which responds to `call`.
def run(callable, options=nil)
callable = Builder.new.use(callable) if callable.kind_of?(Class)
callable = self.class.actions[callable] if callable.kind_of?(Symbol)
raise ArgumentError.new("Argument to run must be a callable object or registered action.") if !callable
action_environment = Action::Environment.new(env)
action_environment.merge!(options || {})
# Run the action chain in a busy block, marking the environment as
# interrupted if a SIGINT occurs, and exiting cleanly once the
# chain has been run.
int_callback = lambda do
if action_environment.interrupted?
env.ui.error I18n.t("vagrant.actions.runner.exit_immediately")
abort
end
env.ui.warn I18n.t("vagrant.actions.runner.waiting_cleanup") if !@@reported_interrupt
action_environment.interrupt!
@@reported_interrupt = true
end
Busy.busy(int_callback) { callable.call(action_environment) }
end
end
end