diff options
Diffstat (limited to 'lib/puppet/parser')
-rw-r--r-- | lib/puppet/parser/ast/definition.rb | 226 | ||||
-rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 4 | ||||
-rw-r--r-- | lib/puppet/parser/compile.rb | 16 | ||||
-rw-r--r-- | lib/puppet/parser/functions.rb | 2 | ||||
-rw-r--r-- | lib/puppet/parser/parser_support.rb | 2 |
5 files changed, 241 insertions, 9 deletions
diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb new file mode 100644 index 000000000..c44f0f903 --- /dev/null +++ b/lib/puppet/parser/ast/definition.rb @@ -0,0 +1,226 @@ +require 'puppet/parser/ast/branch' + +class Puppet::Parser::AST + # Evaluate the stored parse tree for a given component. This will + # receive the arguments passed to the component and also the type and + # name of the component. + class Definition < AST::Branch + include Puppet::Util + include Puppet::Util::Warnings + include Puppet::Util::MethodHelper + class << self + attr_accessor :name + end + + # The class name + @name = :definition + + attr_accessor :classname, :arguments, :code, :scope, :keyword + attr_accessor :exported, :namespace, :parser, :virtual + + # These are retrieved when looking up the superclass + attr_accessor :name + + attr_reader :parentclass + + def child_of?(klass) + false + end + + def evaluate_resource(hash) + origscope = hash[:scope] + title = hash[:title] + args = symbolize_options(hash[:arguments] || {}) + + name = args[:name] || title + + exported = hash[:exported] + virtual = hash[:virtual] + + pscope = origscope + scope = subscope(pscope, title) + + if virtual or origscope.virtual? + scope.virtual = true + end + + if exported or origscope.exported? + scope.exported = true + end + + # Additionally, add a tag for whatever kind of class + # we are + if @classname != "" and ! @classname.nil? + @classname.split(/::/).each { |tag| scope.tag(tag) } + end + + [name, title].each do |str| + unless str.nil? or str =~ /[^\w]/ or str == "" + scope.tag(str) + end + end + + # define all of the arguments in our local scope + if self.arguments + # Verify that all required arguments are either present or + # have been provided with defaults. + self.arguments.each { |arg, default| + arg = symbolize(arg) + unless args.include?(arg) + if defined? default and ! default.nil? + default = default.safeevaluate :scope => scope + args[arg] = default + #Puppet.debug "Got default %s for %s in %s" % + # [default.inspect, arg.inspect, @name.inspect] + else + parsefail "Must pass %s to %s of type %s" % + [arg,title,@classname] + end + end + } + end + + # Set each of the provided arguments as variables in the + # component's scope. + args.each { |arg,value| + unless validattr?(arg) + parsefail "%s does not accept attribute %s" % [@classname, arg] + end + + exceptwrap do + scope.setvar(arg.to_s,args[arg]) + end + } + + unless args.include? :title + scope.setvar("title",title) + end + + unless args.include? :name + scope.setvar("name",name) + end + + if self.code + return self.code.safeevaluate(:scope => scope) + else + return nil + end + end + + def initialize(hash = {}) + @arguments = nil + @parentclass = nil + super + + # Convert the arguments to a hash for ease of later use. + if @arguments + unless @arguments.is_a? Array + @arguments = [@arguments] + end + oldargs = @arguments + @arguments = {} + oldargs.each do |arg, val| + @arguments[arg] = val + end + else + @arguments = {} + end + + # Deal with metaparams in the argument list. + @arguments.each do |arg, defvalue| + next unless Puppet::Type.metaparamclass(arg) + if defvalue + warnonce "%s is a metaparam; this value will inherit to all contained elements" % arg + else + raise Puppet::ParseError, + "%s is a metaparameter; please choose another name" % + name + end + end + end + + def find_parentclass + @parser.findclass(namespace, parentclass) + end + + # Set our parent class, with a little check to avoid some potential + # weirdness. + def parentclass=(name) + if name == self.classname + parsefail "Parent classes must have dissimilar names" + end + + @parentclass = name + end + + # Hunt down our class object. + def parentobj + if @parentclass + # Cache our result, since it should never change. + unless defined?(@parentobj) + unless tmp = find_parentclass + parsefail "Could not find %s %s" % [self.class.name, @parentclass] + end + + if tmp == self + parsefail "Parent classes must have dissimilar names" + end + + @parentobj = tmp + end + @parentobj + else + nil + end + end + + # Create a new subscope in which to evaluate our code. + def subscope(scope, name = nil) + args = { + :type => self.classname, + :keyword => self.keyword, + :namespace => self.namespace + } + + args[:name] = name if name + scope = scope.newscope(args) + scope.source = self + + return scope + end + + def to_s + classname + end + + # Check whether a given argument is valid. Searches up through + # any parent classes that might exist. + def validattr?(param) + param = param.to_s + + if @arguments.include?(param) + # It's a valid arg for us + return true + elsif param == "name" + return true +# elsif defined? @parentclass and @parentclass +# # Else, check any existing parent +# if parent = @scope.lookuptype(@parentclass) and parent != [] +# return parent.validarg?(param) +# elsif builtin = Puppet::Type.type(@parentclass) +# return builtin.validattr?(param) +# else +# raise Puppet::Error, "Could not find parent class %s" % +# @parentclass +# end + elsif Puppet::Type.metaparam?(param) + return true + else + # Or just return false + return false + end + end + end +end + +# $Id$ diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 9b60c692f..f3b0602b1 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -1,10 +1,10 @@ -require 'puppet/parser/ast/component' +require 'puppet/parser/ast/definition' class Puppet::Parser::AST # The code associated with a class. This is different from components # in that each class is a singleton -- only one will exist for a given # node. - class HostClass < AST::Component + class HostClass < AST::Definition @name = :class # Are we a child of the passed class? Do a recursive search up our diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index 710f90273..7159947bf 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -70,7 +70,7 @@ class Puppet::Parser::Compile evaluate_ast_node() - evaluate_classes() + evaluate_node_classes() evaluate_generators() @@ -109,10 +109,16 @@ class Puppet::Parser::Compile @environment end - # Evaluate each class in turn. If there are any classes we can't find, - # just tag the configuration and move on. - def evaluate_classes(classes = nil) - classes ||= node.classes + # Evaluate all of the classes specified by the node. + def evaluate_node_classes + evaluate_classes(@node.classes, @parser.findclass("", "")) + end + + # Evaluate each specified class in turn. If there are any classes we can't + # find, just tag the configuration and move on. This method really just + # creates resource objects that point back to the classes, and then the + # resources are themselves evaluated later in the process. + def evaluate_classes(classes, source) found = [] classes.each do |name| if klass = @parser.findclass("", name) diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 895b4f083..05d694310 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -110,7 +110,7 @@ module Functions # Include the specified classes newfunction(:include, :doc => "Evaluate one or more classes.") do |vals| vals = [vals] unless vals.is_a?(Array) - klasses = compile.evaluate_classes(vals) + klasses = compile.evaluate_classes(vals, self) missing = vals.find_all do |klass| ! klasses.include?(klass) diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index 660fa8169..be1d73047 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -336,7 +336,7 @@ class Puppet::Parser::Parser args[param] = options[param] if options[param] end - @astset.definitions[name] = ast AST::Component, args + @astset.definitions[name] = ast AST::Definition, args end # Create a new node. Nodes are special, because they're stored in a global |