summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-10-04 18:24:24 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-10-04 18:24:24 +0000
commit28cee40689440388994a4768bd301ae32c8ecc05 (patch)
treec865ab44f4c9247052cf83de16ffc8ebe8b15e54 /lib
parente0e291332bd4676962a28c7b220ae5c5e9651c0a (diff)
downloadpuppet-28cee40689440388994a4768bd301ae32c8ecc05.tar.gz
puppet-28cee40689440388994a4768bd301ae32c8ecc05.tar.xz
puppet-28cee40689440388994a4768bd301ae32c8ecc05.zip
Merging the changes from the override-refactor branch. This is a significant rewrite of the parser, but it has little affect on the rest of the code tree.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1726 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet.rb1
-rw-r--r--lib/puppet/element.rb5
-rwxr-xr-xlib/puppet/loadedfile.rb1
-rw-r--r--lib/puppet/log.rb6
-rw-r--r--lib/puppet/parser/ast.rb266
-rw-r--r--lib/puppet/parser/ast/astarray.rb44
-rw-r--r--lib/puppet/parser/ast/classdef.rb77
-rw-r--r--lib/puppet/parser/ast/collection.rb97
-rw-r--r--lib/puppet/parser/ast/collexpr.rb81
-rw-r--r--lib/puppet/parser/ast/compdef.rb98
-rw-r--r--lib/puppet/parser/ast/component.rb198
-rw-r--r--lib/puppet/parser/ast/function.rb5
-rw-r--r--lib/puppet/parser/ast/hostclass.rb166
-rw-r--r--lib/puppet/parser/ast/leaf.rb23
-rw-r--r--lib/puppet/parser/ast/node.rb113
-rw-r--r--lib/puppet/parser/ast/nodedef.rb73
-rw-r--r--lib/puppet/parser/ast/objectdef.rb353
-rw-r--r--lib/puppet/parser/ast/objectref.rb77
-rw-r--r--lib/puppet/parser/ast/resourcedef.rb215
-rw-r--r--lib/puppet/parser/ast/resourcedefaults.rb (renamed from lib/puppet/parser/ast/typedefaults.rb)24
-rw-r--r--lib/puppet/parser/ast/resourceoverride.rb62
-rw-r--r--lib/puppet/parser/ast/resourceparam.rb (renamed from lib/puppet/parser/ast/objectparam.rb)21
-rw-r--r--lib/puppet/parser/ast/resourceref.rb44
-rw-r--r--lib/puppet/parser/ast/selector.rb6
-rw-r--r--lib/puppet/parser/ast/vardef.rb14
-rw-r--r--lib/puppet/parser/collector.rb97
-rw-r--r--lib/puppet/parser/functions.rb46
-rw-r--r--lib/puppet/parser/grammar.ra485
-rw-r--r--lib/puppet/parser/interpreter.rb1059
-rw-r--r--lib/puppet/parser/lexer.rb96
-rw-r--r--lib/puppet/parser/parser.rb1571
-rw-r--r--lib/puppet/parser/resource.rb324
-rw-r--r--lib/puppet/parser/resource/param.rb44
-rw-r--r--lib/puppet/parser/resource/reference.rb68
-rw-r--r--lib/puppet/parser/scope.rb1544
-rw-r--r--lib/puppet/parser/templatewrapper.rb58
-rw-r--r--lib/puppet/rails/database.rb17
-rw-r--r--lib/puppet/rails/host.rb54
-rw-r--r--lib/puppet/rails/rails_object.rb42
-rw-r--r--lib/puppet/rails/rails_parameter.rb10
-rw-r--r--lib/puppet/rails/rails_resource.rb34
-rw-r--r--lib/puppet/transportable.rb14
-rw-r--r--lib/puppet/type.rb31
-rw-r--r--lib/puppet/util.rb2
-rw-r--r--lib/puppet/util/errors.rb55
-rw-r--r--lib/puppet/util/logging.rb20
-rw-r--r--lib/puppet/util/methodhelper.rb21
47 files changed, 3979 insertions, 3783 deletions
diff --git a/lib/puppet.rb b/lib/puppet.rb
index a802688e8..b0b3bbea9 100644
--- a/lib/puppet.rb
+++ b/lib/puppet.rb
@@ -1,5 +1,6 @@
# see the bottom of the file for further inclusions
require 'singleton'
+require 'facter'
require 'puppet/error'
require 'puppet/event-loop'
require 'puppet/util'
diff --git a/lib/puppet/element.rb b/lib/puppet/element.rb
index cc682f2e4..934fafeb9 100644
--- a/lib/puppet/element.rb
+++ b/lib/puppet/element.rb
@@ -7,6 +7,7 @@ require 'puppet'
class Puppet::Element
include Puppet
include Puppet::Util
+ include Puppet::Util::Errors
attr_writer :noop
class << self
@@ -48,10 +49,10 @@ class Puppet::Element
@path = [@parent.path, self.class.name.to_s + "=" + self.name]
end
else
- # The top-level name is always puppet[top], so we don't bother with
+ # The top-level name is always main[top], so we don't bother with
# that. And we don't add the hostname here, it gets added
# in the log server thingy.
- if self.name == "puppet[top]"
+ if self.name == "main[top]"
@path = ["/"]
else
if self.is_a?(Puppet.type(:component))
diff --git a/lib/puppet/loadedfile.rb b/lib/puppet/loadedfile.rb
index b0e408475..c14bcc195 100755
--- a/lib/puppet/loadedfile.rb
+++ b/lib/puppet/loadedfile.rb
@@ -44,6 +44,7 @@ module Puppet
"Can not use a non-existent file for parsing"
end
@statted = 0
+ @stamp = nil
@tstamp = stamp()
end
diff --git a/lib/puppet/log.rb b/lib/puppet/log.rb
index 0659042ce..c8d92e649 100644
--- a/lib/puppet/log.rb
+++ b/lib/puppet/log.rb
@@ -489,10 +489,8 @@ module Puppet
# If they pass a source in to us, we make sure it is a string, and
# we retrieve any tags we can.
def source=(source)
- # We can't store the actual source, we just store the path. This
- # is a bit of a stupid hack, specifically testing for elements, but
- # eh.
- if source.is_a?(Puppet::Element) and source.respond_to?(:path)
+ # We can't store the actual source, we just store the path.
+ if source.respond_to?(:path)
@objectsource = true
@source = source.path
else
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb
index ccde7928b..6f9c9492c 100644
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@ -3,158 +3,126 @@
require 'puppet'
require 'puppet/autoload'
-module Puppet
- module Parser
- # The base class for all of the objects that make up the parse trees.
- # Handles things like file name, line #, and also does the initialization
- # for all of the parameters of all of the child objects.
- class AST
- # Do this so I don't have to type the full path in all of the subclasses
- AST = Puppet::Parser::AST
-
- Puppet.setdefaults("ast",
- :typecheck => [true, "Whether to validate types during parsing."],
- :paramcheck => [true, "Whether to validate parameters during parsing."]
- )
- attr_accessor :line, :file, :parent, :scope
-
- # Just used for 'tree', which is only used in debugging.
- @@pink = ""
- @@green = ""
- @@yellow = ""
- @@slate = ""
- @@reset = ""
-
- # Just used for 'tree', which is only used in debugging.
- @@indent = " " * 4
- @@indline = @@pink + ("-" * 4) + @@reset
- @@midline = @@slate + ("-" * 4) + @@reset
-
- @@settypes = {}
-
- # Just used for 'tree', which is only used in debugging.
- def AST.indention
- return @@indent * @@indention
- end
-
- # Just used for 'tree', which is only used in debugging.
- def AST.midline
- return @@midline
- end
-
- # Evaluate the current object. Basically just iterates across all
- # of the contained children and evaluates them in turn, returning a
- # list of all of the collected values, rejecting nil values
- def evaluate(args)
- #Puppet.debug("Evaluating ast %s" % @name)
- value = self.collect { |obj|
- obj.safeevaluate(args)
- }.reject { |obj|
- obj.nil?
- }
- end
-
- # The version of the evaluate method that should be called, because it
- # correctly handles errors. It is critical to use this method because
- # it can enable you to catch the error where it happens, rather than
- # much higher up the stack.
- def safeevaluate(*args)
- begin
- self.evaluate(*args)
- rescue Puppet::DevError => except
- except.line ||= @line
- except.file ||= @file
- raise
- rescue Puppet::ParseError => except
- except.line ||= @line
- except.file ||= @file
- raise
- rescue => detail
- error = Puppet::DevError.new(
- "Child of type %s failed with error %s: %s" %
- [self.class, detail.class, detail.to_s]
- )
- error.line ||= @line
- error.file ||= @file
- error.set_backtrace detail.backtrace
- raise error
- end
- end
-
- # Again, just used for printing out the parse tree.
- def typewrap(string)
- #return self.class.to_s.sub(/.+::/,'') +
- #"(" + @@green + string.to_s + @@reset + ")"
- return @@green + string.to_s + @@reset +
- "(" + self.class.to_s.sub(/.+::/,'') + ")"
- end
-
- # Initialize the object. Requires a hash as the argument, and
- # takes each of the parameters of the hash and calls the settor
- # method for them. This is probably pretty inefficient and should
- # likely be changed at some point.
- def initialize(args)
- @file = nil
- @line = nil
- args.each { |param,value|
- method = param.to_s + "="
- unless self.respond_to?(method)
- error = Puppet::ParseError.new(
- "Invalid parameter %s to object class %s" %
- [param,self.class.to_s]
- )
- error.line = self.line
- error.file = self.file
- raise error
- end
-
- begin
- #Puppet.debug("sending %s to %s" % [method, self.class])
- self.send(method,value)
- rescue => detail
- error = Puppet::DevError.new(
- "Could not set parameter %s on class %s: %s" %
- [method,self.class.to_s,detail]
- )
- error.line ||= self.line
- error.file ||= self.file
- raise error
- end
- }
- end
- #---------------------------------------------------------------
- # Now autoload everything.
- # XXX We can't do this, because it causes multiple loads of some
- # things.
- #@autoloader = Puppet::Autoload.new(self,
- # "puppet/parser/ast"
- #)
- #@autoloader.loadall
+# The base class for all of the objects that make up the parse trees.
+# Handles things like file name, line #, and also does the initialization
+# for all of the parameters of all of the child objects.
+class Puppet::Parser::AST
+ # Do this so I don't have to type the full path in all of the subclasses
+ AST = Puppet::Parser::AST
+
+ include Puppet::Util::Errors
+ include Puppet::Util::MethodHelper
+
+ Puppet.setdefaults("ast",
+ :typecheck => [true, "Whether to validate types during parsing."],
+ :paramcheck => [true, "Whether to validate parameters during parsing."]
+ )
+ attr_accessor :line, :file, :parent, :scope
+
+ # Just used for 'tree', which is only used in debugging.
+ @@pink = ""
+ @@green = ""
+ @@yellow = ""
+ @@slate = ""
+ @@reset = ""
+
+ # Just used for 'tree', which is only used in debugging.
+ @@indent = " " * 4
+ @@indline = @@pink + ("-" * 4) + @@reset
+ @@midline = @@slate + ("-" * 4) + @@reset
+
+ @@settypes = {}
+
+ # Just used for 'tree', which is only used in debugging.
+ def AST.indention
+ return @@indent * @@indention
+ end
+
+ # Just used for 'tree', which is only used in debugging.
+ def AST.midline
+ return @@midline
+ end
+
+ # Evaluate the current object. Basically just iterates across all
+ # of the contained children and evaluates them in turn, returning a
+ # list of all of the collected values, rejecting nil values
+ def evaluate(args)
+ #Puppet.debug("Evaluating ast %s" % @name)
+ value = self.collect { |obj|
+ obj.safeevaluate(args)
+ }.reject { |obj|
+ obj.nil?
+ }
+ end
+
+ # Throw a parse error.
+ def parsefail(message)
+ self.fail(Puppet::ParseError, message)
+ end
+
+ # Wrap a statemp in a reusable way so we always throw a parse error.
+ def parsewrap
+ exceptwrap :type => Puppet::ParseError do
+ yield
+ end
+ end
+
+ # The version of the evaluate method that should be called, because it
+ # correctly handles errors. It is critical to use this method because
+ # it can enable you to catch the error where it happens, rather than
+ # much higher up the stack.
+ def safeevaluate(*args)
+ exceptwrap do
+ self.evaluate(*args)
end
end
+
+ # Again, just used for printing out the parse tree.
+ def typewrap(string)
+ #return self.class.to_s.sub(/.+::/,'') +
+ #"(" + @@green + string.to_s + @@reset + ")"
+ return @@green + string.to_s + @@reset +
+ "(" + self.class.to_s.sub(/.+::/,'') + ")"
+ end
+
+ # Initialize the object. Requires a hash as the argument, and
+ # takes each of the parameters of the hash and calls the settor
+ # method for them. This is probably pretty inefficient and should
+ # likely be changed at some point.
+ def initialize(args)
+ @file = nil
+ @line = nil
+ set_options(args)
+ end
+ #---------------------------------------------------------------
+ # Now autoload everything.
+ # XXX We can't do this, because it causes multiple loads of some
+ # things.
+ @autoloader = Puppet::Autoload.new(self,
+ "puppet/parser/ast"
+ )
+ @autoloader.loadall
end
-require 'puppet/parser/ast/astarray'
-require 'puppet/parser/ast/branch'
-require 'puppet/parser/ast/collection'
-require 'puppet/parser/ast/caseopt'
-require 'puppet/parser/ast/casestatement'
-require 'puppet/parser/ast/classdef'
-require 'puppet/parser/ast/compdef'
-require 'puppet/parser/ast/component'
-require 'puppet/parser/ast/else'
-require 'puppet/parser/ast/hostclass'
-require 'puppet/parser/ast/ifstatement'
-require 'puppet/parser/ast/leaf'
-require 'puppet/parser/ast/node'
-require 'puppet/parser/ast/nodedef'
-require 'puppet/parser/ast/objectdef'
-require 'puppet/parser/ast/objectparam'
-require 'puppet/parser/ast/objectref'
-require 'puppet/parser/ast/selector'
-require 'puppet/parser/ast/typedefaults'
-require 'puppet/parser/ast/vardef'
-require 'puppet/parser/ast/tag'
-require 'puppet/parser/ast/function'
+#require 'puppet/parser/ast/astarray'
+#require 'puppet/parser/ast/branch'
+#require 'puppet/parser/ast/collection'
+#require 'puppet/parser/ast/caseopt'
+#require 'puppet/parser/ast/casestatement'
+#require 'puppet/parser/ast/component'
+#require 'puppet/parser/ast/else'
+#require 'puppet/parser/ast/hostclass'
+#require 'puppet/parser/ast/ifstatement'
+#require 'puppet/parser/ast/leaf'
+#require 'puppet/parser/ast/node'
+#require 'puppet/parser/ast/resourcedef'
+#require 'puppet/parser/ast/resourceparam'
+#require 'puppet/parser/ast/resourceref'
+#require 'puppet/parser/ast/resourceoverride'
+#require 'puppet/parser/ast/selector'
+#require 'puppet/parser/ast/resourcedefaults'
+#require 'puppet/parser/ast/vardef'
+#require 'puppet/parser/ast/tag'
+#require 'puppet/parser/ast/function'
# $Id$
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb
index c42f658fd..fb0a3f671 100644
--- a/lib/puppet/parser/ast/astarray.rb
+++ b/lib/puppet/parser/ast/astarray.rb
@@ -25,14 +25,10 @@ class Puppet::Parser::AST
# This is such a stupid hack. I've no real idea how to make a
# "real" declarative language, so I hack it so it looks like
# one, yay.
- definelist = [
- AST::CompDef, AST::NodeDef, AST::ClassDef
- ]
setlist = [
- AST::VarDef, AST::TypeDefaults, AST::Function
+ AST::VarDef, AST::ResourceDefaults, AST::Function
]
- definers = []
settors = []
others = []
@@ -53,15 +49,13 @@ class Puppet::Parser::AST
# Now sort them all according to the type of action
items.each { |child|
- if definelist.include?(child.class)
- definers << child
- elsif setlist.include?(child.class)
+ if setlist.include?(child.class)
settors << child
else
others << child
end
}
- rets = [definers, settors, others].flatten.collect { |child|
+ rets = [settors, others].flatten.collect { |child|
child.safeevaluate(:scope => scope)
}
else
@@ -107,37 +101,7 @@ class Puppet::Parser::AST
# 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 ObjectInst < ASTArray; end
-
- # Another simple container class to make sure we can correctly arrayfy
- # things.
- class CompArgument < ASTArray
- @@warnings = {}
- def initialize(hash)
- super
- name = @children[0].value
-
- # If it's not a metaparamer, we're fine.
- return unless Puppet::Type.metaparamclass(name)
-
- if @children[1]
- if @children[1].value == false
- raise Puppet::ParseError,
- "%s is a metaparameter; please choose another name" %
- name
- else
- unless @@warnings[name]
- @@warnings[name] = true
- Puppet.warning "%s is a metaparam; this value will inherit to all contained elements" % name
- end
- end
- else
- raise Puppet::ParseError,
- "%s is a metaparameter; please choose another name" %
- name
- end
- end
- end
+ class ResourceInst < ASTArray; end
end
# $Id$
diff --git a/lib/puppet/parser/ast/classdef.rb b/lib/puppet/parser/ast/classdef.rb
deleted file mode 100644
index e09db985f..000000000
--- a/lib/puppet/parser/ast/classdef.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require 'puppet/parser/ast/compdef'
-
-class Puppet::Parser::AST
- # Define a new class. Syntactically similar to component definitions,
- # but classes are always singletons -- only one can exist on a given
- # host.
- class ClassDef < AST::CompDef
- @keyword = "class"
-
- def self.genclass
- AST::HostClass
- end
-
- def each
- if @parentclass
- #[@type,@args,@parentclass,@code].each { |child| yield child }
- [@type,@parentclass,@code].each { |child| yield child }
- else
- #[@type,@args,@code].each { |child| yield child }
- [@type,@code].each { |child| yield child }
- end
- end
-
- # Store our parse tree according to type.
- def disabled_evaluate(hash)
- scope = hash[:scope]
- type = @type.safeevaluate(:scope => scope)
- #args = @args.safeevaluate(:scope => scope)
-
- #:args => args,
- arghash = {
- :type => type,
- :code => @code
- }
-
- if @parentclass
- arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope)
- end
-
- #Puppet.debug("defining hostclass '%s' with arguments [%s]" %
- # [type,args])
-
- begin
- hclass = HostClass.new(arghash)
- hclass.keyword = self.keyword
- scope.settype(type, hclass)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
- end
- end
-
- def tree(indent = 0)
- #@args.tree(indent + 1),
- return [
- @type.tree(indent + 1),
- ((@@indline * 4 * indent) + self.typewrap("class")),
- @parentclass ? @parentclass.tree(indent + 1) : "",
- @code.tree(indent + 1),
- ].join("\n")
- end
-
- def to_s
- return "class %s(%s) inherits %s {\n%s }" %
- [@type, @parentclass, @code]
- #[@type, @args, @parentclass, @code]
- end
- end
-
-end
diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb
index 8e9acce57..fa480b179 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -1,91 +1,30 @@
-require 'puppet/rails'
+require 'puppet'
+require 'puppet/parser/ast/branch'
+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
- # An object that collects stored objects from the central cache and returns
- # them to the current host, yo.
- class Collection < AST::Branch
- attr_accessor :type
+class Collection < AST::Branch
+ attr_accessor :type, :query, :form
- # We cannot evaluate directly here; instead we need to store a
- # CollectType object, which will do the collection. This is
- # the only way to find certain exported types in the current
- # configuration.
- def evaluate(hash)
- scope = hash[:scope]
+ # We return an object that does a late-binding evaluation.
+ def evaluate(hash)
+ scope = hash[:scope]
- @convertedtype = @type.safeevaluate(:scope => scope)
-
- scope.newcollection(self)
+ if self.query
+ q = self.query.safeevaluate :scope => scope
+ else
+ q = nil
end
- # Now perform the actual collection, yo.
- def perform(scope)
- # First get everything from the export table.
-
- # FIXME This will only find objects that are before us in the tree,
- # which is a problem.
- objects = scope.exported(@convertedtype)
-
- # We want to return all of these objects, and then whichever objects
- # we find in the db.
- array = objects.values
-
- # Mark all of these objects as collected, so that they also get
- # returned to the client. We don't store them in our scope
- # or anything, which is a little odd, but eh.
- array.each do |obj|
- obj.collected = true
- end
-
- count = array.length
-
- # Now we also have to see if there are any exported objects
- # in our own scope.
- scope.lookupexported(@convertedtype).each do |obj|
- objects[obj.name] = obj
- obj.collected = true
- end
-
- bucket = Puppet::TransBucket.new
-
- Puppet::Rails::RailsObject.find_all_by_collectable(true).each do |obj|
- # FIXME This should check that the source of the object is the
- # host we're running on, else it's a bad conflict.
- if objects.include?(obj.name)
- scope.debug("%s[%s] is already exported" % [@convertedtype, obj.name])
- next
- end
- count += 1
- trans = obj.to_trans
- bucket.push(trans)
+ newcoll = Puppet::Parser::Collector.new(scope, @type, q, self.form)
- args = {
- :name => trans.name,
- :type => trans.type,
- }
+ scope.newcollection(newcoll)
- [:file, :line].each do |param|
- if val = trans.send(param)
- args[param] = val
- end
- end
-
- args[:arguments] = {}
- trans.each do |p,v| args[:arguments][p] = v end
-
-
- # XXX Because the scopes don't expect objects to return values,
- # we have to manually add our objects to the scope. This is
- # uber-lame.
- scope.setobject(args)
- end
-
- scope.debug("Collected %s objects of type %s" %
- [count, @convertedtype])
-
- return bucket
- end
+ newcoll
end
end
+end
# $Id$
diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb
new file mode 100644
index 000000000..f69b2e92e
--- /dev/null
+++ b/lib/puppet/parser/ast/collexpr.rb
@@ -0,0 +1,81 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+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 CollExpr < AST::Branch
+ attr_accessor :test1, :test2, :oper, :form, :type, :parens
+
+ # We return an object that does a late-binding evaluation.
+ def evaluate(hash)
+ scope = hash[:scope]
+
+ # Make sure our contained expressions have all the info they need.
+ [@test1, @test2].each do |t|
+ if t.is_a?(self.class)
+ t.form ||= self.form
+ t.type ||= self.type
+ end
+ end
+
+ # The code is only used for virtual lookups
+ str1, code1 = @test1.safeevaluate :scope => scope
+ str2, code2 = @test2.safeevaluate :scope => scope
+
+ # First build up the virtual code.
+ # If we're a conjunction operator, then we're calling code. I did
+ # some speed comparisons, and it's at least twice as fast doing these
+ # case statements as doing an eval here.
+ code = proc do |resource|
+ case @oper
+ when "and": code1.call(resource) and code2.call(resource)
+ when "or": code1.call(resource) or code2.call(resource)
+ when "==": resource[str1] == str2
+ when "!=": resource[str1] != str2
+ end
+ end
+
+ # Now build up the rails conditions code
+ if self.parens and self.form == :exported
+ Puppet.warning "Parentheses are ignored in Rails searches"
+ end
+
+ case @oper
+ when "and", "or": oper = @oper.upcase
+ when "==": oper = "="
+ else
+ oper = @oper
+ end
+
+ if oper == "=" or oper == "!="
+ # Add the rails association info where necessary
+ if str1 == "title"
+ str = "title #{oper} '#{str2}'"
+ else
+ unless self.form == :virtual or str1 == "title"
+ parsefail "Collection from the database only supports " +
+ "title matching currently"
+ end
+ str = "rails_parameters.name = '#{str1}' and " +
+ "rails_parameters.value #{oper} '#{str2}'"
+ end
+ else
+ str = [str1, oper, str2].join(" ")
+ end
+
+ return str, code
+ end
+
+ def initialize(hash = {})
+ super
+
+ unless %w{== != and or}.include?(@oper)
+ raise ArgumentError, "Invalid operator %s" % @oper
+ end
+ end
+end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/compdef.rb b/lib/puppet/parser/ast/compdef.rb
deleted file mode 100644
index 17ee60181..000000000
--- a/lib/puppet/parser/ast/compdef.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-class Puppet::Parser::AST
- # Define a new component. This basically just stores the
- # associated parse tree by name in our current scope. Note that
- # there is currently a mismatch in how we look up components -- it
- # usually uses scopes, but sometimes uses '@@settypes'.
- # FIXME This class should verify that each of its direct children
- # has an abstractable name -- i.e., if a file does not include a
- # variable in its name, then the user is essentially guaranteed to
- # encounter an error if the component is instantiated more than
- # once.
- class CompDef < AST::Branch
- attr_accessor :type, :args, :code, :scope, :parentclass
- attr_writer :keyword
-
- @keyword = "define"
-
- class << self
- attr_reader :keyword
- end
-
-
- def self.genclass
- AST::Component
- end
-
- def each
- [@type,@args,@code].each { |child| yield child }
- end
-
- # Store the parse tree.
- def evaluate(hash)
- scope = hash[:scope]
- arghash = {:code => @code}
- arghash[:type] = @type.safeevaluate(:scope => scope)
-
- if @args
- arghash[:args] = @args.safeevaluate(:scope => scope)
- end
-
- if @parentclass
- arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope)
- end
-
-
- begin
- comp = self.class.genclass.new(arghash)
- comp.keyword = self.keyword
- scope.settype(arghash[:type], comp)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
- end
- end
-
- def initialize(hash)
- @parentclass = nil
- @args = nil
- super
-
- #if @parentclass
- # Puppet.notice "Parent class of %s is %s" %
- # [@type.value, @parentclass.value]
- #end
-
- #Puppet.debug "Defining type %s" % @type.value
- end
-
- def keyword
- if defined? @keyword
- @keyword
- else
- self.class.keyword
- end
- end
-
- def tree(indent = 0)
- return [
- @type.tree(indent + 1),
- ((@@indline * 4 * indent) + self.typewrap("define")),
- @args.tree(indent + 1),
- @code.tree(indent + 1),
- ].join("\n")
- end
-
- def to_s
- return "define %s(%s) {\n%s }" % [@type, @args, @code]
- end
- end
-end
-
-# $Id$
diff --git a/lib/puppet/parser/ast/component.rb b/lib/puppet/parser/ast/component.rb
index ebbf21959..312b11d99 100644
--- a/lib/puppet/parser/ast/component.rb
+++ b/lib/puppet/parser/ast/component.rb
@@ -1,80 +1,68 @@
+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 Component < AST::Branch
+ include Puppet::Util
+ include Puppet::Util::Warnings
+ include Puppet::Util::MethodHelper
class << self
attr_accessor :name
end
# The class name
- @name = :component
+ @name = :definition
- attr_accessor :type, :args, :code, :scope, :keyword
- attr_accessor :collectable, :parentclass
+ attr_accessor :type, :arguments, :code, :scope, :keyword
+ attr_accessor :exported, :namespace, :fqname, :interp
# These are retrieved when looking up the superclass
- attr_accessor :name, :arguments
+ attr_accessor :name
def evaluate(hash)
origscope = hash[:scope]
objtype = hash[:type]
- @name = hash[:name]
- @arguments = hash[:arguments] || {}
+ name = hash[:name]
+ args = symbolize_options(hash[:arguments] || {})
- @collectable = hash[:collectable]
+ exported = hash[:exported]
pscope = origscope
- #pscope = if ! Puppet[:lexical] or hash[:asparent] == false
- # origscope
- #else
- # @scope
- #end
- scope = pscope.newscope(
- :type => @type,
- :name => @name,
- :keyword => self.keyword
- )
- newcontext = hash[:newcontext]
+ scope = subscope(pscope, name)
- if @collectable or origscope.collectable
- scope.collectable = true
+ if exported or origscope.exported?
+ scope.exported = true
end
-
- unless self.is_a? AST::HostClass and ! newcontext
- #scope.warning "Setting context to %s" % self.object_id
- scope.context = self.object_id
- end
- @scope = scope
-
+ scope = scope
# Additionally, add a tag for whatever kind of class
# we are
- scope.tag(@type)
+ if @type != ""
+ scope.tag(@type)
+ end
- unless @name.nil?
- scope.tag(@name)
+ unless name.nil? or name =~ /[^\w]/
+ scope.tag(name)
end
# define all of the arguments in our local scope
- if self.args
+ if self.arguments
# Verify that all required arguments are either present or
# have been provided with defaults.
# FIXME This should probably also require each parent
# class's arguments...
- self.args.each { |arg, default|
- unless @arguments.include?(arg)
+ self.arguments.each { |arg, default|
+ arg = symbolize(arg)
+ unless args.include?(arg)
if defined? default and ! default.nil?
- @arguments[arg] = default
+ default = default.safeevaluate :scope => scope
+ args[arg] = default
#Puppet.debug "Got default %s for %s in %s" %
# [default.inspect, arg.inspect, @name.inspect]
else
- error = Puppet::ParseError.new(
- "Must pass %s to %s of type %s" %
- [arg.inspect,@name,@type]
- )
- error.line = self.line
- error.file = self.file
- raise error
+ parsefail "Must pass %s to %s of type %s" %
+ [arg,name,@type]
end
end
}
@@ -82,54 +70,116 @@ class Puppet::Parser::AST
# Set each of the provided arguments as variables in the
# component's scope.
- @arguments.each { |arg,value|
- begin
- scope.setvar(arg,@arguments[arg])
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => except
- error = Puppet::ParseError.new(except.message)
- error.line = self.line
- error.file = self.file
- error.set_backtrace except.backtrace
- raise error
+ args.each { |arg,value|
+ unless validattr?(arg)
+ parsefail "%s does not accept attribute %s" % [@type, arg]
+ end
+
+ exceptwrap do
+ scope.setvar(arg.to_s,args[arg])
end
}
- unless @arguments.include? "name"
- scope.setvar("name",@name)
+ unless args.include? "name"
+ scope.setvar("name",name)
end
- # Now just evaluate the code with our new bindings.
- #scope.inside(self) do # part of definition inheritance
- self.code.safeevaluate(:scope => scope)
- #end
+ if self.code
+ return self.code.safeevaluate(:scope => scope)
+ else
+ return nil
+ end
+ end
+
+ def initialize(hash = {})
+ @arguments = nil
+ @parentclass = nil
+ super
+
+ # Deal with metaparams in the argument list.
+ if @arguments
+ @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
+ end
+
+ def parentclass
+ parentobj do |name|
+ @interp.findclass(namespace, name)
+ end
+ end
- # If we're being evaluated as a parent class, we want to return the
- # scope, so it can be overridden and such, but if not, we want to
- # return a TransBucket of our objects.
- if hash.include?(:asparent)
- return scope
+ # Set our parent class, with a little check to avoid some potential
+ # weirdness.
+ def parentclass=(name)
+ if name == @type
+ 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 @parentclass.is_a?(AST::HostClass)
+ unless tmp = yield(@parentclass)
+ parsefail "Could not find %s %s" % [self.class.name, @parentclass]
+ end
+
+ if tmp == self
+ parsefail "Parent classes must have dissimilar names"
+ end
+
+ @parentclass = tmp
+ end
+ @parentclass
else
- return scope.to_trans
+ nil
end
end
+ # Create a new subscope in which to evaluate our code.
+ def subscope(scope, name = nil)
+ args = {
+ :type => @type,
+ :keyword => self.keyword,
+ :namespace => self.namespace
+ }
+
+ args[:name] = name if name
+ args[:type] = self.type if self.type
+ scope = scope.newscope(args)
+ scope.source = self
+
+ return scope
+ end
+
+ def to_s
+ fqname
+ end
+
# Check whether a given argument is valid. Searches up through
# any parent classes that might exist.
- def validarg?(param)
+ def validattr?(param)
+ return true if Puppet::Type.metaparam?(param)
+
+ param = param.to_s
found = false
- unless @args.is_a? Array
- @args = [@args]
+ unless @arguments.is_a? Array
+ @arguments = [@arguments]
end
- found = @args.detect { |arg|
+ found = @arguments.detect { |arg|
if arg.is_a? Array
arg[0] == param
else
diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb
index 2c63c8b76..f67531ae3 100644
--- a/lib/puppet/parser/ast/function.rb
+++ b/lib/puppet/parser/ast/function.rb
@@ -11,7 +11,10 @@ class Puppet::Parser::AST
args = @arguments.safeevaluate(:scope => scope)
- return scope.send("function_" + @name, args)
+ #exceptwrap :message => "Failed to execute %s" % @name,
+ # :type => Puppet::ParseError do
+ return scope.send("function_" + @name, args)
+ #end
end
def initialize(hash)
diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb
index 44077983d..4a4664f0f 100644
--- a/lib/puppet/parser/ast/hostclass.rb
+++ b/lib/puppet/parser/ast/hostclass.rb
@@ -1,3 +1,5 @@
+require 'puppet/parser/ast/component'
+
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
@@ -5,152 +7,50 @@ class Puppet::Parser::AST
class HostClass < AST::Component
@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.parentclass
+ return true
+ else
+ return self.parentclass.child_of?(klass)
+ end
+ end
+
+ # Evaluate the code associated with this class.
def evaluate(hash)
scope = hash[:scope]
- objname = hash[:name]
args = hash[:arguments]
+
# Verify that we haven't already been evaluated
- # FIXME The second subclass won't evaluate the parent class
- # code at all, and any overrides will throw an error.
- if myscope = scope.lookupclass(self.object_id)
+ if scope.setclass?(self)
Puppet.debug "%s class already evaluated" % @type
-
- # Not used, but will eventually be used to fix #140.
- if myscope.is_a? Puppet::Parser::Scope
- unless scope.object_id == myscope.object_id
- #scope.parent = myscope
- end
- end
return nil
end
- # Set the class before we do anything else, so that it's set
- # during the evaluation and can be inspected.
- scope.setclass(self.object_id, @type)
-
- origscope = scope
-
- # Default to creating a new context
- newcontext = true
-
- # If we've got a parent, then we pass it the original scope we
- # received. It will get passed all the way up to the top class,
- # which will create a subscope and pass that subscope to its
- # subclass.
- if @parentscope = self.evalparent(
- :scope => scope, :arguments => args, :name => objname
- )
- if @parentscope.is_a? Puppet::TransBucket
- raise Puppet::DevError, "Got a bucket instead of a scope"
- end
-
- # Override our scope binding with the parent scope
- # binding.
- scope = @parentscope
-
- # But don't create a new context if our parent created one
- newcontext = false
- end
-
- # Just use the Component evaluate method, but change the type
- # to our own type.
- result = super(
- :scope => scope,
- :arguments => args,
- :type => @type,
- :name => objname, # might be nil
- :newcontext => newcontext,
- :asparent => hash[:asparent] || false # might be nil
- )
-
- # Now set the class again, this time using the scope. This way
- # we can look up the parent scope of this class later, so we
- # can hook the children together.
- scope.setscope(self.object_id, result)
-
- # This is important but painfully difficult. If we're the top-level
- # class, that is, we have no parent classes, then the transscope
- # is our own scope, but if there are parent classes, then the topmost
- # parent's scope is the transscope, since it contains its code and
- # all of the subclass's code.
- transscope ||= result
-
- if hash[:asparent]
- # If we're a parent class, then return the scope object itself.
- return result
- else
- transscope = nil
- if @parentscope
- transscope = @parentscope
- until transscope.parent.object_id == origscope.object_id
- transscope = transscope.parent
- end
+ if @parentclass
+ if pklass = self.parentclass
+ pklass.safeevaluate :scope => scope
else
- transscope = result
+ parsefail "Could not find class %s" % @parentclass
end
-
- # But if we're the final subclass, translate the whole scope tree
- # into TransObjects and TransBuckets.
- return transscope.to_trans
end
- end
- # Evaluate our parent class. Parent classes are evaluated in the
- # exact same scope as the children. This is maybe not a good idea
- # but, eh.
- #def evalparent(scope, args, name)
- def evalparent(hash)
- scope = hash[:scope]
- args = hash[:arguments]
- name = hash[:name]
- if @parentclass
- #scope.warning "parent class of %s is %s" %
- # [@type, @parentclass.inspect]
- parentobj = nil
+ # Set the class before we do anything else, so that it's set
+ # during the evaluation and can be inspected.
+ scope.setclass(self)
- begin
- parentobj = scope.lookuptype(@parentclass)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- raise error
- end
- unless parentobj
- error = Puppet::ParseError.new(
- "Could not find parent '%s' of '%s'" %
- [@parentclass,@name])
- error.line = self.line
- error.file = self.file
- raise error
- end
+ unless hash[:nosubscope]
+ scope = subscope(scope)
+ end
- # Verify that the parent and child are of the same type
- unless parentobj.class == self.class
- error = Puppet::ParseError.new(
- "Class %s has incompatible parent type, %s vs %s" %
- [@type, parentobj.class, self.class]
- )
- error.file = self.file
- error.line = self.line
- raise error
- end
- # We don't need to pass the type, because the parent will just
- # use its own type. Specify that it's being evaluated as a parent,
- # so that it returns the scope, not a transbucket.
- return parentobj.safeevaluate(
- :scope => scope,
- :arguments => args,
- :name => name,
- :asparent => true,
- :collectable => self.collectable
- )
+ # Now evaluate our code, yo.
+ if self.code
+ return self.code.evaluate(:scope => scope)
else
- return false
+ return nil
end
end
@@ -158,7 +58,7 @@ class Puppet::Parser::AST
@parentclass = nil
super
end
-
end
-
end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index 7b9a283d7..298c0168f 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -28,15 +28,11 @@ class Puppet::Parser::AST
def initialize(hash)
super
- unless @value == 'true' or @value == 'false'
+ unless @value == true or @value == false
raise Puppet::DevError,
"'%s' is not a boolean" % @value
end
- if @value == 'true'
- @value = true
- else
- @value = false
- end
+ @value
end
end
@@ -69,6 +65,9 @@ class Puppet::Parser::AST
# Lower-case words.
class Name < AST::Leaf; end
+ # double-colon separated class names
+ class ClassName < AST::Leaf; end
+
# Host names, either fully qualified or just the short name
class HostName < AST::Leaf
def initialize(hash)
@@ -87,18 +86,8 @@ class Puppet::Parser::AST
# Looks up the value of the object in the scope tree (does
# not include syntactical constructs, like '$' and '{}').
def evaluate(hash)
- begin
+ parsewrap do
return hash[:scope].lookupvar(@value)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::DevError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
end
end
end
diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb
index e4e69bed9..3f508b2bf 100644
--- a/lib/puppet/parser/ast/node.rb
+++ b/lib/puppet/parser/ast/node.rb
@@ -1,113 +1,70 @@
+require 'puppet/parser/ast/hostclass'
+
class Puppet::Parser::AST
# 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 Node < AST::HostClass
@name = :node
- attr_accessor :type, :args, :code, :parentclass
+ attr_accessor :name
#def evaluate(scope, facts = {})
def evaluate(hash)
- origscope = hash[:scope]
- facts = hash[:facts] || {}
-
- # nodes are never instantiated like a normal object,
- # but we need the type to be the name users would use for
- # instantiation, otherwise tags don't work out
+ scope = hash[:scope]
- pscope = origscope
#pscope = if ! Puppet[:lexical] or hash[:asparent]
# @scope
#else
# origscope
#end
- scope = pscope.newscope(
- :type => self.type,
- :keyword => @keyword
- )
- scope.context = self.object_id
+ Puppet.warning "%s => %s" % [scope.type, self.name]
- # Now set all of the facts inside this scope
- facts.each { |var, value|
- scope.setvar(var, value)
- }
-
- if tmp = self.evalparent(scope)
- # Again, override our scope with the parent scope, if
- # there is one.
- scope = tmp
+ # We don't have to worry about the declarativeness of node parentage,
+ # because the entry point is always a single node definition.
+ if parent = self.parentclass
+ scope = parent.safeevaluate :scope => scope
end
+ Puppet.notice "%s => %s" % [scope.type, self.name]
- #scope.tag(@name)
-
- # We never pass the facts to the parent class, because they've
- # already been defined at this top-level scope.
- #super(scope, facts, @name, @name)
+ scope = scope.newscope(
+ :type => self.name,
+ :keyword => @keyword,
+ :source => self,
+ :namespace => "" # nodes are always in ""
+ )
+ Puppet.info "%s => %s" % [scope.type, self.name]
# Mark our node name as a class, too, but strip it of the domain
# name. Make the mark before we evaluate the code, so that it is
# marked within the code itself.
- scope.setclass(self.object_id, @type.sub(/\..+/, ''))
+ scope.setclass(self)
- # And then evaluate our code.
- @code.safeevaluate(:scope => scope)
+ # And then evaluate our code if we have any
+ if self.code
+ @code.safeevaluate(:scope => scope)
+ end
return scope
end
- # Evaluate our parent class.
- def evalparent(scope)
- if @parentclass
- # This is pretty messed up. I don't know if this will
- # work in the long term, but we need to evaluate the node
- # in our own scope, even though our parent node has
- # a scope associated with it, because otherwise we 1) won't
- # get our facts defined, and 2) we won't actually get the
- # objects returned, based on how nodes work.
-
- # We also can't just evaluate the node itself, because
- # it would create a node scope within this scope,
- # and that would cause mass havoc.
- node = nil
-
- # The 'node' method just returns a hash of the node
- # code and name. It's used here, and in 'evalnode'.
- unless hash = scope.node(@parentclass)
- raise Puppet::ParseError,
- "Could not find parent node %s" %
- @parentclass
- end
-
- node = hash[:node]
- type = nil
- if type = node.type
- scope.tag(node.type)
- end
-
- begin
- code = node.code
- code.safeevaluate(:scope => scope, :asparent => true)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- raise error
- end
+ def initialize(hash)
+ @parentclass = nil
+ super
- if node.parentclass
- node.evalparent(scope)
- end
+ # Do some validation on the node name
+ if @name =~ /[^-\w.]/
+ raise Puppet::ParseError, "Invalid node name %s" % @name
end
end
- def initialize(hash)
- @parentclass = nil
- super
+ def parentclass
+ parentobj do |name|
+ @interp.nodesearch(name)
+ end
+ @parentclass
end
end
end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/nodedef.rb b/lib/puppet/parser/ast/nodedef.rb
deleted file mode 100644
index 06b104828..000000000
--- a/lib/puppet/parser/ast/nodedef.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-class Puppet::Parser::AST
- # Define a node. The node definition stores a parse tree for each
- # specified node, and this parse tree is only ever looked up when
- # a client connects.
- class NodeDef < AST::Branch
- attr_accessor :names, :code, :parentclass, :keyword, :scope
-
- def each
- [@names,@code].each { |child| yield child }
- end
-
- # Do implicit iteration over each of the names passed.
- def evaluate(hash)
- scope = hash[:scope]
- names = @names.safeevaluate(:scope => scope)
-
- unless names.is_a?(Array)
- names = [names]
- end
-
- names.each { |name|
- #Puppet.debug("defining host '%s' in scope %s" %
- # [name, scope.object_id])
- # We use 'type' here instead of name, because every component
- # type supports both 'type' and 'name', and 'type' is a more
- # appropriate description of the syntactic role that this term
- # plays.
- arghash = {
- :type => name,
- :code => @code
- }
-
- if @parentclass
- arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope)
- end
-
- begin
- node = Node.new(arghash)
- node.keyword = true
- scope.setnode(name, node)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- raise error
- end
- }
- end
-
- def initialize(hash)
- @parentclass = nil
- @keyword = "node"
- super
- end
-
- def tree(indent = 0)
- return [
- @names.tree(indent + 1),
- ((@@indline * 4 * indent) + self.typewrap("node")),
- @code.tree(indent + 1),
- ].join("\n")
- end
-
- def to_s
- return "node %s {\n%s }" % [@name, @code]
- end
- end
-
-end
diff --git a/lib/puppet/parser/ast/objectdef.rb b/lib/puppet/parser/ast/objectdef.rb
deleted file mode 100644
index ac5fe3070..000000000
--- a/lib/puppet/parser/ast/objectdef.rb
+++ /dev/null
@@ -1,353 +0,0 @@
-class Puppet::Parser::AST
- # Any normal puppet object declaration. Can result in a class or a
- # component, in addition to builtin types.
- class ObjectDef < AST::Branch
- attr_accessor :name, :type, :collectable
- attr_reader :params
-
- # probably not used at all
- def []=(index,obj)
- @params[index] = obj
- end
-
- # probably not used at all
- def [](index)
- return @params[index]
- end
-
- # Iterate across all of our children.
- def each
- [@type,@name,@params].flatten.each { |param|
- #Puppet.debug("yielding param %s" % param)
- yield param
- }
- end
-
- # Does not actually return an object; instead sets an object
- # in the current scope.
- def evaluate(hash)
- scope = hash[:scope]
- @scope = scope
- hash = {}
-
- # Get our type and name.
- objtype = @type.safeevaluate(:scope => scope)
-
- # Disable definition inheritance, for now. 8/27/06, luke
- #if objtype == "super"
- # objtype = supertype()
- # @subtype = true
- #else
- @subtype = false
- #end
-
- # If the type was a variable, we wouldn't have typechecked yet.
- # Do it now, if so.
- unless @checked
- self.typecheck(objtype)
- end
-
- # See if our object type was defined. If not, we know it's
- # builtin because we already typechecked.
- begin
- object = scope.lookuptype(objtype)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
- end
-
- hash = {}
- # Evaluate all of the specified params.
- @params.each { |param|
- ary = param.safeevaluate(:scope => scope)
- hash[ary[0]] = ary[1]
- }
-
- # Now collect info from our parent.
- parentname = nil
- if @subtype
- parentname = supersetup(hash)
- end
-
- objnames = [nil]
- # Determine our name if we have one.
- if self.name
- objnames = @name.safeevaluate(:scope => scope)
- # it's easier to always use an array, even for only one name
- unless objnames.is_a?(Array)
- objnames = [objnames]
- end
- else
- if parentname
- objnames = [parentname]
- else
- # See if they specified the name as a parameter instead of
- # as a normal name (i.e., before the colon).
- unless object # we're a builtin
- if objclass = Puppet::Type.type(objtype)
- namevar = objclass.namevar
-
- tmp = hash["name"] || hash[namevar.to_s]
-
- if tmp
- objnames = [tmp]
- end
- else
- # this should never happen, because we've already
- # typechecked, but it's no real problem if it does
- # happen. We just end up with an object with no
- # name.
- end
- end
- end
- end
-
- # 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
- objnames.collect { |objname|
- # If the object is a class, that means it's a builtin type, so
- # we just store it in the scope
- begin
- #Puppet.debug(
- # ("Setting object '%s' " +
- # "in scope %s " +
- # "with arguments %s") %
- # [objname, scope.object_id, hash.inspect]
- #)
- obj = scope.setobject(
- :type => objtype,
- :name => objname,
- :arguments => hash,
- :file => @file,
- :line => @line,
- :collectable => self.collectable
- )
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
- end
- }.reject { |obj| obj.nil? }
- end
-
- # Create our ObjectDef. Handles type checking for us.
- def initialize(hash)
- @checked = false
- super
-
- #self.typecheck(@type.value)
- end
-
- # Verify that all passed parameters are valid
- def paramcheck(builtin, objtype)
- # This defaults to true
- unless Puppet[:paramcheck]
- return
- end
-
- @params.each { |param|
- if builtin
- self.parambuiltincheck(builtin, param)
- else
- self.paramdefinedcheck(objtype, param)
- end
- }
-
- # Mark that we've made it all the way through.
- @checked = true
- end
-
- def parambuiltincheck(type, param)
- unless param.is_a?(AST::ObjectParam)
- raise Puppet::DevError,
- "Got something other than param"
- end
- begin
- pname = param.param.value
- rescue => detail
- raise Puppet::DevError, detail.to_s
- end
-
- return if pname == "name" # always allow these
- unless type.validattr?(pname)
- error = Puppet::ParseError.new(
- "Invalid parameter '%s' for type '%s'" %
- [pname, type.name]
- )
- error.line = self.line
- error.file = self.file
- raise error
- end
- end
-
- def paramdefinedcheck(objtype, param)
- # FIXME We might need to do more here eventually. Metaparams
- # behave strangely on containers.
- if Puppet::Type.metaparam?(param.param.value.intern)
- return
- end
-
- begin
- pname = param.param.value
- rescue => detail
- raise Puppet::DevError, detail.to_s
- end
-
- unless objtype.validarg?(pname)
- error = Puppet::ParseError.new(
- "Invalid parameter '%s' for type '%s'" %
- [pname,objtype.type]
- )
- error.line = self.line
- error.file = self.file
- raise error
- end
- end
-
- # Set the parameters for our object.
- def params=(params)
- if params.is_a?(AST::ASTArray)
- @params = params
- else
- @params = AST::ASTArray.new(
- :line => params.line,
- :file => params.file,
- :children => [params]
- )
- end
- end
-
- def supercomp
- unless defined? @supercomp
- if @scope and comp = @scope.inside
- @supercomp = comp
- else
- error = Puppet::ParseError.new(
- "'super' is only valid within definitions"
- )
- error.line = self.line
- error.file = self.file
- raise error
- end
- end
- @supercomp
- end
-
- # Take all of the arguments of our parent and add them into our own,
- # without overriding anything.
- def supersetup(hash)
- comp = supercomp()
-
- # Now check each of the arguments from the parent.
- comp.arguments.each do |name, value|
- unless hash.has_key? name
- hash[name] = value
- end
- end
-
- # Return the parent name, so it can be used if appropriate.
- return comp.name
- end
-
- # Retrieve our supertype.
- def supertype
- unless defined? @supertype
- if parent = supercomp.parentclass
- @supertype = parent
- else
- error = Puppet::ParseError.new(
- "%s does not have a parent class" % comp.type
- )
- error.line = self.line
- error.file = self.file
- raise error
- end
- end
- @supertype
- end
-
- # Print this object out.
- def tree(indent = 0)
- return [
- @type.tree(indent + 1),
- @name.tree(indent + 1),
- ((@@indline * indent) + self.typewrap(self.pin)),
- @params.collect { |param|
- begin
- param.tree(indent + 1)
- rescue NoMethodError => detail
- Puppet.err @params.inspect
- error = Puppet::DevError.new(
- "failed to tree a %s" % self.class
- )
- error.set_backtrace detail.backtrace
- raise error
- end
- }.join("\n")
- ].join("\n")
- end
-
- # Verify that the type is valid. This throws an error if there's
- # a problem, so the return value doesn't matter
- def typecheck(objtype)
- # This will basically always be on, but I wanted to make it at
- # least simple to turn off if it came to that
- unless Puppet[:typecheck]
- return
- end
-
- builtin = false
- begin
- builtin = Puppet::Type.type(objtype)
- rescue TypeError
- # nothing; we've already set builtin to false
- end
-
- typeobj = nil
- if builtin
- self.paramcheck(builtin, objtype)
- else
- # If there's no set scope, then we're in initialize, not
- # evaluate, so we can't test defined types.
- return true unless defined? @scope and @scope
-
- # Unless we can look up the type, throw an error
- unless typeobj = @scope.lookuptype(objtype)
- error = Puppet::ParseError.new(
- "Unknown type '%s'" % objtype
- )
- error.line = self.line
- error.file = self.file
- raise error
- end
-
- # Now that we have the type, verify all of the parameters.
- # Note that we're now passing an AST Class object or whatever
- # as the type, not a simple string.
- self.paramcheck(builtin, typeobj)
- end
- end
-
- def to_s
- return "%s => { %s }" % [@name,
- @params.collect { |param|
- param.to_s
- }.join("\n")
- ]
- end
- end
-end
diff --git a/lib/puppet/parser/ast/objectref.rb b/lib/puppet/parser/ast/objectref.rb
deleted file mode 100644
index f9a63e222..000000000
--- a/lib/puppet/parser/ast/objectref.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-class Puppet::Parser::AST
- # A reference to an object. Only valid as an rvalue.
- class ObjectRef < AST::Branch
- attr_accessor :name, :type
-
- def each
- [@type,@name].flatten.each { |param|
- #Puppet.debug("yielding param %s" % param)
- yield param
- }
- end
-
- # Evaluate our object, but just return a simple array of the type
- # and name.
- def evaluate(hash)
- scope = hash[:scope]
- objtype = @type.safeevaluate(:scope => scope)
- objnames = @name.safeevaluate(:scope => scope)
-
- # it's easier to always use an array, even for only one name
- unless objnames.is_a?(Array)
- objnames = [objnames]
- end
-
- # See if we can look the object up in our scope tree.
- begin
- object = scope.lookuptype(objtype)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
- end
-
- # If the type isn't defined, verify that it's builtin
- unless object or Puppet::Type.type(objtype)
- error = Puppet::ParseError.new("Could not find type %s" %
- objtype.inspect)
- error.line = self.line
- error.file = self.file
- raise error
- end
-
- # should we implicitly iterate here?
- # yes, i believe that we essentially have to...
- ret = objnames.collect { |objname|
- if object.is_a?(AST::Component)
- objname = "%s[%s]" % [objtype,objname]
- objtype = "component"
- end
- [objtype,objname]
- }.reject { |obj| obj.nil? }
-
- # Return a flattened array, since we know that we've created an
- # array
- return *ret
- end
-
- def tree(indent = 0)
- return [
- @type.tree(indent + 1),
- @name.tree(indent + 1),
- ((@@indline * indent) + self.typewrap(self.pin))
- ].join("\n")
- end
-
- def to_s
- return "%s[%s]" % [@name,@type]
- end
- end
-
-end
diff --git a/lib/puppet/parser/ast/resourcedef.rb b/lib/puppet/parser/ast/resourcedef.rb
new file mode 100644
index 000000000..1c9333030
--- /dev/null
+++ b/lib/puppet/parser/ast/resourcedef.rb
@@ -0,0 +1,215 @@
+require 'puppet/parser/ast/branch'
+
+# Any normal puppet object declaration. Can result in a class or a
+# component, in addition to builtin types.
+class Puppet::Parser::AST
+class ResourceDef < AST::Branch
+ attr_accessor :title, :type, :exported, :virtual
+ attr_reader :params
+
+ # probably not used at all
+ def []=(index,obj)
+ @params[index] = obj
+ end
+
+ # probably not used at all
+ def [](index)
+ return @params[index]
+ end
+
+ # Iterate across all of our children.
+ def each
+ [@type,@title,@params].flatten.each { |param|
+ #Puppet.debug("yielding param %s" % param)
+ yield param
+ }
+ end
+
+ # Does not actually return an object; instead sets an object
+ # in the current scope.
+ def evaluate(hash)
+ scope = hash[:scope]
+ @scope = scope
+ hash = {}
+
+ # Get our type and name.
+ objtype = @type
+
+ # Disable definition inheritance, for now. 8/27/06, luke
+ #if objtype == "super"
+ # objtype = supertype()
+ # @subtype = true
+ #else
+ @subtype = false
+ #end
+
+ # Evaluate all of the specified params.
+ paramobjects = @params.collect { |param|
+ param.safeevaluate(:scope => scope)
+ }
+
+ # Now collect info from our parent.
+ parentname = nil
+ if @subtype
+ parentname = supersetup(hash)
+ end
+
+ objtitles = nil
+ # Determine our name if we have one.
+ if self.title
+ objtitles = @title.safeevaluate(:scope => scope)
+ # it's easier to always use an array, even for only one name
+ unless objtitles.is_a?(Array)
+ objtitles = [objtitles]
+ end
+ else
+ if parentname
+ objtitles = [parentname]
+ else
+ # See if they specified the name as a parameter instead of
+ # as a normal name (i.e., before the colon).
+ unless object # we're a builtin
+ if objclass = Puppet::Type.type(objtype)
+ namevar = objclass.namevar
+
+ tmp = hash["name"] || hash[namevar.to_s]
+
+ if tmp
+ objtitles = [tmp]
+ end
+ else
+ # This isn't grammatically legal.
+ raise Puppet::ParseError, "Got a resource with no title"
+ end
+ end
+ end
+ end
+
+ # 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.
+ objtitles.collect { |objtitle|
+ exceptwrap :type => Puppet::ParseError do
+ obj = Puppet::Parser::Resource.new(
+ :type => objtype,
+ :title => objtitle,
+ :params => paramobjects,
+ :file => @file,
+ :line => @line,
+ :exported => self.exported || scope.exported,
+ :virtual => self.virtual,
+ :source => scope.source,
+ :scope => scope
+ )
+
+ # And then store the resource in the scope.
+ # XXX At some point, we need to switch all of this to return
+ # objects instead of storing them like this.
+ scope.setresource(obj)
+ obj
+ end
+ }.reject { |obj| obj.nil? }
+ end
+
+ # Create our ResourceDef. Handles type checking for us.
+ def initialize(hash)
+ @checked = false
+ super
+
+ #self.typecheck(@type.value)
+ end
+
+ # Set the parameters for our object.
+ def params=(params)
+ if params.is_a?(AST::ASTArray)
+ @params = params
+ else
+ @params = AST::ASTArray.new(
+ :line => params.line,
+ :file => params.file,
+ :children => [params]
+ )
+ end
+ end
+
+ def supercomp
+ unless defined? @supercomp
+ if @scope and comp = @scope.inside
+ @supercomp = comp
+ else
+ error = Puppet::ParseError.new(
+ "'super' is only valid within definitions"
+ )
+ error.line = self.line
+ error.file = self.file
+ raise error
+ end
+ end
+ @supercomp
+ end
+
+ # Take all of the arguments of our parent and add them into our own,
+ # without overriding anything.
+ def supersetup(hash)
+ comp = supercomp()
+
+ # Now check each of the arguments from the parent.
+ comp.arguments.each do |name, value|
+ unless hash.has_key? name
+ hash[name] = value
+ end
+ end
+
+ # Return the parent name, so it can be used if appropriate.
+ return comp.name
+ end
+
+ # Retrieve our supertype.
+ def supertype
+ unless defined? @supertype
+ if parent = supercomp.parentclass
+ @supertype = parent
+ else
+ error = Puppet::ParseError.new(
+ "%s does not have a parent class" % comp.type
+ )
+ error.line = self.line
+ error.file = self.file
+ raise error
+ end
+ end
+ @supertype
+ end
+
+ # Print this object out.
+ def tree(indent = 0)
+ return [
+ @type.tree(indent + 1),
+ @title.tree(indent + 1),
+ ((@@indline * indent) + self.typewrap(self.pin)),
+ @params.collect { |param|
+ begin
+ param.tree(indent + 1)
+ rescue NoMethodError => detail
+ Puppet.err @params.inspect
+ error = Puppet::DevError.new(
+ "failed to tree a %s" % self.class
+ )
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+ }.join("\n")
+ ].join("\n")
+ end
+
+ def to_s
+ return "%s => { %s }" % [@title,
+ @params.collect { |param|
+ param.to_s
+ }.join("\n")
+ ]
+ end
+end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/typedefaults.rb b/lib/puppet/parser/ast/resourcedefaults.rb
index 2e11a1b94..44db4d465 100644
--- a/lib/puppet/parser/ast/typedefaults.rb
+++ b/lib/puppet/parser/ast/resourcedefaults.rb
@@ -1,32 +1,22 @@
class Puppet::Parser::AST
- # A statement syntactically similar to an ObjectDef, but uses a
+ # A statement syntactically similar to an ResourceDef, but uses a
# capitalized object type and cannot have a name.
- class TypeDefaults < AST::Branch
+ class ResourceDefaults < AST::Branch
attr_accessor :type, :params
def each
[@type,@params].each { |child| yield child }
end
- # As opposed to ObjectDef, this stores each default for the given
+ # As opposed to ResourceDef, this stores each default for the given
# object type.
def evaluate(hash)
scope = hash[:scope]
- type = @type.safeevaluate(:scope => scope)
+ type = @type.downcase
params = @params.safeevaluate(:scope => scope)
- begin
- scope.setdefaults(type.downcase,params)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
+ parsewrap do
+ scope.setdefaults(type, params)
end
end
@@ -44,3 +34,5 @@ class Puppet::Parser::AST
end
end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/resourceoverride.rb b/lib/puppet/parser/ast/resourceoverride.rb
new file mode 100644
index 000000000..26d69ae97
--- /dev/null
+++ b/lib/puppet/parser/ast/resourceoverride.rb
@@ -0,0 +1,62 @@
+require 'puppet/parser/ast/resourcedef'
+
+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 < ResourceDef
+ attr_accessor :object
+ attr_reader :params
+
+ # Iterate across all of our children.
+ def each
+ [@object,@params].flatten.each { |param|
+ #Puppet.debug("yielding param %s" % param)
+ yield param
+ }
+ end
+
+ # Does not actually return an object; instead sets an object
+ # in the current scope.
+ def evaluate(hash)
+ scope = hash[:scope]
+
+ # Get our object reference.
+ object = @object.safeevaluate(:scope => scope)
+
+ hash = {}
+
+ # Evaluate all of the specified params.
+ params = @params.collect { |param|
+ param.safeevaluate(:scope => scope)
+ }
+
+ # Now we just create a normal resource, but we call a very different
+ # method on the scope.
+ obj = Puppet::Parser::Resource.new(
+ :type => object.type,
+ :title => object.title,
+ :params => params,
+ :file => @file,
+ :line => @line,
+ :source => scope.source,
+ :scope => scope
+ )
+
+ # Now we tell the scope that it's an override, and it behaves as
+ # necessary.
+ scope.setoverride(obj)
+
+ obj
+ end
+
+ # Create our ResourceDef. Handles type checking for us.
+ def initialize(hash)
+ @checked = false
+ super
+
+ #self.typecheck(@type.value)
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/objectparam.rb b/lib/puppet/parser/ast/resourceparam.rb
index 87c3e5e8e..248e91b32 100644
--- a/lib/puppet/parser/ast/objectparam.rb
+++ b/lib/puppet/parser/ast/resourceparam.rb
@@ -1,6 +1,8 @@
+require 'puppet/parser/ast/branch'
+
class Puppet::Parser::AST
- # The AST object for the parameters inside ObjectDefs and Selectors.
- class ObjectParam < AST::Branch
+ # The AST object for the parameters inside ResourceDefs and Selectors.
+ class ResourceParam < AST::Branch
attr_accessor :value, :param
def each
@@ -10,9 +12,17 @@ class Puppet::Parser::AST
# Return the parameter and the value.
def evaluate(hash)
scope = hash[:scope]
- param = @param.safeevaluate(:scope => scope)
+ param = @param
value = @value.safeevaluate(:scope => scope)
- return [param, value]
+
+ args = {:name => param, :value => value, :source => scope.source}
+ [:line, :file].each do |p|
+ if v = self.send(p)
+ args[p] = v
+ end
+ end
+
+ return Puppet::Parser::Resource::Param.new(args)
end
def tree(indent = 0)
@@ -27,5 +37,6 @@ class Puppet::Parser::AST
return "%s => %s" % [@param,@value]
end
end
-
end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/resourceref.rb b/lib/puppet/parser/ast/resourceref.rb
new file mode 100644
index 000000000..b0fe5f6d7
--- /dev/null
+++ b/lib/puppet/parser/ast/resourceref.rb
@@ -0,0 +1,44 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+ # A reference to an object. Only valid as an rvalue.
+ class ResourceRef < AST::Branch
+ attr_accessor :title, :type
+
+ def each
+ [@type,@title].flatten.each { |param|
+ #Puppet.debug("yielding param %s" % param)
+ yield param
+ }
+ end
+
+ # Evaluate our object, but just return a simple array of the type
+ # and name.
+ def evaluate(hash)
+ scope = hash[:scope]
+
+ # We want a lower-case type.
+ objtype = @type.downcase
+
+ title = @title.safeevaluate(:scope => scope)
+
+ return Puppet::Parser::Resource::Reference.new(
+ :type => objtype, :title => title
+ )
+ end
+
+ def tree(indent = 0)
+ return [
+ @type.tree(indent + 1),
+ @title.tree(indent + 1),
+ ((@@indline * indent) + self.typewrap(self.pin))
+ ].join("\n")
+ end
+
+ def to_s
+ return "%s[%s]" % [@type,@title]
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb
index 5d1c41494..fe3fe9eaf 100644
--- a/lib/puppet/parser/ast/selector.rb
+++ b/lib/puppet/parser/ast/selector.rb
@@ -42,12 +42,8 @@ class Puppet::Parser::AST
if default
retvalue = default.value.safeevaluate(:scope => scope)
else
- error = Puppet::ParseError.new(
+ self.fail Puppet::ParseError,
"No value for selector param '%s'" % paramvalue
- )
- error.line = self.line
- error.file = self.file
- raise error
end
end
diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb
index 79129f31a..30eef204a 100644
--- a/lib/puppet/parser/ast/vardef.rb
+++ b/lib/puppet/parser/ast/vardef.rb
@@ -10,18 +10,8 @@ class Puppet::Parser::AST
name = @name.safeevaluate(:scope => scope)
value = @value.safeevaluate(:scope => scope)
- begin
+ parsewrap do
scope.setvar(name,value)
- rescue Puppet::ParseError => except
- except.line = self.line
- except.file = self.file
- raise except
- rescue => detail
- error = Puppet::ParseError.new(detail)
- error.line = self.line
- error.file = self.file
- error.set_backtrace detail.backtrace
- raise error
end
end
@@ -43,3 +33,5 @@ class Puppet::Parser::AST
end
end
+
+# $Id$
diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb
new file mode 100644
index 000000000..f3c7949de
--- /dev/null
+++ b/lib/puppet/parser/collector.rb
@@ -0,0 +1,97 @@
+# An object that collects stored objects from the central cache and returns
+# them to the current host, yo.
+class Puppet::Parser::Collector
+ attr_accessor :type, :scope, :query, :form
+
+ # Collect exported objects.
+ def collect_exported
+ require 'puppet/rails'
+ # First get everything from the export table. Just reuse our
+ # collect_virtual method but tell it to use 'exported? for the test.
+ resources = collect_virtual(true)
+
+ count = resources.length
+
+ # We're going to collect objects from rails, but we don't want any
+ # objects from this host.
+ host = Puppet::Rails::Host.find_by_name(@scope.host)
+
+ args = {}
+ if host
+ args[:conditions] = "host_id != #{host.id}"
+ else
+ #Puppet.info "Host %s is uninitialized" % @scope.host
+ end
+
+ # Now look them up in the rails db. When we support attribute comparison
+ # and such, we'll need to vary the conditions, but this works with no
+ # attributes, anyway.
+ Puppet::Util.benchmark(:debug, "Collected #{self.type} resources") do
+ Puppet::Rails::RailsResource.find_all_by_restype_and_exported(@type, true,
+ args
+ ).each do |obj|
+ count += 1
+ resource = obj.to_resource(self.scope)
+
+ # XXX Because the scopes don't expect objects to return values,
+ # we have to manually add our objects to the scope. This is
+ # uber-lame.
+ scope.setresource(resource)
+
+ resources << resource
+ end
+ end
+
+ scope.debug("Collected %s objects of type %s" %
+ [count, @convertedtype])
+
+ return resources
+ end
+
+ # Collect just virtual objects, from our local configuration.
+ def collect_virtual(exported = false)
+ if exported
+ method = :exported?
+ else
+ method = :virtual?
+ end
+ scope.resources.find_all do |resource|
+ resource.type == @type and resource.send(method) and match?(resource)
+ end
+ end
+
+ # Call the collection method, mark all of the returned objects as non-virtual,
+ # and then delete this object from the list of collections to evaluate.
+ def evaluate
+ method = "collect_#{@form.to_s}"
+ objects = send(method).each do |obj|
+ obj.virtual = false
+ end
+
+ # And then remove us from the list of collections, since we've
+ # now been evaluated.
+ @scope.collections.delete(self)
+
+ objects
+ end
+
+ def initialize(scope, type, query, form)
+ @scope = scope
+ @type = type
+ @query = query
+ @form = form
+ @tests = []
+ end
+
+ # Does the resource match our tests? We don't yet support tests,
+ # so it's always true at the moment.
+ def match?(resource)
+ if self.query
+ return self.query.call(resource)
+ else
+ return true
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb
index 9562441bc..96fccd7cd 100644
--- a/lib/puppet/parser/functions.rb
+++ b/lib/puppet/parser/functions.rb
@@ -76,29 +76,24 @@ module Functions
# Include the specified classes
newfunction(:include) do |vals|
- vals.each do |val|
- if objecttype = lookuptype(val)
- # It's a defined type, so set it into the scope so it can
- # be evaluated.
- setobject(
- :type => val,
- :arguments => {}
- )
- else
- raise Puppet::ParseError, "Unknown class %s" % val
- end
+ klasses = evalclasses(*vals)
+
+ missing = vals.find_all do |klass|
+ ! klass.include?(klass)
+ end
+
+ # Throw an error if we didn't evaluate all of the classes.
+ if missing.length == 1
+ self.fail Puppet::ParseError,
+ "Could not find class %s" % missing
+ elsif missing.length > 1
+ self.fail Puppet::ParseError,
+ "Could not find classes %s" % missing.join(", ")
end
end
# Tag the current scope with each passed name
newfunction(:tag) do |vals|
- vals.each do |val|
- # Some hackery, because the tags are stored by object id
- # for singletonness.
- self.setclass(val.object_id, val)
- end
-
- # Also add them as tags
self.tag(*vals)
end
@@ -120,16 +115,13 @@ module Functions
# Test whether a given class or definition is defined
newfunction(:defined, :rvalue) do |vals|
- retval = true
-
- vals.each do |val|
- unless builtintype?(val) or lookuptype(val)
- retval = false
- break
- end
+ # For some reason, it doesn't want me to return from here.
+ if vals.detect do |val| Puppet::Type.type(val) or finddefine(val) end
+ true
+ else
+ false
end
- return retval
end
newfunction(:fail, :statement) do |vals|
@@ -151,7 +143,7 @@ module Functions
# Use a wrapper, so the template can't get access to the full
# Scope object.
debug "Retrieving template %s" % file
- wrapper = Puppet::Parser::Scope::TemplateWrapper.new(self, file)
+ wrapper = Puppet::Parser::TemplateWrapper.new(self, file)
begin
wrapper.result()
diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra
index 3a1a78e50..5c91aabdc 100644
--- a/lib/puppet/parser/grammar.ra
+++ b/lib/puppet/parser/grammar.ra
@@ -5,38 +5,52 @@
class Puppet::Parser::Parser
token LBRACK DQTEXT SQTEXT RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE
-token FALSE EQUALS LESSEQUAL NOTEQUAL DOT COLON TYPE
+token FALSE EQUALS LESSEQUAL NOTEQUAL DOT COLON TYPE LLCOLLECT RRCOLLECT
token QMARK LPAREN RPAREN ISEQUAL GREATEREQUAL GREATERTHAN LESSTHAN
token IF ELSE IMPORT DEFINE ELSIF VARIABLE CLASS INHERITS NODE BOOLEAN
-token NAME SEMIC CASE DEFAULT AT LCOLLECT RCOLLECT
+token NAME SEMIC CASE DEFAULT AT LCOLLECT RCOLLECT CLASSNAME CLASSREF
+token NOT OR AND
# We have 2 shift/reduce conflicts
#expect 2
rule
program: statements {
- # Make sure we always return an array.
- if val[0].is_a?(AST::ASTArray)
- result = val[0]
+ if val[0]
+ # Make sure we always return an array.
+ if val[0].is_a?(AST::ASTArray)
+ if val[0].children.empty?
+ result = nil
+ else
+ result = val[0]
+ end
+ else
+ result = aryfy(val[0])
+ end
else
- result = aryfy(val[0])
+ result = nil
end
}
- | nothing
+ | nil
-statements: statement
+statements: statement
| statements statement {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[1])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[1]]
+ if val[0] and val[1]
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[1])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[1]]
+ end
+ elsif obj = (val[0] || val[1])
+ result = obj
+ else result = nil
end
}
# The main list of valid statements
-statement: object
- | collectable
+statement: resource
+ | virtualresource
| collection
| assignment
| casestatement
@@ -46,15 +60,16 @@ statement: object
| definition
| hostclass
| nodedef
+ | resourceoverride
-fstatement: NAME LPAREN classnames RPAREN {
+fstatement: NAME LPAREN namestrings RPAREN {
args = aryfy(val[2])
result = ast AST::Function,
:name => val[0],
:arguments => args,
:ftype => :statement
}
- | NAME classnames {
+ | NAME namestrings {
args = aryfy(val[1])
result = ast AST::Function,
:name => val[0],
@@ -62,108 +77,163 @@ fstatement: NAME LPAREN classnames RPAREN {
:ftype => :statement
}
-# Includes are just syntactic sugar for classes with no names and
-# no arguments.
-#include: INCLUDE classnames {
-# result = function_include(val[1])
-#}
-
-# Define a new tag. Both of these functions should really be done generically,
-# but I'm not in a position to do that just yet. :/
-#tag: TAG classnames {
-# result = function_tag(val[1])
-#}
-
-classnames: classname
- | classnames COMMA classname {
+namestrings: namestring
+ | namestrings COMMA namestring {
result = aryfy(val[0], val[2])
result.line = @lexer.line
result.file = @lexer.file
}
-classname: name
+namestring: name
| variable
| quotedtext
-#object: name LBRACE objectname COLON params endcomma RBRACE {
-object: name LBRACE objectinstances endsemi RBRACE {
+resource: NAME LBRACE resourceinstances endsemi RBRACE {
if val[0].instance_of?(AST::ASTArray)
- raise Puppet::ParseError, "Invalid name"
+ error "Invalid name"
end
array = val[2]
- if array.instance_of?(AST::ObjectInst)
+ if array.instance_of?(AST::ResourceInst)
array = [array]
end
result = ast AST::ASTArray
- # this iterates across each specified objectinstance
+ # this iterates across each specified resourceinstance
array.each { |instance|
- unless instance.instance_of?(AST::ObjectInst)
+ unless instance.instance_of?(AST::ResourceInst)
raise Puppet::Dev, "Got something that isn't an instance"
end
# now, i need to somehow differentiate between those things with
# arrays in their names, and normal things
- result.push ast(AST::ObjectDef,
+ result.push ast(AST::ResourceDef,
:type => val[0],
- :name => instance[0],
+ :title => instance[0],
:params => instance[1])
}
-} | name LBRACE params endcomma RBRACE {
- if val[0].instance_of?(AST::ASTArray)
- Puppet.notice "invalid name"
- raise Puppet::ParseError, "Invalid name"
- end
- # an object but without a name
- # this cannot be an instance of a library type
- result = ast AST::ObjectDef, :type => val[0], :params => val[2]
-
-} | type LBRACE params endcomma RBRACE {
+} | NAME LBRACE params endcomma RBRACE {
+ # This is a deprecated syntax.
+ error "All resource specifications require names"
+} | TYPE LBRACE params endcomma RBRACE {
# a template setting for a type
if val[0].instance_of?(AST::ASTArray)
- raise Puppet::ParseError, "Invalid type"
+ error "Invalid type"
end
- result = ast(AST::TypeDefaults, :type => val[0], :params => val[2])
+ result = ast(AST::ResourceDefaults, :type => val[0], :params => val[2])
+}
+
+# Override a value set elsewhere in the configuration.
+resourceoverride: resourceref LBRACE params RBRACE {
+ result = ast AST::ResourceOverride, :object => val[0], :params => val[2]
}
-# Collectable objects; these get stored in the database, instead of
-# being passed to the client.
-collectable: AT object {
- unless Puppet[:storeconfigs]
- raise Puppet::ParseError, "You cannot collect without storeconfigs being set"
+# Exported and virtual resources; these don't get sent to the client
+# unless they get collected elsewhere in the db.
+virtualresource: at resource {
+ type = val[0]
+
+ if type == :exported and ! Puppet[:storeconfigs]
+ error "You cannot collect without storeconfigs being set"
end
- if val[1].is_a? AST::TypeDefaults
- raise Puppet::ParseError, "Defaults are not collectable"
+ if val[1].is_a? AST::ResourceDefaults
+ error "Defaults are not virtualizable"
end
- # Just mark our objects as collectable and pass them through.
+ method = type.to_s + "="
+
+ # Just mark our resources as exported and pass them through.
if val[1].instance_of?(AST::ASTArray)
val[1].each do |obj|
- obj.collectable = true
+ obj.send(method, true)
end
else
- val[1].collectable = true
+ val[1].send(method, true)
end
result = val[1]
}
+at: AT { result = :virtual }
+ | AT AT { result = :exported }
+
# A collection statement. Currently supports no arguments at all, but eventually
# will, I assume.
-collection: name LCOLLECT RCOLLECT {
- unless Puppet[:storeconfigs]
- raise Puppet::ParseError, "You cannot collect without storeconfigs being set"
+collection: collectname collectrhand {
+ if val[0] =~ /^[a-z]/
+ Puppet.warning addcontext("Collection names must now be capitalized")
+ end
+ type = val[0].downcase
+ args = {:type => type}
+
+ if val[1].is_a?(AST::CollExpr)
+ args[:query] = val[1]
+ args[:query].type = type
+ args[:form] = args[:query].form
+ else
+ args[:form] = val[1]
+ end
+ if args[:form] == :exported and ! Puppet[:storeconfigs]
+ error "You cannot collect exported resources without storeconfigs being set"
end
- result = ast AST::Collection, :type => val[0]
+ result = ast AST::Collection, args
}
-objectinst: objectname COLON params endcomma {
- result = ast AST::ObjectInst, :children => [val[0],val[2]]
+collectname: TYPE | NAME
+
+collectrhand: LCOLLECT collstatements RCOLLECT {
+ if val[1]
+ result = val[1]
+ result.form = :virtual
+ else
+ result = :virtual
+ end
}
+ | LLCOLLECT collstatements RRCOLLECT {
+ if val[1]
+ result = val[1]
+ result.form = :exported
+ else
+ result = :exported
+ end
+}
+
+# A mini-language for handling collection comparisons. This is organized
+# to avoid the need for precedence indications.
+collstatements: nil
+ | collstatement
+ | collstatements colljoin collstatement {
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+}
+
+collstatement: collexpr
+ | LPAREN collstatements RPAREN {
+ result = val[1]
+ result.parens = true
+}
+
+colljoin: AND | OR
-objectinstances: objectinst
- | objectinstances SEMIC objectinst {
- if val[0].instance_of?(AST::ObjectInst)
+collexpr: colllval ISEQUAL simplervalue {
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+ #result = ast AST::CollExpr
+ #result.push *val
+}
+ | colllval NOTEQUAL simplervalue {
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+ #result = ast AST::CollExpr
+ #result.push *val
+}
+
+colllval: variable
+ | name
+
+resourceinst: resourcename COLON params endcomma {
+ result = ast AST::ResourceInst, :children => [val[0],val[2]]
+}
+
+resourceinstances: resourceinst
+ | resourceinstances SEMIC resourceinst {
+ if val[0].instance_of?(AST::ResourceInst)
result = ast AST::ASTArray, :children => [val[0],val[2]]
else
val[0].push val[2]
@@ -182,7 +252,7 @@ type: TYPE {
result = ast AST::Type, :value => val[0]
}
-objectname: quotedtext
+resourcename: quotedtext
| name
| type
| selector
@@ -191,7 +261,7 @@ objectname: quotedtext
assignment: VARIABLE EQUALS rvalue {
# this is distinct from referencing a variable
- variable = ast AST::Name, :value => val[0].sub(/^\$/,'')
+ variable = ast AST::Name, :value => val[0]
result = ast AST::VarDef, :name => variable, :value => val[2]
}
@@ -210,8 +280,7 @@ params: # nothing
}
param: NAME FARROW rvalue {
- leaf = ast AST::String, :value => val[0]
- result = ast AST::ObjectParam, :param => leaf, :value => val[2]
+ result = ast AST::ResourceParam, :param => val[0], :value => val[2]
}
rvalues: rvalue
@@ -223,6 +292,13 @@ rvalues: rvalue
end
}
+simplervalue: quotedtext
+ | name
+ | type
+ | boolean
+ | selector
+ | variable
+
rvalue: quotedtext
| name
| type
@@ -230,11 +306,11 @@ rvalue: quotedtext
| selector
| variable
| array
- | objectref
+ | resourceref
| funcrvalue
# We currently require arguments in these functions.
-funcrvalue: NAME LPAREN classnames RPAREN {
+funcrvalue: NAME LPAREN namestrings RPAREN {
args = aryfy(val[2])
result = ast AST::Function,
:name => val[0],
@@ -252,8 +328,11 @@ boolean: BOOLEAN {
result = ast AST::Boolean, :value => val[0]
}
-objectref: name LBRACK rvalue RBRACK {
- result = ast AST::ObjectRef, :type => val[0], :name => val[2]
+resourceref: NAME LBRACK rvalue RBRACK {
+ Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized")
+ result = ast AST::ResourceRef, :type => val[0], :title => val[2]
+} | TYPE LBRACK rvalue RBRACK {
+ result = ast AST::ResourceRef, :type => val[0], :title => val[2]
}
ifstatement: IF iftest LBRACE statements RBRACE else {
@@ -333,7 +412,7 @@ sintvalues: selectval
}
selectval: selectlhand FARROW rvalue {
- result = ast AST::ObjectParam, :param => val[0], :value => val[2]
+ result = ast AST::ResourceParam, :param => val[0], :value => val[2]
}
selectlhand: name
@@ -378,7 +457,7 @@ import: IMPORT quotedtext {
end
files.each { |file|
- parser = Puppet::Parser::Parser.new()
+ parser = Puppet::Parser::Parser.new(interp)
parser.files = self.files
Puppet.debug("importing '%s'" % file)
@@ -396,8 +475,13 @@ import: IMPORT quotedtext {
end
# push the results into the main result array
# We always return an array when we parse.
- parser.parse.each do |child|
- result.push child
+ ast = parser.parse
+
+ # Things that just get added to the classtable or whatever return nil
+ if ast
+ ast.each do |child|
+ result.push child
+ end
end
}
}
@@ -405,165 +489,99 @@ import: IMPORT quotedtext {
# Disable definition inheritance for now. 8/27/06, luke
#definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE {
-definition: DEFINE NAME argumentlist LBRACE statements RBRACE {
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :args => val[2],
- :code => val[4] # Switch to 5 for parents
- }
+definition: DEFINE fqname argumentlist LBRACE statements RBRACE {
+ interp.newdefine fqname(val[1]), :arguments => val[2], :code => val[4]
+ @lexer.indefine = false
+ result = nil
- if val[3].instance_of?(AST::Name)
- args[:parentclass] = val[3]
- end
- result = ast AST::CompDef, args
#} | DEFINE NAME argumentlist parent LBRACE RBRACE {
-} | DEFINE NAME argumentlist LBRACE RBRACE {
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :args => val[2],
- :code => ast(AST::ASTArray)
- }
-
- if val[3].instance_of?(AST::Name)
- args[:parentclass] = val[3]
- end
-
- result = ast AST::CompDef, args
+} | DEFINE fqname argumentlist LBRACE RBRACE {
+ interp.newdefine fqname(val[1]), :arguments => val[2]
+ @lexer.indefine = false
+ result = nil
}
#hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE {
-hostclass: CLASS NAME parent LBRACE statements RBRACE {
- #:args => val[2],
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :code => val[4]
- }
- # It'll be an ASTArray if we didn't get a parent
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::ClassDef, args
-} | CLASS NAME parent LBRACE RBRACE {
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :code => ast(AST::ASTArray, :children => [])
- }
- # It'll be an ASTArray if we didn't get a parent
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::ClassDef, args
+hostclass: CLASS fqname parent LBRACE statements RBRACE {
+ # Our class gets defined in the parent namespace, not our own.
+ @lexer.namepop
+ interp.newclass fqname(val[1]), :code => val[4], :parent => val[2]
+ result = nil
+} | CLASS fqname parent LBRACE RBRACE {
+ # Our class gets defined in the parent namespace, not our own.
+ @lexer.namepop
+ interp.newclass fqname(val[1]), :parent => val[2]
+ result = nil
}
nodedef: NODE hostnames parent LBRACE statements RBRACE {
- unless val[1].instance_of?(AST::ASTArray)
- val[1] = ast AST::ASTArray,
- :line => val[1].line,
- :file => val[1].file,
- :children => [val[1]]
- end
- args = {
- :names => val[1],
- :code => val[4]
- }
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::NodeDef, args
+ interp.newnode val[1], :parent => val[2], :code => val[4]
+ result = nil
} | NODE hostnames parent LBRACE RBRACE {
- unless val[1].instance_of?(AST::ASTArray)
- val[1] = ast AST::ASTArray,
- :line => val[1].line,
- :file => val[1].file,
- :children => [val[1]]
- end
- args = {
- :names => val[1],
- :code => ast(AST::ASTArray, :children => [])
- }
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::NodeDef,args
+ interp.newnode val[1], :parent => val[2]
+ result = nil
}
-# Multiple hostnames, as used for node names.
+fqname: NAME
+ | CLASSNAME
+
+# Multiple hostnames, as used for node names. These are all literal
+# strings, not AST objects.
hostnames: hostname
| hostnames COMMA hostname {
- if val[0].instance_of?(AST::ASTArray)
- result = val[0]
- result.push val[2]
- else
- result = ast AST::ASTArray, :children => [val[0], val[2]]
- end
+ result = val[0]
+ result = [result] unless result.is_a?(Array)
+ result << val[2]
}
-hostname: NAME {
- result = ast AST::HostName, :value => val[0]
-} | SQTEXT {
- result = ast AST::HostName, :value => val[0]
-} | DEFAULT {
- result = ast AST::Default, :value => val[0]
+hostname: NAME
+ | SQTEXT
+ | DEFAULT
+
+nil: {
+ result = nil
}
nothing: {
result = ast AST::ASTArray, :children => []
}
-argumentlist: nothing
+argumentlist: nil
| LPAREN nothing RPAREN {
- result = val[1]
+ result = nil
}
| LPAREN arguments RPAREN {
- if val[1].instance_of?(AST::ASTArray)
- result = val[1]
- else
- result = ast AST::ASTArray, :children => [val[1]]
- end
+ result = val[1]
+ result = [result] unless result[0].is_a?(Array)
}
arguments: argument
| arguments COMMA argument {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[2])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+ result = val[0]
+ result = [result] unless result[0].is_a?(Array)
+ result << val[2]
}
-argument: name EQUALS rvalue {
- msg = "Deprecation notice: #{val[0].value} must now include '$' in prototype"
- msg += " at line %s" % @lexer.line
- msg += " in file %s" % @lexer.file if @lexer.file
- Puppet.warning msg
- result = ast AST::CompArgument, :children => [val[0],val[2]]
+argument: NAME EQUALS rvalue {
+ Puppet.warning addcontext("Deprecation notice: #{val[0].value} must now include '$' in prototype")
+ result = [val[0], val[2]]
}
- | name {
- msg = "Deprecation notice: #{val[0].value} must now include '$' in prototype"
- msg += " at line %s" % @lexer.line
- msg += " in file %s" % @lexer.file if @lexer.file
- Puppet.warning msg
- result = ast AST::CompArgument, :children => [val[0]]
-} | lvariable EQUALS rvalue {
- result = ast AST::CompArgument, :children => [val[0],val[2]]
-} | lvariable {
- result = ast AST::CompArgument, :children => [val[0]]
+ | NAME {
+ Puppet.warning addcontext("Deprecation notice: #{val[0].value} must now include '$' in prototype")
+ result = [val[0]]
+} | VARIABLE EQUALS rvalue {
+ result = [val[0], val[2]]
+} | VARIABLE {
+ result = [val[0]]
}
-parent: nothing
+parent: nil
| INHERITS NAME {
- result = ast AST::Name, :value => val[1]
+ result = val[1]
}
variable: VARIABLE {
- name = val[0].sub(/^\$/,'')
- result = ast AST::Variable, :value => name
-}
-
-# This is variables as lvalues; we're assigning them, not deferencing them.
-lvariable: VARIABLE {
- result = ast AST::Name, :value => val[0].sub(/^\$/,'')
+ result = ast AST::Variable, :value => val[0]
}
array: LBRACK rvalues RBRACK {
@@ -602,9 +620,21 @@ Puppet[:paramcheck] = true
---- inner ----
require 'puppet/parser/functions'
-attr_reader :file
+attr_reader :file, :interp
attr_accessor :files
+# Add context to a message; useful for error messages and such.
+def addcontext(message, obj = nil)
+ obj ||= @lexer
+
+ message += " on line %s" % obj.line
+ if file = obj.file
+ message += " in file %s" % file
+ end
+
+ return message
+end
+
# Create an AST array out of all of the args
def aryfy(*args)
if args[0].instance_of?(AST::ASTArray)
@@ -636,6 +666,17 @@ def ast(klass, hash = nil)
return klass.new(hash)
end
+# Raise a Parse error.
+def error(message)
+ except = Puppet::ParseError.new(message)
+ except.line = @lexer.line
+ if @lexer.file
+ except.file = @lexer.file
+ end
+
+ raise except
+end
+
def file=(file)
unless FileTest.exists?(file)
unless file =~ /\.pp$/
@@ -653,23 +694,20 @@ def file=(file)
end
end
-def initialize
+def initialize(interpreter)
+ @interp = interpreter
+ initvars()
+end
+
+# Initialize or reset all of our variables.
+def initvars
@lexer = Puppet::Parser::Lexer.new()
@files = []
- #if Puppet[:debug]
- # @yydebug = true
- #end
end
-# Add a new file to be checked when we're checking to see if we should be
-# reparsed.
-def newfile(*files)
- files.each do |file|
- unless file.is_a? Puppet::LoadedFile
- file = Puppet::LoadedFile.new(file)
- end
- @files << file
- end
+# The fully qualifed name, with the full namespace.
+def fqname(name)
+ [@lexer.namespace, name].join("::").sub(/^::/, '')
end
def on_error(token,value,stack)
@@ -693,7 +731,7 @@ def parse(string = nil)
self.string = string
end
begin
- yyparse(@lexer,:scan)
+ main = yyparse(@lexer,:scan)
rescue Racc::ParseError => except
error = Puppet::ParseError.new(except)
error.line = @lexer.line
@@ -720,6 +758,13 @@ def parse(string = nil)
error.set_backtrace except.backtrace
raise error
end
+ if main
+ # Store the results as the top-level class.
+ interp.newclass("", :code => main)
+ return main
+ end
+ensure
+ @lexer.clear
end
# See if any of the files have changed.
diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb
index 26bf8104e..111fe2ed3 100644
--- a/lib/puppet/parser/interpreter.rb
+++ b/lib/puppet/parser/interpreter.rb
@@ -3,463 +3,774 @@
# and calls out to other objects.
require 'puppet'
+require 'timeout'
require 'puppet/parser/parser'
require 'puppet/parser/scope'
+class Puppet::Parser::Interpreter
+ include Puppet::Util
+
+ Puppet.setdefaults("ldap",
+ :ldapnodes => [false,
+ "Whether to search for node configurations in LDAP."],
+ :ldapssl => [false,
+ "Whether SSL should be used when searching for nodes.
+ Defaults to false because SSL usually requires certificates
+ to be set up on the client side."],
+ :ldaptls => [false,
+ "Whether TLS should be used when searching for nodes.
+ Defaults to false because TLS usually requires certificates
+ to be set up on the client side."],
+ :ldapserver => ["ldap",
+ "The LDAP server. Only used if ``ldapnodes`` is enabled."],
+ :ldapport => [389,
+ "The LDAP port. Only used if ``ldapnodes`` is enabled."],
+ :ldapstring => ["(&(objectclass=puppetClient)(cn=%s))",
+ "The search string used to find an LDAP node."],
+ :ldapattrs => ["puppetclass",
+ "The LDAP attributes to use to define Puppet classes. Values
+ should be comma-separated."],
+ :ldapparentattr => ["parentnode",
+ "The attribute to use to define the parent node."],
+ :ldapuser => ["",
+ "The user to use to connect to LDAP. Must be specified as a
+ full DN."],
+ :ldappassword => ["",
+ "The password to use to connect to LDAP."],
+ :ldapbase => ["",
+ "The search base for LDAP searches. It's impossible to provide
+ a meaningful default here, although the LDAP libraries might
+ have one already set. Generally, it should be the 'ou=Hosts'
+ branch under your main directory."]
+ )
+
+ Puppet.setdefaults(:puppetmaster,
+ :storeconfigs => [false,
+ "Whether to store each client's configuration. This
+ requires ActiveRecord from Ruby on Rails."]
+ )
+
+ attr_accessor :usenodes
+
+ class << self
+ attr_writer :ldap
+ end
+ # just shorten the constant path a bit, using what amounts to an alias
+ AST = Puppet::Parser::AST
+
+ include Puppet::Util::Errors
+
+ # Create an ldap connection. This is a class method so others can call
+ # it and use the same variables and such.
+ def self.ldap
+ unless defined? @ldap and @ldap
+ if Puppet[:ldapssl]
+ @ldap = LDAP::SSLConn.new(Puppet[:ldapserver], Puppet[:ldapport])
+ elsif Puppet[:ldaptls]
+ @ldap = LDAP::SSLConn.new(
+ Puppet[:ldapserver], Puppet[:ldapport], true
+ )
+ else
+ @ldap = LDAP::Conn.new(Puppet[:ldapserver], Puppet[:ldapport])
+ end
+ @ldap.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
+ @ldap.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
+ @ldap.simple_bind(Puppet[:ldapuser], Puppet[:ldappassword])
+ end
-module Puppet
- module Parser
- class Interpreter
- include Puppet::Util
-
- Puppet.setdefaults("ldap",
- :ldapnodes => [false,
- "Whether to search for node configurations in LDAP."],
- :ldapssl => [false,
- "Whether SSL should be used when searching for nodes.
- Defaults to false because SSL usually requires certificates
- to be set up on the client side."],
- :ldaptls => [false,
- "Whether TLS should be used when searching for nodes.
- Defaults to false because TLS usually requires certificates
- to be set up on the client side."],
- :ldapserver => ["ldap",
- "The LDAP server. Only used if ``ldapnodes`` is enabled."],
- :ldapport => [389,
- "The LDAP port. Only used if ``ldapnodes`` is enabled."],
- :ldapstring => ["(&(objectclass=puppetClient)(cn=%s))",
- "The search string used to find an LDAP node."],
- :ldapattrs => ["puppetclass",
- "The LDAP attributes to use to define Puppet classes. Values
- should be comma-separated."],
- :ldapparentattr => ["parentnode",
- "The attribute to use to define the parent node."],
- :ldapuser => ["",
- "The user to use to connect to LDAP. Must be specified as a
- full DN."],
- :ldappassword => ["",
- "The password to use to connect to LDAP."],
- :ldapbase => ["",
- "The search base for LDAP searches. It's impossible to provide
- a meaningful default here, although the LDAP libraries might
- have one already set. Generally, it should be the 'ou=Hosts'
- branch under your main directory."]
- )
-
- Puppet.setdefaults(:puppetmaster,
- :storeconfigs => [false,
- "Whether to store each client's configuration. This
- requires ActiveRecord from Ruby on Rails."]
- )
+ return @ldap
+ end
- attr_accessor :ast
+ def clear
+ initparsevars
+ end
- class << self
- attr_writer :ldap
- end
- # just shorten the constant path a bit, using what amounts to an alias
- AST = Puppet::Parser::AST
-
- # Create an ldap connection. This is a class method so others can call
- # it and use the same variables and such.
- def self.ldap
- unless defined? @ldap and @ldap
- if Puppet[:ldapssl]
- @ldap = LDAP::SSLConn.new(Puppet[:ldapserver], Puppet[:ldapport])
- elsif Puppet[:ldaptls]
- @ldap = LDAP::SSLConn.new(
- Puppet[:ldapserver], Puppet[:ldapport], true
- )
- else
- @ldap = LDAP::Conn.new(Puppet[:ldapserver], Puppet[:ldapport])
+ # Iteratively evaluate all of the objects. This finds all fo the
+ # objects that represent definitions and evaluates the definitions appropriately.
+ # It also adds defaults and overrides as appropriate.
+ def evaliterate(scope)
+ count = 0
+ begin
+ timeout 300 do
+ while ary = scope.unevaluated
+ ary.each do |resource|
+ resource.evaluate
end
- @ldap.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
- @ldap.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
- @ldap.simple_bind(Puppet[:ldapuser], Puppet[:ldappassword])
end
-
- return @ldap
end
+ rescue Timeout::Error
+ raise Puppet::DevError, "Got a timeout trying to evaluate all definitions"
+ end
+ end
- # create our interpreter
- def initialize(hash)
- if @code = hash[:Code]
- @file = nil # to avoid warnings
- elsif ! @file = hash[:Manifest]
- raise Puppet::DevError, "You must provide code or a manifest"
- end
+ # Evaluate a specific node.
+ def evalnode(client, scope, facts)
+ return unless self.usenodes
- if hash.include?(:UseNodes)
- @usenodes = hash[:UseNodes]
- else
- @usenodes = true
- end
+ unless client
+ raise Puppet::Error,
+ "Cannot evaluate nodes with a nil client"
+ end
+ names = [client]
+
+ # Make sure both the fqdn and the short name of the
+ # host can be used in the manifest
+ if client =~ /\./
+ names << client.sub(/\..+/,'')
+ else
+ names << "#{client}.#{facts['domain']}"
+ end
- # By default, we only search the parse tree.
- @nodesources = []
+ if names.empty?
+ raise Puppet::Error,
+ "Cannot evaluate nodes with a nil client"
+ end
- if Puppet[:ldapnodes]
- @nodesources << :ldap
- end
+ # Look up our node object.
+ if nodeclass = nodesearch(*names)
+ nodeclass.safeevaluate :scope => scope
+ else
+ raise Puppet::Error, "Could not find %s with names %s" %
+ [client, names.join(", ")]
+ end
+ end
- if hash[:NodeSources]
- hash[:NodeSources].each do |src|
- if respond_to? "nodesearch_#{src.to_s}"
- @nodesources << src.to_s.intern
- else
- Puppet.warning "Node source '#{src}' not supported"
- end
- end
- end
+ # Evaluate all of the code we can find that's related to our client.
+ def evaluate(client, facts)
- @setup = false
+ scope = Puppet::Parser::Scope.new(:interp => self) # no parent scope
+ scope.name = "top"
+ scope.type = "main"
- # Set it to either the value or nil. This is currently only used
- # by the cfengine module.
- @classes = hash[:Classes] || []
+ scope.host = facts["hostname"] || Facter.value("hostname")
- @local = hash[:Local] || false
+ classes = @classes.dup
- if hash.include?(:ForkSave)
- @forksave = hash[:ForkSave]
- else
- # This is just too dangerous right now. Sorry, it's going
- # to have to be slow.
- @forksave = false
- end
+ # Okay, first things first. Set our facts.
+ scope.setfacts(facts)
- if Puppet[:storeconfigs]
- Puppet::Rails.init
- end
+ # Everyone will always evaluate the top-level class, if there is one.
+ if klass = findclass("", "")
+ # Set the source, so objects can tell where they were defined.
+ scope.source = klass
+ klass.safeevaluate :scope => scope, :nosubscope => true
+ end
- @files = []
+ # Next evaluate the node
+ evalnode(client, scope, facts)
- # Create our parser object
- parsefiles
+ # If we were passed any classes, evaluate those.
+ if classes
+ classes.each do |klass|
+ if klassobj = findclass("", klass)
+ klassobj.safeevaluate :scope => scope
+ end
end
+ end
- # Search for our node in the various locations. This only searches
- # locations external to the files; the scope is responsible for
- # searching the parse tree.
- def nodesearch(*nodes)
- # At this point, stop at the first source that defines
- # the node
- @nodesources.each do |source|
- method = "nodesearch_%s" % source
- parent = nil
- nodeclasses = nil
- if self.respond_to? method
- nodes.each do |node|
- parent, nodeclasses = self.send(method, node)
-
- if parent or (nodeclasses and !nodeclasses.empty?)
- Puppet.info "Found %s in %s" % [node, source]
- return parent, nodeclasses
- else
- # Look for a default node.
- parent, nodeclasses = self.send(method, "default")
- if parent or (nodeclasses and !nodeclasses.empty?)
- Puppet.info "Found default node for %s in %s" %
- [node, source]
- return parent, nodeclasses
- end
- end
- end
- end
- end
+ # That was the first pass evaluation. Now iteratively evaluate
+ # until we've gotten rid of all of everything or thrown an error.
+ evaliterate(scope)
+
+ # Now make sure we fail if there's anything left to do
+ failonleftovers(scope)
- return nil, nil
+ # Now perform the collections
+ scope.collections.each do |coll|
+ coll.evaluate
+ end
+
+ # Now finish everything. This recursively calls finish on the
+ # contained scopes and resources.
+ scope.finish
+
+ # Store everything. We need to do this before translation, because
+ # it operates on resources, not transobjects.
+ if Puppet[:storeconfigs]
+ args = {
+ :resources => scope.resources,
+ :name => client,
+ :facts => facts
+ }
+ unless scope.classlist.empty?
+ args[:classes] = scope.classlist
end
- # Find the ldap node and extra the info, returning just
- # the critical data.
- def nodesearch_ldap(node)
- unless defined? @ldap and @ldap
- setup_ldap()
- unless @ldap
- Puppet.info "Skipping ldap source; no ldap connection"
- return nil, []
- end
- end
+ storeconfigs(args)
+ end
- if node =~ /\./
- node = node.sub(/\..+/, '')
- end
+ # Now, finally, convert our scope tree + resources into a tree of
+ # buckets and objects.
+ objects = scope.translate
- filter = Puppet[:ldapstring]
- attrs = Puppet[:ldapattrs].split("\s*,\s*")
- sattrs = attrs.dup
- pattr = nil
- if pattr = Puppet[:ldapparentattr]
- if pattr == ""
- pattr = nil
- else
- sattrs << pattr
- end
- end
+ # Add the class list
+ unless scope.classlist.empty?
+ objects.classes = scope.classlist
+ end
- if filter =~ /%s/
- filter = filter.gsub(/%s/, node)
- end
+ return objects
+ end
- parent = nil
- classes = []
-
- found = false
- count = 0
- begin
- # We're always doing a sub here; oh well.
- @ldap.search(Puppet[:ldapbase], 2, filter, sattrs) do |entry|
- found = true
- if pattr
- if values = entry.vals(pattr)
- if values.length > 1
- raise Puppet::Error,
- "Node %s has more than one parent: %s" %
- [node, values.inspect]
- end
- unless values.empty?
- parent = values.shift
- end
- end
- end
+ # Fail if there any overrides left to perform.
+ def failonleftovers(scope)
+ overrides = scope.overrides
+ if overrides.empty?
+ return nil
+ else
+ fail Puppet::ParseError,
+ "Could not find object(s) %s" % overrides.collect { |o|
+ o.ref
+ }.join(", ")
+ end
+ end
- attrs.each { |attr|
- if values = entry.vals(attr)
- values.each do |v| classes << v end
- end
- }
- end
- rescue => detail
- if count == 0
- # Try reconnecting to ldap
- @ldap = nil
- setup_ldap()
- retry
- else
- raise Puppet::Error, "LDAP Search failed: %s" % detail
- end
- end
+ # Find a class definition, relative to the current namespace.
+ def findclass(namespace, name)
+ fqfind namespace, name, @classtable
+ end
- classes.flatten!
+ # Find a component definition, relative to the current namespace.
+ def finddefine(namespace, name)
+ fqfind namespace, name, @definetable
+ end
- return parent, classes
- end
+ # The recursive method used to actually look these objects up.
+ def fqfind(namespace, name, table)
+ if name =~ /^::/ or namespace == ""
+ return table[name.sub(/^::/, '')]
+ end
+ ary = namespace.split("::")
- def parsedate
- parsefiles()
- @parsedate
+ while ary.length > 0
+ newname = (ary + [name]).join("::").sub(/^::/, '')
+ if obj = table[newname]
+ return obj
end
- # Add a new file to check for updateness.
- def newfile(file)
- unless @files.find { |f| f.file == file }
- @files << Puppet::LoadedFile.new(file)
- end
- end
+ # Delete the second to last object, which reduces our namespace by one.
+ ary.pop
+ end
- # evaluate our whole tree
- def run(client, facts)
- # We have to leave this for after initialization because there
- # seems to be a problem keeping ldap open after a fork.
- unless @setup
- @nodesources.each { |source|
- method = "setup_%s" % source.to_s
- if respond_to? method
- begin
- self.send(method)
- rescue => detail
- raise Puppet::Error,
- "Could not set up node source %s" % source
- end
- end
- }
- end
- parsefiles()
+ # If we've gotten to this point without finding it, see if the name
+ # exists at the top namespace
+ if obj = table[name]
+ return obj
+ end
+
+ return nil
+ end
+
+ # Create a new node, just from a list of names, classes, and an optional parent.
+ def gennode(name, hash)
+ facts = hash[:facts]
+ classes = hash[:classes]
+ parent = hash[:parentnode]
+ arghash = {
+ :name => name,
+ :code => AST::ASTArray.new(:pin => "[]"),
+ :interp => self,
+ :fqname => name
+ }
+ classes = [classes] unless classes.is_a?(Array)
+
+ classcode = @parser.ast(AST::ASTArray, :children => classes.collect do |klass|
+ @parser.ast(AST::FlatString, :value => klass)
+ end)
+
+ # Now generate a function call.
+ code = @parser.ast(AST::Function,
+ :name => "include",
+ :arguments => classcode,
+ :ftype => :statement
+ )
+
+ if parent
+ arghash[:parentclass] = parent
+ end
+
+ # Create the node
+ return @parser.ast(AST::Node, arghash)
+ end
+
+ # create our interpreter
+ def initialize(hash)
+ if @code = hash[:Code]
+ @file = nil # to avoid warnings
+ elsif ! @file = hash[:Manifest]
+ devfail "You must provide code or a manifest"
+ end
+
+ if hash.include?(:UseNodes)
+ @usenodes = hash[:UseNodes]
+ else
+ @usenodes = true
+ end
+
+ # By default, we only search for parsed nodes.
+ @nodesources = [:code]
- # Really, we should stick multiple names in here
- # but for now just make a simple array
- names = [client]
+ if Puppet[:ldapnodes]
+ # Nodes in the file override nodes in ldap.
+ @nodesources << :ldap
+ end
- # Make sure both the fqdn and the short name of the
- # host can be used in the manifest
- if client =~ /\./
- names << client.sub(/\..+/,'')
+ if hash[:NodeSources]
+ unless hash[:NodeSources].is_a?(Array)
+ hash[:NodeSources] = [hash[:NodeSources]]
+ end
+ hash[:NodeSources].each do |src|
+ if respond_to? "nodesearch_#{src.to_s}"
+ @nodesources << src.to_s.intern
else
- names << "#{client}.#{facts['domain']}"
+ Puppet.warning "Node source '#{src}' not supported"
end
+ end
+ end
- scope = Puppet::Parser::Scope.new() # no parent scope
- scope.name = "top"
- scope.type = "puppet"
- scope.interp = self
+ @setup = false
- classes = @classes.dup
+ initparsevars()
- args = {:ast => @ast, :facts => facts, :classes => classes}
+ # Set it to either the value or nil. This is currently only used
+ # by the cfengine module.
+ @classes = hash[:Classes] || []
- if @usenodes
- unless client
- raise Puppet::Error,
- "Cannot evaluate nodes with a nil client"
- end
+ @local = hash[:Local] || false
- args[:names] = names
+ if hash.include?(:ForkSave)
+ @forksave = hash[:ForkSave]
+ else
+ # This is just too dangerous right now. Sorry, it's going
+ # to have to be slow.
+ @forksave = false
+ end
+
+ # The class won't always be defined during testing.
+ if Puppet[:storeconfigs] and defined? ActiveRecord::Base
+ Puppet::Rails.init
+ end
+
+ @files = []
+
+ # Create our parser object
+ parsefiles
+ end
+
+ # Initialize or reset the variables related to parsing.
+ def initparsevars
+ @classtable = {}
+ @namespace = "main"
+
+ @nodetable = {}
+
+ @definetable = {}
+ end
+
+ # Find the ldap node and extra the info, returning just
+ # the critical data.
+ def ldapsearch(node)
+ unless defined? @ldap and @ldap
+ setup_ldap()
+ unless @ldap
+ Puppet.info "Skipping ldap source; no ldap connection"
+ return nil, []
+ end
+ end
- parent, nodeclasses = nodesearch(*names)
+ if node =~ /\./
+ node = node.sub(/\..+/, '')
+ end
- args[:classes] += nodeclasses if nodeclasses
+ filter = Puppet[:ldapstring]
+ attrs = Puppet[:ldapattrs].split("\s*,\s*")
+ sattrs = attrs.dup
+ pattr = nil
+ if pattr = Puppet[:ldapparentattr]
+ if pattr == ""
+ pattr = nil
+ else
+ sattrs << pattr
+ end
+ end
- args[:parentnode] = parent if parent
+ if filter =~ /%s/
+ filter = filter.gsub(/%s/, node)
+ end
- if nodeclasses or parent
- args[:searched] = true
+ parent = nil
+ classes = []
+
+ found = false
+ count = 0
+ begin
+ # We're always doing a sub here; oh well.
+ @ldap.search(Puppet[:ldapbase], 2, filter, sattrs) do |entry|
+ found = true
+ if pattr
+ if values = entry.vals(pattr)
+ if values.length > 1
+ raise Puppet::Error,
+ "Node %s has more than one parent: %s" %
+ [node, values.inspect]
+ end
+ unless values.empty?
+ parent = values.shift
+ end
end
end
- begin
- objects = scope.evaluate(args)
- rescue Puppet::DevError, Puppet::Error, Puppet::ParseError => except
- raise
- rescue => except
- error = Puppet::DevError.new("%s: %s" %
- [except.class, except.message])
- error.set_backtrace except.backtrace
- raise error
- end
+ attrs.each { |attr|
+ if values = entry.vals(attr)
+ values.each do |v| classes << v end
+ end
+ }
+ end
+ rescue => detail
+ if count == 0
+ # Try reconnecting to ldap
+ @ldap = nil
+ setup_ldap()
+ retry
+ else
+ raise Puppet::Error, "LDAP Search failed: %s" % detail
+ end
+ end
- if Puppet[:storeconfigs]
- storeconfigs(
- :objects => objects,
- :host => client,
- :facts => facts
- )
- end
+ classes.flatten!
+
+ return parent, classes
+ 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
- return objects
+ # Create a new class, or merge with an existing class.
+ def newclass(fqname, options = {})
+ if @definetable.include?(fqname)
+ raise Puppet::ParseError, "Cannot redefine class %s as a definition" %
+ fqname
+ end
+ code = options[:code]
+ parent = options[:parent]
+
+ # If the class is already defined, then add code to it.
+ if other = @classtable[fqname]
+ # Make sure the parents match
+ if parent and other.parentclass and (parent != other.parentclass)
+ @parser.error @parser.addcontext("Class %s is already defined" % fqname) +
+ " with parent %s" % [fqname, other.parentclass]
end
- # Connect to the LDAP Server
- def setup_ldap
- self.class.ldap = nil
- begin
- require 'ldap'
- rescue LoadError
- Puppet.notice(
- "Could not set up LDAP Connection: Missing ruby/ldap libraries"
- )
- @ldap = nil
- return
+ # This might be dangerous...
+ if parent and ! other.parentclass
+ other.parentclass = parent
+ end
+
+ # This might just be an empty, stub class.
+ if code
+ tmp = fqname
+ if tmp == ""
+ tmp = "main"
end
- begin
- @ldap = self.class.ldap()
- rescue => detail
- raise Puppet::Error, "Could not connect to LDAP: %s" % detail
+
+ Puppet.debug @parser.addcontext("Adding code to %s" % tmp)
+ # Else, add our code to it.
+ if other.code and code
+ other.code.children += code.children
+ else
+ other.code ||= code
end
end
+ else
+ # Define it anew.
+ ns, name = namesplit(fqname)
+ args = {:type => name, :namespace => ns, :fqname => fqname, :interp => self}
+ args[:code] = code if code
+ args[:parentclass] = parent if parent
+ @classtable[fqname] = @parser.ast AST::HostClass, args
+ end
- def scope
- return @scope
- end
+ return @classtable[fqname]
+ end
- private
+ # Create a new definition.
+ def newdefine(fqname, options = {})
+ if @classtable.include?(fqname)
+ raise Puppet::ParseError, "Cannot redefine class %s as a definition" %
+ fqname
+ end
+ # Make sure our definition doesn't already exist
+ if other = @definetable[fqname]
+ @parser.error @parser.addcontext(
+ "%s is already defined at line %s" % [fqname, other.line],
+ other
+ )
+ end
- # Check whether any of our files have changed.
- def checkfiles
- if @files.find { |f| f.changed? }
- @parsedate = Time.now.to_i
- end
+ ns, name = namesplit(fqname)
+ args = {
+ :type => name,
+ :namespace => ns,
+ :arguments => options[:arguments],
+ :code => options[:code],
+ :fqname => fqname
+ }
+
+ [:code, :arguments].each do |param|
+ args[param] = options[param] if options[param]
+ end
+
+ @definetable[fqname] = @parser.ast AST::Component, args
+ end
+
+ # Create a new node. Nodes are special, because they're stored in a global
+ # table, not according to namespaces.
+ def newnode(names, options = {})
+ names = [names] unless names.instance_of?(Array)
+ names.collect do |name|
+ if other = @nodetable[name]
+ @parser.error @parser.addcontext("Node %s is already defined" % [other.name], other)
+ end
+ name = name.to_s if name.is_a?(Symbol)
+ args = {
+ :name => name,
+ }
+ if options[:code]
+ args[:code] = options[:code]
+ end
+ if options[:parent]
+ args[:parentclass] = options[:parent]
end
+ @nodetable[name] = @parser.ast(AST::Node, args)
+ @nodetable[name].fqname = name
+ @nodetable[name]
+ @nodetable[name].interp = self
+ @nodetable[name]
+ end
+ end
+
+ # Add a new file to be checked when we're checking to see if we should be
+ # reparsed.
+ def newfile(*files)
+ files.each do |file|
+ unless file.is_a? Puppet::LoadedFile
+ file = Puppet::LoadedFile.new(file)
+ end
+ @files << file
+ end
+ end
- # Parse the files, generating our parse tree. This automatically
- # reparses only if files are updated, so it's safe to call multiple
- # times.
- def parsefiles
- # First check whether there are updates to any non-puppet files
- # like templates. If we need to reparse, this will get quashed,
- # but it needs to be done first in case there's no reparse
- # but there are other file changes.
- checkfiles()
-
- # Check if the parser should reparse.
- if @file
- if defined? @parser
- if stamp = @parser.reparse?
- Puppet.notice "Reloading files"
- else
- return false
+ # Search for our node in the various locations.
+ def nodesearch(*nodes)
+ # At this point, stop at the first source that defines
+ # the node
+ @nodesources.each do |source|
+ method = "nodesearch_%s" % source
+ if self.respond_to? method
+ # Do an inverse sort on the length, so the longest match always
+ # wins
+ nodes.sort { |a,b| b.length <=> a.length }.each do |node|
+ node = node.to_s if node.is_a?(Symbol)
+ if obj = self.send(method, node)
+ nsource = obj.file || source
+ Puppet.info "Found %s in %s" % [node, nsource]
+ return obj
+ else
+ # Look for a default node.
+ if defobj = self.send(method, "default")
+ Puppet.info "Found default node for %s in %s" %
+ [node, source]
+ return defobj
end
end
+ end
+ end
+ end
- unless FileTest.exists?(@file)
- if @ast
- return
- else
- raise Puppet::Error, "Manifest %s must exist" % @file
- end
+ return nil
+ end
+
+ # See if our node was defined in the code.
+ def nodesearch_code(name)
+ @nodetable[name]
+ end
+
+ # Look for our node in ldap.
+ def nodesearch_ldap(node)
+ parent, classes = ldapsearch(node)
+ if parent or classes
+ args = {}
+ args[:classes] = classes if classes and ! classes.empty?
+ args[:parentnode] = parent if parent
+ return gennode(node, args)
+ else
+ return nil
+ end
+ end
+
+ def parsedate
+ parsefiles()
+ @parsedate
+ end
+
+ # evaluate our whole tree
+ def run(client, facts)
+ # We have to leave this for after initialization because there
+ # seems to be a problem keeping ldap open after a fork.
+ unless @setup
+ @nodesources.each { |source|
+ method = "setup_%s" % source.to_s
+ if respond_to? method
+ exceptwrap :type => Puppet::Error,
+ :message => "Could not set up node source %s" % source do
+ self.send(method)
end
end
+ }
+ end
+ parsefiles()
+
+ # Evaluate all of the appropriate code.
+ objects = evaluate(client, facts)
+
+ # And return it all.
+ return objects
+ end
+
+ # Connect to the LDAP Server
+ def setup_ldap
+ self.class.ldap = nil
+ begin
+ require 'ldap'
+ rescue LoadError
+ Puppet.notice(
+ "Could not set up LDAP Connection: Missing ruby/ldap libraries"
+ )
+ @ldap = nil
+ return
+ end
+ begin
+ @ldap = self.class.ldap()
+ rescue => detail
+ raise Puppet::Error, "Could not connect to LDAP: %s" % detail
+ end
+ end
+
+ def scope
+ return @scope
+ end
+
+ # Iteratively make sure that every object in the scope tree is translated.
+ def translate(scope)
+ end
+
+ private
- # should i be creating a new parser each time...?
- @parser = Puppet::Parser::Parser.new()
- if @code
- @parser.string = @code
+ # Check whether any of our files have changed.
+ def checkfiles
+ if @files.find { |f| f.changed? }
+ @parsedate = Time.now.to_i
+ end
+ end
+
+ # Parse the files, generating our parse tree. This automatically
+ # reparses only if files are updated, so it's safe to call multiple
+ # times.
+ def parsefiles
+ # First check whether there are updates to any non-puppet files
+ # like templates. If we need to reparse, this will get quashed,
+ # but it needs to be done first in case there's no reparse
+ # but there are other file changes.
+ checkfiles()
+
+ # Check if the parser should reparse.
+ if @file
+ if defined? @parser
+ if stamp = @parser.reparse?
+ Puppet.notice "Reloading files"
else
- @parser.file = @file
- # Mark when we parsed, so we can check freshness
- @parsedate = File.stat(@file).ctime.to_i
+ return false
end
+ end
- if @local
- @ast = @parser.parse
+ unless FileTest.exists?(@file)
+ # If we've already parsed, then we're ok.
+ if findclass("", "")
+ return
else
- benchmark(:info, "Parsed manifest") do
- @ast = @parser.parse
- end
+ raise Puppet::Error, "Manifest %s must exist" % @file
end
- @parsedate = Time.now.to_i
end
+ end
- # Store the configs into the database.
- def storeconfigs(hash)
- unless defined? ActiveRecord
- require 'puppet/rails'
- unless defined? ActiveRecord
- raise LoadError,
- "storeconfigs is enabled but rails is unavailable"
- end
- end
+ # Reset our parse tables.
+ clear()
+
+ # Create a new parser, just to keep things fresh.
+ @parser = Puppet::Parser::Parser.new(self)
+ if @code
+ @parser.string = @code
+ else
+ @parser.file = @file
+ # Mark when we parsed, so we can check freshness
+ @parsedate = File.stat(@file).ctime.to_i
+ end
- Puppet::Rails.init
-
- # Fork the storage, since we don't need the client waiting
- # on that. How do I avoid this duplication?
- if @forksave
- fork {
- # We store all of the objects, even the collectable ones
- benchmark(:info, "Stored configuration for #{hash[:client]}") do
- # Try to batch things a bit, by putting them into
- # a transaction
- Puppet::Rails::Host.transaction do
- Puppet::Rails::Host.store(hash)
- end
- end
- }
- else
- # We store all of the objects, even the collectable ones
- benchmark(:info, "Stored configuration for #{hash[:client]}") do
- Puppet::Rails::Host.transaction do
- Puppet::Rails::Host.store(hash)
- end
+ # Parsing stores all classes and defines and such in their
+ # various tables, so we don't worry about the return.
+ if @local
+ @parser.parse
+ else
+ benchmark(:info, "Parsed manifest") do
+ @parser.parse
+ end
+ end
+ @parsedate = Time.now.to_i
+ end
+
+ # Store the configs into the database.
+ def storeconfigs(hash)
+ unless defined? ActiveRecord
+ require 'puppet/rails'
+ unless defined? ActiveRecord
+ raise LoadError,
+ "storeconfigs is enabled but rails is unavailable"
+ end
+ end
+
+ Puppet::Rails.init
+
+ # Fork the storage, since we don't need the client waiting
+ # on that. How do I avoid this duplication?
+ if @forksave
+ fork {
+ # We store all of the objects, even the collectable ones
+ benchmark(:info, "Stored configuration for #{hash[:name]}") do
+ # Try to batch things a bit, by putting them into
+ # a transaction
+ Puppet::Rails::Host.transaction do
+ Puppet::Rails::Host.store(hash)
end
end
-
- # Now that we've stored everything, we need to strip out
- # the collectable objects so that they are not sent on
- # to the host
- hash[:objects].collectstrip!
+ }
+ else
+ # We store all of the objects, even the collectable ones
+ benchmark(:info, "Stored configuration for #{hash[:name]}") do
+ Puppet::Rails::Host.transaction do
+ Puppet::Rails::Host.store(hash)
+ end
end
end
+
+ # Now that we've stored everything, we need to strip out
+ # the collectable objects so that they are not sent on
+ # to the host
+ #hash[:objects].collectstrip!
end
end
diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb
index 80a8715ba..39fef8668 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -12,6 +12,8 @@ module Puppet
class Lexer
attr_reader :line, :last, :file
+ attr_accessor :indefine
+
#%r{\w+} => :WORD,
@@tokens = {
%r{#.*} => :COMMENT,
@@ -31,10 +33,13 @@ module Puppet
%r{<} => :LESSTHAN,
%r{<=} => :LESSEQUAL,
%r{!=} => :NOTEQUAL,
+ %r{!} => :NOT,
%r{,} => :COMMA,
%r{\.} => :DOT,
%r{:} => :COLON,
%r{@} => :AT,
+ %r{<<\|} => :LLCOLLECT,
+ %r{\|>>} => :RRCOLLECT,
%r{<\|} => :LCOLLECT,
%r{\|>} => :RCOLLECT,
%r{;} => :SEMIC,
@@ -42,6 +47,8 @@ module Puppet
%r{\\} => :BACKSLASH,
%r{=>} => :FARROW,
%r{[a-z][-\w]*} => :NAME,
+ %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME,
+ %r{([A-Z][-\w]*::)+[A-Z][-\w]*} => :CLASSREF,
%r{[A-Z][-\w]*} => :TYPE,
%r{[0-9]+} => :NUMBER,
%r{\$\w+} => :VARIABLE
@@ -59,9 +66,15 @@ module Puppet
"else" => :ELSE,
"inherits" => :INHERITS,
"node" => :NODE,
- "true" => :BOOLEAN
+ "true" => :BOOLEAN,
+ "and" => :AND,
+ "or" => :OR
}
+ def clear
+ initvars
+ end
+
# scan the whole file
# basically just used for testing
def fullscan
@@ -90,14 +103,47 @@ module Puppet
}
end
+ def indefine?
+ if defined? @indefine
+ @indefine
+ else
+ false
+ end
+ end
+
def initialize
+ initvars()
+ end
+
+ def initvars
@line = 1
@last = ""
+ @lasttoken = nil
@scanner = nil
@file = nil
# AAARRGGGG! okay, regexes in ruby are bloody annoying
# no one else has "\n" =~ /\s/
@skip = %r{[ \t]+}
+
+ @namestack = []
+ @indefine = false
+ end
+
+ # Go up one in the namespace.
+ def namepop
+ @namestack.pop
+ end
+
+ # Collect the current namespace.
+ def namespace
+ @namestack.join("::")
+ end
+
+ # This value might have :: in it, but we don't care -- it'll be
+ # handled normally when joining, and when popping we want to pop
+ # this full value, however long the namespace is.
+ def namestack(value)
+ @namestack << value
end
def rest
@@ -164,6 +210,7 @@ module Puppet
# if this gets much more complicated, it should
# be moved up to where the tokens themselves are defined
# which will get me about 75% of the way to a lexer generator
+ ptoken = stoken
case stoken
when :NAME then
wtoken = stoken
@@ -171,36 +218,51 @@ module Puppet
if @@keywords.include?(value)
wtoken = @@keywords[value]
#Puppet.debug("token '%s'" % wtoken)
+ if wtoken == :BOOLEAN
+ value = eval(value)
+ end
end
- yield [wtoken,value]
- @last = value
+ ptoken = wtoken
when :NUMBER then
- yield [:NAME,value]
- # just throw comments away
+ ptoken = :NAME
when :COMMENT then
# just throw comments away
+ next
when :RETURN then
@line += 1
@scanner.skip(@skip)
+ next
when :SQUOTE then
#Puppet.debug("searching '%s' after '%s'" % [self.rest,value])
value = self.slurpstring(value)
- yield [:SQTEXT,value]
- @last = value
- #stoken = :DQTEXT
+ ptoken = :SQTEXT
#Puppet.debug("got string '%s' => '%s'" % [:DQTEXT,value])
when :DQUOTE then
- #Puppet.debug("searching '%s' after '%s'" % [self.rest,value])
value = self.slurpstring(value)
- yield [:DQTEXT,value]
- @last = value
- #stoken = :DQTEXT
- #Puppet.debug("got string '%s' => '%s'" % [:DQTEXT,value])
- else
- #Puppet.debug("got token '%s' => '%s'" % [stoken,value])
- yield [stoken,value]
- @last = value
+ ptoken = :DQTEXT
+ when :VARIABLE then
+ value = value.sub(/^\$/, '')
+ end
+
+ yield [ptoken, value]
+
+ if @lasttoken == :CLASS
+ namestack(value)
end
+
+ if @lasttoken == :DEFINE
+ if indefine?
+ self.indefine = false
+ raise Puppet::ParseError,
+ "Definitions cannot nest"
+ end
+
+ @indefine = true
+ end
+
+ @last = value
+ @lasttoken = ptoken
+
@scanner.skip(@skip)
end
@scanner = nil
diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb
index 3cda43ee0..047dace3a 100644
--- a/lib/puppet/parser/parser.rb
+++ b/lib/puppet/parser/parser.rb
@@ -29,12 +29,24 @@ module Puppet
class Parser < Racc::Parser
-module_eval <<'..end grammar.ra modeval..idc4b6d943e3', 'grammar.ra', 603
+module_eval <<'..end grammar.ra modeval..ide506d3a623', 'grammar.ra', 621
require 'puppet/parser/functions'
-attr_reader :file
+attr_reader :file, :interp
attr_accessor :files
+# Add context to a message; useful for error messages and such.
+def addcontext(message, obj = nil)
+ obj ||= @lexer
+
+ message += " on line %s" % obj.line
+ if file = obj.file
+ message += " in file %s" % file
+ end
+
+ return message
+end
+
# Create an AST array out of all of the args
def aryfy(*args)
if args[0].instance_of?(AST::ASTArray)
@@ -66,6 +78,17 @@ def ast(klass, hash = nil)
return klass.new(hash)
end
+# Raise a Parse error.
+def error(message)
+ except = Puppet::ParseError.new(message)
+ except.line = @lexer.line
+ if @lexer.file
+ except.file = @lexer.file
+ end
+
+ raise except
+end
+
def file=(file)
unless FileTest.exists?(file)
unless file =~ /\.pp$/
@@ -83,23 +106,20 @@ def file=(file)
end
end
-def initialize
+def initialize(interpreter)
+ @interp = interpreter
+ initvars()
+end
+
+# Initialize or reset all of our variables.
+def initvars
@lexer = Puppet::Parser::Lexer.new()
@files = []
- #if Puppet[:debug]
- # @yydebug = true
- #end
end
-# Add a new file to be checked when we're checking to see if we should be
-# reparsed.
-def newfile(*files)
- files.each do |file|
- unless file.is_a? Puppet::LoadedFile
- file = Puppet::LoadedFile.new(file)
- end
- @files << file
- end
+# The fully qualifed name, with the full namespace.
+def fqname(name)
+ [@lexer.namespace, name].join("::").sub(/^::/, '')
end
def on_error(token,value,stack)
@@ -123,7 +143,7 @@ def parse(string = nil)
self.string = string
end
begin
- yyparse(@lexer,:scan)
+ main = yyparse(@lexer,:scan)
rescue Racc::ParseError => except
error = Puppet::ParseError.new(except)
error.line = @lexer.line
@@ -150,6 +170,13 @@ def parse(string = nil)
error.set_backtrace except.backtrace
raise error
end
+ if main
+ # Store the results as the top-level class.
+ interp.newclass("", :code => main)
+ return main
+ end
+ensure
+ @lexer.clear
end
# See if any of the files have changed.
@@ -172,363 +199,413 @@ end
# $Id$
-..end grammar.ra modeval..idc4b6d943e3
+..end grammar.ra modeval..ide506d3a623
##### racc 1.4.5 generates ###
racc_reduce_table = [
0, 0, :racc_error,
- 1, 44, :_reduce_1,
- 1, 44, :_reduce_none,
- 1, 45, :_reduce_none,
- 2, 45, :_reduce_4,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 1, 47, :_reduce_none,
- 4, 55, :_reduce_16,
- 2, 55, :_reduce_17,
- 1, 59, :_reduce_none,
- 3, 59, :_reduce_19,
- 1, 60, :_reduce_none,
- 1, 60, :_reduce_none,
- 1, 60, :_reduce_none,
- 5, 48, :_reduce_23,
- 5, 48, :_reduce_24,
- 5, 48, :_reduce_25,
- 2, 49, :_reduce_26,
- 3, 50, :_reduce_27,
- 4, 69, :_reduce_28,
- 1, 64, :_reduce_none,
- 3, 64, :_reduce_30,
- 0, 65, :_reduce_none,
- 1, 65, :_reduce_none,
- 1, 61, :_reduce_33,
- 1, 68, :_reduce_34,
- 1, 70, :_reduce_none,
- 1, 70, :_reduce_none,
- 1, 70, :_reduce_none,
- 1, 70, :_reduce_none,
- 1, 70, :_reduce_none,
- 1, 70, :_reduce_none,
- 3, 51, :_reduce_41,
- 0, 66, :_reduce_42,
- 1, 66, :_reduce_43,
- 3, 66, :_reduce_44,
- 3, 74, :_reduce_45,
- 1, 75, :_reduce_none,
- 3, 75, :_reduce_47,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 1, 73, :_reduce_none,
- 4, 79, :_reduce_57,
- 1, 63, :_reduce_58,
- 1, 63, :_reduce_59,
- 1, 77, :_reduce_60,
- 4, 78, :_reduce_61,
- 6, 53, :_reduce_62,
- 0, 81, :_reduce_none,
- 4, 81, :_reduce_64,
+ 1, 51, :_reduce_1,
+ 1, 51, :_reduce_none,
+ 1, 52, :_reduce_none,
+ 2, 52, :_reduce_4,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 4, 62, :_reduce_17,
+ 2, 62, :_reduce_18,
+ 1, 67, :_reduce_none,
+ 3, 67, :_reduce_20,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 5, 55, :_reduce_24,
+ 5, 55, :_reduce_25,
+ 5, 55, :_reduce_26,
+ 4, 66, :_reduce_27,
+ 2, 56, :_reduce_28,
+ 1, 77, :_reduce_29,
+ 2, 77, :_reduce_30,
+ 2, 57, :_reduce_31,
+ 1, 78, :_reduce_none,
+ 1, 78, :_reduce_none,
+ 3, 79, :_reduce_34,
+ 3, 79, :_reduce_35,
+ 1, 80, :_reduce_none,
1, 80, :_reduce_none,
- 5, 52, :_reduce_66,
+ 3, 80, :_reduce_38,
+ 1, 81, :_reduce_none,
+ 3, 81, :_reduce_40,
1, 82, :_reduce_none,
- 2, 82, :_reduce_68,
- 5, 83, :_reduce_69,
- 4, 83, :_reduce_70,
+ 1, 82, :_reduce_none,
+ 3, 83, :_reduce_43,
+ 3, 83, :_reduce_44,
+ 1, 84, :_reduce_none,
1, 84, :_reduce_none,
- 3, 84, :_reduce_72,
- 3, 71, :_reduce_73,
- 1, 86, :_reduce_none,
- 3, 86, :_reduce_75,
- 1, 88, :_reduce_none,
- 3, 88, :_reduce_77,
- 3, 87, :_reduce_78,
+ 4, 86, :_reduce_47,
+ 1, 72, :_reduce_none,
+ 3, 72, :_reduce_49,
+ 0, 73, :_reduce_none,
+ 1, 73, :_reduce_none,
+ 1, 69, :_reduce_52,
+ 1, 88, :_reduce_53,
+ 1, 87, :_reduce_none,
+ 1, 87, :_reduce_none,
+ 1, 87, :_reduce_none,
+ 1, 87, :_reduce_none,
+ 1, 87, :_reduce_none,
+ 1, 87, :_reduce_none,
+ 3, 58, :_reduce_60,
+ 0, 74, :_reduce_61,
+ 1, 74, :_reduce_62,
+ 3, 74, :_reduce_63,
+ 3, 92, :_reduce_64,
+ 1, 93, :_reduce_none,
+ 3, 93, :_reduce_66,
1, 85, :_reduce_none,
1, 85, :_reduce_none,
1, 85, :_reduce_none,
1, 85, :_reduce_none,
1, 85, :_reduce_none,
1, 85, :_reduce_none,
- 1, 85, :_reduce_85,
- 2, 54, :_reduce_86,
- 6, 56, :_reduce_87,
- 5, 56, :_reduce_88,
- 6, 57, :_reduce_89,
- 5, 57, :_reduce_90,
- 6, 58, :_reduce_91,
- 5, 58, :_reduce_92,
1, 91, :_reduce_none,
- 3, 91, :_reduce_94,
- 1, 92, :_reduce_95,
- 1, 92, :_reduce_96,
- 1, 92, :_reduce_97,
- 0, 46, :_reduce_98,
- 1, 89, :_reduce_none,
- 3, 89, :_reduce_100,
- 3, 89, :_reduce_101,
- 1, 93, :_reduce_none,
- 3, 93, :_reduce_103,
- 3, 94, :_reduce_104,
- 1, 94, :_reduce_105,
- 3, 94, :_reduce_106,
- 1, 94, :_reduce_107,
- 1, 90, :_reduce_none,
- 2, 90, :_reduce_109,
- 1, 62, :_reduce_110,
- 1, 95, :_reduce_111,
- 3, 72, :_reduce_112,
- 2, 72, :_reduce_113,
- 1, 76, :_reduce_none,
- 1, 76, :_reduce_none,
- 0, 67, :_reduce_none,
- 1, 67, :_reduce_117 ]
-
-racc_reduce_n = 118
-
-racc_shift_n = 197
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 4, 96, :_reduce_82,
+ 1, 71, :_reduce_83,
+ 1, 71, :_reduce_84,
+ 1, 95, :_reduce_85,
+ 4, 76, :_reduce_86,
+ 4, 76, :_reduce_87,
+ 6, 60, :_reduce_88,
+ 0, 98, :_reduce_none,
+ 4, 98, :_reduce_90,
+ 1, 97, :_reduce_none,
+ 5, 59, :_reduce_92,
+ 1, 99, :_reduce_none,
+ 2, 99, :_reduce_94,
+ 5, 100, :_reduce_95,
+ 4, 100, :_reduce_96,
+ 1, 101, :_reduce_none,
+ 3, 101, :_reduce_98,
+ 3, 89, :_reduce_99,
+ 1, 103, :_reduce_none,
+ 3, 103, :_reduce_101,
+ 1, 105, :_reduce_none,
+ 3, 105, :_reduce_103,
+ 3, 104, :_reduce_104,
+ 1, 102, :_reduce_none,
+ 1, 102, :_reduce_none,
+ 1, 102, :_reduce_none,
+ 1, 102, :_reduce_none,
+ 1, 102, :_reduce_none,
+ 1, 102, :_reduce_none,
+ 1, 102, :_reduce_111,
+ 2, 61, :_reduce_112,
+ 6, 63, :_reduce_113,
+ 5, 63, :_reduce_114,
+ 6, 64, :_reduce_115,
+ 5, 64, :_reduce_116,
+ 6, 65, :_reduce_117,
+ 5, 65, :_reduce_118,
+ 1, 106, :_reduce_none,
+ 1, 106, :_reduce_none,
+ 1, 109, :_reduce_none,
+ 3, 109, :_reduce_122,
+ 1, 110, :_reduce_none,
+ 1, 110, :_reduce_none,
+ 1, 110, :_reduce_none,
+ 0, 53, :_reduce_126,
+ 0, 111, :_reduce_127,
+ 1, 107, :_reduce_none,
+ 3, 107, :_reduce_129,
+ 3, 107, :_reduce_130,
+ 1, 112, :_reduce_none,
+ 3, 112, :_reduce_132,
+ 3, 113, :_reduce_133,
+ 1, 113, :_reduce_134,
+ 3, 113, :_reduce_135,
+ 1, 113, :_reduce_136,
+ 1, 108, :_reduce_none,
+ 2, 108, :_reduce_138,
+ 1, 70, :_reduce_139,
+ 3, 90, :_reduce_140,
+ 2, 90, :_reduce_141,
+ 1, 94, :_reduce_none,
+ 1, 94, :_reduce_none,
+ 0, 75, :_reduce_none,
+ 1, 75, :_reduce_145 ]
+
+racc_reduce_n = 146
+
+racc_shift_n = 240
racc_action_table = [
- 48, 36, 38, 81, 162, 20, 48, 36, 38, 64,
- 79, 161, 48, 36, 38, 86, 20, 36, 38, 75,
- 36, 38, 20, 37, -79, 145, 36, 38, 20, 44,
- 37, -82, -79, 49, 53, 44, 31, 55, 31, 49,
- 53, 44, 72, 55, 65, 49, 53, -81, 44, 55,
- 48, 36, 38, 37, 44, 145, 48, 36, 38, 37,
- 37, 137, 48, 36, 38, 113, 20, 139, 29, 79,
- 29, 33, 20, 33, -80, 79, 85, 170, 20, 44,
- 154, 146, 102, 49, 53, 44, 115, 55, 171, 49,
- 53, 44, 149, 55, 77, 49, 53, 36, 38, 55,
- 48, 36, 38, 36, 38, 116, 48, 36, 38, 117,
- 118, 88, 48, 36, 38, 179, 20, 117, 118, -81,
- 45, 87, 20, 112, 155, 44, -82, 158, 20, 44,
- 37, 44, 105, 49, 53, 44, 37, 55, 64, 49,
- 53, 44, 163, 55, 77, 49, 53, 85, 84, 55,
- 48, 36, 38, -80, 169, 72, 48, 36, 38, 172,
- 173, -83, 48, 36, 38, -84, 20, 178, 108, 136,
- 182, 77, 20, 36, 38, 112, 71, 160, 20, 44,
- 109, 70, 69, 49, 53, 44, 113, 55, 20, 49,
- 53, 44, 190, 55, 66, 49, 93, 36, 38, 55,
- 112, 44, 35, 28, 166, 49, 53, 36, 38, 55,
- 125, nil, 20, 36, 38, nil, nil, nil, nil, 36,
- 38, nil, 20, nil, nil, 44, nil, nil, 20, 49,
- 53, nil, nil, 55, 20, 44, nil, nil, nil, 49,
- 53, 44, nil, 55, nil, 49, 53, 44, nil, 55,
- nil, 49, 53, 36, 38, 55, nil, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 20, 176,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- 20, 44, nil, nil, 168, 49, 53, nil, 12, 55,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, 175,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- 20, 3, nil, 9, 196, 14, nil, 21, 12, nil,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, 153,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- 20, 3, nil, 9, 185, 14, nil, 21, 12, nil,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, 189,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- 20, 3, nil, 9, 195, 14, nil, 21, 12, nil,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, 148,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- 20, 3, nil, 9, 193, 14, nil, 21, 12, nil,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, nil,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- 20, 3, nil, 9, nil, 14, nil, 21, 12, nil,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, nil,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- 20, 3, nil, 9, nil, 14, nil, 21, 12, nil,
- 16, 19, nil, 24, 26, 20, 3, nil, 9, nil,
- 14, nil, 21, 12, nil, 16, 19, nil, 24, 26,
- nil, 3, nil, 9, nil, 14, nil, 21 ]
+ 59, 50, 52, 50, 52, 97, 59, 50, 52, 33,
+ 146, 75, 59, 50, 52, 76, 69, -105, 59, 50,
+ 52, 171, 111, 120, 59, 50, 52, 117, 69, 32,
+ 84, 45, 38, 45, 69, 64, 67, 45, 54, 70,
+ 69, 64, 108, 45, 146, 70, 137, 64, 67, 45,
+ 150, 70, 121, 64, 67, 45, 39, 70, 178, 64,
+ 67, 50, 52, 70, 59, 50, 52, 50, 52, 122,
+ 59, 50, 52, 48, 134, 135, 59, 50, 52, 75,
+ 69, 99, 59, 50, 52, -110, 69, 124, 59, 50,
+ 52, 45, 69, 120, 143, 45, 54, 45, 69, 64,
+ 67, 45, 54, 70, 69, 64, 67, 45, 126, 70,
+ -107, 64, 67, 45, -108, 70, 139, 64, 67, 45,
+ 183, 70, 87, 64, 67, 138, 99, 70, 59, 50,
+ 52, -105, 173, 45, 59, 50, 52, 177, 54, 205,
+ 59, 50, 52, 119, 69, 134, 135, 50, 52, 197,
+ 69, 208, 173, 50, 52, 179, 111, 177, 180, 45,
+ 41, 215, 111, 64, 67, 45, 198, 70, 111, 64,
+ 67, 45, 41, 70, 214, 64, 163, 45, 124, 70,
+ 124, 64, 163, 45, -106, 70, 210, 64, 163, 50,
+ 52, 70, 35, 209, 42, 50, 52, 43, 202, 34,
+ 35, 120, 50, 52, 111, 164, 42, 34, 99, 43,
+ 111, 50, 52, 50, 52, 50, 52, 111, 150, 45,
+ 50, 52, 147, 64, 163, 45, 111, 70, 111, 64,
+ 163, -107, 45, 70, 152, 111, 64, 163, 154, 155,
+ 70, 45, -108, 45, 211, 64, 163, 64, 163, 70,
+ 45, 70, 212, 87, 64, 163, 87, 87, 70, 48,
+ 50, 52, 213, 56, 45, 219, 140, 45, 45, 54,
+ 134, 135, 54, 54, -105, 224, 17, 154, 155, 46,
+ 216, 84, 206, 124, 76, -106, 14, -109, 20, 23,
+ 45, 1, 5, 17, 9, 54, 12, -108, 16, 217,
+ 24, -107, -110, 14, 56, 20, 23, 150, 1, 5,
+ 17, 9, 82, 12, -106, 16, 220, 24, 225, 227,
+ 14, 81, 20, 23, 145, 1, 5, 17, 9, 127,
+ 12, 124, 16, 232, 24, 77, 141, 14, 234, 20,
+ 23, 131, 1, 5, 17, 9, 132, 12, 30, 16,
+ 235, 24, 151, nil, 14, nil, 20, 23, nil, 1,
+ 5, 17, 9, nil, 12, nil, 16, 193, 24, nil,
+ nil, 14, nil, 20, 23, nil, 1, 5, 17, 9,
+ nil, 12, nil, 16, 238, 24, nil, nil, 14, nil,
+ 20, 23, nil, 1, 5, 17, 9, nil, 12, nil,
+ 16, 181, 24, nil, nil, 14, nil, 20, 23, nil,
+ 1, 5, 17, 9, nil, 12, nil, 16, 239, 24,
+ nil, nil, 14, nil, 20, 23, nil, 1, 5, 17,
+ 9, nil, 12, nil, 16, nil, 24, nil, nil, 14,
+ nil, 20, 23, nil, 1, 5, 17, 9, nil, 12,
+ nil, 16, nil, 24, nil, nil, 14, nil, 20, 23,
+ nil, 1, 5, 17, 9, nil, 12, nil, 16, nil,
+ 24, nil, nil, 14, nil, 20, 23, nil, 1, 5,
+ 17, 9, nil, 12, nil, 16, nil, 24, nil, nil,
+ 14, nil, 20, 23, nil, 1, 5, 17, 9, nil,
+ 12, nil, 16, nil, 24, nil, nil, 14, nil, 20,
+ 23, nil, 1, 5, nil, 9, nil, 12, nil, 16,
+ nil, 24 ]
racc_action_check = [
- 48, 48, 48, 48, 133, 21, 86, 86, 86, 17,
- 39, 133, 137, 137, 137, 57, 48, 16, 16, 30,
- 79, 79, 86, 21, 98, 170, 45, 45, 137, 48,
- 170, 99, 57, 48, 48, 86, 3, 48, 75, 86,
- 86, 137, 30, 86, 17, 137, 137, 100, 79, 137,
- 69, 69, 69, 79, 45, 105, 119, 119, 119, 45,
- 105, 101, 172, 172, 172, 93, 69, 103, 3, 121,
- 75, 3, 119, 75, 92, 80, 93, 141, 172, 69,
- 121, 107, 65, 69, 69, 119, 80, 69, 141, 119,
- 119, 172, 111, 119, 112, 172, 172, 85, 85, 172,
- 12, 12, 12, 9, 9, 83, 14, 14, 14, 83,
- 83, 62, 113, 113, 113, 156, 12, 156, 156, 61,
- 9, 60, 14, 90, 122, 85, 59, 128, 113, 12,
- 85, 9, 66, 12, 12, 14, 9, 12, 68, 14,
- 14, 113, 135, 14, 136, 113, 113, 53, 52, 113,
- 173, 173, 173, 51, 140, 70, 158, 158, 158, 142,
- 144, 50, 64, 64, 64, 46, 173, 153, 72, 95,
- 161, 35, 158, 131, 131, 164, 28, 131, 64, 173,
- 74, 26, 24, 173, 173, 158, 77, 173, 131, 158,
- 158, 64, 178, 158, 19, 64, 64, 88, 88, 64,
- 76, 131, 6, 2, 138, 131, 131, 87, 87, 131,
- 87, nil, 88, 125, 125, nil, nil, nil, nil, 162,
- 162, nil, 87, nil, nil, 88, nil, nil, 125, 88,
- 88, nil, nil, 88, 162, 87, nil, nil, nil, 87,
- 87, 125, nil, 87, nil, 125, 125, 162, nil, 125,
- nil, 162, 162, 180, 180, 162, nil, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 180, 147,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- 147, 180, nil, nil, 139, 180, 180, nil, 147, 180,
- 147, 147, nil, 147, 147, 139, 147, nil, 147, 146,
- 147, nil, 147, 139, nil, 139, 139, nil, 139, 139,
- 146, 139, nil, 139, 194, 139, nil, 139, 146, nil,
- 146, 146, nil, 146, 146, 194, 146, nil, 146, 120,
- 146, nil, 146, 194, nil, 194, 194, nil, 194, 194,
- 120, 194, nil, 194, 167, 194, nil, 194, 120, nil,
- 120, 120, nil, 120, 120, 167, 120, nil, 120, 174,
- 120, nil, 120, 167, nil, 167, 167, nil, 167, 167,
- 174, 167, nil, 167, 192, 167, nil, 167, 174, nil,
- 174, 174, nil, 174, 174, 192, 174, nil, 174, 109,
- 174, nil, 174, 192, nil, 192, 192, nil, 192, 192,
- 109, 192, nil, 192, 182, 192, nil, 192, 109, nil,
- 109, 109, nil, 109, 109, 182, 109, nil, 109, nil,
- 109, nil, 109, 182, nil, 182, 182, nil, 182, 182,
- 84, 182, nil, 182, nil, 182, nil, 182, 84, nil,
- 84, 84, nil, 84, 84, 190, 84, nil, 84, nil,
- 84, nil, 84, 190, nil, 190, 190, nil, 190, 190,
- 5, 190, nil, 190, nil, 190, nil, 190, 5, nil,
- 5, 5, nil, 5, 5, 0, 5, nil, 5, nil,
- 5, nil, 5, 0, nil, 0, 0, nil, 0, 0,
- nil, 0, nil, 0, nil, 0, nil, 0 ]
+ 75, 75, 75, 46, 46, 44, 56, 56, 56, 2,
+ 108, 17, 153, 153, 153, 17, 75, 187, 146, 146,
+ 146, 123, 56, 108, 59, 59, 59, 59, 153, 2,
+ 44, 75, 6, 46, 146, 75, 75, 56, 46, 75,
+ 59, 56, 56, 153, 124, 56, 89, 153, 153, 146,
+ 125, 153, 72, 146, 146, 59, 6, 146, 128, 59,
+ 59, 99, 99, 59, 30, 30, 30, 120, 120, 74,
+ 48, 48, 48, 67, 89, 89, 14, 14, 14, 69,
+ 30, 98, 16, 16, 16, 68, 48, 76, 202, 202,
+ 202, 99, 14, 67, 98, 30, 99, 120, 16, 30,
+ 30, 48, 120, 30, 202, 48, 48, 14, 77, 48,
+ 66, 14, 14, 16, 65, 14, 93, 16, 16, 202,
+ 133, 16, 136, 202, 202, 93, 165, 202, 212, 212,
+ 212, 63, 215, 136, 216, 216, 216, 215, 136, 165,
+ 147, 147, 147, 61, 212, 133, 133, 167, 167, 148,
+ 216, 167, 127, 210, 210, 130, 147, 127, 130, 212,
+ 97, 175, 167, 212, 212, 216, 149, 212, 210, 216,
+ 216, 147, 9, 216, 175, 147, 147, 167, 150, 147,
+ 151, 167, 167, 210, 57, 167, 169, 210, 210, 223,
+ 223, 210, 23, 169, 97, 122, 122, 97, 158, 23,
+ 5, 163, 119, 119, 223, 119, 9, 5, 47, 9,
+ 122, 139, 139, 138, 138, 20, 20, 119, 113, 223,
+ 164, 164, 109, 223, 223, 122, 139, 223, 138, 122,
+ 122, 107, 119, 122, 118, 164, 119, 119, 118, 118,
+ 119, 139, 106, 138, 172, 139, 139, 138, 138, 139,
+ 164, 138, 173, 87, 164, 164, 39, 38, 164, 12,
+ 12, 12, 174, 12, 87, 182, 95, 39, 38, 87,
+ 95, 95, 39, 38, 104, 204, 182, 204, 204, 12,
+ 177, 36, 166, 180, 33, 185, 182, 71, 182, 182,
+ 12, 182, 182, 166, 182, 12, 182, 188, 182, 178,
+ 182, 189, 190, 166, 32, 166, 166, 200, 166, 166,
+ 178, 166, 27, 166, 101, 166, 194, 166, 206, 209,
+ 178, 24, 178, 178, 100, 178, 178, 194, 178, 80,
+ 178, 82, 178, 218, 178, 19, 96, 194, 225, 194,
+ 194, 84, 194, 194, 218, 194, 86, 194, 1, 194,
+ 227, 194, 115, nil, 218, nil, 218, 218, nil, 218,
+ 218, 227, 218, nil, 218, nil, 218, 141, 218, nil,
+ nil, 227, nil, 227, 227, nil, 227, 227, 141, 227,
+ nil, 227, nil, 227, 236, 227, nil, nil, 141, nil,
+ 141, 141, nil, 141, 141, 236, 141, nil, 141, nil,
+ 141, 132, 141, nil, nil, 236, nil, 236, 236, nil,
+ 236, 236, 132, 236, nil, 236, nil, 236, 237, 236,
+ nil, nil, 132, nil, 132, 132, nil, 132, 132, 237,
+ 132, nil, 132, nil, 132, nil, 132, nil, nil, 237,
+ nil, 237, 237, nil, 237, 237, 22, 237, nil, 237,
+ nil, 237, nil, 237, nil, nil, 22, nil, 22, 22,
+ nil, 22, 22, 234, 22, nil, 22, nil, 22, nil,
+ 22, nil, nil, 234, nil, 234, 234, nil, 234, 234,
+ 121, 234, nil, 234, nil, 234, nil, 234, nil, nil,
+ 121, nil, 121, 121, nil, 121, 121, 0, 121, nil,
+ 121, nil, 121, nil, 121, nil, nil, 0, nil, 0,
+ 0, nil, 0, 0, nil, 0, nil, 0, nil, 0,
+ nil, 0 ]
racc_action_pointer = [
- 457, nil, 203, 32, nil, 442, 196, nil, nil, 100,
- nil, nil, 98, nil, 104, nil, 14, 3, nil, 158,
- nil, -13, nil, nil, 169, nil, 145, nil, 176, nil,
- 9, nil, nil, nil, nil, 135, nil, nil, nil, 0,
- nil, nil, nil, nil, nil, 23, 146, nil, -2, nil,
- 142, 134, 142, 127, nil, nil, nil, 13, nil, 107,
- 102, 100, 105, nil, 160, 40, 112, nil, 132, 48,
- 122, nil, 132, nil, 174, 34, 190, 177, nil, 17,
- 65, nil, nil, 100, 412, 94, 4, 204, 194, nil,
- 113, nil, 55, 56, nil, 152, nil, nil, 5, 12,
- 28, 24, nil, 61, nil, 24, nil, 75, nil, 382,
- nil, 85, 58, 110, nil, nil, nil, nil, nil, 54,
- 322, 59, 119, nil, nil, 210, nil, nil, 118, nil,
- nil, 170, nil, -6, nil, 135, 108, 10, 197, 277,
- 133, 67, 146, nil, 147, nil, 292, 262, nil, nil,
- nil, nil, nil, 140, nil, nil, 108, nil, 154, nil,
- nil, 164, 216, nil, 165, nil, nil, 337, nil, nil,
- -6, nil, 60, 148, 352, nil, nil, nil, 186, nil,
- 250, nil, 397, nil, nil, nil, nil, nil, nil, nil,
- 427, nil, 367, nil, 307, nil, nil ]
+ 479, 335, -9, nil, nil, 162, 13, nil, nil, 168,
+ nil, nil, 257, nil, 74, nil, 80, 9, nil, 335,
+ 212, nil, 428, 154, 279, nil, nil, 306, nil, nil,
+ 62, nil, 298, 278, nil, nil, 246, nil, 235, 234,
+ nil, nil, nil, nil, -5, nil, 0, 198, 68, nil,
+ nil, nil, nil, nil, nil, nil, 4, 163, nil, 22,
+ nil, 122, nil, 110, nil, 93, 89, 71, 64, 77,
+ nil, 266, 46, nil, 63, -2, 49, 108, nil, nil,
+ 307, nil, 293, nil, 303, nil, 340, 231, nil, 26,
+ nil, nil, nil, 101, nil, 222, 330, 156, 71, 58,
+ 319, 293, nil, nil, 253, nil, 221, 210, 1, 183,
+ nil, nil, nil, 208, nil, 335, nil, nil, 229, 199,
+ 64, 462, 192, 16, 35, 40, nil, 119, 52, nil,
+ 148, nil, 394, 97, nil, nil, 100, nil, 210, 208,
+ nil, 360, nil, nil, nil, nil, 16, 138, 142, 159,
+ 140, 142, nil, 10, nil, nil, nil, nil, 189, nil,
+ nil, nil, nil, 179, 217, 116, 275, 144, nil, 176,
+ nil, nil, 237, 239, 239, 151, nil, 267, 292, nil,
+ 245, nil, 258, nil, nil, 264, nil, -4, 276, 280,
+ 281, nil, nil, nil, 309, nil, nil, nil, nil, nil,
+ 297, nil, 86, nil, 268, nil, 289, nil, nil, 313,
+ 150, nil, 126, nil, nil, 99, 132, nil, 326, nil,
+ nil, nil, nil, 186, nil, 332, nil, 343, nil, nil,
+ nil, nil, nil, nil, 445, nil, 377, 411, nil, nil ]
racc_action_default = [
- -98, -12, -118, -118, -13, -1, -118, -14, -2, -33,
- -15, -3, -118, -5, -118, -6, -118, -118, -7, -118,
- -34, -118, -8, -9, -118, -10, -118, -11, -118, -95,
- -98, -96, -93, -97, -4, -42, -58, -33, -59, -17,
- -18, -20, -21, -22, -110, -118, -51, -55, -118, -60,
- -56, -50, -118, -33, -52, -85, -54, -49, -65, -53,
- -118, -48, -118, -86, -42, -118, -98, -26, -118, -118,
- -98, 197, -118, -108, -118, -118, -116, -118, -43, -118,
- -118, -113, -46, -118, -118, -118, -118, -118, -118, -84,
- -116, -83, -37, -33, -29, -118, -38, -40, -36, -39,
- -35, -31, -27, -118, -99, -98, -41, -118, -109, -118,
- -94, -118, -117, -118, -19, -16, -112, -114, -115, -118,
- -118, -118, -118, -80, -79, -118, -82, -81, -118, -73,
- -74, -118, -67, -118, -71, -118, -42, -32, -118, -118,
- -118, -118, -105, -102, -107, -111, -118, -118, -92, -25,
- -44, -45, -47, -63, -57, -61, -118, -76, -118, -68,
- -66, -118, -118, -24, -116, -30, -23, -118, -88, -100,
- -118, -101, -118, -118, -118, -90, -91, -62, -118, -75,
- -118, -78, -118, -72, -28, -87, -103, -104, -106, -89,
- -118, -77, -118, -70, -118, -69, -64 ]
+ -126, -146, -146, -16, -5, -146, -146, -6, -7, -146,
+ -8, -9, -33, -10, -146, -11, -146, -32, -12, -146,
+ -146, -13, -1, -146, -29, -14, -2, -146, -15, -3,
+ -146, -28, -146, -146, -120, -119, -126, -31, -126, -126,
+ -121, -124, -123, -125, -126, -139, -146, -18, -146, -19,
+ -83, -21, -84, -22, -52, -23, -61, -75, -77, -146,
+ -79, -146, -91, -74, -85, -78, -73, -52, -76, -53,
+ -111, -81, -146, -80, -146, -146, -61, -146, -112, -4,
+ -126, -30, -61, -60, -146, -137, -146, -126, -46, -146,
+ -45, -37, -39, -146, -36, -146, -146, -146, -146, -146,
+ -146, -56, -57, -59, -55, -62, -58, -54, -52, -50,
+ -110, -53, -109, -144, -48, -146, -65, -141, -146, -146,
+ -146, -146, -146, -146, -146, -144, 240, -127, -146, -128,
+ -146, -138, -146, -146, -42, -41, -146, -35, -146, -146,
+ -34, -146, -122, -17, -20, -86, -146, -51, -146, -146,
+ -145, -61, -140, -146, -142, -143, -106, -105, -146, -108,
+ -99, -107, -100, -52, -146, -146, -146, -146, -93, -146,
+ -97, -87, -146, -136, -146, -146, -131, -134, -146, -27,
+ -146, -116, -146, -40, -38, -69, -71, -68, -72, -67,
+ -70, -43, -44, -118, -146, -64, -49, -24, -25, -63,
+ -144, -66, -146, -102, -146, -82, -89, -94, -92, -146,
+ -146, -26, -146, -129, -130, -146, -146, -114, -146, -115,
+ -117, -47, -104, -146, -101, -146, -88, -146, -98, -135,
+ -132, -133, -113, -103, -146, -96, -146, -146, -95, -90 ]
racc_goto_table = [
- 5, 76, 34, 43, 32, 8, 58, 42, 62, 111,
- 63, 132, 39, 143, 150, 51, 52, 51, 130, 94,
- 74, 128, 134, 135, 177, 96, 89, 119, 97, 131,
- 90, 83, 138, 129, 101, 156, 103, 114, 30, 43,
- 67, 141, 82, 42, 2, nil, nil, nil, 80, 89,
- 89, 51, nil, nil, 159, nil, 157, nil, 100, 128,
- 107, nil, 99, 106, nil, 134, nil, 92, nil, nil,
- nil, 104, 51, 43, nil, nil, 110, 42, 186, 43,
- 122, 127, 127, 42, 120, 126, 126, 89, 121, 51,
- 123, 123, 165, 89, nil, nil, 183, 184, 96, 89,
- 180, 97, 164, nil, nil, nil, nil, 151, nil, 147,
- 140, 191, nil, 152, 128, nil, 51, 34, nil, 127,
- nil, nil, 51, 126, 89, 127, nil, nil, 123, 126,
- nil, 100, nil, 41, 123, 99, 57, nil, 57, 167,
- 92, nil, 89, nil, 34, 68, 174, nil, nil, nil,
- nil, nil, 181, nil, nil, nil, 127, nil, nil, nil,
- 126, 51, nil, nil, 34, 123, 187, 188, nil, 41,
- nil, 34, 57, 91, 127, 51, 51, nil, 126, nil,
- nil, nil, 192, 123, nil, nil, nil, nil, 98, 34,
- 194, 34, nil, 57, nil, nil, 91, 91, nil, nil,
- nil, nil, nil, 41, nil, nil, nil, nil, nil, 41,
- 57, 124, 124, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, 142,
- nil, nil, nil, nil, 91, nil, nil, 57, nil, nil,
- 91, nil, nil, 57, nil, nil, 91, nil, nil, 124,
- nil, nil, nil, nil, nil, 124, nil, nil, nil, nil,
- nil, 98, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, 91, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, 57, nil, nil, nil, 124, nil, nil, 91,
- nil, nil, nil, nil, 142, nil, 57, 57, nil, nil,
- nil, nil, nil, nil, 124 ]
+ 22, 79, 51, 162, 102, 47, 113, 55, 62, 40,
+ 74, 114, 103, 153, 158, 78, 176, 170, 109, 149,
+ 168, 89, 95, 72, 83, 199, 125, 36, 88, 88,
+ 86, 172, 130, 191, 192, 226, 51, 167, 96, 98,
+ 26, 55, 100, 148, 144, 80, 104, 73, 203, 73,
+ 160, 107, 31, 116, 204, 199, 53, 118, 128, 158,
+ 37, 44, 170, 73, 184, 207, 174, 175, 19, 123,
+ 133, nil, nil, nil, nil, nil, 85, 88, nil, nil,
+ nil, 73, 90, 90, 85, nil, 186, 186, nil, 51,
+ 53, nil, 73, nil, 55, 102, nil, 142, nil, 223,
+ 106, 200, 196, 103, 230, 228, 221, 233, 73, 157,
+ 51, 112, 157, 165, 161, 55, nil, 161, 158, nil,
+ 129, 166, nil, nil, nil, nil, 88, nil, 187, 187,
+ nil, 90, 182, 189, 189, nil, nil, 104, nil, nil,
+ 195, 194, 107, 53, nil, 79, nil, 201, nil, nil,
+ nil, nil, nil, nil, 157, nil, nil, 157, nil, 161,
+ 110, 79, 161, 159, 53, 101, 159, nil, nil, nil,
+ nil, nil, nil, 79, 112, nil, nil, 112, 218, 73,
+ 90, nil, 188, 188, nil, nil, 73, nil, nil, nil,
+ nil, 106, nil, 112, 112, nil, 222, 79, nil, nil,
+ 157, nil, 112, nil, nil, 161, 229, nil, 159, nil,
+ 231, 159, nil, 157, nil, 79, 79, nil, 161, 112,
+ nil, nil, 112, 110, nil, nil, 110, 236, 156, nil,
+ nil, 156, nil, nil, 237, 73, nil, nil, nil, nil,
+ nil, nil, 190, 190, nil, 73, nil, 185, 185, 73,
+ nil, 110, nil, nil, 159, nil, 101, nil, nil, nil,
+ nil, nil, nil, nil, nil, 112, nil, 159, 110, nil,
+ nil, 110, nil, 156, nil, nil, 156, nil, 112, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, 110, nil, nil, nil, nil, 156,
+ nil, nil, nil, nil, nil, nil, nil, 110, nil, nil,
+ nil, nil, 156 ]
racc_goto_check = [
- 2, 23, 4, 20, 49, 3, 30, 19, 30, 24,
- 20, 40, 16, 51, 31, 25, 37, 25, 44, 26,
- 47, 42, 42, 24, 38, 28, 34, 33, 29, 39,
- 23, 32, 22, 43, 21, 45, 46, 17, 48, 20,
- 5, 50, 30, 19, 1, nil, nil, nil, 16, 34,
- 34, 25, nil, nil, 40, nil, 44, nil, 20, 42,
- 47, nil, 19, 30, nil, 42, nil, 25, nil, nil,
- nil, 3, 25, 20, nil, nil, 49, 19, 51, 20,
- 30, 20, 20, 19, 2, 19, 19, 34, 16, 25,
- 25, 25, 26, 34, nil, nil, 42, 24, 28, 34,
- 33, 29, 23, nil, nil, nil, nil, 30, nil, 2,
- 3, 44, nil, 30, 42, nil, 25, 4, nil, 20,
- nil, nil, 25, 19, 34, 20, nil, nil, 25, 19,
- nil, 20, nil, 18, 25, 19, 18, nil, 18, 2,
- 25, nil, 34, nil, 4, 18, 2, nil, nil, nil,
- nil, nil, 30, nil, nil, nil, 20, nil, nil, nil,
- 19, 25, nil, nil, 4, 25, 30, 30, nil, 18,
- nil, 4, 18, 36, 20, 25, 25, nil, 19, nil,
- nil, nil, 2, 25, nil, nil, nil, nil, 18, 4,
- 2, 4, nil, 18, nil, nil, 36, 36, nil, nil,
- nil, nil, nil, 18, nil, nil, nil, nil, nil, 18,
- 18, 18, 18, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, 18,
- nil, nil, nil, nil, 36, nil, nil, 18, nil, nil,
- 36, nil, nil, 18, nil, nil, 36, nil, nil, 18,
- nil, nil, nil, nil, nil, 18, nil, nil, nil, nil,
- nil, 18, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, 36, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, 18, nil, nil, nil, 18, nil, nil, 36,
- nil, nil, nil, nil, 18, nil, 18, 18, nil, nil,
- nil, nil, nil, nil, 18 ]
+ 2, 4, 19, 54, 39, 17, 24, 21, 41, 60,
+ 41, 36, 40, 44, 52, 21, 63, 52, 22, 25,
+ 50, 30, 30, 47, 41, 42, 24, 56, 19, 19,
+ 58, 25, 24, 35, 35, 48, 19, 49, 58, 17,
+ 3, 21, 41, 23, 18, 56, 19, 26, 54, 26,
+ 53, 21, 5, 41, 55, 42, 20, 43, 57, 52,
+ 29, 59, 52, 26, 31, 50, 61, 62, 1, 41,
+ 30, nil, nil, nil, nil, nil, 3, 19, nil, nil,
+ nil, 26, 20, 20, 3, nil, 39, 39, nil, 19,
+ 20, nil, 26, nil, 21, 39, nil, 60, nil, 44,
+ 20, 24, 36, 40, 63, 52, 25, 54, 26, 19,
+ 19, 46, 19, 17, 21, 21, nil, 21, 52, nil,
+ 3, 2, nil, nil, nil, nil, 19, nil, 19, 19,
+ nil, 20, 2, 21, 21, nil, nil, 19, nil, nil,
+ 41, 2, 21, 20, nil, 4, nil, 41, nil, nil,
+ nil, nil, nil, nil, 19, nil, nil, 19, nil, 21,
+ 45, 4, 21, 20, 20, 38, 20, nil, nil, nil,
+ nil, nil, nil, 4, 46, nil, nil, 46, 2, 26,
+ 20, nil, 20, 20, nil, nil, 26, nil, nil, nil,
+ nil, 20, nil, 46, 46, nil, 41, 4, nil, nil,
+ 19, nil, 46, nil, nil, 21, 41, nil, 20, nil,
+ 41, 20, nil, 19, nil, 4, 4, nil, 21, 46,
+ nil, nil, 46, 45, nil, nil, 45, 2, 38, nil,
+ nil, 38, nil, nil, 2, 26, nil, nil, nil, nil,
+ nil, nil, 45, 45, nil, 26, nil, 38, 38, 26,
+ nil, 45, nil, nil, 20, nil, 38, nil, nil, nil,
+ nil, nil, nil, nil, nil, 46, nil, 20, 45, nil,
+ nil, 45, nil, 38, nil, nil, 38, nil, 46, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, 45, nil, nil, nil, nil, 38,
+ nil, nil, nil, nil, nil, nil, nil, 45, nil, nil,
+ nil, nil, 38 ]
racc_goto_pointer = [
- nil, 44, 0, 5, -3, 19, nil, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, 3, -42, 124, -2,
- -6, -30, -69, -34, -67, 3, -45, nil, -39, -36,
- -6, -98, -17, -56, -38, nil, 109, 4, -129, -59,
- -77, nil, -66, -54, -69, -90, -30, -10, 35, 1,
- -64, -92, nil ]
+ nil, 68, 0, 40, -21, 50, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, -7, -55, -10,
+ 44, -5, -38, -66, -50, -94, 33, nil, nil, 54,
+ -17, -72, nil, nil, nil, -105, -45, nil, 109, -52,
+ -44, -6, -125, -2, -105, 104, 55, 9, -171, -85,
+ -102, nil, -105, -69, -116, -110, 22, -22, -6, 52,
+ 0, -61, -60, -111 ]
racc_goto_default = [
- nil, nil, nil, 73, 11, 13, 15, 18, 22, 23,
- 25, 27, 1, 4, 7, 10, nil, 40, 17, 59,
- 61, nil, nil, nil, nil, 6, nil, 95, 54, 56,
- nil, 78, nil, nil, 46, 47, 50, nil, nil, nil,
- nil, 133, 60, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, 144 ]
+ nil, nil, nil, 94, 29, 4, 7, 8, 10, 11,
+ 13, 15, 18, 21, 25, 28, 3, nil, 49, 63,
+ 65, 66, nil, nil, nil, nil, 27, 2, 6, nil,
+ nil, 91, 136, 92, 93, nil, nil, 115, 57, 58,
+ 60, nil, 105, nil, nil, 68, 71, nil, nil, nil,
+ nil, 169, 61, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil ]
racc_token_table = {
false => 0,
@@ -550,34 +627,41 @@ racc_token_table = {
:DOT => 16,
:COLON => 17,
:TYPE => 18,
- :QMARK => 19,
- :LPAREN => 20,
- :RPAREN => 21,
- :ISEQUAL => 22,
- :GREATEREQUAL => 23,
- :GREATERTHAN => 24,
- :LESSTHAN => 25,
- :IF => 26,
- :ELSE => 27,
- :IMPORT => 28,
- :DEFINE => 29,
- :ELSIF => 30,
- :VARIABLE => 31,
- :CLASS => 32,
- :INHERITS => 33,
- :NODE => 34,
- :BOOLEAN => 35,
- :NAME => 36,
- :SEMIC => 37,
- :CASE => 38,
- :DEFAULT => 39,
- :AT => 40,
- :LCOLLECT => 41,
- :RCOLLECT => 42 }
+ :LLCOLLECT => 19,
+ :RRCOLLECT => 20,
+ :QMARK => 21,
+ :LPAREN => 22,
+ :RPAREN => 23,
+ :ISEQUAL => 24,
+ :GREATEREQUAL => 25,
+ :GREATERTHAN => 26,
+ :LESSTHAN => 27,
+ :IF => 28,
+ :ELSE => 29,
+ :IMPORT => 30,
+ :DEFINE => 31,
+ :ELSIF => 32,
+ :VARIABLE => 33,
+ :CLASS => 34,
+ :INHERITS => 35,
+ :NODE => 36,
+ :BOOLEAN => 37,
+ :NAME => 38,
+ :SEMIC => 39,
+ :CASE => 40,
+ :DEFAULT => 41,
+ :AT => 42,
+ :LCOLLECT => 43,
+ :RCOLLECT => 44,
+ :CLASSNAME => 45,
+ :CLASSREF => 46,
+ :NOT => 47,
+ :OR => 48,
+ :AND => 49 }
racc_use_result_var = true
-racc_nt_base = 43
+racc_nt_base = 50
Racc_arg = [
racc_action_table,
@@ -615,6 +699,8 @@ Racc_token_to_s_table = [
'DOT',
'COLON',
'TYPE',
+'LLCOLLECT',
+'RRCOLLECT',
'QMARK',
'LPAREN',
'RPAREN',
@@ -639,13 +725,18 @@ Racc_token_to_s_table = [
'AT',
'LCOLLECT',
'RCOLLECT',
+'CLASSNAME',
+'CLASSREF',
+'NOT',
+'OR',
+'AND',
'$start',
'program',
'statements',
-'nothing',
+'nil',
'statement',
-'object',
-'collectable',
+'resource',
+'virtualresource',
'collection',
'assignment',
'casestatement',
@@ -655,18 +746,29 @@ Racc_token_to_s_table = [
'definition',
'hostclass',
'nodedef',
-'classnames',
-'classname',
+'resourceoverride',
+'namestrings',
+'namestring',
'name',
'variable',
'quotedtext',
-'objectinstances',
+'resourceinstances',
'endsemi',
'params',
'endcomma',
+'resourceref',
+'at',
+'collectname',
+'collectrhand',
+'collstatements',
+'collstatement',
+'colljoin',
+'collexpr',
+'colllval',
+'simplervalue',
+'resourceinst',
+'resourcename',
'type',
-'objectinst',
-'objectname',
'selector',
'array',
'rvalue',
@@ -674,7 +776,6 @@ Racc_token_to_s_table = [
'rvalues',
'comma',
'boolean',
-'objectref',
'funcrvalue',
'iftest',
'else',
@@ -685,13 +786,14 @@ Racc_token_to_s_table = [
'svalues',
'selectval',
'sintvalues',
+'fqname',
'argumentlist',
'parent',
'hostnames',
'hostname',
+'nothing',
'arguments',
-'argument',
-'lvariable']
+'argument']
Racc_debug_parser = false
@@ -699,13 +801,21 @@ Racc_debug_parser = false
# reduce 0 omitted
-module_eval <<'.,.,', 'grammar.ra', 24
+module_eval <<'.,.,', 'grammar.ra', 33
def _reduce_1( val, _values, result )
- # Make sure we always return an array.
- if val[0].is_a?(AST::ASTArray)
- result = val[0]
+ if val[0]
+ # Make sure we always return an array.
+ if val[0].is_a?(AST::ASTArray)
+ if val[0].children.empty?
+ result = nil
+ else
+ result = val[0]
+ end
+ else
+ result = aryfy(val[0])
+ end
else
- result = aryfy(val[0])
+ result = nil
end
result
end
@@ -715,13 +825,18 @@ module_eval <<'.,.,', 'grammar.ra', 24
# reduce 3 omitted
-module_eval <<'.,.,', 'grammar.ra', 35
+module_eval <<'.,.,', 'grammar.ra', 49
def _reduce_4( val, _values, result )
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[1])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[1]]
+ if val[0] and val[1]
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[1])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[1]]
+ end
+ elsif obj = (val[0] || val[1])
+ result = obj
+ else result = nil
end
result
end
@@ -749,8 +864,10 @@ module_eval <<'.,.,', 'grammar.ra', 35
# reduce 15 omitted
-module_eval <<'.,.,', 'grammar.ra', 56
- def _reduce_16( val, _values, result )
+ # reduce 16 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 71
+ def _reduce_17( val, _values, result )
args = aryfy(val[2])
result = ast AST::Function,
:name => val[0],
@@ -760,8 +877,8 @@ module_eval <<'.,.,', 'grammar.ra', 56
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 63
- def _reduce_17( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 78
+ def _reduce_18( val, _values, result )
args = aryfy(val[1])
result = ast AST::Function,
:name => val[0],
@@ -771,10 +888,10 @@ module_eval <<'.,.,', 'grammar.ra', 63
end
.,.,
- # reduce 18 omitted
+ # reduce 19 omitted
-module_eval <<'.,.,', 'grammar.ra', 82
- def _reduce_19( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 85
+ def _reduce_20( val, _values, result )
result = aryfy(val[0], val[2])
result.line = @lexer.line
result.file = @lexer.file
@@ -782,80 +899,86 @@ module_eval <<'.,.,', 'grammar.ra', 82
end
.,.,
- # reduce 20 omitted
-
# reduce 21 omitted
# reduce 22 omitted
-module_eval <<'.,.,', 'grammar.ra', 111
- def _reduce_23( val, _values, result )
+ # reduce 23 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 113
+ def _reduce_24( val, _values, result )
if val[0].instance_of?(AST::ASTArray)
- raise Puppet::ParseError, "Invalid name"
+ error "Invalid name"
end
array = val[2]
- if array.instance_of?(AST::ObjectInst)
+ if array.instance_of?(AST::ResourceInst)
array = [array]
end
result = ast AST::ASTArray
- # this iterates across each specified objectinstance
+ # this iterates across each specified resourceinstance
array.each { |instance|
- unless instance.instance_of?(AST::ObjectInst)
+ unless instance.instance_of?(AST::ResourceInst)
raise Puppet::Dev, "Got something that isn't an instance"
end
# now, i need to somehow differentiate between those things with
# arrays in their names, and normal things
- result.push ast(AST::ObjectDef,
+ result.push ast(AST::ResourceDef,
:type => val[0],
- :name => instance[0],
+ :title => instance[0],
:params => instance[1])
}
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 120
- def _reduce_24( val, _values, result )
- if val[0].instance_of?(AST::ASTArray)
- Puppet.notice "invalid name"
- raise Puppet::ParseError, "Invalid name"
- end
- # an object but without a name
- # this cannot be an instance of a library type
- result = ast AST::ObjectDef, :type => val[0], :params => val[2]
+module_eval <<'.,.,', 'grammar.ra', 116
+ def _reduce_25( val, _values, result )
+ # This is a deprecated syntax.
+ error "All resource specifications require names"
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 126
- def _reduce_25( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 122
+ def _reduce_26( val, _values, result )
# a template setting for a type
if val[0].instance_of?(AST::ASTArray)
- raise Puppet::ParseError, "Invalid type"
+ error "Invalid type"
end
- result = ast(AST::TypeDefaults, :type => val[0], :params => val[2])
+ result = ast(AST::ResourceDefaults, :type => val[0], :params => val[2])
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 149
- def _reduce_26( val, _values, result )
- unless Puppet[:storeconfigs]
- raise Puppet::ParseError, "You cannot collect without storeconfigs being set"
+module_eval <<'.,.,', 'grammar.ra', 127
+ def _reduce_27( val, _values, result )
+ result = ast AST::ResourceOverride, :object => val[0], :params => val[2]
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'grammar.ra', 154
+ def _reduce_28( val, _values, result )
+ type = val[0]
+
+ if type == :exported and ! Puppet[:storeconfigs]
+ error "You cannot collect without storeconfigs being set"
end
- if val[1].is_a? AST::TypeDefaults
- raise Puppet::ParseError, "Defaults are not collectable"
+ if val[1].is_a? AST::ResourceDefaults
+ error "Defaults are not virtualizable"
end
- # Just mark our objects as collectable and pass them through.
+ method = type.to_s + "="
+
+ # Just mark our resources as exported and pass them through.
if val[1].instance_of?(AST::ASTArray)
val[1].each do |obj|
- obj.collectable = true
+ obj.send(method, true)
end
else
- val[1].collectable = true
+ val[1].send(method, true)
end
result = val[1]
@@ -863,28 +986,130 @@ module_eval <<'.,.,', 'grammar.ra', 149
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 158
- def _reduce_27( val, _values, result )
- unless Puppet[:storeconfigs]
- raise Puppet::ParseError, "You cannot collect without storeconfigs being set"
+module_eval <<'.,.,', 'grammar.ra', 155
+ def _reduce_29( val, _values, result )
+ result = :virtual
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'grammar.ra', 156
+ def _reduce_30( val, _values, result )
+ result = :exported
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'grammar.ra', 179
+ def _reduce_31( val, _values, result )
+ if val[0] =~ /^[a-z]/
+ Puppet.warning addcontext("Collection names must now be capitalized")
+ end
+ type = val[0].downcase
+ args = {:type => type}
+
+ if val[1].is_a?(AST::CollExpr)
+ args[:query] = val[1]
+ args[:query].type = type
+ args[:form] = args[:query].form
+ else
+ args[:form] = val[1]
+ end
+ if args[:form] == :exported and ! Puppet[:storeconfigs]
+ error "You cannot collect exported resources without storeconfigs being set"
end
- result = ast AST::Collection, :type => val[0]
+ result = ast AST::Collection, args
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 162
- def _reduce_28( val, _values, result )
- result = ast AST::ObjectInst, :children => [val[0],val[2]]
+ # reduce 32 omitted
+
+ # reduce 33 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 190
+ def _reduce_34( val, _values, result )
+ if val[1]
+ result = val[1]
+ result.form = :virtual
+ else
+ result = :virtual
+ end
result
end
.,.,
- # reduce 29 omitted
+module_eval <<'.,.,', 'grammar.ra', 198
+ def _reduce_35( val, _values, result )
+ if val[1]
+ result = val[1]
+ result.form = :exported
+ else
+ result = :exported
+ end
+ result
+ end
+.,.,
-module_eval <<'.,.,', 'grammar.ra', 172
- def _reduce_30( val, _values, result )
- if val[0].instance_of?(AST::ObjectInst)
+ # reduce 36 omitted
+
+ # reduce 37 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 206
+ def _reduce_38( val, _values, result )
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+ result
+ end
+.,.,
+
+ # reduce 39 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 212
+ def _reduce_40( val, _values, result )
+ result = val[1]
+ result.parens = true
+ result
+ end
+.,.,
+
+ # reduce 41 omitted
+
+ # reduce 42 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 220
+ def _reduce_43( val, _values, result )
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+ #result = ast AST::CollExpr
+ #result.push *val
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'grammar.ra', 225
+ def _reduce_44( val, _values, result )
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+ #result = ast AST::CollExpr
+ #result.push *val
+ result
+ end
+.,.,
+
+ # reduce 45 omitted
+
+ # reduce 46 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 232
+ def _reduce_47( val, _values, result )
+ result = ast AST::ResourceInst, :children => [val[0],val[2]]
+ result
+ end
+.,.,
+
+ # reduce 48 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 242
+ def _reduce_49( val, _values, result )
+ if val[0].instance_of?(AST::ResourceInst)
result = ast AST::ASTArray, :children => [val[0],val[2]]
else
val[0].push val[2]
@@ -894,61 +1119,61 @@ module_eval <<'.,.,', 'grammar.ra', 172
end
.,.,
- # reduce 31 omitted
+ # reduce 50 omitted
- # reduce 32 omitted
+ # reduce 51 omitted
-module_eval <<'.,.,', 'grammar.ra', 179
- def _reduce_33( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 249
+ def _reduce_52( val, _values, result )
result = ast AST::Name, :value => val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 183
- def _reduce_34( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 253
+ def _reduce_53( val, _values, result )
result = ast AST::Type, :value => val[0]
result
end
.,.,
- # reduce 35 omitted
+ # reduce 54 omitted
- # reduce 36 omitted
+ # reduce 55 omitted
- # reduce 37 omitted
+ # reduce 56 omitted
- # reduce 38 omitted
+ # reduce 57 omitted
- # reduce 39 omitted
+ # reduce 58 omitted
- # reduce 40 omitted
+ # reduce 59 omitted
-module_eval <<'.,.,', 'grammar.ra', 196
- def _reduce_41( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 266
+ def _reduce_60( val, _values, result )
# this is distinct from referencing a variable
- variable = ast AST::Name, :value => val[0].sub(/^\$/,'')
+ variable = ast AST::Name, :value => val[0]
result = ast AST::VarDef, :name => variable, :value => val[2]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 201
- def _reduce_42( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 271
+ def _reduce_61( val, _values, result )
result = ast AST::ASTArray
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 201
- def _reduce_43( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 271
+ def _reduce_62( val, _values, result )
result = val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 210
- def _reduce_44( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 280
+ def _reduce_63( val, _values, result )
if val[0].instance_of?(AST::ASTArray)
val[0].push(val[2])
result = val[0]
@@ -959,18 +1184,17 @@ module_eval <<'.,.,', 'grammar.ra', 210
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 215
- def _reduce_45( val, _values, result )
- leaf = ast AST::String, :value => val[0]
- result = ast AST::ObjectParam, :param => leaf, :value => val[2]
+module_eval <<'.,.,', 'grammar.ra', 284
+ def _reduce_64( val, _values, result )
+ result = ast AST::ResourceParam, :param => val[0], :value => val[2]
result
end
.,.,
- # reduce 46 omitted
+ # reduce 65 omitted
-module_eval <<'.,.,', 'grammar.ra', 224
- def _reduce_47( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 293
+ def _reduce_66( val, _values, result )
if val[0].instance_of?(AST::ASTArray)
result = val[0].push(val[2])
else
@@ -980,26 +1204,38 @@ module_eval <<'.,.,', 'grammar.ra', 224
end
.,.,
- # reduce 48 omitted
+ # reduce 67 omitted
- # reduce 49 omitted
+ # reduce 68 omitted
- # reduce 50 omitted
+ # reduce 69 omitted
- # reduce 51 omitted
+ # reduce 70 omitted
- # reduce 52 omitted
+ # reduce 71 omitted
- # reduce 53 omitted
+ # reduce 72 omitted
- # reduce 54 omitted
+ # reduce 73 omitted
- # reduce 55 omitted
+ # reduce 74 omitted
- # reduce 56 omitted
+ # reduce 75 omitted
+
+ # reduce 76 omitted
+
+ # reduce 77 omitted
+
+ # reduce 78 omitted
+
+ # reduce 79 omitted
-module_eval <<'.,.,', 'grammar.ra', 243
- def _reduce_57( val, _values, result )
+ # reduce 80 omitted
+
+ # reduce 81 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 319
+ def _reduce_82( val, _values, result )
args = aryfy(val[2])
result = ast AST::Function,
:name => val[0],
@@ -1009,36 +1245,44 @@ module_eval <<'.,.,', 'grammar.ra', 243
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 247
- def _reduce_58( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 323
+ def _reduce_83( val, _values, result )
result = ast AST::String, :value => val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 249
- def _reduce_59( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 325
+ def _reduce_84( val, _values, result )
result = ast AST::FlatString, :value => val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 253
- def _reduce_60( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 329
+ def _reduce_85( val, _values, result )
result = ast AST::Boolean, :value => val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 257
- def _reduce_61( val, _values, result )
- result = ast AST::ObjectRef, :type => val[0], :name => val[2]
+module_eval <<'.,.,', 'grammar.ra', 334
+ def _reduce_86( val, _values, result )
+ Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized")
+ result = ast AST::ResourceRef, :type => val[0], :title => val[2]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 270
- def _reduce_62( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 336
+ def _reduce_87( val, _values, result )
+ result = ast AST::ResourceRef, :type => val[0], :title => val[2]
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'grammar.ra', 349
+ def _reduce_88( val, _values, result )
args = {
:test => val[1],
:statements => val[3]
@@ -1053,19 +1297,19 @@ module_eval <<'.,.,', 'grammar.ra', 270
end
.,.,
- # reduce 63 omitted
+ # reduce 89 omitted
-module_eval <<'.,.,', 'grammar.ra', 275
- def _reduce_64( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 354
+ def _reduce_90( val, _values, result )
result = ast AST::Else, :statements => val[2]
result
end
.,.,
- # reduce 65 omitted
+ # reduce 91 omitted
-module_eval <<'.,.,', 'grammar.ra', 287
- def _reduce_66( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 366
+ def _reduce_92( val, _values, result )
options = val[3]
unless options.instance_of?(AST::ASTArray)
options = ast AST::ASTArray, :children => [val[3]]
@@ -1075,10 +1319,10 @@ module_eval <<'.,.,', 'grammar.ra', 287
end
.,.,
- # reduce 67 omitted
+ # reduce 93 omitted
-module_eval <<'.,.,', 'grammar.ra', 297
- def _reduce_68( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 376
+ def _reduce_94( val, _values, result )
if val[0].instance_of?(AST::ASTArray)
val[0].push val[1]
result = val[0]
@@ -1089,15 +1333,15 @@ module_eval <<'.,.,', 'grammar.ra', 297
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 301
- def _reduce_69( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 380
+ def _reduce_95( val, _values, result )
result = ast AST::CaseOpt, :value => val[0], :statements => val[3]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 306
- def _reduce_70( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 385
+ def _reduce_96( val, _values, result )
result = ast(AST::CaseOpt,
:value => val[0],
:statements => ast(AST::ASTArray)
@@ -1106,10 +1350,10 @@ module_eval <<'.,.,', 'grammar.ra', 306
end
.,.,
- # reduce 71 omitted
+ # reduce 97 omitted
-module_eval <<'.,.,', 'grammar.ra', 316
- def _reduce_72( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 395
+ def _reduce_98( val, _values, result )
if val[0].instance_of?(AST::ASTArray)
val[0].push(val[2])
result = val[0]
@@ -1120,26 +1364,26 @@ module_eval <<'.,.,', 'grammar.ra', 316
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 320
- def _reduce_73( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 399
+ def _reduce_99( val, _values, result )
result = ast AST::Selector, :param => val[0], :values => val[2]
result
end
.,.,
- # reduce 74 omitted
+ # reduce 100 omitted
-module_eval <<'.,.,', 'grammar.ra', 322
- def _reduce_75( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 401
+ def _reduce_101( val, _values, result )
result = val[1]
result
end
.,.,
- # reduce 76 omitted
+ # reduce 102 omitted
-module_eval <<'.,.,', 'grammar.ra', 333
- def _reduce_77( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 412
+ def _reduce_103( val, _values, result )
if val[0].instance_of?(AST::ASTArray)
val[0].push(val[2])
result = val[0]
@@ -1150,34 +1394,34 @@ module_eval <<'.,.,', 'grammar.ra', 333
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 337
- def _reduce_78( val, _values, result )
- result = ast AST::ObjectParam, :param => val[0], :value => val[2]
+module_eval <<'.,.,', 'grammar.ra', 416
+ def _reduce_104( val, _values, result )
+ result = ast AST::ResourceParam, :param => val[0], :value => val[2]
result
end
.,.,
- # reduce 79 omitted
+ # reduce 105 omitted
- # reduce 80 omitted
+ # reduce 106 omitted
- # reduce 81 omitted
+ # reduce 107 omitted
- # reduce 82 omitted
+ # reduce 108 omitted
- # reduce 83 omitted
+ # reduce 109 omitted
- # reduce 84 omitted
+ # reduce 110 omitted
-module_eval <<'.,.,', 'grammar.ra', 347
- def _reduce_85( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 426
+ def _reduce_111( val, _values, result )
result = ast AST::Default, :value => val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 404
- def _reduce_86( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 488
+ def _reduce_112( val, _values, result )
# importing files
# yuk, i hate keywords
# we'll probably have to have some kind of search path eventually
@@ -1209,7 +1453,7 @@ module_eval <<'.,.,', 'grammar.ra', 404
end
files.each { |file|
- parser = Puppet::Parser::Parser.new()
+ parser = Puppet::Parser::Parser.new(interp)
parser.files = self.files
Puppet.debug("importing '%s'" % file)
@@ -1227,8 +1471,13 @@ module_eval <<'.,.,', 'grammar.ra', 404
end
# push the results into the main result array
# We always return an array when we parse.
- parser.parse.each do |child|
- result.push child
+ ast = parser.parse
+
+ # Things that just get added to the classtable or whatever return nil
+ if ast
+ ast.each do |child|
+ result.push child
+ end
end
}
}
@@ -1236,249 +1485,173 @@ module_eval <<'.,.,', 'grammar.ra', 404
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 420
- def _reduce_87( val, _values, result )
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :args => val[2],
- :code => val[4] # Switch to 5 for parents
- }
+module_eval <<'.,.,', 'grammar.ra', 498
+ def _reduce_113( val, _values, result )
+ interp.newdefine fqname(val[1]), :arguments => val[2], :code => val[4]
+ @lexer.indefine = false
+ result = nil
- if val[3].instance_of?(AST::Name)
- args[:parentclass] = val[3]
- end
- result = ast AST::CompDef, args
#} | DEFINE NAME argumentlist parent LBRACE RBRACE {
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 432
- def _reduce_88( val, _values, result )
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :args => val[2],
- :code => ast(AST::ASTArray)
- }
-
- if val[3].instance_of?(AST::Name)
- args[:parentclass] = val[3]
- end
-
- result = ast AST::CompDef, args
+module_eval <<'.,.,', 'grammar.ra', 502
+ def _reduce_114( val, _values, result )
+ interp.newdefine fqname(val[1]), :arguments => val[2]
+ @lexer.indefine = false
+ result = nil
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 446
- def _reduce_89( val, _values, result )
- #:args => val[2],
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :code => val[4]
- }
- # It'll be an ASTArray if we didn't get a parent
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::ClassDef, args
+module_eval <<'.,.,', 'grammar.ra', 510
+ def _reduce_115( val, _values, result )
+ # Our class gets defined in the parent namespace, not our own.
+ @lexer.namepop
+ interp.newclass fqname(val[1]), :code => val[4], :parent => val[2]
+ result = nil
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 456
- def _reduce_90( val, _values, result )
- args = {
- :type => ast(AST::Name, :value => val[1]),
- :code => ast(AST::ASTArray, :children => [])
- }
- # It'll be an ASTArray if we didn't get a parent
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::ClassDef, args
+module_eval <<'.,.,', 'grammar.ra', 515
+ def _reduce_116( val, _values, result )
+ # Our class gets defined in the parent namespace, not our own.
+ @lexer.namepop
+ interp.newclass fqname(val[1]), :parent => val[2]
+ result = nil
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 473
- def _reduce_91( val, _values, result )
- unless val[1].instance_of?(AST::ASTArray)
- val[1] = ast AST::ASTArray,
- :line => val[1].line,
- :file => val[1].file,
- :children => [val[1]]
- end
- args = {
- :names => val[1],
- :code => val[4]
- }
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::NodeDef, args
+module_eval <<'.,.,', 'grammar.ra', 520
+ def _reduce_117( val, _values, result )
+ interp.newnode val[1], :parent => val[2], :code => val[4]
+ result = nil
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 488
- def _reduce_92( val, _values, result )
- unless val[1].instance_of?(AST::ASTArray)
- val[1] = ast AST::ASTArray,
- :line => val[1].line,
- :file => val[1].file,
- :children => [val[1]]
- end
- args = {
- :names => val[1],
- :code => ast(AST::ASTArray, :children => [])
- }
- if val[2].instance_of?(AST::Name)
- args[:parentclass] = val[2]
- end
- result = ast AST::NodeDef,args
+module_eval <<'.,.,', 'grammar.ra', 523
+ def _reduce_118( val, _values, result )
+ interp.newnode val[1], :parent => val[2]
+ result = nil
result
end
.,.,
- # reduce 93 omitted
+ # reduce 119 omitted
-module_eval <<'.,.,', 'grammar.ra', 499
- def _reduce_94( val, _values, result )
- if val[0].instance_of?(AST::ASTArray)
- result = val[0]
- result.push val[2]
- else
- result = ast AST::ASTArray, :children => [val[0], val[2]]
- end
- result
- end
-.,.,
+ # reduce 120 omitted
-module_eval <<'.,.,', 'grammar.ra', 503
- def _reduce_95( val, _values, result )
- result = ast AST::HostName, :value => val[0]
- result
- end
-.,.,
+ # reduce 121 omitted
-module_eval <<'.,.,', 'grammar.ra', 505
- def _reduce_96( val, _values, result )
- result = ast AST::HostName, :value => val[0]
+module_eval <<'.,.,', 'grammar.ra', 535
+ def _reduce_122( val, _values, result )
+ result = val[0]
+ result = [result] unless result.is_a?(Array)
+ result << val[2]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 507
- def _reduce_97( val, _values, result )
- result = ast AST::Default, :value => val[0]
+ # reduce 123 omitted
+
+ # reduce 124 omitted
+
+ # reduce 125 omitted
+
+module_eval <<'.,.,', 'grammar.ra', 543
+ def _reduce_126( val, _values, result )
+ result = nil
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 511
- def _reduce_98( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 547
+ def _reduce_127( val, _values, result )
result = ast AST::ASTArray, :children => []
result
end
.,.,
- # reduce 99 omitted
+ # reduce 128 omitted
-module_eval <<'.,.,', 'grammar.ra', 516
- def _reduce_100( val, _values, result )
- result = val[1]
+module_eval <<'.,.,', 'grammar.ra', 552
+ def _reduce_129( val, _values, result )
+ result = nil
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 523
- def _reduce_101( val, _values, result )
- if val[1].instance_of?(AST::ASTArray)
- result = val[1]
- else
- result = ast AST::ASTArray, :children => [val[1]]
- end
+module_eval <<'.,.,', 'grammar.ra', 556
+ def _reduce_130( val, _values, result )
+ result = val[1]
+ result = [result] unless result[0].is_a?(Array)
result
end
.,.,
- # reduce 102 omitted
+ # reduce 131 omitted
-module_eval <<'.,.,', 'grammar.ra', 533
- def _reduce_103( val, _values, result )
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[2])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+module_eval <<'.,.,', 'grammar.ra', 563
+ def _reduce_132( val, _values, result )
+ result = val[0]
+ result = [result] unless result[0].is_a?(Array)
+ result << val[2]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 541
- def _reduce_104( val, _values, result )
- msg = "Deprecation notice: #{val[0].value} must now include '$' in prototype"
- msg += " at line %s" % @lexer.line
- msg += " in file %s" % @lexer.file if @lexer.file
- Puppet.warning msg
- result = ast AST::CompArgument, :children => [val[0],val[2]]
+module_eval <<'.,.,', 'grammar.ra', 568
+ def _reduce_133( val, _values, result )
+ Puppet.warning addcontext("Deprecation notice: #{val[0].value} must now include '$' in prototype")
+ result = [val[0], val[2]]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 548
- def _reduce_105( val, _values, result )
- msg = "Deprecation notice: #{val[0].value} must now include '$' in prototype"
- msg += " at line %s" % @lexer.line
- msg += " in file %s" % @lexer.file if @lexer.file
- Puppet.warning msg
- result = ast AST::CompArgument, :children => [val[0]]
+module_eval <<'.,.,', 'grammar.ra', 572
+ def _reduce_134( val, _values, result )
+ Puppet.warning addcontext("Deprecation notice: #{val[0].value} must now include '$' in prototype")
+ result = [val[0]]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 550
- def _reduce_106( val, _values, result )
- result = ast AST::CompArgument, :children => [val[0],val[2]]
+module_eval <<'.,.,', 'grammar.ra', 574
+ def _reduce_135( val, _values, result )
+ result = [val[0], val[2]]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 552
- def _reduce_107( val, _values, result )
- result = ast AST::CompArgument, :children => [val[0]]
+module_eval <<'.,.,', 'grammar.ra', 576
+ def _reduce_136( val, _values, result )
+ result = [val[0]]
result
end
.,.,
- # reduce 108 omitted
+ # reduce 137 omitted
-module_eval <<'.,.,', 'grammar.ra', 557
- def _reduce_109( val, _values, result )
- result = ast AST::Name, :value => val[1]
+module_eval <<'.,.,', 'grammar.ra', 581
+ def _reduce_138( val, _values, result )
+ result = val[1]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 562
- def _reduce_110( val, _values, result )
- name = val[0].sub(/^\$/,'')
- result = ast AST::Variable, :value => name
+module_eval <<'.,.,', 'grammar.ra', 585
+ def _reduce_139( val, _values, result )
+ result = ast AST::Variable, :value => val[0]
result
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 567
- def _reduce_111( val, _values, result )
- result = ast AST::Name, :value => val[0].sub(/^\$/,'')
- result
- end
-.,.,
-
-module_eval <<'.,.,', 'grammar.ra', 575
- def _reduce_112( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 593
+ def _reduce_140( val, _values, result )
if val[1].instance_of?(AST::ASTArray)
result = val[1]
else
@@ -1488,21 +1661,21 @@ module_eval <<'.,.,', 'grammar.ra', 575
end
.,.,
-module_eval <<'.,.,', 'grammar.ra', 577
- def _reduce_113( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 595
+ def _reduce_141( val, _values, result )
result = ast AST::ASTArray
result
end
.,.,
- # reduce 114 omitted
+ # reduce 142 omitted
- # reduce 115 omitted
+ # reduce 143 omitted
- # reduce 116 omitted
+ # reduce 144 omitted
-module_eval <<'.,.,', 'grammar.ra', 582
- def _reduce_117( val, _values, result )
+module_eval <<'.,.,', 'grammar.ra', 600
+ def _reduce_145( val, _values, result )
result = nil
result
end
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
new file mode 100644
index 000000000..5d09eaa9b
--- /dev/null
+++ b/lib/puppet/parser/resource.rb
@@ -0,0 +1,324 @@
+# A resource that we're managing. This handles making sure that only subclasses
+# can set parameters.
+class Puppet::Parser::Resource
+ require 'puppet/parser/resource/param'
+ require 'puppet/parser/resource/reference'
+ ResParam = Struct.new :name, :value, :source, :line, :file
+ include Puppet::Util
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Errors
+ include Puppet::Util::Logging
+
+ attr_accessor :source, :line, :file, :scope
+ attr_accessor :virtual, :override, :params, :translated
+
+ attr_reader :exported
+
+ attr_writer :tags
+
+ # Proxy a few methods to our @ref object.
+ [:builtin?, :type, :title].each do |method|
+ define_method(method) do
+ @ref.send(method)
+ end
+ end
+
+ # Set up some boolean test methods
+ [:exported, :translated, :override].each do |method|
+ newmeth = (method.to_s + "?").intern
+ define_method(newmeth) do
+ self.send(method)
+ end
+ end
+
+ def [](param)
+ param = symbolize(param)
+ if param == :title
+ return self.title
+ end
+ if @params.has_key?(param)
+ @params[param].value
+ else
+ nil
+ end
+ end
+
+ # Add default values from our definition.
+ def adddefaults
+ defaults = scope.lookupdefaults(self.type)
+
+ defaults.each do |name, param|
+ unless @params.include?(param.name)
+ self.debug "Adding default for %s" % param.name
+
+ @params[param.name] = param
+ end
+ end
+ end
+
+ # Add any metaparams defined in our scope. This actually adds any metaparams
+ # from any parent scope, and there's currently no way to turn that off.
+ def addmetaparams
+ Puppet::Type.eachmetaparam do |name|
+ if val = scope.lookupvar(name.to_s, false)
+ unless val == :undefined
+ set Param.new(:name => name, :value => val, :source => scope.source)
+ end
+ end
+ end
+ end
+
+ # Add any overrides for this object.
+ def addoverrides
+ overrides = scope.lookupoverrides(self)
+
+ overrides.each do |over|
+ self.merge(over)
+ end
+
+ overrides.clear
+ end
+
+ def builtin=(bool)
+ @ref.builtin = bool
+ end
+
+ # Retrieve the associated definition and evaluate it.
+ def evaluate
+ if builtin?
+ devfail "Cannot evaluate a builtin type"
+ end
+
+ unless klass = scope.finddefine(self.type)
+ self.fail "Cannot find definition %s" % self.type
+ end
+
+ finish()
+
+ scope.deleteresource(self)
+
+ return klass.evaluate(:scope => scope,
+ :type => self.type,
+ :name => self.title,
+ :arguments => self.to_hash,
+ :scope => self.scope,
+ :exported => self.exported
+ )
+ ensure
+ @evaluated = true
+ end
+
+ def exported=(value)
+ if value
+ @virtual = true
+ @exported = value
+ else
+ @exported = value
+ end
+ end
+
+ def evaluated?
+ if defined? @evaluated and @evaluated
+ true
+ else
+ false
+ end
+ end
+
+ # Do any finishing work on this object, called before evaluation or
+ # before storage/translation.
+ def finish
+ addoverrides()
+ adddefaults()
+ addmetaparams()
+ end
+
+ def initialize(options)
+ options = symbolize_options(options)
+
+ # Collect the options necessary to make the reference.
+ refopts = [:type, :title].inject({}) do |hash, param|
+ hash[param] = options[param] ||
+ devfail("%s must be passed to Resources" % param)
+ options.delete(param)
+ hash
+ end
+
+ @params = {}
+ tmpparams = nil
+ if tmpparams = options[:params]
+ options.delete(:params)
+ end
+
+ # Now set the rest of the options.
+ set_options(options)
+
+ @ref = Reference.new(refopts)
+
+ requiredopts(:scope, :source)
+
+ @ref.scope = self.scope
+
+ if tmpparams
+ tmpparams.each do |param|
+ # We use the method here, because it does type-checking.
+ set(param)
+ end
+ end
+ end
+
+ # Merge an override resource in.
+ def merge(resource)
+ # Some of these might fail, but they'll fail in the way we want.
+ resource.params.each do |name, param|
+ set(param)
+ end
+ end
+
+ # Verify that all passed parameters are valid. This throws an error if there's
+ # a problem, so we don't have to worry about the return value.
+ def paramcheck(param)
+ # This defaults to true
+ unless Puppet[:paramcheck]
+ return
+ end
+
+ return if param == "name" or param == "title" # always allow these
+
+ # FIXME We might need to do more here eventually. Metaparams
+ # behave strangely on containers.
+ return if Puppet::Type.metaparam?(param)
+
+ # Now make sure it's a valid argument to our class.
+ unless @ref.typeclass.validattr?(param)
+ self.fail Puppet::ParseError, "Invalid parameter '%s' for type '%s'" %
+ [param.inspect, @ref.type]
+ end
+ end
+
+ # A temporary occasion, until I get paths in the scopes figured out.
+ def path
+ to_s
+ end
+
+ # Return the short version of our name.
+ def ref
+ @ref.to_s
+ end
+
+ # You have to pass a Resource::Param to this.
+ def set(param)
+ # Because definitions are now parse-time, I can paramcheck immediately.
+ paramcheck(param.name)
+
+ if current = @params[param.name]
+ # XXX Should we ignore any settings that have the same values?
+ if param.source.child_of?(current.source)
+ # Replace it, keeping all of its info.
+ @params[param.name] = param
+ else
+ fail Puppet::ParseError, "Parameter %s is already set on %s by %s" %
+ [param.name, self.to_s, param.source]
+ end
+ else
+ if self.source == param.source or param.source.child_of?(self.source)
+ @params[param.name] = param
+ else
+ fail Puppet::ParseError, "Only subclasses can set parameters"
+ end
+ end
+ end
+
+ # Store our object as a Rails object. We need the host object we're storing it
+ # with.
+ def store(host)
+ args = {}
+ %w{type title tags file line exported}.each do |param|
+ if value = self.send(param)
+ args[param] = value
+ end
+ end
+
+ # 'type' isn't a valid column name, so we have to use something else.
+ args = symbolize_options(args)
+ args[:restype] = args[:type]
+ args.delete(:type)
+
+ # Let's see if the object exists
+ #if obj = host.rails_resources.find_by_type_and_title(self.type, self.title)
+ if obj = host.rails_resources.find_by_restype_and_title(self.type, self.title)
+ # We exist
+ args.each do |param, value|
+ obj[param] = value
+ end
+ else
+ # Else create it anew
+ obj = host.rails_resources.build(args)
+ end
+
+ # Either way, now add our parameters
+ @params.each do |name, param|
+ param.store(obj)
+ end
+
+ return obj
+ end
+
+ def tags
+ unless defined? @tags
+ @tags = scope.tags
+ @tags << self.type
+ end
+ @tags
+ end
+
+ def to_hash
+ @params.inject({}) do |hash, ary|
+ param = ary[1]
+ hash[param.name] = param.value
+ hash
+ end
+ end
+
+ def to_s
+ self.ref
+ end
+
+ # Translate our object to a transportable object.
+ def to_trans
+ unless builtin?
+ devfail "Tried to translate a non-builtin resource"
+ end
+
+ return nil if virtual?
+
+ # Now convert to a transobject
+ obj = Puppet::TransObject.new(@ref.title, @ref.type)
+ to_hash.each do |p, v|
+ if v.is_a?(Reference)
+ v = v.to_ref
+ elsif v.is_a?(Array)
+ v = v.collect { |av|
+ if av.is_a?(Reference)
+ av = av.to_ref
+ end
+ av
+ }
+ end
+ obj[p.to_s] = v
+ end
+
+ obj.file = self.file
+ obj.line = self.line
+
+ obj.tags = self.tags
+
+ return obj
+ end
+
+ def virtual?
+ self.virtual
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb
new file mode 100644
index 000000000..259e935d1
--- /dev/null
+++ b/lib/puppet/parser/resource/param.rb
@@ -0,0 +1,44 @@
+# The parameters we stick in Resources.
+class Puppet::Parser::Resource::Param
+ attr_accessor :name, :value, :source, :line, :file
+ include Puppet::Util::Errors
+ include Puppet::Util::MethodHelper
+
+ def initialize(hash)
+ set_options(hash)
+ requiredopts(:name, :value, :source)
+ @name = @name.intern if @name.is_a?(String)
+ end
+
+ def inspect
+ "#<#{self.class} @name => #{self.name}, @value => #{self.value}, @source => #{self.source.type}>"
+ end
+
+ # Store this parameter in a Rails db.
+ def store(resource)
+ args = {}
+ [:name, :value, :line, :file].each do |var|
+ if val = self.send(var)
+ args[var] = val
+ end
+ end
+ args[:name] = args[:name].to_s
+ if obj = resource.rails_parameters.find_by_name(self.name)
+ # We exist
+ args.each do |p, v|
+ obj[p] = v
+ end
+ else
+ # Else create it anew
+ obj = resource.rails_parameters.build(args)
+ end
+
+ return obj
+ end
+
+ def to_s
+ "%s => %s" % [self.name, self.value]
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb
new file mode 100644
index 000000000..2210b71c2
--- /dev/null
+++ b/lib/puppet/parser/resource/reference.rb
@@ -0,0 +1,68 @@
+# A reference to a resource. Mostly just the type and title.
+class Puppet::Parser::Resource::Reference
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Errors
+
+ attr_accessor :type, :title, :builtin, :file, :line, :scope
+
+ # Are we a builtin type?
+ def builtin?
+ unless defined? @builtin
+ if builtintype()
+ @builtin = true
+ else
+ @builtin = false
+ end
+ end
+
+ self.builtin
+ end
+
+ def builtintype
+ if t = Puppet::Type.type(self.type) and t.name != :component
+ t
+ else
+ nil
+ end
+ end
+
+ # Return the defined type for our obj.
+ def definedtype
+ unless defined? @definedtype
+ if tmp = @scope.finddefine(self.type)
+ @definedtype = tmp
+ else
+ fail Puppet::ParseError, "Could not find definition %s" % self.type
+ end
+ end
+
+ @definedtype
+ end
+
+ def initialize(hash)
+ set_options(hash)
+ requiredopts(:type, :title)
+ end
+
+ def to_ref
+ return [type.to_s,title.to_s]
+ end
+
+ def to_s
+ "%s[%s]" % [type, title]
+ end
+
+ def typeclass
+ unless defined? @typeclass
+ if tmp = builtintype || definedtype
+ @typeclass = tmp
+ else
+ fail Puppet::ParseError, "Could not find type %s" % self.type
+ end
+ end
+
+ @typeclass
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index a26ec938d..9b59ebd64 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -2,1191 +2,645 @@
# such.
require 'puppet/parser/parser'
+require 'puppet/parser/templatewrapper'
require 'puppet/transportable'
-module Puppet::Parser
- class Scope
- class ScopeObj < Hash
- attr_accessor :file, :line, :type, :name
- end
-
- # A simple wrapper for templates, so they don't have full access to
- # the scope objects.
- class TemplateWrapper
- attr_accessor :scope, :file
- include Puppet::Util
- Puppet::Util.logmethods(self)
-
- def initialize(scope, file)
- @scope = scope
- if file =~ /^#{File::SEPARATOR}/
- @file = file
- else
- @file = File.join(Puppet[:templatedir], file)
- end
+class Puppet::Parser::Scope
+ require 'puppet/parser/resource'
- unless FileTest.exists?(@file)
- raise Puppet::ParseError,
- "Could not find template %s" % file
- end
+ AST = Puppet::Parser::AST
- # We'll only ever not have an interpreter in testing, but, eh.
- if @scope.interp
- @scope.interp.newfile(@file)
- end
- end
+ # This doesn't actually work right now.
+ Puppet.config.setdefaults(:puppet,
+ :lexical => [false, "Whether to use lexical scoping (vs. dynamic)."],
+ :templatedir => ["$vardir/templates",
+ "Where Puppet looks for template files."
+ ]
+ )
- # Ruby treats variables like methods, so we can cheat here and
- # trap missing vars like they were missing methods.
- def method_missing(name, *args)
- # We have to tell lookupvar to return :undefined to us when
- # appropriate; otherwise it converts to "".
- value = @scope.lookupvar(name.to_s, false)
- if value != :undefined
- return value
- else
- # Just throw an error immediately, instead of searching for
- # other missingmethod things or whatever.
- raise Puppet::ParseError,
- "Could not find value for '%s'" % name
- end
- end
-
- def result
- result = nil
- benchmark(:debug, "Interpolated template #{@file}") do
- template = ERB.new(File.read(@file), 0, "-")
- result = template.result(binding)
- end
-
- result
- end
-
- def to_s
- "template[%s]" % @file
- end
- end
+ Puppet::Util.logmethods(self)
- # This doesn't actually work right now.
- Puppet.config.setdefaults(:puppet,
- :lexical => [false, "Whether to use lexical scoping (vs. dynamic)."],
- :templatedir => ["$vardir/templates",
- "Where Puppet looks for template files."
- ]
- )
+ include Enumerable
+ include Puppet::Util::Errors
+ attr_accessor :parent, :level, :interp, :source, :host
+ attr_accessor :name, :type, :topscope, :base, :keyword, :namespace
+ attr_accessor :top, :context, :translated, :exported
- Puppet::Util.logmethods(self)
+ # Whether we behave declaratively. Note that it's a class variable,
+ # so all scopes behave the same.
+ @@declarative = true
- include Enumerable
- attr_accessor :parent, :level, :interp
- attr_accessor :name, :type, :topscope, :base, :keyword
+ # Retrieve and set the declarative setting.
+ def self.declarative
+ return @@declarative
+ end
- attr_accessor :top, :context, :translated, :collectable
+ def self.declarative=(val)
+ @@declarative = val
+ end
- # This is probably not all that good of an idea, but...
- # This way a parent can share its tables with all of its children.
- attr_writer :nodetable, :classtable, :definedtable, :exportable
+ # This handles the shared tables that all scopes have. They're effectively
+ # global tables, except that they're only global for a single scope tree,
+ # which is why I can't use class variables for them.
+ def self.sharedtable(*names)
+ attr_accessor(*names)
+ @@sharedtables ||= []
+ @@sharedtables += names
+ end
- # Whether we behave declaratively. Note that it's a class variable,
- # so all scopes behave the same.
- @@declarative = true
+ # This is probably not all that good of an idea, but...
+ # This way a parent can share its tables with all of its children.
+ sharedtable :classtable, :definedtable, :exportable, :overridetable, :collecttable
- # Retrieve and set the declarative setting.
- def self.declarative
- return @@declarative
+ # Is the value true? This allows us to control the definition of truth
+ # in one place.
+ def self.true?(value)
+ if value == false or value == ""
+ return false
+ else
+ return true
end
+ end
- def self.declarative=(val)
- @@declarative = val
+ # Is the type a builtin type?
+ def builtintype?(type)
+ if typeklass = Puppet::Type.type(type)
+ return typeklass
+ else
+ return false
end
+ end
- # Is the value true? This allows us to control the definition of truth
- # in one place.
- def self.true?(value)
- if value == false or value == ""
- return false
- else
- return true
- end
+ # Create a new child scope.
+ def child=(scope)
+ @children.push(scope)
+
+ # Copy all of the shared tables over to the child.
+ @@sharedtables.each do |name|
+ scope.send(name.to_s + "=", self.send(name))
end
+ end
- # Add all of the defaults for a given object to that object.
- def adddefaults(obj)
- defaults = lookupdefaults(obj.type)
+ # Verify that the given object isn't defined elsewhere.
+ def chkobjectclosure(obj)
+ if @definedtable.include?(obj.ref)
+ typeklass = Puppet::Type.type(obj.type)
+ if typeklass and ! typeklass.isomorphic?
+ Puppet.info "Allowing duplicate %s" % type
+ else
+ exobj = @definedtable[obj.ref]
- defaults.each do |var, value|
- unless obj[var]
- self.debug "Adding default %s for %s" %
- [var, obj.type]
+ # Either it's a defined type, which are never
+ # isomorphic, or it's a non-isomorphic type.
+ msg = "Duplicate definition: %s is already defined" % obj.ref
- obj[var] = value
+ if exobj.file and exobj.line
+ msg << " in file %s at line %s" %
+ [exobj.file, exobj.line]
end
- end
- end
- # Add a single object's tags to the global list of tags for
- # that object.
- def addtags(obj)
- unless defined? @tagtable
- raise Puppet::DevError, "Told to add tags, but no tag table"
- end
- list = @tagtable[obj.type][obj.name]
-
- obj.tags.each { |tag|
- unless list.include?(tag)
- if tag.nil? or tag == ""
- Puppet.debug "Got tag %s from %s(%s)" %
- [tag.inspect, obj.type, obj.name]
- else
- list << tag
- end
+ if obj.line or obj.file
+ msg << "; cannot redefine"
end
- }
- end
- # Is the type a builtin type?
- def builtintype?(type)
- if typeklass = Puppet::Type.type(type)
- return typeklass
- else
- return false
+ raise Puppet::ParseError.new(msg)
end
end
- # Verify that the given object isn't defined elsewhere.
- def chkobjectclosure(hash)
- type = hash[:type]
- name = hash[:name]
- unless name
- return true
- end
- if @definedtable[type].include?(name)
- typeklass = Puppet::Type.type(type)
- if typeklass and ! typeklass.isomorphic?
- Puppet.info "Allowing duplicate %s" % type
- else
- exobj = @definedtable[type][name]
-
- # Either it's a defined type, which are never
- # isomorphic, or it's a non-isomorphic type.
- msg = "Duplicate definition: %s[%s] is already defined" %
- [type, name]
-
- if exobj.file and exobj.line
- msg << " in file %s at line %s" %
- [exobj.file, exobj.line]
- end
-
- if hash[:line] or hash[:file]
- msg << "; cannot redefine"
- end
-
- error = Puppet::ParseError.new(msg)
- raise error
- end
- end
-
- return true
- end
-
- def declarative=(val)
- self.class.declarative = val
- end
-
- def declarative
- self.class.declarative
- end
-
- # Log the existing tags. At some point this should be in a better
- # place, but eh.
- def logtags
- @tagtable.sort { |a, b|
- a[0] <=> b[0]
- }.each { |type, names|
- names.sort { |a, b|
- a[0] <=> b[0]
- }.each { |name, tags|
- Puppet.info "%s(%s): '%s'" % [type, name, tags.join("' '")]
- }
- }
- end
+ return true
+ end
- # Create a new child scope.
- def child=(scope)
- @children.push(scope)
+ # Return the list of collections.
+ def collections
+ @collecttable
+ end
- if defined? @nodetable
- scope.nodetable = @nodetable
- else
- raise Puppet::DevError, "No nodetable has been defined"
- end
+ def declarative=(val)
+ self.class.declarative = val
+ end
- if defined? @classtable
- scope.classtable = @classtable
- else
- raise Puppet::DevError, "No classtable has been defined"
- end
+ def declarative
+ self.class.declarative
+ end
- if defined? @exportable
- scope.exportable = @exportable
- else
- raise Puppet::DevError, "No exportable has been defined"
- end
+ # Test whether a given scope is declarative. Even though it's
+ # a global value, the calling objects don't need to know that.
+ def declarative?
+ @@declarative
+ end
- if defined? @definedtable
- scope.definedtable = @definedtable
- else
- raise Puppet::DevError, "No definedtable has been defined"
- end
- end
+ # Remove a specific child.
+ def delete(child)
+ @children.delete(child)
+ end
- # Test whether a given scope is declarative. Even though it's
- # a global value, the calling objects don't need to know that.
- def declarative?
- @@declarative
+ # Remove a resource from the various tables. This is only used when
+ # a resource maps to a definition and gets evaluated.
+ def deleteresource(resource)
+ if @definedtable[resource.ref]
+ @definedtable.delete(resource.ref)
end
- # Remove a specific child.
- def delete(child)
- @children.delete(child)
+ if @children.include?(resource)
+ @children.delete(resource)
end
+ end
- # Are we the top scope?
- def topscope?
- @level == 1
- end
+ # Are we the top scope?
+ def topscope?
+ @level == 1
+ end
- # Return a list of all of the defined classes.
- def classlist
- unless defined? @classtable
- raise Puppet::DevError, "Scope did not receive class table"
- end
- return @classtable.collect { |id, klass|
- # The class table can contain scopes or strings as its values
- # so support them accordingly.
- if klass.is_a? Scope
- klass.type
- else
- klass
- end
- }
+ # Return a list of all of the defined classes.
+ def classlist
+ unless defined? @classtable
+ raise Puppet::DevError, "Scope did not receive class table"
end
+ return @classtable.keys.reject { |k| k == "" }
+ end
- # Yield each child scope in turn
- def each
- @children.each { |child|
- yield child
- }
- end
+ # Yield each child scope in turn
+ def each
+ @children.each { |child|
+ yield child
+ }
+ end
- # Evaluate a list of classes.
- def evalclasses(classes)
- return unless classes
- classes.each do |klass|
- if code = lookuptype(klass)
- # Just reuse the 'include' function, since that's the equivalent
- # of what we're doing here.
- function_include(klass)
- end
+ # Evaluate a list of classes.
+ def evalclasses(*classes)
+ retval = []
+ classes.each do |klass|
+ if obj = findclass(klass)
+ obj.safeevaluate :scope => self
+ retval << klass
end
end
+ end
- # 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(hash)
- objects = hash[:ast]
- names = hash[:names] or
- raise Puppet::DevError, "Node names must be provided to evalnode"
- facts = hash[:facts]
- classes = hash[:classes]
- parent = hash[:parent]
-
- # Always add "default" to our name list, so we're always searching
- # for a default node.
- names << "default"
-
- scope = code = nil
- # Find a node that matches one of our names
- names.each { |node|
- if nodehash = @nodetable[node]
- code = nodehash[:node]
- scope = nodehash[:scope]
-
- if node == "default"
- Puppet.info "Using default node"
- end
- break
- end
- }
-
- # And fail if we don't find one.
- unless scope and code
- raise Puppet::Error, "Could not find configuration for %s" %
- names.join(" or ")
- end
+ def exported?
+ self.exported
+ end
- # We need to do a little skullduggery here. We want a
- # temporary scope, because we don't want this scope to
- # show up permanently in the scope tree -- otherwise we could
- # not evaluate the node multiple times. We could conceivably
- # cache the results, but it's not worth it at this stage.
+ def findclass(name)
+ interp.findclass(namespace, name)
+ end
- # Note that we evaluate the node code with its containing
- # scope, not with the top scope. We also retrieve the created
- # scope so that we can get any classes set within it
- nodescope = code.safeevaluate(:scope => scope, :facts => facts)
+ def finddefine(name)
+ interp.finddefine(namespace, name)
+ end
- scope.evalclasses(classes)
+ def findresource(string, name = nil)
+ if name
+ string = "%s[%s]" % [string, name]
end
- # 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)
- }
-
- # Evaluate all of our configuration. This does not evaluate any
- # node definitions.
- result = objects.safeevaluate(:scope => self)
-
- # If they've provided a name or a parent, we assume they're looking
- # for nodes.
- if hash[:searched]
- # Specifying a parent node takes precedence, because it is assumed
- # that this node was found in a remote repository like ldap.
- gennode(hash)
- elsif hash.include? :names # else, look for it in the config
- evalnode(hash)
- else
- # Else we're not using nodes at all, so just evaluate any passed-in
- # classes.
- classes = hash[:classes] || []
- evalclasses(classes)
-
- # These classes would be passed in manually, via something like
- # a cfengine module
- end
-
- bucket = self.to_trans
-
- # Add our class list
- unless self.classlist.empty?
- bucket.classes = self.classlist
- end
-
- # Now clean up after ourselves
- [@@done].each do |table|
- table.clear
- end
+ @definedtable[string]
+ end
- return bucket
+ # Recursively complete the whole tree, in preparation for
+ # translation or storage.
+ def finish
+ self.each do |obj|
+ obj.finish
end
+ end
- # Return the hash of objects that we specifically exported. We return
- # a hash to make it easy for the caller to deduplicate based on name.
- def exported(type)
- if @exportable.include?(type)
- return @exportable[type].dup
+ # Initialize our new scope. Defaults to having no parent and to
+ # being declarative.
+ def initialize(hash = {})
+ @parent = nil
+ @type = nil
+ @name = nil
+ @finished = false
+ hash.each { |name, val|
+ method = name.to_s + "="
+ if self.respond_to? method
+ self.send(method, val)
else
- return {}
- end
- end
-
- # Store our object in the central export table.
- def exportobject(obj)
- if @exportable.include?(obj.type) and
- @exportable[obj.type].include?(obj.name)
- raise Puppet::ParseError, "Object %s[%s] is already exported" %
- [obj.type, obj.name]
+ raise Puppet::DevError, "Invalid scope argument %s" % name
end
+ }
- debug "Exporting %s[%s]" % [obj.type, obj.name]
+ @tags = []
- @exportable[obj.type][obj.name] = obj
+ if @parent.nil?
+ unless hash.include?(:declarative)
+ hash[:declarative] = true
+ end
+ self.istop(hash[:declarative])
+ @inside = nil
+ else
+ # This is here, rather than in newchild(), so that all
+ # of the later variable initialization works.
+ @parent.child = self
- return obj
+ @level = @parent.level + 1
+ @interp = @parent.interp
+ @source = hash[:source] || @parent.source
+ @topscope = @parent.topscope
+ @context = @parent.context
+ @inside = @parent.inside
+ @host = @parent.host
+ @type ||= @parent.type
end
- # Pull in all of the appropriate classes and evaluate them. It'd
- # be nice if this didn't know quite so much about how AST::Node
- # operated internally. This is used when a list of classes is passed in,
- # instead of a node definition, such as from the cfengine module.
- def gennode(hash)
- names = hash[:names] or
- raise Puppet::DevError, "Node names must be provided to gennode"
- facts = hash[:facts]
- classes = hash[:classes]
- parent = hash[:parentnode]
- name = names.shift
- arghash = {
- :type => name,
- :code => AST::ASTArray.new(:pin => "[]")
- }
+ # Our child scopes and objects
+ @children = []
- #Puppet.notice "hash is %s" %
- # hash.inspect
- #Puppet.notice "Classes are %s, parent is %s" %
- # [classes.inspect, parent.inspect]
+ # The symbol table for this scope
+ @symtable = Hash.new(nil)
- if parent
- arghash[:parentclass] = parent
- end
+ # All of the defaults set for types. It's a hash of hashes,
+ # with the first key being the type, then the second key being
+ # the parameter.
+ @defaultstable = Hash.new { |dhash,type|
+ dhash[type] = Hash.new(nil)
+ }
- # Create the node
- node = AST::Node.new(arghash)
- node.keyword = "node"
+ # Map the names to the tables.
+ @map = {
+ "variable" => @symtable,
+ "defaults" => @defaultstable
+ }
- # Now evaluate it, which evaluates the parent and nothing else
- # but does return the nodescope.
- scope = node.safeevaluate(:scope => self)
-
- # Finally evaluate our list of classes in this new scope.
- scope.evalclasses(classes)
+ unless @interp
+ raise Puppet::DevError, "Scopes require an interpreter"
end
+ end
- # Initialize our new scope. Defaults to having no parent and to
- # being declarative.
- def initialize(hash = {})
- @parent = nil
- @type = nil
- @name = nil
- @finished = false
- hash.each { |name, val|
- method = name.to_s + "="
- if self.respond_to? method
- self.send(method, val)
- else
- raise Puppet::DevError, "Invalid scope argument %s" % name
- end
- }
-
- @tags = []
-
- if @parent.nil?
- unless hash.include?(:declarative)
- hash[:declarative] = true
- end
- self.istop(hash[:declarative])
- @inside = nil
- 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
- @context = @parent.context
- @inside = @parent.inside
- end
-
- # Our child scopes and objects
- @children = []
-
- # The symbol table for this scope
- @symtable = Hash.new(nil)
+ # Associate the object directly with the scope, so that contained objects
+ # can look up what container they're running within.
+ def inside(arg = nil)
+ return @inside unless arg
+
+ old = @inside
+ @inside = arg
+ yield
+ ensure
+ #Puppet.warning "exiting %s" % @inside.name
+ @inside = old
+ end
- # The type table for this scope
- @typetable = Hash.new(nil)
+ # Mark that we're the top scope, and set some hard-coded info.
+ def istop(declarative = true)
+ # the level is mostly used for debugging
+ @level = 1
- # All of the defaults set for types. It's a hash of hashes,
- # with the first key being the type, then the second key being
- # the parameter.
- @defaultstable = Hash.new { |dhash,type|
- dhash[type] = Hash.new(nil)
- }
+ # The table for storing class singletons. This will only actually
+ # be used by top scopes and node scopes.
+ @classtable = Hash.new(nil)
- # The object table is similar, but it is actually a hash of hashes
- # where the innermost objects are TransObject instances.
- @objectable = Hash.new { |typehash,typekey|
- # See #newobject for how to create the actual objects
- typehash[typekey] = Hash.new(nil)
- }
+ self.class.declarative = declarative
- # 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|
- typehash[typekey] = Hash.new(nil)
- }
+ # The table for all defined objects.
+ @definedtable = {}
- # Map the names to the tables.
- @map = {
- "variable" => @symtable,
- "type" => @typetable,
- "node" => @nodetable,
- "object" => @objectable,
- "defaults" => @defaultstable
- }
- end
+ # The list of objects that will available for export.
+ @exportable = {}
- # Associate the object directly with the scope, so that contained objects
- # can look up what container they're running within.
- def inside(arg = nil)
- return @inside unless arg
-
- old = @inside
- @inside = arg
- yield
- ensure
- #Puppet.warning "exiting %s" % @inside.name
- @inside = old
+ # The list of overrides. This is used to cache overrides on objects
+ # that don't exist yet. We store an array of each override.
+ @overridetable = Hash.new do |overs, ref|
+ overs[ref] = []
end
- # Mark that we're the top scope, and set some hard-coded info.
- def istop(declarative = true)
- # the level is mostly used for debugging
- @level = 1
-
- # The table for storing class singletons. This will only actually
- # be used by top scopes and node scopes.
- @classtable = Hash.new(nil)
+ # Eventually, if we support sites, this will allow definitions
+ # of nodes with the same name in different sites. For now
+ # the top-level scope is always the only site scope.
+ @sitescope = true
- self.class.declarative = declarative
+ @namespace = ""
- # The table for all defined objects.
- @definedtable = Hash.new { |types, type|
- types[type] = {}
- }
-
- # A table for storing nodes.
- @nodetable = Hash.new(nil)
+ # The list of collections that have been created. This is a global list,
+ # but they each refer back to the scope that created them.
+ @collecttable = []
- # The list of objects that will available for export.
- @exportable = Hash.new { |types, type|
- types[type] = {}
- }
+ @context = nil
+ @topscope = self
+ @type = "puppet"
+ @name = "top"
+ end
- # Eventually, if we support sites, this will allow definitions
- # of nodes with the same name in different sites. For now
- # the top-level scope is always the only site scope.
- @sitescope = true
-
- # And create a tag table, so we can collect all of the tags
- # associated with any objects created in this scope tree
- @tagtable = Hash.new { |types, type|
- types[type] = Hash.new { |names, name|
- names[name] = []
- }
+ # Collect all of the defaults set at any higher scopes.
+ # This is a different type of lookup because it's additive --
+ # it collects all of the defaults, with defaults in closer scopes
+ # overriding those in later scopes.
+ def lookupdefaults(type)
+ values = {}
+
+ # first collect the values from the parents
+ unless @parent.nil?
+ @parent.lookupdefaults(type).each { |var,value|
+ values[var] = value
}
-
- @context = nil
- @topscope = self
- @type = "puppet"
- @name = "top"
- end
-
- # Look up a given class. This enables us to make sure classes are
- # singletons
- def lookupclass(klassid)
- unless defined? @classtable
- raise Puppet::DevError, "Scope did not receive class table"
- end
- return @classtable[klassid]
end
- # Collect all of the defaults set at any higher scopes.
- # This is a different type of lookup because it's additive --
- # it collects all of the defaults, with defaults in closer scopes
- # overriding those in later scopes.
- def lookupdefaults(type)
- values = {}
-
- # first collect the values from the parents
- unless @parent.nil?
- @parent.lookupdefaults(type).each { |var,value|
- values[var] = value
- }
- end
-
- # then override them with any current values
- # this should probably be done differently
- if @defaultstable.include?(type)
- @defaultstable[type].each { |var,value|
- values[var] = value
- }
- end
- #Puppet.debug "Got defaults for %s: %s" %
- # [type,values.inspect]
- return values
- end
-
- # Look up all of the exported objects of a given type. Just like
- # lookupobject, this only searches up through parent classes, not
- # the whole scope tree.
- def lookupexported(type)
- found = []
- sub = proc { |table|
- # We always return nil so that it will search all the way
- # up the scope tree.
- if table.has_key?(type)
- table[type].each do |name, obj|
- found << obj
- end
- nil
- else
- info table.keys.inspect
- nil
- end
+ # then override them with any current values
+ # this should probably be done differently
+ if @defaultstable.include?(type)
+ @defaultstable[type].each { |var,value|
+ values[var] = value
}
-
- value = lookup("object",sub, false)
-
- return found
end
- # Look up a node by name
- def lookupnode(name)
- #Puppet.debug "Looking up type %s" % name
- value = lookup("type",name)
- if value == :undefined
- return nil
- else
- #Puppet.debug "Found node %s" % name
- return value
- end
- end
+ #Puppet.debug "Got defaults for %s: %s" %
+ # [type,values.inspect]
+ return values
+ end
- # Look up a defined type.
- def lookuptype(name)
- #Puppet.debug "Looking up type %s" % name
- value = lookup("type",name)
- if value == :undefined
- return nil
- else
- #Puppet.debug "Found type %s" % name
- return value
- end
+ # Look up all of the exported objects of a given type. Just like
+ # lookupobject, this only searches up through parent classes, not
+ # the whole scope tree.
+ def lookupexported(type)
+ @definedtable.find_all do |name, r|
+ r.type == type and r.exported?
end
+ end
- # Look up an object by name and type. This should only look up objects
- # within a class structure, not within the entire scope structure.
- def lookupobject(hash)
- type = hash[:type]
- name = hash[:name]
- #Puppet.debug "Looking up object %s of type %s in level %s" %
- # [name, type, @level]
- sub = proc { |table|
- if table.include?(type)
- if table[type].include?(name)
- table[type][name]
- end
- else
- nil
- end
- }
- value = lookup("object",sub, true)
- if value == :undefined
- return nil
- else
- return value
- end
- end
+ def lookupoverrides(obj)
+ @overridetable[obj.ref]
+ end
- # Look up a variable. The simplest value search we do. Default to returning
- # an empty string for missing values, but support returning a constant.
- def lookupvar(name, usestring = true)
- value = lookup("variable", name)
- if value == :undefined
- if usestring
- return ""
- else
- return :undefined
- end
+ # Look up a defined type.
+ def lookuptype(name)
+ finddefine(name) || findclass(name)
+ end
+
+ # Look up a variable. The simplest value search we do. Default to returning
+ # an empty string for missing values, but support returning a constant.
+ def lookupvar(name, usestring = true)
+ value = lookup("variable", name)
+ if value == :undefined
+ if usestring
+ return ""
else
- return value
+ return :undefined
end
+ else
+ return value
end
+ end
- def newcollection(coll)
- @children << coll
- end
-
- # Add a new object to our object table.
- def newobject(hash)
- if @objectable[hash[:type]].include?(hash[:name])
- raise Puppet::DevError, "Object %s[%s] is already defined" %
- [hash[:type], hash[:name]]
- end
-
- self.chkobjectclosure(hash)
-
- obj = nil
-
- obj = Puppet::TransObject.new(hash[:name], hash[:type])
-
- @children << obj
+ # Add a collection to the global list.
+ def newcollection(coll)
+ @collecttable << coll
+ end
- @objectable[hash[:type]][hash[:name]] = obj
+ # Create a new scope.
+ def newscope(hash = {})
+ hash[:parent] = self
+ #debug "Creating new scope, level %s" % [self.level + 1]
+ return Puppet::Parser::Scope.new(hash)
+ end
- @definedtable[hash[:type]][hash[:name]] = obj
+ # Return the list of remaining overrides.
+ def overrides
+ @overridetable.collect { |name, overs| overs }.flatten
+ end
- return obj
- end
+ def resources
+ @definedtable.values
+ end
- # Create a new scope.
- def newscope(hash = {})
- hash[:parent] = self
- #debug "Creating new scope, level %s" % [self.level + 1]
- return Puppet::Parser::Scope.new(hash)
+ def setclass?(obj)
+ if obj.respond_to?(:fqname)
+ @classtable.has_key?(obj.fqname)
+ else
+ @classtable[obj]
end
+ end
- # Retrieve a specific node. This is used in ast.rb to find a
- # parent node and in findnode to retrieve and evaluate a node.
- def node(name)
- @nodetable[name]
+ # Store the fact that we've evaluated a given class. We use a hash
+ # that gets inherited from the top scope down, rather than a global
+ # hash. We store the object ID, not class name, so that we
+ # can support multiple unrelated classes with the same name.
+ def setclass(obj)
+ if obj.is_a?(AST::HostClass)
+ unless obj.fqname
+ raise Puppet::DevError, "Got a %s with no fully qualified name" %
+ obj.class
+ end
+ @classtable[obj.fqname] = obj
+ else
+ raise Puppet::DevError, "Invalid class %s" % obj.inspect
end
+ end
- # Store the fact that we've evaluated a given class. We use a hash
- # that gets inherited from the top scope down, rather than a global
- # hash. We store the object ID, not class name, so that we
- # can support multiple unrelated classes with the same name.
- def setclass(id, name)
- unless name =~ /^[a-z][\w-]*$/
- raise Puppet::ParseError, "Invalid class name '%s'" % name
- end
+ # Set all of our facts in the top-level scope.
+ def setfacts(facts)
+ facts.each { |var, value|
+ self.setvar(var, value)
+ }
+ end
- @classtable[id] = name
- end
+ # Add a new object to our object table and the global list, and do any necessary
+ # checks.
+ def setresource(obj)
+ self.chkobjectclosure(obj)
- # Store the scope for each class, so that other subclasses can look
- # them up.
- def setscope(id, scope)
- @classtable[id] = scope
- end
+ @children << obj
- # Set defaults for a type. The typename should already be downcased,
- # so that the syntax is isolated.
- def setdefaults(type,params)
- table = @defaultstable[type]
+ # The global table
+ @definedtable[obj.ref] = obj
- # if we got a single param, it'll be in its own array
- unless params[0].is_a?(Array)
- params = [params]
- end
+ return obj
+ end
- params.each { |ary|
- #Puppet.debug "Default for %s is %s => %s" %
- # [type,ary[0].inspect,ary[1].inspect]
- if @@declarative
- if table.include?(ary[0])
- error = Puppet::ParseError.new(
- "Default already defined for %s { %s }" %
- [type,ary[0]]
- )
- raise error
- end
- else
- if table.include?(ary[0])
- # we should maybe allow this warning to be turned off...
- Puppet.warning "Replacing default for %s { %s }" %
- [type,ary[0]]
- end
- end
- table[ary[0]] = ary[1]
- }
+ # Override a parameter in an existing object. If the object does not yet
+ # exist, then cache the override in a global table, so it can be flushed
+ # at the end.
+ def setoverride(resource)
+ resource.override = true
+ if obj = @definedtable[resource.ref]
+ obj.merge(resource)
+ else
+ @overridetable[resource.ref] << resource
end
+ end
- # Store a host in the site node table.
- def setnode(name,code)
- unless defined? @nodetable
- raise Puppet::DevError, "No node table defined"
- end
- if @nodetable.include?(name)
- raise Puppet::ParseError, "Host %s is already defined" % name
+ # Set defaults for a type. The typename should already be downcased,
+ # so that the syntax is isolated. We don't do any kind of type-checking
+ # here; instead we let the resource do it when the defaults are used.
+ def setdefaults(type, params)
+ table = @defaultstable[type]
+
+ # if we got a single param, it'll be in its own array
+ params = [params] unless params.is_a?(Array)
+
+ params.each { |param|
+ #Puppet.debug "Default for %s is %s => %s" %
+ # [type,ary[0].inspect,ary[1].inspect]
+ if @@declarative
+ if table.include?(param.name)
+ self.fail "Default already defined for %s { %s }" %
+ [type,param.name]
+ end
else
- #Puppet.warning "Setting node %s at level %s" % [name, @level]
-
- # We have to store both the scope that's setting the node and
- # the node itself, so that the node gets evaluated in the correct
- # scope.
- code.scope = self
- @nodetable[name] = {
- :scope => self,
- :node => code
- }
+ if table.include?(param.name)
+ # we should maybe allow this warning to be turned off...
+ Puppet.warning "Replacing default for %s { %s }" %
+ [type,param.name]
+ end
end
- end
+ table[param.name] = param
+ }
+ end
- # Define our type.
- def settype(name,ltype)
- unless name
- raise Puppet::DevError, "Got told to set type with a nil type"
- end
- unless ltype
- raise Puppet::DevError, "Got told to set type with a nil object"
- end
- # Don't let them redefine the class in this scope.
- if @typetable.include?(name)
- raise Puppet::ParseError,
- "%s is already defined" % name
- else
- ltype.scope = self
- @typetable[name] = ltype
+ # Set a variable in the current scope. This will override settings
+ # in scopes above, but will not allow variables in the current scope
+ # to be reassigned if we're declarative (which is the default).
+ def setvar(name,value)
+ #Puppet.debug "Setting %s to '%s' at level %s" %
+ # [name.inspect,value,self.level]
+ if @@declarative and @symtable.include?(name)
+ raise Puppet::ParseError, "Cannot reassign variable %s" % name
+ else
+ if @symtable.include?(name)
+ Puppet.warning "Reassigning %s to %s" % [name,value]
end
+ @symtable[name] = value
end
+ end
- # This method will fail if the named object is already defined anywhere
- # in the scope tree, which is what provides some minimal closure-like
- # behaviour.
- def setobject(hash)
- # FIXME This objectlookup stuff should be looking up using both
- # the name and the namevar.
-
- # First see if we can look the object up using normal scope
- # rules, i.e., one of our parent classes has defined the
- # object or something
-
- name = hash[:name]
- type = hash[:type]
- params = hash[:arguments]
- file = hash[:file]
- line = hash[:line]
-
- collectable = hash[:collectable] || self.collectable
-
- # Verify that we're not overriding any already-set parameters.
- if localobj = @localobjectable[type][name]
- params.each { |var, value|
- if localobj.include?(var)
- msg = "Cannot reassign attribute %s on %s[%s]" %
- [var, type, name]
-
- error = Puppet::ParseError.new(msg)
- error.line = line
- error.file = file
- raise error
- end
- }
+ # Return an interpolated string.
+ def strinterp(string)
+ newstring = string.gsub(/\\\$|\$\{(\w+)\}|\$(\w+)/) do |value|
+ # If it matches the backslash, then just retun the dollar sign.
+ if value == '\\$'
+ '$'
+ else # look the variable up
+ var = $1 || $2
+ lookupvar($1 || $2)
end
+ end
- # First look for it in a parent scope
- obj = lookupobject(:name => name, :type => type)
-
- if obj
- unless collectable == obj.collectable
- msg = nil
- if collectable
- msg = "Exported %s[%s] cannot override local objects"
- [type, name]
- else
- msg = "Local %s[%s] cannot override exported objects"
- [type, name]
- end
-
- error = Puppet::ParseError.new(msg)
- error.line = line
- error.file = file
- raise error
- end
- end
+ return newstring.gsub(/\\t/, "\t").gsub(/\\n/, "\n").gsub(/\\s/, "\s")
+ end
- unless obj and obj != :undefined
- unless obj = @objectable[type][name]
- obj = self.newobject(
- :type => type,
- :name => name,
- :line => line,
- :file => file
- )
-
- obj.collectable = collectable
-
- # 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
+ # Add a tag to our current list. These tags will be added to all
+ # of the objects contained in this scope.
+ def tag(*ary)
+ ary.each { |tag|
+ unless tag =~ /^\w[-\w]+$/
+ fail Puppet::ParseError, "Invalid tag %s" % tag
end
-
- # 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
- }
-
- return obj
- end
-
- # Set a variable in the current scope. This will override settings
- # in scopes above, but will not allow variables in the current scope
- # to be reassigned if we're declarative (which is the default).
- def setvar(name,value)
- #Puppet.debug "Setting %s to '%s' at level %s" %
- # [name.inspect,value,self.level]
- if @@declarative and @symtable.include?(name)
- raise Puppet::ParseError, "Cannot reassign variable %s" % name
- else
- if @symtable.include?(name)
- Puppet.warning "Reassigning %s to %s" % [name,value]
- end
- @symtable[name] = value
+ if tag.nil? or tag == ""
+ puts caller
+ Puppet.debug "got told to tag with %s" % tag.inspect
+ next
end
- end
-
- # Return an interpolated string.
- def strinterp(string)
- newstring = string.gsub(/\\\$|\$\{(\w+)\}|\$(\w+)/) do |value|
- # If it matches the backslash, then just retun the dollar sign.
- if value == '\\$'
- '$'
- else # look the variable up
- var = $1 || $2
- lookupvar($1 || $2)
- end
+ tag = tag.to_s
+ unless @tags.include?(tag)
+ #Puppet.info "Tagging scope %s with %s" % [self.object_id, tag]
+ @tags << tag
end
+ }
+ end
- return newstring.gsub(/\\t/, "\t").gsub(/\\n/, "\n").gsub(/\\s/, "\s")
- end
-
- # Add a tag to our current list. These tags will be added to all
- # of the objects contained in this scope.
- def tag(*ary)
- ary.each { |tag|
+ # Return the tags associated with this scope. It's basically
+ # just our parents' tags, plus our type. We don't cache this value
+ # because our parent tags might change between calls.
+ def tags
+ tmp = [] + @tags
+ unless ! defined? @type or @type.nil? or @type == ""
+ tmp << @type.to_s
+ end
+ if @parent
+ #info "Looking for tags in %s" % @parent.type
+ @parent.tags.each { |tag|
if tag.nil? or tag == ""
- Puppet.debug "got told to tag with %s" % tag.inspect
+ Puppet.debug "parent returned tag %s" % tag.inspect
next
end
- unless @tags.include?(tag)
- #Puppet.info "Tagging scope %s with %s" % [self.object_id, tag]
- @tags << tag.to_s
+ unless tmp.include?(tag)
+ tmp << tag
end
}
end
+ return tmp.sort.uniq
+ end
- # Return the tags associated with this scope. It's basically
- # just our parents' tags, plus our type.
- def tags
- tmp = [] + @tags
- unless ! defined? @type or @type.nil? or @type == ""
- tmp << @type.to_s
- end
- if @parent
- #info "Looking for tags in %s" % @parent.type
- @parent.tags.each { |tag|
- if tag.nil? or tag == ""
- Puppet.debug "parent returned tag %s" % tag.inspect
- next
- end
- unless tmp.include?(tag)
- tmp << tag
- end
- }
- end
- return tmp
+ # Used mainly for logging
+ def to_s
+ if self.name
+ return "%s[%s]" % [@type, @name]
+ else
+ return self.type.to_s
end
+ end
- # Used mainly for logging
- def to_s
- if @name
- return "%s[%s]" % [@type, @name]
+ # Convert all of our objects as necessary.
+ def translate
+ ret = @children.collect do |child|
+ case child
+ when self.class
+ child.translate
+ when Puppet::Parser::Resource
+ child.to_trans
else
- return @type.to_s
+ devfail "Got %s for translation" % child.class
end
+ end.reject { |o| o.nil? }
+ bucket = Puppet::TransBucket.new ret
+ unless self.type
+ devfail "A Scope with no type"
end
+ if @type == ""
+ bucket.type = "main"
+ else
+ bucket.type = @type
+ end
+ if self.name
+ bucket.name = self.name
+ end
+ return bucket
+ end
- # Convert our scope to a TransBucket. Everything in our @localobjecttable
- # gets converted to either an evaluated definition, or a TransObject
- def to_trans
- results = []
-
- # Set this on entry, just in case someone tries to get all weird
- @translated = true
-
- @children.dup.each do |child|
- if @@done.include?(child)
- raise Puppet::DevError, "Already translated %s" %
- child.object_id
- else
- @@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
- 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. Retain whether
- # the object is collectable. If the object is collectable,
- # then it will store all of its contents into the
- # @exportable table, rather than returning them.
- result = objecttype.safeevaluate(
- :name => child.name,
- :type => child.type,
- :arguments => child.to_hash,
- :scope => self,
- :collectable => child.collectable
- )
- else
- # If it's collectable, then store it. It will be
- # stripped out in the interpreter using the collectstrip
- # method. If we don't do this, then these objects
- # don't get stored in the DB.
- if child.collectable
- exportobject(child)
- end
- result = child
- end
- # This is pretty hackish, but the collection has to actually
- # be performed after all of the classes and definitions are
- # evaluated, otherwise we won't catch objects that are exported
- # in them. I think this will still be pretty limited in some
- # cases, especially those where you are both exporting and
- # collecting, but it's the best I can do for now.
- when Puppet::Parser::AST::Collection
- child.perform(self).each do |obj|
- results << obj
- end
- else
- raise Puppet::DevError,
- "Puppet::Parse::Scope cannot handle objects of type %s" %
- child.class
- end
-
- # Skip nil objects or empty transbuckets
- if result
- unless result.is_a? Puppet::TransBucket and result.empty?
- results << result
- end
- end
- end
-
- # Get rid of any nil objects.
- results.reject! { |child|
- child.nil?
- }
+ # Undefine a variable; only used for testing.
+ def unsetvar(var)
+ if @symtable.include?(var)
+ @symtable.delete(var)
+ end
+ end
- # 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
+ # Return an array of all of the unevaluated objects
+ def unevaluated
+ ary = @definedtable.find_all do |name, object|
+ ! object.builtin? and ! object.evaluated?
+ end.collect { |name, object| object }
- 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
+ if ary.empty?
+ return nil
+ else
+ return ary
end
+ end
- # Undefine a variable; only used for testing.
- def unsetvar(var)
- if @symtable.include?(var)
- @symtable.delete(var)
- end
- end
+ protected
- protected
-
- # This method abstracts recursive searching. It accepts the type
- # of search being done and then either a literal key to search for or
- # a Proc instance to do the searching.
- def lookup(type,sub, usecontext = false)
- table = @map[type]
- if table.nil?
- error = Puppet::ParseError.new(
- "Could not retrieve %s table at level %s" %
- [type,self.level]
- )
- raise error
- end
+ # This method abstracts recursive searching. It accepts the type
+ # of search being done and then either a literal key to search for or
+ # a Proc instance to do the searching.
+ def lookup(type,sub, usecontext = false)
+ table = @map[type]
+ if table.nil?
+ self.fail "Could not retrieve %s table at level %s" %
+ [type,self.level]
+ end
- if sub.is_a?(Proc) and obj = sub.call(table)
- return obj
- elsif table.include?(sub)
- return table[sub]
- elsif ! @parent.nil?
- # Context is used for retricting overrides.
- if usecontext and self.context != @parent.context
- return :undefined
- else
- return @parent.lookup(type,sub, usecontext)
- end
- else
+ if sub.is_a?(Proc) and obj = sub.call(table)
+ return obj
+ elsif table.include?(sub)
+ return table[sub]
+ elsif ! @parent.nil?
+ # Context is used for retricting overrides.
+ if usecontext and self.context != @parent.context
return :undefined
+ else
+ return @parent.lookup(type,sub, usecontext)
end
+ else
+ return :undefined
end
end
end
diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb
new file mode 100644
index 000000000..62b45852b
--- /dev/null
+++ b/lib/puppet/parser/templatewrapper.rb
@@ -0,0 +1,58 @@
+# A simple wrapper for templates, so they don't have full access to
+# the scope objects.
+class Puppet::Parser::TemplateWrapper
+ attr_accessor :scope, :file
+ include Puppet::Util
+ Puppet::Util.logmethods(self)
+
+ def initialize(scope, file)
+ @scope = scope
+ if file =~ /^#{File::SEPARATOR}/
+ @file = file
+ else
+ @file = File.join(Puppet[:templatedir], file)
+ end
+
+ unless FileTest.exists?(@file)
+ raise Puppet::ParseError,
+ "Could not find template %s" % file
+ end
+
+ # We'll only ever not have an interpreter in testing, but, eh.
+ if @scope.interp
+ @scope.interp.newfile(@file)
+ end
+ end
+
+ # Ruby treats variables like methods, so we can cheat here and
+ # trap missing vars like they were missing methods.
+ def method_missing(name, *args)
+ # We have to tell lookupvar to return :undefined to us when
+ # appropriate; otherwise it converts to "".
+ value = @scope.lookupvar(name.to_s, false)
+ if value != :undefined
+ return value
+ else
+ # Just throw an error immediately, instead of searching for
+ # other missingmethod things or whatever.
+ raise Puppet::ParseError,
+ "Could not find value for '%s'" % name
+ end
+ end
+
+ def result
+ result = nil
+ benchmark(:debug, "Interpolated template #{@file}") do
+ template = ERB.new(File.read(@file), 0, "-")
+ result = template.result(binding)
+ end
+
+ result
+ end
+
+ def to_s
+ "template[%s]" % @file
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/rails/database.rb b/lib/puppet/rails/database.rb
index caf87cbb8..8be05bd88 100644
--- a/lib/puppet/rails/database.rb
+++ b/lib/puppet/rails/database.rb
@@ -6,20 +6,23 @@ class Puppet::Rails::Database < ActiveRecord::Migration
ActiveRecord::Migration.verbose = false
end
- create_table :rails_objects do |table|
- table.column :name, :string, :null => false
- table.column :ptype, :string, :null => false
+ # 'type' cannot be a column name, apparently
+ create_table :rails_resources do |table|
+ table.column :title, :string, :null => false
+ table.column :restype, :string, :null => false
table.column :tags, :string
table.column :file, :string
table.column :line, :integer
table.column :host_id, :integer
- table.column :collectable, :boolean
+ table.column :exported, :boolean
end
create_table :rails_parameters do |table|
table.column :name, :string, :null => false
table.column :value, :string, :null => false
- table.column :rails_object_id, :integer
+ table.column :file, :string
+ table.column :line, :integer
+ table.column :rails_resource_id, :integer
end
create_table :hosts do |table|
@@ -33,8 +36,10 @@ class Puppet::Rails::Database < ActiveRecord::Migration
end
def self.down
- drop_table :rails_objects
+ drop_table :rails_resources
drop_table :rails_parameters
drop_table :hosts
end
end
+
+# $Id$
diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb
index 77123c871..ccda1af64 100644
--- a/lib/puppet/rails/host.rb
+++ b/lib/puppet/rails/host.rb
@@ -1,11 +1,12 @@
-require 'puppet/rails/rails_object'
+require 'puppet/rails/rails_resource'
#RailsObject = Puppet::Rails::RailsObject
class Puppet::Rails::Host < ActiveRecord::Base
serialize :facts, Hash
serialize :classes, Array
- has_many :rails_objects, :dependent => :delete_all
+ has_many :rails_resources, :dependent => :delete_all,
+ :include => :rails_parameters
# If the host already exists, get rid of its objects
def self.clean(host)
@@ -19,40 +20,43 @@ class Puppet::Rails::Host < ActiveRecord::Base
# Store our host in the database.
def self.store(hash)
- name = hash[:host] || "localhost"
- ip = hash[:ip] || "127.0.0.1"
- facts = hash[:facts] || {}
- objects = hash[:objects]
+ unless hash[:name]
+ raise ArgumentError, "You must specify the hostname for storage"
+ end
- unless objects
- raise ArgumentError, "You must pass objects"
+ args = {}
+ [:name, :facts, :classes].each do |param|
+ if hash[param]
+ args[param] = hash[param]
+ end
end
- hostargs = {
- :name => name,
- :ip => ip,
- :facts => facts,
- :classes => objects.classes
- }
+ if hash[:facts].include?("ipaddress")
+ args[:ip] = hash[:facts]["ipaddress"]
+ end
- objects = objects.flatten
+ unless hash[:resources]
+ raise ArgumentError, "You must pass resources"
+ end
- host = nil
- if host = clean(name)
- [:name, :facts, :classes].each do |param|
- unless host[param] == hostargs[param]
- host[param] = hostargs[param]
+ if host = self.find_by_name(hash[:name])
+ args.each do |param, value|
+ unless host[param] == args[param]
+ host[param] = args[param]
end
end
- host.addobjects(objects)
else
- host = self.new(hostargs) do |hostobj|
- hostobj.addobjects(objects)
- end
+ # Create it anew
+ host = self.new(args)
end
+ hash[:resources].each do |res|
+ res.store(host)
+ end
- host.save
+ Puppet::Util.benchmark(:info, "Saved host to database") do
+ host.save
+ end
return host
end
diff --git a/lib/puppet/rails/rails_object.rb b/lib/puppet/rails/rails_object.rb
deleted file mode 100644
index d1e58e453..000000000
--- a/lib/puppet/rails/rails_object.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require 'puppet'
-require 'puppet/rails/rails_parameter'
-
-#RailsParameter = Puppet::Rails::RailsParameter
-class Puppet::Rails::RailsObject < ActiveRecord::Base
- has_many :rails_parameters, :dependent => :delete_all
- serialize :tags, Array
-
- belongs_to :host
-
- # Add a set of parameters.
- def addparams(params)
- params.each do |pname, pvalue|
- rails_parameters.build(
- :name => pname,
- :value => pvalue
- )
-
- #self.rails_parameters << pobj
- end
- end
-
- # Convert our object to a trans_object. Do not retain whether the object
- # is collectable, though, since that would cause it to get stripped
- # from the configuration.
- def to_trans
- obj = Puppet::TransObject.new(name(), ptype())
-
- [:file, :line, :tags].each do |method|
- if val = send(method)
- obj.send(method.to_s + "=", val)
- end
- end
- rails_parameters.each do |param|
- obj[param.name] = param.value
- end
-
- return obj
- end
-end
-
-# $Id$
diff --git a/lib/puppet/rails/rails_parameter.rb b/lib/puppet/rails/rails_parameter.rb
index a1966e3dc..295662146 100644
--- a/lib/puppet/rails/rails_parameter.rb
+++ b/lib/puppet/rails/rails_parameter.rb
@@ -1,5 +1,13 @@
class Puppet::Rails::RailsParameter < ActiveRecord::Base
- belongs_to :rails_objects
+ belongs_to :rails_resources
+
+ def to_resourceparam(source)
+ hash = self.attributes
+ hash[:source] = source
+ hash.delete("rails_resource_id")
+ hash.delete("id")
+ Puppet::Parser::Resource::Param.new hash
+ end
end
# $Id$
diff --git a/lib/puppet/rails/rails_resource.rb b/lib/puppet/rails/rails_resource.rb
new file mode 100644
index 000000000..caad1b460
--- /dev/null
+++ b/lib/puppet/rails/rails_resource.rb
@@ -0,0 +1,34 @@
+require 'puppet'
+require 'puppet/rails/rails_parameter'
+
+#RailsParameter = Puppet::Rails::RailsParameter
+class Puppet::Rails::RailsResource < ActiveRecord::Base
+ has_many :rails_parameters, :dependent => :delete_all
+ serialize :tags, Array
+
+ belongs_to :host
+
+ # Convert our object to a resource. Do not retain whether the object
+ # is collectable, though, since that would cause it to get stripped
+ # from the configuration.
+ def to_resource(scope)
+ hash = self.attributes
+ hash["type"] = hash["restype"]
+ hash.delete("restype")
+ hash.delete("host_id")
+ hash.delete("id")
+ hash.each do |p, v|
+ hash.delete(p) if v.nil?
+ end
+ hash[:scope] = scope
+ hash[:source] = scope.source
+ obj = Puppet::Parser::Resource.new(hash)
+ rails_parameters.each do |param|
+ obj.set(param.to_resourceparam(scope.source))
+ end
+
+ return obj
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
index 90bc70fc2..4b43b9825 100644
--- a/lib/puppet/transportable.rb
+++ b/lib/puppet/transportable.rb
@@ -141,8 +141,8 @@ module Puppet
end.flatten
end
- def initialize
- @children = []
+ def initialize(children = [])
+ @children = children
end
def push(*args)
@@ -219,7 +219,7 @@ module Puppet
else
#Puppet.debug "%s[%s] has no parameters" % [@type, @name]
end
- container = Puppet.type(:component).create(trans)
+ container = Puppet::Type::Component.create(trans)
else
hash = {
:name => self.name,
@@ -238,7 +238,7 @@ module Puppet
#if parent
# hash[:parent] = parent
#end
- container = Puppet.type(:component).create(hash)
+ container = Puppet::Type::Component.create(hash)
end
#Puppet.info container.inspect
@@ -267,8 +267,10 @@ module Puppet
begin
child.to_type(container)
rescue => detail
- # We don't do anything on failures, since we assume it's
- # been logged elsewhere.
+ if Puppet[:trace] and ! detail.is_a?(Puppet::Error)
+ puts detail.backtrace
+ end
+ Puppet.err detail.to_s
end
}
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 320aa83a0..55421eb4c 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -856,9 +856,7 @@ class Type < Puppet::Element
end
def self.validattr?(name)
- if name.is_a?(String)
- name = name.intern
- end
+ name = symbolize(name)
if self.validstate?(name) or self.validparameter?(name) or self.metaparam?(name)
return true
else
@@ -1017,32 +1015,6 @@ class Type < Puppet::Element
}
end
- def devfail(msg)
- self.fail(Puppet::DevError, msg)
- end
-
- # Throw an error, defaulting to a Puppet::Error
- def fail(*args)
- type = nil
- if args[0].is_a?(Class)
- type = args.shift
- else
- type = Puppet::Error
- end
-
- error = type.new(args.join(" "))
-
- if defined? @line and @line
- error.line = @line
- end
-
- if defined? @file and @file
- error.file = @file
- end
-
- raise error
- end
-
# retrieve the 'is' value for a specified state
def is(state)
if @states.include?(state)
@@ -2141,6 +2113,7 @@ class Type < Puppet::Element
# Is the parameter in question a meta-parameter?
def self.metaparam?(param)
+ param = symbolize(param)
@@metaparamhash.include?(param)
end
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index d8b8c812f..755c254d2 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -456,11 +456,13 @@ module Util
end
end
+require 'puppet/util/errors'
require 'puppet/util/methodhelper'
require 'puppet/util/metaid'
require 'puppet/util/classgen'
require 'puppet/util/docs'
require 'puppet/util/execution'
+require 'puppet/util/logging'
require 'puppet/util/package'
require 'puppet/util/warnings'
diff --git a/lib/puppet/util/errors.rb b/lib/puppet/util/errors.rb
new file mode 100644
index 000000000..ad129ee34
--- /dev/null
+++ b/lib/puppet/util/errors.rb
@@ -0,0 +1,55 @@
+# Some helper methods for throwing errors.
+module Puppet::Util::Errors
+ # Throw a dev error.
+ def devfail(msg)
+ self.fail(Puppet::DevError, msg)
+ end
+
+ # Add line and file info if available and appropriate.
+ def adderrorcontext(error, other = nil)
+ error.line ||= self.line if self.respond_to?(:line) and self.line
+ error.file ||= self.file if self.respond_to?(:file) and self.file
+
+ if other and other.respond_to?(:backtrace)
+ error.set_backtrace other.backtrace
+ end
+
+ return error
+ end
+
+ # Wrap a call in such a way that we always throw the right exception and keep
+ # as much context as possible.
+ def exceptwrap(options = {})
+ options[:type] ||= Puppet::DevError
+ begin
+ retval = yield
+ rescue Puppet::Error => detail
+ raise adderrorcontext(detail)
+ rescue => detail
+ message = options[:message] || "%s failed with error %s: %s" %
+ [self.class, detail.class, detail.to_s]
+
+ error = options[:type].new(message)
+ # We can't use self.fail here because it always expects strings,
+ # not exceptions.
+ raise adderrorcontext(error, detail)
+ end
+
+ return retval
+ end
+
+ # Throw an error, defaulting to a Puppet::Error.
+ def fail(*args)
+ if args[0].is_a?(Class)
+ type = args.shift
+ else
+ type = Puppet::Error
+ end
+
+ error = adderrorcontext(type.new(args.join(" ")))
+
+ raise error
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/util/logging.rb b/lib/puppet/util/logging.rb
new file mode 100644
index 000000000..1245e24de
--- /dev/null
+++ b/lib/puppet/util/logging.rb
@@ -0,0 +1,20 @@
+# A module to make logging a bit easier.
+require 'puppet/log'
+
+module Puppet::Util::Logging
+ # Create a method for each log level.
+ Puppet::Log.eachlevel do |level|
+ define_method(level) do |args|
+ if args.is_a?(Array)
+ args = args.join(" ")
+ end
+ Puppet::Log.create(
+ :level => level,
+ :source => self,
+ :message => args
+ )
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/util/methodhelper.rb b/lib/puppet/util/methodhelper.rb
index 5643ac245..c229e8efb 100644
--- a/lib/puppet/util/methodhelper.rb
+++ b/lib/puppet/util/methodhelper.rb
@@ -1,5 +1,26 @@
# Where we store helper methods related to, um, methods.
module Puppet::Util::MethodHelper
+ def requiredopts(*names)
+ names.each do |name|
+ if self.send(name).nil?
+ devfail("%s is a required option for %s" % [name, self.class])
+ end
+ end
+ end
+
+ # Iterate over a hash, treating each member as an attribute.
+ def set_options(options)
+ options.dup.each do |param,value|
+ method = param.to_s + "="
+ unless self.respond_to?(method)
+ self.fail "Invalid parameter %s to object class %s" %
+ [param,self.class.to_s]
+ end
+
+ self.send(method,value)
+ end
+ end
+
# Take a hash and convert all of the keys to symbols if possible.
def symbolize_options(options)
options.inject({}) do |hash, opts|