252 lines
8.8 KiB
Ruby
252 lines
8.8 KiB
Ruby
require "set"
|
|
|
|
require "log4r"
|
|
|
|
require "vagrant/plugin/v2/components"
|
|
|
|
module Vagrant
|
|
module Plugin
|
|
module V2
|
|
# This is the superclass for all V2 plugins.
|
|
class Plugin
|
|
# Special marker that can be used for action hooks that matches
|
|
# all action sequences.
|
|
ALL_ACTIONS = :__all_actions__
|
|
|
|
# The logger for this class.
|
|
LOGGER = Log4r::Logger.new("vagrant::plugin::v2::plugin")
|
|
|
|
# Set the root class up to be ourself, so that we can reference this
|
|
# from within methods which are probably in subclasses.
|
|
ROOT_CLASS = self
|
|
|
|
# This returns the manager for all V2 plugins.
|
|
#
|
|
# @return [V2::Manager]
|
|
def self.manager
|
|
@manager ||= Manager.new
|
|
end
|
|
|
|
# Returns the {Components} for this plugin.
|
|
#
|
|
# @return [Components]
|
|
def self.components
|
|
@components ||= Components.new
|
|
end
|
|
|
|
# Set the name of the plugin. The moment that this is called, the
|
|
# plugin will be registered and available. Before this is called, a
|
|
# plugin does not exist. The name must be unique among all installed
|
|
# plugins.
|
|
#
|
|
# @param [String] name Name of the plugin.
|
|
# @return [String] The name of the plugin.
|
|
def self.name(name=UNSET_VALUE)
|
|
# Get or set the value first, so we have a name for logging when
|
|
# we register.
|
|
result = get_or_set(:name, name)
|
|
|
|
# The plugin should be registered if we're setting a real name on it
|
|
Plugin.manager.register(self) if name != UNSET_VALUE
|
|
|
|
# Return the result
|
|
result
|
|
end
|
|
|
|
# Sets a human-friendly descrition of the plugin.
|
|
#
|
|
# @param [String] value Description of the plugin.
|
|
# @return [String] Description of the plugin.
|
|
def self.description(value=UNSET_VALUE)
|
|
get_or_set(:description, value)
|
|
end
|
|
|
|
# Registers a callback to be called when a specific action sequence
|
|
# is run. This allows plugin authors to hook into things like VM
|
|
# bootup, VM provisioning, etc.
|
|
#
|
|
# @param [String] name Name of the action.
|
|
# @param [Symbol] hook_name The location to hook. If this isn't
|
|
# set, every middleware action is hooked.
|
|
# @return [Array] List of the hooks for the given action.
|
|
def self.action_hook(name, hook_name=nil, &block)
|
|
# The name is currently not used but we want it for the future.
|
|
|
|
hook_name ||= ALL_ACTIONS
|
|
components.action_hooks[hook_name.to_sym] << block
|
|
end
|
|
|
|
# Defines additional command line commands available by key. The key
|
|
# becomes the subcommand, so if you register a command "foo" then
|
|
# "vagrant foo" becomes available.
|
|
#
|
|
# @param [String] name Subcommand key.
|
|
def self.command(name, **opts, &block)
|
|
# Validate the name of the command
|
|
if name.to_s !~ /^[-a-z0-9]+$/i
|
|
raise InvalidCommandName, "Commands can only contain letters, numbers, and hyphens"
|
|
end
|
|
|
|
# By default, the command is primary
|
|
opts[:primary] = true if !opts.has_key?(:primary)
|
|
|
|
# Register the command
|
|
components.commands.register(name.to_sym) do
|
|
[block, opts]
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# Defines additional communicators to be available. Communicators
|
|
# should be returned by a block passed to this method. This is done
|
|
# to ensure that the class is lazy loaded, so if your class inherits
|
|
# from or uses any Vagrant internals specific to Vagrant 1.0, then
|
|
# the plugin can still be defined without breaking anything in future
|
|
# versions of Vagrant.
|
|
#
|
|
# @param [String] name Communicator name.
|
|
def self.communicator(name=UNSET_VALUE, &block)
|
|
data[:communicator] ||= Registry.new
|
|
|
|
# Register a new communicator class only if a name was given.
|
|
data[:communicator].register(name.to_sym, &block) if name != UNSET_VALUE
|
|
|
|
# Return the registry
|
|
data[:communicator]
|
|
end
|
|
|
|
# Defines additional configuration keys to be available in the
|
|
# Vagrantfile. The configuration class should be returned by a
|
|
# block passed to this method. This is done to ensure that the class
|
|
# is lazy loaded, so if your class inherits from any classes that
|
|
# are specific to Vagrant 1.0, then the plugin can still be defined
|
|
# without breaking anything in future versions of Vagrant.
|
|
#
|
|
# @param [String] name Configuration key.
|
|
def self.config(name, scope=nil, &block)
|
|
scope ||= :top
|
|
components.configs[scope].register(name.to_sym, &block)
|
|
nil
|
|
end
|
|
|
|
# Defines an additionally available guest implementation with
|
|
# the given key.
|
|
#
|
|
# @param [String] name Name of the guest.
|
|
# @param [String] parent Name of the parent guest (if any)
|
|
def self.guest(name, parent=nil, &block)
|
|
components.guests.register(name.to_sym) do
|
|
parent = parent.to_sym if parent
|
|
|
|
[block.call, parent]
|
|
end
|
|
nil
|
|
end
|
|
|
|
# Defines a capability for the given guest. The block should return
|
|
# a class/module that has a method with the capability name, ready
|
|
# to be executed. This means that if it is an instance method,
|
|
# the block should return an instance of the class.
|
|
#
|
|
# @param [String] guest The name of the guest
|
|
# @param [String] cap The name of the capability
|
|
def self.guest_capability(guest, cap, &block)
|
|
components.guest_capabilities[guest.to_sym].register(cap.to_sym, &block)
|
|
nil
|
|
end
|
|
|
|
# Defines an additionally available host implementation with
|
|
# the given key.
|
|
#
|
|
# @param [String] name Name of the host.
|
|
# @param [String] parent Name of the parent host (if any)
|
|
def self.host(name, parent=nil, &block)
|
|
components.hosts.register(name.to_sym) do
|
|
parent = parent.to_sym if parent
|
|
|
|
[block.call, parent]
|
|
end
|
|
nil
|
|
end
|
|
|
|
# Defines a capability for the given host. The block should return
|
|
# a class/module that has a method with the capability name, ready
|
|
# to be executed. This means that if it is an instance method,
|
|
# the block should return an instance of the class.
|
|
#
|
|
# @param [String] host The name of the host
|
|
# @param [String] cap The name of the capability
|
|
def self.host_capability(host, cap, &block)
|
|
components.host_capabilities[host.to_sym].register(cap.to_sym, &block)
|
|
nil
|
|
end
|
|
|
|
# Registers additional providers to be available.
|
|
#
|
|
# @param [Symbol] name Name of the provider.
|
|
def self.provider(name=UNSET_VALUE, options=nil, &block)
|
|
components.providers.register(name.to_sym) do
|
|
[block.call, options || {}]
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# Registers additional provisioners to be available.
|
|
#
|
|
# @param [String] name Name of the provisioner.
|
|
def self.provisioner(name=UNSET_VALUE, &block)
|
|
data[:provisioners] ||= Registry.new
|
|
|
|
# Register a new provisioner class only if a name was given
|
|
data[:provisioners].register(name.to_sym, &block) if name != UNSET_VALUE
|
|
|
|
# Return the registry
|
|
data[:provisioners]
|
|
end
|
|
|
|
# Registers additional synced folder implementations.
|
|
#
|
|
# @param [String] name Name of the implementation.
|
|
# @param [Integer] priority The priority of the implementation,
|
|
# higher (big) numbers are tried before lower (small) numbers.
|
|
def self.synced_folder(name, priority=10, &block)
|
|
components.synced_folders.register(name.to_sym) do
|
|
[block.call, priority]
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# Returns the internal data associated with this plugin. This
|
|
# should NOT be called by the general public.
|
|
#
|
|
# @return [Hash]
|
|
def self.data
|
|
@data ||= {}
|
|
end
|
|
|
|
protected
|
|
|
|
# Sentinel value denoting that a value has not been set.
|
|
UNSET_VALUE = Object.new
|
|
|
|
# Helper method that will set a value if a value is given, or otherwise
|
|
# return the already set value.
|
|
#
|
|
# @param [Symbol] key Key for the data
|
|
# @param [Object] value Value to store.
|
|
# @return [Object] Stored value.
|
|
def self.get_or_set(key, value=UNSET_VALUE)
|
|
# If no value is to be set, then return the value we have already set
|
|
return data[key] if value.eql?(UNSET_VALUE)
|
|
|
|
# Otherwise set the value
|
|
data[key] = value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|