diff options
Diffstat (limited to 'lib/puppet/parser/scope.rb')
-rw-r--r-- | lib/puppet/parser/scope.rb | 287 |
1 files changed, 168 insertions, 119 deletions
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 394c46033..0fb3510b0 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -179,7 +179,7 @@ module Puppet::Parser # Yield each child scope in turn def each - @children.reject { |child| + @children.each { |child| yield child } end @@ -189,11 +189,9 @@ module Puppet::Parser return unless classes classes.each do |klass| if code = lookuptype(klass) - code.safeevaluate( - :scope => self, - :facts => {}, - :type => klass - ) + # Just reuse the 'include' function, since that's the equivalent + # of what we're doing here. + function_include(klass) end end end @@ -201,7 +199,6 @@ module Puppet::Parser # Evaluate a specific node's code. This method will normally be called # on the top-level scope, but it actually evaluates the node at the # appropriate scope. - #def evalnode(names, facts, classes = nil, parent = nil) def evalnode(hash) objects = hash[:ast] names = hash[:names] or @@ -240,17 +237,19 @@ module Puppet::Parser scope.evalclasses(classes) end - # Evaluate normally, with no node definitions. This is a bit of a - # silly method, in that it just calls evaluate on the passed-in - # objects, and then calls to_trans on itself. It just conceals - # a paltry amount of info from whomever's using the scope object. + # The top-level evaluate, used to evaluate a whole AST tree. This is + # a strange method, in that it turns around and calls evaluate() on its + # :ast argument. def evaluate(hash) objects = hash[:ast] facts = hash[:facts] || {} + @@done = [] + unless objects raise Puppet::DevError, "Evaluation requires an AST tree" end + # Set all of our facts in the top-level scope. facts.each { |var, value| self.setvar(var, value) @@ -258,9 +257,10 @@ module Puppet::Parser # Evaluate all of our configuration. This does not evaluate any # node definitions. - objects.safeevaluate(:scope => self) + result = objects.safeevaluate(:scope => self) - # If they've provided a name or a parent, we assume they're looking for nodes. + # If they've provided a name or a parent, we assume they're looking + # for nodes. if hash.include? :parentnode # Specifying a parent node takes precedence, because it is assumed # that this node was found in a remote repository like ldap. @@ -277,15 +277,14 @@ module Puppet::Parser # a cfengine module end - objects = self.to_trans - objects.top = true + bucket = self.to_trans # Add our class list unless self.classlist.empty? - objects.classes = self.classlist + bucket.classes = self.classlist end - return objects + return bucket end # Pull in all of the appropriate classes and evaluate them. It'd @@ -306,8 +305,8 @@ module Puppet::Parser #Puppet.notice "hash is %s" % # hash.inspect - Puppet.notice "Classes are %s, parent is %s" % - [classes.inspect, parent.inspect] + #Puppet.notice "Classes are %s, parent is %s" % + # [classes.inspect, parent.inspect] if parent arghash[:parentclass] = parent @@ -325,52 +324,6 @@ module Puppet::Parser scope.evalclasses(classes) end - # Take all of our objects and evaluate them. -# def finish -# self.info "finishing" -# @objectlist.each { |object| -# if object.is_a? ScopeObj -# self.info "finishing %s" % object.name -# if obj = finishobject(object) -# @children << obj -# end -# end -# } -# -# @finished = true -# -# self.info "finished" -# end -# -# # If the object is defined in an upper scope, then add our -# # params to that upper scope; else, create a transobject -# # or evaluate the definition. -# def finishobject(object) -# type = object.type -# name = object.name -# -# # It should be a defined type. -# definedtype = lookuptype(type) -# -# unless definedtype -# error = Puppet::ParseError.new("No such type %s" % type) -# error.line = object.line -# error.file = object.file -# raise error -# end -# -# return definedtype.safeevaluate( -# :scope => self, -# :arguments => object, -# :type => type, -# :name => name -# ) -# end -# -# def finished? -# @finished -# end - # Initialize our new scope. Defaults to having no parent and to # being declarative. def initialize(hash = {}) @@ -395,7 +348,10 @@ module Puppet::Parser end self.istop(hash[:declarative]) else + # This is here, rather than in newchild(), so that all + # of the later variable initialization works. @parent.child = self + @level = @parent.level + 1 @interp = @parent.interp @topscope = @parent.topscope @@ -425,9 +381,6 @@ module Puppet::Parser typehash[typekey] = Hash.new(nil) } - # The list of simpler hash objects. - @objectlist = [] - # This is just for collecting statements locally, so we can # verify that there is no overlap within this specific scope @localobjectable = Hash.new { |typehash,typekey| @@ -591,25 +544,14 @@ module Puppet::Parser obj = nil - # If it's a builtin type, then use a transobject, else use - # a ScopeObj, which will get replaced later. - if self.builtintype?(hash[:type]) - obj = Puppet::TransObject.new(hash[:name], hash[:type]) + obj = Puppet::TransObject.new(hash[:name], hash[:type]) - @children << obj - else - obj = ScopeObj.new(nil) - obj.name = hash[:name] - obj.type = hash[:type] - end + @children << obj @objectable[hash[:type]][hash[:name]] = obj @definedtable[hash[:type]][hash[:name]] = obj - # Keep them in order, just for kicks - @objectlist << obj - return obj end @@ -737,48 +679,43 @@ module Puppet::Parser } end - if objecttype = lookuptype(type) - # It's a defined type - objecttype.safeevaluate( - :name => name, - :type => type, - :arguments => params, - :scope => self - ) - else - # First look for it in a parent scope - obj = lookupobject(:name => name, :type => type) - - unless obj and obj != :undefined - unless obj = @objectable[type][name] - obj = self.newobject( - :type => type, - :name => name, - :line => line, - :file => file - ) + # First look for it in a parent scope + obj = lookupobject(:name => name, :type => type) - # only set these if we've created the object, - # which is the most common case - # FIXME we eventually need to store the file - # and line with each param, not the object - # itself. - obj.file = file - obj.line = line - end - end + unless obj and obj != :undefined + unless obj = @objectable[type][name] + obj = self.newobject( + :type => type, + :name => name, + :line => line, + :file => file + ) - # Now add our parameters. This has the function of overriding - # existing values, which might have been defined in a higher - # scope. - params.each { |var,value| - # Add it to our found object - obj[var] = value - } + # only set these if we've created the object, + # which is the most common case + # FIXME we eventually need to store the file + # and line with each param, not the object + # itself. + obj.file = file + obj.line = line + end end - @localobjectable[type][name] ||= {} + # Now add our parameters. This has the function of overriding + # existing values, which might have been defined in a higher + # scope. + params.each { |var,value| + # Add it to our found object + obj[var] = value + } + # This is only used for override verification -- the local object + # table does not have transobjects or whatever in it, it just has + # simple hashes. This is necessary because setobject can modify + # our object table or a parent class's object table, and we + # still need to make sure param settings cannot be duplicated + # within our scope. + @localobjectable[type][name] ||= {} params.each { |var,value| # And add it to the local table; mmm, hack @localobjectable[type][name][var] = value @@ -867,9 +804,121 @@ module Puppet::Parser end end - # Convert our scope to a list of Transportable objects. + # Convert our scope to a TransBucket. Everything in our @localobjecttable + # gets converted to either an evaluated definition, or a TransObject def to_trans + results = [] + + @children.dup.each do |child| + + if @@done.include?(child) + raise Puppet::DevError, "Already translated %s" % child.object_id + else + info "Translating %s" % child.object_id + @@done << child + end + #warning "Working on %s of type %s with id %s" % + # [child.type, child.class, child.object_id] + + # If it's a scope, then it can only be a subclass's scope, so + # convert it to a transbucket and store it in our results list + result = nil + case child + when Scope + #raise Puppet::DevError, "got a child scope" + result = child.to_trans + when Puppet::TransObject + # These objects can map to defined types or builtin types. + # Builtin types should be passed out as they are, but defined + # types need to be evaluated. We have to wait until this + # point so that subclass overrides can happen. + # Wait until the last minute to set tags, although this + # probably should not matter + child.tags = self.tags + + # Add any defaults. + self.adddefaults(child) + + # Then make sure this child's tags are stored in the + # central table. This should maybe be in the evaluate + # methods, but, eh. + @topscope.addtags(child) + + # Now that all that is done, check to see what kind of object + # it is. + if objecttype = lookuptype(child.type) + # It's a defined type, so evaluate it + result = objecttype.safeevaluate( + :name => child.name, + :type => child.type, + :arguments => child.to_hash, + :scope => self + ) + else + # It's a builtin type, so just chunk it on in + result = child + end + else + raise Puppet::DevError, + "Puppet::Parse::Scope cannot handle objects of type %s" % + child.class + end + + # Skip empty builtin types or defined types + if result and ! result.empty? + results << result + end + end + # Get rid of any nil objects. + results.reject! { |child| + child.nil? + } + + # If we have a name and type, then make a TransBucket, which + # becomes a component. + # Else, just stack all of the objects into the current bucket. + if @type + bucket = Puppet::TransBucket.new + + if defined? @name and @name + bucket.name = @name + end + # it'd be nice not to have to do this... + results.each { |result| + #Puppet.warning "Result type is %s" % result.class + bucket.push(result) + } + bucket.type = @type + + if defined? @keyword + bucket.keyword = @keyword + end + #Puppet.debug( + # "TransBucket with name %s and type %s in scope %s" % + # [@name,@type,self.object_id] + #) + + # now find metaparams + @symtable.each { |var,value| + if Puppet::Type.metaparam?(var.intern) + #Puppet.debug("Adding metaparam %s" % var) + bucket.param(var,value) + else + #Puppet.debug("%s is not a metaparam" % var) + end + } + #Puppet.debug "Returning bucket %s from scope %s" % + # [bucket.name,self.object_id] + return bucket + else + Puppet.debug "typeless scope; just returning a list" + return results + end + end + + # Convert our scope to a list of Transportable objects. + def oldto_trans results = [] # Iterate across our child scopes and call to_trans on them |