diff options
| author | Luke Kanies <luke@madstop.com> | 2009-12-01 16:41:38 -0800 |
|---|---|---|
| committer | James Turnbull <james@lovedthanlost.net> | 2009-12-09 02:13:03 +1100 |
| commit | 8971d8beae2c409f9052f27c3f80ad3bdfff4de2 (patch) | |
| tree | c6f7eda0523c31c2b2f3a02b3761bf43ef716ebf /lib/puppet/parser/ast | |
| parent | 39d4a935d47f1d42241ce492c48818dc5b533c29 (diff) | |
| download | puppet-8971d8beae2c409f9052f27c3f80ad3bdfff4de2.tar.gz puppet-8971d8beae2c409f9052f27c3f80ad3bdfff4de2.tar.xz puppet-8971d8beae2c409f9052f27c3f80ad3bdfff4de2.zip | |
Fixing #2596 - Node, Class, Definition are not AST
This commit extracts these three classes into a single
ResourceType class in the Parser heirarchy, now completely
independent of the AST heirarchy.
Most of the other changes are just changing the interface
to the new class, which is greatly simplified over the previous
classes.
This opens up the possibility of drastically simplifying a lot
of this other code, too -- in particular, replacing the reference
to the parser with a reference to the (soon to be renamed)
LoadedCode class.
Signed-off-by: Luke Kanies <luke@madstop.com>
Diffstat (limited to 'lib/puppet/parser/ast')
| -rw-r--r-- | lib/puppet/parser/ast/definition.rb | 207 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 95 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/leaf.rb | 24 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/node.rb | 42 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/resource_reference.rb | 4 |
5 files changed, 3 insertions, 369 deletions
diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb deleted file mode 100644 index 00b0416a0..000000000 --- a/lib/puppet/parser/ast/definition.rb +++ /dev/null @@ -1,207 +0,0 @@ -require 'puppet/parser/ast/branch' - -require 'puppet/util/warnings' - -# The AST class for defined types, which is also the base class -# nodes and classes. -class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch - include Puppet::Util::Warnings - class << self - attr_accessor :name - end - - associates_doc - - # The class name - @name = :definition - - attr_accessor :classname, :arguments, :code, :scope, :keyword - attr_accessor :exported, :namespace, :parser, :virtual, :name - - attr_reader :parentclass - - def child_of?(klass) - false - end - - def get_classname(scope) - self.classname - end - - # Create a resource that knows how to evaluate our actual code. - def evaluate(scope) - resource = Puppet::Parser::Resource.new(:type => self.class.name, :title => get_classname(scope), :scope => scope, :source => scope.source) - - scope.catalog.tag(*resource.tags) - - scope.compiler.add_resource(scope, resource) - - return resource - end - - # Now evaluate the code associated with this class or definition. - def evaluate_code(resource) - # Create a new scope. - scope = subscope(resource.scope, resource) - - set_resource_parameters(scope, resource) - - if self.code - return self.code.safeevaluate(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 resources" % arg - else - raise Puppet::ParseError, "%s is a metaparameter; please choose another parameter name in the %s definition" % [arg, self.classname] - end - end - end - - def find_parentclass - @parser.find_hostclass(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 - return nil unless @parentclass - - # Cache our result, since it should never change. - unless defined?(@parentobj) - unless tmp = find_parentclass - parsefail "Could not find %s parent %s" % [self.class.name, @parentclass] - end - - if tmp == self - parsefail "Parent classes must have dissimilar names" - end - - @parentobj = tmp - end - @parentobj - end - - # Create a new subscope in which to evaluate our code. - def subscope(scope, resource) - args = { - :resource => resource, - :keyword => self.keyword, - :namespace => self.namespace, - :source => self - } - - oldscope = scope - 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 - - private - - # Set any arguments passed by the resource as variables in the scope. - def set_resource_parameters(scope, resource) - args = symbolize_options(resource.to_hash || {}) - - # Verify that all required arguments are either present or - # have been provided with defaults. - if self.arguments - self.arguments.each { |arg, default| - arg = arg.to_sym - unless args.include?(arg) - if defined? default and ! default.nil? - default = default.safeevaluate 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, resource.title, @classname] - end - end - } - end - - # Set each of the provided arguments as variables in the - # definition'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 - } - - scope.setvar("title", resource.title) unless args.include? :title - scope.setvar("name", resource.name) unless args.include? :name - end -end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb deleted file mode 100644 index 23d9a00e5..000000000 --- a/lib/puppet/parser/ast/hostclass.rb +++ /dev/null @@ -1,95 +0,0 @@ -require 'puppet/parser/ast/definition' - -# The code associated with a class. This is different from definitions -# in that each class is a singleton -- only one will exist for a given -# node. -class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition - - associates_doc - - @name = :class - - # 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 self.parentclass - - if klass == self.parentobj - return true - else - return self.parentobj.child_of?(klass) - end - end - - # Make sure our parent class has been evaluated, if we have one. - def evaluate(scope) - if parentclass and ! scope.catalog.resource(self.class.name, parentclass) - parent_resource = parentobj.evaluate(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(self.class.name, self.classname) - return resource - end - - super - end - - # Evaluate the code associated with this class. - def evaluate_code(resource) - scope = resource.scope - # Verify that we haven't already been evaluated. This is - # what provides the singleton aspect. - if existing_scope = scope.compiler.class_scope(self) - Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname) - return nil - end - - pnames = nil - if pklass = self.parentobj - parent_resource = resource.scope.compiler.catalog.resource(self.class.name, pklass.classname) - # This shouldn't evaluate if the class has already been evaluated. - pklass.evaluate_code(parent_resource) - - scope = parent_scope(scope, pklass) - pnames = scope.namespaces - end - - # Don't create a subscope for the top-level class, since it already - # has its own scope. - unless resource.title == :main - scope = subscope(scope, resource) - - scope.setvar("title", resource.title) - scope.setvar("name", resource.name) - end - - # Add the parent scope namespaces to our own. - if pnames - pnames.each do |ns| - scope.add_namespace(ns) - end - end - - # Set the class before we evaluate the code, so that it's set during - # the evaluation and can be inspected. - scope.compiler.class_set(self.classname, scope) - - # Now evaluate our code, yo. - if self.code - return self.code.safeevaluate(scope) - else - return nil - end - end - - def parent_scope(scope, klass) - if s = scope.compiler.class_scope(klass) - return s - else - raise Puppet::DevError, "Could not find scope for %s" % klass.classname - end - end -end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index b73c781e1..07bba1b4c 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -94,6 +94,7 @@ class Puppet::Parser::AST def initialize(hash) super + # Note that this is an AST::Regex, not a Regexp @value = @value.to_s.downcase unless @value.is_a?(Regex) if @value =~ /[^-\w.]/ raise Puppet::DevError, @@ -101,10 +102,6 @@ class Puppet::Parser::AST end end - def to_classname - to_s.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'') - end - # implementing eql? and hash so that when an HostName is stored # in a hash it has the same hashing properties as the underlying value def eql?(value) @@ -116,25 +113,6 @@ class Puppet::Parser::AST return @value.hash end - def match(value) - return @value.match(value) unless value.is_a?(HostName) - - if value.regex? and self.regex? - # Wow this is some sweet design; maybe a touch of refactoring - # in order here. - return value.value.value == self.value.value - elsif value.regex? # we know if the existing name is not a regex, it won't match a regex - return false - else - # else, we could be either a regex or normal and it doesn't matter - return @value.match(value.value) - end - end - - def regex? - @value.is_a?(Regex) - end - def to_s @value.to_s end diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb deleted file mode 100644 index 4f75201eb..000000000 --- a/lib/puppet/parser/ast/node.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'puppet/parser/ast/hostclass' - -# The specific code associated with a host. Nodes are annoyingly unlike -# other objects. That's just the way it is, at least for now. -class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass - - associates_doc - - @name = :node - - def initialize(options) - @parentclass = nil - super - end - - def namespace - "" - end - - # in Regex mode, our classname can't be our Regex. - # so we use the currently connected client as our - # classname, mimicing exactly what would have happened - # if there was a specific node definition for this node. - def get_classname(scope) - return scope.host if name.regex? - classname - end - - # Make sure node scopes are marked as such. - def subscope(*args) - scope = super - scope.nodescope = true - scope - end - - private - - # Search for the object matching our parent class. - def find_parentclass - @parser.node(parentclass) - end -end diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb index 117bc88af..794e505b8 100644 --- a/lib/puppet/parser/ast/resource_reference.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -44,7 +44,7 @@ class Puppet::Parser::AST def qualified_class(scope, title) # Look up the full path to the class if classobj = scope.find_hostclass(title) - title = classobj.classname + title = classobj.name else raise Puppet::ParseError, "Could not find class %s" % title end @@ -57,7 +57,7 @@ class Puppet::Parser::AST objtype = @type.downcase unless builtintype?(objtype) if dtype = scope.find_definition(objtype) - objtype = dtype.classname + objtype = dtype.name else raise Puppet::ParseError, "Could not find resource type %s" % objtype end |
