class Vagrant::Plugin::V2::Trigger
Attributes
@return [Kernel_V2::Config::Trigger]
Public Class Methods
This class is responsible for setting up basic triggers that were defined inside a Vagrantfile
.
@param [Vagrant::Environment] env Vagrant
environment @param [Kernel_V2::TriggerConfig] config Trigger
configuration @param [Vagrant::Machine] machine Active Machine
@param [Vagrant::UI] ui Class for printing messages to user
# File lib/vagrant/plugin/v2/trigger.rb, line 24 def initialize(env, config, machine, ui) @env = env @config = config @machine = machine @ui = ui @logger = Log4r::Logger.new("vagrant::trigger::#{self.class.to_s.downcase}") end
Public Instance Methods
Find all triggers defined for the named type and guest.
@param [Symbol] name Name of ‘type` thing to fire trigger on @param [Symbol] stage :before or :after @param [String] guest The guest that invoked firing the triggers @param [Symbol] type Type of trigger to fire @return [Array]
# File lib/vagrant/plugin/v2/trigger.rb, line 69 def find(name, stage, guest, type, all: false) triggers = nil name = nameify(name) if stage == :before triggers = config.before_triggers.select do |t| (all && t.command.respond_to?(:to_sym) && t.command.to_sym == :all && !t.ignore.include?(name.to_sym)) || (type == :hook && matched_hook?(t.command, name)) || nameify(t.command) == name end elsif stage == :after triggers = config.after_triggers.select do |t| (all && t.command.respond_to?(:to_sym) && t.command.to_sym == :all && !t.ignore.include?(name.to_sym)) || (type == :hook && matched_hook?(t.command, name)) || nameify(t.command) == name end else raise Errors::TriggersNoStageGiven, name: name, stage: stage, type: type, guest_name: guest end filter_triggers(triggers, guest, type) end
Fires all triggers, if any are defined for the named type and guest. Returns early and logs a warning if the community plugin ‘vagrant-triggers` is installed
@param [Symbol] name Name of ‘type` thing to fire trigger on @param [Symbol] stage :before or :after @param [String] guest The guest that invoked firing the triggers @param [Symbol] type Type of trigger to fire (:action, :hook, :command)
# File lib/vagrant/plugin/v2/trigger.rb, line 40 def fire(name, stage, guest, type, all: false) if community_plugin_detected? @logger.warn("Community plugin `vagrant-triggers detected, so core triggers will not fire") return end return @logger.warn("Name given is nil, no triggers will fire") if !name return @logger.warn("Name given cannot be symbolized, no triggers will fire") if !name.respond_to?(:to_sym) name = name.to_sym # get all triggers matching action triggers = find(name, stage, guest, type, all: all) if !triggers.empty? @logger.info("Firing trigger for #{type} #{name} on guest #{guest}") @ui.info(I18n.t("vagrant.trigger.start", type: type, stage: stage, name: name)) execute(triggers) end end
Protected Instance Methods
Looks up if the community plugin ‘vagrant-triggers` is installed and also caches the result
@return [Boolean]
# File lib/vagrant/plugin/v2/trigger.rb, line 129 def community_plugin_detected? if !defined?(@_triggers_enabled) plugins = Vagrant::Plugin::Manager.instance.installed_plugins @_triggers_enabled = plugins.keys.include?("vagrant-triggers") end @_triggers_enabled end
Execute all triggers in the given array
@param [Array] triggers An array of triggers to be fired
# File lib/vagrant/plugin/v2/trigger.rb, line 179 def execute(triggers) # ensure on_error is respected by exiting or continuing triggers.each do |trigger| @logger.debug("Running trigger #{trigger.id}...") if trigger.name @ui.info(I18n.t("vagrant.trigger.fire_with_name", name: trigger.name)) else @ui.info(I18n.t("vagrant.trigger.fire")) end if trigger.info info(trigger.info) end if trigger.warn warn(trigger.warn) end if trigger.abort trigger_abort(trigger.abort) end if trigger.run run(trigger.run, trigger.on_error, trigger.exit_codes) end if trigger.run_remote run_remote(trigger.run_remote, trigger.on_error, trigger.exit_codes) end if trigger.ruby_block execute_ruby(trigger.ruby_block) end end end
Calls the given ruby block for execution
@param [Proc] ruby_block
# File lib/vagrant/plugin/v2/trigger.rb, line 358 def execute_ruby(ruby_block) ruby_block.call(@env, @machine) end
Filters triggers to be fired based on configured restraints
@param [Array] triggers An array of triggers to be filtered @param [String] guest_name The name of the current guest @param [Symbol] type The type of trigger (:command or :type) @return [Array] The filtered array of triggers
# File lib/vagrant/plugin/v2/trigger.rb, line 143 def filter_triggers(triggers, guest_name, type) # look for only_on trigger constraint and if it doesn't match guest # name, throw it away also be sure to preserve order filter = triggers.dup filter.each do |trigger| index = nil match = false if trigger.only_on trigger.only_on.each do |o| if o.match(guest_name.to_s) # trigger matches on current guest, so we're fine to use it match = true break end end # no matches found, so don't use trigger for guest index = triggers.index(trigger) unless match == true end if trigger.type != type index = triggers.index(trigger) end if index @logger.debug("Trigger #{trigger.id} will be ignored for #{guest_name}") triggers.delete_at(index) end end return triggers end
Prints the given message at info level for a trigger
@param [String] message The string to be printed
# File lib/vagrant/plugin/v2/trigger.rb, line 220 def info(message) @ui.info(message) end
Generate all valid lookup keys for given action key
@param [Class, String] key Base key for generation @return [Array<String>] all valid keys
# File lib/vagrant/plugin/v2/trigger.rb, line 118 def matched_hook?(key, subject) subject = nameify(subject) Vagrant.plugin("2").manager.generate_hook_keys(key).any? do |k| k == subject end end
Convert object into name
@param [Object, Class] object Object to name @return [String]
# File lib/vagrant/plugin/v2/trigger.rb, line 102 def nameify(object) if object.is_a?(Class) object.name.to_s else object.to_s end end
Runs a script on a guest
@param [Provisioners::Shell::Config] config A Shell provisioner config
# File lib/vagrant/plugin/v2/trigger.rb, line 234 def run(config, on_error, exit_codes) if config.inline if Vagrant::Util::Platform.windows? cmd = config.inline else cmd = Shellwords.split(config.inline) end @ui.detail(I18n.t("vagrant.trigger.run.inline", command: config.inline)) else cmd = File.expand_path(config.path, @env.root_path).shellescape args = Array(config.args) cmd << " #{args.join(' ')}" if !args.empty? cmd = Shellwords.split(cmd) @ui.detail(I18n.t("vagrant.trigger.run.script", path: config.path)) end # Pick an execution method to run the script or inline string with # Default to Subprocess::Execute exec_method = Vagrant::Util::Subprocess.method(:execute) if Vagrant::Util::Platform.windows? if config.inline exec_method = Vagrant::Util::PowerShell.method(:execute_inline) else exec_method = Vagrant::Util::PowerShell.method(:execute) end end begin result = exec_method.call(*cmd, :notify => [:stdout, :stderr]) do |type,data| options = {} case type when :stdout options[:color] = :green if !config.keep_color when :stderr options[:color] = :red if !config.keep_color end @ui.detail(data, **options) end if !exit_codes.include?(result.exit_code) raise Errors::TriggersBadExitCodes, code: result.exit_code end rescue => e @ui.error(I18n.t("vagrant.errors.triggers_run_fail")) @ui.error(e.message) if on_error == :halt @logger.debug("Trigger run encountered an error. Halting on error...") raise e else @logger.debug("Trigger run encountered an error. Continuing on anyway...") @ui.warn(I18n.t("vagrant.trigger.on_error_continue")) end end end
Runs a script on the guest
@param [ShellProvisioner/Config] config A Shell provisioner config
# File lib/vagrant/plugin/v2/trigger.rb, line 297 def run_remote(config, on_error, exit_codes) if !@machine # machine doesn't even exist. if on_error == :halt raise Errors::TriggersGuestNotExist else @ui.warn(I18n.t("vagrant.errors.triggers_guest_not_exist")) @ui.warn(I18n.t("vagrant.trigger.on_error_continue")) return end elsif @machine.state.id != :running if on_error == :halt raise Errors::TriggersGuestNotRunning, machine_name: @machine.name, state: @machine.state.id else @machine.ui.error(I18n.t("vagrant.errors.triggers_guest_not_running", machine_name: @machine.name, state: @machine.state.id)) @machine.ui.warn(I18n.t("vagrant.trigger.on_error_continue")) return end end prov = VagrantPlugins::Shell::Provisioner.new(@machine, config) begin prov.provision rescue => e @machine.ui.error(I18n.t("vagrant.errors.triggers_run_fail")) if on_error == :halt @logger.debug("Trigger run encountered an error. Halting on error...") raise e else @logger.debug("Trigger run encountered an error. Continuing on anyway...") @machine.ui.error(e.message) end end end
Exits Vagrant
immediately
@param [Integer] code Code to exit Vagrant
on
# File lib/vagrant/plugin/v2/trigger.rb, line 341 def trigger_abort(exit_code) if Thread.current[:batch_parallel_action] @ui.warn(I18n.t("vagrant.trigger.abort_threaded")) @logger.debug("Trigger abort within parallel batch action. " \ "Setting exit code and terminating.") Thread.current[:exit_code] = exit_code Thread.current.terminate else @ui.warn(I18n.t("vagrant.trigger.abort")) @logger.debug("Trigger abort within non-parallel action, exiting directly") Process.exit!(exit_code) end end
Prints the given message at warn level for a trigger
@param [String] message The string to be printed
# File lib/vagrant/plugin/v2/trigger.rb, line 227 def warn(message) @ui.warn(message) end