diff options
| author | Markus Roberts <Markus@reality.com> | 2010-07-09 18:12:17 -0700 |
|---|---|---|
| committer | Markus Roberts <Markus@reality.com> | 2010-07-09 18:12:17 -0700 |
| commit | 3180b9d9b2c844dade1d361326600f7001ec66dd (patch) | |
| tree | 98fe7c5ac7eb942aac9c39f019a17b0b3f5a57f4 /lib/puppet/parser | |
| parent | 543225970225de5697734bfaf0a6eee996802c04 (diff) | |
| download | puppet-3180b9d9b2c844dade1d361326600f7001ec66dd.tar.gz puppet-3180b9d9b2c844dade1d361326600f7001ec66dd.tar.xz puppet-3180b9d9b2c844dade1d361326600f7001ec66dd.zip | |
Code smell: Two space indentation
Replaced 106806 occurances of ^( +)(.*$) with
The ruby community almost universally (i.e. everyone but Luke, Markus, and the other eleven people
who learned ruby in the 1900s) uses two-space indentation.
3 Examples:
The code:
end
# Tell getopt which arguments are valid
def test_get_getopt_args
element = Setting.new :name => "foo", :desc => "anything", :settings => Puppet::Util::Settings.new
assert_equal([["--foo", GetoptLong::REQUIRED_ARGUMENT]], element.getopt_args, "Did not produce appropriate getopt args")
becomes:
end
# Tell getopt which arguments are valid
def test_get_getopt_args
element = Setting.new :name => "foo", :desc => "anything", :settings => Puppet::Util::Settings.new
assert_equal([["--foo", GetoptLong::REQUIRED_ARGUMENT]], element.getopt_args, "Did not produce appropriate getopt args")
The code:
assert_equal(str, val)
assert_instance_of(Float, result)
end
# Now test it with a passed object
becomes:
assert_equal(str, val)
assert_instance_of(Float, result)
end
# Now test it with a passed object
The code:
end
assert_nothing_raised do
klass[:Yay] = "boo"
klass["Cool"] = :yayness
end
becomes:
end
assert_nothing_raised do
klass[:Yay] = "boo"
klass["Cool"] = :yayness
end
Diffstat (limited to 'lib/puppet/parser')
62 files changed, 4292 insertions, 4292 deletions
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index dffc30a8a..2773a240e 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -8,85 +8,85 @@ require 'puppet/file_collection/lookup' # 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 + # Do this so I don't have to type the full path in all of the subclasses + AST = Puppet::Parser::AST - include Puppet::FileCollection::Lookup + include Puppet::FileCollection::Lookup - include Puppet::Util::Errors - include Puppet::Util::MethodHelper - include Puppet::Util::Docs + include Puppet::Util::Errors + include Puppet::Util::MethodHelper + include Puppet::Util::Docs - attr_accessor :parent, :scope + attr_accessor :parent, :scope - # don't fetch lexer comment by default - def use_docs - self.class.use_docs - end + # don't fetch lexer comment by default + def use_docs + self.class.use_docs + end - # allow our subclass to specify they want documentation - class << self - attr_accessor :use_docs - def associates_doc - self.use_docs = true - end + # allow our subclass to specify they want documentation + class << self + attr_accessor :use_docs + def associates_doc + self.use_docs = true end + end - # Does this ast object set something? If so, it gets evaluated first. - def self.settor? - if defined?(@settor) - @settor - else - false - end + # Does this ast object set something? If so, it gets evaluated first. + def self.settor? + if defined?(@settor) + @settor + else + false end + end - # Evaluate the current object. Just a stub method, since the subclass - # should override this method. - # of the contained children and evaluates them in turn, returning a - # list of all of the collected values, rejecting nil values - def evaluate(*options) - raise Puppet::DevError, "Did not override #evaluate in #{self.class}" - end + # Evaluate the current object. Just a stub method, since the subclass + # should override this method. + # of the contained children and evaluates them in turn, returning a + # list of all of the collected values, rejecting nil values + def evaluate(*options) + raise Puppet::DevError, "Did not override #evaluate in #{self.class}" + end - # Throw a parse error. - def parsefail(message) - self.fail(Puppet::ParseError, message) - 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 + # 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(*options) - # We duplicate code here, rather than using exceptwrap, because this - # is called so many times during parsing. - begin - return self.evaluate(*options) - rescue Puppet::Error => detail - raise adderrorcontext(detail) - rescue => detail - error = Puppet::Error.new(detail.to_s) - # We can't use self.fail here because it always expects strings, - # not exceptions. - raise adderrorcontext(error, detail) - 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(*options) + # We duplicate code here, rather than using exceptwrap, because this + # is called so many times during parsing. + begin + return self.evaluate(*options) + rescue Puppet::Error => detail + raise adderrorcontext(detail) + rescue => detail + error = Puppet::Error.new(detail.to_s) + # We can't use self.fail here because it always expects strings, + # not exceptions. + raise adderrorcontext(error, detail) end + 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) - set_options(args) - 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) + set_options(args) + end end # And include all of the AST subclasses. diff --git a/lib/puppet/parser/ast/arithmetic_operator.rb b/lib/puppet/parser/ast/arithmetic_operator.rb index 6b9a6018c..33352d727 100644 --- a/lib/puppet/parser/ast/arithmetic_operator.rb +++ b/lib/puppet/parser/ast/arithmetic_operator.rb @@ -2,38 +2,38 @@ require 'puppet' require 'puppet/parser/ast/branch' class Puppet::Parser::AST - class ArithmeticOperator < AST::Branch + class ArithmeticOperator < AST::Branch - attr_accessor :operator, :lval, :rval + attr_accessor :operator, :lval, :rval - # Iterate across all of our children. - def each - [@lval,@rval,@operator].each { |child| yield child } - end + # Iterate across all of our children. + def each + [@lval,@rval,@operator].each { |child| yield child } + end - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - # evaluate the operands, should return a boolean value - lval = @lval.safeevaluate(scope) - lval = Puppet::Parser::Scope.number?(lval) - if lval == nil - raise ArgumentError, "left operand of #{@operator} is not a number" - end - rval = @rval.safeevaluate(scope) - rval = Puppet::Parser::Scope.number?(rval) - if rval == nil - raise ArgumentError, "right operand of #{@operator} is not a number" - end + # Returns a boolean which is the result of the boolean operation + # of lval and rval operands + def evaluate(scope) + # evaluate the operands, should return a boolean value + lval = @lval.safeevaluate(scope) + lval = Puppet::Parser::Scope.number?(lval) + if lval == nil + raise ArgumentError, "left operand of #{@operator} is not a number" + end + rval = @rval.safeevaluate(scope) + rval = Puppet::Parser::Scope.number?(rval) + if rval == nil + raise ArgumentError, "right operand of #{@operator} is not a number" + end - # compute result - lval.send(@operator, rval) - end + # compute result + lval.send(@operator, rval) + end - def initialize(hash) - super + def initialize(hash) + super - raise ArgumentError, "Invalid arithmetic operator #{@operator}" unless %w{+ - * / << >>}.include?(@operator) - end + raise ArgumentError, "Invalid arithmetic operator #{@operator}" unless %w{+ - * / << >>}.include?(@operator) end + end end diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index f0a0c5602..529998e3c 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -1,61 +1,61 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # The basic container class. This object behaves almost identically - # to a normal array except at initialization time. Note that its name - # is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many - # bugs when it was just 'AST::Array', because things like - # 'object.is_a?(Array)' never behaved as I expected. - class ASTArray < Branch - include Enumerable - - # Return a child by index. Probably never used. - def [](index) - @children[index] - end + # The basic container class. This object behaves almost identically + # to a normal array except at initialization time. Note that its name + # is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many + # bugs when it was just 'AST::Array', because things like + # 'object.is_a?(Array)' never behaved as I expected. + class ASTArray < Branch + include Enumerable + + # Return a child by index. Probably never used. + def [](index) + @children[index] + end - # Evaluate our children. - def evaluate(scope) - # Make a new array, so we don't have to deal with the details of - # flattening and such - items = [] - - # First clean out any AST::ASTArrays - @children.each { |child| - if child.instance_of?(AST::ASTArray) - child.each do |ac| - items << ac - end - else - items << child - end - } - - rets = items.flatten.collect { |child| - child.safeevaluate(scope) - } - rets.reject { |o| o.nil? } + # Evaluate our children. + def evaluate(scope) + # Make a new array, so we don't have to deal with the details of + # flattening and such + items = [] + + # First clean out any AST::ASTArrays + @children.each { |child| + if child.instance_of?(AST::ASTArray) + child.each do |ac| + items << ac + end + else + items << child end + } - def push(*ary) - ary.each { |child| - #Puppet.debug "adding %s(%s) of type %s to %s" % - # [child, child.object_id, child.class.to_s.sub(/.+::/,''), - # self.object_id] - @children.push(child) - } + rets = items.flatten.collect { |child| + child.safeevaluate(scope) + } + rets.reject { |o| o.nil? } + end - self - end + def push(*ary) + ary.each { |child| + #Puppet.debug "adding %s(%s) of type %s to %s" % + # [child, child.object_id, child.class.to_s.sub(/.+::/,''), + # self.object_id] + @children.push(child) + } - def to_s - "[" + @children.collect { |c| c.to_s }.join(', ') + "]" - end + self + end + + def to_s + "[" + @children.collect { |c| c.to_s }.join(', ') + "]" end + end - # A simple container class, containing the parameters for an object. - # Used for abstracting the grammar declarations. Basically unnecessary - # except that I kept finding bugs because I had too many arrays that - # meant completely different things. - class ResourceInstance < ASTArray; end + # A simple container class, containing the parameters for an object. + # Used for abstracting the grammar declarations. Basically unnecessary + # except that I kept finding bugs because I had too many arrays that + # meant completely different things. + class ResourceInstance < ASTArray; end end diff --git a/lib/puppet/parser/ast/asthash.rb b/lib/puppet/parser/ast/asthash.rb index d16b7459f..ae81d35dd 100644 --- a/lib/puppet/parser/ast/asthash.rb +++ b/lib/puppet/parser/ast/asthash.rb @@ -1,37 +1,37 @@ require 'puppet/parser/ast/leaf' class Puppet::Parser::AST - class ASTHash < Leaf - include Enumerable + class ASTHash < Leaf + include Enumerable - # Evaluate our children. - def evaluate(scope) - items = {} + # Evaluate our children. + def evaluate(scope) + items = {} - @value.each_pair do |k,v| - key = k.respond_to?(:safeevaluate) ? k.safeevaluate(scope) : k - items.merge!({ key => v.safeevaluate(scope) }) - end + @value.each_pair do |k,v| + key = k.respond_to?(:safeevaluate) ? k.safeevaluate(scope) : k + items.merge!({ key => v.safeevaluate(scope) }) + end - items - end + items + end - def merge(hash) - case hash - when ASTHash - @value = @value.merge(hash.value) - when Hash - @value = @value.merge(hash) - end - end + def merge(hash) + case hash + when ASTHash + @value = @value.merge(hash.value) + when Hash + @value = @value.merge(hash) + end + end - def to_s - "{" + @value.collect { |v| v.collect { |a| a.to_s }.join(' => ') }.join(', ') + "}" - end + def to_s + "{" + @value.collect { |v| v.collect { |a| a.to_s }.join(' => ') }.join(', ') + "}" + end - def initialize(args) - super(args) - @value ||= {} - end + def initialize(args) + super(args) + @value ||= {} end + end end diff --git a/lib/puppet/parser/ast/boolean_operator.rb b/lib/puppet/parser/ast/boolean_operator.rb index 0f7e21d2c..8481e4f8d 100644 --- a/lib/puppet/parser/ast/boolean_operator.rb +++ b/lib/puppet/parser/ast/boolean_operator.rb @@ -2,45 +2,45 @@ require 'puppet' require 'puppet/parser/ast/branch' class Puppet::Parser::AST - class BooleanOperator < AST::Branch + class BooleanOperator < AST::Branch - attr_accessor :operator, :lval, :rval + attr_accessor :operator, :lval, :rval - # Iterate across all of our children. - def each - [@lval,@rval,@operator].each { |child| yield child } - end + # Iterate across all of our children. + def each + [@lval,@rval,@operator].each { |child| yield child } + end - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - # evaluate the first operand, should return a boolean value - lval = @lval.safeevaluate(scope) + # Returns a boolean which is the result of the boolean operation + # of lval and rval operands + def evaluate(scope) + # evaluate the first operand, should return a boolean value + lval = @lval.safeevaluate(scope) - # return result - # lazy evaluate right operand - case @operator - when "and" - if Puppet::Parser::Scope.true?(lval) - rval = @rval.safeevaluate(scope) - Puppet::Parser::Scope.true?(rval) - else # false and false == false - false - end - when "or" - if Puppet::Parser::Scope.true?(lval) - true - else - rval = @rval.safeevaluate(scope) - Puppet::Parser::Scope.true?(rval) - end - end + # return result + # lazy evaluate right operand + case @operator + when "and" + if Puppet::Parser::Scope.true?(lval) + rval = @rval.safeevaluate(scope) + Puppet::Parser::Scope.true?(rval) + else # false and false == false + false + end + when "or" + if Puppet::Parser::Scope.true?(lval) + true + else + rval = @rval.safeevaluate(scope) + Puppet::Parser::Scope.true?(rval) end + end + end - def initialize(hash) - super + def initialize(hash) + super - raise ArgumentError, "Invalid boolean operator #{@operator}" unless %w{and or}.include?(@operator) - end + raise ArgumentError, "Invalid boolean operator #{@operator}" unless %w{and or}.include?(@operator) end + end end diff --git a/lib/puppet/parser/ast/branch.rb b/lib/puppet/parser/ast/branch.rb index 96d065e4c..73a2f674b 100644 --- a/lib/puppet/parser/ast/branch.rb +++ b/lib/puppet/parser/ast/branch.rb @@ -1,37 +1,37 @@ class Puppet::Parser::AST - # The parent class of all AST objects that contain other AST objects. - # Everything but the really simple objects descend from this. It is - # important to note that Branch objects contain other AST objects only -- - # if you want to contain values, use a descendent of the AST::Leaf class. - class Branch < AST - include Enumerable - attr_accessor :pin, :children + # The parent class of all AST objects that contain other AST objects. + # Everything but the really simple objects descend from this. It is + # important to note that Branch objects contain other AST objects only -- + # if you want to contain values, use a descendent of the AST::Leaf class. + class Branch < AST + include Enumerable + attr_accessor :pin, :children - # Yield each contained AST node in turn. Used mostly by 'evaluate'. - # This definition means that I don't have to override 'evaluate' - # every time, but each child of Branch will likely need to override - # this method. - def each - @children.each { |child| - yield child - } - end + # Yield each contained AST node in turn. Used mostly by 'evaluate'. + # This definition means that I don't have to override 'evaluate' + # every time, but each child of Branch will likely need to override + # this method. + def each + @children.each { |child| + yield child + } + end - # Initialize our object. Largely relies on the method from the base - # class, but also does some verification. - def initialize(arghash) - super(arghash) + # Initialize our object. Largely relies on the method from the base + # class, but also does some verification. + def initialize(arghash) + super(arghash) - # Create the hash, if it was not set at initialization time. - @children ||= [] + # Create the hash, if it was not set at initialization time. + @children ||= [] - # Verify that we only got valid AST nodes. - @children.each { |child| - unless child.is_a?(AST) - raise Puppet::DevError, - "child #{child} is a #{child.class} instead of ast" - end - } + # Verify that we only got valid AST nodes. + @children.each { |child| + unless child.is_a?(AST) + raise Puppet::DevError, + "child #{child} is a #{child.class} instead of ast" end + } end + end end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index 6cf36f94c..4e296e82f 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -1,64 +1,64 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # Each individual option in a case statement. - class CaseOpt < AST::Branch - attr_accessor :value, :statements + # Each individual option in a case statement. + class CaseOpt < AST::Branch + attr_accessor :value, :statements - # CaseOpt is a bit special -- we just want the value first, - # so that CaseStatement can compare, and then it will selectively - # decide whether to fully evaluate this option + # CaseOpt is a bit special -- we just want the value first, + # so that CaseStatement can compare, and then it will selectively + # decide whether to fully evaluate this option - def each - [@value,@statements].each { |child| yield child } - end + def each + [@value,@statements].each { |child| yield child } + end - # Are we the default option? - def default? - # Cache the @default value. - return @default if defined?(@default) + # Are we the default option? + def default? + # Cache the @default value. + return @default if defined?(@default) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - if subval.is_a?(AST::Default) - @default = true - break - end - } - else - @default = true if @value.is_a?(AST::Default) - end + if @value.is_a?(AST::ASTArray) + @value.each { |subval| + if subval.is_a?(AST::Default) + @default = true + break + end + } + else + @default = true if @value.is_a?(AST::Default) + end - @default ||= false + @default ||= false - @default - end + @default + end - # You can specify a list of values; return each in turn. - def eachvalue(scope) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval.safeevaluate(scope) - } - else - yield @value.safeevaluate(scope) - end - end + # You can specify a list of values; return each in turn. + def eachvalue(scope) + if @value.is_a?(AST::ASTArray) + @value.each { |subval| + yield subval.safeevaluate(scope) + } + else + yield @value.safeevaluate(scope) + end + end - def eachopt - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval - } - else - yield @value - end - end + def eachopt + if @value.is_a?(AST::ASTArray) + @value.each { |subval| + yield subval + } + else + yield @value + end + end - # Evaluate the actual statements; this only gets called if - # our option matched. - def evaluate(scope) - @statements.safeevaluate(scope) - end + # Evaluate the actual statements; this only gets called if + # our option matched. + def evaluate(scope) + @statements.safeevaluate(scope) end + end end diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb index 0cddef0f0..8370d11f3 100644 --- a/lib/puppet/parser/ast/casestatement.rb +++ b/lib/puppet/parser/ast/casestatement.rb @@ -1,44 +1,44 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # The basic logical structure in Puppet. Supports a list of - # tests and statement arrays. - class CaseStatement < AST::Branch - attr_accessor :test, :options, :default + # The basic logical structure in Puppet. Supports a list of + # tests and statement arrays. + class CaseStatement < AST::Branch + attr_accessor :test, :options, :default - associates_doc + associates_doc - # Short-curcuit evaluation. Return the value of the statements for - # the first option that matches. - def evaluate(scope) - level = scope.ephemeral_level + # Short-curcuit evaluation. Return the value of the statements for + # the first option that matches. + def evaluate(scope) + level = scope.ephemeral_level - value = @test.safeevaluate(scope) + value = @test.safeevaluate(scope) - retvalue = nil - found = false + retvalue = nil + found = false - # Iterate across the options looking for a match. - default = nil - @options.each do |option| - option.eachopt do |opt| - return option.safeevaluate(scope) if opt.evaluate_match(value, scope) - end + # Iterate across the options looking for a match. + default = nil + @options.each do |option| + option.eachopt do |opt| + return option.safeevaluate(scope) if opt.evaluate_match(value, scope) + end - default = option if option.default? - end + default = option if option.default? + end - # Unless we found something, look for the default. - return default.safeevaluate(scope) if default + # Unless we found something, look for the default. + return default.safeevaluate(scope) if default - Puppet.debug "No true answers and no default" - return nil - ensure - scope.unset_ephemeral_var(level) - end + Puppet.debug "No true answers and no default" + return nil + ensure + scope.unset_ephemeral_var(level) + end - def each - [@test,@options].each { |child| yield child } - end + def each + [@test,@options].each { |child| yield child } end + end end diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index 44f3b330c..09d5b4eb3 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -6,60 +6,60 @@ require 'puppet/parser/collector' # them to the current host, yo. class Puppet::Parser::AST class Collection < AST::Branch - attr_accessor :type, :query, :form - attr_reader :override + attr_accessor :type, :query, :form + attr_reader :override - associates_doc + associates_doc - # We return an object that does a late-binding evaluation. - def evaluate(scope) - if self.query - str, code = self.query.safeevaluate scope - else - str = code = nil - end + # We return an object that does a late-binding evaluation. + def evaluate(scope) + if self.query + str, code = self.query.safeevaluate scope + else + str = code = nil + end - newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) + newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) - scope.compiler.add_collection(newcoll) + scope.compiler.add_collection(newcoll) - # overrides if any - # Evaluate all of the specified params. - if @override - params = @override.collect do |param| - param.safeevaluate(scope) - end + # overrides if any + # Evaluate all of the specified params. + if @override + params = @override.collect do |param| + param.safeevaluate(scope) + end - newcoll.add_override( + newcoll.add_override( - :parameters => params, - :file => @file, - :line => @line, - :source => scope.source, + :parameters => params, + :file => @file, + :line => @line, + :source => scope.source, - :scope => scope - ) - end - - newcoll + :scope => scope + ) end - # Handle our parameter ourselves - def override=(override) - if override.is_a?(AST::ASTArray) - @override = override - else + newcoll + end + + # Handle our parameter ourselves + def override=(override) + if override.is_a?(AST::ASTArray) + @override = override + else - @override = AST::ASTArray.new( + @override = AST::ASTArray.new( - :line => override.line, - :file => override.file, + :line => override.line, + :file => override.file, - :children => [override] - ) - end + :children => [override] + ) end + end end end diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb index f71b53d46..f912b4b33 100644 --- a/lib/puppet/parser/ast/collexpr.rb +++ b/lib/puppet/parser/ast/collexpr.rb @@ -6,81 +6,81 @@ require 'puppet/parser/collector' # them to the current host, yo. class Puppet::Parser::AST class CollExpr < AST::Branch - attr_accessor :test1, :test2, :oper, :form, :type, :parens + attr_accessor :test1, :test2, :oper, :form, :type, :parens - # We return an object that does a late-binding evaluation. - def evaluate(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 - str2, code2 = @test2.safeevaluate 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 "==" - if str1 == "tag" - resource.tagged?(str2) - else - if resource[str1].is_a?(Array) - resource[str1].include?(str2) - else - resource[str1] == str2 - end - end - 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 + # We return an object that does a late-binding evaluation. + def evaluate(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 - case @oper - when "and", "or" - if form == :exported - raise Puppet::ParseError, "Puppet does not currently support collecting exported resources with more than one condition" - end - oper = @oper.upcase - when "=="; oper = "=" - else - oper = @oper - end + # The code is only used for virtual lookups + str1, code1 = @test1.safeevaluate scope + str2, code2 = @test2.safeevaluate scope - if oper == "=" or oper == "!=" - # Add the rails association info where necessary - case str1 - when "title" - str = "title #{oper} '#{str2}'" - when "tag" - str = "puppet_tags.name #{oper} '#{str2}'" - else - str = "param_values.value #{oper} '#{str2}' and param_names.name = '#{str1}'" - end + # 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 "==" + if str1 == "tag" + resource.tagged?(str2) else - str = "(#{str1}) #{oper} (#{str2})" + if resource[str1].is_a?(Array) + resource[str1].include?(str2) + else + resource[str1] == str2 + end end + when "!="; resource[str1] != str2 + end + end - return str, code + # Now build up the rails conditions code + if self.parens and self.form == :exported + Puppet.warning "Parentheses are ignored in Rails searches" end - def initialize(hash = {}) - super + case @oper + when "and", "or" + if form == :exported + raise Puppet::ParseError, "Puppet does not currently support collecting exported resources with more than one condition" + end + oper = @oper.upcase + when "=="; oper = "=" + else + oper = @oper + end - raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper) + if oper == "=" or oper == "!=" + # Add the rails association info where necessary + case str1 + when "title" + str = "title #{oper} '#{str2}'" + when "tag" + str = "puppet_tags.name #{oper} '#{str2}'" + else + str = "param_values.value #{oper} '#{str2}' and param_names.name = '#{str1}'" + end + else + str = "(#{str1}) #{oper} (#{str2})" end + + return str, code + end + + def initialize(hash = {}) + super + + raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper) + end end end diff --git a/lib/puppet/parser/ast/comparison_operator.rb b/lib/puppet/parser/ast/comparison_operator.rb index e8b21d45f..c8694bbff 100644 --- a/lib/puppet/parser/ast/comparison_operator.rb +++ b/lib/puppet/parser/ast/comparison_operator.rb @@ -2,38 +2,38 @@ require 'puppet' require 'puppet/parser/ast/branch' class Puppet::Parser::AST - class ComparisonOperator < AST::Branch - - attr_accessor :operator, :lval, :rval - - # Iterate across all of our children. - def each - [@lval,@rval,@operator].each { |child| yield child } - end - - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - # evaluate the operands, should return a boolean value - lval = @lval.safeevaluate(scope) - rval = @rval.safeevaluate(scope) - - # convert to number if operands are number - lval = Puppet::Parser::Scope.number?(lval) || lval - rval = Puppet::Parser::Scope.number?(rval) || rval - - # return result - unless @operator == '!=' - lval.send(@operator,rval) - else - lval != rval - end - end - - def initialize(hash) - super - - raise ArgumentError, "Invalid comparison operator #{@operator}" unless %w{== != < > <= >=}.include?(@operator) - end + class ComparisonOperator < AST::Branch + + attr_accessor :operator, :lval, :rval + + # Iterate across all of our children. + def each + [@lval,@rval,@operator].each { |child| yield child } + end + + # Returns a boolean which is the result of the boolean operation + # of lval and rval operands + def evaluate(scope) + # evaluate the operands, should return a boolean value + lval = @lval.safeevaluate(scope) + rval = @rval.safeevaluate(scope) + + # convert to number if operands are number + lval = Puppet::Parser::Scope.number?(lval) || lval + rval = Puppet::Parser::Scope.number?(rval) || rval + + # return result + unless @operator == '!=' + lval.send(@operator,rval) + else + lval != rval + end + end + + def initialize(hash) + super + + raise ArgumentError, "Invalid comparison operator #{@operator}" unless %w{== != < > <= >=}.include?(@operator) end + end end diff --git a/lib/puppet/parser/ast/else.rb b/lib/puppet/parser/ast/else.rb index 2da9191c8..172149116 100644 --- a/lib/puppet/parser/ast/else.rb +++ b/lib/puppet/parser/ast/else.rb @@ -1,22 +1,22 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # A separate ElseIf statement; can function as an 'else' if there's no - # test. - class Else < AST::Branch + # A separate ElseIf statement; can function as an 'else' if there's no + # test. + class Else < AST::Branch - associates_doc + associates_doc - attr_accessor :statements + attr_accessor :statements - def each - yield @statements - end + def each + yield @statements + end - # Evaluate the actual statements; this only gets called if - # our test was true matched. - def evaluate(scope) - @statements.safeevaluate(scope) - end + # Evaluate the actual statements; this only gets called if + # our test was true matched. + def evaluate(scope) + @statements.safeevaluate(scope) end + end end diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb index 6f6c869f5..602016c75 100644 --- a/lib/puppet/parser/ast/function.rb +++ b/lib/puppet/parser/ast/function.rb @@ -1,51 +1,51 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # An AST object to call a function. - class Function < AST::Branch + # An AST object to call a function. + class Function < AST::Branch - associates_doc + associates_doc - attr_accessor :name, :arguments + attr_accessor :name, :arguments - @settor = true + @settor = true - def evaluate(scope) + def evaluate(scope) - # Make sure it's a defined function - raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name) + # Make sure it's a defined function + raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name) - # Now check that it's been used correctly - case @ftype - when :rvalue - raise Puppet::ParseError, "Function '#{@name}' does not return a value" unless Puppet::Parser::Functions.rvalue?(@name) - when :statement - if Puppet::Parser::Functions.rvalue?(@name) - raise Puppet::ParseError, - "Function '#{@name}' must be the value of a statement" - end - else - raise Puppet::DevError, "Invalid function type #{@ftype.inspect}" - end + # Now check that it's been used correctly + case @ftype + when :rvalue + raise Puppet::ParseError, "Function '#{@name}' does not return a value" unless Puppet::Parser::Functions.rvalue?(@name) + when :statement + if Puppet::Parser::Functions.rvalue?(@name) + raise Puppet::ParseError, + "Function '#{@name}' must be the value of a statement" + end + else + raise Puppet::DevError, "Invalid function type #{@ftype.inspect}" + end - # We don't need to evaluate the name, because it's plaintext - args = @arguments.safeevaluate(scope) + # We don't need to evaluate the name, because it's plaintext + args = @arguments.safeevaluate(scope) - scope.send("function_#{@name}", args) - end + scope.send("function_#{@name}", args) + end - def initialize(hash) - @ftype = hash[:ftype] || :rvalue - hash.delete(:ftype) if hash.include? :ftype + def initialize(hash) + @ftype = hash[:ftype] || :rvalue + hash.delete(:ftype) if hash.include? :ftype - super(hash) + super(hash) - # Lastly, check the parity - end + # Lastly, check the parity + end - def to_s - args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments - "#{name}(#{args})" - end + def to_s + args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments + "#{name}(#{args})" end + end end diff --git a/lib/puppet/parser/ast/ifstatement.rb b/lib/puppet/parser/ast/ifstatement.rb index cbb61bf9c..7fd8a576a 100644 --- a/lib/puppet/parser/ast/ifstatement.rb +++ b/lib/puppet/parser/ast/ifstatement.rb @@ -1,34 +1,34 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # A basic 'if/elsif/else' statement. - class IfStatement < AST::Branch + # A basic 'if/elsif/else' statement. + class IfStatement < AST::Branch - associates_doc + associates_doc - attr_accessor :test, :else, :statements + attr_accessor :test, :else, :statements - def each - [@test,@else,@statements].each { |child| yield child } - end + def each + [@test,@else,@statements].each { |child| yield child } + end - # Short-curcuit evaluation. If we're true, evaluate our statements, - # else if there's an 'else' setting, evaluate it. - # the first option that matches. - def evaluate(scope) - level = scope.ephemeral_level - value = @test.safeevaluate(scope) + # Short-curcuit evaluation. If we're true, evaluate our statements, + # else if there's an 'else' setting, evaluate it. + # the first option that matches. + def evaluate(scope) + level = scope.ephemeral_level + value = @test.safeevaluate(scope) - # let's emulate a new scope for each branches - begin - if Puppet::Parser::Scope.true?(value) - return @statements.safeevaluate(scope) - else - return defined?(@else) ? @else.safeevaluate(scope) : nil - end - ensure - scope.unset_ephemeral_var(level) - end + # let's emulate a new scope for each branches + begin + if Puppet::Parser::Scope.true?(value) + return @statements.safeevaluate(scope) + else + return defined?(@else) ? @else.safeevaluate(scope) : nil end + ensure + scope.unset_ephemeral_var(level) + end end + end end diff --git a/lib/puppet/parser/ast/in_operator.rb b/lib/puppet/parser/ast/in_operator.rb index 1b17b1006..2a163e726 100644 --- a/lib/puppet/parser/ast/in_operator.rb +++ b/lib/puppet/parser/ast/in_operator.rb @@ -2,23 +2,23 @@ require 'puppet' require 'puppet/parser/ast/branch' class Puppet::Parser::AST - class InOperator < AST::Branch + class InOperator < AST::Branch - attr_accessor :lval, :rval + attr_accessor :lval, :rval - # Returns a boolean which is the result of the 'in' operation - # of lval and rval operands - def evaluate(scope) + # Returns a boolean which is the result of the 'in' operation + # of lval and rval operands + def evaluate(scope) - # evaluate the operands, should return a boolean value - lval = @lval.safeevaluate(scope) - raise ArgumentError, "'#{lval}' from left operand of 'in' expression is not a string" unless lval.is_a?(::String) + # evaluate the operands, should return a boolean value + lval = @lval.safeevaluate(scope) + raise ArgumentError, "'#{lval}' from left operand of 'in' expression is not a string" unless lval.is_a?(::String) - rval = @rval.safeevaluate(scope) - unless rval.respond_to?(:include?) - raise ArgumentError, "'#{rval}' from right operand of 'in' expression is not of a supported type (string, array or hash)" - end - rval.include?(lval) - end + rval = @rval.safeevaluate(scope) + unless rval.respond_to?(:include?) + raise ArgumentError, "'#{rval}' from right operand of 'in' expression is not of a supported type (string, array or hash)" + end + rval.include?(lval) end + end end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index a62edc61e..3b9163d9c 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -1,224 +1,224 @@ class Puppet::Parser::AST - # The base class for all of the leaves of the parse trees. These - # basically just have types and values. Both of these parameters - # are simple values, not AST objects. - class Leaf < AST - attr_accessor :value, :type - - # Return our value. - def evaluate(scope) - @value - end - - # evaluate ourselves, and match - def evaluate_match(value, scope) - obj = self.safeevaluate(scope) + # The base class for all of the leaves of the parse trees. These + # basically just have types and values. Both of these parameters + # are simple values, not AST objects. + class Leaf < AST + attr_accessor :value, :type + + # Return our value. + def evaluate(scope) + @value + end - obj = obj.downcase if obj.respond_to?(:downcase) - value = value.downcase if value.respond_to?(:downcase) + # evaluate ourselves, and match + def evaluate_match(value, scope) + obj = self.safeevaluate(scope) - # "" == undef for case/selector/if - obj == value or (obj == "" and value == :undef) - end + obj = obj.downcase if obj.respond_to?(:downcase) + value = value.downcase if value.respond_to?(:downcase) - def match(value) - @value == value - end + # "" == undef for case/selector/if + obj == value or (obj == "" and value == :undef) + end - def to_s - @value.to_s unless @value.nil? - end + def match(value) + @value == value end - # The boolean class. True or false. Converts the string it receives - # to a Ruby boolean. - class Boolean < AST::Leaf + def to_s + @value.to_s unless @value.nil? + end + end - # Use the parent method, but then convert to a real boolean. - def initialize(hash) - super + # The boolean class. True or false. Converts the string it receives + # to a Ruby boolean. + class Boolean < AST::Leaf - unless @value == true or @value == false - raise Puppet::DevError, - "'#{@value}' is not a boolean" - end - @value - end + # Use the parent method, but then convert to a real boolean. + def initialize(hash) + super - def to_s - @value ? "true" : "false" - end + unless @value == true or @value == false + raise Puppet::DevError, + "'#{@value}' is not a boolean" + end + @value end - # The base string class. - class String < AST::Leaf - def evaluate(scope) - @value - end + def to_s + @value ? "true" : "false" + end + end - def to_s - "\"#{@value}\"" - end + # The base string class. + class String < AST::Leaf + def evaluate(scope) + @value end - # An uninterpreted string. - class FlatString < AST::Leaf - def evaluate(scope) - @value - end + def to_s + "\"#{@value}\"" + end + end - def to_s - "\"#{@value}\"" - end + # An uninterpreted string. + class FlatString < AST::Leaf + def evaluate(scope) + @value end - class Concat < AST::Leaf - def evaluate(scope) - @value.collect { |x| x.evaluate(scope) }.join - end + def to_s + "\"#{@value}\"" + end + end - def to_s - "concat(#{@value.join(',')})" - end + class Concat < AST::Leaf + def evaluate(scope) + @value.collect { |x| x.evaluate(scope) }.join end - # The 'default' option on case statements and selectors. - class Default < AST::Leaf; end + def to_s + "concat(#{@value.join(',')})" + end + end - # Capitalized words; used mostly for type-defaults, but also - # get returned by the lexer any other time an unquoted capitalized - # word is found. - class Type < AST::Leaf; end + # The 'default' option on case statements and selectors. + class Default < AST::Leaf; end - # Lower-case words. - class Name < AST::Leaf; end + # Capitalized words; used mostly for type-defaults, but also + # get returned by the lexer any other time an unquoted capitalized + # word is found. + class Type < AST::Leaf; end - # double-colon separated class names - class ClassName < AST::Leaf; end + # Lower-case words. + class Name < AST::Leaf; end - # undef values; equiv to nil - class Undef < AST::Leaf; end + # double-colon separated class names + class ClassName < AST::Leaf; end - # Host names, either fully qualified or just the short name, or even a regex - class HostName < AST::Leaf - def initialize(hash) - super + # undef values; equiv to nil + class Undef < AST::Leaf; end - # Note that this is an AST::Regex, not a Regexp - @value = @value.to_s.downcase unless @value.is_a?(Regex) - if @value =~ /[^-\w.]/ - raise Puppet::DevError, - "'#{@value}' is not a valid hostname" - end - end + # Host names, either fully qualified or just the short name, or even a regex + class HostName < AST::Leaf + def initialize(hash) + super - # implementing eql? and hash so that when an HostName is stored - # in a hash it has the same hashing properties as the underlying value - def eql?(value) - value = value.value if value.is_a?(HostName) - @value.eql?(value) - end + # Note that this is an AST::Regex, not a Regexp + @value = @value.to_s.downcase unless @value.is_a?(Regex) + if @value =~ /[^-\w.]/ + raise Puppet::DevError, + "'#{@value}' is not a valid hostname" + end + end - def hash - @value.hash - end + # implementing eql? and hash so that when an HostName is stored + # in a hash it has the same hashing properties as the underlying value + def eql?(value) + value = value.value if value.is_a?(HostName) + @value.eql?(value) + end - def to_s - @value.to_s - end + def hash + @value.hash end - # A simple variable. This object is only used during interpolation; - # the VarDef class is used for assignment. - class Variable < Name - # Looks up the value of the object in the scope tree (does - # not include syntactical constructs, like '$' and '{}'). - def evaluate(scope) - parsewrap do - if (var = scope.lookupvar(@value, false)) == :undefined - var = :undef - end - var - end - end + def to_s + @value.to_s + end + end + + # A simple variable. This object is only used during interpolation; + # the VarDef class is used for assignment. + class Variable < Name + # Looks up the value of the object in the scope tree (does + # not include syntactical constructs, like '$' and '{}'). + def evaluate(scope) + parsewrap do + if (var = scope.lookupvar(@value, false)) == :undefined + var = :undef + end + var + end + end - def to_s - "\$#{value}" - end + def to_s + "\$#{value}" end + end - class HashOrArrayAccess < AST::Leaf - attr_accessor :variable, :key + class HashOrArrayAccess < AST::Leaf + attr_accessor :variable, :key - def evaluate_container(scope) - container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable - (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container) - end + def evaluate_container(scope) + container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable + (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container) + end - def evaluate_key(scope) - key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key - end + def evaluate_key(scope) + key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key + end - def evaluate(scope) - object = evaluate_container(scope) + def evaluate(scope) + object = evaluate_container(scope) - raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array) + raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array) - object[evaluate_key(scope)] - end + object[evaluate_key(scope)] + end - # Assign value to this hashkey or array index - def assign(scope, value) - object = evaluate_container(scope) - accesskey = evaluate_key(scope) + # Assign value to this hashkey or array index + def assign(scope, value) + object = evaluate_container(scope) + accesskey = evaluate_key(scope) - if object.is_a?(Hash) and object.include?(accesskey) - raise Puppet::ParseError, "Assigning to the hash '#{variable}' with an existing key '#{accesskey}' is forbidden" - end + if object.is_a?(Hash) and object.include?(accesskey) + raise Puppet::ParseError, "Assigning to the hash '#{variable}' with an existing key '#{accesskey}' is forbidden" + end - # assign to hash or array - object[accesskey] = value - end + # assign to hash or array + object[accesskey] = value + end - def to_s - "\$#{variable.to_s}[#{key.to_s}]" - end + def to_s + "\$#{variable.to_s}[#{key.to_s}]" end + end - class Regex < AST::Leaf - def initialize(hash) - super - @value = Regexp.new(@value) unless @value.is_a?(Regexp) - end + class Regex < AST::Leaf + def initialize(hash) + super + @value = Regexp.new(@value) unless @value.is_a?(Regexp) + end - # we're returning self here to wrap the regexp and to be used in places - # where a string would have been used, without modifying any client code. - # For instance, in many places we have the following code snippet: - # val = @val.safeevaluate(@scope) - # if val.match(otherval) - # ... - # end - # this way, we don't have to modify this test specifically for handling - # regexes. - def evaluate(scope) - self - end + # we're returning self here to wrap the regexp and to be used in places + # where a string would have been used, without modifying any client code. + # For instance, in many places we have the following code snippet: + # val = @val.safeevaluate(@scope) + # if val.match(otherval) + # ... + # end + # this way, we don't have to modify this test specifically for handling + # regexes. + def evaluate(scope) + self + end - def evaluate_match(value, scope, options = {}) - value = value.is_a?(String) ? value : value.to_s + def evaluate_match(value, scope, options = {}) + value = value.is_a?(String) ? value : value.to_s - if matched = @value.match(value) - scope.ephemeral_from(matched, options[:file], options[:line]) - end - matched - end + if matched = @value.match(value) + scope.ephemeral_from(matched, options[:file], options[:line]) + end + matched + end - def match(value) - @value.match(value) - end + def match(value) + @value.match(value) + end - def to_s - "/#{@value.source}/" - end + def to_s + "/#{@value.source}/" end + end end diff --git a/lib/puppet/parser/ast/match_operator.rb b/lib/puppet/parser/ast/match_operator.rb index 2ab2befd4..6207a8c2c 100644 --- a/lib/puppet/parser/ast/match_operator.rb +++ b/lib/puppet/parser/ast/match_operator.rb @@ -2,27 +2,27 @@ require 'puppet' require 'puppet/parser/ast/branch' class Puppet::Parser::AST - class MatchOperator < AST::Branch + class MatchOperator < AST::Branch - attr_accessor :lval, :rval, :operator + attr_accessor :lval, :rval, :operator - # Iterate across all of our children. - def each - [@lval,@rval].each { |child| yield child } - end + # Iterate across all of our children. + def each + [@lval,@rval].each { |child| yield child } + end - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - lval = @lval.safeevaluate(scope) + # Returns a boolean which is the result of the boolean operation + # of lval and rval operands + def evaluate(scope) + lval = @lval.safeevaluate(scope) - return(rval.evaluate_match(lval, scope) ? @operator == "=~" : @operator == "!~") - end + return(rval.evaluate_match(lval, scope) ? @operator == "=~" : @operator == "!~") + end - def initialize(hash) - super + def initialize(hash) + super - raise ArgumentError, "Invalid regexp operator #{@operator}" unless %w{!~ =~}.include?(@operator) - end + raise ArgumentError, "Invalid regexp operator #{@operator}" unless %w{!~ =~}.include?(@operator) end + end end diff --git a/lib/puppet/parser/ast/minus.rb b/lib/puppet/parser/ast/minus.rb index 40f64336c..d7a362aa1 100644 --- a/lib/puppet/parser/ast/minus.rb +++ b/lib/puppet/parser/ast/minus.rb @@ -4,20 +4,20 @@ require 'puppet/parser/ast/branch' # An object that returns a boolean which is the boolean not # of the given value. class Puppet::Parser::AST - class Minus < AST::Branch - attr_accessor :value + class Minus < AST::Branch + attr_accessor :value - def each - yield @value - end + def each + yield @value + end - def evaluate(scope) - val = @value.safeevaluate(scope) - val = Puppet::Parser::Scope.number?(val) - if val == nil - raise ArgumentError, "minus operand #{val} is not a number" - end - -val - end + def evaluate(scope) + val = @value.safeevaluate(scope) + val = Puppet::Parser::Scope.number?(val) + if val == nil + raise ArgumentError, "minus operand #{val} is not a number" + end + -val end + end end diff --git a/lib/puppet/parser/ast/nop.rb b/lib/puppet/parser/ast/nop.rb index ea5232043..bf35c6a5c 100644 --- a/lib/puppet/parser/ast/nop.rb +++ b/lib/puppet/parser/ast/nop.rb @@ -1,11 +1,11 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # This class is a no-op, it doesn't produce anything - # when evaluated, hence it's name :-) - class Nop < AST::Leaf - def evaluate(scope) - # nothing to do - end + # This class is a no-op, it doesn't produce anything + # when evaluated, hence it's name :-) + class Nop < AST::Leaf + def evaluate(scope) + # nothing to do end + end end diff --git a/lib/puppet/parser/ast/not.rb b/lib/puppet/parser/ast/not.rb index 24d5e838b..30fa6d503 100644 --- a/lib/puppet/parser/ast/not.rb +++ b/lib/puppet/parser/ast/not.rb @@ -4,16 +4,16 @@ require 'puppet/parser/ast/branch' # An object that returns a boolean which is the boolean not # of the given value. class Puppet::Parser::AST - class Not < AST::Branch - attr_accessor :value + class Not < AST::Branch + attr_accessor :value - def each - yield @value - end + def each + yield @value + end - def evaluate(scope) - val = @value.safeevaluate(scope) - ! Puppet::Parser::Scope.true?(val) - end + def evaluate(scope) + val = @value.safeevaluate(scope) + ! Puppet::Parser::Scope.true?(val) end + end end diff --git a/lib/puppet/parser/ast/relationship.rb b/lib/puppet/parser/ast/relationship.rb index 9f9f6fc1d..a7134a04f 100644 --- a/lib/puppet/parser/ast/relationship.rb +++ b/lib/puppet/parser/ast/relationship.rb @@ -3,58 +3,58 @@ require 'puppet/parser/ast/branch' require 'puppet/parser/relationship' class Puppet::Parser::AST::Relationship < Puppet::Parser::AST::Branch - RELATIONSHIP_TYPES = %w{-> <- ~> <~} + RELATIONSHIP_TYPES = %w{-> <- ~> <~} - attr_accessor :left, :right, :arrow, :type + attr_accessor :left, :right, :arrow, :type - def actual_left - chained? ? left.right : left - end + def actual_left + chained? ? left.right : left + end - # Evaluate our object, but just return a simple array of the type - # and name. - def evaluate(scope) - if chained? - real_left = left.safeevaluate(scope) - left_dep = left_dep.shift if left_dep.is_a?(Array) - else - real_left = left.safeevaluate(scope) - end - real_right = right.safeevaluate(scope) - - source, target = sides2edge(real_left, real_right) - result = Puppet::Parser::Relationship.new(source, target, type) - scope.compiler.add_relationship(result) - real_right + # Evaluate our object, but just return a simple array of the type + # and name. + def evaluate(scope) + if chained? + real_left = left.safeevaluate(scope) + left_dep = left_dep.shift if left_dep.is_a?(Array) + else + real_left = left.safeevaluate(scope) end + real_right = right.safeevaluate(scope) - def initialize(left, right, arrow, args = {}) - super(args) - unless RELATIONSHIP_TYPES.include?(arrow) - raise ArgumentError, "Invalid relationship type #{arrow.inspect}; valid types are #{RELATIONSHIP_TYPES.collect { |r| r.to_s }.join(", ")}" - end - @left, @right, @arrow = left, right, arrow - end + source, target = sides2edge(real_left, real_right) + result = Puppet::Parser::Relationship.new(source, target, type) + scope.compiler.add_relationship(result) + real_right + end - def type - subscription? ? :subscription : :relationship + def initialize(left, right, arrow, args = {}) + super(args) + unless RELATIONSHIP_TYPES.include?(arrow) + raise ArgumentError, "Invalid relationship type #{arrow.inspect}; valid types are #{RELATIONSHIP_TYPES.collect { |r| r.to_s }.join(", ")}" end + @left, @right, @arrow = left, right, arrow + end - def sides2edge(left, right) - out_edge? ? [left, right] : [right, left] - end + def type + subscription? ? :subscription : :relationship + end - private + def sides2edge(left, right) + out_edge? ? [left, right] : [right, left] + end - def chained? - left.is_a?(self.class) - end + private - def out_edge? - ["->", "~>"].include?(arrow) - end + def chained? + left.is_a?(self.class) + end - def subscription? - ["~>", "<~"].include?(arrow) - end + def out_edge? + ["->", "~>"].include?(arrow) + end + + def subscription? + ["~>", "<~"].include?(arrow) + end end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 01b9370ff..1b063c984 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -5,73 +5,73 @@ require 'puppet/parser/ast/resource_reference' class Puppet::Parser::AST class Resource < AST::ResourceReference - associates_doc + associates_doc - attr_accessor :title, :type, :exported, :virtual - attr_reader :parameters + attr_accessor :title, :type, :exported, :virtual + attr_reader :parameters - # Does not actually return an object; instead sets an object - # in the current scope. - def evaluate(scope) - # Evaluate all of the specified params. - paramobjects = parameters.collect { |param| - param.safeevaluate(scope) - } + # Does not actually return an object; instead sets an object + # in the current scope. + def evaluate(scope) + # Evaluate all of the specified params. + paramobjects = parameters.collect { |param| + param.safeevaluate(scope) + } - resource_titles = @title.safeevaluate(scope) + resource_titles = @title.safeevaluate(scope) - # it's easier to always use an array, even for only one name - resource_titles = [resource_titles] unless resource_titles.is_a?(Array) + # it's easier to always use an array, even for only one name + resource_titles = [resource_titles] unless resource_titles.is_a?(Array) - # We want virtual to be true if exported is true. We can't - # just set :virtual => self.virtual in the initialization, - # because sometimes the :virtual attribute is set *after* - # :exported, in which case it clobbers :exported if :exported - # is true. Argh, this was a very tough one to track down. - virt = self.virtual || self.exported + # We want virtual to be true if exported is true. We can't + # just set :virtual => self.virtual in the initialization, + # because sometimes the :virtual attribute is set *after* + # :exported, in which case it clobbers :exported if :exported + # is true. Argh, this was a very tough one to track down. + virt = self.virtual || self.exported - # This is where our implicit iteration takes place; if someone - # passed an array as the name, then we act just like the called us - # many times. - resource_titles.flatten.collect { |resource_title| - exceptwrap :type => Puppet::ParseError do + # This is where our implicit iteration takes place; if someone + # passed an array as the name, then we act just like the called us + # many times. + resource_titles.flatten.collect { |resource_title| + exceptwrap :type => Puppet::ParseError do - resource = Puppet::Parser::Resource.new( - type, resource_title, - :parameters => paramobjects, - :file => self.file, - :line => self.line, - :exported => self.exported, - :virtual => virt, - :source => scope.source, - :scope => scope, + resource = Puppet::Parser::Resource.new( + type, resource_title, + :parameters => paramobjects, + :file => self.file, + :line => self.line, + :exported => self.exported, + :virtual => virt, + :source => scope.source, + :scope => scope, - :strict => true - ) + :strict => true + ) - # And then store the resource in the compiler. - # At some point, we need to switch all of this to return - # resources instead of storing them like this. - scope.compiler.add_resource(scope, resource) - resource - end - }.reject { |resource| resource.nil? } - end + # And then store the resource in the compiler. + # At some point, we need to switch all of this to return + # resources instead of storing them like this. + scope.compiler.add_resource(scope, resource) + resource + end + }.reject { |resource| resource.nil? } + end - # Set the parameters for our object. - def parameters=(params) - if params.is_a?(AST::ASTArray) - @parameters = params - else + # Set the parameters for our object. + def parameters=(params) + if params.is_a?(AST::ASTArray) + @parameters = params + else - @parameters = AST::ASTArray.new( + @parameters = AST::ASTArray.new( - :line => params.line, - :file => params.file, + :line => params.line, + :file => params.file, - :children => [params] - ) - end + :children => [params] + ) end + end end end diff --git a/lib/puppet/parser/ast/resource_defaults.rb b/lib/puppet/parser/ast/resource_defaults.rb index aec86d02d..812b979e9 100644 --- a/lib/puppet/parser/ast/resource_defaults.rb +++ b/lib/puppet/parser/ast/resource_defaults.rb @@ -1,24 +1,24 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # A statement syntactically similar to an ResourceDef, but uses a - # capitalized object type and cannot have a name. - class ResourceDefaults < AST::Branch - attr_accessor :type, :parameters + # A statement syntactically similar to an ResourceDef, but uses a + # capitalized object type and cannot have a name. + class ResourceDefaults < AST::Branch + attr_accessor :type, :parameters - associates_doc + associates_doc - # As opposed to ResourceDef, this stores each default for the given - # object type. - def evaluate(scope) - # Use a resource reference to canonize the type - ref = Puppet::Resource.new(@type, "whatever") - type = ref.type - params = @parameters.safeevaluate(scope) + # As opposed to ResourceDef, this stores each default for the given + # object type. + def evaluate(scope) + # Use a resource reference to canonize the type + ref = Puppet::Resource.new(@type, "whatever") + type = ref.type + params = @parameters.safeevaluate(scope) - parsewrap do - scope.setdefaults(type, params) - end - end + parsewrap do + scope.setdefaults(type, params) + end end + end end diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index 7f7047dd9..e0be889ff 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -1,68 +1,68 @@ require 'puppet/parser/ast/resource' class Puppet::Parser::AST - # Set a parameter on a resource specification created somewhere else in the - # configuration. The object is responsible for verifying that this is allowed. - class ResourceOverride < Resource + # Set a parameter on a resource specification created somewhere else in the + # configuration. The object is responsible for verifying that this is allowed. + class ResourceOverride < Resource - associates_doc + associates_doc - attr_accessor :object - attr_reader :parameters + attr_accessor :object + attr_reader :parameters - # Iterate across all of our children. - def each - [@object,@parameters].flatten.each { |param| - #Puppet.debug("yielding param #{param}") - yield param - } - end + # Iterate across all of our children. + def each + [@object,@parameters].flatten.each { |param| + #Puppet.debug("yielding param #{param}") + yield param + } + end - # Does not actually return an object; instead sets an object - # in the current scope. - def evaluate(scope) - # Get our object reference. - resource = @object.safeevaluate(scope) + # Does not actually return an object; instead sets an object + # in the current scope. + def evaluate(scope) + # Get our object reference. + resource = @object.safeevaluate(scope) - hash = {} + hash = {} - # Evaluate all of the specified params. - params = @parameters.collect { |param| - param.safeevaluate(scope) - } + # Evaluate all of the specified params. + params = @parameters.collect { |param| + param.safeevaluate(scope) + } - # Now we just create a normal resource, but we call a very different - # method on the scope. - resource = [resource] unless resource.is_a?(Array) + # Now we just create a normal resource, but we call a very different + # method on the scope. + resource = [resource] unless resource.is_a?(Array) - resource = resource.collect do |r| + resource = resource.collect do |r| - res = Puppet::Parser::Resource.new( - r.type, r.title, - :parameters => params, - :file => file, - :line => line, - :source => scope.source, + res = Puppet::Parser::Resource.new( + r.type, r.title, + :parameters => params, + :file => file, + :line => line, + :source => scope.source, - :scope => scope - ) + :scope => scope + ) - # Now we tell the scope that it's an override, and it behaves as - # necessary. - scope.compiler.add_override(res) + # Now we tell the scope that it's an override, and it behaves as + # necessary. + scope.compiler.add_override(res) - res - end - # decapsulate array in case of only one item - return(resource.length == 1 ? resource.pop : resource) - end + res + end + # decapsulate array in case of only one item + return(resource.length == 1 ? resource.pop : resource) + end - # Create our ResourceDef. Handles type checking for us. - def initialize(hash) - @checked = false - super + # Create our ResourceDef. Handles type checking for us. + def initialize(hash) + @checked = false + super - #self.typecheck(@type.value) - end + #self.typecheck(@type.value) end + end end diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb index 37e82d568..5d8334335 100644 --- a/lib/puppet/parser/ast/resource_reference.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -2,20 +2,20 @@ require 'puppet/parser/ast' require 'puppet/parser/ast/branch' class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch - attr_accessor :title, :type + attr_accessor :title, :type - # Evaluate our object, but just return a simple array of the type - # and name. - def evaluate(scope) - titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) } - return(titles.length == 1 ? titles.pop : titles) - end + # Evaluate our object, but just return a simple array of the type + # and name. + def evaluate(scope) + titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) } + return(titles.length == 1 ? titles.pop : titles) + end - def to_s - if title.is_a?(Puppet::Parser::AST::ASTArray) - "#{type.to_s.capitalize}#{title}" - else - "#{type.to_s.capitalize}[#{title}]" - end + def to_s + if title.is_a?(Puppet::Parser::AST::ASTArray) + "#{type.to_s.capitalize}#{title}" + else + "#{type.to_s.capitalize}[#{title}]" end + end end diff --git a/lib/puppet/parser/ast/resourceparam.rb b/lib/puppet/parser/ast/resourceparam.rb index bf0a2258b..4073a197b 100644 --- a/lib/puppet/parser/ast/resourceparam.rb +++ b/lib/puppet/parser/ast/resourceparam.rb @@ -1,29 +1,29 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # The AST object for the parameters inside ResourceDefs and Selectors. - class ResourceParam < AST::Branch - attr_accessor :value, :param, :add + # The AST object for the parameters inside ResourceDefs and Selectors. + class ResourceParam < AST::Branch + attr_accessor :value, :param, :add - def each - [@param,@value].each { |child| yield child } - end + def each + [@param,@value].each { |child| yield child } + end - # Return the parameter and the value. - def evaluate(scope) + # Return the parameter and the value. + def evaluate(scope) - return Puppet::Parser::Resource::Param.new( + return Puppet::Parser::Resource::Param.new( - :name => @param, - :value => @value.safeevaluate(scope), + :name => @param, + :value => @value.safeevaluate(scope), - :source => scope.source, :line => self.line, :file => self.file, - :add => self.add - ) - end + :source => scope.source, :line => self.line, :file => self.file, + :add => self.add + ) + end - def to_s - "#{@param} => #{@value.to_s}" - end + def to_s + "#{@param} => #{@value.to_s}" end + end end diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb index cf6b8ac19..d6a4ea436 100644 --- a/lib/puppet/parser/ast/selector.rb +++ b/lib/puppet/parser/ast/selector.rb @@ -1,44 +1,44 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # The inline conditional operator. Unlike CaseStatement, which executes - # code, we just return a value. - class Selector < AST::Branch - attr_accessor :param, :values + # The inline conditional operator. Unlike CaseStatement, which executes + # code, we just return a value. + class Selector < AST::Branch + attr_accessor :param, :values - def each - [@param,@values].each { |child| yield child } - end + def each + [@param,@values].each { |child| yield child } + end - # Find the value that corresponds with the test. - def evaluate(scope) - level = scope.ephemeral_level - # Get our parameter. - paramvalue = @param.safeevaluate(scope) + # Find the value that corresponds with the test. + def evaluate(scope) + level = scope.ephemeral_level + # Get our parameter. + paramvalue = @param.safeevaluate(scope) - default = nil + default = nil - @values = [@values] unless @values.instance_of? AST::ASTArray or @values.instance_of? Array + @values = [@values] unless @values.instance_of? AST::ASTArray or @values.instance_of? Array - # Then look for a match in the options. - @values.each do |obj| - # short circuit asap if we have a match - return obj.value.safeevaluate(scope) if obj.param.evaluate_match(paramvalue, scope) + # Then look for a match in the options. + @values.each do |obj| + # short circuit asap if we have a match + return obj.value.safeevaluate(scope) if obj.param.evaluate_match(paramvalue, scope) - # Store the default, in case it's necessary. - default = obj if obj.param.is_a?(Default) - end + # Store the default, in case it's necessary. + default = obj if obj.param.is_a?(Default) + end - # Unless we found something, look for the default. - return default.value.safeevaluate(scope) if default + # Unless we found something, look for the default. + return default.value.safeevaluate(scope) if default - self.fail Puppet::ParseError, "No matching value for selector param '#{paramvalue}'" - ensure - scope.unset_ephemeral_var(level) - end + self.fail Puppet::ParseError, "No matching value for selector param '#{paramvalue}'" + ensure + scope.unset_ephemeral_var(level) + end - def to_s - param.to_s + " ? { " + values.collect { |v| v.to_s }.join(', ') + " }" - end + def to_s + param.to_s + " ? { " + values.collect { |v| v.to_s }.join(', ') + " }" end + end end diff --git a/lib/puppet/parser/ast/tag.rb b/lib/puppet/parser/ast/tag.rb index 2909504a7..6f906a1c6 100644 --- a/lib/puppet/parser/ast/tag.rb +++ b/lib/puppet/parser/ast/tag.rb @@ -1,24 +1,24 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # The code associated with a class. This is different from components - # in that each class is a singleton -- only one will exist for a given - # node. - class Tag < AST::Branch - @name = :class - attr_accessor :type + # The code associated with a class. This is different from components + # in that each class is a singleton -- only one will exist for a given + # node. + class Tag < AST::Branch + @name = :class + attr_accessor :type - def evaluate(scope) - types = @type.safeevaluate(scope) + def evaluate(scope) + types = @type.safeevaluate(scope) - types = [types] unless types.is_a? Array + types = [types] unless types.is_a? Array - types.each do |type| - # Now set our class. We don't have to worry about checking - # whether we've been evaluated because we're not evaluating - # any code. - scope.setclass(self.object_id, type) - end - end + types.each do |type| + # Now set our class. We don't have to worry about checking + # whether we've been evaluated because we're not evaluating + # any code. + scope.setclass(self.object_id, type) + end end + end end diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb index f103d49c3..6de1860c8 100644 --- a/lib/puppet/parser/ast/vardef.rb +++ b/lib/puppet/parser/ast/vardef.rb @@ -1,33 +1,33 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST - # Define a variable. Stores the value in the current scope. - class VarDef < AST::Branch + # Define a variable. Stores the value in the current scope. + class VarDef < AST::Branch - associates_doc + associates_doc - attr_accessor :name, :value, :append + attr_accessor :name, :value, :append - @settor = true + @settor = true - # Look up our name and value, and store them appropriately. The - # lexer strips off the syntax stuff like '$'. - def evaluate(scope) - value = @value.safeevaluate(scope) - if name.is_a?(HashOrArrayAccess) - name.assign(scope, value) - else - name = @name.safeevaluate(scope) + # Look up our name and value, and store them appropriately. The + # lexer strips off the syntax stuff like '$'. + def evaluate(scope) + value = @value.safeevaluate(scope) + if name.is_a?(HashOrArrayAccess) + name.assign(scope, value) + else + name = @name.safeevaluate(scope) - parsewrap do - scope.setvar(name,value, :file => @file, :line => @line, :append => @append) - end - end + parsewrap do + scope.setvar(name,value, :file => @file, :line => @line, :append => @append) end + end + end - def each - [@name,@value].each { |child| yield child } - end + def each + [@name,@value].each { |child| yield child } end + end end diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index c03add304..de60cb170 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -1,223 +1,223 @@ # 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, :vquery, :equery, :form, :resources, :overrides, :collected - - # Call the collection method, mark all of the returned objects as non-virtual, - # optionally applying parameter overrides. The collector can also delete himself - # from the compiler if there is no more resources to collect (valid only for resource fixed-set collector - # which get their resources from +collect_resources+ and not from the catalog) - def evaluate - # Shortcut if we're not using storeconfigs and they're trying to collect - # exported resources. - if form == :exported and Puppet[:storeconfigs] != true - Puppet.warning "Not collecting exported resources without storeconfigs" - return false - end + attr_accessor :type, :scope, :vquery, :equery, :form, :resources, :overrides, :collected + + # Call the collection method, mark all of the returned objects as non-virtual, + # optionally applying parameter overrides. The collector can also delete himself + # from the compiler if there is no more resources to collect (valid only for resource fixed-set collector + # which get their resources from +collect_resources+ and not from the catalog) + def evaluate + # Shortcut if we're not using storeconfigs and they're trying to collect + # exported resources. + if form == :exported and Puppet[:storeconfigs] != true + Puppet.warning "Not collecting exported resources without storeconfigs" + return false + end - if self.resources - unless objects = collect_resources and ! objects.empty? - return false - end - else - method = "collect_#{@form.to_s}" - objects = send(method).each do |obj| - obj.virtual = false - end - return false if objects.empty? - end + if self.resources + unless objects = collect_resources and ! objects.empty? + return false + end + else + method = "collect_#{@form.to_s}" + objects = send(method).each do |obj| + obj.virtual = false + end + return false if objects.empty? + end - # we have an override for the collected resources - if @overrides and !objects.empty? - - # force the resource to be always child of any other resource - overrides[:source].meta_def(:child_of?) do - true - end - - # tell the compiler we have some override for him unless we already - # overrided those resources - objects.each do |res| - unless @collected.include?(res.ref) - - newres = Puppet::Parser::Resource.new( - res.type, res.title, - :parameters => overrides[:parameters], - :file => overrides[:file], - :line => overrides[:line], - :source => overrides[:source], + # we have an override for the collected resources + if @overrides and !objects.empty? + + # force the resource to be always child of any other resource + overrides[:source].meta_def(:child_of?) do + true + end + + # tell the compiler we have some override for him unless we already + # overrided those resources + objects.each do |res| + unless @collected.include?(res.ref) + + newres = Puppet::Parser::Resource.new( + res.type, res.title, + :parameters => overrides[:parameters], + :file => overrides[:file], + :line => overrides[:line], + :source => overrides[:source], - :scope => overrides[:scope] - ) + :scope => overrides[:scope] + ) - scope.compiler.add_override(newres) - end - end + scope.compiler.add_override(newres) end + end + end - # filter out object that already have been collected by ourself - objects.reject! { |o| @collected.include?(o.ref) } + # filter out object that already have been collected by ourself + objects.reject! { |o| @collected.include?(o.ref) } - return false if objects.empty? + return false if objects.empty? - # keep an eye on the resources we have collected - objects.inject(@collected) { |c,o| c[o.ref]=o; c } + # keep an eye on the resources we have collected + objects.inject(@collected) { |c,o| c[o.ref]=o; c } - # return our newly collected resources - objects - end + # return our newly collected resources + objects + end - def initialize(scope, type, equery, vquery, form) - @scope = scope + def initialize(scope, type, equery, vquery, form) + @scope = scope - # initialisation - @collected = {} + # initialisation + @collected = {} - # Canonize the type - @type = Puppet::Resource.new(type, "whatever").type - @equery = equery - @vquery = vquery + # Canonize the type + @type = Puppet::Resource.new(type, "whatever").type + @equery = equery + @vquery = vquery - raise(ArgumentError, "Invalid query form #{form}") unless [:exported, :virtual].include?(form) - @form = form - end + raise(ArgumentError, "Invalid query form #{form}") unless [:exported, :virtual].include?(form) + @form = form + end - # add a resource override to the soon to be exported/realized resources - def add_override(hash) - raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters] + # add a resource override to the soon to be exported/realized resources + def add_override(hash) + raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters] - # schedule an override for an upcoming collection - @overrides = hash - end - - private - - # Create our active record query. - def build_active_record_query - Puppet::Rails.init unless ActiveRecord::Base.connected? - - raise Puppet::DevError, "Cannot collect resources for a nil host" unless @scope.host - host = Puppet::Rails::Host.find_by_name(@scope.host) - - search = "(exported=? AND restype=?)" - values = [true, @type] - - search += " AND (#{@equery})" if @equery - - # note: - # we're not eagerly including any relations here because - # it can creates so much objects we'll throw out later. - # We used to eagerly include param_names/values but the way - # the search filter is built ruined those efforts and we - # were eagerly loading only the searched parameter and not - # the other ones. - query = {} - case search - when /puppet_tags/ - query = {:joins => {:resource_tags => :puppet_tag}} - when /param_name/ - query = {:joins => {:param_values => :param_name}} - end + # schedule an override for an upcoming collection + @overrides = hash + end - # We're going to collect objects from rails, but we don't want any - # objects from this host. - search = ("host_id != ? AND #{search}") and values.unshift(host.id) if host + private - query[:conditions] = [search, *values] + # Create our active record query. + def build_active_record_query + Puppet::Rails.init unless ActiveRecord::Base.connected? - query - end + raise Puppet::DevError, "Cannot collect resources for a nil host" unless @scope.host + host = Puppet::Rails::Host.find_by_name(@scope.host) - # Collect exported objects. - def collect_exported - # 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).reject { |r| ! r.virtual? } - - count = resources.length - - query = build_active_record_query - - # 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. - time = Puppet::Util.thinmark do - Puppet::Rails::Resource.find(:all, query).each do |obj| - if resource = exported_resource(obj) - count += 1 - resources << resource - end - end - end + search = "(exported=? AND restype=?)" + values = [true, @type] - scope.debug("Collected %s %s resource%s in %.2f seconds" % [count, @type, count == 1 ? "" : "s", time]) + search += " AND (#{@equery})" if @equery - resources + # note: + # we're not eagerly including any relations here because + # it can creates so much objects we'll throw out later. + # We used to eagerly include param_names/values but the way + # the search filter is built ruined those efforts and we + # were eagerly loading only the searched parameter and not + # the other ones. + query = {} + case search + when /puppet_tags/ + query = {:joins => {:resource_tags => :puppet_tag}} + when /param_name/ + query = {:joins => {:param_values => :param_name}} end - def collect_resources - @resources = [@resources] unless @resources.is_a?(Array) - method = "collect_#{form.to_s}_resources" - send(method) - end + # We're going to collect objects from rails, but we don't want any + # objects from this host. + search = ("host_id != ? AND #{search}") and values.unshift(host.id) if host - def collect_exported_resources - raise Puppet::ParseError, "realize() is not yet implemented for exported resources" - end + query[:conditions] = [search, *values] - # Collect resources directly; this is the result of using 'realize', - # which specifies resources, rather than using a normal collection. - def collect_virtual_resources - return [] unless defined?(@resources) and ! @resources.empty? - result = @resources.dup.collect do |ref| - if res = @scope.findresource(ref.to_s) - @resources.delete(ref) - res - end - end.reject { |r| r.nil? }.each do |res| - res.virtual = false - end + query + end - # If there are no more resources to find, delete this from the list - # of collections. - @scope.compiler.delete_collection(self) if @resources.empty? + # Collect exported objects. + def collect_exported + # 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).reject { |r| ! r.virtual? } - result - end + count = resources.length - # Collect just virtual objects, from our local compiler. - def collect_virtual(exported = false) - scope.compiler.resources.find_all do |resource| - resource.type == @type and (exported ? resource.exported? : true) and match?(resource) + query = build_active_record_query + + # 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. + time = Puppet::Util.thinmark do + Puppet::Rails::Resource.find(:all, query).each do |obj| + if resource = exported_resource(obj) + count += 1 + resources << resource end + end end - # Seek a specific exported resource. - def exported_resource(obj) - if existing = @scope.findresource(obj.restype, obj.title) - # Next see if we've already collected this resource - return nil if existing.rails_id == obj.id + scope.debug("Collected %s %s resource%s in %.2f seconds" % [count, @type, count == 1 ? "" : "s", time]) + + resources + end + + def collect_resources + @resources = [@resources] unless @resources.is_a?(Array) + method = "collect_#{form.to_s}_resources" + send(method) + end + + def collect_exported_resources + raise Puppet::ParseError, "realize() is not yet implemented for exported resources" + end + + # Collect resources directly; this is the result of using 'realize', + # which specifies resources, rather than using a normal collection. + def collect_virtual_resources + return [] unless defined?(@resources) and ! @resources.empty? + result = @resources.dup.collect do |ref| + if res = @scope.findresource(ref.to_s) + @resources.delete(ref) + res + end + end.reject { |r| r.nil? }.each do |res| + res.virtual = false + end - # This is the one we've already collected - raise Puppet::ParseError, "Exported resource #{obj.ref} cannot override local resource" - end + # If there are no more resources to find, delete this from the list + # of collections. + @scope.compiler.delete_collection(self) if @resources.empty? - resource = obj.to_resource(self.scope) + result + end - resource.exported = false + # Collect just virtual objects, from our local compiler. + def collect_virtual(exported = false) + scope.compiler.resources.find_all do |resource| + resource.type == @type and (exported ? resource.exported? : true) and match?(resource) + end + end - scope.compiler.add_resource(scope, resource) + # Seek a specific exported resource. + def exported_resource(obj) + if existing = @scope.findresource(obj.restype, obj.title) + # Next see if we've already collected this resource + return nil if existing.rails_id == obj.id - resource + # This is the one we've already collected + raise Puppet::ParseError, "Exported resource #{obj.ref} cannot override local resource" 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.vquery - return self.vquery.call(resource) - else - return true - end + resource = obj.to_resource(self.scope) + + resource.exported = false + + scope.compiler.add_resource(scope, resource) + + resource + 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.vquery + return self.vquery.call(resource) + else + return true end + end end diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index 17b05baab..85980722c 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -10,484 +10,484 @@ require 'puppet/resource/type_collection_helper' # Maintain a graph of scopes, along with a bunch of data # about the individual catalog we're compiling. class Puppet::Parser::Compiler - include Puppet::Util - include Puppet::Util::Errors - include Puppet::Resource::TypeCollectionHelper - - def self.compile(node) - new(node).compile.to_resource - rescue => detail - puts detail.backtrace if Puppet[:trace] - raise Puppet::Error, "#{detail} on node #{node.name}" - end - - attr_reader :node, :facts, :collections, :catalog, :node_scope, :resources, :relationships + include Puppet::Util + include Puppet::Util::Errors + include Puppet::Resource::TypeCollectionHelper - # Add a collection to the global list. - def add_collection(coll) - @collections << coll - end - - def add_relationship(dep) - @relationships << dep - end + def self.compile(node) + new(node).compile.to_resource + rescue => detail + puts detail.backtrace if Puppet[:trace] + raise Puppet::Error, "#{detail} on node #{node.name}" + end - # Store a resource override. - def add_override(override) - # If possible, merge the override in immediately. - if resource = @catalog.resource(override.ref) - resource.merge(override) - else - # Otherwise, store the override for later; these - # get evaluated in Resource#finish. - @resource_overrides[override.ref] << override - end - end + attr_reader :node, :facts, :collections, :catalog, :node_scope, :resources, :relationships - # Store a resource in our resource table. - def add_resource(scope, resource) - @resources << resource + # Add a collection to the global list. + def add_collection(coll) + @collections << coll + end - # Note that this will fail if the resource is not unique. - @catalog.add_resource(resource) + def add_relationship(dep) + @relationships << dep + end - set_container_resource(scope, resource) + # Store a resource override. + def add_override(override) + # If possible, merge the override in immediately. + if resource = @catalog.resource(override.ref) + resource.merge(override) + else + # Otherwise, store the override for later; these + # get evaluated in Resource#finish. + @resource_overrides[override.ref] << override end + end - # Add our container edge. If we're a class, then we get treated specially - we can - # control the stage that the class is applied in. Otherwise, we just - # get added to our parent container. - def set_container_resource(scope, resource) - return if resource.type.to_s.downcase == "stage" - - if resource.type.to_s.downcase != "class" - raise ArgumentError, "Only classes can set 'stage'; normal resources like #{resource} cannot change run stage" if resource[:stage] - return @catalog.add_edge(scope.resource, resource) - end - - unless stage = @catalog.resource(:stage, resource[:stage] || :main) - raise ArgumentError, "Could not find stage #{resource[:stage] || :main} specified by #{resource}" - end + # Store a resource in our resource table. + def add_resource(scope, resource) + @resources << resource - @catalog.add_edge(stage, resource) - end + # Note that this will fail if the resource is not unique. + @catalog.add_resource(resource) - private :set_container_resource + set_container_resource(scope, resource) + end - # Do we use nodes found in the code, vs. the external node sources? - def ast_nodes? - known_resource_types.nodes? - end + # Add our container edge. If we're a class, then we get treated specially - we can + # control the stage that the class is applied in. Otherwise, we just + # get added to our parent container. + def set_container_resource(scope, resource) + return if resource.type.to_s.downcase == "stage" - # Store the fact that we've evaluated a class - def add_class(name) - @catalog.add_class(name) unless name == "" + if resource.type.to_s.downcase != "class" + raise ArgumentError, "Only classes can set 'stage'; normal resources like #{resource} cannot change run stage" if resource[:stage] + return @catalog.add_edge(scope.resource, resource) end - - # Return a list of all of the defined classes. - def classlist - @catalog.classes + unless stage = @catalog.resource(:stage, resource[:stage] || :main) + raise ArgumentError, "Could not find stage #{resource[:stage] || :main} specified by #{resource}" end - # Compiler our catalog. This mostly revolves around finding and evaluating classes. - # This is the main entry into our catalog. - def compile - # Set the client's parameters into the top scope. - set_node_parameters - create_settings_scope + @catalog.add_edge(stage, resource) + end - evaluate_main + private :set_container_resource + + # Do we use nodes found in the code, vs. the external node sources? + def ast_nodes? + known_resource_types.nodes? + end - evaluate_ast_node + # Store the fact that we've evaluated a class + def add_class(name) + @catalog.add_class(name) unless name == "" + end - evaluate_node_classes - evaluate_generators + # Return a list of all of the defined classes. + def classlist + @catalog.classes + end + + # Compiler our catalog. This mostly revolves around finding and evaluating classes. + # This is the main entry into our catalog. + def compile + # Set the client's parameters into the top scope. + set_node_parameters + create_settings_scope + + evaluate_main + + evaluate_ast_node + + evaluate_node_classes + + evaluate_generators + + finish + + fail_on_unevaluated + + @catalog + end + + # LAK:FIXME There are no tests for this. + def delete_collection(coll) + @collections.delete(coll) if @collections.include?(coll) + end - finish - - fail_on_unevaluated - - @catalog + # Return the node's environment. + def environment + unless defined?(@environment) + @environment = (node.environment and node.environment != "") ? node.environment : nil end + Puppet::Node::Environment.current = @environment + @environment + end - # LAK:FIXME There are no tests for this. - def delete_collection(coll) - @collections.delete(coll) if @collections.include?(coll) - end + # Evaluate all of the classes specified by the node. + def evaluate_node_classes + evaluate_classes(@node.classes, topscope) + end - # Return the node's environment. - def environment - unless defined?(@environment) - @environment = (node.environment and node.environment != "") ? node.environment : nil - end - Puppet::Node::Environment.current = @environment - @environment - end + # Evaluate each specified class in turn. If there are any classes we can't + # find, just tag the catalog and move on. This method really just + # creates resource objects that point back to the classes, and then the + # resources are themselves evaluated later in the process. + def evaluate_classes(classes, scope, lazy_evaluate = true) + raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source + found = [] + classes.each do |name| + # If we can find the class, then make a resource that will evaluate it. + if klass = scope.find_hostclass(name) + found << name and next if scope.class_scope(klass) - # Evaluate all of the classes specified by the node. - def evaluate_node_classes - evaluate_classes(@node.classes, topscope) - end - - # Evaluate each specified class in turn. If there are any classes we can't - # find, just tag the catalog and move on. This method really just - # creates resource objects that point back to the classes, and then the - # resources are themselves evaluated later in the process. - def evaluate_classes(classes, scope, lazy_evaluate = true) - raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source - found = [] - classes.each do |name| - # If we can find the class, then make a resource that will evaluate it. - if klass = scope.find_hostclass(name) - found << name and next if scope.class_scope(klass) - - resource = klass.mk_plain_resource(scope) - - # If they've disabled lazy evaluation (which the :include function does), - # then evaluate our resource immediately. - resource.evaluate unless lazy_evaluate - found << name - else - Puppet.info "Could not find class #{name} for #{node.name}" - @catalog.tag(name) - end - end - found - end - - def evaluate_relationships - @relationships.each { |rel| rel.evaluate(catalog) } - end + resource = klass.mk_plain_resource(scope) - # Return a resource by either its ref or its type and title. - def findresource(*args) - @catalog.resource(*args) + # If they've disabled lazy evaluation (which the :include function does), + # then evaluate our resource immediately. + resource.evaluate unless lazy_evaluate + found << name + else + Puppet.info "Could not find class #{name} for #{node.name}" + @catalog.tag(name) + end end - - def initialize(node, options = {}) - @node = node - - options.each do |param, value| - begin - send(param.to_s + "=", value) - rescue NoMethodError - raise ArgumentError, "Compiler objects do not accept #{param}" - end + found + end + + def evaluate_relationships + @relationships.each { |rel| rel.evaluate(catalog) } + end + + # Return a resource by either its ref or its type and title. + def findresource(*args) + @catalog.resource(*args) + end + + def initialize(node, options = {}) + @node = node + + options.each do |param, value| + begin + send(param.to_s + "=", value) + rescue NoMethodError + raise ArgumentError, "Compiler objects do not accept #{param}" + end + end + + initvars + end + + # Create a new scope, with either a specified parent scope or + # using the top scope. + def newscope(parent, options = {}) + parent ||= topscope + options[:compiler] = self + scope = Puppet::Parser::Scope.new(options) + scope.parent = parent + scope + end + + # Return any overrides for the given resource. + def resource_overrides(resource) + @resource_overrides[resource.ref] + end + + # The top scope is usually the top-level scope, but if we're using AST nodes, + # then it is instead the node's scope. + def topscope + node_scope || @topscope + end + + private + + # If ast nodes are enabled, then see if we can find and evaluate one. + def evaluate_ast_node + return unless ast_nodes? + + # Now see if we can find the node. + astnode = nil + @node.names.each do |name| + break if astnode = known_resource_types.node(name.to_s.downcase) + end + + unless (astnode ||= known_resource_types.node("default")) + raise Puppet::ParseError, "Could not find default node or by name with '#{node.names.join(", ")}'" + end + + # Create a resource to model this node, and then add it to the list + # of resources. + resource = astnode.mk_plain_resource(topscope) + + resource.evaluate + + # Now set the node scope appropriately, so that :topscope can + # behave differently. + @node_scope = topscope.class_scope(astnode) + end + + # Evaluate our collections and return true if anything returned an object. + # The 'true' is used to continue a loop, so it's important. + def evaluate_collections + return false if @collections.empty? + + found_something = false + exceptwrap do + # We have to iterate over a dup of the array because + # collections can delete themselves from the list, which + # changes its length and causes some collections to get missed. + @collections.dup.each do |collection| + found_something = true if collection.evaluate + end + end + + found_something + end + + # Make sure all of our resources have been evaluated into native resources. + # We return true if any resources have, so that we know to continue the + # evaluate_generators loop. + def evaluate_definitions + exceptwrap do + if ary = unevaluated_resources + evaluated = false + ary.each do |resource| + if not resource.virtual? + resource.evaluate + evaluated = true + end end - - initvars - end - - # Create a new scope, with either a specified parent scope or - # using the top scope. - def newscope(parent, options = {}) - parent ||= topscope - options[:compiler] = self - scope = Puppet::Parser::Scope.new(options) - scope.parent = parent - scope - end - - # Return any overrides for the given resource. - def resource_overrides(resource) - @resource_overrides[resource.ref] - end - - # The top scope is usually the top-level scope, but if we're using AST nodes, - # then it is instead the node's scope. - def topscope - node_scope || @topscope - end - - private - - # If ast nodes are enabled, then see if we can find and evaluate one. - def evaluate_ast_node - return unless ast_nodes? - - # Now see if we can find the node. - astnode = nil - @node.names.each do |name| - break if astnode = known_resource_types.node(name.to_s.downcase) - end - - unless (astnode ||= known_resource_types.node("default")) - raise Puppet::ParseError, "Could not find default node or by name with '#{node.names.join(", ")}'" + # If we evaluated, let the loop know. + return evaluated + else + return false + end + end + end + + # Iterate over collections and resources until we're sure that the whole + # compile is evaluated. This is necessary because both collections + # and defined resources can generate new resources, which themselves could + # be defined resources. + def evaluate_generators + count = 0 + loop do + done = true + + # Call collections first, then definitions. + done = false if evaluate_collections + done = false if evaluate_definitions + break if done + + count += 1 + + if count > 1000 + raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host catalog" + end + end + end + + # Find and evaluate our main object, if possible. + def evaluate_main + @main = known_resource_types.find_hostclass([""], "") || known_resource_types.add(Puppet::Resource::Type.new(:hostclass, "")) + @topscope.source = @main + @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main) + @topscope.resource = @main_resource + + @resources << @main_resource + @catalog.add_resource(@main_resource) + + set_container_resource(@topscope, @main_resource) + + @main_resource.evaluate + end + + # Make sure the entire catalog is evaluated. + def fail_on_unevaluated + fail_on_unevaluated_overrides + fail_on_unevaluated_resource_collections + end + + # If there are any resource overrides remaining, then we could + # not find the resource they were supposed to override, so we + # want to throw an exception. + def fail_on_unevaluated_overrides + remaining = [] + @resource_overrides.each do |name, overrides| + remaining += overrides + end + + unless remaining.empty? + fail Puppet::ParseError, + "Could not find resource(s) %s for overriding" % remaining.collect { |o| + o.ref + }.join(", ") + end + end + + # Make sure we don't have any remaining collections that specifically + # look for resources, because we want to consider those to be + # parse errors. + def fail_on_unevaluated_resource_collections + remaining = [] + @collections.each do |coll| + # We're only interested in the 'resource' collections, + # which result from direct calls of 'realize'. Anything + # else is allowed not to return resources. + # Collect all of them, so we have a useful error. + if r = coll.resources + if r.is_a?(Array) + remaining += r + else + remaining << r end - - # Create a resource to model this node, and then add it to the list - # of resources. - resource = astnode.mk_plain_resource(topscope) - - resource.evaluate - - # Now set the node scope appropriately, so that :topscope can - # behave differently. - @node_scope = topscope.class_scope(astnode) + end end - # Evaluate our collections and return true if anything returned an object. - # The 'true' is used to continue a loop, so it's important. - def evaluate_collections - return false if @collections.empty? - - found_something = false - exceptwrap do - # We have to iterate over a dup of the array because - # collections can delete themselves from the list, which - # changes its length and causes some collections to get missed. - @collections.dup.each do |collection| - found_something = true if collection.evaluate - end - end + raise Puppet::ParseError, "Failed to realize virtual resources #{remaining.join(', ')}" unless remaining.empty? + end - found_something - end + # Make sure all of our resources and such have done any last work + # necessary. + def finish + evaluate_relationships - # Make sure all of our resources have been evaluated into native resources. - # We return true if any resources have, so that we know to continue the - # evaluate_generators loop. - def evaluate_definitions - exceptwrap do - if ary = unevaluated_resources - evaluated = false - ary.each do |resource| - if not resource.virtual? - resource.evaluate - evaluated = true - end - end - # If we evaluated, let the loop know. - return evaluated - else - return false - end + resources.each do |resource| + # Add in any resource overrides. + if overrides = resource_overrides(resource) + overrides.each do |over| + resource.merge(over) end - end - # Iterate over collections and resources until we're sure that the whole - # compile is evaluated. This is necessary because both collections - # and defined resources can generate new resources, which themselves could - # be defined resources. - def evaluate_generators - count = 0 - loop do - done = true - - # Call collections first, then definitions. - done = false if evaluate_collections - done = false if evaluate_definitions - break if done - - count += 1 - - if count > 1000 - raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host catalog" - end - end - end - - # Find and evaluate our main object, if possible. - def evaluate_main - @main = known_resource_types.find_hostclass([""], "") || known_resource_types.add(Puppet::Resource::Type.new(:hostclass, "")) - @topscope.source = @main - @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main) - @topscope.resource = @main_resource - - @resources << @main_resource - @catalog.add_resource(@main_resource) + # Remove the overrides, so that the configuration knows there + # are none left. + overrides.clear + end - set_container_resource(@topscope, @main_resource) - - @main_resource.evaluate + resource.finish if resource.respond_to?(:finish) end - # Make sure the entire catalog is evaluated. - def fail_on_unevaluated - fail_on_unevaluated_overrides - fail_on_unevaluated_resource_collections - end + add_resource_metaparams + end - # If there are any resource overrides remaining, then we could - # not find the resource they were supposed to override, so we - # want to throw an exception. - def fail_on_unevaluated_overrides - remaining = [] - @resource_overrides.each do |name, overrides| - remaining += overrides - end - - unless remaining.empty? - fail Puppet::ParseError, - "Could not find resource(s) %s for overriding" % remaining.collect { |o| - o.ref - }.join(", ") - end + def add_resource_metaparams + unless main = catalog.resource(:class, :main) + raise "Couldn't find main" end - # Make sure we don't have any remaining collections that specifically - # look for resources, because we want to consider those to be - # parse errors. - def fail_on_unevaluated_resource_collections - remaining = [] - @collections.each do |coll| - # We're only interested in the 'resource' collections, - # which result from direct calls of 'realize'. Anything - # else is allowed not to return resources. - # Collect all of them, so we have a useful error. - if r = coll.resources - if r.is_a?(Array) - remaining += r - else - remaining << r - end - end - end - - raise Puppet::ParseError, "Failed to realize virtual resources #{remaining.join(', ')}" unless remaining.empty? + names = [] + Puppet::Type.eachmetaparam do |name| + next if Puppet::Parser::Resource.relationship_parameter?(name) + names << name end - # Make sure all of our resources and such have done any last work - # necessary. - def finish - evaluate_relationships - - resources.each do |resource| - # Add in any resource overrides. - if overrides = resource_overrides(resource) - overrides.each do |over| - resource.merge(over) - end - - # Remove the overrides, so that the configuration knows there - # are none left. - overrides.clear - end - - resource.finish if resource.respond_to?(:finish) + data = {} + catalog.walk(main, :out) do |source, target| + if source_data = data[source] || metaparams_as_data(source, names) + # only store anything in the data hash if we've actually got + # data + data[source] ||= source_data + source_data.each do |param, value| + target[param] = value if target[param].nil? end + data[target] = source_data.merge(metaparams_as_data(target, names)) + end - add_resource_metaparams + target.tag(*(source.tags)) end + end - def add_resource_metaparams - unless main = catalog.resource(:class, :main) - raise "Couldn't find main" - end - - names = [] - Puppet::Type.eachmetaparam do |name| - next if Puppet::Parser::Resource.relationship_parameter?(name) - names << name - end - - data = {} - catalog.walk(main, :out) do |source, target| - if source_data = data[source] || metaparams_as_data(source, names) - # only store anything in the data hash if we've actually got - # data - data[source] ||= source_data - source_data.each do |param, value| - target[param] = value if target[param].nil? - end - data[target] = source_data.merge(metaparams_as_data(target, names)) - end - - target.tag(*(source.tags)) - end + def metaparams_as_data(resource, params) + data = nil + params.each do |param| + unless resource[param].nil? + # Because we could be creating a hash for every resource, + # and we actually probably don't often have any data here at all, + # we're optimizing a bit by only creating a hash if there's + # any data to put in it. + data ||= {} + data[param] = resource[param] + end end + data + end - def metaparams_as_data(resource, params) - data = nil - params.each do |param| - unless resource[param].nil? - # Because we could be creating a hash for every resource, - # and we actually probably don't often have any data here at all, - # we're optimizing a bit by only creating a hash if there's - # any data to put in it. - data ||= {} - data[param] = resource[param] - end - end - data - end + # Set up all of our internal variables. + def initvars + # The list of objects that will available for export. + @exported_resources = {} - # Set up all of our internal variables. - def initvars - # The list of objects that will available for export. - @exported_resources = {} + # The list of overrides. This is used to cache overrides on objects + # that don't exist yet. We store an array of each override. + @resource_overrides = Hash.new do |overs, ref| + overs[ref] = [] + end - # The list of overrides. This is used to cache overrides on objects - # that don't exist yet. We store an array of each override. - @resource_overrides = Hash.new do |overs, ref| - overs[ref] = [] - end + # The list of collections that have been created. This is a global list, + # but they each refer back to the scope that created them. + @collections = [] - # The list of collections that have been created. This is a global list, - # but they each refer back to the scope that created them. - @collections = [] + # The list of relationships to evaluate. + @relationships = [] - # The list of relationships to evaluate. - @relationships = [] + # For maintaining the relationship between scopes and their resources. + @catalog = Puppet::Resource::Catalog.new(@node.name) + @catalog.version = known_resource_types.version - # For maintaining the relationship between scopes and their resources. - @catalog = Puppet::Resource::Catalog.new(@node.name) - @catalog.version = known_resource_types.version + # Create our initial scope and a resource that will evaluate main. + @topscope = Puppet::Parser::Scope.new(:compiler => self) - # Create our initial scope and a resource that will evaluate main. - @topscope = Puppet::Parser::Scope.new(:compiler => self) + @main_stage_resource = Puppet::Parser::Resource.new("stage", :main, :scope => @topscope) + @catalog.add_resource(@main_stage_resource) - @main_stage_resource = Puppet::Parser::Resource.new("stage", :main, :scope => @topscope) - @catalog.add_resource(@main_stage_resource) + # local resource array to maintain resource ordering + @resources = [] - # local resource array to maintain resource ordering - @resources = [] + # Make sure any external node classes are in our class list + @catalog.add_class(*@node.classes) + end - # Make sure any external node classes are in our class list - @catalog.add_class(*@node.classes) + # Set the node's parameters into the top-scope as variables. + def set_node_parameters + node.parameters.each do |param, value| + @topscope.setvar(param, value) end - # Set the node's parameters into the top-scope as variables. - def set_node_parameters - node.parameters.each do |param, value| - @topscope.setvar(param, value) - end + # These might be nil. + catalog.client_version = node.parameters["clientversion"] + catalog.server_version = node.parameters["serverversion"] + end - # These might be nil. - catalog.client_version = node.parameters["clientversion"] - catalog.server_version = node.parameters["serverversion"] + def create_settings_scope + unless settings_type = environment.known_resource_types.hostclass("settings") + settings_type = Puppet::Resource::Type.new :hostclass, "settings" + environment.known_resource_types.add(settings_type) end - def create_settings_scope - unless settings_type = environment.known_resource_types.hostclass("settings") - settings_type = Puppet::Resource::Type.new :hostclass, "settings" - environment.known_resource_types.add(settings_type) - end + settings_resource = Puppet::Parser::Resource.new("class", "settings", :scope => @topscope) + settings_type.evaluate_code(settings_resource) - settings_resource = Puppet::Parser::Resource.new("class", "settings", :scope => @topscope) - settings_type.evaluate_code(settings_resource) + @catalog.add_resource(settings_resource) - @catalog.add_resource(settings_resource) + scope = @topscope.class_scope(settings_type) - scope = @topscope.class_scope(settings_type) - - Puppet.settings.each do |name, setting| - next if name.to_s == "name" - scope.setvar name.to_s, environment[name] - end + Puppet.settings.each do |name, setting| + next if name.to_s == "name" + scope.setvar name.to_s, environment[name] end + end - # Return an array of all of the unevaluated resources. These will be definitions, - # which need to get evaluated into native resources. - def unevaluated_resources - ary = resources.reject { |resource| resource.builtin? or resource.evaluated? } + # Return an array of all of the unevaluated resources. These will be definitions, + # which need to get evaluated into native resources. + def unevaluated_resources + ary = resources.reject { |resource| resource.builtin? or resource.evaluated? } - if ary.empty? - return nil - else - return ary - end + if ary.empty? + return nil + else + return ary end + end end diff --git a/lib/puppet/parser/files.rb b/lib/puppet/parser/files.rb index 875a87826..749743493 100644 --- a/lib/puppet/parser/files.rb +++ b/lib/puppet/parser/files.rb @@ -6,83 +6,83 @@ require 'puppet/parser/parser' # doesn't really belong in the Puppet::Module class, # but it doesn't really belong anywhere else, either. module Puppet::Parser::Files - module_function + module_function - # Return a list of manifests (as absolute filenames) that match +pat+ - # with the current directory set to +cwd+. If the first component of - # +pat+ does not contain any wildcards and is an existing module, return - # a list of manifests in that module matching the rest of +pat+ - # Otherwise, try to find manifests matching +pat+ relative to +cwd+ - def find_manifests(start, options = {}) - cwd = options[:cwd] || Dir.getwd - module_name, pattern = split_file_path(start) - begin - if mod = Puppet::Module.find(module_name, options[:environment]) - return [mod.name, mod.match_manifests(pattern)] - end - rescue Puppet::Module::InvalidName - # Than that would be a "no." - end - abspat = File::expand_path(start, cwd) - [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{,.pp,.rb}' : '' )).reject { |f| FileTest.directory?(f) }] + # Return a list of manifests (as absolute filenames) that match +pat+ + # with the current directory set to +cwd+. If the first component of + # +pat+ does not contain any wildcards and is an existing module, return + # a list of manifests in that module matching the rest of +pat+ + # Otherwise, try to find manifests matching +pat+ relative to +cwd+ + def find_manifests(start, options = {}) + cwd = options[:cwd] || Dir.getwd + module_name, pattern = split_file_path(start) + begin + if mod = Puppet::Module.find(module_name, options[:environment]) + return [mod.name, mod.match_manifests(pattern)] + end + rescue Puppet::Module::InvalidName + # Than that would be a "no." end + abspat = File::expand_path(start, cwd) + [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{,.pp,.rb}' : '' )).reject { |f| FileTest.directory?(f) }] + end - # Find the concrete file denoted by +file+. If +file+ is absolute, - # return it directly. Otherwise try to find it as a template in a - # module. If that fails, return it relative to the +templatedir+ config - # param. - # In all cases, an absolute path is returned, which does not - # necessarily refer to an existing file - def find_template(template, environment = nil) - if template == File.expand_path(template) - return template - end - - if template_paths = templatepath(environment) - # If we can find the template in :templatedir, we return that. - template_paths.collect { |path| - File::join(path, template) - }.each do |f| - return f if FileTest.exist?(f) - end - end + # Find the concrete file denoted by +file+. If +file+ is absolute, + # return it directly. Otherwise try to find it as a template in a + # module. If that fails, return it relative to the +templatedir+ config + # param. + # In all cases, an absolute path is returned, which does not + # necessarily refer to an existing file + def find_template(template, environment = nil) + if template == File.expand_path(template) + return template + end - # check in the default template dir, if there is one - if td_file = find_template_in_module(template, environment) - return td_file - end + if template_paths = templatepath(environment) + # If we can find the template in :templatedir, we return that. + template_paths.collect { |path| + File::join(path, template) + }.each do |f| + return f if FileTest.exist?(f) + end + end - nil + # check in the default template dir, if there is one + if td_file = find_template_in_module(template, environment) + return td_file end - def find_template_in_module(template, environment = nil) - path, file = split_file_path(template) + nil + end - # Because templates don't have an assumed template name, like manifests do, - # we treat templates with no name as being templates in the main template - # directory. - return nil unless file + def find_template_in_module(template, environment = nil) + path, file = split_file_path(template) - if mod = Puppet::Module.find(path, environment) and t = mod.template(file) - return t - end - nil - end + # Because templates don't have an assumed template name, like manifests do, + # we treat templates with no name as being templates in the main template + # directory. + return nil unless file - # Return an array of paths by splitting the +templatedir+ config - # parameter. - def templatepath(environment = nil) - dirs = Puppet.settings.value(:templatedir, environment).split(File::PATH_SEPARATOR) - dirs.select do |p| - File::directory?(p) - end + if mod = Puppet::Module.find(path, environment) and t = mod.template(file) + return t end + nil + end - # Split the path into the module and the rest of the path, or return - # nil if the path is empty or absolute (starts with a /). - # This method can return nil & anyone calling it needs to handle that. - def split_file_path(path) - path.split(File::SEPARATOR, 2) unless path == "" or path == File.expand_path(path) + # Return an array of paths by splitting the +templatedir+ config + # parameter. + def templatepath(environment = nil) + dirs = Puppet.settings.value(:templatedir, environment).split(File::PATH_SEPARATOR) + dirs.select do |p| + File::directory?(p) end + end + + # Split the path into the module and the rest of the path, or return + # nil if the path is empty or absolute (starts with a /). + # This method can return nil & anyone calling it needs to handle that. + def split_file_path(path) + path.split(File::SEPARATOR, 2) unless path == "" or path == File.expand_path(path) + end end diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 3e56f2a95..c238da5d4 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -7,116 +7,116 @@ require 'monitor' # class. module Puppet::Parser::Functions - (@functions = Hash.new { |h,k| h[k] = {} }).extend(MonitorMixin) - (@modules = {} ).extend(MonitorMixin) + (@functions = Hash.new { |h,k| h[k] = {} }).extend(MonitorMixin) + (@modules = {} ).extend(MonitorMixin) - class << self - include Puppet::Util - end + class << self + include Puppet::Util + end - def self.autoloader - unless defined?(@autoloader) + def self.autoloader + unless defined?(@autoloader) - @autoloader = Puppet::Util::Autoload.new( - self, - "puppet/parser/functions", + @autoloader = Puppet::Util::Autoload.new( + self, + "puppet/parser/functions", - :wrap => false - ) - end - - @autoloader + :wrap => false + ) end - Environment = Puppet::Node::Environment + @autoloader + end - def self.environment_module(env = nil) - @modules.synchronize { - @modules[ env || Environment.current || Environment.root ] ||= Module.new - } - end + Environment = Puppet::Node::Environment - # Create a new function type. - def self.newfunction(name, options = {}, &block) - name = symbolize(name) + def self.environment_module(env = nil) + @modules.synchronize { + @modules[ env || Environment.current || Environment.root ] ||= Module.new + } + end - raise Puppet::DevError, "Function #{name} already defined" if functions.include?(name) + # Create a new function type. + def self.newfunction(name, options = {}, &block) + name = symbolize(name) - ftype = options[:type] || :statement + raise Puppet::DevError, "Function #{name} already defined" if functions.include?(name) - unless ftype == :statement or ftype == :rvalue - raise Puppet::DevError, "Invalid statement type #{ftype.inspect}" - end + ftype = options[:type] || :statement - fname = "function_#{name}" - environment_module.send(:define_method, fname, &block) - - # Someday we'll support specifying an arity, but for now, nope - #functions[name] = {:arity => arity, :type => ftype} - functions[name] = {:type => ftype, :name => fname} - functions[name][:doc] = options[:doc] if options[:doc] + unless ftype == :statement or ftype == :rvalue + raise Puppet::DevError, "Invalid statement type #{ftype.inspect}" end - # Remove a function added by newfunction - def self.rmfunction(name) - name = symbolize(name) + fname = "function_#{name}" + environment_module.send(:define_method, fname, &block) - raise Puppet::DevError, "Function #{name} is not defined" unless functions.include? name + # Someday we'll support specifying an arity, but for now, nope + #functions[name] = {:arity => arity, :type => ftype} + functions[name] = {:type => ftype, :name => fname} + functions[name][:doc] = options[:doc] if options[:doc] + end - functions.delete name + # Remove a function added by newfunction + def self.rmfunction(name) + name = symbolize(name) - fname = "function_#{name}" - environment_module.send(:remove_method, fname) - end + raise Puppet::DevError, "Function #{name} is not defined" unless functions.include? name - # Determine if a given name is a function - def self.function(name) - name = symbolize(name) + functions.delete name - unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name) - autoloader.load(name,Environment.current || Environment.root) - end + fname = "function_#{name}" + environment_module.send(:remove_method, fname) + end - ( functions(Environment.root)[name] || functions[name] || {:name => false} )[:name] + # Determine if a given name is a function + def self.function(name) + name = symbolize(name) + + unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name) + autoloader.load(name,Environment.current || Environment.root) end - def self.functiondocs - autoloader.loadall + ( functions(Environment.root)[name] || functions[name] || {:name => false} )[:name] + end - ret = "" + def self.functiondocs + autoloader.loadall - functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash| - #ret += "#{name}\n#{hash[:type]}\n" - ret += "#{name}\n#{"-" * name.to_s.length}\n" - if hash[:doc] - ret += Puppet::Util::Docs.scrub(hash[:doc]) - else - ret += "Undocumented.\n" - end + ret = "" - ret += "\n\n- **Type**: #{hash[:type]}\n\n" - end + functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash| + #ret += "#{name}\n#{hash[:type]}\n" + ret += "#{name}\n#{"-" * name.to_s.length}\n" + if hash[:doc] + ret += Puppet::Util::Docs.scrub(hash[:doc]) + else + ret += "Undocumented.\n" + end - ret + ret += "\n\n- **Type**: #{hash[:type]}\n\n" end - def self.functions(env = nil) - @functions.synchronize { - @functions[ env || Environment.current || Environment.root ] - } - end + ret + end - # Determine if a given function returns a value or not. - def self.rvalue?(name) - (functions[symbolize(name)] || {})[:type] == :rvalue - end + def self.functions(env = nil) + @functions.synchronize { + @functions[ env || Environment.current || Environment.root ] + } + end + + # Determine if a given function returns a value or not. + def self.rvalue?(name) + (functions[symbolize(name)] || {})[:type] == :rvalue + end - # Runs a newfunction to create a function for each of the log levels + # Runs a newfunction to create a function for each of the log levels - Puppet::Util::Log.levels.each do |level| - newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals| - send(level, vals.join(" ")) - end + Puppet::Util::Log.levels.each do |level| + newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals| + send(level, vals.join(" ")) end + end end diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index 4d1d8c6fd..2930a65cc 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -1,27 +1,27 @@ # Test whether a given class or definition is defined Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether a given - type is defined, either as a native type or a defined type, or whether a class is defined. - This is useful for checking whether a class is defined and only including it if it is. - This function can also test whether a resource has been defined, using resource references - (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately - dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals| - result = false - vals = [vals] unless vals.is_a?(Array) - vals.each do |val| - case val - when String - if Puppet::Type.type(val) or find_definition(val) or find_hostclass(val) - result = true - break - end - when Puppet::Resource - if findresource(val.to_s) - result = true - break - end - else - raise ArgumentError, "Invalid argument of type '#{val.class}' to 'defined'" - end + type is defined, either as a native type or a defined type, or whether a class is defined. + This is useful for checking whether a class is defined and only including it if it is. + This function can also test whether a resource has been defined, using resource references + (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately + dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals| + result = false + vals = [vals] unless vals.is_a?(Array) + vals.each do |val| + case val + when String + if Puppet::Type.type(val) or find_definition(val) or find_hostclass(val) + result = true + break end - result + when Puppet::Resource + if findresource(val.to_s) + result = true + break + end + else + raise ArgumentError, "Invalid argument of type '#{val.class}' to 'defined'" + end + end + result end diff --git a/lib/puppet/parser/functions/fail.rb b/lib/puppet/parser/functions/fail.rb index 35b20ee92..5bef6c7e3 100644 --- a/lib/puppet/parser/functions/fail.rb +++ b/lib/puppet/parser/functions/fail.rb @@ -1,4 +1,4 @@ Puppet::Parser::Functions::newfunction(:fail, :doc => "Fail with a parse error.") do |vals| - vals = vals.collect { |s| s.to_s }.join(" ") if vals.is_a? Array - raise Puppet::ParseError, vals.to_s + vals = vals.collect { |s| s.to_s }.join(" ") if vals.is_a? Array + raise Puppet::ParseError, vals.to_s end diff --git a/lib/puppet/parser/functions/file.rb b/lib/puppet/parser/functions/file.rb index d13b01ede..963111260 100644 --- a/lib/puppet/parser/functions/file.rb +++ b/lib/puppet/parser/functions/file.rb @@ -1,23 +1,23 @@ # Returns the contents of a file - Puppet::Parser::Functions::newfunction( - :file, :type => :rvalue, + Puppet::Parser::Functions::newfunction( + :file, :type => :rvalue, - :doc => "Return the contents of a file. Multiple files - can be passed, and the first file that exists will be read in.") do |vals| - ret = nil - vals.each do |file| - unless file =~ /^#{File::SEPARATOR}/ - raise Puppet::ParseError, "Files must be fully qualified" - end - if FileTest.exists?(file) - ret = File.read(file) - break - end - end - if ret - ret - else - raise Puppet::ParseError, "Could not find any files from #{vals.join(", ")}" - end + :doc => "Return the contents of a file. Multiple files + can be passed, and the first file that exists will be read in.") do |vals| + ret = nil + vals.each do |file| + unless file =~ /^#{File::SEPARATOR}/ + raise Puppet::ParseError, "Files must be fully qualified" + end + if FileTest.exists?(file) + ret = File.read(file) + break + end + end + if ret + ret + else + raise Puppet::ParseError, "Could not find any files from #{vals.join(", ")}" + end end diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb index 27af2d7ca..3e7018ac4 100644 --- a/lib/puppet/parser/functions/fqdn_rand.rb +++ b/lib/puppet/parser/functions/fqdn_rand.rb @@ -1,9 +1,9 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc => - "Generates random numbers based on the node's fqdn. The first argument - sets the range. Additional (optional) arguments may be used to further - distinguish the seed.") do |args| - require 'md5' - max = args.shift - srand MD5.new([lookupvar('fqdn'),args].join(':')).to_s.hex - rand(max).to_s + "Generates random numbers based on the node's fqdn. The first argument + sets the range. Additional (optional) arguments may be used to further + distinguish the seed.") do |args| + require 'md5' + max = args.shift + srand MD5.new([lookupvar('fqdn'),args].join(':')).to_s.hex + rand(max).to_s end diff --git a/lib/puppet/parser/functions/generate.rb b/lib/puppet/parser/functions/generate.rb index 8430f03a6..91f7b2240 100644 --- a/lib/puppet/parser/functions/generate.rb +++ b/lib/puppet/parser/functions/generate.rb @@ -1,31 +1,31 @@ # Runs an external command and returns the results Puppet::Parser::Functions::newfunction(:generate, :type => :rvalue, - :doc => "Calls an external command on the Puppet master and returns - the results of the command. Any arguments are passed to the external command as - arguments. If the generator does not exit with return code of 0, - the generator is considered to have failed and a parse error is - thrown. Generators can only have file separators, alphanumerics, dashes, - and periods in them. This function will attempt to protect you from - malicious generator calls (e.g., those with '..' in them), but it can - never be entirely safe. No subshell is used to execute - generators, so all shell metacharacters are passed directly to - the generator.") do |args| + :doc => "Calls an external command on the Puppet master and returns + the results of the command. Any arguments are passed to the external command as + arguments. If the generator does not exit with return code of 0, + the generator is considered to have failed and a parse error is + thrown. Generators can only have file separators, alphanumerics, dashes, + and periods in them. This function will attempt to protect you from + malicious generator calls (e.g., those with '..' in them), but it can + never be entirely safe. No subshell is used to execute + generators, so all shell metacharacters are passed directly to + the generator.") do |args| - raise Puppet::ParseError, "Generators must be fully qualified" unless args[0] =~ /^#{File::SEPARATOR}/ + raise Puppet::ParseError, "Generators must be fully qualified" unless args[0] =~ /^#{File::SEPARATOR}/ - unless args[0] =~ /^[-#{File::SEPARATOR}\w.]+$/ - raise Puppet::ParseError, - "Generators can only contain alphanumerics, file separators, and dashes" - end + unless args[0] =~ /^[-#{File::SEPARATOR}\w.]+$/ + raise Puppet::ParseError, + "Generators can only contain alphanumerics, file separators, and dashes" + end - if args[0] =~ /\.\./ - raise Puppet::ParseError, - "Can not use generators with '..' in them." - end + if args[0] =~ /\.\./ + raise Puppet::ParseError, + "Can not use generators with '..' in them." + end - begin - Dir.chdir(File.dirname(args[0])) { Puppet::Util.execute(args) } - rescue Puppet::ExecutionFailure => detail - raise Puppet::ParseError, "Failed to execute generator #{args[0]}: #{detail}" - end + begin + Dir.chdir(File.dirname(args[0])) { Puppet::Util.execute(args) } + rescue Puppet::ExecutionFailure => detail + raise Puppet::ParseError, "Failed to execute generator #{args[0]}: #{detail}" + end end diff --git a/lib/puppet/parser/functions/include.rb b/lib/puppet/parser/functions/include.rb index d1bafa54a..1e12a6a88 100644 --- a/lib/puppet/parser/functions/include.rb +++ b/lib/puppet/parser/functions/include.rb @@ -1,24 +1,24 @@ # Include the specified classes Puppet::Parser::Functions::newfunction(:include, :doc => "Evaluate one or more classes.") do |vals| - vals = [vals] unless vals.is_a?(Array) + vals = [vals] unless vals.is_a?(Array) - # The 'false' disables lazy evaluation. - klasses = compiler.evaluate_classes(vals, self, false) + # The 'false' disables lazy evaluation. + klasses = compiler.evaluate_classes(vals, self, false) - missing = vals.find_all do |klass| - ! klasses.include?(klass) - end + missing = vals.find_all do |klass| + ! klasses.include?(klass) + end - unless missing.empty? - # Throw an error if we didn't evaluate all of the classes. - str = "Could not find class" - str += "es" if missing.length > 1 + unless missing.empty? + # Throw an error if we didn't evaluate all of the classes. + str = "Could not find class" + str += "es" if missing.length > 1 - str += " " + missing.join(", ") + str += " " + missing.join(", ") - if n = namespaces and ! n.empty? and n != [""] - str += " in namespaces #{@namespaces.join(", ")}" - end - self.fail Puppet::ParseError, str - end + if n = namespaces and ! n.empty? and n != [""] + str += " in namespaces #{@namespaces.join(", ")}" + end + self.fail Puppet::ParseError, str + end end diff --git a/lib/puppet/parser/functions/inline_template.rb b/lib/puppet/parser/functions/inline_template.rb index 6c0485d1e..11d980fab 100644 --- a/lib/puppet/parser/functions/inline_template.rb +++ b/lib/puppet/parser/functions/inline_template.rb @@ -1,20 +1,20 @@ Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :doc => - "Evaluate a template string and return its value. See `the templating docs - </trac/puppet/wiki/PuppetTemplating>`_ for more information. Note that - if multiple template strings are specified, their output is all concatenated - and returned as the output of the function.") do |vals| - require 'erb' + "Evaluate a template string and return its value. See `the templating docs + </trac/puppet/wiki/PuppetTemplating>`_ for more information. Note that + if multiple template strings are specified, their output is all concatenated + and returned as the output of the function.") do |vals| + require 'erb' - vals.collect do |string| - # Use a wrapper, so the template can't get access to the full - # Scope object. + vals.collect do |string| + # Use a wrapper, so the template can't get access to the full + # Scope object. - wrapper = Puppet::Parser::TemplateWrapper.new(self) - begin - wrapper.result(string) - rescue => detail - raise Puppet::ParseError, - "Failed to parse inline template: #{detail}" - end - end.join("") + wrapper = Puppet::Parser::TemplateWrapper.new(self) + begin + wrapper.result(string) + rescue => detail + raise Puppet::ParseError, + "Failed to parse inline template: #{detail}" + end + end.join("") end diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb index 6aff19d29..4247b8af8 100644 --- a/lib/puppet/parser/functions/realize.rb +++ b/lib/puppet/parser/functions/realize.rb @@ -2,13 +2,13 @@ # be a good bit faster. Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object real. This is useful - when you want to know the name of the virtual object and don't want to - bother with a full collection. It is slightly faster than a collection, - and, of course, is a bit shorter. You must pass the object using a - reference; e.g.: ``realize User[luke]``." ) do |vals| - coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual) - vals = [vals] unless vals.is_a?(Array) - coll.resources = vals.flatten + when you want to know the name of the virtual object and don't want to + bother with a full collection. It is slightly faster than a collection, + and, of course, is a bit shorter. You must pass the object using a + reference; e.g.: ``realize User[luke]``." ) do |vals| + coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual) + vals = [vals] unless vals.is_a?(Array) + coll.resources = vals.flatten - compiler.add_collection(coll) + compiler.add_collection(coll) end diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb index c47c1654e..c0aeef222 100644 --- a/lib/puppet/parser/functions/regsubst.rb +++ b/lib/puppet/parser/functions/regsubst.rb @@ -1,10 +1,10 @@ module Puppet::Parser::Functions - newfunction( - :regsubst, :type => :rvalue, + newfunction( + :regsubst, :type => :rvalue, - :doc => " - Perform regexp replacement on a string or array of strings. + :doc => " + Perform regexp replacement on a string or array of strings. - **Parameters** (in order): @@ -16,85 +16,85 @@ module Puppet::Parser::Functions :flags: Optional. String of single letter flags for how the regexp is interpreted: - - **E** Extended regexps - - **I** Ignore case in regexps - - **M** Multiline regexps - - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. + - **E** Extended regexps + - **I** Ignore case in regexps + - **M** Multiline regexps + - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. :lang: Optional. How to handle multibyte characters. A single-character string with the following values: - - **N** None - - **E** EUC - - **S** SJIS - - **U** UTF-8 + - **N** None + - **E** EUC + - **S** SJIS + - **U** UTF-8 - **Examples** Get the third octet from the node's IP address:: - $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3') + $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3') Put angle brackets around each octet in the node's IP address:: - $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') + $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') ") \ - do |args| - unless args.length.between?(3, 5) - - raise( - Puppet::ParseError, - - "regsubst(): got #{args.length} arguments, expected 3 to 5") - end - target, regexp, replacement, flags, lang = args - reflags = 0 - operation = :sub - if flags == nil - flags = [] - elsif flags.respond_to?(:split) - flags = flags.split('') - else - - raise( - Puppet::ParseError, - - "regsubst(): bad flags parameter #{flags.class}:`#{flags}'") - end - flags.each do |f| - case f - when 'G' then operation = :gsub - when 'E' then reflags |= Regexp::EXTENDED - when 'I' then reflags |= Regexp::IGNORECASE - when 'M' then reflags |= Regexp::MULTILINE - else raise(Puppet::ParseError, "regsubst(): bad flag `#{f}'") - end - end - begin - re = Regexp.compile(regexp, reflags, lang) - rescue RegexpError, TypeError - - raise( - Puppet::ParseError, - - "regsubst(): Bad regular expression `#{regexp}'") - end - if target.respond_to?(operation) - # String parameter -> string result - result = target.send(operation, re, replacement) - elsif target.respond_to?(:collect) and - target.respond_to?(:all?) and - target.all? { |e| e.respond_to?(operation) } - # Array parameter -> array result - result = target.collect { |e| - e.send(operation, re, replacement) - } - else - - raise( - Puppet::ParseError, - - "regsubst(): bad target #{target.class}:`#{target}'") - end - return result + do |args| + unless args.length.between?(3, 5) + + raise( + Puppet::ParseError, + + "regsubst(): got #{args.length} arguments, expected 3 to 5") + end + target, regexp, replacement, flags, lang = args + reflags = 0 + operation = :sub + if flags == nil + flags = [] + elsif flags.respond_to?(:split) + flags = flags.split('') + else + + raise( + Puppet::ParseError, + + "regsubst(): bad flags parameter #{flags.class}:`#{flags}'") + end + flags.each do |f| + case f + when 'G' then operation = :gsub + when 'E' then reflags |= Regexp::EXTENDED + when 'I' then reflags |= Regexp::IGNORECASE + when 'M' then reflags |= Regexp::MULTILINE + else raise(Puppet::ParseError, "regsubst(): bad flag `#{f}'") + end + end + begin + re = Regexp.compile(regexp, reflags, lang) + rescue RegexpError, TypeError + + raise( + Puppet::ParseError, + + "regsubst(): Bad regular expression `#{regexp}'") + end + if target.respond_to?(operation) + # String parameter -> string result + result = target.send(operation, re, replacement) + elsif target.respond_to?(:collect) and + target.respond_to?(:all?) and + target.all? { |e| e.respond_to?(operation) } + # Array parameter -> array result + result = target.collect { |e| + e.send(operation, re, replacement) + } + else + + raise( + Puppet::ParseError, + + "regsubst(): bad target #{target.class}:`#{target}'") end + return result + end end diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb index c5c4c851f..3f98c9523 100644 --- a/lib/puppet/parser/functions/require.rb +++ b/lib/puppet/parser/functions/require.rb @@ -1,9 +1,9 @@ # Requires the specified classes - Puppet::Parser::Functions::newfunction( - :require, + Puppet::Parser::Functions::newfunction( + :require, - :doc =>"Evaluate one or more classes, adding the required class as a dependency. + :doc =>"Evaluate one or more classes, adding the required class as a dependency. The relationship metaparameters work well for specifying relationships between individual resources, but they can be clumsy for specifying @@ -12,47 +12,47 @@ relationships between classes. This function is a superset of the class depends on the required class. Warning: using require in place of include can lead to unwanted dependency cycles. - For instance the following manifest, with 'require' instead of 'include' - would produce a nasty dependence cycle, because notify imposes a before - between File[/foo] and Service[foo]:: + For instance the following manifest, with 'require' instead of 'include' + would produce a nasty dependence cycle, because notify imposes a before + between File[/foo] and Service[foo]:: - class myservice { - service { foo: ensure => running } - } + class myservice { + service { foo: ensure => running } + } - class otherstuff { - include myservice - file { '/foo': notify => Service[foo] } - } + class otherstuff { + include myservice + file { '/foo': notify => Service[foo] } + } Note that this function only works with clients 0.25 and later, and it will fail if used with earlier clients. ") do |vals| - # Verify that the 'include' function is loaded - method = Puppet::Parser::Functions.function(:include) - - send(method, vals) - if resource.metaparam_compatibility_mode? - warning "The 'require' function is only compatible with clients at 0.25 and above; including class but not adding dependency" - else - vals = [vals] unless vals.is_a?(Array) - - vals.each do |klass| - # lookup the class in the scopes - if classobj = find_hostclass(klass) - klass = classobj.name - else - raise Puppet::ParseError, "Could not find class #{klass}" - end - - # This is a bit hackish, in some ways, but it's the only way - # to configure a dependency that will make it to the client. - # The 'obvious' way is just to add an edge in the catalog, - # but that is considered a containment edge, not a dependency - # edge, so it usually gets lost on the client. - ref = Puppet::Resource.new(:class, klass) - resource.set_parameter(:require, [resource[:require]].flatten.compact << ref) - end + # Verify that the 'include' function is loaded + method = Puppet::Parser::Functions.function(:include) + + send(method, vals) + if resource.metaparam_compatibility_mode? + warning "The 'require' function is only compatible with clients at 0.25 and above; including class but not adding dependency" + else + vals = [vals] unless vals.is_a?(Array) + + vals.each do |klass| + # lookup the class in the scopes + if classobj = find_hostclass(klass) + klass = classobj.name + else + raise Puppet::ParseError, "Could not find class #{klass}" + end + + # This is a bit hackish, in some ways, but it's the only way + # to configure a dependency that will make it to the client. + # The 'obvious' way is just to add an edge in the catalog, + # but that is considered a containment edge, not a dependency + # edge, so it usually gets lost on the client. + ref = Puppet::Resource.new(:class, klass) + resource.set_parameter(:require, [resource[:require]].flatten.compact << ref) end + end end diff --git a/lib/puppet/parser/functions/search.rb b/lib/puppet/parser/functions/search.rb index 87dd02d67..8a9c7c8be 100644 --- a/lib/puppet/parser/functions/search.rb +++ b/lib/puppet/parser/functions/search.rb @@ -1,7 +1,7 @@ Puppet::Parser::Functions::newfunction(:search, :doc => "Add another namespace for this class to search. - This allows you to create classes with sets of definitions and add - those classes to another class's search path.") do |vals| - vals.each do |val| - add_namespace(val) - end + This allows you to create classes with sets of definitions and add + those classes to another class's search path.") do |vals| + vals.each do |val| + add_namespace(val) + end end diff --git a/lib/puppet/parser/functions/sha1.rb b/lib/puppet/parser/functions/sha1.rb index 432825ee9..10cc55cfe 100644 --- a/lib/puppet/parser/functions/sha1.rb +++ b/lib/puppet/parser/functions/sha1.rb @@ -1,5 +1,5 @@ Puppet::Parser::Functions::newfunction(:sha1, :type => :rvalue, :doc => "Returns a SHA1 hash value from a provided string.") do |args| - require 'sha1' + require 'sha1' - Digest::SHA1.hexdigest(args[0]) + Digest::SHA1.hexdigest(args[0]) end diff --git a/lib/puppet/parser/functions/shellquote.rb b/lib/puppet/parser/functions/shellquote.rb index 888b9769d..3ddb988f2 100644 --- a/lib/puppet/parser/functions/shellquote.rb +++ b/lib/puppet/parser/functions/shellquote.rb @@ -1,39 +1,39 @@ module Puppet::Parser::Functions - Safe = 'a-zA-Z0-9@%_+=:,./-' # Safe unquoted - Dangerous = '!"`$\\' # Unsafe inside double quotes + Safe = 'a-zA-Z0-9@%_+=:,./-' # Safe unquoted + Dangerous = '!"`$\\' # Unsafe inside double quotes - newfunction(:shellquote, :type => :rvalue, :doc => "\ - Quote and concatenate arguments for use in Bourne shell. + newfunction(:shellquote, :type => :rvalue, :doc => "\ + Quote and concatenate arguments for use in Bourne shell. - Each argument is quoted separately, and then all are concatenated - with spaces. If an argument is an array, the elements of that - array is interpolated within the rest of the arguments; this makes - it possible to have an array of arguments and pass that array to - shellquote instead of having to specify each argument - individually in the call. - ") \ - do |args| + Each argument is quoted separately, and then all are concatenated + with spaces. If an argument is an array, the elements of that + array is interpolated within the rest of the arguments; this makes + it possible to have an array of arguments and pass that array to + shellquote instead of having to specify each argument + individually in the call. + ") \ + do |args| - result = [] - args.flatten.each do |word| - if word.length != 0 and word.count(Safe) == word.length - result << word - elsif word.count(Dangerous) == 0 - result << ('"' + word + '"') - elsif word.count("'") == 0 - result << ("'" + word + "'") - else - r = '"' - word.each_byte do |c| - r += "\\" if Dangerous.include?(c) - r += c.chr - end - r += '"' - result << r - end + result = [] + args.flatten.each do |word| + if word.length != 0 and word.count(Safe) == word.length + result << word + elsif word.count(Dangerous) == 0 + result << ('"' + word + '"') + elsif word.count("'") == 0 + result << ("'" + word + "'") + else + r = '"' + word.each_byte do |c| + r += "\\" if Dangerous.include?(c) + r += c.chr end - - return result.join(" ") + r += '"' + result << r + end end + + return result.join(" ") + end end diff --git a/lib/puppet/parser/functions/split.rb b/lib/puppet/parser/functions/split.rb index 09caa18aa..5d0a9dabc 100644 --- a/lib/puppet/parser/functions/split.rb +++ b/lib/puppet/parser/functions/split.rb @@ -1,17 +1,17 @@ module Puppet::Parser::Functions - newfunction( - :split, :type => :rvalue, + newfunction( + :split, :type => :rvalue, - :doc => "\ + :doc => "\ Split a string variable into an array using the specified split regexp. - Usage:: + Usage:: - $string = 'v1.v2:v3.v4' - $array_var1 = split($string, ':') - $array_var2 = split($string, '[.]') - $array_var3 = split($string, '[.:]') + $string = 'v1.v2:v3.v4' + $array_var1 = split($string, ':') + $array_var2 = split($string, '[.]') + $array_var3 = split($string, '[.:]') $array_var1 now holds the result ['v1.v2', 'v3.v4'], while $array_var2 holds ['v1', 'v2:v3', 'v4'], and @@ -22,8 +22,8 @@ a regexp meta-character (.), and that needs protection. A simple way to do that for a single character is to enclose it in square brackets.") do |args| - raise Puppet::ParseError, ("split(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2 + raise Puppet::ParseError, ("split(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2 - return args[0].split(Regexp.compile(args[1])) - end + return args[0].split(Regexp.compile(args[1])) + end end diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb index af0a7213e..5ada0fed7 100644 --- a/lib/puppet/parser/functions/sprintf.rb +++ b/lib/puppet/parser/functions/sprintf.rb @@ -1,13 +1,13 @@ module Puppet::Parser::Functions - newfunction( - :sprintf, :type => :rvalue, + newfunction( + :sprintf, :type => :rvalue, - :doc => "Perform printf-style formatting of text. + :doc => "Perform printf-style formatting of text. - The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args| - raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1 - fmt = args.shift - return sprintf(fmt, *args) - end + The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args| + raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1 + fmt = args.shift + return sprintf(fmt, *args) + end end diff --git a/lib/puppet/parser/functions/tag.rb b/lib/puppet/parser/functions/tag.rb index 3e487feaf..84df175eb 100644 --- a/lib/puppet/parser/functions/tag.rb +++ b/lib/puppet/parser/functions/tag.rb @@ -1,6 +1,6 @@ # Tag the current scope with each passed name Puppet::Parser::Functions::newfunction(:tag, :doc => "Add the specified tags to the containing class - or definition. All contained objects will then acquire that tag, also. - ") do |vals| - self.resource.tag(*vals) + or definition. All contained objects will then acquire that tag, also. + ") do |vals| + self.resource.tag(*vals) end diff --git a/lib/puppet/parser/functions/tagged.rb b/lib/puppet/parser/functions/tagged.rb index fccb13205..aaa2adfad 100644 --- a/lib/puppet/parser/functions/tagged.rb +++ b/lib/puppet/parser/functions/tagged.rb @@ -1,18 +1,18 @@ # Test whether a given tag is set. This functions as a big OR -- if any of the specified tags are unset, we return false. Puppet::Parser::Functions::newfunction(:tagged, :type => :rvalue, :doc => "A boolean function that - tells you whether the current container is tagged with the specified tags. - The tags are ANDed, so that all of the specified tags must be included for - the function to return true.") do |vals| - configtags = compiler.catalog.tags - resourcetags = resource.tags + tells you whether the current container is tagged with the specified tags. + The tags are ANDed, so that all of the specified tags must be included for + the function to return true.") do |vals| + configtags = compiler.catalog.tags + resourcetags = resource.tags - retval = true - vals.each do |val| - unless configtags.include?(val) or resourcetags.include?(val) - retval = false - break - end - end + retval = true + vals.each do |val| + unless configtags.include?(val) or resourcetags.include?(val) + retval = false + break + end + end - return retval + return retval end diff --git a/lib/puppet/parser/functions/template.rb b/lib/puppet/parser/functions/template.rb index 6c4873efe..f51bcc1e2 100644 --- a/lib/puppet/parser/functions/template.rb +++ b/lib/puppet/parser/functions/template.rb @@ -1,22 +1,22 @@ Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :doc => - "Evaluate a template and return its value. See `the templating docs - <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. - Note that if multiple templates are specified, their output is all - concatenated and returned as the output of the function.") do |vals| - require 'erb' + "Evaluate a template and return its value. See `the templating docs + <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. + Note that if multiple templates are specified, their output is all + concatenated and returned as the output of the function.") do |vals| + require 'erb' - vals.collect do |file| - # Use a wrapper, so the template can't get access to the full - # Scope object. - debug "Retrieving template #{file}" + vals.collect do |file| + # Use a wrapper, so the template can't get access to the full + # Scope object. + debug "Retrieving template #{file}" - wrapper = Puppet::Parser::TemplateWrapper.new(self) - wrapper.file = file - begin - wrapper.result - rescue => detail - raise Puppet::ParseError, - "Failed to parse template #{file}: #{detail}" - end - end.join("") + wrapper = Puppet::Parser::TemplateWrapper.new(self) + wrapper.file = file + begin + wrapper.result + rescue => detail + raise Puppet::ParseError, + "Failed to parse template #{file}: #{detail}" + end + end.join("") end diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index b8d39af96..b38406532 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -1,34 +1,34 @@ require 'puppet/util/package' - Puppet::Parser::Functions::newfunction( - :versioncmp, :type => :rvalue, + Puppet::Parser::Functions::newfunction( + :versioncmp, :type => :rvalue, - :doc => "Compares two versions + :doc => "Compares two versions Prototype:: - \$result = versioncmp(a, b) + \$result = versioncmp(a, b) - where a and b are arbitrary version strings + where a and b are arbitrary version strings This functions returns a number:: - * > 0 if version a is greater than version b - * == 0 if both version are equals - * < 0 if version a is less than version b + * > 0 if version a is greater than version b + * == 0 if both version are equals + * < 0 if version a is less than version b Example:: - if versioncmp('2.6-1', '2.4.5') > 0 { - notice('2.6-1 is > than 2.4.5') - } + if versioncmp('2.6-1', '2.4.5') > 0 { + notice('2.6-1 is > than 2.4.5') + } ") do |args| - unless args.length == 2 - raise Puppet::ParseError, "versioncmp should have 2 arguments" - end + unless args.length == 2 + raise Puppet::ParseError, "versioncmp should have 2 arguments" + end - return Puppet::Util::Package.versioncmp(args[0], args[1]) + return Puppet::Util::Package.versioncmp(args[0], args[1]) end diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 9fa8f5069..7a316d4d7 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -15,73 +15,73 @@ token MATCH NOMATCH REGEX IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB token IN prechigh - right NOT - nonassoc UMINUS - left IN MATCH NOMATCH - left TIMES DIV - left MINUS PLUS - left LSHIFT RSHIFT - left NOTEQUAL ISEQUAL - left GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL - left AND - left OR + right NOT + nonassoc UMINUS + left IN MATCH NOMATCH + left TIMES DIV + left MINUS PLUS + left LSHIFT RSHIFT + left NOTEQUAL ISEQUAL + left GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL + left AND + left OR preclow rule program: statements { - 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 + 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 = nil + end } - | nil + | nil statements: statement - | statements statement { - 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 + | statements statement { + 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: resource - | virtualresource - | collection - | assignment - | casestatement - | ifstatement_begin - | import - | fstatement - | definition - | hostclass - | nodedef - | resourceoverride - | append - | relationship + | virtualresource + | collection + | assignment + | casestatement + | ifstatement_begin + | import + | fstatement + | definition + | hostclass + | nodedef + | resourceoverride + | append + | relationship relationship: relationship_side edge relationship_side { - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) + result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) } - | relationship edge relationship_side { - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) + | relationship edge relationship_side { + result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) } relationship_side: resource | resourceref | collection @@ -89,411 +89,411 @@ relationship_side: resource | resourceref | collection edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB fstatement: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + args = aryfy(val[2]) + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => args, + :ftype => :statement } | NAME LPAREN funcvalues COMMA RPAREN { - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + args = aryfy(val[2]) + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => args, + :ftype => :statement } | NAME LPAREN RPAREN { + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => AST::ASTArray.new({}), + :ftype => :statement +} + | NAME funcvalues { + args = aryfy(val[1]) result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :statement -} - | NAME funcvalues { - args = aryfy(val[1]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + :name => val[0][:value], + :line => val[0][:line], + :arguments => args, + :ftype => :statement } funcvalues: namestring - | resourceref - | funcvalues COMMA namestring { - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file -} - | funcvalues COMMA resourceref { - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end + | resourceref + | funcvalues COMMA namestring { + result = aryfy(val[0], val[2]) + result.line = @lexer.line + result.file = @lexer.file +} + | funcvalues COMMA resourceref { + unless val[0].is_a?(AST::ASTArray) + val[0] = aryfy(val[0]) + end - val[0].push(val[2]) + val[0].push(val[2]) - result = val[0] + result = val[0] } # This is *almost* an rvalue, but I couldn't get a full # rvalue to work without scads of shift/reduce conflicts. namestring: name - | variable - | type - | boolean - | funcrvalue - | selector - | quotedtext - | hasharrayaccesses - | CLASSNAME { - result = ast AST::Name, :value => val[0][:value] - } + | variable + | type + | boolean + | funcrvalue + | selector + | quotedtext + | hasharrayaccesses + | CLASSNAME { + result = ast AST::Name, :value => val[0][:value] + } resource: classname LBRACE resourceinstances endsemi RBRACE { - @lexer.commentpop - array = val[2] - array = [array] if array.instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance) - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - - result.push ast( - AST::Resource, - :type => val[0], - :title => instance[0], - - :parameters => instance[1]) - } + @lexer.commentpop + array = val[2] + array = [array] if array.instance_of?(AST::ResourceInstance) + result = ast AST::ASTArray + + # this iterates across each specified resourceinstance + array.each { |instance| + raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance) + # now, i need to somehow differentiate between those things with + # arrays in their names, and normal things + + result.push ast( + AST::Resource, + :type => val[0], + :title => instance[0], + + :parameters => instance[1]) + } } | classname LBRACE params endcomma RBRACE { - # This is a deprecated syntax. - error "All resource specifications require names" + # This is a deprecated syntax. + error "All resource specifications require names" } | classref LBRACE params endcomma RBRACE { - # a defaults setting for a type - @lexer.commentpop - result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) + # a defaults setting for a type + @lexer.commentpop + result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) } # Override a value set elsewhere in the configuration. resourceoverride: resourceref LBRACE anyparams endcomma RBRACE { - @lexer.commentpop - result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] + @lexer.commentpop + result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] } # 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] + type = val[0] - if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect without storeconfigs being set") - end + if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect without storeconfigs being set") + end - error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults + error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults - method = type.to_s + "=" + 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.send(method, true) - end - else - val[1].send(method, true) + # Just mark our resources as exported and pass them through. + if val[1].instance_of?(AST::ASTArray) + val[1].each do |obj| + obj.send(method, true) end + else + val[1].send(method, true) + end - result = val[1] + result = val[1] } at: AT { result = :virtual } - | AT AT { result = :exported } + | AT AT { result = :exported } # A collection statement. Currently supports no arguments at all, but eventually # will, I assume. collection: classref collectrhand LBRACE anyparams endcomma RBRACE { - @lexer.commentpop - Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/ - 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] and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - args[:override] = val[3] - result = ast AST::Collection, args -} - | classref 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] and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - result = ast AST::Collection, args + @lexer.commentpop + Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/ + 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] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + args[:override] = val[3] + result = ast AST::Collection, args +} + | classref 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] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + result = ast AST::Collection, args } collectrhand: LCOLLECT collstatements RCOLLECT { - if val[1] - result = val[1] - result.form = :virtual - else - result = :virtual - end + 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 + | 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 + | 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 + | LPAREN collstatements RPAREN { + result = val[1] + result.parens = true } colljoin: AND { result=val[0][:value] } - | OR { result=val[0][:value] } + | OR { result=val[0][:value] } collexpr: colllval ISEQUAL simplervalue { + result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] + #result = ast AST::CollExpr + #result.push *val +} + | colllval NOTEQUAL simplervalue { result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val } - | colllval NOTEQUAL simplervalue { - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val -} colllval: variable - | name + | name resourceinst: resourcename COLON params endcomma { - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :children => [val[0],val[2]] } resourceinstances: resourceinst - | resourceinstances SEMIC resourceinst { - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else - val[0].push val[2] - result = val[0] - end + | resourceinstances SEMIC resourceinst { + if val[0].instance_of?(AST::ResourceInstance) + result = ast AST::ASTArray, :children => [val[0],val[2]] + else + val[0].push val[2] + result = val[0] + end } endsemi: # nothing - | SEMIC + | SEMIC undef: UNDEF { - result = ast AST::Undef, :value => :undef + result = ast AST::Undef, :value => :undef } name: NAME { - result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] } type: CLASSREF { - result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] } resourcename: quotedtext - | name - | type - | selector - | variable - | array - | hasharrayaccesses + | name + | type + | selector + | variable + | array + | hasharrayaccesses assignment: VARIABLE EQUALS expression { - raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ - # this is distinct from referencing a variable - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] + raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ + # this is distinct from referencing a variable + variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] } - | hasharrayaccess EQUALS expression { - result = ast AST::VarDef, :name => val[0], :value => val[2] + | hasharrayaccess EQUALS expression { + result = ast AST::VarDef, :name => val[0], :value => val[2] } append: VARIABLE APPENDS expression { - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] + variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] } params: # nothing { - result = ast AST::ASTArray + result = ast AST::ASTArray } - | param { result = val[0] } - | params COMMA param { - 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 + | param { result = val[0] } + | params COMMA param { + 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 } param: NAME FARROW rvalue { - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] + result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] } addparam: NAME PARROW rvalue { - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], - :add => true + result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], + :add => true } anyparam: param - | addparam + | addparam anyparams: # nothing { - result = ast AST::ASTArray + result = ast AST::ASTArray } - | anyparam { result = val[0] } - | anyparams COMMA anyparam { - 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 + | anyparam { result = val[0] } + | anyparams COMMA anyparam { + 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 } rvalues: rvalue - | rvalues comma rvalue { - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + | rvalues comma rvalue { + if val[0].instance_of?(AST::ASTArray) + result = val[0].push(val[2]) + else + result = ast AST::ASTArray, :children => [val[0],val[2]] + end } simplervalue: quotedtext - | name - | type - | boolean - | selector - | variable + | name + | type + | boolean + | selector + | variable rvalue: quotedtext - | name - | type - | boolean - | selector - | variable - | array - | hash - | hasharrayaccesses - | resourceref - | funcrvalue - | undef + | name + | type + | boolean + | selector + | variable + | array + | hash + | hasharrayaccesses + | resourceref + | funcrvalue + | undef # We currently require arguments in these functions. funcrvalue: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => args, - :ftype => :rvalue + args = aryfy(val[2]) + result = ast AST::Function, + :name => val[0][:value], :line => val[0][:line], + :arguments => args, + :ftype => :rvalue } | NAME LPAREN RPAREN { - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :rvalue + result = ast AST::Function, + :name => val[0][:value], :line => val[0][:line], + :arguments => AST::ASTArray.new({}), + :ftype => :rvalue } quotedtext: STRING { result = ast AST::String, :value => val[0][:value], :line => val[0][:line] } - | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] } + | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] } dqrval: expression dqtail { result = [val[0]] + val[1] } dqtail: DQPOST { result = [ast(AST::String,val[0])] } - | DQMID dqrval { result = [ast(AST::String,val[0])] + val[1] } + | DQMID dqrval { result = [ast(AST::String,val[0])] + val[1] } boolean: BOOLEAN { - result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] } resourceref: NAME LBRACK rvalues RBRACK { - Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] + Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") + result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] } | classref LBRACK rvalues RBRACK { - result = ast AST::ResourceReference, :type => val[0], :title => val[2] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] } ifstatement_begin: IF ifstatement { - result = val[1] + result = val[1] } ifstatement: expression LBRACE statements RBRACE else { - @lexer.commentpop - args = { - :test => val[0], - :statements => val[2] - } + @lexer.commentpop + args = { + :test => val[0], + :statements => val[2] + } - args[:else] = val[4] if val[4] + args[:else] = val[4] if val[4] - result = ast AST::IfStatement, args + result = ast AST::IfStatement, args } - | expression LBRACE RBRACE else { - @lexer.commentpop - args = { - :test => val[0], - :statements => ast(AST::Nop) - } + | expression LBRACE RBRACE else { + @lexer.commentpop + args = { + :test => val[0], + :statements => ast(AST::Nop) + } - args[:else] = val[3] if val[3] + args[:else] = val[3] if val[3] - result = ast AST::IfStatement, args + result = ast AST::IfStatement, args } else: # nothing - | ELSIF ifstatement { - result = ast AST::Else, :statements => val[1] + | ELSIF ifstatement { + result = ast AST::Else, :statements => val[1] } - | ELSE LBRACE statements RBRACE { - @lexer.commentpop - result = ast AST::Else, :statements => val[2] + | ELSE LBRACE statements RBRACE { + @lexer.commentpop + result = ast AST::Else, :statements => val[2] } - | ELSE LBRACE RBRACE { - @lexer.commentpop - result = ast AST::Else, :statements => ast(AST::Nop) + | ELSE LBRACE RBRACE { + @lexer.commentpop + result = ast AST::Else, :statements => ast(AST::Nop) } # Unlike yacc/bison, it seems racc @@ -509,343 +509,343 @@ else: # nothing # per operator :-( expression: rvalue - | expression IN rvalue { - result = ast AST::InOperator, :lval => val[0], :rval => val[2] + | expression IN rvalue { + result = ast AST::InOperator, :lval => val[0], :rval => val[2] } - | expression MATCH regex { - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression MATCH regex { + result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression NOMATCH regex { - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression NOMATCH regex { + result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression PLUS expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression PLUS expression { + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression MINUS expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression MINUS expression { + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression DIV expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression DIV expression { + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression TIMES expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression TIMES expression { + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression LSHIFT expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression LSHIFT expression { + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression RSHIFT expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression RSHIFT expression { + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | MINUS expression =UMINUS { - result = ast AST::Minus, :value => val[1] + | MINUS expression =UMINUS { + result = ast AST::Minus, :value => val[1] } - | expression NOTEQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression NOTEQUAL expression { + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression ISEQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression ISEQUAL expression { + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression GREATERTHAN expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression GREATERTHAN expression { + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression GREATEREQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression GREATEREQUAL expression { + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression LESSTHAN expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression LESSTHAN expression { + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression LESSEQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression LESSEQUAL expression { + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | NOT expression { - result = ast AST::Not, :value => val[1] + | NOT expression { + result = ast AST::Not, :value => val[1] } - | expression AND expression { - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression AND expression { + result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | expression OR expression { - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + | expression OR expression { + result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } - | LPAREN expression RPAREN { - result = val[1] + | LPAREN expression RPAREN { + result = val[1] } casestatement: CASE rvalue LBRACE caseopts RBRACE { - @lexer.commentpop - options = val[3] - options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray) - result = ast AST::CaseStatement, :test => val[1], :options => options + @lexer.commentpop + options = val[3] + options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray) + result = ast AST::CaseStatement, :test => val[1], :options => options } caseopts: caseopt - | caseopts caseopt { - 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 + | caseopts caseopt { + 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 } caseopt: casevalues COLON LBRACE statements RBRACE { - @lexer.commentpop - result = ast AST::CaseOpt, :value => val[0], :statements => val[3] + @lexer.commentpop + result = ast AST::CaseOpt, :value => val[0], :statements => val[3] } | casevalues COLON LBRACE RBRACE { - @lexer.commentpop + @lexer.commentpop - result = ast( - AST::CaseOpt, - :value => val[0], + result = ast( + AST::CaseOpt, + :value => val[0], - :statements => ast(AST::ASTArray) - ) + :statements => ast(AST::ASTArray) + ) } casevalues: selectlhand - | casevalues COMMA selectlhand { - 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 + | casevalues COMMA selectlhand { + 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 } selector: selectlhand QMARK svalues { - result = ast AST::Selector, :param => val[0], :values => val[2] + result = ast AST::Selector, :param => val[0], :values => val[2] } svalues: selectval - | LBRACE sintvalues endcomma RBRACE { - @lexer.commentpop - result = val[1] + | LBRACE sintvalues endcomma RBRACE { + @lexer.commentpop + result = val[1] } sintvalues: selectval - | sintvalues comma selectval { - 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 + | sintvalues comma selectval { + 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 } selectval: selectlhand FARROW rvalue { - result = ast AST::ResourceParam, :param => val[0], :value => val[2] + result = ast AST::ResourceParam, :param => val[0], :value => val[2] } selectlhand: name - | type - | quotedtext - | variable - | funcrvalue - | boolean - | undef - | DEFAULT { - result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] + | type + | quotedtext + | variable + | funcrvalue + | boolean + | undef + | DEFAULT { + result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] } - | regex + | regex # These are only used for importing, and we don't interpolate there. string: STRING { result = [val[0][:value]] } strings: string - | strings COMMA string { result = val[0] += val[2] } + | strings COMMA string { result = val[0] += val[2] } import: IMPORT strings { - val[1].each do |file| - import(file) - end + val[1].each do |file| + import(file) + end - result = AST::ASTArray.new(:children => []) + result = AST::ASTArray.new(:children => []) } # Disable definition inheritance for now. 8/27/06, luke #definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE { definition: DEFINE classname argumentlist LBRACE statements RBRACE { - @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line] - @lexer.indefine = false - result = nil + @lexer.commentpop + newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line] + @lexer.indefine = false + result = nil #} | DEFINE NAME argumentlist parent LBRACE RBRACE { } | DEFINE classname argumentlist LBRACE RBRACE { - @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line] - @lexer.indefine = false - result = nil + @lexer.commentpop + newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line] + @lexer.indefine = false + result = nil } #hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE { hostclass: CLASS classname argumentlist classparent LBRACE statements RBRACE { - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line] - result = nil + @lexer.commentpop + # Our class gets defined in the parent namespace, not our own. + @lexer.namepop + newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line] + result = nil } | CLASS classname argumentlist classparent LBRACE RBRACE { - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line] - result = nil + @lexer.commentpop + # Our class gets defined in the parent namespace, not our own. + @lexer.namepop + newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line] + result = nil } nodedef: NODE hostnames nodeparent LBRACE statements RBRACE { - @lexer.commentpop - newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line] - result = nil + @lexer.commentpop + newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line] + result = nil } | NODE hostnames nodeparent LBRACE RBRACE { - @lexer.commentpop - newnode val[1], :parent => val[2], :line => val[0][:line] - result = nil + @lexer.commentpop + newnode val[1], :parent => val[2], :line => val[0][:line] + result = nil } classref: CLASSREF { result = val[0][:value] } classname: NAME { result = val[0][:value] } - | CLASSNAME { result = val[0][:value] } - | CLASS { result = "class" } + | CLASSNAME { result = val[0][:value] } + | CLASS { result = "class" } # Multiple hostnames, as used for node names. These are all literal # strings, not AST objects. hostnames: nodename - | hostnames COMMA nodename { - result = val[0] - result = [result] unless result.is_a?(Array) - result << val[2] + | hostnames COMMA nodename { + result = val[0] + result = [result] unless result.is_a?(Array) + result << val[2] } nodename: hostname { - result = ast AST::HostName, :value => val[0] + result = ast AST::HostName, :value => val[0] } hostname: NAME { result = val[0][:value] } - | STRING { result = val[0][:value] } - | DEFAULT { result = val[0][:value] } - | regex + | STRING { result = val[0][:value] } + | DEFAULT { result = val[0][:value] } + | regex nil: { - result = nil + result = nil } nothing: { - result = ast AST::ASTArray, :children => [] + result = ast AST::ASTArray, :children => [] } argumentlist: nil - | LPAREN nothing RPAREN { - result = nil + | LPAREN nothing RPAREN { + result = nil } - | LPAREN arguments RPAREN { - result = val[1] - result = [result] unless result[0].is_a?(Array) + | LPAREN arguments RPAREN { + result = val[1] + result = [result] unless result[0].is_a?(Array) } arguments: argument - | arguments COMMA argument { - result = val[0] - result = [result] unless result[0].is_a?(Array) - result << val[2] + | arguments COMMA argument { + result = val[0] + result = [result] unless result[0].is_a?(Array) + result << val[2] } argument: NAME EQUALS rvalue { - Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") - result = [val[0][:value], val[2]] + Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") + result = [val[0][:value], val[2]] } - | NAME { - Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") - result = [val[0][:value]] + | NAME { + Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") + result = [val[0][:value]] } | VARIABLE EQUALS rvalue { - result = [val[0][:value], val[2]] + result = [val[0][:value], val[2]] } | VARIABLE { - result = [val[0][:value]] + result = [val[0][:value]] } nodeparent: nil - | INHERITS hostname { - result = val[1] + | INHERITS hostname { + result = val[1] } classparent: nil - | INHERITS classnameordefault { - result = val[1] + | INHERITS classnameordefault { + result = val[1] } classnameordefault: classname | DEFAULT variable: VARIABLE { - result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] } array: LBRACK rvalues RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end + if val[1].instance_of?(AST::ASTArray) + result = val[1] + else + result = ast AST::ASTArray, :children => [val[1]] + end } - | LBRACK rvalues COMMA RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end + | LBRACK rvalues COMMA RBRACK { + if val[1].instance_of?(AST::ASTArray) + result = val[1] + else + result = ast AST::ASTArray, :children => [val[1]] + end } | LBRACK RBRACK { - result = ast AST::ASTArray + result = ast AST::ASTArray } comma: FARROW - | COMMA + | COMMA endcomma: # nothing - | COMMA { result = nil } + | COMMA { result = nil } regex: REGEX { - result = ast AST::Regex, :value => val[0][:value] + result = ast AST::Regex, :value => val[0][:value] } hash: LBRACE hashpairs RBRACE { - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end + if val[1].instance_of?(AST::ASTHash) + result = val[1] + else + result = ast AST::ASTHash, { :value => val[1] } + end } - | LBRACE hashpairs COMMA RBRACE { - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end + | LBRACE hashpairs COMMA RBRACE { + if val[1].instance_of?(AST::ASTHash) + result = val[1] + else + result = ast AST::ASTHash, { :value => val[1] } + end } | LBRACE RBRACE { - result = ast AST::ASTHash + result = ast AST::ASTHash } hashpairs: hashpair - | hashpairs COMMA hashpair { - if val[0].instance_of?(AST::ASTHash) - result = val[0].merge(val[2]) - else - result = ast AST::ASTHash, :value => val[0] - result.merge(val[2]) - end + | hashpairs COMMA hashpair { + if val[0].instance_of?(AST::ASTHash) + result = val[0].merge(val[2]) + else + result = ast AST::ASTHash, :value => val[0] + result.merge(val[2]) + end } hashpair: key FARROW rvalue { - result = ast AST::ASTHash, { :value => { val[0] => val[2] } } + result = ast AST::ASTHash, { :value => { val[0] => val[2] } } } key: NAME { result = val[0][:value] } - | quotedtext { result = val[0] } + | quotedtext { result = val[0] } hasharrayaccess: VARIABLE LBRACK rvalue RBRACK { - result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] + result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] } hasharrayaccesses: hasharrayaccess - | hasharrayaccess LBRACK rvalue RBRACK { - result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] + | hasharrayaccess LBRACK rvalue RBRACK { + result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] } end @@ -856,9 +856,9 @@ require 'puppet/parser/lexer' require 'puppet/parser/ast' module Puppet - class ParseError < Puppet::Error; end - class ImportError < Racc::ParseError; end - class AlreadyImportedError < ImportError; end + class ParseError < Puppet::Error; end + class ImportError < Racc::ParseError; end + class AlreadyImportedError < ImportError; end end ---- inner ---- diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 0c95142f9..6a9f1cfc4 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -5,573 +5,573 @@ require 'puppet' module Puppet - class LexError < RuntimeError; end + class LexError < RuntimeError; end end module Puppet::Parser; end class Puppet::Parser::Lexer - attr_reader :last, :file, :lexing_context, :token_queue + attr_reader :last, :file, :lexing_context, :token_queue - attr_accessor :line, :indefine + attr_accessor :line, :indefine - def lex_error msg - raise Puppet::LexError.new(msg) - end - - class Token - attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate - - def initialize(regex, name) - if regex.is_a?(String) - @name, @string = name, regex - @regex = Regexp.new(Regexp.escape(@string)) - else - @name, @regex = name, regex - end - end - - # MQR: Why not just alias? - %w{skip accumulate}.each do |method| - define_method(method+"?") do - self.send(method) - end - end - - def to_s - if self.string - @string - else - @name.to_s - end - end - - def acceptable?(context={}) - # By default tokens are aceeptable in any context - true - end - end - - # Maintain a list of tokens. - class TokenList - attr_reader :regex_tokens, :string_tokens - - def [](name) - @tokens[name] - end - - # Create a new token. - def add_token(name, regex, options = {}, &block) - token = Token.new(regex, name) - raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name) - @tokens[token.name] = token - if token.string - @string_tokens << token - @tokens_by_string[token.string] = token - else - @regex_tokens << token - end - - options.each do |name, option| - token.send(name.to_s + "=", option) - end - - token.meta_def(:convert, &block) if block_given? - - token - end - - def initialize - @tokens = {} - @regex_tokens = [] - @string_tokens = [] - @tokens_by_string = {} - end - - # Look up a token by its value, rather than name. - def lookup(string) - @tokens_by_string[string] - end - - # Define more tokens. - def add_tokens(hash) - hash.each do |regex, name| - add_token(name, regex) - end - end - - # Sort our tokens by length, so we know once we match, we're done. - # This helps us avoid the O(n^2) nature of token matching. - def sort_tokens - @string_tokens.sort! { |a, b| b.string.length <=> a.string.length } - end - end + def lex_error msg + raise Puppet::LexError.new(msg) + end - TOKENS = TokenList.new - - TOKENS.add_tokens( - - '[' => :LBRACK, - ']' => :RBRACK, - '{' => :LBRACE, - '}' => :RBRACE, - '(' => :LPAREN, - - ')' => :RPAREN, - '=' => :EQUALS, - '+=' => :APPENDS, - '==' => :ISEQUAL, - '>=' => :GREATEREQUAL, - '>' => :GREATERTHAN, - '<' => :LESSTHAN, - '<=' => :LESSEQUAL, - '!=' => :NOTEQUAL, - '!' => :NOT, - ',' => :COMMA, - '.' => :DOT, - ':' => :COLON, - '@' => :AT, - '<<|' => :LLCOLLECT, - '->' => :IN_EDGE, - '<-' => :OUT_EDGE, - '~>' => :IN_EDGE_SUB, - '<~' => :OUT_EDGE_SUB, - '|>>' => :RRCOLLECT, - '<|' => :LCOLLECT, - '|>' => :RCOLLECT, - ';' => :SEMIC, - '?' => :QMARK, - '\\' => :BACKSLASH, - '=>' => :FARROW, - '+>' => :PARROW, - '+' => :PLUS, - '-' => :MINUS, - '/' => :DIV, - '*' => :TIMES, - '<<' => :LSHIFT, - '>>' => :RSHIFT, - '=~' => :MATCH, - '!~' => :NOMATCH, - %r{([a-z][-\w]*)?(::[a-z][-\w]*)+} => :CLASSNAME, # Require '::' in the class name, else we'd compete with NAME - %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF, - "<string>" => :STRING, - "<dqstring up to first interpolation>" => :DQPRE, - "<dqstring between two interpolations>" => :DQMID, - "<dqstring after final interpolation>" => :DQPOST, - "<boolean>" => :BOOLEAN - ) - - TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value| - [TOKENS[:NAME], value] - end - #:stopdoc: # Issue #4161 - def (TOKENS[:NUMBER]).acceptable?(context={}) - ![:DQPRE,:DQMID].include? context[:after] - end - #:startdoc: + class Token + attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate - TOKENS.add_token :NAME, %r{[a-z0-9][-\w]*} do |lexer, value| - string_token = self - # we're looking for keywords here - if tmp = KEYWORDS.lookup(value) - string_token = tmp - if [:TRUE, :FALSE].include?(string_token.name) - value = eval(value) - string_token = TOKENS[:BOOLEAN] - end - end - [string_token, value] + def initialize(regex, name) + if regex.is_a?(String) + @name, @string = name, regex + @regex = Regexp.new(Regexp.escape(@string)) + else + @name, @regex = name, regex + end end - [:NAME,:CLASSNAME,:CLASSREF].each { |name_token| - #:stopdoc: # Issue #4161 - def (TOKENS[name_token]).acceptable?(context={}) - ![:DQPRE,:DQMID].include? context[:after] - end - #:startdoc: - } - TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value| - value.sub!(/# ?/,'') - [self, value] + # MQR: Why not just alias? + %w{skip accumulate}.each do |method| + define_method(method+"?") do + self.send(method) + end end - TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip => true do |lexer, value| - lexer.line += value.count("\n") - value.sub!(/^\/\* ?/,'') - value.sub!(/ ?\*\/$/,'') - [self,value] + def to_s + if self.string + @string + else + @name.to_s + end end - TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value| - # Make sure we haven't matched an escaped / - while value[-2..-2] == '\\' - other = lexer.scan_until(%r{/}) - value += other - end - regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/") - [self, Regexp.new(regex)] - end - - #:stopdoc: # Issue #4161 - def (TOKENS[:REGEX]).acceptable?(context={}) - [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA].include? context[:after] + def acceptable?(context={}) + # By default tokens are aceeptable in any context + true end - #:startdoc: + end - TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true + # Maintain a list of tokens. + class TokenList + attr_reader :regex_tokens, :string_tokens - TOKENS.add_token :SQUOTE, "'" do |lexer, value| - [TOKENS[:STRING], lexer.slurpstring(value).first ] + def [](name) + @tokens[name] end - DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING} - DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST} + # Create a new token. + def add_token(name, regex, options = {}, &block) + token = Token.new(regex, name) + raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name) + @tokens[token.name] = token + if token.string + @string_tokens << token + @tokens_by_string[token.string] = token + else + @regex_tokens << token + end - TOKENS.add_token :DQUOTE, /"/ do |lexer, value| - lexer.tokenize_interpolated_string(DQ_initial_token_types) - end + options.each do |name, option| + token.send(name.to_s + "=", option) + end - TOKENS.add_token :DQCONT, /\}/ do |lexer, value| - lexer.tokenize_interpolated_string(DQ_continuation_token_types) - end - #:stopdoc: # Issue #4161 - def (TOKENS[:DQCONT]).acceptable?(context={}) - context[:string_interpolation_depth] > 0 - end - #:startdoc: + token.meta_def(:convert, &block) if block_given? - TOKENS.add_token :DOLLAR_VAR, %r{\$(\w*::)*\w+} do |lexer, value| - [TOKENS[:VARIABLE],value[1..-1]] + token end - TOKENS.add_token :VARIABLE, %r{(\w*::)*\w+} + def initialize + @tokens = {} + @regex_tokens = [] + @string_tokens = [] + @tokens_by_string = {} + end + + # Look up a token by its value, rather than name. + def lookup(string) + @tokens_by_string[string] + end + + # Define more tokens. + def add_tokens(hash) + hash.each do |regex, name| + add_token(name, regex) + end + end + + # Sort our tokens by length, so we know once we match, we're done. + # This helps us avoid the O(n^2) nature of token matching. + def sort_tokens + @string_tokens.sort! { |a, b| b.string.length <=> a.string.length } + end + end + + TOKENS = TokenList.new + + TOKENS.add_tokens( + + '[' => :LBRACK, + ']' => :RBRACK, + '{' => :LBRACE, + '}' => :RBRACE, + '(' => :LPAREN, + + ')' => :RPAREN, + '=' => :EQUALS, + '+=' => :APPENDS, + '==' => :ISEQUAL, + '>=' => :GREATEREQUAL, + '>' => :GREATERTHAN, + '<' => :LESSTHAN, + '<=' => :LESSEQUAL, + '!=' => :NOTEQUAL, + '!' => :NOT, + ',' => :COMMA, + '.' => :DOT, + ':' => :COLON, + '@' => :AT, + '<<|' => :LLCOLLECT, + '->' => :IN_EDGE, + '<-' => :OUT_EDGE, + '~>' => :IN_EDGE_SUB, + '<~' => :OUT_EDGE_SUB, + '|>>' => :RRCOLLECT, + '<|' => :LCOLLECT, + '|>' => :RCOLLECT, + ';' => :SEMIC, + '?' => :QMARK, + '\\' => :BACKSLASH, + '=>' => :FARROW, + '+>' => :PARROW, + '+' => :PLUS, + '-' => :MINUS, + '/' => :DIV, + '*' => :TIMES, + '<<' => :LSHIFT, + '>>' => :RSHIFT, + '=~' => :MATCH, + '!~' => :NOMATCH, + %r{([a-z][-\w]*)?(::[a-z][-\w]*)+} => :CLASSNAME, # Require '::' in the class name, else we'd compete with NAME + %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF, + "<string>" => :STRING, + "<dqstring up to first interpolation>" => :DQPRE, + "<dqstring between two interpolations>" => :DQMID, + "<dqstring after final interpolation>" => :DQPOST, + "<boolean>" => :BOOLEAN + ) + + TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value| + [TOKENS[:NAME], value] + end + #:stopdoc: # Issue #4161 + def (TOKENS[:NUMBER]).acceptable?(context={}) + ![:DQPRE,:DQMID].include? context[:after] + end + #:startdoc: + + TOKENS.add_token :NAME, %r{[a-z0-9][-\w]*} do |lexer, value| + string_token = self + # we're looking for keywords here + if tmp = KEYWORDS.lookup(value) + string_token = tmp + if [:TRUE, :FALSE].include?(string_token.name) + value = eval(value) + string_token = TOKENS[:BOOLEAN] + end + end + [string_token, value] + end + [:NAME,:CLASSNAME,:CLASSREF].each { |name_token| #:stopdoc: # Issue #4161 - def (TOKENS[:VARIABLE]).acceptable?(context={}) - [:DQPRE,:DQMID].include? context[:after] + def (TOKENS[name_token]).acceptable?(context={}) + ![:DQPRE,:DQMID].include? context[:after] end #:startdoc: - - - TOKENS.sort_tokens - - @@pairs = { - "{" => "}", - "(" => ")", - "[" => "]", - "<|" => "|>", - "<<|" => "|>>" + } + + TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value| + value.sub!(/# ?/,'') + [self, value] + end + + TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip => true do |lexer, value| + lexer.line += value.count("\n") + value.sub!(/^\/\* ?/,'') + value.sub!(/ ?\*\/$/,'') + [self,value] + end + + TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value| + # Make sure we haven't matched an escaped / + while value[-2..-2] == '\\' + other = lexer.scan_until(%r{/}) + value += other + end + regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/") + [self, Regexp.new(regex)] + end + + #:stopdoc: # Issue #4161 + def (TOKENS[:REGEX]).acceptable?(context={}) + [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA].include? context[:after] + end + #:startdoc: + + TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true + + TOKENS.add_token :SQUOTE, "'" do |lexer, value| + [TOKENS[:STRING], lexer.slurpstring(value).first ] + end + + DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING} + DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST} + + TOKENS.add_token :DQUOTE, /"/ do |lexer, value| + lexer.tokenize_interpolated_string(DQ_initial_token_types) + end + + TOKENS.add_token :DQCONT, /\}/ do |lexer, value| + lexer.tokenize_interpolated_string(DQ_continuation_token_types) + end + #:stopdoc: # Issue #4161 + def (TOKENS[:DQCONT]).acceptable?(context={}) + context[:string_interpolation_depth] > 0 + end + #:startdoc: + + TOKENS.add_token :DOLLAR_VAR, %r{\$(\w*::)*\w+} do |lexer, value| + [TOKENS[:VARIABLE],value[1..-1]] + end + + TOKENS.add_token :VARIABLE, %r{(\w*::)*\w+} + #:stopdoc: # Issue #4161 + def (TOKENS[:VARIABLE]).acceptable?(context={}) + [:DQPRE,:DQMID].include? context[:after] + end + #:startdoc: + + + TOKENS.sort_tokens + + @@pairs = { + "{" => "}", + "(" => ")", + "[" => "]", + "<|" => "|>", + "<<|" => "|>>" + } + + KEYWORDS = TokenList.new + + + KEYWORDS.add_tokens( + + "case" => :CASE, + "class" => :CLASS, + "default" => :DEFAULT, + "define" => :DEFINE, + "import" => :IMPORT, + "if" => :IF, + "elsif" => :ELSIF, + "else" => :ELSE, + "inherits" => :INHERITS, + "node" => :NODE, + "and" => :AND, + "or" => :OR, + "undef" => :UNDEF, + "false" => :FALSE, + "true" => :TRUE, + + "in" => :IN + ) + + def clear + initvars + end + + def expected + return nil if @expected.empty? + name = @expected[-1] + TOKENS.lookup(name) or lex_error "Could not find expected token #{name}" + end + + # scan the whole file + # basically just used for testing + def fullscan + array = [] + + self.scan { |token, str| + # Ignore any definition nesting problems + @indefine = false + array.push([token,str]) } - - KEYWORDS = TokenList.new - - - KEYWORDS.add_tokens( - - "case" => :CASE, - "class" => :CLASS, - "default" => :DEFAULT, - "define" => :DEFINE, - "import" => :IMPORT, - "if" => :IF, - "elsif" => :ELSIF, - "else" => :ELSE, - "inherits" => :INHERITS, - "node" => :NODE, - "and" => :AND, - "or" => :OR, - "undef" => :UNDEF, - "false" => :FALSE, - "true" => :TRUE, - - "in" => :IN - ) - - def clear - initvars - end - - def expected - return nil if @expected.empty? - name = @expected[-1] - TOKENS.lookup(name) or lex_error "Could not find expected token #{name}" - end - - # scan the whole file - # basically just used for testing - def fullscan - array = [] - - self.scan { |token, str| - # Ignore any definition nesting problems - @indefine = false - array.push([token,str]) - } - array - end - - def file=(file) - @file = file - @line = 1 - @scanner = StringScanner.new(File.read(file)) - end - - def shift_token - @token_queue.shift - end - - def find_string_token - # We know our longest string token is three chars, so try each size in turn - # until we either match or run out of chars. This way our worst-case is three - # tries, where it is otherwise the number of string token we have. Also, - # the lookups are optimized hash lookups, instead of regex scans. - # - s = @scanner.peek(3) - token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1]) - [ token, token && @scanner.scan(token.regex) ] - end - - # Find the next token that matches a regex. We look for these first. - def find_regex_token - @regex += 1 - best_token = nil - best_length = 0 - - # I tried optimizing based on the first char, but it had - # a slightly negative affect and was a good bit more complicated. - TOKENS.regex_tokens.each do |token| - if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context) - # We've found a longer match - if length > best_length - best_length = length - best_token = token - end - end + array + end + + def file=(file) + @file = file + @line = 1 + @scanner = StringScanner.new(File.read(file)) + end + + def shift_token + @token_queue.shift + end + + def find_string_token + # We know our longest string token is three chars, so try each size in turn + # until we either match or run out of chars. This way our worst-case is three + # tries, where it is otherwise the number of string token we have. Also, + # the lookups are optimized hash lookups, instead of regex scans. + # + s = @scanner.peek(3) + token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1]) + [ token, token && @scanner.scan(token.regex) ] + end + + # Find the next token that matches a regex. We look for these first. + def find_regex_token + @regex += 1 + best_token = nil + best_length = 0 + + # I tried optimizing based on the first char, but it had + # a slightly negative affect and was a good bit more complicated. + TOKENS.regex_tokens.each do |token| + if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context) + # We've found a longer match + if length > best_length + best_length = length + best_token = token end + end + end - return best_token, @scanner.scan(best_token.regex) if best_token - end - - # Find the next token, returning the string and the token. - def find_token - @find += 1 - shift_token || find_regex_token || find_string_token - end + return best_token, @scanner.scan(best_token.regex) if best_token + end - def indefine? - if defined?(@indefine) - @indefine - else - false - end - end + # Find the next token, returning the string and the token. + def find_token + @find += 1 + shift_token || find_regex_token || find_string_token + end - def initialize - @find = 0 - @regex = 0 - initvars + def indefine? + if defined?(@indefine) + @indefine + else + false end + end - def initvars - @line = 1 - @previous_token = nil - @scanner = nil - @file = nil - # AAARRGGGG! okay, regexes in ruby are bloody annoying - # no one else has "\n" =~ /\s/ - @skip = %r{[ \t\r]+} - - @namestack = [] - @token_queue = [] - @indefine = false - @expected = [] - @commentstack = [ ['', @line] ] - @lexing_context = { - :after => nil, - :start_of_line => true, - :string_interpolation_depth => 0 - } - end + def initialize + @find = 0 + @regex = 0 + initvars + end - # Make any necessary changes to the token and/or value. - def munge_token(token, value) - @line += 1 if token.incr_line + def initvars + @line = 1 + @previous_token = nil + @scanner = nil + @file = nil + # AAARRGGGG! okay, regexes in ruby are bloody annoying + # no one else has "\n" =~ /\s/ + @skip = %r{[ \t\r]+} - skip if token.skip_text + @namestack = [] + @token_queue = [] + @indefine = false + @expected = [] + @commentstack = [ ['', @line] ] + @lexing_context = { + :after => nil, + :start_of_line => true, + :string_interpolation_depth => 0 + } + end - return if token.skip and not token.accumulate? + # Make any necessary changes to the token and/or value. + def munge_token(token, value) + @line += 1 if token.incr_line - token, value = token.convert(self, value) if token.respond_to?(:convert) + skip if token.skip_text - return unless token + return if token.skip and not token.accumulate? - if token.accumulate? - comment = @commentstack.pop - comment[0] << value + "\n" - @commentstack.push(comment) - end + token, value = token.convert(self, value) if token.respond_to?(:convert) - return if token.skip + return unless token - return token, { :value => value, :line => @line } + if token.accumulate? + comment = @commentstack.pop + comment[0] << value + "\n" + @commentstack.push(comment) end - # Go up one in the namespace. - def namepop - @namestack.pop - end + return if token.skip - # Collect the current namespace. - def namespace - @namestack.join("::") - end + return token, { :value => value, :line => @line } + 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 - @scanner.rest - end - - # this is the heart of the lexer - def scan - #Puppet.debug("entering scan") - lex_error "Invalid or empty string" unless @scanner - - # Skip any initial whitespace. - skip + # Go up one in the namespace. + def namepop + @namestack.pop + end - until token_queue.empty? and @scanner.eos? do - yielded = false - matched_token, value = find_token + # Collect the current namespace. + def namespace + @namestack.join("::") + end - # error out if we didn't match anything at all - lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token + # 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 - newline = matched_token.name == :RETURN + def rest + @scanner.rest + end - # this matches a blank line; eat the previously accumulated comments - getcomment if lexing_context[:start_of_line] and newline - lexing_context[:start_of_line] = newline + # this is the heart of the lexer + def scan + #Puppet.debug("entering scan") + lex_error "Invalid or empty string" unless @scanner - final_token, token_value = munge_token(matched_token, value) + # Skip any initial whitespace. + skip - unless final_token - skip - next - end + until token_queue.empty? and @scanner.eos? do + yielded = false + matched_token, value = find_token - lexing_context[:after] = final_token.name unless newline - lexing_context[:string_interpolation_depth] += 1 if final_token.name == :DQPRE - lexing_context[:string_interpolation_depth] -= 1 if final_token.name == :DQPOST + # error out if we didn't match anything at all + lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token - value = token_value[:value] + newline = matched_token.name == :RETURN + + # this matches a blank line; eat the previously accumulated comments + getcomment if lexing_context[:start_of_line] and newline + lexing_context[:start_of_line] = newline - if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE - @expected << match - elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE - @expected.pop - end + final_token, token_value = munge_token(matched_token, value) - if final_token.name == :LBRACE - commentpush - end - - yield [final_token.name, token_value] + unless final_token + skip + next + end - if @previous_token - namestack(value) if @previous_token.name == :CLASS + lexing_context[:after] = final_token.name unless newline + lexing_context[:string_interpolation_depth] += 1 if final_token.name == :DQPRE + lexing_context[:string_interpolation_depth] -= 1 if final_token.name == :DQPOST - if @previous_token.name == :DEFINE - if indefine? - msg = "Cannot nest definition #{value} inside #{@indefine}" - self.indefine = false - raise Puppet::ParseError, msg - end + value = token_value[:value] - @indefine = value - end - end - @previous_token = final_token - skip - end - @scanner = nil + if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE + @expected << match + elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE + @expected.pop + end - # This indicates that we're done parsing. - yield [false,false] - end + if final_token.name == :LBRACE + commentpush + end - # Skip any skipchars in our remaining string. - def skip - @scanner.skip(@skip) - end + yield [final_token.name, token_value] - # Provide some limited access to the scanner, for those - # tokens that need it. - def scan_until(regex) - @scanner.scan_until(regex) - end + if @previous_token + namestack(value) if @previous_token.name == :CLASS - # we've encountered the start of a string... - # slurp in the rest of the string and return it - Valid_escapes_in_strings = %w{ \\ $ ' " n t s }+["\n"] - def slurpstring(terminators) - # we search for the next quote that isn't preceded by a - # backslash; the caret is there to match empty strings - str = @scanner.scan_until(/([^\\]|^)[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" - @line += str.count("\n") # literal carriage returns add to the line count. - str.gsub!(/\\(.)/) { - case ch=$1 - when 'n'; "\n" - when 't'; "\t" - when 's'; " " - else - if Valid_escapes_in_strings.include? ch and not (ch == '"' and terminators == "'") - ch - else - Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" - "\\#{ch}" - end - end - } - [ str[0..-2],str[-1,1] ] - end + if @previous_token.name == :DEFINE + if indefine? + msg = "Cannot nest definition #{value} inside #{@indefine}" + self.indefine = false + raise Puppet::ParseError, msg + end - def tokenize_interpolated_string(token_type) - value,terminator = slurpstring('"$') - token_queue << [TOKENS[token_type[terminator]],value] - while terminator == '$' and not @scanner.scan(/\{/) - token_queue << [TOKENS[:VARIABLE],@scanner.scan(%r{(\w*::)*\w+|[0-9]})] - value,terminator = slurpstring('"$') - token_queue << [TOKENS[DQ_continuation_token_types[terminator]],value] + @indefine = value end - token_queue.shift - end - - # just parse a string, not a whole file - def string=(string) - @scanner = StringScanner.new(string) - end - - # returns the content of the currently accumulated content cache - def commentpop - @commentstack.pop[0] - end - - def getcomment(line = nil) - comment = @commentstack.last - if line.nil? or comment[1] <= line - @commentstack.pop - @commentstack.push(['', @line]) - return comment[0] + end + @previous_token = final_token + skip + end + @scanner = nil + + # This indicates that we're done parsing. + yield [false,false] + end + + # Skip any skipchars in our remaining string. + def skip + @scanner.skip(@skip) + end + + # Provide some limited access to the scanner, for those + # tokens that need it. + def scan_until(regex) + @scanner.scan_until(regex) + end + + # we've encountered the start of a string... + # slurp in the rest of the string and return it + Valid_escapes_in_strings = %w{ \\ $ ' " n t s }+["\n"] + def slurpstring(terminators) + # we search for the next quote that isn't preceded by a + # backslash; the caret is there to match empty strings + str = @scanner.scan_until(/([^\\]|^)[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" + @line += str.count("\n") # literal carriage returns add to the line count. + str.gsub!(/\\(.)/) { + case ch=$1 + when 'n'; "\n" + when 't'; "\t" + when 's'; " " + else + if Valid_escapes_in_strings.include? ch and not (ch == '"' and terminators == "'") + ch + else + Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" + "\\#{ch}" end - '' - end - - def commentpush - @commentstack.push(['', @line]) - end + end + } + [ str[0..-2],str[-1,1] ] + end + + def tokenize_interpolated_string(token_type) + value,terminator = slurpstring('"$') + token_queue << [TOKENS[token_type[terminator]],value] + while terminator == '$' and not @scanner.scan(/\{/) + token_queue << [TOKENS[:VARIABLE],@scanner.scan(%r{(\w*::)*\w+|[0-9]})] + value,terminator = slurpstring('"$') + token_queue << [TOKENS[DQ_continuation_token_types[terminator]],value] + end + token_queue.shift + end + + # just parse a string, not a whole file + def string=(string) + @scanner = StringScanner.new(string) + end + + # returns the content of the currently accumulated content cache + def commentpop + @commentstack.pop[0] + end + + def getcomment(line = nil) + comment = @commentstack.last + if line.nil? or comment[1] <= line + @commentstack.pop + @commentstack.push(['', @line]) + return comment[0] + end + '' + end + + def commentpush + @commentstack.push(['', @line]) + end end diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index 8dd986bd5..4f3a4ddff 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -1,235 +1,235 @@ # I pulled this into a separate file, because I got # tired of rebuilding the parser.rb file all the time. class Puppet::Parser::Parser - require 'puppet/parser/functions' - require 'puppet/parser/files' - require 'puppet/resource/type_collection' - require 'puppet/resource/type_collection_helper' - require 'puppet/resource/type' - require 'monitor' + require 'puppet/parser/functions' + require 'puppet/parser/files' + require 'puppet/resource/type_collection' + require 'puppet/resource/type_collection_helper' + require 'puppet/resource/type' + require 'monitor' - AST = Puppet::Parser::AST + AST = Puppet::Parser::AST - include Puppet::Resource::TypeCollectionHelper + include Puppet::Resource::TypeCollectionHelper - attr_reader :version, :environment - attr_accessor :files + attr_reader :version, :environment + attr_accessor :files - attr_accessor :lexer - - # Add context to a message; useful for error messages and such. - def addcontext(message, obj = nil) - obj ||= @lexer - - message += " on line #{obj.line}" - if file = obj.file - message += " in file #{file}" - end - - message - end - - # Create an AST array out of all of the args - def aryfy(*args) - if args[0].instance_of?(AST::ASTArray) - result = args.shift - args.each { |arg| - result.push arg - } - else - result = ast AST::ASTArray, :children => args - end - - result - end - - # Create an AST object, and automatically add the file and line information if - # available. - def ast(klass, hash = {}) - klass.new ast_context(klass.use_docs).merge(hash) - end - - def ast_context(include_docs = false) - result = { - :line => lexer.line, - :file => lexer.file - } - result[:doc] = lexer.getcomment(result[:line]) if include_docs - result - end - - # The fully qualifed name, with the full namespace. - def classname(name) - [@lexer.namespace, name].join("::").sub(/^::/, '') - end - - def clear - initvars - end - - # Raise a Parse error. - def error(message) - if brace = @lexer.expected - message += "; expected '%s'" - end - except = Puppet::ParseError.new(message) - except.line = @lexer.line - except.file = @lexer.file if @lexer.file - - raise except - end - - def file - @lexer.file - end - - def file=(file) - unless FileTest.exist?(file) - unless file =~ /\.pp$/ - file = file + ".pp" - end - raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file) - end - raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file) - - watch_file(file) - @lexer.file = file - end - - [:hostclass, :definition, :node, :nodes?].each do |method| - define_method(method) do |*args| - known_resource_types.send(method, *args) - end - end - - def find_hostclass(namespace, name) - known_resource_types.find_or_load(namespace, name, :hostclass) - end - - def find_definition(namespace, name) - known_resource_types.find_or_load(namespace, name, :definition) - end - - def import(file) - known_resource_types.loader.import(file, @lexer.file) - end - - def initialize(env) - # The environment is needed to know how to find the resource type collection. - @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env - initvars - end - - # Initialize or reset all of our variables. - def initvars - @lexer = Puppet::Parser::Lexer.new - 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 - - # Create a new class, or merge with an existing class. - def newclass(name, options = {}) - known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options)) - end - - # Create a new definition. - def newdefine(name, options = {}) - known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options)) - 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) - context = ast_context(true) - names.collect do |name| - known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options))) - end - end - - def on_error(token,value,stack) - if token == 0 # denotes end of file - value = 'end of file' - else - value = "'#{value[:value]}'" - end - error = "Syntax error at #{value}" - - if brace = @lexer.expected - error += "; expected '#{brace}'" - end - - except = Puppet::ParseError.new(error) - except.line = @lexer.line - except.file = @lexer.file if @lexer.file - - raise except - end - - # how should I do error handling here? - def parse(string = nil) - return parse_ruby_file if self.file =~ /\.rb$/ - self.string = string if string - begin - @yydebug = false - main = yyparse(@lexer,:scan) - rescue Racc::ParseError => except - error = Puppet::ParseError.new(except) - error.line = @lexer.line - error.file = @lexer.file - error.set_backtrace except.backtrace - raise error - rescue Puppet::ParseError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue Puppet::Error => except - # and this is a framework error - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue Puppet::DevError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue => except - error = Puppet::DevError.new(except.message) - error.line = @lexer.line - error.file = @lexer.file - error.set_backtrace except.backtrace - raise error - end - if main - # Store the results as the top-level class. - newclass("", :code => main) - end - return known_resource_types - ensure - @lexer.clear - end - - def parse_ruby_file - require self.file - end - - def string=(string) - @lexer.string = string - end - - def version - known_resource_types.version - end - - # Add a new file to be checked when we're checking to see if we should be - # reparsed. This is basically only used by the TemplateWrapper to let the - # parser know about templates that should be parsed. - def watch_file(filename) - known_resource_types.watch_file(filename) - end + attr_accessor :lexer + + # Add context to a message; useful for error messages and such. + def addcontext(message, obj = nil) + obj ||= @lexer + + message += " on line #{obj.line}" + if file = obj.file + message += " in file #{file}" + end + + message + end + + # Create an AST array out of all of the args + def aryfy(*args) + if args[0].instance_of?(AST::ASTArray) + result = args.shift + args.each { |arg| + result.push arg + } + else + result = ast AST::ASTArray, :children => args + end + + result + end + + # Create an AST object, and automatically add the file and line information if + # available. + def ast(klass, hash = {}) + klass.new ast_context(klass.use_docs).merge(hash) + end + + def ast_context(include_docs = false) + result = { + :line => lexer.line, + :file => lexer.file + } + result[:doc] = lexer.getcomment(result[:line]) if include_docs + result + end + + # The fully qualifed name, with the full namespace. + def classname(name) + [@lexer.namespace, name].join("::").sub(/^::/, '') + end + + def clear + initvars + end + + # Raise a Parse error. + def error(message) + if brace = @lexer.expected + message += "; expected '%s'" + end + except = Puppet::ParseError.new(message) + except.line = @lexer.line + except.file = @lexer.file if @lexer.file + + raise except + end + + def file + @lexer.file + end + + def file=(file) + unless FileTest.exist?(file) + unless file =~ /\.pp$/ + file = file + ".pp" + end + raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file) + end + raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file) + + watch_file(file) + @lexer.file = file + end + + [:hostclass, :definition, :node, :nodes?].each do |method| + define_method(method) do |*args| + known_resource_types.send(method, *args) + end + end + + def find_hostclass(namespace, name) + known_resource_types.find_or_load(namespace, name, :hostclass) + end + + def find_definition(namespace, name) + known_resource_types.find_or_load(namespace, name, :definition) + end + + def import(file) + known_resource_types.loader.import(file, @lexer.file) + end + + def initialize(env) + # The environment is needed to know how to find the resource type collection. + @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env + initvars + end + + # Initialize or reset all of our variables. + def initvars + @lexer = Puppet::Parser::Lexer.new + 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 + + # Create a new class, or merge with an existing class. + def newclass(name, options = {}) + known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options)) + end + + # Create a new definition. + def newdefine(name, options = {}) + known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options)) + 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) + context = ast_context(true) + names.collect do |name| + known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options))) + end + end + + def on_error(token,value,stack) + if token == 0 # denotes end of file + value = 'end of file' + else + value = "'#{value[:value]}'" + end + error = "Syntax error at #{value}" + + if brace = @lexer.expected + error += "; expected '#{brace}'" + end + + except = Puppet::ParseError.new(error) + except.line = @lexer.line + except.file = @lexer.file if @lexer.file + + raise except + end + + # how should I do error handling here? + def parse(string = nil) + return parse_ruby_file if self.file =~ /\.rb$/ + self.string = string if string + begin + @yydebug = false + main = yyparse(@lexer,:scan) + rescue Racc::ParseError => except + error = Puppet::ParseError.new(except) + error.line = @lexer.line + error.file = @lexer.file + error.set_backtrace except.backtrace + raise error + rescue Puppet::ParseError => except + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue Puppet::Error => except + # and this is a framework error + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue Puppet::DevError => except + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue => except + error = Puppet::DevError.new(except.message) + error.line = @lexer.line + error.file = @lexer.file + error.set_backtrace except.backtrace + raise error + end + if main + # Store the results as the top-level class. + newclass("", :code => main) + end + return known_resource_types + ensure + @lexer.clear + end + + def parse_ruby_file + require self.file + end + + def string=(string) + @lexer.string = string + end + + def version + known_resource_types.version + end + + # Add a new file to be checked when we're checking to see if we should be + # reparsed. This is basically only used by the TemplateWrapper to let the + # parser know about templates that should be parsed. + def watch_file(filename) + known_resource_types.watch_file(filename) + end end diff --git a/lib/puppet/parser/relationship.rb b/lib/puppet/parser/relationship.rb index 1d1bad76c..6190df52c 100644 --- a/lib/puppet/parser/relationship.rb +++ b/lib/puppet/parser/relationship.rb @@ -1,43 +1,43 @@ class Puppet::Parser::Relationship - attr_accessor :source, :target, :type + attr_accessor :source, :target, :type - PARAM_MAP = {:relationship => :before, :subscription => :notify} + PARAM_MAP = {:relationship => :before, :subscription => :notify} - def evaluate(catalog) - if source.is_a?(Puppet::Parser::Collector) - sources = source.collected.values - else - sources = [source] - end - if target.is_a?(Puppet::Parser::Collector) - targets = target.collected.values - else - targets = [target] - end - sources.each do |s| - targets.each do |t| - mk_relationship(s, t, catalog) - end - end + def evaluate(catalog) + if source.is_a?(Puppet::Parser::Collector) + sources = source.collected.values + else + sources = [source] end - - def initialize(source, target, type) - @source, @target, @type = source, target, type + if target.is_a?(Puppet::Parser::Collector) + targets = target.collected.values + else + targets = [target] end - - def param_name - PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}") + sources.each do |s| + targets.each do |t| + mk_relationship(s, t, catalog) + end end + end + + def initialize(source, target, type) + @source, @target, @type = source, target, type + end - def mk_relationship(source, target, catalog) - unless source_resource = catalog.resource(source.to_s) - raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'" - end - unless target_resource = catalog.resource(target.to_s) - raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'" - end - Puppet.debug "Adding relationship from #{source.to_s} to #{target.to_s} with '#{param_name}'" - source_resource[param_name] ||= [] - source_resource[param_name] << target.to_s + def param_name + PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}") + end + + def mk_relationship(source, target, catalog) + unless source_resource = catalog.resource(source.to_s) + raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'" + end + unless target_resource = catalog.resource(target.to_s) + raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'" end + Puppet.debug "Adding relationship from #{source.to_s} to #{target.to_s} with '#{param_name}'" + source_resource[param_name] ||= [] + source_resource[param_name] << target.to_s + end end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 2d31b40e7..3cccf4f3e 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -4,323 +4,323 @@ require 'puppet/resource' # parent is that this class has rules on who can set # parameters class Puppet::Parser::Resource < Puppet::Resource - require 'puppet/parser/resource/param' - require 'puppet/util/tagging' - require 'puppet/file_collection/lookup' - require 'puppet/parser/yaml_trimmer' - require 'puppet/resource/type_collection_helper' - - include Puppet::FileCollection::Lookup - include Puppet::Resource::TypeCollectionHelper - - include Puppet::Util - include Puppet::Util::MethodHelper - include Puppet::Util::Errors - include Puppet::Util::Logging - include Puppet::Util::Tagging - include Puppet::Parser::YamlTrimmer - - attr_accessor :source, :scope, :rails_id - attr_accessor :virtual, :override, :translated, :catalog, :evaluated - - attr_reader :exported, :parameters - - # Determine whether the provided parameter name is a relationship parameter. - def self.relationship_parameter?(name) - @relationship_names ||= Puppet::Type.relationship_params.collect { |p| p.name } - @relationship_names.include?(name) + require 'puppet/parser/resource/param' + require 'puppet/util/tagging' + require 'puppet/file_collection/lookup' + require 'puppet/parser/yaml_trimmer' + require 'puppet/resource/type_collection_helper' + + include Puppet::FileCollection::Lookup + include Puppet::Resource::TypeCollectionHelper + + include Puppet::Util + include Puppet::Util::MethodHelper + include Puppet::Util::Errors + include Puppet::Util::Logging + include Puppet::Util::Tagging + include Puppet::Parser::YamlTrimmer + + attr_accessor :source, :scope, :rails_id + attr_accessor :virtual, :override, :translated, :catalog, :evaluated + + attr_reader :exported, :parameters + + # Determine whether the provided parameter name is a relationship parameter. + def self.relationship_parameter?(name) + @relationship_names ||= Puppet::Type.relationship_params.collect { |p| p.name } + @relationship_names.include?(name) + end + + # Set up some boolean test methods + [:translated, :override, :evaluated].each do |method| + newmeth = (method.to_s + "?").intern + define_method(newmeth) do + self.send(method) end + end - # Set up some boolean test methods - [:translated, :override, :evaluated].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 @parameters.has_key?(param) - @parameters[param].value - else - nil - end - end - - def []=(param, value) - set_parameter(param, value) + def [](param) + param = symbolize(param) + if param == :title + return self.title end - - def eachparam - @parameters.each do |name, param| - yield param - end + if @parameters.has_key?(param) + @parameters[param].value + else + nil end + end - def environment - scope.environment - end + def []=(param, value) + set_parameter(param, value) + end - # Retrieve the associated definition and evaluate it. - def evaluate - if klass = resource_type and ! builtin_type? - finish - return klass.evaluate_code(self) - elsif builtin? - devfail "Cannot evaluate a builtin type (#{type})" - else - self.fail "Cannot find definition #{type}" - end - ensure - @evaluated = true + def eachparam + @parameters.each do |name, param| + yield param end - - # Mark this resource as both exported and virtual, - # or remove the exported mark. - def exported=(value) - if value - @virtual = true - @exported = value - else - @exported = value - end + end + + def environment + scope.environment + end + + # Retrieve the associated definition and evaluate it. + def evaluate + if klass = resource_type and ! builtin_type? + finish + return klass.evaluate_code(self) + elsif builtin? + devfail "Cannot evaluate a builtin type (#{type})" + else + self.fail "Cannot find definition #{type}" end - - # Do any finishing work on this object, called before evaluation or - # before storage/translation. - def finish - return if finished? - @finished = true - add_defaults - add_metaparams - validate + ensure + @evaluated = true + end + + # Mark this resource as both exported and virtual, + # or remove the exported mark. + def exported=(value) + if value + @virtual = true + @exported = value + else + @exported = value end - - # Has this resource already been finished? - def finished? - @finished + end + + # Do any finishing work on this object, called before evaluation or + # before storage/translation. + def finish + return if finished? + @finished = true + add_defaults + add_metaparams + validate + end + + # Has this resource already been finished? + def finished? + @finished + end + + def initialize(*args) + super + + raise ArgumentError, "Resources require a scope" unless scope + @source ||= scope.source + end + + # Is this resource modeling an isomorphic resource type? + def isomorphic? + if builtin_type? + return resource_type.isomorphic? + else + return true end - - def initialize(*args) - super - - raise ArgumentError, "Resources require a scope" unless scope - @source ||= scope.source + end + + # Merge an override resource in. This will throw exceptions if + # any overrides aren't allowed. + def merge(resource) + # Test the resource scope, to make sure the resource is even allowed + # to override. + unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source) + raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file) end - - # Is this resource modeling an isomorphic resource type? - def isomorphic? - if builtin_type? - return resource_type.isomorphic? - else - return true - end + # Some of these might fail, but they'll fail in the way we want. + resource.parameters.each do |name, param| + override_parameter(param) end - - # Merge an override resource in. This will throw exceptions if - # any overrides aren't allowed. - def merge(resource) - # Test the resource scope, to make sure the resource is even allowed - # to override. - unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source) - raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file) - end - # Some of these might fail, but they'll fail in the way we want. - resource.parameters.each do |name, param| - override_parameter(param) - end + end + + # Unless we're running >= 0.25, we're in compat mode. + def metaparam_compatibility_mode? + ! (catalog and ver = (catalog.client_version||'0.0.0').split(".") and (ver[0] > "0" or ver[1].to_i >= 25)) + end + + def name + self[:name] || self.title + end + + def namespaces + scope.namespaces + end + + # A temporary occasion, until I get paths in the scopes figured out. + def path + to_s + end + + # Define a parameter in our resource. + # if we ever receive a parameter named 'tag', set + # the resource tags with its value. + def set_parameter(param, value = nil) + if ! value.nil? + param = Puppet::Parser::Resource::Param.new( + :name => param, :value => value, :source => self.source + ) + elsif ! param.is_a?(Puppet::Parser::Resource::Param) + raise ArgumentError, "Must pass a parameter or all necessary values" end - # Unless we're running >= 0.25, we're in compat mode. - def metaparam_compatibility_mode? - ! (catalog and ver = (catalog.client_version||'0.0.0').split(".") and (ver[0] > "0" or ver[1].to_i >= 25)) - end + tag(*param.value) if param.name == :tag - def name - self[:name] || self.title - end + # And store it in our parameter hash. + @parameters[param.name] = param + end - def namespaces - scope.namespaces + def to_hash + @parameters.inject({}) do |hash, ary| + param = ary[1] + # Skip "undef" values. + hash[param.name] = param.value if param.value != :undef + hash end - - # A temporary occasion, until I get paths in the scopes figured out. - def path - to_s - end - - # Define a parameter in our resource. - # if we ever receive a parameter named 'tag', set - # the resource tags with its value. - def set_parameter(param, value = nil) - if ! value.nil? - param = Puppet::Parser::Resource::Param.new( - :name => param, :value => value, :source => self.source - ) - elsif ! param.is_a?(Puppet::Parser::Resource::Param) - raise ArgumentError, "Must pass a parameter or all necessary values" + end + + + # Create a Puppet::Resource instance from this parser resource. + # We plan, at some point, on not needing to do this conversion, but + # it's sufficient for now. + def to_resource + result = Puppet::Resource.new(type, title) + + to_hash.each do |p, v| + if v.is_a?(Puppet::Resource) + v = Puppet::Resource.new(v.type, v.title) + elsif v.is_a?(Array) + # flatten resource references arrays + v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) } + v = v.collect do |av| + av = Puppet::Resource.new(av.type, av.title) if av.is_a?(Puppet::Resource) + av end - - tag(*param.value) if param.name == :tag - - # And store it in our parameter hash. - @parameters[param.name] = param + end + + # If the value is an array with only one value, then + # convert it to a single value. This is largely so that + # the database interaction doesn't have to worry about + # whether it returns an array or a string. + result[p] = if v.is_a?(Array) and v.length == 1 + v[0] + else + v + end end - def to_hash - @parameters.inject({}) do |hash, ary| - param = ary[1] - # Skip "undef" values. - hash[param.name] = param.value if param.value != :undef - hash - end - end + result.file = self.file + result.line = self.line + result.exported = self.exported + result.virtual = self.virtual + result.tag(*self.tags) + result + end - # Create a Puppet::Resource instance from this parser resource. - # We plan, at some point, on not needing to do this conversion, but - # it's sufficient for now. - def to_resource - result = Puppet::Resource.new(type, title) - - to_hash.each do |p, v| - if v.is_a?(Puppet::Resource) - v = Puppet::Resource.new(v.type, v.title) - elsif v.is_a?(Array) - # flatten resource references arrays - v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) } - v = v.collect do |av| - av = Puppet::Resource.new(av.type, av.title) if av.is_a?(Puppet::Resource) - av - end - end - - # If the value is an array with only one value, then - # convert it to a single value. This is largely so that - # the database interaction doesn't have to worry about - # whether it returns an array or a string. - result[p] = if v.is_a?(Array) and v.length == 1 - v[0] - else - v - end - end + # Translate our object to a transportable object. + def to_trans + return nil if virtual? - result.file = self.file - result.line = self.line - result.exported = self.exported - result.virtual = self.virtual - result.tag(*self.tags) + to_resource.to_trans + end - result - end + # Convert this resource to a RAL resource. We hackishly go via the + # transportable stuff. + def to_ral + to_resource.to_ral + end - # Translate our object to a transportable object. - def to_trans - return nil if virtual? + private - to_resource.to_trans - end + # Add default values from our definition. + def add_defaults + scope.lookupdefaults(self.type).each do |name, param| + unless @parameters.include?(name) + self.debug "Adding default for #{name}" - # Convert this resource to a RAL resource. We hackishly go via the - # transportable stuff. - def to_ral - to_resource.to_ral + @parameters[name] = param.dup + end end + end - private + def add_backward_compatible_relationship_param(name) + # Skip metaparams for which we get no value. + return unless val = scope.lookupvar(name.to_s, false) and val != :undefined - # Add default values from our definition. - def add_defaults - scope.lookupdefaults(self.type).each do |name, param| - unless @parameters.include?(name) - self.debug "Adding default for #{name}" + # The default case: just set the value + set_parameter(name, val) and return unless @parameters[name] - @parameters[name] = param.dup - end - end - end + # For relationship params, though, join the values (a la #446). + @parameters[name].value = [@parameters[name].value, val].flatten + end - def add_backward_compatible_relationship_param(name) - # Skip metaparams for which we get no value. - return unless val = scope.lookupvar(name.to_s, false) and val != :undefined + # 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 add_metaparams + compat_mode = metaparam_compatibility_mode? - # The default case: just set the value - set_parameter(name, val) and return unless @parameters[name] - - # For relationship params, though, join the values (a la #446). - @parameters[name].value = [@parameters[name].value, val].flatten + Puppet::Type.eachmetaparam do |name| + next unless self.class.relationship_parameter?(name) + add_backward_compatible_relationship_param(name) if compat_mode 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 add_metaparams - compat_mode = metaparam_compatibility_mode? - - Puppet::Type.eachmetaparam do |name| - next unless self.class.relationship_parameter?(name) - add_backward_compatible_relationship_param(name) if compat_mode - end + end + + # Accept a parameter from an override. + def override_parameter(param) + # This can happen if the override is defining a new parameter, rather + # than replacing an existing one. + (set_parameter(param) and return) unless current = @parameters[param.name] + + # The parameter is already set. Fail if they're not allowed to override it. + unless param.source.child_of?(current.source) + puts caller if Puppet[:trace] + msg = "Parameter '#{param.name}' is already set on #{self}" + msg += " by #{current.source}" if current.source.to_s != "" + if current.file or current.line + fields = [] + fields << current.file if current.file + fields << current.line.to_s if current.line + msg += " at #{fields.join(":")}" + end + msg += "; cannot redefine" + raise Puppet::ParseError.new(msg, param.line, param.file) end - # Accept a parameter from an override. - def override_parameter(param) - # This can happen if the override is defining a new parameter, rather - # than replacing an existing one. - (set_parameter(param) and return) unless current = @parameters[param.name] - - # The parameter is already set. Fail if they're not allowed to override it. - unless param.source.child_of?(current.source) - puts caller if Puppet[:trace] - msg = "Parameter '#{param.name}' is already set on #{self}" - msg += " by #{current.source}" if current.source.to_s != "" - if current.file or current.line - fields = [] - fields << current.file if current.file - fields << current.line.to_s if current.line - msg += " at #{fields.join(":")}" - end - msg += "; cannot redefine" - raise Puppet::ParseError.new(msg, param.line, param.file) - end - - # If we've gotten this far, we're allowed to override. - - # Merge with previous value, if the parameter was generated with the +> - # syntax. It's important that we use a copy of the new param instance - # here, not the old one, and not the original new one, so that the source - # is registered correctly for later overrides but the values aren't - # implcitly shared when multiple resources are overrriden at once (see - # ticket #3556). - if param.add - param = param.dup - param.value = [current.value, param.value].flatten - end - - set_parameter(param) + # If we've gotten this far, we're allowed to override. + + # Merge with previous value, if the parameter was generated with the +> + # syntax. It's important that we use a copy of the new param instance + # here, not the old one, and not the original new one, so that the source + # is registered correctly for later overrides but the values aren't + # implcitly shared when multiple resources are overrriden at once (see + # ticket #3556). + if param.add + param = param.dup + param.value = [current.value, param.value].flatten end - # Make sure the resource's parameters are all valid for the type. - def validate - @parameters.each do |name, param| - validate_parameter(name) - end - rescue => detail - fail Puppet::ParseError, detail.to_s + set_parameter(param) + end + + # Make sure the resource's parameters are all valid for the type. + def validate + @parameters.each do |name, param| + validate_parameter(name) end + rescue => detail + fail Puppet::ParseError, detail.to_s + end - private + private - def extract_parameters(params) - params.each do |param| - # Don't set the same parameter twice - self.fail Puppet::ParseError, "Duplicate parameter '#{param.name}' for on #{self}" if @parameters[param.name] + def extract_parameters(params) + params.each do |param| + # Don't set the same parameter twice + self.fail Puppet::ParseError, "Duplicate parameter '#{param.name}' for on #{self}" if @parameters[param.name] - set_parameter(param) - end + set_parameter(param) end + end end diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb index 7ca240df7..af2d98fe8 100644 --- a/lib/puppet/parser/resource/param.rb +++ b/lib/puppet/parser/resource/param.rb @@ -3,25 +3,25 @@ require 'puppet/parser/yaml_trimmer' # The parameters we stick in Resources. class Puppet::Parser::Resource::Param - attr_accessor :name, :value, :source, :add - include Puppet::Util - include Puppet::Util::Errors - include Puppet::Util::MethodHelper + attr_accessor :name, :value, :source, :add + include Puppet::Util + include Puppet::Util::Errors + include Puppet::Util::MethodHelper - include Puppet::FileCollection::Lookup - include Puppet::Parser::YamlTrimmer + include Puppet::FileCollection::Lookup + include Puppet::Parser::YamlTrimmer - def initialize(hash) - set_options(hash) - requiredopts(:name, :value, :source) - @name = symbolize(@name) - end + def initialize(hash) + set_options(hash) + requiredopts(:name, :value, :source) + @name = symbolize(@name) + end - def line_to_i - line ? Integer(line) : nil - end + def line_to_i + line ? Integer(line) : nil + end - def to_s - "#{self.name} => #{self.value}" - end + def to_s + "#{self.name} => #{self.value}" + end end diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 9b49ab680..ae0f9ea4a 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -9,475 +9,475 @@ require 'strscan' require 'puppet/resource/type_collection_helper' class Puppet::Parser::Scope - include Puppet::Resource::TypeCollectionHelper - require 'puppet/parser/resource' - - AST = Puppet::Parser::AST - - Puppet::Util.logmethods(self) - - include Enumerable - include Puppet::Util::Errors - attr_accessor :level, :source, :resource - attr_accessor :base, :keyword - attr_accessor :top, :translated, :compiler - attr_accessor :parent - attr_reader :namespaces - - # thin wrapper around an ephemeral - # symbol table. - # when a symbol - class Ephemeral - def initialize(parent=nil) - @symbols = {} - @parent = parent + include Puppet::Resource::TypeCollectionHelper + require 'puppet/parser/resource' + + AST = Puppet::Parser::AST + + Puppet::Util.logmethods(self) + + include Enumerable + include Puppet::Util::Errors + attr_accessor :level, :source, :resource + attr_accessor :base, :keyword + attr_accessor :top, :translated, :compiler + attr_accessor :parent + attr_reader :namespaces + + # thin wrapper around an ephemeral + # symbol table. + # when a symbol + class Ephemeral + def initialize(parent=nil) + @symbols = {} + @parent = parent + end + + [:include?, :delete, :[]=].each do |m| + define_method(m) do |*args| + @symbols.send(m, *args) + end + end + + def [](name) + unless @symbols.include?(name) or @parent.nil? + @parent[name] + else + @symbols[name] + end + end + end + + # A demeterific shortcut to the catalog. + def catalog + compiler.catalog + end + + def environment + compiler.environment + end + + # Proxy accessors + def host + @compiler.node.name + end + + # Is the value true? This allows us to control the definition of truth + # in one place. + def self.true?(value) + (value != false and value != "" and value != :undef) + end + + # Is the value a number?, return the correct object or nil if not a number + def self.number?(value) + return nil unless value.is_a?(Fixnum) or value.is_a?(Bignum) or value.is_a?(Float) or value.is_a?(String) + + if value.is_a?(String) + if value =~ /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/ + return value.to_f + elsif value =~ /^0x[0-9a-f]+$/i + return value.to_i(16) + elsif value =~ /^0[0-7]+$/ + return value.to_i(8) + elsif value =~ /^-?\d+$/ + return value.to_i + else + return nil + end + end + # it is one of Fixnum,Bignum or Float + value + end + + # Add to our list of namespaces. + def add_namespace(ns) + return false if @namespaces.include?(ns) + if @namespaces == [""] + @namespaces = [ns] + else + @namespaces << ns + end + end + + # Remove this when rebasing + def environment + compiler.environment + end + + # Are we the top scope? + def topscope? + @level == 1 + end + + def find_hostclass(name) + known_resource_types.find_hostclass(namespaces, name) + end + + def find_definition(name) + known_resource_types.find_definition(namespaces, name) + end + + def findresource(string, name = nil) + compiler.findresource(string, name) + end + + # Initialize our new scope. Defaults to having no parent. + def initialize(hash = {}) + if hash.include?(:namespace) + if n = hash[:namespace] + @namespaces = [n] + end + hash.delete(:namespace) + else + @namespaces = [""] + end + hash.each { |name, val| + method = name.to_s + "=" + if self.respond_to? method + self.send(method, val) + else + raise Puppet::DevError, "Invalid scope argument #{name}" + end + } + + extend_with_functions_module + + @tags = [] + + # The symbol table for this scope. This is where we store variables. + @symtable = {} + + # the ephemeral symbol tables + # those should not persist long, and are used for the moment only + # for $0..$xy capture variables of regexes + # this is actually implemented as a stack, with each ephemeral scope + # shadowing the previous one + @ephemeral = [ Ephemeral.new ] + + # 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. + @defaults = Hash.new { |dhash,type| + dhash[type] = {} + } + + # The table for storing class singletons. This will only actually + # be used by top scopes and node scopes. + @class_scopes = {} + end + + # Store the fact that we've evaluated a class, and store a reference to + # the scope in which it was evaluated, so that we can look it up later. + def class_set(name, scope) + return parent.class_set(name,scope) if parent + @class_scopes[name] = scope + end + + # Return the scope associated with a class. This is just here so + # that subclasses can set their parent scopes to be the scope of + # their parent class, and it's also used when looking up qualified + # variables. + def class_scope(klass) + # They might pass in either the class or class name + k = klass.respond_to?(:name) ? klass.name : klass + @class_scopes[k] || (parent && parent.class_scope(k)) + 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 @defaults.include?(type) + @defaults[type].each { |var,value| + values[var] = value + } + end + + #Puppet.debug "Got defaults for %s: %s" % + # [type,values.inspect] + values + end + + # Look up a defined type. + def lookuptype(name) + find_definition(name) || find_hostclass(name) + end + + def lookup_qualified_var(name, usestring) + parts = name.split(/::/) + shortname = parts.pop + klassname = parts.join("::") + klass = find_hostclass(klassname) + unless klass + warning "Could not look up qualified variable '#{name}'; class #{klassname} could not be found" + return usestring ? "" : :undefined + end + unless kscope = class_scope(klass) + warning "Could not look up qualified variable '#{name}'; class #{klassname} has not been evaluated" + return usestring ? "" : :undefined + end + kscope.lookupvar(shortname, usestring) + end + + private :lookup_qualified_var + + # 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) + table = ephemeral?(name) ? @ephemeral.last : @symtable + # If the variable is qualified, then find the specified scope and look the variable up there instead. + if name =~ /::/ + return lookup_qualified_var(name, usestring) + end + # We can't use "if table[name]" here because the value might be false + if ephemeral_include?(name) or table.include?(name) + if usestring and table[name] == :undef + return "" + else + return table[name] + end + elsif self.parent + return parent.lookupvar(name, usestring) + elsif usestring + return "" + else + return :undefined + end + end + + # Return a hash containing our variables and their values, optionally (and + # by default) including the values defined in our parent. Local values + # shadow parent values. + def to_hash(recursive = true) + target = parent.to_hash(recursive) if recursive and parent + target ||= Hash.new + @symtable.keys.each { |name| + value = @symtable[name] + if value == :undef + target.delete(name) + else + target[name] = value + end + } + target + end + + def namespaces + @namespaces.dup + end + + # Create a new scope and set these options. + def newscope(options = {}) + compiler.newscope(self, options) + end + + def parent_module_name + return nil unless @parent + return nil unless @parent.source + @parent.source.module_name + end + + # Return the list of scopes up to the top scope, ordered with our own first. + # This is used for looking up variables and defaults. + def scope_path + if parent + [self, parent.scope_path].flatten.compact + else + [self] + end + end + + # 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 = @defaults[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 table.include?(param.name) + raise Puppet::ParseError.new("Default already defined for #{type} { #{param.name} }; cannot redefine", param.line, param.file) + end + table[param.name] = param + } + 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. + def setvar(name,value, options = {}) + table = options[:ephemeral] ? @ephemeral.last : @symtable + #Puppet.debug "Setting %s to '%s' at level %s mode append %s" % + # [name.inspect,value,self.level, append] + if table.include?(name) + unless options[:append] + error = Puppet::ParseError.new("Cannot reassign variable #{name}") + else + error = Puppet::ParseError.new("Cannot append, variable #{name} is defined in this scope") + end + error.file = options[:file] if options[:file] + error.line = options[:line] if options[:line] + raise error + end + + unless options[:append] + table[name] = value + else # append case + # lookup the value in the scope if it exists and insert the var + table[name] = lookupvar(name) + # concatenate if string, append if array, nothing for other types + case value + when Array + table[name] += value + when Hash + raise ArgumentError, "Trying to append to a hash with something which is not a hash is unsupported" unless value.is_a?(Hash) + table[name].merge!(value) + else + table[name] << value + end + end + end + + # Return an interpolated string. + def strinterp(string, file = nil, line = nil) + # Most strings won't have variables in them. + ss = StringScanner.new(string) + out = "" + while not ss.eos? + if ss.scan(/^\$\{((\w*::)*\w+|[0-9]+)\}|^\$([0-9])|^\$((\w*::)*\w+)/) + # If it matches the backslash, then just retun the dollar sign. + if ss.matched == '\\$' + out << '$' + else # look the variable up + # make sure $0-$9 are lookupable only if ephemeral + var = ss[1] || ss[3] || ss[4] + if var and var =~ /^[0-9]+$/ and not ephemeral_include?(var) + next + end + out << lookupvar(var).to_s || "" end - - [:include?, :delete, :[]=].each do |m| - define_method(m) do |*args| - @symbols.send(m, *args) - end - end - - def [](name) - unless @symbols.include?(name) or @parent.nil? - @parent[name] - else - @symbols[name] - end - end - end - - # A demeterific shortcut to the catalog. - def catalog - compiler.catalog - end - - def environment - compiler.environment - end - - # Proxy accessors - def host - @compiler.node.name - end - - # Is the value true? This allows us to control the definition of truth - # in one place. - def self.true?(value) - (value != false and value != "" and value != :undef) - end - - # Is the value a number?, return the correct object or nil if not a number - def self.number?(value) - return nil unless value.is_a?(Fixnum) or value.is_a?(Bignum) or value.is_a?(Float) or value.is_a?(String) - - if value.is_a?(String) - if value =~ /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/ - return value.to_f - elsif value =~ /^0x[0-9a-f]+$/i - return value.to_i(16) - elsif value =~ /^0[0-7]+$/ - return value.to_i(8) - elsif value =~ /^-?\d+$/ - return value.to_i - else - return nil - end - end - # it is one of Fixnum,Bignum or Float - value - end - - # Add to our list of namespaces. - def add_namespace(ns) - return false if @namespaces.include?(ns) - if @namespaces == [""] - @namespaces = [ns] + elsif ss.scan(/^\\(.)/) + # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched]) + case ss[1] + when 'n' + out << "\n" + when 't' + out << "\t" + when 's' + out << " " + when '\\' + out << '\\' + when '$' + out << '$' else - @namespaces << ns + str = "Unrecognised escape sequence '#{ss.matched}'" + str += " in file #{file}" if file + str += " at line #{line}" if line + Puppet.warning str + out << ss.matched end - end - - # Remove this when rebasing - def environment - compiler.environment - end - - # Are we the top scope? - def topscope? - @level == 1 - end - - def find_hostclass(name) - known_resource_types.find_hostclass(namespaces, name) - end - - def find_definition(name) - known_resource_types.find_definition(namespaces, name) - end - - def findresource(string, name = nil) - compiler.findresource(string, name) - end - - # Initialize our new scope. Defaults to having no parent. - def initialize(hash = {}) - if hash.include?(:namespace) - if n = hash[:namespace] - @namespaces = [n] - end - hash.delete(:namespace) - else - @namespaces = [""] + elsif ss.scan(/^\$/) + out << '$' + elsif ss.scan(/^\\\n/) # an escaped carriage return + next + else + tmp = ss.scan(/[^\\$]+/) + # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp]) + unless tmp + error = Puppet::ParseError.new("Could not parse string #{string.inspect}") + {:file= => file, :line= => line}.each do |m,v| + error.send(m, v) if v + end + raise error end - hash.each { |name, val| - method = name.to_s + "=" - if self.respond_to? method - self.send(method, val) - else - raise Puppet::DevError, "Invalid scope argument #{name}" - end - } - - extend_with_functions_module - - @tags = [] - - # The symbol table for this scope. This is where we store variables. - @symtable = {} - - # the ephemeral symbol tables - # those should not persist long, and are used for the moment only - # for $0..$xy capture variables of regexes - # this is actually implemented as a stack, with each ephemeral scope - # shadowing the previous one - @ephemeral = [ Ephemeral.new ] - - # 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. - @defaults = Hash.new { |dhash,type| - dhash[type] = {} - } - - # The table for storing class singletons. This will only actually - # be used by top scopes and node scopes. - @class_scopes = {} + out << tmp + end end - # Store the fact that we've evaluated a class, and store a reference to - # the scope in which it was evaluated, so that we can look it up later. - def class_set(name, scope) - return parent.class_set(name,scope) if parent - @class_scopes[name] = scope - end + out + end - # Return the scope associated with a class. This is just here so - # that subclasses can set their parent scopes to be the scope of - # their parent class, and it's also used when looking up qualified - # variables. - def class_scope(klass) - # They might pass in either the class or class name - k = klass.respond_to?(:name) ? klass.name : klass - @class_scopes[k] || (parent && parent.class_scope(k)) - end + # 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 + resource.tags + 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 + # Used mainly for logging + def to_s + "Scope(#{@resource})" + end - # then override them with any current values - # this should probably be done differently - if @defaults.include?(type) - @defaults[type].each { |var,value| - values[var] = value - } - end + # Undefine a variable; only used for testing. + def unsetvar(var) + table = ephemeral?(var) ? @ephemeral.last : @symtable + table.delete(var) if table.include?(var) + end - #Puppet.debug "Got defaults for %s: %s" % - # [type,values.inspect] - values + # remove ephemeral scope up to level + def unset_ephemeral_var(level=:all) + if level == :all + @ephemeral = [ Ephemeral.new ] + else + (@ephemeral.size - level).times do + @ephemeral.pop + end end + end - # Look up a defined type. - def lookuptype(name) - find_definition(name) || find_hostclass(name) + # check if name exists in one of the ephemeral scope. + def ephemeral_include?(name) + @ephemeral.reverse.each do |eph| + return true if eph.include?(name) end + false + end - def lookup_qualified_var(name, usestring) - parts = name.split(/::/) - shortname = parts.pop - klassname = parts.join("::") - klass = find_hostclass(klassname) - unless klass - warning "Could not look up qualified variable '#{name}'; class #{klassname} could not be found" - return usestring ? "" : :undefined - end - unless kscope = class_scope(klass) - warning "Could not look up qualified variable '#{name}'; class #{klassname} has not been evaluated" - return usestring ? "" : :undefined - end - kscope.lookupvar(shortname, usestring) - end + # is name an ephemeral variable? + def ephemeral?(name) + name =~ /^\d+$/ + end - private :lookup_qualified_var + def ephemeral_level + @ephemeral.size + 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) - table = ephemeral?(name) ? @ephemeral.last : @symtable - # If the variable is qualified, then find the specified scope and look the variable up there instead. - if name =~ /::/ - return lookup_qualified_var(name, usestring) - end - # We can't use "if table[name]" here because the value might be false - if ephemeral_include?(name) or table.include?(name) - if usestring and table[name] == :undef - return "" - else - return table[name] - end - elsif self.parent - return parent.lookupvar(name, usestring) - elsif usestring - return "" - else - return :undefined - end - end + def new_ephemeral + @ephemeral.push(Ephemeral.new(@ephemeral.last)) + end - # Return a hash containing our variables and their values, optionally (and - # by default) including the values defined in our parent. Local values - # shadow parent values. - def to_hash(recursive = true) - target = parent.to_hash(recursive) if recursive and parent - target ||= Hash.new - @symtable.keys.each { |name| - value = @symtable[name] - if value == :undef - target.delete(name) - else - target[name] = value - end - } - target - end + def ephemeral_from(match, file = nil, line = nil) + raise(ArgumentError,"Invalid regex match data") unless match.is_a?(MatchData) - def namespaces - @namespaces.dup - end + new_ephemeral - # Create a new scope and set these options. - def newscope(options = {}) - compiler.newscope(self, options) + setvar("0", match[0], :file => file, :line => line, :ephemeral => true) + match.captures.each_with_index do |m,i| + setvar("#{i+1}", m, :file => file, :line => line, :ephemeral => true) end + end - def parent_module_name - return nil unless @parent - return nil unless @parent.source - @parent.source.module_name - end - - # Return the list of scopes up to the top scope, ordered with our own first. - # This is used for looking up variables and defaults. - def scope_path - if parent - [self, parent.scope_path].flatten.compact - else - [self] - end - end - - # 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 = @defaults[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 table.include?(param.name) - raise Puppet::ParseError.new("Default already defined for #{type} { #{param.name} }; cannot redefine", param.line, param.file) - end - table[param.name] = param - } - 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. - def setvar(name,value, options = {}) - table = options[:ephemeral] ? @ephemeral.last : @symtable - #Puppet.debug "Setting %s to '%s' at level %s mode append %s" % - # [name.inspect,value,self.level, append] - if table.include?(name) - unless options[:append] - error = Puppet::ParseError.new("Cannot reassign variable #{name}") - else - error = Puppet::ParseError.new("Cannot append, variable #{name} is defined in this scope") - end - error.file = options[:file] if options[:file] - error.line = options[:line] if options[:line] - raise error - end - - unless options[:append] - table[name] = value - else # append case - # lookup the value in the scope if it exists and insert the var - table[name] = lookupvar(name) - # concatenate if string, append if array, nothing for other types - case value - when Array - table[name] += value - when Hash - raise ArgumentError, "Trying to append to a hash with something which is not a hash is unsupported" unless value.is_a?(Hash) - table[name].merge!(value) - else - table[name] << value - end - end - end - - # Return an interpolated string. - def strinterp(string, file = nil, line = nil) - # Most strings won't have variables in them. - ss = StringScanner.new(string) - out = "" - while not ss.eos? - if ss.scan(/^\$\{((\w*::)*\w+|[0-9]+)\}|^\$([0-9])|^\$((\w*::)*\w+)/) - # If it matches the backslash, then just retun the dollar sign. - if ss.matched == '\\$' - out << '$' - else # look the variable up - # make sure $0-$9 are lookupable only if ephemeral - var = ss[1] || ss[3] || ss[4] - if var and var =~ /^[0-9]+$/ and not ephemeral_include?(var) - next - end - out << lookupvar(var).to_s || "" - end - elsif ss.scan(/^\\(.)/) - # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched]) - case ss[1] - when 'n' - out << "\n" - when 't' - out << "\t" - when 's' - out << " " - when '\\' - out << '\\' - when '$' - out << '$' - else - str = "Unrecognised escape sequence '#{ss.matched}'" - str += " in file #{file}" if file - str += " at line #{line}" if line - Puppet.warning str - out << ss.matched - end - elsif ss.scan(/^\$/) - out << '$' - elsif ss.scan(/^\\\n/) # an escaped carriage return - next - else - tmp = ss.scan(/[^\\$]+/) - # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp]) - unless tmp - error = Puppet::ParseError.new("Could not parse string #{string.inspect}") - {:file= => file, :line= => line}.each do |m,v| - error.send(m, v) if v - end - raise error - end - out << tmp - end - end - - out - end - - # 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 - resource.tags - end - - # Used mainly for logging - def to_s - "Scope(#{@resource})" - end - - # Undefine a variable; only used for testing. - def unsetvar(var) - table = ephemeral?(var) ? @ephemeral.last : @symtable - table.delete(var) if table.include?(var) - end - - # remove ephemeral scope up to level - def unset_ephemeral_var(level=:all) - if level == :all - @ephemeral = [ Ephemeral.new ] - else - (@ephemeral.size - level).times do - @ephemeral.pop - end - end - end + private - # check if name exists in one of the ephemeral scope. - def ephemeral_include?(name) - @ephemeral.reverse.each do |eph| - return true if eph.include?(name) - end - false - end - - # is name an ephemeral variable? - def ephemeral?(name) - name =~ /^\d+$/ - end - - def ephemeral_level - @ephemeral.size - end - - def new_ephemeral - @ephemeral.push(Ephemeral.new(@ephemeral.last)) - end - - def ephemeral_from(match, file = nil, line = nil) - raise(ArgumentError,"Invalid regex match data") unless match.is_a?(MatchData) - - new_ephemeral - - setvar("0", match[0], :file => file, :line => line, :ephemeral => true) - match.captures.each_with_index do |m,i| - setvar("#{i+1}", m, :file => file, :line => line, :ephemeral => true) - end - end - - private - - def extend_with_functions_module - extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root) - extend Puppet::Parser::Functions.environment_module(compiler ? environment : nil) - end + def extend_with_functions_module + extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root) + extend Puppet::Parser::Functions.environment_module(compiler ? environment : nil) + end end diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 6966387cf..73a4ad8aa 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -3,112 +3,112 @@ require 'puppet/parser/files' class Puppet::Parser::TemplateWrapper - attr_writer :scope - attr_reader :file - attr_accessor :string - include Puppet::Util - Puppet::Util.logmethods(self) - - def initialize(scope) - @__scope__ = scope + attr_writer :scope + attr_reader :file + attr_accessor :string + include Puppet::Util + Puppet::Util.logmethods(self) + + def initialize(scope) + @__scope__ = scope + end + + def scope + @__scope__ + end + + # Should return true if a variable is defined, false if it is not + def has_variable?(name) + if scope.lookupvar(name.to_s, false) != :undefined + true + else + false end - - def scope - @__scope__ + end + + # Allow templates to access the defined classes + def classes + scope.catalog.classes + end + + # Allow templates to access the tags defined in the current scope + def tags + scope.tags + end + + # Allow templates to access the all the defined tags + def all_tags + scope.catalog.tags + end + + # Ruby treats variables like methods, so we used to expose variables + # within scope to the ERB code via method_missing. As per RedMine #1427, + # though, this means that conflicts between methods in our inheritance + # tree (Kernel#fork) and variable names (fork => "yes/no") could arise. + # + # Worse, /new/ conflicts could pop up when a new kernel or object method + # was added to Ruby, causing templates to suddenly fail mysteriously when + # Ruby was upgraded. + # + # To ensure that legacy templates using unqualified names work we retain + # the missing_method definition here until we declare the syntax finally + # dead. + 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 '#{name}'" end + end - # Should return true if a variable is defined, false if it is not - def has_variable?(name) - if scope.lookupvar(name.to_s, false) != :undefined - true - else - false - end + def file=(filename) + unless @file = Puppet::Parser::Files.find_template(filename, scope.compiler.environment.to_s) + raise Puppet::ParseError, "Could not find template '#{filename}'" end - # Allow templates to access the defined classes - def classes - scope.catalog.classes - end + # We'll only ever not have a parser in testing, but, eh. + scope.known_resource_types.watch_file(file) - # Allow templates to access the tags defined in the current scope - def tags - scope.tags - end + @string = File.read(file) + end - # Allow templates to access the all the defined tags - def all_tags - scope.catalog.tags + def result(string = nil) + if string + self.string = string + template_source = "inline template" + else + template_source = file end - # Ruby treats variables like methods, so we used to expose variables - # within scope to the ERB code via method_missing. As per RedMine #1427, - # though, this means that conflicts between methods in our inheritance - # tree (Kernel#fork) and variable names (fork => "yes/no") could arise. - # - # Worse, /new/ conflicts could pop up when a new kernel or object method - # was added to Ruby, causing templates to suddenly fail mysteriously when - # Ruby was upgraded. - # - # To ensure that legacy templates using unqualified names work we retain - # the missing_method definition here until we declare the syntax finally - # dead. - 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 + # Expose all the variables in our scope as instance variables of the + # current object, making it possible to access them without conflict + # to the regular methods. + benchmark(:debug, "Bound template variables for #{template_source}") do + scope.to_hash.each { |name, value| + if name.kind_of?(String) + realname = name.gsub(/[^\w]/, "_") else - # Just throw an error immediately, instead of searching for - # other missingmethod things or whatever. - raise Puppet::ParseError, "Could not find value for '#{name}'" + realname = name end + instance_variable_set("@#{realname}", value) + } end - def file=(filename) - unless @file = Puppet::Parser::Files.find_template(filename, scope.compiler.environment.to_s) - raise Puppet::ParseError, "Could not find template '#{filename}'" - end - - # We'll only ever not have a parser in testing, but, eh. - scope.known_resource_types.watch_file(file) - - @string = File.read(file) + result = nil + benchmark(:debug, "Interpolated template #{template_source}") do + template = ERB.new(self.string, 0, "-") + result = template.result(binding) end - def result(string = nil) - if string - self.string = string - template_source = "inline template" - else - template_source = file - end - - # Expose all the variables in our scope as instance variables of the - # current object, making it possible to access them without conflict - # to the regular methods. - benchmark(:debug, "Bound template variables for #{template_source}") do - scope.to_hash.each { |name, value| - if name.kind_of?(String) - realname = name.gsub(/[^\w]/, "_") - else - realname = name - end - instance_variable_set("@#{realname}", value) - } - end - - result = nil - benchmark(:debug, "Interpolated template #{template_source}") do - template = ERB.new(self.string, 0, "-") - result = template.result(binding) - end - - result - end + result + end - def to_s - "template[#{(file ? file : "inline")}]" - end + def to_s + "template[#{(file ? file : "inline")}]" + end end diff --git a/lib/puppet/parser/type_loader.rb b/lib/puppet/parser/type_loader.rb index 37fa03f20..e56ab9418 100644 --- a/lib/puppet/parser/type_loader.rb +++ b/lib/puppet/parser/type_loader.rb @@ -1,146 +1,146 @@ require 'puppet/node/environment' class Puppet::Parser::TypeLoader - include Puppet::Node::Environment::Helper - - class Helper < Hash - include MonitorMixin - def done_with(item) - synchronize do - delete(item)[:busy].signal if self.has_key?(item) and self[item][:loader] == Thread.current - end - end - def owner_of(item) - synchronize do - if !self.has_key? item - self[item] = { :loader => Thread.current, :busy => self.new_cond} - :nobody - elsif self[item][:loader] == Thread.current - :this_thread - else - flag = self[item][:busy] - flag.wait - flag.signal - :another_thread - end - end - end + include Puppet::Node::Environment::Helper + + class Helper < Hash + include MonitorMixin + def done_with(item) + synchronize do + delete(item)[:busy].signal if self.has_key?(item) and self[item][:loader] == Thread.current + end end - - # Import our files. - def import(file, current_file = nil) - return if Puppet[:ignoreimport] - - # use a path relative to the file doing the importing - if current_file - dir = current_file.sub(%r{[^/]+$},'').sub(/\/$/, '') + def owner_of(item) + synchronize do + if !self.has_key? item + self[item] = { :loader => Thread.current, :busy => self.new_cond} + :nobody + elsif self[item][:loader] == Thread.current + :this_thread else - dir = "." - end - if dir == "" - dir = "." - end - - pat = file - modname, files = Puppet::Parser::Files.find_manifests(pat, :cwd => dir, :environment => environment) - if files.size == 0 - raise Puppet::ImportError.new("No file(s) found for import of '#{pat}'") - end - - files.each do |file| - unless file =~ /^#{File::SEPARATOR}/ - file = File.join(dir, file) - end - @imported[file] = true - parse_file(file) + flag = self[item][:busy] + flag.wait + flag.signal + :another_thread end - - modname + end end + end - def imported?(file) - @imported.has_key?(file) - end + # Import our files. + def import(file, current_file = nil) + return if Puppet[:ignoreimport] - def known_resource_types - environment.known_resource_types + # use a path relative to the file doing the importing + if current_file + dir = current_file.sub(%r{[^/]+$},'').sub(/\/$/, '') + else + dir = "." end - - def initialize(env) - self.environment = env - @loaded = [] - @loading = Helper.new - - @imported = {} + if dir == "" + dir = "." end - def load_until(namespaces, name) - return nil if name == "" # special-case main. - name2files(namespaces, name).each do |filename| - modname = nil - import_if_possible(filename) do - modname = import(filename) - @loaded << filename - end - if result = yield(filename) - Puppet.info "Automatically imported #{name} from #{filename}" - result.module_name = modname if modname and result.respond_to?(:module_name=) - return result - end - end - nil + pat = file + modname, files = Puppet::Parser::Files.find_manifests(pat, :cwd => dir, :environment => environment) + if files.size == 0 + raise Puppet::ImportError.new("No file(s) found for import of '#{pat}'") end - def loaded?(name) - @loaded.include?(name) + files.each do |file| + unless file =~ /^#{File::SEPARATOR}/ + file = File.join(dir, file) + end + @imported[file] = true + parse_file(file) end - def name2files(namespaces, name) - return [name.sub(/^::/, '').gsub("::", File::SEPARATOR)] if name =~ /^::/ + modname + end + + def imported?(file) + @imported.has_key?(file) + end + + def known_resource_types + environment.known_resource_types + end + + def initialize(env) + self.environment = env + @loaded = [] + @loading = Helper.new + + @imported = {} + end + + def load_until(namespaces, name) + return nil if name == "" # special-case main. + name2files(namespaces, name).each do |filename| + modname = nil + import_if_possible(filename) do + modname = import(filename) + @loaded << filename + end + if result = yield(filename) + Puppet.info "Automatically imported #{name} from #{filename}" + result.module_name = modname if modname and result.respond_to?(:module_name=) + return result + end + end + nil + end - result = namespaces.inject([]) do |names_to_try, namespace| - fullname = (namespace + "::#{name}").sub(/^::/, '') + def loaded?(name) + @loaded.include?(name) + end - # Try to load the module init file if we're a qualified name - names_to_try << fullname.split("::")[0] if fullname.include?("::") + def name2files(namespaces, name) + return [name.sub(/^::/, '').gsub("::", File::SEPARATOR)] if name =~ /^::/ - # Then the fully qualified name - names_to_try << fullname - end + result = namespaces.inject([]) do |names_to_try, namespace| + fullname = (namespace + "::#{name}").sub(/^::/, '') - # Otherwise try to load the bare name on its own. This - # is appropriate if the class we're looking for is in a - # module that's different from our namespace. - result << name - result.uniq.collect { |f| f.gsub("::", File::SEPARATOR) } - end + # Try to load the module init file if we're a qualified name + names_to_try << fullname.split("::")[0] if fullname.include?("::") - def parse_file(file) - Puppet.debug("importing '#{file}' in environment #{environment}") - parser = Puppet::Parser::Parser.new(environment) - parser.file = file - parser.parse + # Then the fully qualified name + names_to_try << fullname end - private - - # Utility method factored out of load for handling thread-safety. - # This isn't tested in the specs, because that's basically impossible. - def import_if_possible(file) - return if @loaded.include?(file) - begin - case @loading.owner_of(file) - when :this_thread - return - when :another_thread - return import_if_possible(file) - when :nobody - yield - end - rescue Puppet::ImportError => detail - # We couldn't load the item - ensure - @loading.done_with(file) - end + # Otherwise try to load the bare name on its own. This + # is appropriate if the class we're looking for is in a + # module that's different from our namespace. + result << name + result.uniq.collect { |f| f.gsub("::", File::SEPARATOR) } + end + + def parse_file(file) + Puppet.debug("importing '#{file}' in environment #{environment}") + parser = Puppet::Parser::Parser.new(environment) + parser.file = file + parser.parse + end + + private + + # Utility method factored out of load for handling thread-safety. + # This isn't tested in the specs, because that's basically impossible. + def import_if_possible(file) + return if @loaded.include?(file) + begin + case @loading.owner_of(file) + when :this_thread + return + when :another_thread + return import_if_possible(file) + when :nobody + yield + end + rescue Puppet::ImportError => detail + # We couldn't load the item + ensure + @loading.done_with(file) end + end end diff --git a/lib/puppet/parser/yaml_trimmer.rb b/lib/puppet/parser/yaml_trimmer.rb index 131bafb8d..cf7870916 100644 --- a/lib/puppet/parser/yaml_trimmer.rb +++ b/lib/puppet/parser/yaml_trimmer.rb @@ -1,9 +1,9 @@ module Puppet::Parser::YamlTrimmer - REMOVE = %w{@scope @source} + REMOVE = %w{@scope @source} - def to_yaml_properties - r = instance_variables - REMOVE - r -= skip_for_yaml if respond_to?(:skip_for_yaml) - r - end + def to_yaml_properties + r = instance_variables - REMOVE + r -= skip_for_yaml if respond_to?(:skip_for_yaml) + r + end end |
