1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
require_relative '../../puppet'
require_relative '../../puppet/util/classgen'
require_relative '../../puppet/node/environment'
# This module defines methods dealing with Type management.
# This module gets included into the Puppet::Type class, it's just split out here for clarity.
# @api public
#
module Puppet::MetaType
module Manager
include Puppet::Util::ClassGen
# An implementation specific method that removes all type instances during testing.
# @note Only use this method for testing purposes.
# @api private
#
def allclear
@types.each { |name, type|
type.clear
}
end
# Clears any types that were used but absent when types were last loaded.
# @note Used after each catalog compile when always_retry_plugins is false
# @api private
#
def clear_misses
unless @types.nil?
@types.delete_if {|_, v| v.nil? }
end
end
# Iterates over all already loaded Type subclasses.
# @yield [t] a block receiving each type
# @yieldparam t [Puppet::Type] each defined type
# @yieldreturn [Object] the last returned object is also returned from this method
# @return [Object] the last returned value from the block.
def eachtype
@types.each do |name, type|
# Only consider types that have names
#if ! type.parameters.empty? or ! type.validproperties.empty?
yield type
#end
end
end
# Loads all types.
# @note Should only be used for purposes such as generating documentation as this is potentially a very
# expensive operation.
# @return [void]
#
def loadall
typeloader.loadall(Puppet.lookup(:current_environment))
end
# Defines a new type or redefines an existing type with the given name.
# A convenience method on the form `new<name>` where name is the name of the type is also created.
# (If this generated method happens to clash with an existing method, a warning is issued and the original
# method is kept).
#
# @param name [String] the name of the type to create or redefine.
# @param options [Hash] options passed on to {Puppet::Util::ClassGen#genclass} as the option `:attributes`.
# @option options [Puppet::Type]
# Puppet::Type. This option is not passed on as an attribute to genclass.
# @yield [ ] a block evaluated in the context of the created class, thus allowing further detailing of
# that class.
# @return [Class<inherits Puppet::Type>] the created subclass
# @see Puppet::Util::ClassGen.genclass
#
# @dsl type
# @api public
def newtype(name, options = {}, &block)
@manager_lock.synchronize do
# Handle backward compatibility
unless options.is_a?(Hash)
#TRANSLATORS 'Puppet::Type.newtype' should not be translated
Puppet.warning(_("Puppet::Type.newtype(%{name}) now expects a hash as the second argument, not %{argument}") %
{ name: name, argument: options.inspect})
end
# First make sure we don't have a method sitting around
name = name.intern
newmethod = "new#{name}"
# Used for method manipulation.
selfobj = singleton_class
if @types.include?(name)
if self.respond_to?(newmethod)
# Remove the old newmethod
selfobj.send(:remove_method,newmethod)
end
end
# Then create the class.
klass = genclass(
name,
:parent => Puppet::Type,
:overwrite => true,
:hash => @types,
:attributes => options,
&block
)
# Now define a "new<type>" method for convenience.
if self.respond_to? newmethod
# Refuse to overwrite existing methods like 'newparam' or 'newtype'.
#TRANSLATORS 'new%{method}' will become a method name, do not translate this string
Puppet.warning(_("'new%{method}' method already exists; skipping") % { method: name.to_s })
else
selfobj.send(:define_method, newmethod) do |*args|
klass.new(*args)
end
end
# If they've got all the necessary methods defined and they haven't
# already added the property, then do so now.
klass.ensurable if klass.ensurable? and ! klass.validproperty?(:ensure)
# Now set up autoload any providers that might exist for this type.
klass.providerloader = Puppet::Util::Autoload.new(klass, "puppet/provider/#{klass.name}")
# We have to load everything so that we can figure out the default provider.
klass.providerloader.loadall(Puppet.lookup(:current_environment))
klass.providify unless klass.providers.empty?
loc = block_given? ? block.source_location : nil
uri = loc.nil? ? nil : URI("#{Puppet::Util.path_to_uri(loc[0])}?line=#{loc[1]}")
Puppet::Pops::Loaders.register_runtime3_type(name, uri)
klass
end
end
# Removes an existing type.
# @note Only use this for testing.
# @api private
def rmtype(name)
# Then create the class.
rmclass(name, :hash => @types)
singleton_class.send(:remove_method, "new#{name}") if respond_to?("new#{name}")
end
# Returns a Type instance by name.
# This will load the type if not already defined.
# @param [String, Symbol] name of the wanted Type
# @return [Puppet::Type, nil] the type or nil if the type was not defined and could not be loaded
#
def type(name)
@manager_lock.synchronize do
# Avoid loading if name obviously is not a type name
if name.to_s.include?(':')
return nil
end
# We are overwhelmingly symbols here, which usually match, so it is worth
# having this special-case to return quickly. Like, 25K symbols vs. 300
# strings in this method. --daniel 2012-07-17
return @types[name] if @types.include? name
# Try mangling the name, if it is a string.
if name.is_a? String
name = name.downcase.intern
return @types[name] if @types.include? name
end
# Try loading the type.
if typeloader.load(name, Puppet.lookup(:current_environment))
#TRANSLATORS 'puppet/type/%{name}' should not be translated
Puppet.warning(_("Loaded puppet/type/%{name} but no class was created") % { name: name }) unless @types.include? name
elsif !Puppet[:always_retry_plugins]
# PUP-5482 - Only look for a type once if plugin retry is disabled
@types[name] = nil
end
# ...and I guess that is that, eh.
return @types[name]
end
end
# Creates a loader for Puppet types.
# Defaults to an instance of {Puppet::Util::Autoload} if no other auto loader has been set.
# @return [Puppet::Util::Autoload] the loader to use.
# @api private
def typeloader
unless defined?(@typeloader)
@typeloader = Puppet::Util::Autoload.new(self, "puppet/type")
end
@typeloader
end
end
end
|