From 046a3269db6468f1f7a79b98f8738328b9992fb7 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 11:42:47 -0800 Subject: Fixing #977 -- rundir is again set to 1777. --- lib/puppet/defaults.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index a95023895..0c8ac3f82 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -66,7 +66,11 @@ module Puppet :owner => "root", :desc => "Where SSL certificates are kept." }, - :rundir => { :default => rundir, + :rundir => { + :default => rundir, + :mode => 01777, + :owner => "$user", + :group => "$group", :desc => "Where Puppet PID files are kept." }, :genconfig => [false, -- cgit From 9161ae8f215520cda16ba9345a8818de08b89ca0 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 11:45:09 -0800 Subject: Applying a fix for #998 -- I used a patch equivalent to bartv's, although I could not use his commit because it was against the 'master' branch instead of 0.24.x. --- lib/puppet/parser/compile.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index f76103a28..e1e230d48 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -309,6 +309,9 @@ class Puppet::Parser::Compile 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 -- cgit From 7a9aae84805e415de090f0ce9be04beb8435e117 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 14:08:44 -0600 Subject: Wrapping the Resolv call in the mongrel server so if it fails it doesn't kill the server. --- lib/puppet/network/http_server/mongrel.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb index d6e21b189..d340f3d63 100644 --- a/lib/puppet/network/http_server/mongrel.rb +++ b/lib/puppet/network/http_server/mongrel.rb @@ -127,7 +127,12 @@ module Puppet::Network client = dn_matchdata[1].to_str valid = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS') else - client = Resolv.getname(ip) + begin + client = Resolv.getname(ip) + rescue => detail + Puppet.err "Could not resolve %s: %s" % [ip, detail] + client = "unknown" + end valid = false end -- cgit From f5674cd527defd2db9165fdc3d7f966a43b70b75 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 14:20:48 -0600 Subject: Fixing #995 -- puppetd no longer dies at startup if the server is not running. --- lib/puppet/network/xmlrpc/client.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb index 27bb3dc5e..f6a5e8db6 100644 --- a/lib/puppet/network/xmlrpc/client.rb +++ b/lib/puppet/network/xmlrpc/client.rb @@ -90,6 +90,13 @@ module Puppet::Network @clients[handler] || self.mkclient(handler) end + def http + unless @http + @http = Puppet::Network::HttpPool.http_instance(@host, @port, true) + end + @http + end + def initialize(hash = {}) hash[:Path] ||= "/RPC2" hash[:Server] ||= Puppet[:server] @@ -125,7 +132,11 @@ module Puppet::Network end def start - @http.start unless @http.started? + begin + @http.start unless @http.started? + rescue => detail + Puppet.err "Could not connect to server: %s" % detail + end end def local -- cgit From 2cbab2c6916d6bd7c5ad01b137b3469eeea8d3e4 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 14:34:20 -0600 Subject: Fixing #1008 -- Puppet no longer throws an exception when you've pointed a file at a source that doesn't exist and you specify 'ensure'. --- lib/puppet/type/pfile/ensure.rb | 5 +++++ lib/puppet/type/pfile/source.rb | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/pfile/ensure.rb b/lib/puppet/type/pfile/ensure.rb index 0a6f73d95..3aa918f65 100755 --- a/lib/puppet/type/pfile/ensure.rb +++ b/lib/puppet/type/pfile/ensure.rb @@ -136,6 +136,11 @@ module Puppet # We have to treat :present specially, because it works with any # type of file. def insync?(currentvalue) + if property = @resource.property(:source) and ! property.described? + warning "No specified sources exist" + return true + end + if self.should == :present if currentvalue.nil? or currentvalue == :absent return false diff --git a/lib/puppet/type/pfile/source.rb b/lib/puppet/type/pfile/source.rb index 1849d5a61..3dfb5cccd 100755 --- a/lib/puppet/type/pfile/source.rb +++ b/lib/puppet/type/pfile/source.rb @@ -138,10 +138,10 @@ module Puppet # Use the info we get from describe() to check if we're in sync. def insync?(currentvalue) unless described? - info "No specified sources exist" + warning "No specified sources exist" return true end - + if currentvalue == :nocopy return true end -- cgit From f98be4a7198326b26f1072c401b3e337f340db40 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 13:40:40 -0800 Subject: Fixing #976 -- both the full name of qualified classes and the class parts are now added as tags. I've also created a Tagging module that we should push throughout the rest of the system that uses tags. --- lib/puppet/parser/resource.rb | 35 ++++++++++------------------------- lib/puppet/transaction.rb | 2 +- lib/puppet/util/tagging.rb | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 lib/puppet/util/tagging.rb (limited to 'lib') diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 3f346166e..7dc42ccec 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -3,18 +3,18 @@ class Puppet::Parser::Resource require 'puppet/parser/resource/param' require 'puppet/parser/resource/reference' + require 'puppet/util/tagging' include Puppet::Util include Puppet::Util::MethodHelper include Puppet::Util::Errors include Puppet::Util::Logging + include Puppet::Util::Tagging attr_accessor :source, :line, :file, :scope, :rails_id attr_accessor :virtual, :override, :translated attr_reader :exported, :evaluated, :params - attr_writer :tags - # Determine whether the provided parameter name is a relationship parameter. def self.relationship_parameter?(name) unless defined?(@relationship_names) @@ -86,6 +86,7 @@ class Puppet::Parser::Resource add_overrides() add_defaults() add_metaparams() + add_scope_tags() validate() end @@ -130,13 +131,8 @@ class Puppet::Parser::Resource raise ArgumentError, "Resources do not accept %s" % options.keys.collect { |k| k.to_s }.join(", ") end - @tags = [] tag(@ref.type) - tag(@ref.title) if @ref.title.to_s =~ /^[-\w]+$/ - - if scope.resource - @tags += scope.resource.tags - end + tag(@ref.title) if valid_tag?(@ref.title.to_s) end # Merge an override resource in. This will throw exceptions if @@ -223,23 +219,6 @@ class Puppet::Parser::Resource @ref.to_s end - # Add a tag to our current list. These tags will be added to all - # of the objects contained in this scope. - def tag(*ary) - ary.collect { |tag| tag.to_s.downcase }.collect { |tag| tag.split("::") }.flatten.each do |tag| - unless tag =~ /^\w[-\w]*$/ - fail Puppet::ParseError, "Invalid tag %s" % tag.inspect - end - unless @tags.include?(tag) - @tags << tag - end - end - end - - def tags - @tags.dup - end - def to_hash @params.inject({}) do |hash, ary| param = ary[1] @@ -374,6 +353,12 @@ class Puppet::Parser::Resource end end + def add_scope_tags + if scope_resource = scope.resource + tag(*scope_resource.tags) + end + end + # Accept a parameter from an override. def override_parameter(param) # This can happen if the override is defining a new parameter, rather diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 6a4981298..f304cadc6 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -424,7 +424,7 @@ class Transaction # Should we ignore tags? def ignore_tags? - ! @catalog.host_config? + ! (@catalog.host_config? or Puppet[:name] == "puppet") end # this should only be called by a Puppet::Type::Component resource now diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb new file mode 100644 index 000000000..25d74c420 --- /dev/null +++ b/lib/puppet/util/tagging.rb @@ -0,0 +1,34 @@ +# Created on 2008-01-19 +# Copyright Luke Kanies + +# A common module to handle tagging. +module Puppet::Util::Tagging + # Add a tag to our current list. These tags will be added to all + # of the objects contained in this scope. + def tag(*ary) + @tags ||= [] + + qualified = [] + + ary.collect { |tag| tag.to_s.downcase }.each do |tag| + fail(Puppet::ParseError, "Invalid tag %s" % tag.inspect) unless valid_tag?(tag) + qualified << tag if tag.include?("::") + @tags << tag unless @tags.include?(tag) + end + + qualified.collect { |name| name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) } + end + + # Return a copy of the tag list, so someone can't ask for our tags + # and then modify them. + def tags + @tags ||= [] + @tags.dup + end + + private + + def valid_tag?(tag) + tag =~ /^\w[-\w:]*$/ + end +end -- cgit From f43be56d7b84c5a4f7ecbe8463fbb38836f1ef9a Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 13:40:52 -0800 Subject: Removing the line that marked fink as the default package manager on darwin. --- lib/puppet/provider/package/fink.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/provider/package/fink.rb b/lib/puppet/provider/package/fink.rb index e0933df08..030e1a347 100755 --- a/lib/puppet/provider/package/fink.rb +++ b/lib/puppet/provider/package/fink.rb @@ -9,8 +9,6 @@ Puppet::Type.type(:package).provide :fink, :parent => :dpkg, :source => :dpkg do commands :aptcache => "/sw/bin/apt-cache" commands :dpkgquery => "/sw/bin/dpkg-query" - defaultfor :operatingsystem => :darwin - has_feature :versionable # A derivative of DPKG; this is how most people actually manage -- cgit From 8a649ff28a46afe6b1e4dd002ac90c93651edfa3 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sun, 20 Jan 2008 21:21:37 -0800 Subject: I think I've finally fixed #959, by having the Settings class skip any resources that are already in memory. --- lib/puppet/util/settings.rb | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index b672d9564..ff019edb8 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -510,18 +510,19 @@ class Puppet::Util::Settings end # Only files are convertable to transportable resources. - if obj.respond_to? :to_transportable - next if value(obj.name) =~ /^\/dev/ - transobjects = obj.to_transportable - transobjects = [transobjects] unless transobjects.is_a? Array - transobjects.each do |trans| - # transportable could return nil - next unless trans - unless done[:file].include? trans.name - @created << trans.name - objects << trans - done[:file][trans.name] = trans - end + next unless obj.respond_to? :to_transportable + next if value(obj.name) =~ /^\/dev/ + next if Puppet::Type::File[obj.value] # skip files that are in our global resource list. + + transobjects = obj.to_transportable + transobjects = [transobjects] unless transobjects.is_a? Array + transobjects.each do |trans| + # transportable could return nil + next unless trans + unless done[:file].include? trans.name + @created << trans.name + objects << trans + done[:file][trans.name] = trans end end end -- cgit From d7a89b449520abb95396132bc379782a0d596816 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Mon, 21 Jan 2008 17:24:30 +1100 Subject: Fixed #1019 - made libshadow available for non-Linux users --- lib/puppet/provider/user/useradd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb index c2476203a..9ecaad87d 100644 --- a/lib/puppet/provider/user/useradd.rb +++ b/lib/puppet/provider/user/useradd.rb @@ -19,7 +19,7 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ has_features :manages_homedir, :allows_duplicates - if Puppet.features.libshadow? and (Facter.value(:kernel) == "Linux") + if Puppet.features.libshadow? has_feature :manages_passwords end -- cgit From 1ccc9c3b47e7e96f70fa48b2a21c5e10dc103d6e Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Tue, 22 Jan 2008 11:58:40 +1100 Subject: Fixes ticket #151 - host type now validates IP addresses and hostnames/FQDNs - the regex for the latter is quite complex but I have found it bullet-proof in the past --- lib/puppet/type/host.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lib') diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index be5c2ed72..7f633d989 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -1,9 +1,16 @@ +require 'ipaddr' + module Puppet newtype(:host) do ensurable newproperty(:ip) do desc "The host's IP address, IPv4 or IPv6." + + validate do |value| + addr = IPAddr.new(value) + end + end newproperty(:alias) do @@ -78,6 +85,12 @@ module Puppet desc "The host name." isnamevar + + validate do |value| + unless value =~ /^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])$/ + raise Puppet::Error, "Invalid host name" + end + end end @doc = "Installs and manages host entries. For most systems, these -- cgit From b561ae64014630d9d2b93a6a6625fe67e9844c9e Mon Sep 17 00:00:00 2001 From: Bart Vanbrabant Date: Tue, 22 Jan 2008 16:29:38 +0100 Subject: Fix bug #997, only evaluate non-virtual definitions --- lib/puppet/parser/compile.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index e1e230d48..3dc7d3657 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -285,11 +285,15 @@ class Puppet::Parser::Compile def evaluate_definitions exceptwrap do if ary = unevaluated_resources + evaluated = false ary.each do |resource| - resource.evaluate + if not resource.virtual? + resource.evaluate + evaluated = true + end end # If we evaluated, let the loop know. - return true + return evaluated else return false end -- cgit From 4a7fcfc761aa086488b255f457373f6626498e72 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Fri, 25 Jan 2008 16:12:59 +1100 Subject: Revert "Fixes ticket #151 - host type now validates IP addresses and hostnames/FQDNs - the regex for the latter is quite complex but I have found it bullet-proof in the past" This reverts commit 1ccc9c3b47e7e96f70fa48b2a21c5e10dc103d6e. --- lib/puppet/type/host.rb | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index 7f633d989..be5c2ed72 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -1,16 +1,9 @@ -require 'ipaddr' - module Puppet newtype(:host) do ensurable newproperty(:ip) do desc "The host's IP address, IPv4 or IPv6." - - validate do |value| - addr = IPAddr.new(value) - end - end newproperty(:alias) do @@ -85,12 +78,6 @@ module Puppet desc "The host name." isnamevar - - validate do |value| - unless value =~ /^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])$/ - raise Puppet::Error, "Invalid host name" - end - end end @doc = "Installs and manages host entries. For most systems, these -- cgit From 9a290bb646e23191184230243ef58cc0c9501400 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Fri, 25 Jan 2008 22:49:48 +1100 Subject: Second attempt to fix ticket #151 - host type now validates IP addresses and hostnames/FQDNs --- lib/puppet/type/host.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib') diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index be5c2ed72..2a04474e8 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -1,9 +1,18 @@ +require 'ipaddr' + module Puppet newtype(:host) do ensurable newproperty(:ip) do desc "The host's IP address, IPv4 or IPv6." + + validate do |value| + unless value =~ /((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})/ + raise Puppet::Error, "Invalid IP address" + end + end + end newproperty(:alias) do @@ -78,6 +87,12 @@ module Puppet desc "The host name." isnamevar + + validate do |value| + unless value =~ /^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])$/ + raise Puppet::Error, "Invalid host name" + end + end end @doc = "Installs and manages host entries. For most systems, these -- cgit From ee6ddc9c3bf76d4a6499fdbcb43f18daed247395 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 28 Jan 2008 16:48:35 +1100 Subject: Removing tons of unnecessary calls to "nil?" from the lexer. --- lib/puppet/parser/lexer.rb | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 086d82c09..09f263eb9 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -62,8 +62,6 @@ module Puppet "<<|" => "|>>" } - @@reverse_pairs = @@pairs.inject({}) { |hash, pair| hash[pair[1]] = pair[0]; hash } - @@keywords = { "case" => :CASE, "class" => :CLASS, @@ -105,15 +103,10 @@ module Puppet def fullscan array = [] - self.scan { |token,str| + self.scan { |token, str| # Ignore any definition nesting problems @indefine = false - #Puppet.debug("got token '%s' => '%s'" % [token,str]) - if token.nil? - return array - else - array.push([token,str]) - end + array.push([token,str]) } return array end @@ -182,9 +175,7 @@ module Puppet # this is the heart of the lexer def scan #Puppet.debug("entering scan") - if @scanner.nil? - raise TypeError.new("Invalid or empty string") - end + raise TypeError.new("Invalid or empty string") unless @scanner @scanner.skip(@skip) until @scanner.eos? do @@ -195,15 +186,10 @@ module Puppet value = "" # first find out which type of token we've got - @@tokens.each { |regex,token| + @@tokens.each { |regex, token| # we're just checking, which doesn't advance the scan # pointer - tmp = @scanner.check(regex) - if tmp.nil? - #puppet.debug("did not match %s to '%s'" % - # [regex,@scanner.rest]) - next - end + next unless tmp = @scanner.check(regex) # find the longest match if tmp.length > value.length @@ -231,9 +217,7 @@ module Puppet value = @scanner.scan(sregex) - if value == "" - raise "Didn't match regex on token %s" % stoken - end + raise "Didn't match regex on token %s" % stoken if value == "" # token-specific operations # if this gets much more complicated, it should -- cgit From 11799b3266674edf5eba3591dcb41eae51c1a0e4 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Mon, 28 Jan 2008 22:57:54 +1100 Subject: Fixed #1001 --- lib/puppet/provider/package/openbsd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/provider/package/openbsd.rb b/lib/puppet/provider/package/openbsd.rb index ce69dd432..f76c37176 100755 --- a/lib/puppet/provider/package/openbsd.rb +++ b/lib/puppet/provider/package/openbsd.rb @@ -66,7 +66,7 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa info = pkginfo @resource[:name] # Search for the version info - if info =~ /Information for #{@resource[:name]}-(\S+)/ + if info =~ /Information for (inst:)?#{@resource[:name]}-(\S+)/ hash[:ensure] = $1 else return nil -- cgit From 6ff9423c7ebaf759fcee28a3009cd59bed3ea886 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 30 Jan 2008 23:28:07 +1100 Subject: Significantly refactoring the lexer, including adding Token and TokenList classes for managing how the tokens work. I also moved they tests to RSpec, but I didn't rewrite all of them. --- lib/puppet/parser/lexer.rb | 661 +++++++++++++++++++++--------------- lib/puppet/parser/parser_support.rb | 7 +- 2 files changed, 393 insertions(+), 275 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 09f263eb9..6661650ba 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -1,4 +1,3 @@ - # the scanner/lexer require 'strscan' @@ -7,310 +6,432 @@ require 'puppet' module Puppet class LexError < RuntimeError; end - module Parser - #--------------------------------------------------------------- - class Lexer - attr_reader :line, :last, :file - - attr_accessor :indefine - - #%r{\w+} => :WORD, - @@tokens = { - %r{#.*} => :COMMENT, - %r{\[} => :LBRACK, - %r{\]} => :RBRACK, - %r{\{} => :LBRACE, - %r{\}} => :RBRACE, - %r{\(} => :LPAREN, - %r{\)} => :RPAREN, - %r{\"} => :DQUOTE, - %r{\n} => :RETURN, - %r{\'} => :SQUOTE, - %r{=} => :EQUALS, - %r{==} => :ISEQUAL, - %r{>=} => :GREATEREQUAL, - %r{>} => :GREATERTHAN, - %r{<} => :LESSTHAN, - %r{<=} => :LESSEQUAL, - %r{!=} => :NOTEQUAL, - %r{!} => :NOT, - %r{,} => :COMMA, - %r{\.} => :DOT, - %r{:} => :COLON, - %r{@} => :AT, - %r{<<\|} => :LLCOLLECT, - %r{\|>>} => :RRCOLLECT, - %r{<\|} => :LCOLLECT, - %r{\|>} => :RCOLLECT, - %r{;} => :SEMIC, - %r{\?} => :QMARK, - %r{\\} => :BACKSLASH, - %r{=>} => :FARROW, - %r{\+>} => :PARROW, - %r{[a-z][-\w]*} => :NAME, - %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME, - %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF, - %r{[0-9]+} => :NUMBER, - %r{\$(\w*::)*\w+} => :VARIABLE - } - - @@pairs = { - "{" => "}", - "(" => ")", - "[" => "]", - "<|" => "|>", - "<<|" => "|>>" - } - - @@keywords = { - "case" => :CASE, - "class" => :CLASS, - "default" => :DEFAULT, - "define" => :DEFINE, - "false" => :BOOLEAN, - "import" => :IMPORT, - "if" => :IF, - "elsif" => :ELSIF, - "else" => :ELSE, - "inherits" => :INHERITS, - "node" => :NODE, - "true" => :BOOLEAN, - "and" => :AND, - "or" => :OR, - "undef" => :UNDEF - } - - def clear - initvars - end +end - def expected - if @expected.empty? - nil - else - token = @expected[-1] - @@tokens.each do |value, name| - if token == name - return value - end - end - return token - end - end +module Puppet::Parser; 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]) - } - return array - end +class Puppet::Parser::Lexer + attr_reader :last, :file + + attr_accessor :line, :indefine + + # Our base token class. + class Token + attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text - # this is probably pretty damned inefficient... - # it'd be nice not to have to load the whole file first... - def file=(file) - @file = file - @line = 1 - File.open(file) { |of| - str = "" - of.each { |line| str += line } - @scanner = StringScanner.new(str) - } + 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 - def indefine? - if defined? @indefine - @indefine - else - false - end + def skip? + self.skip + end + + def to_s + "Lexer token %s" % @name.to_s + 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 %s already exists" % name) 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 - def initialize - initvars() + options.each do |name, option| + token.send(name.to_s + "=", option) end - def initvars - @line = 1 - @last = "" - @lasttoken = nil - @scanner = nil - @file = nil - # AAARRGGGG! okay, regexes in ruby are bloody annoying - # no one else has "\n" =~ /\s/ - @skip = %r{[ \t]+} + token.meta_def(:convert, &block) if block_given? - @namestack = [] - @indefine = false + token + end - @expected = [] - 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 - # Go up one in the namespace. - def namepop - @namestack.pop + # 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 - # Collect the current namespace. - def namespace - @namestack.join("::") + TOKENS = TokenList.new + TOKENS.add_tokens( + '[' => :LBRACK, + ']' => :RBRACK, + '{' => :LBRACE, + '}' => :RBRACE, + '(' => :LPAREN, + ')' => :RPAREN, + '=' => :EQUALS, + '==' => :ISEQUAL, + '>=' => :GREATEREQUAL, + '>' => :GREATERTHAN, + '<' => :LESSTHAN, + '<=' => :LESSEQUAL, + '!=' => :NOTEQUAL, + '!' => :NOT, + ',' => :COMMA, + '.' => :DOT, + ':' => :COLON, + '@' => :AT, + '<<|' => :LLCOLLECT, + '|>>' => :RRCOLLECT, + '<|' => :LCOLLECT, + '|>' => :RCOLLECT, + ';' => :SEMIC, + '?' => :QMARK, + '\\' => :BACKSLASH, + '=>' => :FARROW, + '+>' => :PARROW, + %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME, + %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF + ) + + TOKENS.add_tokens "Whatever" => :DQTEXT, "Nomatter" => :SQTEXT, "alsonomatter" => :BOOLEAN + + TOKENS.add_token :NAME, %r{[a-z][-\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 + + TOKENS.add_token :NUMBER, %r{[0-9]+} do |lexer, value| + [TOKENS[:NAME], value] + end + + TOKENS.add_token :COMMENT, %r{#.*}, :skip => true + + TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true + + TOKENS.add_token :SQUOTE, "'" do |lexer, value| + value = lexer.slurpstring(value) + [TOKENS[:SQTEXT], value] + end + + TOKENS.add_token :DQUOTE, '"' do |lexer, value| + value = lexer.slurpstring(value) + [TOKENS[:DQTEXT], value] + end + + TOKENS.add_token :VARIABLE, %r{\$(\w*::)*\w+} do |lexer, value| + value = value.sub(/^\$/, '') + [self, value] + end + + 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 + ) + + def clear + initvars + end + + def expected + return nil if @expected.empty? + name = @expected[-1] + raise "Could not find expected token %s" % name unless token = TOKENS.lookup(name) + + return token + 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]) + } + return array + end + + # this is probably pretty damned inefficient... + # it'd be nice not to have to load the whole file first... + def file=(file) + @file = file + @line = 1 + File.open(file) { |of| + str = "" + of.each { |line| str += line } + @scanner = StringScanner.new(str) + } + 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 + def find_string_token + matched_token = value = nil + + # 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 chars we have. Also, + # the lookups are optimized hash lookups, instead of regex scans. + [3, 2, 1].each do |i| + str = @scanner.peek(i) + if matched_token = TOKENS.lookup(str) + value = @scanner.scan(matched_token.regex) + break end + end + + return matched_token, value + end - def rest - @scanner.rest + # Find the next token that matches a regex. We look for these first. + def find_regex_token + @regex += 1 + matched_token = nil + value = "" + 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| + next unless match_length = @scanner.match?(token.regex) + + # We've found a longer match + if match_length > length + value = @scanner.scan(token.regex) + length = value.length + matched_token = token end + end - # this is the heart of the lexer - def scan - #Puppet.debug("entering scan") - raise TypeError.new("Invalid or empty string") unless @scanner - - @scanner.skip(@skip) - until @scanner.eos? do - yielded = false - sendbreak = false # gah, this is a nasty hack - stoken = nil - sregex = nil - value = "" - - # first find out which type of token we've got - @@tokens.each { |regex, token| - # we're just checking, which doesn't advance the scan - # pointer - next unless tmp = @scanner.check(regex) - - # find the longest match - if tmp.length > value.length - value = tmp - stoken = token - sregex = regex - else - # we've already got a longer match - next - end - } - - # error out if we didn't match anything at all - if stoken.nil? - nword = nil - if @scanner.rest =~ /^(\S+)/ - nword = $1 - elsif@scanner.rest =~ /^(\s+)/ - nword = $1 - else - nword = @scanner.rest - end - raise "Could not match '%s'" % nword - end + return matched_token, value + end - value = @scanner.scan(sregex) - - raise "Didn't match regex on token %s" % stoken if value == "" - - # token-specific operations - # if this gets much more complicated, it should - # be moved up to where the tokens themselves are defined - # which will get me about 75% of the way to a lexer generator - ptoken = stoken - case stoken - when :NAME then - wtoken = stoken - # we're looking for keywords here - if @@keywords.include?(value) - wtoken = @@keywords[value] - #Puppet.debug("token '%s'" % wtoken) - if wtoken == :BOOLEAN - value = eval(value) - end - end - ptoken = wtoken - when :NUMBER then - ptoken = :NAME - when :COMMENT then - # just throw comments away - next - when :RETURN then - @line += 1 - @scanner.skip(@skip) - next - when :SQUOTE then - #Puppet.debug("searching '%s' after '%s'" % [self.rest,value]) - value = self.slurpstring(value) - ptoken = :SQTEXT - #Puppet.debug("got string '%s' => '%s'" % [:DQTEXT,value]) - when :DQUOTE then - value = self.slurpstring(value) - ptoken = :DQTEXT - when :VARIABLE then - value = value.sub(/^\$/, '') - end + # Find the next token, returning the string and the token. + def find_token + @find += 1 + matched_token, value = find_regex_token - if match = @@pairs[value] and ptoken != :DQUOTE and ptoken != :SQUOTE - @expected << match - elsif exp = @expected[-1] and exp == value and ptoken != :DQUOTE and ptoken != :SQUOTE - @expected.pop - end + unless matched_token + matched_token, value = find_string_token + end - yield [ptoken, value] + return matched_token, value + end - if @lasttoken == :CLASS - namestack(value) - end + def indefine? + if defined? @indefine + @indefine + else + false + end + end - if @lasttoken == :DEFINE - if indefine? - msg = "Cannot nest definition %s inside %s" % [value, @indefine] - self.indefine = false - raise Puppet::ParseError, msg - end + def initialize + @find = 0 + @regex = 0 + initvars() + end - @indefine = value - 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]+} + + @namestack = [] + @indefine = false + @expected = [] + end - @last = value - @lasttoken = ptoken + # Make any necessary changes to the token and/or value. + def munge_token(token, value) + @line += 1 if token.incr_line - @scanner.skip(@skip) - end - @scanner = nil - yield [false,false] - end + skip() if token.skip_text + + return if token.skip + + token, value = token.convert(self, value) if token.respond_to?(:convert) + + return unless token + + return token, value + end + + # Go up one in the namespace. + def namepop + @namestack.pop + end - # we've encountered an opening quote... - # slurp in the rest of the string and return it - def slurpstring(quote) - # 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(/([^\\]|^)#{quote}/) - if str.nil? - raise Puppet::LexError.new("Unclosed quote after '%s' in '%s'" % - [self.last,self.rest]) + # Collect the current namespace. + def namespace + @namestack.join("::") + end + + # This value might have :: in it, but we don't care -- it'll be + # handled normally when joining, and when popping we want to pop + # this full value, however long the namespace is. + def namestack(value) + @namestack << value + end + + def rest + @scanner.rest + end + + # this is the heart of the lexer + def scan + #Puppet.debug("entering scan") + raise Puppet::LexError.new("Invalid or empty string") unless @scanner + + # Skip any initial whitespace. + skip() + + until @scanner.eos? do + yielded = false + matched_token, value = find_token + + # error out if we didn't match anything at all + if matched_token.nil? + nword = nil + # Try to pull a 'word' out of the remaining string. + if @scanner.rest =~ /^(\S+)/ + nword = $1 + elsif @scanner.rest =~ /^(\s+)/ + nword = $1 else - str.sub!(/#{quote}\Z/,"") - str.gsub!(/\\#{quote}/,quote) + nword = @scanner.rest end + raise "Could not match '%s'" % nword + end - return str + final_token, value = munge_token(matched_token, value) + + next unless final_token + + 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 - # just parse a string, not a whole file - def string=(string) - @scanner = StringScanner.new(string) + yield [final_token.name, value] + + if @previous_token + namestack(value) if @previous_token.name == :CLASS + + if @previous_token.name == :DEFINE + if indefine? + msg = "Cannot nest definition %s inside %s" % [value, @indefine] + self.indefine = false + raise Puppet::ParseError, msg + end + + @indefine = value + end 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 -end + # we've encountered an opening quote... + # slurp in the rest of the string and return it + def slurpstring(quote) + # 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(/([^\\]|^)#{quote}/) + if str.nil? + raise Puppet::LexError.new("Unclosed quote after '%s' in '%s'" % + [self.last,self.rest]) + else + str.sub!(/#{quote}\Z/,"") + str.gsub!(/\\#{quote}/,quote) + end + + return str + end + + # just parse a string, not a whole file + def string=(string) + @scanner = StringScanner.new(string) + end +end diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index acf3c9f7c..b543cd3ec 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -47,11 +47,8 @@ class Puppet::Parser::Parser # Create an AST object, and automatically add the file and line information if # available. - def ast(klass, hash = nil) - hash ||= {} - unless hash.include?(:line) - hash[:line] = @lexer.line - end + def ast(klass, hash = {}) + hash[:line] = @lexer.line unless hash.include?(:line) unless hash.include?(:file) if file = @lexer.file -- cgit From 047ec5435ef81139b60fc60a5a2668c0a7c4ee85 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Thu, 31 Jan 2008 20:37:26 +1100 Subject: Fixed tickt #1034 - doco typo --- lib/puppet/type/package.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index 9173eaa1c..24b187e5f 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -176,7 +176,7 @@ module Puppet a common name to packages:: # In the 'openssl' class - $ssl = $operationgsystem ? { + $ssl = $operatingsystem ? { solaris => SMCossl, default => openssl } @@ -190,7 +190,7 @@ module Puppet . etc. . - $ssh = $operationgsystem ? { + $ssh = $operatingsystem ? { solaris => SMCossh, default => openssh } -- cgit From ade9f3c7296db12eee6f3c9c3aa29b99da652960 Mon Sep 17 00:00:00 2001 From: Bart Vanbrabant Date: Sun, 3 Feb 2008 11:44:32 +0100 Subject: Store a resource before adding relations to it otherwise activerecord will complain. This fixes #933 --- lib/puppet/parser/resource.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 7dc42ccec..58667727f 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -239,6 +239,8 @@ class Puppet::Parser::Resource # Handle file specially db_resource.file = self.file + db_resource.save + @params.each { |name, param| param.to_rails(db_resource) } -- cgit From ed0c745c0f3b0f277968149ca25c78ce374bd2e4 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sun, 20 Jan 2008 22:00:05 -0800 Subject: Fixing #1017 -- environment-specific modulepath is no longer ignored. (Cherry-picked from master.) --- lib/puppet/parser/parser_support.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index b543cd3ec..ccfc4d48a 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -177,7 +177,7 @@ class Puppet::Parser::Parser "in file #{@lexer.file} at line #{@lexer.line}" ) end - files = Puppet::Module::find_manifests(pat, :cwd => dir) + files = Puppet::Module::find_manifests(pat, :cwd => dir, :environment => @environment) if files.size == 0 raise Puppet::ImportError.new("No file(s) found for import " + "of '#{pat}'") -- cgit From 16df87c419655106b1585b1e443a2050270518e5 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Tue, 5 Feb 2008 13:52:12 +1100 Subject: Updated fix for ticket #151 and added a test --- lib/puppet/type/host.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index 2a04474e8..3e34c0b60 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -1,5 +1,3 @@ -require 'ipaddr' - module Puppet newtype(:host) do ensurable @@ -89,7 +87,7 @@ module Puppet isnamevar validate do |value| - unless value =~ /^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])$/ + unless value =~ /^\w+-?[\w+]?\.?[\w+.{1}]*\w+$/ raise Puppet::Error, "Invalid host name" end end -- cgit From b8036a9ed180dc1e143f66ac786759e7ae4b634b Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Feb 2008 08:30:55 -0600 Subject: Updating the docs for the cron type --- lib/puppet/type/cron.rb | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index 7882745dc..c46a7c83b 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -8,13 +8,6 @@ Puppet::Type.newtype(:cron) do fields would result in the command being executed every minute. While the name of the cron job is not part of the actual job, it is used by Puppet to store and retrieve it. - - You may specify periodic fields as integers, using the standard cron - range syntax (two numbers separated by a hyphen to indicate a range - of values), or using the cron step syntax (for example, '*/2' to - indicate command execution every other time unit). This type does - not yet support the combiantion of these two syntaxes, or lists of - ranges. If you specify a cron job that matches an existing job in every way except name, then the jobs will be considered equivalent and the @@ -30,6 +23,24 @@ Puppet::Type.newtype(:cron) do hour => 2, minute => 0 } + + Note that all cron values can be specified as an array of values:: + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => [2, 4] + } + + Or using ranges, or the step syntax ``*/2`` (although there's no guarantee that + your ``cron`` daemon supports it):: + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => ['2-4'], + minute => '*/10' + } " ensurable -- cgit From aedd59cb2427c8642b817587b0c5ad1319161daa Mon Sep 17 00:00:00 2001 From: Paul Lathrop Date: Fri, 1 Feb 2008 16:51:48 -0800 Subject: fix bug 974 - filenames with opening bracket characters generate exceptions --- lib/puppet/resource_reference.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/resource_reference.rb b/lib/puppet/resource_reference.rb index 3e92662b2..d5fc90d1f 100644 --- a/lib/puppet/resource_reference.rb +++ b/lib/puppet/resource_reference.rb @@ -37,7 +37,7 @@ class Puppet::ResourceReference # set things appropriately; else, just set it. def title=(value) if value =~ /^(.+)\[(.+)\]$/ - self.type = $1 + @type = $1 @title = $2 else @title = value -- cgit From 139ff33e1f93a0634547fc9a06442a720fe0a58e Mon Sep 17 00:00:00 2001 From: Paul Lathrop Date: Mon, 21 Jan 2008 17:01:53 -0800 Subject: Fujin's patch for ticket #1007 - consistent use of 'environment' instead of 'env' --- lib/puppet/type/exec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index 5bb3158c4..a7a046c43 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -228,7 +228,7 @@ module Puppet end end - newparam(:env) do + newparam(:environment) do desc "Any additional environment variables you want to set for a command. Note that if you use this to set PATH, it will override the ``path`` attribute. Multiple environment variables should be @@ -554,32 +554,32 @@ module Puppet begin # Do our chdir Dir.chdir(dir) do - env = {} + environment = {} if self[:path] - env[:PATH] = self[:path].join(":") + environment[:PATH] = self[:path].join(":") end - if envlist = self[:env] + if envlist = self[:environment] envlist = [envlist] unless envlist.is_a? Array envlist.each do |setting| if setting =~ /^(\w+)=((.|\n)+)$/ name = $1 value = $2 - if env.include? name + if environment.include? name warning( "Overriding environment setting '%s' with '%s'" % [name, value] ) end - env[name] = value + environment[name] = value else - warning "Cannot understand env setting %s" % setting.inspect + warning "Cannot understand environment setting %s" % setting.inspect end end end - withenv env do + withenv environment do Timeout::timeout(self[:timeout]) do output, status = Puppet::Util::SUIDManager.run_and_capture( [command], self[:user], self[:group] -- cgit From 8f0d87d498ca12417a7d20b81ba46465658fa210 Mon Sep 17 00:00:00 2001 From: Paul Lathrop Date: Tue, 5 Feb 2008 14:05:14 -0800 Subject: Added :env parameter for backwards-compatibility, with warning about deprecation. :env parameter sets new :environment parameter. Changed instances of :env to :environment for consistency with other types. Added tests for new parameters. This cimmit fixes ticket 1007. --- lib/puppet/type/exec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib') diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index a7a046c43..7d3b1abe1 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -228,6 +228,15 @@ module Puppet end end + newparam(:env) do + desc "This parameter is deprecated. Use 'environment' instead." + + munge do |value| + warning "'env' is deprecated on exec; use 'environment' instead." + resource[:environment] = value + end + end + newparam(:environment) do desc "Any additional environment variables you want to set for a command. Note that if you use this to set PATH, it will override -- cgit From b3f67ec4017940a7eb47f3a044fd77c8d32a74cf Mon Sep 17 00:00:00 2001 From: Paul Lathrop Date: Tue, 5 Feb 2008 15:07:05 -0800 Subject: Fix ticket 974. My original "fix" wasn't. This actually fixes the problem by using a regular expression that matches only up to the first square bracket. --- lib/puppet/resource_reference.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/resource_reference.rb b/lib/puppet/resource_reference.rb index d5fc90d1f..771a91be7 100644 --- a/lib/puppet/resource_reference.rb +++ b/lib/puppet/resource_reference.rb @@ -36,8 +36,8 @@ class Puppet::ResourceReference # If the title has square brackets, treat it like a reference and # set things appropriately; else, just set it. def title=(value) - if value =~ /^(.+)\[(.+)\]$/ - @type = $1 + if value =~ /^([^\[\]]+)\[(.+)\]$/ + self.type = $1 @title = $2 else @title = value -- cgit From 2931723bae9e4226ab8eb7f6f806bf9a2ea5cbb8 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 7 Feb 2008 15:31:43 -0600 Subject: Fixing the Settings class so that it correctly handles file values that are false. --- lib/puppet/util/settings.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index ff019edb8..c84a5bfb1 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -509,12 +509,11 @@ class Puppet::Util::Settings objects += add_user_resources(section, obj, done) end + value = obj.value + # Only files are convertable to transportable resources. - next unless obj.respond_to? :to_transportable - next if value(obj.name) =~ /^\/dev/ - next if Puppet::Type::File[obj.value] # skip files that are in our global resource list. + next unless obj.respond_to? :to_transportable and transobjects = obj.to_transportable - transobjects = obj.to_transportable transobjects = [transobjects] unless transobjects.is_a? Array transobjects.each do |trans| # transportable could return nil @@ -1154,12 +1153,15 @@ Generated on #{Time.now}. def to_transportable type = self.type return nil unless type - path = @parent.value(self.name).split(File::SEPARATOR) - path.shift # remove the leading nil - objects = [] path = self.value + return nil unless path.is_a?(String) + return nil if path =~ /^\/dev/ + return nil if Puppet::Type::File[path] # skip files that are in our global resource list. + + objects = [] + # Skip plain files that don't exist, since we won't be managing them anyway. return nil unless self.name.to_s =~ /dir$/ or File.exist?(path) or self.create obj = Puppet::TransObject.new(path, "file") -- cgit From b293763f9ef2e134f18bb2c3fdaaaa502aa2c201 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 7 Feb 2008 15:34:30 -0600 Subject: Applying patch by Jay to fix #989 -- missing crl files are correctly ignored, and you now use 'false' instead of 'none' to explicitly ignore them. --- lib/puppet/defaults.rb | 2 +- lib/puppet/network/http_server/webrick.rb | 4 ++-- lib/puppet/sslcertificates/ca.rb | 6 +++--- lib/puppet/util/settings.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 0c8ac3f82..520a18d1a 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -232,7 +232,7 @@ module Puppet :owner => "$user", :group => "$group", :mode => 0664, - :desc => "The certificate revocation list (CRL) for the CA. Set this to 'none' if you do not want to use a CRL." + :desc => "The certificate revocation list (CRL) for the CA. Set this to 'false' if you do not want to use a CRL." }, :caprivatedir => { :default => "$cadir/private", :owner => "$user", diff --git a/lib/puppet/network/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb index 3c9f72e17..e4f00dd73 100644 --- a/lib/puppet/network/http_server/webrick.rb +++ b/lib/puppet/network/http_server/webrick.rb @@ -22,12 +22,12 @@ module Puppet # with them, with flags appropriate for checking client # certificates for revocation def x509store - if Puppet[:cacrl] == 'none' + if Puppet[:cacrl] == 'false' # No CRL, no store needed return nil end unless File.exist?(Puppet[:cacrl]) - raise Puppet::Error, "Could not find CRL; set 'cacrl' to 'none' to disable CRL usage" + raise Puppet::Error, "Could not find CRL; set 'cacrl' to 'false' to disable CRL usage" end crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl])) store = OpenSSL::X509::Store.new diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index a3edd2cb4..888bcf5b2 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -194,8 +194,8 @@ class Puppet::SSLCertificates::CA # Revoke the certificate with serial number SERIAL issued by this # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE) - if @config[:cacrl] == 'none' - raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'none'" + if @config[:cacrl] == 'false' + raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'false'" end time = Time.now revoked = OpenSSL::X509::Revoked.new @@ -372,7 +372,7 @@ class Puppet::SSLCertificates::CA @crl = OpenSSL::X509::CRL.new( File.read(@config[:cacrl]) ) - elsif @config[:cacrl] == 'none' + elsif @config[:cacrl] == 'false' @crl = nil else # Create new CRL diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index c84a5bfb1..cf15d3194 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -1124,7 +1124,7 @@ Generated on #{Time.now}. # the variable 'dir', or adding a slash at the end. def munge(value) # If it's not a fully qualified path... - if value.is_a?(String) and value !~ /^\$/ and value !~ /^\// + if value.is_a?(String) and value !~ /^\$/ and value !~ /^\// and value != 'false' # Make it one value = File.join(Dir.getwd, value) end -- cgit From 084d0fb6351ed54ff4c052cff20f21e89063620c Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 7 Feb 2008 15:52:02 -0600 Subject: Adding more information to dependencies that do not resolve --- lib/puppet/metatype/metaparams.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/metatype/metaparams.rb b/lib/puppet/metatype/metaparams.rb index b35adae66..9983c34d2 100644 --- a/lib/puppet/metatype/metaparams.rb +++ b/lib/puppet/metatype/metaparams.rb @@ -258,7 +258,7 @@ class Puppet::Type @value.each do |value| unless @resource.catalog.resource(*value) description = self.class.direction == :in ? "dependency" : "dependent" - raise Puppet::Error, "Could not find #{description} %s[%s]" % [value[0].to_s.capitalize, value[1]] + fail Puppet::Error, "Could not find #{description} %s[%s] for %s" % [value[0].to_s.capitalize, value[1], resource.ref] end end end -- cgit From dbaffaeaafa60c7325f7522a76a84c5dd7df7c6b Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 8 Feb 2008 11:42:24 -0600 Subject: Ceasing autoloading ast files; loading them manually instead --- lib/puppet/parser/ast.rb | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index 14b686e2f..880e406a8 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -107,13 +107,27 @@ class Puppet::Parser::AST @line = nil set_options(args) end - #--------------------------------------------------------------- - # Now autoload everything. - @autoloader = Puppet::Util::Autoload.new(self, - "puppet/parser/ast" - ) - @autoloader.loadall end +# And include all of the AST subclasses. +require 'puppet/parser/ast/astarray' +require 'puppet/parser/ast/branch' +require 'puppet/parser/ast/caseopt' +require 'puppet/parser/ast/casestatement' +require 'puppet/parser/ast/collection' +require 'puppet/parser/ast/collexpr' +require 'puppet/parser/ast/definition' +require 'puppet/parser/ast/else' +require 'puppet/parser/ast/function' +require 'puppet/parser/ast/hostclass' +require 'puppet/parser/ast/ifstatement' require 'puppet/parser/ast/leaf' - +require 'puppet/parser/ast/node' +require 'puppet/parser/ast/resource' +require 'puppet/parser/ast/resource_defaults' +require 'puppet/parser/ast/resource_override' +require 'puppet/parser/ast/resource_reference' +require 'puppet/parser/ast/resourceparam' +require 'puppet/parser/ast/selector' +require 'puppet/parser/ast/tag' +require 'puppet/parser/ast/vardef' -- cgit From 82720d5327b30839a29035ee0b498b940ffc7a5a Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 8 Feb 2008 13:24:39 -0600 Subject: Removing some obsolete code from the AST base class --- lib/puppet/parser/ast.rb | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index 880e406a8..cac18fef4 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -14,30 +14,6 @@ class Puppet::Parser::AST include Puppet::Util::MethodHelper attr_accessor :line, :file, :parent, :scope - # Just used for 'tree', which is only used in debugging. - @@pink = "" - @@green = "" - @@yellow = "" - @@slate = "" - @@reset = "" - - # Just used for 'tree', which is only used in debugging. - @@indent = " " * 4 - @@indline = @@pink + ("-" * 4) + @@reset - @@midline = @@slate + ("-" * 4) + @@reset - - @@settypes = {} - - # Just used for 'tree', which is only used in debugging. - def AST.indention - return @@indent * @@indention - end - - # Just used for 'tree', which is only used in debugging. - def AST.midline - return @@midline - end - # Does this ast object set something? If so, it gets evaluated first. def self.settor? if defined? @settor @@ -47,16 +23,12 @@ class Puppet::Parser::AST end end - # Evaluate the current object. Basically just iterates across all + # 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(args) - #Puppet.debug("Evaluating ast %s" % @name) - value = self.collect { |obj| - obj.safeevaluate(args) - }.reject { |obj| - obj.nil? - } + raise Puppet::DevError, "Did not override #evaluate in %s" % self.class end # Throw a parse error. @@ -90,14 +62,6 @@ class Puppet::Parser::AST end end - # Again, just used for printing out the parse tree. - def typewrap(string) - #return self.class.to_s.sub(/.+::/,'') + - #"(" + @@green + string.to_s + @@reset + ")" - return @@green + string.to_s + @@reset + - "(" + self.class.to_s.sub(/.+::/,'') + ")" - end - # Initialize the object. Requires a hash as the argument, and # takes each of the parameters of the hash and calls the settor # method for them. This is probably pretty inefficient and should -- cgit From 5a0e34b4f8da22e1830ec7d0a730c3686665bceb Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 8 Feb 2008 14:25:52 -0600 Subject: Refactoring the AST classes just a bit. I realized that all of the evaluate() methods only ever accepted a scope, and sometimes one other option, so I switched them all to use named arguments instead of a hash. --- lib/puppet/parser/ast.rb | 6 +++--- lib/puppet/parser/ast/astarray.rb | 5 ++--- lib/puppet/parser/ast/caseopt.rb | 8 ++++---- lib/puppet/parser/ast/casestatement.rb | 9 ++++----- lib/puppet/parser/ast/collection.rb | 6 ++---- lib/puppet/parser/ast/collexpr.rb | 8 +++----- lib/puppet/parser/ast/definition.rb | 9 +++------ lib/puppet/parser/ast/else.rb | 5 ++--- lib/puppet/parser/ast/function.rb | 13 +++---------- lib/puppet/parser/ast/hostclass.rb | 12 +++++------- lib/puppet/parser/ast/ifstatement.rb | 9 ++++----- lib/puppet/parser/ast/leaf.rb | 12 ++++++------ lib/puppet/parser/ast/node.rb | 16 ++++------------ lib/puppet/parser/ast/resource.rb | 8 +++----- lib/puppet/parser/ast/resource_defaults.rb | 6 ++---- lib/puppet/parser/ast/resource_override.rb | 8 +++----- lib/puppet/parser/ast/resource_reference.rb | 6 ++---- lib/puppet/parser/ast/resourceparam.rb | 6 ++---- lib/puppet/parser/ast/selector.rb | 11 +++++------ lib/puppet/parser/ast/tag.rb | 6 ++---- lib/puppet/parser/ast/vardef.rb | 7 +++---- lib/puppet/parser/resource.rb | 2 +- 22 files changed, 68 insertions(+), 110 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index cac18fef4..c9bd7c9e8 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -27,7 +27,7 @@ class Puppet::Parser::AST # 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(args) + def evaluate(*options) raise Puppet::DevError, "Did not override #evaluate in %s" % self.class end @@ -47,11 +47,11 @@ class Puppet::Parser::AST # 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) + 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) + return self.evaluate(*options) rescue Puppet::Error => detail raise adderrorcontext(detail) rescue => detail diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 5f1e838d0..b66fd6bba 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -15,8 +15,7 @@ class Puppet::Parser::AST end # Evaluate our children. - def evaluate(hash) - scope = hash[:scope] + def evaluate(scope) rets = nil # We basically always operate declaratively, and when we # do we need to evaluate the settor-like statements first. This @@ -51,7 +50,7 @@ class Puppet::Parser::AST } rets = [settors, others].flatten.collect { |child| - child.safeevaluate(:scope => scope) + child.safeevaluate(scope) } return rets.reject { |o| o.nil? } end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index d1d9d0e9c..824bde853 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -44,17 +44,17 @@ class Puppet::Parser::AST def eachvalue(scope) if @value.is_a?(AST::ASTArray) @value.each { |subval| - yield subval.evaluate(:scope => scope) + yield subval.safeevaluate(scope) } else - yield @value.evaluate(:scope => scope) + yield @value.safeevaluate(scope) end end # Evaluate the actual statements; this only gets called if # our option matched. - def evaluate(hash) - return @statements.safeevaluate(hash) + def evaluate(scope) + return @statements.safeevaluate(scope) end end end diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb index 3c6f9c7e2..aa03090de 100644 --- a/lib/puppet/parser/ast/casestatement.rb +++ b/lib/puppet/parser/ast/casestatement.rb @@ -8,9 +8,8 @@ class Puppet::Parser::AST # Short-curcuit evaluation. Return the value of the statements for # the first option that matches. - def evaluate(hash) - scope = hash[:scope] - value = @test.safeevaluate(:scope => scope) + def evaluate(scope) + value = @test.safeevaluate(scope) sensitive = Puppet[:casesensitive] value = value.downcase if ! sensitive and value.respond_to?(:downcase) @@ -30,7 +29,7 @@ class Puppet::Parser::AST if found # we found a matching option - retvalue = option.safeevaluate(:scope => scope) + retvalue = option.safeevaluate(scope) break end @@ -42,7 +41,7 @@ class Puppet::Parser::AST # Unless we found something, look for the default. unless found if default - retvalue = default.safeevaluate(:scope => scope) + retvalue = default.safeevaluate(scope) else Puppet.debug "No true answers and no default" retvalue = nil diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index e05977a47..31f508929 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -9,11 +9,9 @@ class Collection < AST::Branch attr_accessor :type, :query, :form # We return an object that does a late-binding evaluation. - def evaluate(hash) - scope = hash[:scope] - + def evaluate(scope) if self.query - str, code = self.query.safeevaluate :scope => scope + str, code = self.query.safeevaluate scope else str = code = nil end diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb index 4a96d9c61..3e13d9400 100644 --- a/lib/puppet/parser/ast/collexpr.rb +++ b/lib/puppet/parser/ast/collexpr.rb @@ -9,9 +9,7 @@ class CollExpr < AST::Branch attr_accessor :test1, :test2, :oper, :form, :type, :parens # We return an object that does a late-binding evaluation. - def evaluate(hash) - scope = hash[:scope] - + 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) @@ -21,8 +19,8 @@ class CollExpr < AST::Branch end # The code is only used for virtual lookups - str1, code1 = @test1.safeevaluate :scope => scope - str2, code2 = @test2.safeevaluate :scope => scope + 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 diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index 3d6d6188c..2e39e7332 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -27,10 +27,7 @@ class Puppet::Parser::AST false end - def evaluate(options) - origscope = options[:scope] - resource = options[:resource] - + def evaluate(origscope, resource) # Create a new scope. scope = subscope(origscope, resource) @@ -49,7 +46,7 @@ class Puppet::Parser::AST set_resource_parameters(scope, resource) if self.code - return self.code.safeevaluate(:scope => scope) + return self.code.safeevaluate(scope) else return nil end @@ -181,7 +178,7 @@ class Puppet::Parser::AST arg = symbolize(arg) unless args.include?(arg) if defined? default and ! default.nil? - default = default.safeevaluate :scope => scope + default = default.safeevaluate scope args[arg] = default #Puppet.debug "Got default %s for %s in %s" % # [default.inspect, arg.inspect, @name.inspect] diff --git a/lib/puppet/parser/ast/else.rb b/lib/puppet/parser/ast/else.rb index e76051372..affac625d 100644 --- a/lib/puppet/parser/ast/else.rb +++ b/lib/puppet/parser/ast/else.rb @@ -12,9 +12,8 @@ class Puppet::Parser::AST # Evaluate the actual statements; this only gets called if # our test was true matched. - def evaluate(hash) - scope = hash[:scope] - return @statements.safeevaluate(:scope => scope) + def evaluate(scope) + return @statements.safeevaluate(scope) end end end diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb index 0cd1fff62..63d7c7abf 100644 --- a/lib/puppet/parser/ast/function.rb +++ b/lib/puppet/parser/ast/function.rb @@ -7,18 +7,11 @@ class Puppet::Parser::AST @settor = true - def evaluate(hash) + def evaluate(scope) # We don't need to evaluate the name, because it's plaintext + args = @arguments.safeevaluate(scope) - # Just evaluate the arguments - scope = hash[:scope] - - args = @arguments.safeevaluate(:scope => scope) - - #exceptwrap :message => "Failed to execute %s" % @name, - # :type => Puppet::ParseError do - return scope.send("function_" + @name, args) - #end + return scope.send("function_" + @name, args) end def initialize(hash) diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 63900d0e3..42d13f4b2 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -20,9 +20,7 @@ class Puppet::Parser::AST end # Evaluate the code associated with this class. - def evaluate(options) - scope = options[:scope] - raise(ArgumentError, "Classes require resources") unless options[:resource] + def evaluate(scope, resource) # Verify that we haven't already been evaluated. This is # what provides the singleton aspect. if existing_scope = scope.compile.class_scope(self) @@ -34,7 +32,7 @@ class Puppet::Parser::AST pnames = nil if pklass = self.parentobj - pklass.safeevaluate :scope => scope, :resource => options[:resource] + pklass.safeevaluate(scope, resource) scope = parent_scope(scope, pklass) pnames = scope.namespaces @@ -42,8 +40,8 @@ class Puppet::Parser::AST # Don't create a subscope for the top-level class, since it already # has its own scope. - unless options[:resource].title == :main - scope = subscope(scope, options[:resource]) + unless resource.title == :main + scope = subscope(scope, resource) end if pnames @@ -58,7 +56,7 @@ class Puppet::Parser::AST # Now evaluate our code, yo. if self.code - return self.code.evaluate(:scope => scope) + return self.code.safeevaluate(scope) else return nil end diff --git a/lib/puppet/parser/ast/ifstatement.rb b/lib/puppet/parser/ast/ifstatement.rb index 66a07b01f..afa2cd572 100644 --- a/lib/puppet/parser/ast/ifstatement.rb +++ b/lib/puppet/parser/ast/ifstatement.rb @@ -12,15 +12,14 @@ class Puppet::Parser::AST # 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(hash) - scope = hash[:scope] - value = @test.safeevaluate(:scope => scope) + def evaluate(scope) + value = @test.safeevaluate(scope) if Puppet::Parser::Scope.true?(value) - return @statements.safeevaluate(:scope => scope) + return @statements.safeevaluate(scope) else if defined? @else - return @else.safeevaluate(:scope => scope) + return @else.safeevaluate(scope) else return nil end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 225253061..c545c1e47 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -6,7 +6,7 @@ class Puppet::Parser::AST attr_accessor :value, :type # Return our value. - def evaluate(hash) + def evaluate(scope) return @value end @@ -35,14 +35,14 @@ class Puppet::Parser::AST class String < AST::Leaf # Interpolate the string looking for variables, and then return # the result. - def evaluate(hash) - return hash[:scope].strinterp(@value, @file, @line) + def evaluate(scope) + return scope.strinterp(@value, @file, @line) end end # An uninterpreted string. class FlatString < AST::Leaf - def evaluate(hash) + def evaluate(scope) return @value end end @@ -81,9 +81,9 @@ class Puppet::Parser::AST class Variable < Name # Looks up the value of the object in the scope tree (does # not include syntactical constructs, like '$' and '{}'). - def evaluate(hash) + def evaluate(scope) parsewrap do - return hash[:scope].lookupvar(@value) + return scope.lookupvar(@value) end end end diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index a296e43ba..3c5d44d1b 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -7,23 +7,15 @@ class Puppet::Parser::AST @name = :node attr_accessor :name - def evaluate(options) - scope = options[:scope] - - #pscope = if ! Puppet[:lexical] or options[:asparent] - # @scope - #else - # origscope - #end - + def evaluate(scope, resource) # We don't have to worry about the declarativeness of node parentage, # because the entry point is always a single node definition. if parent = self.parentobj - scope = parent.safeevaluate :scope => scope, :resource => options[:resource] + scope = parent.safeevaluate scope, resource end scope = scope.newscope( - :resource => options[:resource], + :resource => resource, :keyword => @keyword, :source => self, :namespace => "" # nodes are always in "" @@ -36,7 +28,7 @@ class Puppet::Parser::AST # And then evaluate our code if we have any if self.code - @code.safeevaluate(:scope => scope) + @code.safeevaluate(scope) end return scope diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index c53ab0a68..606beb537 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -9,15 +9,13 @@ class Resource < AST::ResourceReference # Does not actually return an object; instead sets an object # in the current scope. - def evaluate(options) - scope = options[:scope] - + def evaluate(scope) # Evaluate all of the specified params. paramobjects = @params.collect { |param| - param.safeevaluate(:scope => scope) + param.safeevaluate(scope) } - objtitles = @title.safeevaluate(:scope => scope) + objtitles = @title.safeevaluate(scope) # it's easier to always use an array, even for only one name unless objtitles.is_a?(Array) diff --git a/lib/puppet/parser/ast/resource_defaults.rb b/lib/puppet/parser/ast/resource_defaults.rb index 8f9c1b8df..4856f0594 100644 --- a/lib/puppet/parser/ast/resource_defaults.rb +++ b/lib/puppet/parser/ast/resource_defaults.rb @@ -8,13 +8,11 @@ class Puppet::Parser::AST # As opposed to ResourceDef, this stores each default for the given # object type. - def evaluate(hash) - scope = hash[:scope] - + def evaluate(scope) # Use a resource reference to canonize the type ref = Puppet::ResourceReference.new(@type, "whatever") type = ref.type - params = @params.safeevaluate(:scope => scope) + params = @params.safeevaluate(scope) parsewrap do scope.setdefaults(type, params) diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index 46c930902..d15f68608 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -17,17 +17,15 @@ class Puppet::Parser::AST # Does not actually return an object; instead sets an object # in the current scope. - def evaluate(hash) - scope = hash[:scope] - + def evaluate(scope) # Get our object reference. - object = @object.safeevaluate(:scope => scope) + object = @object.safeevaluate(scope) hash = {} # Evaluate all of the specified params. params = @params.collect { |param| - param.safeevaluate(:scope => scope) + param.safeevaluate(scope) } # Now we just create a normal resource, but we call a very different diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb index b06ea17be..4bb41165a 100644 --- a/lib/puppet/parser/ast/resource_reference.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -22,10 +22,8 @@ class Puppet::Parser::AST # Evaluate our object, but just return a simple array of the type # and name. - def evaluate(hash) - scope = hash[:scope] - - title = @title.safeevaluate(:scope => scope) + def evaluate(scope) + title = @title.safeevaluate(scope) if @type.to_s.downcase == "class" objtype = "class" title = qualified_class(scope, title) diff --git a/lib/puppet/parser/ast/resourceparam.rb b/lib/puppet/parser/ast/resourceparam.rb index 8b1e7b367..c552a7ee5 100644 --- a/lib/puppet/parser/ast/resourceparam.rb +++ b/lib/puppet/parser/ast/resourceparam.rb @@ -10,12 +10,10 @@ class Puppet::Parser::AST end # Return the parameter and the value. - def evaluate(hash) - scope = hash[:scope] - + def evaluate(scope) return Puppet::Parser::Resource::Param.new( :name => @param, - :value => @value.safeevaluate(:scope => scope), + :value => @value.safeevaluate(scope), :source => scope.source, :line => self.line, :file => self.file, :add => self.add ) diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb index d363ab7e4..399d405a3 100644 --- a/lib/puppet/parser/ast/selector.rb +++ b/lib/puppet/parser/ast/selector.rb @@ -11,13 +11,12 @@ class Puppet::Parser::AST end # Find the value that corresponds with the test. - def evaluate(hash) - scope = hash[:scope] + def evaluate(scope) retvalue = nil found = nil # Get our parameter. - paramvalue = @param.safeevaluate(:scope => scope) + paramvalue = @param.safeevaluate(scope) sensitive = Puppet[:casesensitive] @@ -33,13 +32,13 @@ class Puppet::Parser::AST # Then look for a match in the options. @values.each { |obj| - param = obj.param.safeevaluate(:scope => scope) + param = obj.param.safeevaluate(scope) if ! sensitive && param.respond_to?(:downcase) param = param.downcase end if param == paramvalue # we found a matching option - retvalue = obj.value.safeevaluate(:scope => scope) + retvalue = obj.value.safeevaluate(scope) found = true break elsif obj.param.is_a?(Default) @@ -51,7 +50,7 @@ class Puppet::Parser::AST # Unless we found something, look for the default. unless found if default - retvalue = default.value.safeevaluate(:scope => scope) + retvalue = default.value.safeevaluate(scope) else self.fail Puppet::ParseError, "No matching value for selector param '%s'" % paramvalue diff --git a/lib/puppet/parser/ast/tag.rb b/lib/puppet/parser/ast/tag.rb index e2882d2f0..2909504a7 100644 --- a/lib/puppet/parser/ast/tag.rb +++ b/lib/puppet/parser/ast/tag.rb @@ -8,10 +8,8 @@ class Puppet::Parser::AST @name = :class attr_accessor :type - def evaluate(hash) - scope = hash[:scope] - - types = @type.safeevaluate(:scope => scope) + def evaluate(scope) + types = @type.safeevaluate(scope) types = [types] unless types.is_a? Array diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb index 1e7f874bc..ee79159d7 100644 --- a/lib/puppet/parser/ast/vardef.rb +++ b/lib/puppet/parser/ast/vardef.rb @@ -9,10 +9,9 @@ class Puppet::Parser::AST # Look up our name and value, and store them appropriately. The # lexer strips off the syntax stuff like '$'. - def evaluate(hash) - scope = hash[:scope] - name = @name.safeevaluate(:scope => scope) - value = @value.safeevaluate(:scope => scope) + def evaluate(scope) + name = @name.safeevaluate(scope) + value = @value.safeevaluate(scope) parsewrap do scope.setvar(name,value, @file, @line) diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 58667727f..ea6038299 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -59,7 +59,7 @@ class Puppet::Parser::Resource if klass = @ref.definedtype finish() scope.compile.delete_resource(self) - return klass.evaluate(:scope => scope, :resource => self) + return klass.evaluate(scope, self) elsif builtin? devfail "Cannot evaluate a builtin type" else -- cgit From fb4bdc0b02bba1291cb78ccd5c2a3198d3929d69 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 8 Feb 2008 13:54:53 -0800 Subject: More AST refactoring -- each of the code wrapping classes just returns a resource from its evaluate() method, and all of the work is done in the evaluate_code method. This makes the code cleaner, because it means 1) evaluate() has the same prototype as all of the other AST classes, 2) evaluate() is no longer called indirectly through the Parser Resource class, and 3) the classes themselves are responsible for creating the resources, rather than it being done in the Compile class. --- lib/puppet/parser/ast/definition.rb | 304 ++++++++++++++++++------------------ lib/puppet/parser/ast/hostclass.rb | 113 +++++++------- lib/puppet/parser/ast/node.rb | 96 ++++++------ lib/puppet/parser/resource.rb | 2 +- lib/puppet/parser/resource/param.rb | 2 +- lib/puppet/parser/scope.rb | 5 + 6 files changed, 256 insertions(+), 266 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index 2e39e7332..bf57942d7 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -1,152 +1,145 @@ require 'puppet/parser/ast/branch' -class Puppet::Parser::AST - # Evaluate the stored parse tree for a given component. This will - # receive the arguments passed to the component and also the type and - # name of the component. - class Definition < AST::Branch - include Puppet::Util - include Puppet::Util::Warnings - include Puppet::Util::MethodHelper - class << self - attr_accessor :name - end +require 'puppet/util/warnings' - # The class name - @name = :definition +# The AST class for defined types, which is also the base class +# nodes and classes. +class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch + include Puppet::Util::Warnings + class << self + attr_accessor :name + end - attr_accessor :classname, :arguments, :code, :scope, :keyword - attr_accessor :exported, :namespace, :parser, :virtual + # The class name + @name = :definition - # These are retrieved when looking up the superclass - attr_accessor :name + attr_accessor :classname, :arguments, :code, :scope, :keyword + attr_accessor :exported, :namespace, :parser, :virtual, :name - attr_reader :parentclass + attr_reader :parentclass - def child_of?(klass) - false - end + def child_of?(klass) + false + end - def evaluate(origscope, resource) - # Create a new scope. - scope = subscope(origscope, resource) + # Create a resource that knows how to evaluate our actual code. + def evaluate(scope) + resource = Puppet::Parser::Resource.new(:type => "class", :title => klass.classname, :scope => scope, :source => scope.source) - # Additionally, add a tag for whatever kind of class - # we are - if @classname != "" and ! @classname.nil? - @classname.split(/::/).each { |tag| scope.resource.tag(tag) } - end + scope.compile.store_resource(scope, resource) - [resource.name, resource.title].each do |str| - unless str.nil? or str =~ /[^\w]/ or str == "" - scope.resource.tag(str) - end - end + return resource + end - set_resource_parameters(scope, resource) + # Now evaluate the code associated with this class or definition. + def evaluate_code(resource) + # Create a new scope. + scope = subscope(resource.scope, resource) - if self.code - return self.code.safeevaluate(scope) - else - return nil - end + set_resource_parameters(scope, resource) + + if self.code + return self.code.safeevaluate(scope) + else + return nil end + end - def initialize(hash = {}) - @arguments = nil - @parentclass = nil - super + def initialize(hash = {}) + @arguments = nil + @parentclass = nil + super - # Convert the arguments to a hash for ease of later use. - if @arguments - unless @arguments.is_a? Array - @arguments = [@arguments] - end - oldargs = @arguments - @arguments = {} - oldargs.each do |arg, val| - @arguments[arg] = val - end - else - @arguments = {} + # Convert the arguments to a hash for ease of later use. + if @arguments + unless @arguments.is_a? Array + @arguments = [@arguments] end - - # Deal with metaparams in the argument list. - @arguments.each do |arg, defvalue| - next unless Puppet::Type.metaparamclass(arg) - if defvalue - warnonce "%s is a metaparam; this value will inherit to all contained resources" % arg - else - raise Puppet::ParseError, "%s is a metaparameter; please choose another parameter name in the %s definition" % [arg, self.classname] - end + oldargs = @arguments + @arguments = {} + oldargs.each do |arg, val| + @arguments[arg] = val end + else + @arguments = {} end - def find_parentclass - @parser.findclass(namespace, parentclass) + # Deal with metaparams in the argument list. + @arguments.each do |arg, defvalue| + next unless Puppet::Type.metaparamclass(arg) + if defvalue + warnonce "%s is a metaparam; this value will inherit to all contained resources" % arg + else + raise Puppet::ParseError, "%s is a metaparameter; please choose another parameter name in the %s definition" % [arg, self.classname] + end end + end - # Set our parent class, with a little check to avoid some potential - # weirdness. - def parentclass=(name) - if name == self.classname - parsefail "Parent classes must have dissimilar names" - end + def find_parentclass + @parser.findclass(namespace, parentclass) + end - @parentclass = name + # Set our parent class, with a little check to avoid some potential + # weirdness. + def parentclass=(name) + if name == self.classname + parsefail "Parent classes must have dissimilar names" end - # Hunt down our class object. - def parentobj - if @parentclass - # Cache our result, since it should never change. - unless defined?(@parentobj) - unless tmp = find_parentclass - parsefail "Could not find %s %s" % [self.class.name, @parentclass] - end + @parentclass = name + end - if tmp == self - parsefail "Parent classes must have dissimilar names" - end + # Hunt down our class object. + def parentobj + if @parentclass + # Cache our result, since it should never change. + unless defined?(@parentobj) + unless tmp = find_parentclass + parsefail "Could not find %s %s" % [self.class.name, @parentclass] + end - @parentobj = tmp + if tmp == self + parsefail "Parent classes must have dissimilar names" end - @parentobj - else - nil + + @parentobj = tmp end + @parentobj + else + nil end + end - # Create a new subscope in which to evaluate our code. - def subscope(scope, resource) - args = { - :resource => resource, - :keyword => self.keyword, - :namespace => self.namespace, - :source => self - } + # Create a new subscope in which to evaluate our code. + def subscope(scope, resource) + args = { + :resource => resource, + :keyword => self.keyword, + :namespace => self.namespace, + :source => self + } - oldscope = scope - scope = scope.newscope(args) - scope.source = self + oldscope = scope + scope = scope.newscope(args) + scope.source = self - return scope - end + return scope + end - def to_s - classname - end + def to_s + classname + end - # Check whether a given argument is valid. Searches up through - # any parent classes that might exist. - def validattr?(param) - param = param.to_s + # Check whether a given argument is valid. Searches up through + # any parent classes that might exist. + def validattr?(param) + param = param.to_s - if @arguments.include?(param) - # It's a valid arg for us - return true - elsif param == "name" - return true + if @arguments.include?(param) + # It's a valid arg for us + return true + elsif param == "name" + return true # elsif defined? @parentclass and @parentclass # # Else, check any existing parent # if parent = @scope.lookuptype(@parentclass) and parent != [] @@ -157,53 +150,52 @@ class Puppet::Parser::AST # raise Puppet::Error, "Could not find parent class %s" % # @parentclass # end - elsif Puppet::Type.metaparam?(param) - return true - else - # Or just return false - return false - end + elsif Puppet::Type.metaparam?(param) + return true + else + # Or just return false + return false end + end - private - - # Set any arguments passed by the resource as variables in the scope. - def set_resource_parameters(scope, resource) - args = symbolize_options(resource.to_hash || {}) - - # Verify that all required arguments are either present or - # have been provided with defaults. - if self.arguments - self.arguments.each { |arg, default| - arg = symbolize(arg) - unless args.include?(arg) - if defined? default and ! default.nil? - default = default.safeevaluate scope - args[arg] = default - #Puppet.debug "Got default %s for %s in %s" % - # [default.inspect, arg.inspect, @name.inspect] - else - parsefail "Must pass %s to %s of type %s" % - [arg, resource.title, @classname] - end + private + + # Set any arguments passed by the resource as variables in the scope. + def set_resource_parameters(scope, resource) + args = symbolize_options(resource.to_hash || {}) + + # Verify that all required arguments are either present or + # have been provided with defaults. + if self.arguments + self.arguments.each { |arg, default| + arg = arg.to_sym + unless args.include?(arg) + if defined? default and ! default.nil? + default = default.safeevaluate scope + args[arg] = default + #Puppet.debug "Got default %s for %s in %s" % + # [default.inspect, arg.inspect, @name.inspect] + else + parsefail "Must pass %s to %s of type %s" % + [arg, resource.title, @classname] end - } - end - - # Set each of the provided arguments as variables in the - # definition's scope. - args.each { |arg,value| - unless validattr?(arg) - parsefail "%s does not accept attribute %s" % [@classname, arg] - end - - exceptwrap do - scope.setvar(arg.to_s, args[arg]) end } - - scope.setvar("title", resource.title) unless args.include? :title - scope.setvar("name", resource.name) unless args.include? :name end + + # Set each of the provided arguments as variables in the + # definition's scope. + args.each { |arg,value| + unless validattr?(arg) + parsefail "%s does not accept attribute %s" % [@classname, arg] + end + + exceptwrap do + scope.setvar(arg.to_s, args[arg]) + end + } + + scope.setvar("title", resource.title) unless args.include? :title + scope.setvar("name", resource.name) unless args.include? :name end end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 42d13f4b2..251d5eba6 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -1,78 +1,73 @@ require 'puppet/parser/ast/definition' -class Puppet::Parser::AST - # The code associated with a class. This is different from definitions - # in that each class is a singleton -- only one will exist for a given - # node. - class HostClass < AST::Definition - @name = :class +# The code associated with a class. This is different from definitions +# in that each class is a singleton -- only one will exist for a given +# node. +class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition + @name = :class - # Are we a child of the passed class? Do a recursive search up our - # parentage tree to figure it out. - def child_of?(klass) - return false unless self.parentclass + # Are we a child of the passed class? Do a recursive search up our + # parentage tree to figure it out. + def child_of?(klass) + return false unless self.parentclass - if klass == self.parentobj - return true - else - return self.parentobj.child_of?(klass) - end + if klass == self.parentobj + return true + else + return self.parentobj.child_of?(klass) end + end - # Evaluate the code associated with this class. - def evaluate(scope, resource) - # Verify that we haven't already been evaluated. This is - # what provides the singleton aspect. - if existing_scope = scope.compile.class_scope(self) - Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname) - return nil - end - - scope.compile.catalog.tag(self.classname) + # Evaluate the code associated with this class. + def evaluate_code(resource) + scope = resource.scope + # Verify that we haven't already been evaluated. This is + # what provides the singleton aspect. + if existing_scope = scope.compile.class_scope(self) + Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname) + return nil + end - pnames = nil - if pklass = self.parentobj - pklass.safeevaluate(scope, resource) + pnames = nil + if pklass = self.parentobj + pklass.evaluate_code(resource) - scope = parent_scope(scope, pklass) - pnames = scope.namespaces - end + scope = parent_scope(scope, pklass) + pnames = scope.namespaces + end - # Don't create a subscope for the top-level class, since it already - # has its own scope. - unless resource.title == :main - scope = subscope(scope, resource) - end + # Don't create a subscope for the top-level class, since it already + # has its own scope. + scope = subscope(scope, resource) unless resource.title == :main - if pnames - pnames.each do |ns| - scope.add_namespace(ns) - end + if pnames + pnames.each do |ns| + scope.add_namespace(ns) end + end - # Set the class before we do anything else, so that it's set - # during the evaluation and can be inspected. - scope.compile.class_set(self.classname, scope) + # Set the class before we do anything else, so that it's set + # during the evaluation and can be inspected. + scope.compile.class_set(self.classname, scope) - # Now evaluate our code, yo. - if self.code - return self.code.safeevaluate(scope) - else - return nil - end + # Now evaluate our code, yo. + if self.code + return self.code.safeevaluate(scope) + else + return nil end + end - def initialize(options) - @parentclass = nil - super - end + def initialize(options) + @parentclass = nil + super + end - def parent_scope(scope, klass) - if s = scope.compile.class_scope(klass) - return s - else - raise Puppet::DevError, "Could not find scope for %s" % klass.classname - end + def parent_scope(scope, klass) + if s = scope.compile.class_scope(klass) + return s + else + raise Puppet::DevError, "Could not find scope for %s" % klass.classname end end end diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index 3c5d44d1b..7ff7a18e1 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -1,59 +1,57 @@ require 'puppet/parser/ast/hostclass' -class Puppet::Parser::AST - # The specific code associated with a host. Nodes are annoyingly unlike - # other objects. That's just the way it is, at least for now. - class Node < AST::HostClass - @name = :node - attr_accessor :name - - def evaluate(scope, resource) - # We don't have to worry about the declarativeness of node parentage, - # because the entry point is always a single node definition. - if parent = self.parentobj - scope = parent.safeevaluate scope, resource - end - - scope = scope.newscope( - :resource => resource, - :keyword => @keyword, - :source => self, - :namespace => "" # nodes are always in "" - ) - - # Mark our node name as a class, too, but strip it of the domain - # name. Make the mark before we evaluate the code, so that it is - # marked within the code itself. - scope.compile.class_set(self.classname, scope) - - # And then evaluate our code if we have any - if self.code - @code.safeevaluate(scope) - end - - return scope +# The specific code associated with a host. Nodes are annoyingly unlike +# other objects. That's just the way it is, at least for now. +class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass + @name = :node + + # Evaluate the code associated with our node definition. + def evaluate_code(resource) + scope = resource.scope + + # We don't have to worry about the declarativeness of node parentage, + # because the entry point is always a single node definition. + if parent = self.parentobj + scope = parent.evaluate_code(resource) end - def initialize(options) - @parentclass = nil - super + scope = scope.newscope( + :resource => resource, + :keyword => @keyword, + :source => self, + :namespace => "" # nodes are always in "" + ) - # Do some validation on the node name - if @name =~ /[^-\w.]/ - raise Puppet::ParseError, "Invalid node name %s" % @name - end - end + # Mark our node name as a class, too, but strip it of the domain + # name. Make the mark before we evaluate the code, so that it is + # marked within the code itself. + scope.compile.class_set(self.classname, scope) - # Make sure node scopes are marked as such. - def subscope(*args) - scope = super - scope.nodescope = true - end + # And then evaluate our code if we have any + @code.safeevaluate(scope) if self.code + + return scope + end + + def initialize(options) + @parentclass = nil + super - private - # Search for the object matching our parent class. - def find_parentclass - @parser.findnode(parentclass) + # Do some validation on the node name + if @name =~ /[^-\w.]/ + raise Puppet::ParseError, "Invalid node name %s" % @name end end + + # Make sure node scopes are marked as such. + def subscope(*args) + scope = super + scope.nodescope = true + end + + private + # Search for the object matching our parent class. + def find_parentclass + @parser.findnode(parentclass) + end end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index ea6038299..f8701578c 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -59,7 +59,7 @@ class Puppet::Parser::Resource if klass = @ref.definedtype finish() scope.compile.delete_resource(self) - return klass.evaluate(scope, self) + return klass.evaluate_code(self) elsif builtin? devfail "Cannot evaluate a builtin type" else diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb index 9352311d6..9dd3f26d2 100644 --- a/lib/puppet/parser/resource/param.rb +++ b/lib/puppet/parser/resource/param.rb @@ -12,7 +12,7 @@ class Puppet::Parser::Resource::Param end def inspect - "#<#{self.class} @name => #{self.name}, @value => #{self.value}, @source => #{self.source.name}>" + "#<#{self.class} @name => #{name}, @value => #{value}, @source => #{source.name}>" end def line_to_i diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 028414cc0..81d4ac71a 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -19,6 +19,11 @@ class Puppet::Parser::Scope attr_accessor :base, :keyword, :nodescope attr_accessor :top, :translated, :compile + # A demeterific shortcut to the catalog. + def catalog + compile.catalog + end + # Proxy accessors def host @compile.node.name -- cgit From 194e7309c9c481f7e67bd63b13e2fc80fe0a4f00 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 12:37:00 -0800 Subject: Moving all of the tests for Puppet::Parser::Compile to rspec, so I can refactor the class to more heavily rely on a Node::Catalog instead of doing its own resource container management. --- lib/puppet/parser/compile.rb | 21 ++++++++++++++++----- lib/puppet/parser/resource.rb | 14 -------------- lib/puppet/parser/resource/reference.rb | 2 +- 3 files changed, 17 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index e1e230d48..42d229867 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -68,10 +68,10 @@ class Puppet::Parser::Compile evaluate_generators() - fail_on_unevaluated() - finish() + fail_on_unevaluated() + if Puppet[:storeconfigs] store() end @@ -200,8 +200,6 @@ class Puppet::Parser::Compile # Store a resource override. def store_override(override) - override.override = true - # If possible, merge the override in immediately. if resource = @resource_table[override.ref] resource.merge(override) @@ -383,7 +381,20 @@ class Puppet::Parser::Compile # Make sure all of our resources and such have done any last work # necessary. def finish - @resource_table.each { |name, resource| resource.finish if resource.respond_to?(:finish) } + @resource_table.each do |name, 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) + end end # Initialize the top-level scope, class, and resource. diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index f8701578c..67428d5f3 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -83,7 +83,6 @@ class Puppet::Parser::Resource # Do any finishing work on this object, called before evaluation or # before storage/translation. def finish - add_overrides() add_defaults() add_metaparams() add_scope_tags() @@ -342,19 +341,6 @@ class Puppet::Parser::Resource end end - # Add any overrides for this object. - def add_overrides - if overrides = scope.compile.resource_overrides(self) - overrides.each do |over| - self.merge(over) - end - - # Remove the overrides, so that the configuration knows there - # are none left. - overrides.clear - end - end - def add_scope_tags if scope_resource = scope.resource tag(*scope_resource.tags) diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb index 6e70d23b7..ea53b421a 100644 --- a/lib/puppet/parser/resource/reference.rb +++ b/lib/puppet/parser/resource/reference.rb @@ -49,7 +49,7 @@ class Puppet::Parser::Resource::Reference < Puppet::ResourceReference if tmp @definedtype = tmp else - fail Puppet::ParseError, "Could not find resource '%s'" % self + fail Puppet::ParseError, "Could not find resource type '%s'" % self.type end end -- cgit From 3b740ff7a6ab7127ec5e4935782c33245687c429 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 13:59:25 -0800 Subject: Converting the Compile class to use a Node::Catalog instance as its resource container, instead of having its own behaviour around resource uniqueness. --- lib/puppet/node/catalog.rb | 26 ++++++++++++++++- lib/puppet/parser/compile.rb | 67 +++++++------------------------------------ lib/puppet/parser/resource.rb | 1 - 3 files changed, 36 insertions(+), 58 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index 9601309d8..03187cc94 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -64,7 +64,7 @@ class Puppet::Node::Catalog < Puppet::PGraph else @resource_table[ref] = resource end - resource.catalog = self unless is_relationship_graph + resource.catalog = self if resource.respond_to?(:catalog=) and ! is_relationship_graph add_vertex!(resource) end end @@ -491,4 +491,28 @@ class Puppet::Node::Catalog < Puppet::PGraph return result end + + # Verify that the given resource isn't defined elsewhere. + def verify_resource_uniqueness(resource) + # Short-curcuit the common case, + unless existing_resource = @resource_table[resource.ref] + return true + end + + # Either it's a defined type, which are never + # isomorphic, or it's a non-isomorphic type, so + # we should throw an exception. + msg = "Duplicate definition: %s is already defined" % resource.ref + + if existing_resource.file and existing_resource.line + msg << " in file %s at line %s" % + [existing_resource.file, existing_resource.line] + end + + if resource.line or resource.file + msg << "; cannot redefine" + end + + raise Puppet::ParseError.new(msg) + end end diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index 42d229867..46ce1cb9b 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -84,11 +84,6 @@ class Puppet::Parser::Compile @collections.delete(coll) if @collections.include?(coll) end - # LAK:FIXME There are no tests for this. - def delete_resource(resource) - @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref) - end - # Return the node's environment. def environment unless defined? @environment @@ -140,10 +135,8 @@ class Puppet::Parser::Compile end # Return a resource by either its ref or its type and title. - def findresource(string, name = nil) - string = "%s[%s]" % [string.capitalize, name] if name - - @resource_table[string] + def findresource(*args) + @catalog.resource(*args) end # Set up our compile. We require a parser @@ -195,13 +188,13 @@ class Puppet::Parser::Compile # Return a list of all resources. def resources - @resource_table.values + @catalog.vertices end # Store a resource override. def store_override(override) # If possible, merge the override in immediately. - if resource = @resource_table[override.ref] + if resource = @catalog.resource(override.ref) resource.merge(override) else # Otherwise, store the override for later; these @@ -212,11 +205,7 @@ class Puppet::Parser::Compile # Store a resource in our resource table. def store_resource(scope, resource) - # This might throw an exception - verify_uniqueness(resource) - - # Store it in the global table. - @resource_table[resource.ref] = resource + @catalog.add_resource(resource) # And in the resource graph. At some point, this might supercede # the global resource table, but the table is a lot faster @@ -323,9 +312,7 @@ class Puppet::Parser::Compile @main_resource = Puppet::Parser::Resource.new(:type => "class", :title => :main, :scope => @topscope, :source => @main) @topscope.resource = @main_resource - @catalog.add_vertex!(@main_resource) - - @resource_table["Class[main]"] = @main_resource + @catalog.add_resource(@main_resource) @main_resource.evaluate end @@ -381,7 +368,9 @@ class Puppet::Parser::Compile # Make sure all of our resources and such have done any last work # necessary. def finish - @resource_table.each do |name, resource| + @catalog.resources.each do |name| + resource = @catalog.resource(name) + # Add in any resource overrides. if overrides = resource_overrides(resource) overrides.each do |over| @@ -410,9 +399,6 @@ class Puppet::Parser::Compile # be used by top scopes and node scopes. @class_scopes = {} - # The table for all defined resources. - @resource_table = {} - # The list of objects that will available for export. @exported_resources = {} @@ -457,7 +443,7 @@ class Puppet::Parser::Compile # We used to have hooks here for forking and saving, but I don't # think it's worth retaining at this point. - store_to_active_record(@node, @resource_table.values) + store_to_active_record(@node, @catalog.vertices) end # Do the actual storage. @@ -480,9 +466,7 @@ class Puppet::Parser::Compile # 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 = @resource_table.find_all do |name, object| - ! object.builtin? and ! object.evaluated? - end.collect { |name, object| object } + ary = @catalog.vertices.reject { |resource| resource.builtin? or resource.evaluated? } if ary.empty? return nil @@ -490,33 +474,4 @@ class Puppet::Parser::Compile return ary end end - - # Verify that the given resource isn't defined elsewhere. - def verify_uniqueness(resource) - # Short-curcuit the common case, - unless existing_resource = @resource_table[resource.ref] - return true - end - - if typeclass = Puppet::Type.type(resource.type) and ! typeclass.isomorphic? - Puppet.info "Allowing duplicate %s" % typeclass.name - return true - end - - # Either it's a defined type, which are never - # isomorphic, or it's a non-isomorphic type, so - # we should throw an exception. - msg = "Duplicate definition: %s is already defined" % resource.ref - - if existing_resource.file and existing_resource.line - msg << " in file %s at line %s" % - [existing_resource.file, existing_resource.line] - end - - if resource.line or resource.file - msg << "; cannot redefine" - end - - raise Puppet::ParseError.new(msg) - end end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 67428d5f3..fb0799011 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -58,7 +58,6 @@ class Puppet::Parser::Resource def evaluate if klass = @ref.definedtype finish() - scope.compile.delete_resource(self) return klass.evaluate_code(self) elsif builtin? devfail "Cannot evaluate a builtin type" -- cgit From 6a4cf6c978e8c8aebba4ed0f16d3de7bb31a0ce0 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:24:02 -0600 Subject: Fixed #1030 - class and definition evaluation has been significantly refactored, fixing this problem and making the whole interplay between the classes, definitions, and nodes, and the Compile class much cleaner. --- lib/puppet/node/catalog.rb | 5 +++++ lib/puppet/parser/ast/definition.rb | 31 +++++++++++++++++-------------- lib/puppet/parser/ast/hostclass.rb | 14 +++++++++----- lib/puppet/parser/compile.rb | 10 +--------- 4 files changed, 32 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index 03187cc94..f93d2786d 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -395,6 +395,11 @@ class Puppet::Node::Catalog < Puppet::PGraph nil end + # Does our tag list include this tag? + def tagged?(tag) + @tags.include?(tag) + end + # Return the list of tags. def tags @tags.dup diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index bf57942d7..e3f6414c3 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -24,7 +24,12 @@ class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch # Create a resource that knows how to evaluate our actual code. def evaluate(scope) - resource = Puppet::Parser::Resource.new(:type => "class", :title => klass.classname, :scope => scope, :source => scope.source) + # Do nothing if the resource already exists; this provides the singleton nature classes need. + return if scope.catalog.resource(:class, self.classname) + + resource = Puppet::Parser::Resource.new(:type => "class", :title => self.classname, :scope => scope, :source => scope.source) + + scope.catalog.tag(*resource.tags) scope.compile.store_resource(scope, resource) @@ -91,23 +96,21 @@ class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch # Hunt down our class object. def parentobj - if @parentclass - # Cache our result, since it should never change. - unless defined?(@parentobj) - unless tmp = find_parentclass - parsefail "Could not find %s %s" % [self.class.name, @parentclass] - end + return nil unless @parentclass - if tmp == self - parsefail "Parent classes must have dissimilar names" - end + # Cache our result, since it should never change. + unless defined?(@parentobj) + unless tmp = find_parentclass + parsefail "Could not find %s parent %s" % [self.class.name, @parentclass] + end - @parentobj = tmp + if tmp == self + parsefail "Parent classes must have dissimilar names" end - @parentobj - else - nil + + @parentobj = tmp end + @parentobj end # Create a new subscope in which to evaluate our code. diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 251d5eba6..4f2d00f0c 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -18,6 +18,15 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition end end + # Make sure our parent class has been evaluated, if we have one. + def evaluate(scope) + if parentclass and ! scope.catalog.resource(:class, parentclass) + resource = parentobj.evaluate(scope) + end + + super + end + # Evaluate the code associated with this class. def evaluate_code(resource) scope = resource.scope @@ -58,11 +67,6 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition end end - def initialize(options) - @parentclass = nil - super - end - def parent_scope(scope, klass) if s = scope.compile.class_scope(klass) return s diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index 46ce1cb9b..bceead271 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -115,16 +115,11 @@ class Puppet::Parser::Compile if klass = scope.findclass(name) found << name and next if class_scope(klass) - # Create a resource to model this class, and then add it to the list - # of resources. - resource = Puppet::Parser::Resource.new(:type => "class", :title => klass.classname, :scope => scope, :source => scope.source) - - store_resource(scope, resource) + resource = klass.evaluate(scope) # If they've disabled lazy evaluation (which the :include function does), # then evaluate our resource immediately. resource.evaluate unless lazy_evaluate - @catalog.tag(klass.classname) found << name else Puppet.info "Could not find class %s for %s" % [name, node.name] @@ -412,9 +407,6 @@ class Puppet::Parser::Compile # but they each refer back to the scope that created them. @collections = [] - # A list of tags we've generated; most class names. - @tags = [] - # A graph for maintaining scope relationships. @scope_graph = Puppet::SimpleGraph.new -- cgit From e247b56d9941b4a636d3a3d9935d6b9cd9b199ea Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:33:12 -0600 Subject: Changing some methods in the Compile class to be more internally consistent (switched store_resource to add_resource, and store_override to add_override). --- lib/puppet/parser/ast/definition.rb | 2 +- lib/puppet/parser/ast/resource.rb | 2 +- lib/puppet/parser/ast/resource_override.rb | 2 +- lib/puppet/parser/collector.rb | 2 +- lib/puppet/parser/compile.rb | 46 +++++++++++++++--------------- 5 files changed, 27 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index e3f6414c3..992bb1f5e 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -31,7 +31,7 @@ class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch scope.catalog.tag(*resource.tags) - scope.compile.store_resource(scope, resource) + scope.compile.add_resource(scope, resource) return resource end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 606beb537..2dadf9ed6 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -51,7 +51,7 @@ class Resource < AST::ResourceReference # And then store the resource in the compile. # At some point, we need to switch all of this to return # objects instead of storing them like this. - scope.compile.store_resource(scope, obj) + scope.compile.add_resource(scope, obj) obj end }.reject { |obj| obj.nil? } diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index d15f68608..db0986a8e 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -42,7 +42,7 @@ class Puppet::Parser::AST # Now we tell the scope that it's an override, and it behaves as # necessary. - scope.compile.store_override(obj) + scope.compile.add_override(obj) obj end diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index b8165a84f..efd64a320 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -150,7 +150,7 @@ class Puppet::Parser::Collector resource.exported = false - scope.compile.store_resource(scope, resource) + scope.compile.add_resource(scope, resource) return resource end diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index bceead271..f68796843 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -17,6 +17,28 @@ class Puppet::Parser::Compile @collections << coll 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 + + # Store a resource in our resource table. + def add_resource(scope, resource) + @catalog.add_resource(resource) + + # And in the resource graph. At some point, this might supercede + # the global resource table, but the table is a lot faster + # so it makes sense to maintain for now. + @catalog.add_edge!(scope.resource, resource) + end + # Do we use nodes found in the code, vs. the external node sources? def ast_nodes? parser.nodes.length > 0 @@ -186,28 +208,6 @@ class Puppet::Parser::Compile @catalog.vertices end - # Store a resource override. - def store_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 - - # Store a resource in our resource table. - def store_resource(scope, resource) - @catalog.add_resource(resource) - - # And in the resource graph. At some point, this might supercede - # the global resource table, but the table is a lot faster - # so it makes sense to maintain for now. - @catalog.add_edge!(scope.resource, resource) - 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 @@ -233,7 +233,7 @@ class Puppet::Parser::Compile # Create a resource to model this node, and then add it to the list # of resources. resource = Puppet::Parser::Resource.new(:type => "node", :title => astnode.classname, :scope => topscope, :source => topscope.source) - store_resource(topscope, resource) + add_resource(topscope, resource) @catalog.tag(astnode.classname) resource.evaluate -- cgit From 5ebaa8953155d091ed5b5c68c3862c9f695f03c0 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:41:19 -0600 Subject: Refactoring the interface between the Compile class and the AST::Node class to match that to the definitions and AST classes. --- lib/puppet/parser/compile.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index f68796843..2415fd5e8 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -232,9 +232,7 @@ class Puppet::Parser::Compile # Create a resource to model this node, and then add it to the list # of resources. - resource = Puppet::Parser::Resource.new(:type => "node", :title => astnode.classname, :scope => topscope, :source => topscope.source) - add_resource(topscope, resource) - @catalog.tag(astnode.classname) + resource = astnode.evaluate(topscope) resource.evaluate -- cgit From fd0c5cbddec8dc53196a3b84e33e1000c3c0720f Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:59:34 -0600 Subject: Changing the name of the Compile class to Compiler, since it's stupid to have a class named after a verb. --- lib/puppet/parser/ast/collection.rb | 2 +- lib/puppet/parser/ast/definition.rb | 2 +- lib/puppet/parser/ast/hostclass.rb | 6 +- lib/puppet/parser/ast/node.rb | 2 +- lib/puppet/parser/ast/resource.rb | 4 +- lib/puppet/parser/ast/resource_override.rb | 2 +- lib/puppet/parser/collector.rb | 8 +- lib/puppet/parser/compile.rb | 467 ----------------------------- lib/puppet/parser/compiler.rb | 467 +++++++++++++++++++++++++++++ lib/puppet/parser/functions.rb | 6 +- lib/puppet/parser/interpreter.rb | 4 +- lib/puppet/parser/scope.rb | 16 +- lib/puppet/parser/templatewrapper.rb | 2 +- 13 files changed, 494 insertions(+), 494 deletions(-) delete mode 100644 lib/puppet/parser/compile.rb create mode 100644 lib/puppet/parser/compiler.rb (limited to 'lib') diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index 31f508929..9e795a33c 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -18,7 +18,7 @@ class Collection < AST::Branch newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) - scope.compile.add_collection(newcoll) + scope.compiler.add_collection(newcoll) newcoll end diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index 992bb1f5e..b4a90016a 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -31,7 +31,7 @@ class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch scope.catalog.tag(*resource.tags) - scope.compile.add_resource(scope, resource) + scope.compiler.add_resource(scope, resource) return resource end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 4f2d00f0c..f49016526 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -32,7 +32,7 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition scope = resource.scope # Verify that we haven't already been evaluated. This is # what provides the singleton aspect. - if existing_scope = scope.compile.class_scope(self) + if existing_scope = scope.compiler.class_scope(self) Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname) return nil end @@ -57,7 +57,7 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition # Set the class before we do anything else, so that it's set # during the evaluation and can be inspected. - scope.compile.class_set(self.classname, scope) + scope.compiler.class_set(self.classname, scope) # Now evaluate our code, yo. if self.code @@ -68,7 +68,7 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition end def parent_scope(scope, klass) - if s = scope.compile.class_scope(klass) + if s = scope.compiler.class_scope(klass) return s else raise Puppet::DevError, "Could not find scope for %s" % klass.classname diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index 7ff7a18e1..8cebac8a8 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -25,7 +25,7 @@ class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass # Mark our node name as a class, too, but strip it of the domain # name. Make the mark before we evaluate the code, so that it is # marked within the code itself. - scope.compile.class_set(self.classname, scope) + scope.compiler.class_set(self.classname, scope) # And then evaluate our code if we have any @code.safeevaluate(scope) if self.code diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 2dadf9ed6..8a60522a3 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -48,10 +48,10 @@ class Resource < AST::ResourceReference :scope => scope ) - # And then store the resource in the compile. + # And then store the resource in the compiler. # At some point, we need to switch all of this to return # objects instead of storing them like this. - scope.compile.add_resource(scope, obj) + scope.compiler.add_resource(scope, obj) obj end }.reject { |obj| obj.nil? } diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index db0986a8e..f9464acda 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -42,7 +42,7 @@ class Puppet::Parser::AST # Now we tell the scope that it's an override, and it behaves as # necessary. - scope.compile.add_override(obj) + scope.compiler.add_override(obj) obj end diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index efd64a320..e0c37cd35 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -118,20 +118,20 @@ class Puppet::Parser::Collector # If there are no more resources to find, delete this from the list # of collections. if @resources.empty? - @scope.compile.delete_collection(self) + @scope.compiler.delete_collection(self) end return result end - # Collect just virtual objects, from our local compile. + # Collect just virtual objects, from our local compiler. def collect_virtual(exported = false) if exported method = :exported? else method = :virtual? end - scope.compile.resources.find_all do |resource| + scope.compiler.resources.find_all do |resource| resource.type == @type and resource.send(method) and match?(resource) end end @@ -150,7 +150,7 @@ class Puppet::Parser::Collector resource.exported = false - scope.compile.add_resource(scope, resource) + scope.compiler.add_resource(scope, resource) return resource end diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb deleted file mode 100644 index 2415fd5e8..000000000 --- a/lib/puppet/parser/compile.rb +++ /dev/null @@ -1,467 +0,0 @@ -# Created by Luke A. Kanies on 2007-08-13. -# Copyright (c) 2007. All rights reserved. - -require 'puppet/node' -require 'puppet/node/catalog' -require 'puppet/util/errors' - -# Maintain a graph of scopes, along with a bunch of data -# about the individual catalog we're compiling. -class Puppet::Parser::Compile - include Puppet::Util - include Puppet::Util::Errors - attr_reader :parser, :node, :facts, :collections, :catalog, :node_scope - - # Add a collection to the global list. - def add_collection(coll) - @collections << coll - 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 - - # Store a resource in our resource table. - def add_resource(scope, resource) - @catalog.add_resource(resource) - - # And in the resource graph. At some point, this might supercede - # the global resource table, but the table is a lot faster - # so it makes sense to maintain for now. - @catalog.add_edge!(scope.resource, resource) - end - - # Do we use nodes found in the code, vs. the external node sources? - def ast_nodes? - parser.nodes.length > 0 - 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) - if existing = @class_scopes[name] - if existing.nodescope? or scope.nodescope? - raise Puppet::ParseError, "Cannot have classes, nodes, or definitions with the same name" - else - raise Puppet::DevError, "Somehow evaluated the same class twice" - end - end - @class_scopes[name] = scope - @catalog.add_class(name) unless name == "" - 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 - if klass.respond_to?(:classname) - @class_scopes[klass.classname] - else - @class_scopes[klass] - end - end - - # Return a list of all of the defined classes. - def classlist - return @catalog.classes - end - - # Compile 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() - - evaluate_main() - - evaluate_ast_node() - - evaluate_node_classes() - - evaluate_generators() - - finish() - - fail_on_unevaluated() - - if Puppet[:storeconfigs] - store() - end - - return @catalog - end - - # LAK:FIXME There are no tests for this. - def delete_collection(coll) - @collections.delete(coll) if @collections.include?(coll) - end - - # Return the node's environment. - def environment - unless defined? @environment - if node.environment and node.environment != "" - @environment = node.environment - else - @environment = nil - end - end - @environment - end - - # 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) - unless scope.source - raise Puppet::DevError, "No source for scope passed to evaluate_classes" - end - found = [] - classes.each do |name| - # If we can find the class, then make a resource that will evaluate it. - if klass = scope.findclass(name) - found << name and next if class_scope(klass) - - resource = klass.evaluate(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 %s for %s" % [name, node.name] - @catalog.tag(name) - end - end - found - end - - # Return a resource by either its ref or its type and title. - def findresource(*args) - @catalog.resource(*args) - end - - # Set up our compile. We require a parser - # and a node object; the parser is so we can look up classes - # and AST nodes, and the node has all of the client's info, - # like facts and environment. - def initialize(node, parser, options = {}) - @node = node - @parser = parser - - options.each do |param, value| - begin - send(param.to_s + "=", value) - rescue NoMethodError - raise ArgumentError, "Compile objects do not accept %s" % param - end - end - - initvars() - init_main() - end - - # Create a new scope, with either a specified parent scope or - # using the top scope. Adds an edge between the scope and - # its parent to the graph. - def newscope(parent, options = {}) - parent ||= topscope - options[:compile] = self - options[:parser] ||= self.parser - scope = Puppet::Parser::Scope.new(options) - @scope_graph.add_edge!(parent, scope) - scope - end - - # Find the parent of a given scope. Assumes scopes only ever have - # one in edge, which will always be true. - def parent(scope) - if ary = @scope_graph.adjacent(scope, :direction => :in) and ary.length > 0 - ary[0] - else - nil - end - end - - # Return any overrides for the given resource. - def resource_overrides(resource) - @resource_overrides[resource.ref] - end - - # Return a list of all resources. - def resources - @catalog.vertices - 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 = @parser.nodes[name.to_s.downcase] - end - - unless (astnode ||= @parser.nodes["default"]) - raise Puppet::ParseError, "Could not find default node or by name with '%s'" % node.names.join(", ") - end - - # Create a resource to model this node, and then add it to the list - # of resources. - resource = astnode.evaluate(topscope) - - resource.evaluate - - # Now set the node scope appropriately, so that :topscope can - # behave differently. - @node_scope = 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 - - return 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 - ary.each do |resource| - resource.evaluate - end - # If we evaluated, let the loop know. - return true - 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 = @parser.findclass("", "") || @parser.newclass("") - @topscope.source = @main - @main_resource = Puppet::Parser::Resource.new(:type => "class", :title => :main, :scope => @topscope, :source => @main) - @topscope.resource = @main_resource - - @catalog.add_resource(@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 object(s) %s" % 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 - end - end - - unless remaining.empty? - raise Puppet::ParseError, "Failed to realize virtual resources %s" % - remaining.join(', ') - end - end - - # Make sure all of our resources and such have done any last work - # necessary. - def finish - @catalog.resources.each do |name| - resource = @catalog.resource(name) - - # 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) - end - end - - # Initialize the top-level scope, class, and resource. - def init_main - # Create our initial scope and a resource that will evaluate main. - @topscope = Puppet::Parser::Scope.new(:compile => self, :parser => self.parser) - @scope_graph.add_vertex!(@topscope) - end - - # Set up all of our internal variables. - def initvars - # The table for storing class singletons. This will only actually - # be used by top scopes and node scopes. - @class_scopes = {} - - # 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 collections that have been created. This is a global list, - # but they each refer back to the scope that created them. - @collections = [] - - # A graph for maintaining scope relationships. - @scope_graph = Puppet::SimpleGraph.new - - # For maintaining the relationship between scopes and their resources. - @catalog = Puppet::Node::Catalog.new(@node.name) - @catalog.version = @parser.version - 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 - end - - # Store the catalog into the database. - def store - unless Puppet.features.rails? - raise Puppet::Error, - "storeconfigs is enabled but rails is unavailable" - end - - unless ActiveRecord::Base.connected? - Puppet::Rails.connect - end - - # We used to have hooks here for forking and saving, but I don't - # think it's worth retaining at this point. - store_to_active_record(@node, @catalog.vertices) - end - - # Do the actual storage. - def store_to_active_record(node, resources) - begin - # We store all of the objects, even the collectable ones - benchmark(:info, "Stored catalog for #{node.name}") do - Puppet::Rails::Host.transaction do - Puppet::Rails::Host.store(node, resources) - end - end - rescue => detail - if Puppet[:trace] - puts detail.backtrace - end - Puppet.err "Could not store configs: %s" % detail.to_s - 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 = @catalog.vertices.reject { |resource| resource.builtin? or resource.evaluated? } - - if ary.empty? - return nil - else - return ary - end - end -end diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb new file mode 100644 index 000000000..27860487a --- /dev/null +++ b/lib/puppet/parser/compiler.rb @@ -0,0 +1,467 @@ +# Created by Luke A. Kanies on 2007-08-13. +# Copyright (c) 2007. All rights reserved. + +require 'puppet/node' +require 'puppet/node/catalog' +require 'puppet/util/errors' + +# 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 + attr_reader :parser, :node, :facts, :collections, :catalog, :node_scope + + # Add a collection to the global list. + def add_collection(coll) + @collections << coll + 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 + + # Store a resource in our resource table. + def add_resource(scope, resource) + @catalog.add_resource(resource) + + # And in the resource graph. At some point, this might supercede + # the global resource table, but the table is a lot faster + # so it makes sense to maintain for now. + @catalog.add_edge!(scope.resource, resource) + end + + # Do we use nodes found in the code, vs. the external node sources? + def ast_nodes? + parser.nodes.length > 0 + 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) + if existing = @class_scopes[name] + if existing.nodescope? or scope.nodescope? + raise Puppet::ParseError, "Cannot have classes, nodes, or definitions with the same name" + else + raise Puppet::DevError, "Somehow evaluated the same class twice" + end + end + @class_scopes[name] = scope + @catalog.add_class(name) unless name == "" + 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 + if klass.respond_to?(:classname) + @class_scopes[klass.classname] + else + @class_scopes[klass] + end + end + + # Return a list of all of the defined classes. + def classlist + return @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() + + evaluate_main() + + evaluate_ast_node() + + evaluate_node_classes() + + evaluate_generators() + + finish() + + fail_on_unevaluated() + + if Puppet[:storeconfigs] + store() + end + + return @catalog + end + + # LAK:FIXME There are no tests for this. + def delete_collection(coll) + @collections.delete(coll) if @collections.include?(coll) + end + + # Return the node's environment. + def environment + unless defined? @environment + if node.environment and node.environment != "" + @environment = node.environment + else + @environment = nil + end + end + @environment + end + + # 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) + unless scope.source + raise Puppet::DevError, "No source for scope passed to evaluate_classes" + end + found = [] + classes.each do |name| + # If we can find the class, then make a resource that will evaluate it. + if klass = scope.findclass(name) + found << name and next if class_scope(klass) + + resource = klass.evaluate(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 %s for %s" % [name, node.name] + @catalog.tag(name) + end + end + found + end + + # Return a resource by either its ref or its type and title. + def findresource(*args) + @catalog.resource(*args) + end + + # Set up our compile. We require a parser + # and a node object; the parser is so we can look up classes + # and AST nodes, and the node has all of the client's info, + # like facts and environment. + def initialize(node, parser, options = {}) + @node = node + @parser = parser + + options.each do |param, value| + begin + send(param.to_s + "=", value) + rescue NoMethodError + raise ArgumentError, "Compiler objects do not accept %s" % param + end + end + + initvars() + init_main() + end + + # Create a new scope, with either a specified parent scope or + # using the top scope. Adds an edge between the scope and + # its parent to the graph. + def newscope(parent, options = {}) + parent ||= topscope + options[:compiler] = self + options[:parser] ||= self.parser + scope = Puppet::Parser::Scope.new(options) + @scope_graph.add_edge!(parent, scope) + scope + end + + # Find the parent of a given scope. Assumes scopes only ever have + # one in edge, which will always be true. + def parent(scope) + if ary = @scope_graph.adjacent(scope, :direction => :in) and ary.length > 0 + ary[0] + else + nil + end + end + + # Return any overrides for the given resource. + def resource_overrides(resource) + @resource_overrides[resource.ref] + end + + # Return a list of all resources. + def resources + @catalog.vertices + 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 = @parser.nodes[name.to_s.downcase] + end + + unless (astnode ||= @parser.nodes["default"]) + raise Puppet::ParseError, "Could not find default node or by name with '%s'" % node.names.join(", ") + end + + # Create a resource to model this node, and then add it to the list + # of resources. + resource = astnode.evaluate(topscope) + + resource.evaluate + + # Now set the node scope appropriately, so that :topscope can + # behave differently. + @node_scope = 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 + + return 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 + ary.each do |resource| + resource.evaluate + end + # If we evaluated, let the loop know. + return true + 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 = @parser.findclass("", "") || @parser.newclass("") + @topscope.source = @main + @main_resource = Puppet::Parser::Resource.new(:type => "class", :title => :main, :scope => @topscope, :source => @main) + @topscope.resource = @main_resource + + @catalog.add_resource(@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 object(s) %s" % 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 + end + end + + unless remaining.empty? + raise Puppet::ParseError, "Failed to realize virtual resources %s" % + remaining.join(', ') + end + end + + # Make sure all of our resources and such have done any last work + # necessary. + def finish + @catalog.resources.each do |name| + resource = @catalog.resource(name) + + # 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) + end + end + + # Initialize the top-level scope, class, and resource. + def init_main + # Create our initial scope and a resource that will evaluate main. + @topscope = Puppet::Parser::Scope.new(:compiler => self, :parser => self.parser) + @scope_graph.add_vertex!(@topscope) + end + + # Set up all of our internal variables. + def initvars + # The table for storing class singletons. This will only actually + # be used by top scopes and node scopes. + @class_scopes = {} + + # 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 collections that have been created. This is a global list, + # but they each refer back to the scope that created them. + @collections = [] + + # A graph for maintaining scope relationships. + @scope_graph = Puppet::SimpleGraph.new + + # For maintaining the relationship between scopes and their resources. + @catalog = Puppet::Node::Catalog.new(@node.name) + @catalog.version = @parser.version + 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 + end + + # Store the catalog into the database. + def store + unless Puppet.features.rails? + raise Puppet::Error, + "storeconfigs is enabled but rails is unavailable" + end + + unless ActiveRecord::Base.connected? + Puppet::Rails.connect + end + + # We used to have hooks here for forking and saving, but I don't + # think it's worth retaining at this point. + store_to_active_record(@node, @catalog.vertices) + end + + # Do the actual storage. + def store_to_active_record(node, resources) + begin + # We store all of the objects, even the collectable ones + benchmark(:info, "Stored catalog for #{node.name}") do + Puppet::Rails::Host.transaction do + Puppet::Rails::Host.store(node, resources) + end + end + rescue => detail + if Puppet[:trace] + puts detail.backtrace + end + Puppet.err "Could not store configs: %s" % detail.to_s + 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 = @catalog.vertices.reject { |resource| resource.builtin? or resource.evaluated? } + + if ary.empty? + return nil + else + return ary + end + end +end diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 34b38b809..e0b60e161 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -111,7 +111,7 @@ module Functions vals = [vals] unless vals.is_a?(Array) # The 'false' disables lazy evaluation. - klasses = compile.evaluate_classes(vals, self, false) + klasses = compiler.evaluate_classes(vals, self, false) missing = vals.find_all do |klass| ! klasses.include?(klass) @@ -146,7 +146,7 @@ module Functions 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 = compile.catalog.tags + configtags = compiler.catalog.tags resourcetags = resource.tags retval = true @@ -235,7 +235,7 @@ module Functions vals = [vals] unless vals.is_a?(Array) coll.resources = vals - compile.add_collection(coll) + compiler.add_collection(coll) end newfunction(:search, :doc => "Add another namespace for this class to search. diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index e29e19944..1d93193dd 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -3,7 +3,7 @@ require 'timeout' require 'puppet/rails' require 'puppet/util/methodhelper' require 'puppet/parser/parser' -require 'puppet/parser/compile' +require 'puppet/parser/compiler' require 'puppet/parser/scope' # The interpreter is a very simple entry-point class that @@ -25,7 +25,7 @@ class Puppet::Parser::Interpreter # evaluate our whole tree def compile(node) raise Puppet::ParseError, "Could not parse configuration; cannot compile" unless env_parser = parser(node.environment) - return Puppet::Parser::Compile.new(node, env_parser).compile + return Puppet::Parser::Compiler.new(node, env_parser).compile end # create our interpreter diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 81d4ac71a..a6e43e7b3 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -17,20 +17,20 @@ class Puppet::Parser::Scope include Puppet::Util::Errors attr_accessor :parent, :level, :parser, :source, :resource attr_accessor :base, :keyword, :nodescope - attr_accessor :top, :translated, :compile + attr_accessor :top, :translated, :compiler # A demeterific shortcut to the catalog. def catalog - compile.catalog + compiler.catalog end # Proxy accessors def host - @compile.node.name + @compiler.node.name end def interpreter - @compile.interpreter + @compiler.interpreter end # Is the value true? This allows us to control the definition of truth @@ -77,7 +77,7 @@ class Puppet::Parser::Scope end def findresource(string, name = nil) - compile.findresource(string, name) + compiler.findresource(string, name) end # Initialize our new scope. Defaults to having no parent. @@ -152,7 +152,7 @@ class Puppet::Parser::Scope unless klass raise Puppet::ParseError, "Could not find class %s" % klassname end - unless kscope = compile.class_scope(klass) + unless kscope = compiler.class_scope(klass) raise Puppet::ParseError, "Class %s has not been evaluated so its variables cannot be referenced" % klass.classname end return kscope.lookupvar(shortname, usestring) @@ -189,7 +189,7 @@ class Puppet::Parser::Scope # Create a new scope and set these options. def newscope(options = {}) - compile.newscope(self, options) + compiler.newscope(self, options) end # Is this class for a node? This is used to make sure that @@ -204,7 +204,7 @@ class Puppet::Parser::Scope # than doing lots of queries. def parent unless defined?(@parent) - @parent = compile.parent(self) + @parent = compiler.parent(self) end @parent end diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 13823d483..7a8f74156 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -7,7 +7,7 @@ class Puppet::Parser::TemplateWrapper def initialize(scope, file) @scope = scope - @file = Puppet::Module::find_template(file, @scope.compile.environment) + @file = Puppet::Module::find_template(file, @scope.compiler.environment) unless FileTest.exists?(@file) raise Puppet::ParseError, -- cgit From d21416b534eaa5717eca850cfe848716a9b1dc09 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 18:08:15 -0600 Subject: Switching the Node Catalog to using a separate method for validating that a given resource is unique within the catalog. This no longer allows any duplication, even with Execs. --- lib/puppet/node/catalog.rb | 56 ++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index f93d2786d..2b9291680 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -58,12 +58,12 @@ class Puppet::Node::Catalog < Puppet::PGraph raise ArgumentError, "Can only add objects that respond to :ref" end + fail_unless_unique(resource) + ref = resource.ref - if @resource_table.include?(ref) - raise ArgumentError, "Resource %s is already defined" % ref - else - @resource_table[ref] = resource - end + + @resource_table[ref] = resource + resource.catalog = self if resource.respond_to?(:catalog=) and ! is_relationship_graph add_vertex!(resource) end @@ -452,6 +452,28 @@ class Puppet::Node::Catalog < Puppet::PGraph end end + # Verify that the given resource isn't defined elsewhere. + def fail_unless_unique(resource) + # Short-curcuit the common case, + return unless existing_resource = @resource_table[resource.ref] + + # Either it's a defined type, which are never + # isomorphic, or it's a non-isomorphic type, so + # we should throw an exception. + msg = "Duplicate definition: %s is already defined" % resource.ref + + if existing_resource.file and existing_resource.line + msg << " in file %s at line %s" % + [existing_resource.file, existing_resource.line] + end + + if resource.line or resource.file + msg << "; cannot redefine" + end + + raise ArgumentError.new(msg) + end + # An abstracted method for converting one catalog into another type of catalog. # This pretty much just converts all of the resources from one class to another, using # a conversion method. @@ -496,28 +518,4 @@ class Puppet::Node::Catalog < Puppet::PGraph return result end - - # Verify that the given resource isn't defined elsewhere. - def verify_resource_uniqueness(resource) - # Short-curcuit the common case, - unless existing_resource = @resource_table[resource.ref] - return true - end - - # Either it's a defined type, which are never - # isomorphic, or it's a non-isomorphic type, so - # we should throw an exception. - msg = "Duplicate definition: %s is already defined" % resource.ref - - if existing_resource.file and existing_resource.line - msg << " in file %s at line %s" % - [existing_resource.file, existing_resource.line] - end - - if resource.line or resource.file - msg << "; cannot redefine" - end - - raise Puppet::ParseError.new(msg) - end end -- cgit From 744cd45378384d33b3118351536e70cd6ea8370d Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 18:13:51 -0600 Subject: Added a 'tagged?' method to the Tagging module. --- lib/puppet/util/tagging.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb index 25d74c420..9abb3fb2b 100644 --- a/lib/puppet/util/tagging.rb +++ b/lib/puppet/util/tagging.rb @@ -19,6 +19,11 @@ module Puppet::Util::Tagging qualified.collect { |name| name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) } end + # Are we tagged with the provided tag? + def tagged?(tag) + defined?(@tags) and @tags.include?(tag.to_s) + end + # Return a copy of the tag list, so someone can't ask for our tags # and then modify them. def tags -- cgit From cf21ade9abf4541920b535b0e2643b30e44b067b Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 18:15:27 -0600 Subject: Switching the Node catalog to use the Tagging module instead of its own tag methods. --- lib/puppet/node/catalog.rb | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index 2b9291680..96f60b179 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -1,5 +1,7 @@ require 'puppet/indirector' +require 'puppet/util/tagging' + # This class models a node catalog. It is the thing # meant to be passed from server to client, and it contains all # of the information in the catalog, including the resources @@ -8,6 +10,8 @@ class Puppet::Node::Catalog < Puppet::PGraph extend Puppet::Indirector indirects :catalog, :terminus_class => :compiler + include Puppet::Util::Tagging + # The host name this is a catalog for. attr_accessor :name @@ -268,7 +272,6 @@ class Puppet::Node::Catalog < Puppet::PGraph super() @name = name if name @extraction_format ||= :transportable - @tags = [] @classes = [] @resource_table = {} @transient_resources = [] @@ -381,30 +384,6 @@ class Puppet::Node::Catalog < Puppet::PGraph @resource_table.keys end - # Add a tag. - def tag(*names) - names.each do |name| - name = name.to_s - @tags << name unless @tags.include?(name) - if name.include?("::") - name.split("::").each do |sub| - @tags << sub unless @tags.include?(sub) - end - end - end - nil - end - - # Does our tag list include this tag? - def tagged?(tag) - @tags.include?(tag) - end - - # Return the list of tags. - def tags - @tags.dup - end - # Convert our catalog into a RAL catalog. def to_ral to_catalog :to_type -- cgit From 8b2fae019b31513becd002eb474e1b4803abde24 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 18:27:49 -0600 Subject: Removing the last remaining vestiges of GRATR -- removing the bangs from 'add_vertex!' and 'add_edge!'. --- lib/puppet/node/catalog.rb | 10 +++++----- lib/puppet/parser/compiler.rb | 6 +++--- lib/puppet/pgraph.rb | 14 +++----------- lib/puppet/simple_graph.rb | 8 ++++---- lib/puppet/transaction.rb | 2 +- lib/puppet/transportable.rb | 2 +- lib/puppet/type/pfile.rb | 2 +- lib/puppet/util/graph.rb | 2 +- 8 files changed, 19 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index 96f60b179..b74947107 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -69,7 +69,7 @@ class Puppet::Node::Catalog < Puppet::PGraph @resource_table[ref] = resource resource.catalog = self if resource.respond_to?(:catalog=) and ! is_relationship_graph - add_vertex!(resource) + add_vertex(resource) end end @@ -316,9 +316,9 @@ class Puppet::Node::Catalog < Puppet::PGraph # First create the dependency graph self.vertices.each do |vertex| - @relationship_graph.add_vertex! vertex + @relationship_graph.add_vertex vertex vertex.builddepends.each do |edge| - @relationship_graph.add_edge!(edge) + @relationship_graph.add_edge(edge) end end @@ -328,7 +328,7 @@ class Puppet::Node::Catalog < Puppet::PGraph unless @relationship_graph.edge?(edge.source, edge.target) # don't let automatic relationships conflict with manual ones. unless @relationship_graph.edge?(edge.target, edge.source) vertex.debug "Autorequiring %s" % [edge.source] - @relationship_graph.add_edge!(edge) + @relationship_graph.add_edge(edge) else vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source) end @@ -487,7 +487,7 @@ class Puppet::Node::Catalog < Puppet::PGraph raise Puppet::DevError, "Could not find resource %s when converting %s resources" % [edge.target.ref, message] end - result.add_edge!(source, target, edge.label) + result.add_edge(source, target, edge.label) end map.clear diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index 27860487a..26fdd3743 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -36,7 +36,7 @@ class Puppet::Parser::Compiler # And in the resource graph. At some point, this might supercede # the global resource table, but the table is a lot faster # so it makes sense to maintain for now. - @catalog.add_edge!(scope.resource, resource) + @catalog.add_edge(scope.resource, resource) end # Do we use nodes found in the code, vs. the external node sources? @@ -184,7 +184,7 @@ class Puppet::Parser::Compiler options[:compiler] = self options[:parser] ||= self.parser scope = Puppet::Parser::Scope.new(options) - @scope_graph.add_edge!(parent, scope) + @scope_graph.add_edge(parent, scope) scope end @@ -383,7 +383,7 @@ class Puppet::Parser::Compiler def init_main # Create our initial scope and a resource that will evaluate main. @topscope = Puppet::Parser::Scope.new(:compiler => self, :parser => self.parser) - @scope_graph.add_vertex!(@topscope) + @scope_graph.add_vertex(@topscope) end # Set up all of our internal variables. diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb index 54b815b45..71547802e 100644 --- a/lib/puppet/pgraph.rb +++ b/lib/puppet/pgraph.rb @@ -7,17 +7,14 @@ require 'puppet/simple_graph' # This class subclasses a graph class in order to handle relationships # among resources. class Puppet::PGraph < Puppet::SimpleGraph - # This is the type used for splicing. - attr_accessor :container_type - include Puppet::Util - def add_edge!(*args) + def add_edge(*args) @reversal = nil super end - def add_vertex!(*args) + def add_vertex(*args) @reversal = nil super end @@ -57,11 +54,6 @@ class Puppet::PGraph < Puppet::SimpleGraph @reversal.tree_from_vertex(resource, :out).keys end - # Override this method to use our class instead. - def edge_class() - Puppet::Relationship - end - # Determine all of the leaf nodes below a given vertex. def leaves(vertex, direction = :out) tree = tree_from_vertex(vertex, direction) @@ -133,7 +125,7 @@ class Puppet::PGraph < Puppet::SimpleGraph copy_label(s, t, edge.label) next end - add_edge!(s, t, edge.label) + add_edge(s, t, edge.label) end # Now get rid of the edge, so remove_vertex! works correctly. diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb index 11542ad53..503e4814c 100644 --- a/lib/puppet/simple_graph.rb +++ b/lib/puppet/simple_graph.rb @@ -100,10 +100,10 @@ class Puppet::SimpleGraph # Return a reversed version of this graph. def reversal result = self.class.new - vertices.each { |vertex| result.add_vertex!(vertex) } + vertices.each { |vertex| result.add_vertex(vertex) } edges.each do |edge| newedge = edge.class.new(edge.target, edge.source, edge.label) - result.add_edge!(newedge) + result.add_edge(newedge) end result end @@ -150,7 +150,7 @@ class Puppet::SimpleGraph end # Add a new vertex to the graph. - def add_vertex!(vertex) + def add_vertex(vertex) return false if vertex?(vertex) setup_vertex(vertex) true # don't return the VertexWrapper instance. @@ -176,7 +176,7 @@ class Puppet::SimpleGraph # Add a new edge. The graph user has to create the edge instance, # since they have to specify what kind of edge it is. - def add_edge!(source, target = nil, label = nil) + def add_edge(source, target = nil, label = nil) if target edge = Puppet::Relationship.new(source, target, label) else diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index f304cadc6..976bf7c68 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -173,7 +173,7 @@ class Transaction relationship_graph.add_resource(gen_child) unless relationship_graph.resource(gen_child.ref) unless relationship_graph.edge?(edge[1], edge[0]) - relationship_graph.add_edge!(*edge) + relationship_graph.add_edge(*edge) else resource.debug "Skipping automatic relationship to %s" % gen_child end diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb index c1d68a881..f686fbb78 100644 --- a/lib/puppet/transportable.rb +++ b/lib/puppet/transportable.rb @@ -193,7 +193,7 @@ module Puppet next unless resource = child.to_type config.add_resource resource end - config.add_edge!(container, resource) + config.add_edge(container, resource) if child.is_a?(self.class) delver.call(child) end diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index 7d928d959..c32a4d474 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -650,7 +650,7 @@ module Puppet # LAK:FIXME This shouldn't be necessary, but as long as we're # modeling the relationship graph specifically, it is. - catalog.relationship_graph.add_edge! self, child + catalog.relationship_graph.add_edge self, child return child end diff --git a/lib/puppet/util/graph.rb b/lib/puppet/util/graph.rb index a9744578b..d1ef36f8e 100644 --- a/lib/puppet/util/graph.rb +++ b/lib/puppet/util/graph.rb @@ -16,7 +16,7 @@ module Puppet::Util::Graph self.each do |child| unless block_given? and ! yield(child) - graph.add_edge!(self, child) + graph.add_edge(self, child) if child.respond_to?(:to_graph) child.to_graph(graph, &block) -- cgit From c8da318a2a4445e0ce10c76a7fbb64635b291ccd Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 12 Feb 2008 14:19:19 -0600 Subject: Moving the ast node tests to rspec (which I could have *sworn* I did this weekend). In the process, I fixed a couple of bugs related to differentiating between nodes and classes, and then cleaned up quite a few error messages. --- lib/puppet/parser/ast/definition.rb | 4 ++-- lib/puppet/parser/ast/hostclass.rb | 11 +++++++---- lib/puppet/parser/ast/node.rb | 34 ++++++--------------------------- lib/puppet/parser/compiler.rb | 5 +++-- lib/puppet/parser/resource/reference.rb | 8 ++++++-- 5 files changed, 24 insertions(+), 38 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index b4a90016a..2b7506446 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -25,9 +25,9 @@ class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch # Create a resource that knows how to evaluate our actual code. def evaluate(scope) # Do nothing if the resource already exists; this provides the singleton nature classes need. - return if scope.catalog.resource(:class, self.classname) + return if scope.catalog.resource(self.class.name, self.classname) - resource = Puppet::Parser::Resource.new(:type => "class", :title => self.classname, :scope => scope, :source => scope.source) + resource = Puppet::Parser::Resource.new(:type => self.class.name, :title => self.classname, :scope => scope, :source => scope.source) scope.catalog.tag(*resource.tags) diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index f49016526..8d4d01660 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -20,7 +20,7 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition # Make sure our parent class has been evaluated, if we have one. def evaluate(scope) - if parentclass and ! scope.catalog.resource(:class, parentclass) + if parentclass and ! scope.catalog.resource(self.class.name, parentclass) resource = parentobj.evaluate(scope) end @@ -39,7 +39,9 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition pnames = nil if pklass = self.parentobj - pklass.evaluate_code(resource) + parent_resource = resource.scope.compiler.catalog.resource(self.class.name, pklass.classname) + # This shouldn't evaluate if the class has already been evaluated. + pklass.evaluate_code(parent_resource) scope = parent_scope(scope, pklass) pnames = scope.namespaces @@ -49,14 +51,15 @@ class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition # has its own scope. scope = subscope(scope, resource) unless resource.title == :main + # Add the parent scope namespaces to our own. if pnames pnames.each do |ns| scope.add_namespace(ns) end end - # Set the class before we do anything else, so that it's set - # during the evaluation and can be inspected. + # Set the class before we evaluate the code, so that it's set during + # the evaluation and can be inspected. scope.compiler.class_set(self.classname, scope) # Now evaluate our code, yo. diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index 8cebac8a8..2bf6c1882 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -5,34 +5,6 @@ require 'puppet/parser/ast/hostclass' class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass @name = :node - # Evaluate the code associated with our node definition. - def evaluate_code(resource) - scope = resource.scope - - # We don't have to worry about the declarativeness of node parentage, - # because the entry point is always a single node definition. - if parent = self.parentobj - scope = parent.evaluate_code(resource) - end - - scope = scope.newscope( - :resource => resource, - :keyword => @keyword, - :source => self, - :namespace => "" # nodes are always in "" - ) - - # Mark our node name as a class, too, but strip it of the domain - # name. Make the mark before we evaluate the code, so that it is - # marked within the code itself. - scope.compiler.class_set(self.classname, scope) - - # And then evaluate our code if we have any - @code.safeevaluate(scope) if self.code - - return scope - end - def initialize(options) @parentclass = nil super @@ -43,13 +15,19 @@ class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass end end + def namespace + "" + end + # Make sure node scopes are marked as such. def subscope(*args) scope = super scope.nodescope = true + scope end private + # Search for the object matching our parent class. def find_parentclass @parser.findnode(parentclass) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index 26fdd3743..68c06e500 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -31,6 +31,7 @@ class Puppet::Parser::Compiler # Store a resource in our resource table. def add_resource(scope, resource) + # Note that this will fail if the resource is not unique. @catalog.add_resource(resource) # And in the resource graph. At some point, this might supercede @@ -48,10 +49,10 @@ class Puppet::Parser::Compiler # the scope in which it was evaluated, so that we can look it up later. def class_set(name, scope) if existing = @class_scopes[name] - if existing.nodescope? or scope.nodescope? + if existing.nodescope? != scope.nodescope? raise Puppet::ParseError, "Cannot have classes, nodes, or definitions with the same name" else - raise Puppet::DevError, "Somehow evaluated the same class twice" + raise Puppet::DevError, "Somehow evaluated %s %s twice" % [ existing.nodescope? ? "node" : "class", name] end end @class_scopes[name] = scope diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb index ea53b421a..c59748049 100644 --- a/lib/puppet/parser/resource/reference.rb +++ b/lib/puppet/parser/resource/reference.rb @@ -37,10 +37,14 @@ class Puppet::Parser::Resource::Reference < Puppet::ResourceReference if self.title == :main tmp = @scope.findclass("") else - tmp = @scope.findclass(self.title) + unless tmp = @scope.findclass(self.title) + fail Puppet::ParseError, "Could not find class '%s'" % self.title + end end when "Node": # look for node definitions - tmp = @scope.parser.nodes[self.title] + unless tmp = @scope.parser.nodes[self.title] + fail Puppet::ParseError, "Could not find node '%s'" % self.title + end else # normal definitions # We have to swap these variables around so the errors are right. tmp = @scope.finddefine(self.type) -- cgit From 3af6827875f4e02b47fe2293280ff9afe811485f Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 12 Feb 2008 16:35:31 -0600 Subject: Adding an inflection util class. --- lib/puppet/util/constant_inflector.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 lib/puppet/util/constant_inflector.rb (limited to 'lib') diff --git a/lib/puppet/util/constant_inflector.rb b/lib/puppet/util/constant_inflector.rb new file mode 100644 index 000000000..8b083951f --- /dev/null +++ b/lib/puppet/util/constant_inflector.rb @@ -0,0 +1,14 @@ +# Created on 2008-02-12 +# Copyright Luke Kanies + +# A common module for converting between constants and +# file names. +module Puppet::Util::ConstantInflector + def file2constant(file) + file.split("/").collect { |name| name.capitalize }.join("::").gsub(/_+(.)/) { |term| $1.capitalize } + end + + def constant2file(constant) + constant.to_s.gsub(/([a-z])([A-Z])/) { |term| $1 + "_" + $2 }.gsub("::", "/").downcase + end +end -- cgit