diff options
| author | Dominic Cleal <dcleal@redhat.com> | 2010-11-27 13:36:04 +0000 |
|---|---|---|
| committer | Dominic Cleal <dcleal@redhat.com> | 2010-11-27 13:36:04 +0000 |
| commit | afe2d014feb2210a8666c93465d11e9c9d555f8b (patch) | |
| tree | 208f5ac82b2c29610d2021821c8fca9b079e638b /lib/puppet/parser/ast | |
| parent | 143fc744a839affd328234fca26246d49d15d3d8 (diff) | |
| parent | 4b35402ba85d8842d757becec5c8a7bf4d6f6654 (diff) | |
Merge branch 'master' of github.com:domcleal/puppet into master-old
Diffstat (limited to 'lib/puppet/parser/ast')
| -rw-r--r-- | lib/puppet/parser/ast/astarray.rb | 35 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/caseopt.rb | 36 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/collection.rb | 85 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/definition.rb | 17 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/function.rb | 3 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 29 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/leaf.rb | 14 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/node.rb | 20 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/resource.rb | 92 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/resource_instance.rb | 9 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/resource_override.rb | 5 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/resource_reference.rb | 11 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/top_level_construct.rb | 4 |
13 files changed, 201 insertions, 159 deletions
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 529998e3c..7283a1f6c 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -16,25 +16,20 @@ class Puppet::Parser::AST # Evaluate our children. def evaluate(scope) - # Make a new array, so we don't have to deal with the details of - # flattening and such - items = [] - - # First clean out any AST::ASTArrays - @children.each { |child| - if child.instance_of?(AST::ASTArray) - child.each do |ac| - items << ac + result = [] + @children.each do |child| + # Skip things that respond to :instantiate (classes, nodes, + # and definitions), because they have already been + # instantiated. + if !child.respond_to?(:instantiate) + item = child.safeevaluate(scope) + if !item.nil? + # nil values are implicitly removed. + result.push(item) end - else - items << child end - } - - rets = items.flatten.collect { |child| - child.safeevaluate(scope) - } - rets.reject { |o| o.nil? } + end + result end def push(*ary) @@ -52,10 +47,4 @@ class Puppet::Parser::AST "[" + @children.collect { |c| c.to_s }.join(', ') + "]" end end - - # A simple container class, containing the parameters for an object. - # Used for abstracting the grammar declarations. Basically unnecessary - # except that I kept finding bugs because I had too many arrays that - # meant completely different things. - class ResourceInstance < ASTArray; end end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index 4e296e82f..db4c2b024 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -18,16 +18,12 @@ class Puppet::Parser::AST # Cache the @default value. return @default if defined?(@default) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - if subval.is_a?(AST::Default) - @default = true - break - end - } - else - @default = true if @value.is_a?(AST::Default) - end + @value.each { |subval| + if subval.is_a?(AST::Default) + @default = true + break + end + } @default ||= false @@ -36,23 +32,15 @@ class Puppet::Parser::AST # You can specify a list of values; return each in turn. def eachvalue(scope) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval.safeevaluate(scope) - } - else - yield @value.safeevaluate(scope) - end + @value.each { |subval| + yield subval.safeevaluate(scope) + } end def eachopt - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval - } - else - yield @value - end + @value.each { |subval| + yield subval + } end # Evaluate the actual statements; this only gets called if diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index 09d5b4eb3..ef36b7143 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -5,61 +5,44 @@ require 'puppet/parser/collector' # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::AST -class Collection < AST::Branch - attr_accessor :type, :query, :form - attr_reader :override - - associates_doc - - # We return an object that does a late-binding evaluation. - def evaluate(scope) - if self.query - str, code = self.query.safeevaluate scope - else - str = code = nil - end - - newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) - - scope.compiler.add_collection(newcoll) - - # overrides if any - # Evaluate all of the specified params. - if @override - params = @override.collect do |param| - param.safeevaluate(scope) + class Collection < AST::Branch + attr_accessor :type, :query, :form + attr_reader :override + + associates_doc + + # We return an object that does a late-binding evaluation. + def evaluate(scope) + str, code = query && query.safeevaluate(scope) + + resource_type = scope.find_resource_type(@type) + newcoll = Puppet::Parser::Collector.new(scope, resource_type.name, str, code, self.form) + + scope.compiler.add_collection(newcoll) + + # overrides if any + # Evaluate all of the specified params. + if @override + params = @override.collect { |param| param.safeevaluate(scope) } + newcoll.add_override( + :parameters => params, + :file => @file, + :line => @line, + :source => scope.source, + :scope => scope + ) end - - newcoll.add_override( - - :parameters => params, - :file => @file, - :line => @line, - :source => scope.source, - - :scope => scope - ) + newcoll end - newcoll - end - - # Handle our parameter ourselves - def override=(override) - if override.is_a?(AST::ASTArray) - @override = override - else - - @override = AST::ASTArray.new( - - :line => override.line, - :file => override.file, - - :children => [override] - ) + # Handle our parameter ourselves + def override=(override) + @override = if override.is_a?(AST::ASTArray) + override + else + AST::ASTArray.new(:line => override.line,:file => override.file,:children => [override]) + end end end - -end end diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb new file mode 100644 index 000000000..c43422f82 --- /dev/null +++ b/lib/puppet/parser/ast/definition.rb @@ -0,0 +1,17 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :context + + def initialize(name, context = {}, &ruby_code) + @name = name + @context = context + @ruby_code = ruby_code + end + + def instantiate(modname) + new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname)) + new_definition.ruby_code = @ruby_code if @ruby_code + [new_definition] + end +end diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb index 602016c75..80e6e6512 100644 --- a/lib/puppet/parser/ast/function.rb +++ b/lib/puppet/parser/ast/function.rb @@ -11,7 +11,6 @@ class Puppet::Parser::AST @settor = true def evaluate(scope) - # Make sure it's a defined function raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name) @@ -29,7 +28,7 @@ class Puppet::Parser::AST end # We don't need to evaluate the name, because it's plaintext - args = @arguments.safeevaluate(scope) + args = @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x } scope.send("function_#{@name}", args) end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb new file mode 100644 index 000000000..cab5e4a24 --- /dev/null +++ b/lib/puppet/parser/ast/hostclass.rb @@ -0,0 +1,29 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Hostclass < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :name, :context + + def initialize(name, context = {}, &ruby_code) + @context = context + @name = name + @ruby_code = ruby_code + end + + def instantiate(modname) + new_class = Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname)) + new_class.ruby_code = @ruby_code if @ruby_code + all_types = [new_class] + if code + code.each do |nested_ast_node| + if nested_ast_node.respond_to? :instantiate + all_types += nested_ast_node.instantiate(modname) + end + end + end + return all_types + end + + def code() + @context[:code] + end +end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 49cde63ca..fcdd219d7 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -42,7 +42,7 @@ class Puppet::Parser::AST # The base string class. class String < AST::Leaf def evaluate(scope) - @value + @value.dup end def to_s @@ -148,12 +148,20 @@ class Puppet::Parser::AST key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key end + def array_index_or_key(object, key) + if object.is_a?(Array) + raise Puppet::ParserError, "#{key} is not an integer, but is used as an index of an array" unless key = Puppet::Parser::Scope.number?(key) + end + key + end + def evaluate(scope) object = evaluate_container(scope) + accesskey = evaluate_key(scope) raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array) - object[evaluate_key(scope)] + object[array_index_or_key(object, accesskey)] end # Assign value to this hashkey or array index @@ -166,7 +174,7 @@ class Puppet::Parser::AST end # assign to hash or array - object[accesskey] = value + object[array_index_or_key(object, accesskey)] = value end def to_s diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb new file mode 100644 index 000000000..b69a5c4e0 --- /dev/null +++ b/lib/puppet/parser/ast/node.rb @@ -0,0 +1,20 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Node < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :names, :context + + def initialize(names, context = {}, &ruby_code) + raise ArgumentError, "names should be an array" unless names.is_a? Array + @names = names + @context = context + @ruby_code = ruby_code + end + + def instantiate(modname) + @names.collect do |name| + new_node = Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname)) + new_node.ruby_code = @ruby_code if @ruby_code + new_node + end + end +end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 1b063c984..ce3c499c5 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -3,26 +3,15 @@ require 'puppet/parser/ast/resource_reference' # Any normal puppet resource declaration. Can point to a definition or a # builtin type. class Puppet::Parser::AST -class Resource < AST::ResourceReference +class Resource < AST::Branch associates_doc - attr_accessor :title, :type, :exported, :virtual - attr_reader :parameters + attr_accessor :type, :instances, :exported, :virtual # Does not actually return an object; instead sets an object # in the current scope. def evaluate(scope) - # Evaluate all of the specified params. - paramobjects = parameters.collect { |param| - param.safeevaluate(scope) - } - - resource_titles = @title.safeevaluate(scope) - - # it's easier to always use an array, even for only one name - resource_titles = [resource_titles] unless resource_titles.is_a?(Array) - # We want virtual to be true if exported is true. We can't # just set :virtual => self.virtual in the initialization, # because sometimes the :virtual attribute is set *after* @@ -30,48 +19,49 @@ class Resource < AST::ResourceReference # is true. Argh, this was a very tough one to track down. virt = self.virtual || self.exported - # This is where our implicit iteration takes place; if someone - # passed an array as the name, then we act just like the called us - # many times. - resource_titles.flatten.collect { |resource_title| - exceptwrap :type => Puppet::ParseError do + # First level of implicit iteration: build a resource for each + # instance. This handles things like: + # file { '/foo': owner => blah; '/bar': owner => blah } + @instances.collect { |instance| - resource = Puppet::Parser::Resource.new( - type, resource_title, - :parameters => paramobjects, - :file => self.file, - :line => self.line, - :exported => self.exported, - :virtual => virt, - :source => scope.source, - :scope => scope, - - :strict => true - ) + # Evaluate all of the specified params. + paramobjects = instance.parameters.collect { |param| + param.safeevaluate(scope) + } - # And then store the resource in the compiler. - # At some point, we need to switch all of this to return - # resources instead of storing them like this. - scope.compiler.add_resource(scope, resource) - resource - end - }.reject { |resource| resource.nil? } - end + resource_titles = instance.title.safeevaluate(scope) + + # it's easier to always use an array, even for only one name + resource_titles = [resource_titles] unless resource_titles.is_a?(Array) + + fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) - # Set the parameters for our object. - def parameters=(params) - if params.is_a?(AST::ASTArray) - @parameters = params - else + # Second level of implicit iteration; build a resource for each + # title. This handles things like: + # file { ['/foo', '/bar']: owner => blah } + resource_titles.flatten.collect { |resource_title| + exceptwrap :type => Puppet::ParseError do + resource = Puppet::Parser::Resource.new( + fully_qualified_type, resource_title, + :parameters => paramobjects, + :file => self.file, + :line => self.line, + :exported => self.exported, + :virtual => virt, + :source => scope.source, + :scope => scope, + :strict => true + ) - @parameters = AST::ASTArray.new( - - :line => params.line, - :file => params.file, - - :children => [params] - ) - end + if resource.resource_type.is_a? Puppet::Resource::Type + resource.resource_type.instantiate_resource(scope, resource) + end + scope.compiler.add_resource(scope, resource) + scope.compiler.evaluate_classes([resource_title],scope,false) if fully_qualified_type == 'class' + resource + end + } + }.flatten.reject { |resource| resource.nil? } end end end diff --git a/lib/puppet/parser/ast/resource_instance.rb b/lib/puppet/parser/ast/resource_instance.rb new file mode 100644 index 000000000..ebfb17bf1 --- /dev/null +++ b/lib/puppet/parser/ast/resource_instance.rb @@ -0,0 +1,9 @@ +require 'puppet/parser/ast/branch' + +class Puppet::Parser::AST + class ResourceInstance < Branch + # A simple container for a parameter for an object. Consists of a + # title and a set of parameters. + attr_accessor :title, :parameters + end +end diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index e0be889ff..d638202ab 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -3,12 +3,11 @@ require 'puppet/parser/ast/resource' class Puppet::Parser::AST # Set a parameter on a resource specification created somewhere else in the # configuration. The object is responsible for verifying that this is allowed. - class ResourceOverride < Resource + class ResourceOverride < AST::Branch associates_doc - attr_accessor :object - attr_reader :parameters + attr_accessor :object, :parameters # Iterate across all of our children. def each diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb index 5d8334335..0f8e655bf 100644 --- a/lib/puppet/parser/ast/resource_reference.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -7,8 +7,15 @@ class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch # Evaluate our object, but just return a simple array of the type # and name. def evaluate(scope) - titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) } - return(titles.length == 1 ? titles.pop : titles) + titles = Array(title.safeevaluate(scope)) + + a_type, titles = scope.resolve_type_and_titles(type, titles) + + resources = titles.collect{ |a_title| + Puppet::Resource.new(a_type, a_title) + } + + return(resources.length == 1 ? resources.pop : resources) end def to_s diff --git a/lib/puppet/parser/ast/top_level_construct.rb b/lib/puppet/parser/ast/top_level_construct.rb new file mode 100644 index 000000000..901a939c2 --- /dev/null +++ b/lib/puppet/parser/ast/top_level_construct.rb @@ -0,0 +1,4 @@ +# The base class for AST nodes representing top level things: +# hostclasses, definitions, and nodes. +class Puppet::Parser::AST::TopLevelConstruct < Puppet::Parser::AST +end |
