From d0389f4d16efbeccf47d6cd2f1b0854ccb1c88d5 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 7 Jan 2010 17:23:31 -0800 Subject: Renaming Parser::ResourceType to Resource::Type Basically, these classes (ResourceType and ResourceTypeCollection) don't really belong in Parser, so I'm moving them to the Resource namespace. This will be where anything RAL-related goes from now on, and as we migrate functionality out of Puppet::Type, it should go here. Signed-off-by: Luke Kanies --- lib/puppet/application/main.rb | 2 +- lib/puppet/application/server.rb | 2 +- lib/puppet/node/environment.rb | 2 +- lib/puppet/parser.rb | 2 +- lib/puppet/parser/compiler.rb | 6 +- lib/puppet/parser/parser_support.rb | 14 +- lib/puppet/parser/resource/reference.rb | 4 +- lib/puppet/parser/resource_type.rb | 237 --------------------- lib/puppet/parser/resource_type_collection.rb | 182 ---------------- .../parser/resource_type_collection_helper.rb | 7 - lib/puppet/parser/scope.rb | 4 +- lib/puppet/resource/type.rb | 237 +++++++++++++++++++++ lib/puppet/resource/type_collection.rb | 182 ++++++++++++++++ lib/puppet/resource/type_collection_helper.rb | 7 + 14 files changed, 444 insertions(+), 444 deletions(-) delete mode 100644 lib/puppet/parser/resource_type.rb delete mode 100644 lib/puppet/parser/resource_type_collection.rb delete mode 100644 lib/puppet/parser/resource_type_collection_helper.rb create mode 100644 lib/puppet/resource/type.rb create mode 100644 lib/puppet/resource/type_collection.rb create mode 100644 lib/puppet/resource/type_collection_helper.rb (limited to 'lib/puppet') diff --git a/lib/puppet/application/main.rb b/lib/puppet/application/main.rb index 3813df612..2952ef4ae 100644 --- a/lib/puppet/application/main.rb +++ b/lib/puppet/application/main.rb @@ -72,7 +72,7 @@ Puppet::Application.new(:main) do Puppet[:manifest] = ARGV.shift end begin - Puppet::Parser::ResourceTypeCollection.new(Puppet[:environment]).perform_initial_import + Puppet::Resource::TypeCollection.new(Puppet[:environment]).perform_initial_import rescue => detail Puppet.err detail exit 1 diff --git a/lib/puppet/application/server.rb b/lib/puppet/application/server.rb index e9253c6f9..afdad54fb 100644 --- a/lib/puppet/application/server.rb +++ b/lib/puppet/application/server.rb @@ -69,7 +69,7 @@ Puppet::Application.new(:server) do command(:parseonly) do begin - Puppet::Parser::ResourceTypeCollection.new(Puppet[:environment]).perform_initial_import + Puppet::Resource::TypeCollection.new(Puppet[:environment]).perform_initial_import rescue => detail Puppet.err detail exit 1 diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index a6e33703b..537a5dd26 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -44,7 +44,7 @@ class Puppet::Node::Environment def known_resource_types if @known_resource_types.nil? or @known_resource_types.stale? - @known_resource_types = Puppet::Parser::ResourceTypeCollection.new(self) + @known_resource_types = Puppet::Resource::TypeCollection.new(self) @known_resource_types.perform_initial_import end @known_resource_types diff --git a/lib/puppet/parser.rb b/lib/puppet/parser.rb index 3eda73885..4d274b43c 100644 --- a/lib/puppet/parser.rb +++ b/lib/puppet/parser.rb @@ -1,4 +1,4 @@ require 'puppet/parser/parser' require 'puppet/parser/compiler' -require 'puppet/parser/resource_type_collection' +require 'puppet/resource/type_collection' diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index 25b064195..c669076bb 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -5,14 +5,14 @@ require 'puppet/node' require 'puppet/resource/catalog' require 'puppet/util/errors' -require 'puppet/parser/resource_type_collection_helper' +require 'puppet/resource/type_collection_helper' # Maintain a graph of scopes, along with a bunch of data # about the individual catalog we're compiling. class Puppet::Parser::Compiler include Puppet::Util include Puppet::Util::Errors - include Puppet::Parser::ResourceTypeCollectionHelper + include Puppet::Resource::TypeCollectionHelper def self.compile(node) new(node).compile.to_resource @@ -275,7 +275,7 @@ class Puppet::Parser::Compiler # Find and evaluate our main object, if possible. def evaluate_main - @main = known_resource_types.find_hostclass("", "") || known_resource_types.add(Puppet::Parser::ResourceType.new(:hostclass, "")) + @main = known_resource_types.find_hostclass("", "") || known_resource_types.add(Puppet::Resource::Type.new(:hostclass, "")) @topscope.source = @main @main_resource = Puppet::Parser::Resource.new(:type => "class", :title => :main, :scope => @topscope, :source => @main) @topscope.resource = @main_resource diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index b21ead3af..e6bc46b86 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -3,14 +3,14 @@ class Puppet::Parser::Parser require 'puppet/parser/functions' require 'puppet/parser/files' - require 'puppet/parser/resource_type_collection' - require 'puppet/parser/resource_type_collection_helper' - require 'puppet/parser/resource_type' + require 'puppet/resource/type_collection' + require 'puppet/resource/type_collection_helper' + require 'puppet/resource/type' require 'monitor' AST = Puppet::Parser::AST - include Puppet::Parser::ResourceTypeCollectionHelper + include Puppet::Resource::TypeCollectionHelper attr_reader :version, :environment attr_accessor :files @@ -278,12 +278,12 @@ class Puppet::Parser::Parser # Create a new class, or merge with an existing class. def newclass(name, options = {}) - known_resource_types.add Puppet::Parser::ResourceType.new(:hostclass, name, ast_context(true).merge(options)) + known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options)) end # Create a new definition. def newdefine(name, options = {}) - known_resource_types.add Puppet::Parser::ResourceType.new(:definition, name, ast_context(true).merge(options)) + known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options)) end # Create a new node. Nodes are special, because they're stored in a global @@ -292,7 +292,7 @@ class Puppet::Parser::Parser names = [names] unless names.instance_of?(Array) context = ast_context(true) names.collect do |name| - known_resource_types.add(Puppet::Parser::ResourceType.new(:node, name, context.merge(options))) + known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options))) end end diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb index bb50efdce..ac1c79aef 100644 --- a/lib/puppet/parser/resource/reference.rb +++ b/lib/puppet/parser/resource/reference.rb @@ -3,7 +3,7 @@ require 'puppet/resource/reference' require 'puppet/file_collection/lookup' require 'puppet/parser/yaml_trimmer' -require 'puppet/parser/resource_type_collection_helper' +require 'puppet/resource/type_collection_helper' # A reference to a resource. Mostly just the type and title. class Puppet::Parser::Resource::Reference < Puppet::Resource::Reference @@ -11,7 +11,7 @@ class Puppet::Parser::Resource::Reference < Puppet::Resource::Reference include Puppet::FileCollection::Lookup include Puppet::Util::MethodHelper include Puppet::Util::Errors - include Puppet::Parser::ResourceTypeCollectionHelper + include Puppet::Resource::TypeCollectionHelper attr_accessor :builtin, :file, :line, :scope diff --git a/lib/puppet/parser/resource_type.rb b/lib/puppet/parser/resource_type.rb deleted file mode 100644 index c0d7f69ed..000000000 --- a/lib/puppet/parser/resource_type.rb +++ /dev/null @@ -1,237 +0,0 @@ -require 'puppet/parser/parser' -require 'puppet/util/warnings' -require 'puppet/util/errors' -require 'puppet/util/inline_docs' -require 'puppet/parser/ast/leaf' - -class Puppet::Parser::ResourceType - include Puppet::Util::InlineDocs - include Puppet::Util::Warnings - include Puppet::Util::Errors - - RESOURCE_SUPERTYPES = [:hostclass, :node, :definition] - - attr_accessor :file, :line, :doc, :code, :parent, :code_collection - attr_reader :type, :namespace, :arguments, :behaves_like - - # Are we a child of the passed class? Do a recursive search up our - # parentage tree to figure it out. - def child_of?(klass) - return false unless parent - - return true if klass == parent_type - return parent_type.child_of?(klass) - end - - # Now evaluate the code associated with this class or definition. - def evaluate_code(resource) - # Create a new scope. - scope = subscope(resource.scope, resource) - scope.compiler.class_set(name, scope) - - set_resource_parameters(resource, scope) - - return nil unless c = self.code - return c.safeevaluate(scope) - end - - def initialize(type, name, options = {}) - @type = type.to_s.downcase.to_sym - raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_SUPERTYPES.include?(@type) - - name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName) - - set_name_and_namespace(name) - - [:code, :doc, :line, :file, :parent].each do |param| - next unless value = options[param] - send(param.to_s + "=", value) - end - - set_arguments(options[:arguments]) - end - - # This is only used for node names, and really only when the node name - # is a regexp. - def match(string) - return string.to_s.downcase == name unless name_is_regex? - - return @name =~ string - end - - # Add code from a new instance to our code. - def merge(other) - fail ArgumentError, "#{name} is not a class; cannot add code to it" unless type == :hostclass - fail ArgumentError, "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass - - if parent and other.parent and parent != other.parent - fail ArgumentError, "Cannot merge classes with different parent classes" - end - - # We know they're either equal or only one is set, so keep whichever parent is specified. - self.parent ||= other.parent - - if other.doc - self.doc ||= "" - self.doc += other.doc - end - - # This might just be an empty, stub class. - return unless other.code - - unless self.code - self.code = other.code - return - end - - array_class = Puppet::Parser::AST::ASTArray - unless self.code.is_a?(array_class) - self.code = array_class.new(:children => [self.code]) - end - - if other.code.is_a?(array_class) - code.children += other.code.children - else - code.children << other.code - end - end - - # Make an instance of our resource type. This is only possible - # for those classes and nodes that don't have any arguments, and is - # only useful for things like the 'include' function. - def mk_plain_resource(scope) - type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" - resource_type = type == :hostclass ? :class : :node - - # Make sure our parent class has been evaluated, if we have one. - if parent and ! scope.catalog.resource(resource_type, parent) - parent_type.mk_plain_resource(scope) - end - - # Do nothing if the resource already exists; this makes sure we don't - # get multiple copies of the class resource, which helps provide the - # singleton nature of classes. - if resource = scope.catalog.resource(resource_type, name) - return resource - end - - resource = Puppet::Parser::Resource.new(:type => resource_type, :title => name, :scope => scope, :source => self) - scope.compiler.add_resource(scope, resource) - scope.catalog.tag(*resource.tags) - resource - end - - def name - return @name unless @name.is_a?(Regexp) - return @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'') - end - - def name_is_regex? - @name.is_a?(Regexp) - end - - def parent_type - return nil unless parent - - unless @parent_type ||= code_collection.send(type, parent) - fail Puppet::ParseError, "Could not find parent resource type '#{parent}'" - end - - @parent_type - end - - # Set any arguments passed by the resource as variables in the scope. - def set_resource_parameters(resource, scope) - set = {} - resource.to_hash.each do |param, value| - param = param.to_sym - fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless validattr?(param) - - exceptwrap { scope.setvar(param.to_s, value) } - - set[param] = true - end - - # Verify that all required arguments are either present or - # have been provided with defaults. - arguments.each do |param, default| - param = param.to_sym - next if set.include?(param) - - # Even if 'default' is a false value, it's an AST value, so this works fine - fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default - - scope.setvar(param.to_s, default.safeevaluate(scope)) - end - - scope.setvar("title", resource.title) unless set.include? :title - scope.setvar("name", resource.name) unless set.include? :name - scope.class_set(self.name,scope) - end - - # Create a new subscope in which to evaluate our code. - def subscope(scope, resource) - scope.newscope :resource => resource, :namespace => self.namespace, :source => self - end - - # Check whether a given argument is valid. - def validattr?(param) - param = param.to_s - - return true if param == "name" - return true if Puppet::Type.metaparam?(param) - return false unless defined?(@arguments) - return true if arguments.include?(param) - return false - end - - def set_arguments(arguments) - @arguments = {} - return if arguments.nil? - - arguments.each do |arg, default| - arg = arg.to_s - warn_if_metaparam(arg, default) - @arguments[arg] = default - end - end - - private - - def convert_from_ast(name) - value = name.value - if value.is_a?(Puppet::Parser::AST::Regex) - name = value.value - else - name = value - end - end - - # Split an fq name into a namespace and name - def namesplit(fullname) - ary = fullname.split("::") - n = ary.pop || "" - ns = ary.join("::") - return ns, n - end - - def set_name_and_namespace(name) - if name.is_a?(Regexp) - @name = name - @namespace = "" - else - @name = name.to_s.downcase - @namespace, ignored_shortname = namesplit(@name) - end - end - - def warn_if_metaparam(param, default) - return unless Puppet::Type.metaparamclass(param) - - if default - warnonce "#{param} is a metaparam; this value will inherit to all contained resources" - else - raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition" - end - end -end diff --git a/lib/puppet/parser/resource_type_collection.rb b/lib/puppet/parser/resource_type_collection.rb deleted file mode 100644 index cb90d9bb9..000000000 --- a/lib/puppet/parser/resource_type_collection.rb +++ /dev/null @@ -1,182 +0,0 @@ -class Puppet::Parser::ResourceTypeCollection - attr_reader :environment - - def initialize(env) - @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env - @hostclasses = {} - @definitions = {} - @nodes = {} - - # So we can keep a list and match the first-defined regex - @node_list = [] - - @watched_files = {} - end - - def <<(thing) - add(thing) - self - end - - def add(instance) - method = "add_#{instance.type}" - send(method, instance) - instance.code_collection = self - instance - end - - def add_hostclass(instance) - dupe_check(instance, @hostclasses) { |dupe| "Class #{instance.name} is already defined#{dupe.error_context}; cannot redefine" } - dupe_check(instance, @definitions) { |dupe| "Definition #{instance.name} is already defined#{dupe.error_context}; cannot be redefined as a class" } - - @hostclasses[instance.name] = instance - instance - end - - def hostclass(name) - @hostclasses[munge_name(name)] - end - - def add_node(instance) - dupe_check(instance, @nodes) { |dupe| "Node #{instance.name} is already defined#{dupe.error_context}; cannot redefine" } - - @node_list << instance - @nodes[instance.name] = instance - instance - end - - def node(name) - name = munge_name(name) - - if node = @nodes[name] - return node - end - - @node_list.each do |node| - next unless node.name_is_regex? - return node if node.match(name) - end - nil - end - - def node_exists?(name) - @nodes[munge_name(name)] - end - - def nodes? - @nodes.length > 0 - end - - def add_definition(code) - @definitions[code.name] = code - end - - def definition(name) - @definitions[munge_name(name)] - end - - def find(namespace, name, type) - if r = find_fully_qualified(name, type) - return r - end - - ary = namespace.split("::") - - while ary.length > 0 - tmp_namespace = ary.join("::") - if r = find_partially_qualified(tmp_namespace, name, type) - return r - end - - # Delete the second to last object, which reduces our namespace by one. - ary.pop - end - - send(type, name) - end - - def find_node(name) - find("", name, :node) - end - - def find_hostclass(namespace, name) - find(namespace, name, :hostclass) - end - - def find_definition(namespace, name) - find(namespace, name, :definition) - end - - [:hostclasses, :nodes, :definitions].each do |m| - define_method(m) do - instance_variable_get("@#{m}").dup - end - end - - def perform_initial_import - parser = Puppet::Parser::Parser.new(environment) - if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != "" - parser.string = code - else - file = Puppet.settings.value(:manifest, environment.to_s) - return unless File.exist?(file) - parser.file = file - end - parser.parse - rescue => detail - msg = "Could not parse for environment #{environment}: #{detail}" - error = Puppet::Error.new(msg) - error.set_backtrace(detail.backtrace) - raise error - end - - def stale? - @watched_files.values.detect { |file| file.changed? } - end - - def version - return @version if defined?(@version) - - if environment[:config_version] == "" - @version = Time.now.to_i - return @version - end - - @version = Puppet::Util.execute([environment[:config_version]]).strip - - rescue Puppet::ExecutionFailure => e - raise Puppet::ParseError, "Unable to set config_version: #{e.message}" - end - - def watch_file(file) - @watched_files[file] = Puppet::Util::LoadedFile.new(file) - end - - def watching_file?(file) - @watched_files.include?(file) - end - - private - - def find_fully_qualified(name, type) - return nil unless name =~ /^::/ - - name = name.sub(/^::/, '') - - send(type, name) - end - - def find_partially_qualified(namespace, name, type) - send(type, [namespace, name].join("::")) - end - - def munge_name(name) - name.to_s.downcase - end - - def dupe_check(instance, hash) - return unless dupe = hash[instance.name] - message = yield dupe - instance.fail Puppet::ParseError, message - end -end diff --git a/lib/puppet/parser/resource_type_collection_helper.rb b/lib/puppet/parser/resource_type_collection_helper.rb deleted file mode 100644 index 51ccdc061..000000000 --- a/lib/puppet/parser/resource_type_collection_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'puppet/parser/resource_type_collection' - -module Puppet::Parser::ResourceTypeCollectionHelper - def known_resource_types - environment.known_resource_types - end -end diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 1f7fd7188..b79b344e3 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -6,10 +6,10 @@ require 'puppet/parser/templatewrapper' require 'puppet/transportable' require 'strscan' -require 'puppet/parser/resource_type_collection_helper' +require 'puppet/resource/type_collection_helper' class Puppet::Parser::Scope - include Puppet::Parser::ResourceTypeCollectionHelper + include Puppet::Resource::TypeCollectionHelper require 'puppet/parser/resource' AST = Puppet::Parser::AST diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb new file mode 100644 index 000000000..1a18b4e97 --- /dev/null +++ b/lib/puppet/resource/type.rb @@ -0,0 +1,237 @@ +require 'puppet/parser/parser' +require 'puppet/util/warnings' +require 'puppet/util/errors' +require 'puppet/util/inline_docs' +require 'puppet/parser/ast/leaf' + +class Puppet::Resource::Type + include Puppet::Util::InlineDocs + include Puppet::Util::Warnings + include Puppet::Util::Errors + + RESOURCE_SUPERTYPES = [:hostclass, :node, :definition] + + attr_accessor :file, :line, :doc, :code, :parent, :code_collection + attr_reader :type, :namespace, :arguments, :behaves_like + + # Are we a child of the passed class? Do a recursive search up our + # parentage tree to figure it out. + def child_of?(klass) + return false unless parent + + return true if klass == parent_type + return parent_type.child_of?(klass) + end + + # Now evaluate the code associated with this class or definition. + def evaluate_code(resource) + # Create a new scope. + scope = subscope(resource.scope, resource) + scope.compiler.class_set(name, scope) + + set_resource_parameters(resource, scope) + + return nil unless c = self.code + return c.safeevaluate(scope) + end + + def initialize(type, name, options = {}) + @type = type.to_s.downcase.to_sym + raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_SUPERTYPES.include?(@type) + + name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName) + + set_name_and_namespace(name) + + [:code, :doc, :line, :file, :parent].each do |param| + next unless value = options[param] + send(param.to_s + "=", value) + end + + set_arguments(options[:arguments]) + end + + # This is only used for node names, and really only when the node name + # is a regexp. + def match(string) + return string.to_s.downcase == name unless name_is_regex? + + return @name =~ string + end + + # Add code from a new instance to our code. + def merge(other) + fail ArgumentError, "#{name} is not a class; cannot add code to it" unless type == :hostclass + fail ArgumentError, "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass + + if parent and other.parent and parent != other.parent + fail ArgumentError, "Cannot merge classes with different parent classes" + end + + # We know they're either equal or only one is set, so keep whichever parent is specified. + self.parent ||= other.parent + + if other.doc + self.doc ||= "" + self.doc += other.doc + end + + # This might just be an empty, stub class. + return unless other.code + + unless self.code + self.code = other.code + return + end + + array_class = Puppet::Parser::AST::ASTArray + unless self.code.is_a?(array_class) + self.code = array_class.new(:children => [self.code]) + end + + if other.code.is_a?(array_class) + code.children += other.code.children + else + code.children << other.code + end + end + + # Make an instance of our resource type. This is only possible + # for those classes and nodes that don't have any arguments, and is + # only useful for things like the 'include' function. + def mk_plain_resource(scope) + type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" + resource_type = type == :hostclass ? :class : :node + + # Make sure our parent class has been evaluated, if we have one. + if parent and ! scope.catalog.resource(resource_type, parent) + parent_type.mk_plain_resource(scope) + end + + # Do nothing if the resource already exists; this makes sure we don't + # get multiple copies of the class resource, which helps provide the + # singleton nature of classes. + if resource = scope.catalog.resource(resource_type, name) + return resource + end + + resource = Puppet::Parser::Resource.new(:type => resource_type, :title => name, :scope => scope, :source => self) + scope.compiler.add_resource(scope, resource) + scope.catalog.tag(*resource.tags) + resource + end + + def name + return @name unless @name.is_a?(Regexp) + return @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'') + end + + def name_is_regex? + @name.is_a?(Regexp) + end + + def parent_type + return nil unless parent + + unless @parent_type ||= code_collection.send(type, parent) + fail Puppet::ParseError, "Could not find parent resource type '#{parent}'" + end + + @parent_type + end + + # Set any arguments passed by the resource as variables in the scope. + def set_resource_parameters(resource, scope) + set = {} + resource.to_hash.each do |param, value| + param = param.to_sym + fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless validattr?(param) + + exceptwrap { scope.setvar(param.to_s, value) } + + set[param] = true + end + + # Verify that all required arguments are either present or + # have been provided with defaults. + arguments.each do |param, default| + param = param.to_sym + next if set.include?(param) + + # Even if 'default' is a false value, it's an AST value, so this works fine + fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default + + scope.setvar(param.to_s, default.safeevaluate(scope)) + end + + scope.setvar("title", resource.title) unless set.include? :title + scope.setvar("name", resource.name) unless set.include? :name + scope.class_set(self.name,scope) + end + + # Create a new subscope in which to evaluate our code. + def subscope(scope, resource) + scope.newscope :resource => resource, :namespace => self.namespace, :source => self + end + + # Check whether a given argument is valid. + def validattr?(param) + param = param.to_s + + return true if param == "name" + return true if Puppet::Type.metaparam?(param) + return false unless defined?(@arguments) + return true if arguments.include?(param) + return false + end + + def set_arguments(arguments) + @arguments = {} + return if arguments.nil? + + arguments.each do |arg, default| + arg = arg.to_s + warn_if_metaparam(arg, default) + @arguments[arg] = default + end + end + + private + + def convert_from_ast(name) + value = name.value + if value.is_a?(Puppet::Parser::AST::Regex) + name = value.value + else + name = value + end + end + + # Split an fq name into a namespace and name + def namesplit(fullname) + ary = fullname.split("::") + n = ary.pop || "" + ns = ary.join("::") + return ns, n + end + + def set_name_and_namespace(name) + if name.is_a?(Regexp) + @name = name + @namespace = "" + else + @name = name.to_s.downcase + @namespace, ignored_shortname = namesplit(@name) + end + end + + def warn_if_metaparam(param, default) + return unless Puppet::Type.metaparamclass(param) + + if default + warnonce "#{param} is a metaparam; this value will inherit to all contained resources" + else + raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition" + end + end +end diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb new file mode 100644 index 000000000..7ca95b1b8 --- /dev/null +++ b/lib/puppet/resource/type_collection.rb @@ -0,0 +1,182 @@ +class Puppet::Resource::TypeCollection + attr_reader :environment + + def initialize(env) + @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env + @hostclasses = {} + @definitions = {} + @nodes = {} + + # So we can keep a list and match the first-defined regex + @node_list = [] + + @watched_files = {} + end + + def <<(thing) + add(thing) + self + end + + def add(instance) + method = "add_#{instance.type}" + send(method, instance) + instance.code_collection = self + instance + end + + def add_hostclass(instance) + dupe_check(instance, @hostclasses) { |dupe| "Class #{instance.name} is already defined#{dupe.error_context}; cannot redefine" } + dupe_check(instance, @definitions) { |dupe| "Definition #{instance.name} is already defined#{dupe.error_context}; cannot be redefined as a class" } + + @hostclasses[instance.name] = instance + instance + end + + def hostclass(name) + @hostclasses[munge_name(name)] + end + + def add_node(instance) + dupe_check(instance, @nodes) { |dupe| "Node #{instance.name} is already defined#{dupe.error_context}; cannot redefine" } + + @node_list << instance + @nodes[instance.name] = instance + instance + end + + def node(name) + name = munge_name(name) + + if node = @nodes[name] + return node + end + + @node_list.each do |node| + next unless node.name_is_regex? + return node if node.match(name) + end + nil + end + + def node_exists?(name) + @nodes[munge_name(name)] + end + + def nodes? + @nodes.length > 0 + end + + def add_definition(code) + @definitions[code.name] = code + end + + def definition(name) + @definitions[munge_name(name)] + end + + def find(namespace, name, type) + if r = find_fully_qualified(name, type) + return r + end + + ary = namespace.split("::") + + while ary.length > 0 + tmp_namespace = ary.join("::") + if r = find_partially_qualified(tmp_namespace, name, type) + return r + end + + # Delete the second to last object, which reduces our namespace by one. + ary.pop + end + + send(type, name) + end + + def find_node(name) + find("", name, :node) + end + + def find_hostclass(namespace, name) + find(namespace, name, :hostclass) + end + + def find_definition(namespace, name) + find(namespace, name, :definition) + end + + [:hostclasses, :nodes, :definitions].each do |m| + define_method(m) do + instance_variable_get("@#{m}").dup + end + end + + def perform_initial_import + parser = Puppet::Parser::Parser.new(environment) + if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != "" + parser.string = code + else + file = Puppet.settings.value(:manifest, environment.to_s) + return unless File.exist?(file) + parser.file = file + end + parser.parse + rescue => detail + msg = "Could not parse for environment #{environment}: #{detail}" + error = Puppet::Error.new(msg) + error.set_backtrace(detail.backtrace) + raise error + end + + def stale? + @watched_files.values.detect { |file| file.changed? } + end + + def version + return @version if defined?(@version) + + if environment[:config_version] == "" + @version = Time.now.to_i + return @version + end + + @version = Puppet::Util.execute([environment[:config_version]]).strip + + rescue Puppet::ExecutionFailure => e + raise Puppet::ParseError, "Unable to set config_version: #{e.message}" + end + + def watch_file(file) + @watched_files[file] = Puppet::Util::LoadedFile.new(file) + end + + def watching_file?(file) + @watched_files.include?(file) + end + + private + + def find_fully_qualified(name, type) + return nil unless name =~ /^::/ + + name = name.sub(/^::/, '') + + send(type, name) + end + + def find_partially_qualified(namespace, name, type) + send(type, [namespace, name].join("::")) + end + + def munge_name(name) + name.to_s.downcase + end + + def dupe_check(instance, hash) + return unless dupe = hash[instance.name] + message = yield dupe + instance.fail Puppet::ParseError, message + end +end diff --git a/lib/puppet/resource/type_collection_helper.rb b/lib/puppet/resource/type_collection_helper.rb new file mode 100644 index 000000000..819cfba0b --- /dev/null +++ b/lib/puppet/resource/type_collection_helper.rb @@ -0,0 +1,7 @@ +require 'puppet/resource/type_collection' + +module Puppet::Resource::TypeCollectionHelper + def known_resource_types + environment.known_resource_types + end +end -- cgit