vagrant/plugins/kernel_v2/config/trigger.rb

212 lines
6.6 KiB
Ruby

require "vagrant"
require File.expand_path("../vm_trigger", __FILE__)
module VagrantPlugins
module Kernel_V2
class TriggerConfig < Vagrant.plugin("2", :config)
# The TriggerConfig class is what gets called when a user
# defines a new trigger in their Vagrantfile. The two entry points are
# either `config.trigger.before` or `config.trigger.after`.
def initialize
@logger = Log4r::Logger.new("vagrant::config::trigger")
# Internal State
@_before_triggers = [] # An array of VagrantConfigTrigger objects
@_after_triggers = [] # An array of VagrantConfigTrigger objects
end
#-------------------------------------------------------------------
# Trigger before/after functions
#-------------------------------------------------------------------
#
# Commands are expected to be ether:
# - splat
# + config.trigger.before :up, :destroy, :halt do |trigger|....
# - array
# + config.trigger.before [:up, :destroy, :halt] do |trigger|....
#
# Config is expected to be given as a block, or the last parameter as a hash
#
# - block
# + config.trigger.before :up, :destroy, :halt do |trigger|
# trigger.option = "option"
# end
# - hash
# + config.trigger.before :up, :destroy, :halt, options: "option"
# Reads in and parses Vagrant command whitelist and settings for a defined
# trigger
#
# @param [Symbol] command Vagrant command to create trigger on
# @param [Block] block The defined before block
def before(*command, &block)
command.flatten!
blk = block
if command.last.is_a?(Hash)
if block_given?
extra_cfg = command.pop
else
# We were given a hash rather than a block,
# so the last element should be the "config block"
# and the rest are commands for the trigger
blk = command.pop
end
elsif !block_given?
raise Vagrant::Errors::TriggersNoBlockGiven,
command: command
end
command.each do |cmd|
trigger = create_trigger(cmd, blk, extra_cfg)
@_before_triggers << trigger
end
end
# Reads in and parses Vagrant command whitelist and settings for a defined
# trigger
#
# @param [Symbol] command Vagrant command to create trigger on
# @param [Block] block The defined after block
def after(*command, &block)
command.flatten!
blk = block
if command.last.is_a?(Hash)
if block_given?
extra_cfg = command.pop
else
# We were given a hash rather than a block,
# so the last element should be the "config block"
# and the rest are commands for the trigger
blk = command.pop
end
elsif !block_given?
raise Vagrant::Errors::TriggersNoBlockGiven,
command: command
end
command.each do |cmd|
trigger = create_trigger(cmd, blk, extra_cfg)
@_after_triggers << trigger
end
end
#-------------------------------------------------------------------
# Internal methods, don't call these.
#-------------------------------------------------------------------
# Creates a new trigger config. If a block is given, parse that block
# by calling it with the created trigger. Otherwise set the options if it's
# a hash.
#
# @param [Symbol] command Vagrant command to create trigger on
# @param [Block] block The defined config block
# @param [Hash] extra_cfg Extra configurations for a block defined trigger (Optional)
# @return [VagrantConfigTrigger]
def create_trigger(command, block, extra_cfg=nil)
trigger = VagrantConfigTrigger.new(command)
if block.is_a?(Hash)
trigger.set_options(block)
else
block.call(trigger, VagrantConfigTrigger)
trigger.set_options(extra_cfg) if extra_cfg
end
return trigger
end
def merge(other)
super.tap do |result|
new_before_triggers = []
new_after_triggers = []
other_defined_before_triggers = other.instance_variable_get(:@_before_triggers)
other_defined_after_triggers = other.instance_variable_get(:@_after_triggers)
@_before_triggers.each do |bt|
other_bft = other_defined_before_triggers.find { |o| bt.id == o.id }
if other_bft
# Override, take it
other_bft = bt.merge(other_bft)
# Preserve order, always
bt = other_bft
other_defined_before_triggers.delete(other_bft)
end
new_before_triggers << bt.dup
end
other_defined_before_triggers.each do |obt|
new_before_triggers << obt.dup
end
result.instance_variable_set(:@_before_triggers, new_before_triggers)
@_after_triggers.each do |at|
other_aft = other_defined_after_triggers.find { |o| at.id == o.id }
if other_aft
# Override, take it
other_aft = at.merge(other_aft)
# Preserve order, always
at = other_aft
other_defined_after_triggers.delete(other_aft)
end
new_after_triggers << at.dup
end
other_defined_after_triggers.each do |oat|
new_after_triggers << oat.dup
end
result.instance_variable_set(:@_after_triggers, new_after_triggers)
end
end
# Iterates over all defined triggers and finalizes their config objects
def finalize!
if !@_before_triggers.empty?
@_before_triggers.map { |t| t.finalize! }
end
if !@_after_triggers.empty?
@_after_triggers.map { |t| t.finalize! }
end
end
# Validate Trigger Arrays
def validate(machine)
errors = _detected_errors
@_before_triggers.each do |bt|
error = bt.validate(machine)
errors.concat error if !error.empty?
end
@_after_triggers.each do |at|
error = at.validate(machine)
errors.concat error if !error.empty?
end
{"trigger" => errors}
end
# return [Array]
def before_triggers
@_before_triggers
end
# return [Array]
def after_triggers
@_after_triggers
end
# The String representation of this Trigger.
#
# @return [String]
def to_s
"trigger"
end
end
end
end