This module enables a class to host capabilities. Prior to being able to use any capabilities, the `initialize_capabilities!` method must be called.
Capabilities allow small pieces of functionality to be plugged in using the Vagrant plugin model. Capabilities even allow for a certain amount of inheritence, where only a subset of capabilities may be implemented but a parent implements the rest.
Capabilities are used heavily in Vagrant for host/guest interactions. For example, “mount_nfs_folder” is a guest-OS specific operation, so capabilities defer these operations to the guest.
Executes the capability with the given name, optionally passing more arguments onwards to the capability. If the capability returns a value, it will be returned.
@param [Symbol] cap_name Name of the capability
# File lib/vagrant/capability_host.rb, line 91 def capability(cap_name, *args) cap_mod = capability_module(cap_name.to_sym) if !cap_mod raise Errors::CapabilityNotFound, :cap => cap_name.to_s, :host => @cap_host_chain[0][0].to_s end cap_method = nil begin cap_method = cap_mod.method(cap_name) rescue NameError raise Errors::CapabilityInvalid, :cap => cap_name.to_s, :host => @cap_host_chain[0][0].to_s end args = @cap_args + args @cap_logger.info( "Execute capability: #{cap_name} #{args.inspect} (#{@cap_host_chain[0][0]})") cap_method.call(*args) end
Tests whether the given capability is possible.
@param [Symbol] cap_name Capability name @return [Boolean]
# File lib/vagrant/capability_host.rb, line 82 def capability?(cap_name) !capability_module(cap_name.to_sym).nil? end
Returns the chain of hosts that will be checked for capabilities.
@return [Array<Array<Symbol, Class>>]
# File lib/vagrant/capability_host.rb, line 74 def capability_host_chain @cap_host_chain end
Initializes the capability system by detecting the proper capability host to execute on and building the chain of capabilities to execute.
@param [Symbol] host The host to use for the capabilities, or nil if
we should auto-detect it.
@param [Hash<Symbol, Array<Class, Symbol>>] hosts Potential capability
hosts. The key is the name of the host, value[0] is a class that implements %x#detect?` and value[1] is a parent host (if any).
@param [Hash<Symbol, Hash<Symbol, Class>>] capabilities The capabilities
that are supported. The key is the host of the capability. Within that is a hash where the key is the name of the capability and the value is the class/module implementing it.
# File lib/vagrant/capability_host.rb, line 27 def initialize_capabilities!(host, hosts, capabilities, *args) @cap_logger = Log4r::Logger.new( "vagrant::capability_host::#{self.class.to_s.downcase}") if host && !hosts[host] raise Errors::CapabilityHostExplicitNotDetected, value: host.to_s end if !host host = autodetect_capability_host(hosts, *args) if !host raise Errors::CapabilityHostNotDetected if !host end if !hosts[host] # This should never happen because the autodetect above uses the # hosts hash to look up hosts. And if an explicit host is specified, # we do another check higher up. raise "Internal error. Host not found: #{host}" end name = host host_info = hosts[name] host = host_info[0].new chain = [] chain << [name, host] # Build the proper chain of parents if there are any. # This allows us to do "inheritance" of capabilities later if host_info[1] parent_name = host_info[1] parent_info = hosts[parent_name] while parent_info chain << [parent_name, parent_info[0].new] parent_name = parent_info[1] parent_info = hosts[parent_name] end end @cap_host_chain = chain @cap_args = args @cap_caps = capabilities true end
# File lib/vagrant/capability_host.rb, line 116 def autodetect_capability_host(hosts, *args) @cap_logger.info("Autodetecting host type for #{args.inspect}") # Get the mapping of hosts with the most parents. We start searching # with the hosts with the most parents first. parent_count = {} hosts.each do |name, parts| parent_count[name] = 0 parent = parts[1] while parent parent_count[name] += 1 parent = hosts[parent] parent = parent[1] if parent end end # Now swap around the mapping so that it is a mapping of # count to the actual list of host names parent_count_to_hosts = {} parent_count.each do |name, count| parent_count_to_hosts[count] ||= [] parent_count_to_hosts[count] << name end sorted_counts = parent_count_to_hosts.keys.sort.reverse sorted_counts.each do |count| parent_count_to_hosts[count].each do |name| @cap_logger.debug("Trying: #{name}") host_info = hosts[name] host = host_info[0].new if host.detect?(*args) @cap_logger.info("Detected: #{name}!") return name end end end return nil end
Returns the registered module for a capability with the given name.
@param [Symbol] cap_name @return [Module]
# File lib/vagrant/capability_host.rb, line 162 def capability_module(cap_name) @cap_logger.debug("Searching for cap: #{cap_name}") @cap_host_chain.each do |host_name, host| @cap_logger.debug("Checking in: #{host_name}") caps = @cap_caps[host_name] if caps && caps.has_key?(cap_name) @cap_logger.debug("Found cap: #{cap_name} in #{host_name}") return caps[cap_name] end end nil end