summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-02-12 17:37:51 -0600
committerLuke Kanies <luke@madstop.com>2008-02-12 17:37:51 -0600
commitda78d96cb139db0775e634b2fa4bd9c173752127 (patch)
tree4139d3a2011baedb171a8307c4830c5ac3fe3625
parentbee9aba2da453151a80c6e1f25f16bec3bfde8d2 (diff)
parent3af6827875f4e02b47fe2293280ff9afe811485f (diff)
downloadpuppet-da78d96cb139db0775e634b2fa4bd9c173752127.tar.gz
puppet-da78d96cb139db0775e634b2fa4bd9c173752127.tar.xz
puppet-da78d96cb139db0775e634b2fa4bd9c173752127.zip
Merge branch '0.24.x'
Conflicts: CHANGELOG
-rw-r--r--CHANGELOG31
-rw-r--r--Rakefile4
-rwxr-xr-xbin/puppetd2
-rwxr-xr-xbin/puppetrun2
-rw-r--r--conf/gentoo/puppet/puppet.conf29
-rwxr-xr-xconf/gentoo/puppet/puppetca.conf29
-rw-r--r--conf/gentoo/puppet/puppetd.conf29
-rwxr-xr-xconf/gentoo/puppet/puppetmasterd.conf29
-rw-r--r--examples/root/etc/puppet/puppet.conf (renamed from examples/root/etc/puppet/puppetmasterd.conf)9
-rw-r--r--examples/root/etc/puppet/puppetd.conf4
-rw-r--r--ext/logcheck/puppet5
-rwxr-xr-xext/puppet-test4
-rw-r--r--lib/puppet/defaults.rb8
-rw-r--r--lib/puppet/metatype/metaparams.rb2
-rw-r--r--lib/puppet/network/http_server/mongrel.rb7
-rw-r--r--lib/puppet/network/http_server/webrick.rb4
-rw-r--r--lib/puppet/network/xmlrpc/client.rb13
-rw-r--r--lib/puppet/node/catalog.rb68
-rw-r--r--lib/puppet/parser/ast.rb76
-rw-r--r--lib/puppet/parser/ast/astarray.rb5
-rw-r--r--lib/puppet/parser/ast/caseopt.rb8
-rw-r--r--lib/puppet/parser/ast/casestatement.rb9
-rw-r--r--lib/puppet/parser/ast/collection.rb8
-rw-r--r--lib/puppet/parser/ast/collexpr.rb8
-rw-r--r--lib/puppet/parser/ast/definition.rb310
-rw-r--r--lib/puppet/parser/ast/else.rb5
-rw-r--r--lib/puppet/parser/ast/function.rb13
-rw-r--r--lib/puppet/parser/ast/hostclass.rb120
-rw-r--r--lib/puppet/parser/ast/ifstatement.rb9
-rw-r--r--lib/puppet/parser/ast/leaf.rb12
-rw-r--r--lib/puppet/parser/ast/node.rb84
-rw-r--r--lib/puppet/parser/ast/resource.rb12
-rw-r--r--lib/puppet/parser/ast/resource_defaults.rb6
-rw-r--r--lib/puppet/parser/ast/resource_override.rb10
-rw-r--r--lib/puppet/parser/ast/resource_reference.rb6
-rw-r--r--lib/puppet/parser/ast/resourceparam.rb6
-rw-r--r--lib/puppet/parser/ast/selector.rb11
-rw-r--r--lib/puppet/parser/ast/tag.rb6
-rw-r--r--lib/puppet/parser/ast/vardef.rb7
-rw-r--r--lib/puppet/parser/collector.rb8
-rw-r--r--lib/puppet/parser/compiler.rb (renamed from lib/puppet/parser/compile.rb)170
-rw-r--r--lib/puppet/parser/functions.rb6
-rw-r--r--lib/puppet/parser/interpreter.rb4
-rw-r--r--lib/puppet/parser/lexer.rb671
-rw-r--r--lib/puppet/parser/parser_support.rb7
-rw-r--r--lib/puppet/parser/resource.rb48
-rw-r--r--lib/puppet/parser/resource/param.rb2
-rw-r--r--lib/puppet/parser/resource/reference.rb10
-rw-r--r--lib/puppet/parser/scope.rb19
-rw-r--r--lib/puppet/parser/templatewrapper.rb2
-rw-r--r--lib/puppet/pgraph.rb14
-rwxr-xr-xlib/puppet/provider/package/fink.rb2
-rwxr-xr-xlib/puppet/provider/package/openbsd.rb2
-rw-r--r--lib/puppet/provider/user/useradd.rb2
-rw-r--r--lib/puppet/resource_reference.rb2
-rw-r--r--lib/puppet/simple_graph.rb8
-rw-r--r--lib/puppet/sslcertificates/ca.rb6
-rw-r--r--lib/puppet/transaction.rb4
-rw-r--r--lib/puppet/transportable.rb2
-rwxr-xr-xlib/puppet/type/cron.rb25
-rwxr-xr-xlib/puppet/type/exec.rb23
-rwxr-xr-xlib/puppet/type/host.rb13
-rw-r--r--lib/puppet/type/package.rb4
-rw-r--r--lib/puppet/type/pfile.rb2
-rwxr-xr-xlib/puppet/type/pfile/ensure.rb5
-rwxr-xr-xlib/puppet/type/pfile/source.rb4
-rw-r--r--lib/puppet/util/constant_inflector.rb14
-rw-r--r--lib/puppet/util/graph.rb2
-rw-r--r--lib/puppet/util/settings.rb35
-rw-r--r--lib/puppet/util/tagging.rb39
-rwxr-xr-xspec/unit/node/catalog.rb60
-rwxr-xr-xspec/unit/other/pgraph.rb34
-rwxr-xr-xspec/unit/parser/ast/definition.rb158
-rwxr-xr-xspec/unit/parser/ast/hostclass.rb131
-rwxr-xr-xspec/unit/parser/ast/node.rb127
-rwxr-xr-xspec/unit/parser/collector.rb60
-rwxr-xr-xspec/unit/parser/compile.rb281
-rwxr-xr-xspec/unit/parser/compiler.rb544
-rwxr-xr-xspec/unit/parser/interpreter.rb6
-rwxr-xr-xspec/unit/parser/lexer.rb465
-rwxr-xr-xspec/unit/parser/resource.rb74
-rwxr-xr-xspec/unit/parser/resource/reference.rb8
-rwxr-xr-xspec/unit/ral/type.rb4
-rwxr-xr-xspec/unit/resource_reference.rb6
-rwxr-xr-xspec/unit/simple_graph.rb64
-rwxr-xr-xspec/unit/util/constant_inflector.rb70
-rwxr-xr-xspec/unit/util/settings.rb16
-rwxr-xr-xspec/unit/util/tagging.rb88
-rw-r--r--test/data/snippets/collection_within_virtual_definitions.pp20
-rw-r--r--test/data/snippets/realize_defined_types.pp13
-rwxr-xr-xtest/language/ast.rb66
-rwxr-xr-xtest/language/ast/casestatement.rb6
-rwxr-xr-xtest/language/ast/definition.rb166
-rwxr-xr-xtest/language/ast/hostclass.rb184
-rwxr-xr-xtest/language/ast/resource.rb13
-rwxr-xr-xtest/language/ast/resource_reference.rb24
-rwxr-xr-xtest/language/ast/selector.rb4
-rwxr-xr-xtest/language/ast/variable.rb4
-rwxr-xr-xtest/language/compile.rb569
-rwxr-xr-xtest/language/functions.rb48
-rwxr-xr-xtest/language/lexer.rb276
-rwxr-xr-xtest/language/parser.rb16
-rwxr-xr-xtest/language/resource.rb47
-rwxr-xr-xtest/language/scope.rb58
-rwxr-xr-xtest/language/snippets.rb7
-rw-r--r--test/lib/puppettest/parsertesting.rb16
-rwxr-xr-xtest/lib/puppettest/support/resources.rb2
-rwxr-xr-xtest/other/transactions.rb8
-rwxr-xr-xtest/ral/manager/type.rb4
-rwxr-xr-xtest/ral/types/basic.rb4
-rwxr-xr-xtest/ral/types/exec.rb40
-rwxr-xr-xtest/ral/types/host.rb16
112 files changed, 3081 insertions, 2891 deletions
diff --git a/CHANGELOG b/CHANGELOG
index e6c4ac6d3..0c98d829e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,7 +1,38 @@
The environment is now available as a variable in the manifests.
+ Fixed #997 -- virtual defined types are no longer evaluated.
+ NOTE: This introduces a behaviour change, in that you previously
+ could realize a resource within a virtual defined resource, and now
+ you must realize the entire defined resource, rather than just
+ the contained resource.
+
+ 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.
+
+ Exec resources must now have unique names. This is easily accomplished by
+ just specifying a unique name with whatever (unique or otherwise) command
+ you need.
+
+ Fixed #989 -- missing CRL files are correctly ignored, and the
+ value should be set to 'false' to explicitly not look for these
+ files.
+
Fixed #1017 -- environment-specific modulepath is no longer ignored.
+ Fixing #794 -- consolidating the gentoo configuration files.
+
+ 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.
+
+ Fixing #995 -- puppetd no longer dies at startup if the server
+ is not running.
+
+ Fixing #977 -- the rundir is again set to 1777.
+
Fixed #971 -- classes can once again be included multiple
times.
diff --git a/Rakefile b/Rakefile
index d5b65e49a..f67ad923e 100644
--- a/Rakefile
+++ b/Rakefile
@@ -83,10 +83,6 @@ rule(/_is_runnable$/) do |t|
end
end
-file "debian" => :bzr_is_runnable do
- system("bzr get http://www.hezmatt.org/~mpalmer/bzr/puppet.debian.svn debian") || exit(1)
-end
-
task :check_build_deps => 'dpkg-checkbuilddeps_is_runnable' do
system("dpkg-checkbuilddeps") || exit(1)
end
diff --git a/bin/puppetd b/bin/puppetd
index 297d4876d..e993d3aa8 100755
--- a/bin/puppetd
+++ b/bin/puppetd
@@ -374,7 +374,7 @@ if Puppet[:listen] and ! options[:onetime]
# to clients. In the meantime, we just disable CRL checking if
# the CRL file doesn't exist
unless File::exist?(Puppet[:cacrl])
- Puppet[:cacrl] = 'none'
+ Puppet[:cacrl] = 'false'
end
handlers = nil
diff --git a/bin/puppetrun b/bin/puppetrun
index 5f99d6325..fe981dadf 100755
--- a/bin/puppetrun
+++ b/bin/puppetrun
@@ -281,7 +281,7 @@ if File.exists? config
Puppet.settings.parse(config)
end
-if Puppet[:ldapnodes]
+if Puppet[:node_terminus] = "ldap"
if options[:all]
hosts = ldapnodes(:all, options[:fqdn])
puts "all: %s" % hosts.join(", ")
diff --git a/conf/gentoo/puppet/puppet.conf b/conf/gentoo/puppet/puppet.conf
new file mode 100644
index 000000000..1d62c90e4
--- /dev/null
+++ b/conf/gentoo/puppet/puppet.conf
@@ -0,0 +1,29 @@
+[main]
+ # Where Puppet stores dynamic and growing data.
+ # The default value is '/var/puppet'.
+ vardir = /var/lib/puppet
+
+ # The Puppet log directory.
+ # The default value is '$vardir/log'.
+ logdir = /var/log/puppet
+
+ # Where Puppet PID files are kept.
+ # The default value is '$vardir/run'.
+ rundir = /var/run/puppet
+
+ # Where SSL certificates are kept.
+ # The default value is '$confdir/ssl'.
+ ssldir = $vardir/ssl
+
+[puppetd]
+ # The file in which puppetd stores a list of the classes
+ # associated with the retrieved configuratiion. Can be loaded in
+ # the separate ``puppet`` executable using the ``--loadclasses``
+ # option.
+ # The default value is '$confdir/classes.txt'.
+ classfile = $vardir/classes.txt
+
+ # Where puppetd caches the local configuration. An
+ # extension indicating the cache format is added automatically.
+ # The default value is '$confdir/localconfig'.
+ localconfig = $vardir/localconfig
diff --git a/conf/gentoo/puppet/puppetca.conf b/conf/gentoo/puppet/puppetca.conf
deleted file mode 100755
index 35f4abf1a..000000000
--- a/conf/gentoo/puppet/puppetca.conf
+++ /dev/null
@@ -1,29 +0,0 @@
-[puppet]
- # Where Puppet stores dynamic and growing data.
- # The default value is '/var/puppet'.
- vardir = /var/lib/puppet
-
- # The Puppet log directory.
- # The default value is '$vardir/log'.
- logdir = /var/log/puppet
-
- # Where Puppet PID files are kept.
- # The default value is '$vardir/run'.
- rundir = /var/run/puppet
-
- # Where SSL certificates are kept.
- # The default value is '$confdir/ssl'.
- ssldir = $vardir/ssl
-
-[puppetd]
- # The file in which puppetd stores a list of the classes
- # associated with the retrieved configuratiion. Can be loaded in
- # the separate ``puppet`` executable using the ``--loadclasses``
- # option.
- # The default value is '$confdir/classes.txt'.
- classfile = $vardir/classes.txt
-
- # Where puppetd caches the local configuration. An
- # extension indicating the cache format is added automatically.
- # The default value is '$confdir/localconfig'.
- localconfig = $vardir/localconfig
diff --git a/conf/gentoo/puppet/puppetd.conf b/conf/gentoo/puppet/puppetd.conf
deleted file mode 100644
index 35f4abf1a..000000000
--- a/conf/gentoo/puppet/puppetd.conf
+++ /dev/null
@@ -1,29 +0,0 @@
-[puppet]
- # Where Puppet stores dynamic and growing data.
- # The default value is '/var/puppet'.
- vardir = /var/lib/puppet
-
- # The Puppet log directory.
- # The default value is '$vardir/log'.
- logdir = /var/log/puppet
-
- # Where Puppet PID files are kept.
- # The default value is '$vardir/run'.
- rundir = /var/run/puppet
-
- # Where SSL certificates are kept.
- # The default value is '$confdir/ssl'.
- ssldir = $vardir/ssl
-
-[puppetd]
- # The file in which puppetd stores a list of the classes
- # associated with the retrieved configuratiion. Can be loaded in
- # the separate ``puppet`` executable using the ``--loadclasses``
- # option.
- # The default value is '$confdir/classes.txt'.
- classfile = $vardir/classes.txt
-
- # Where puppetd caches the local configuration. An
- # extension indicating the cache format is added automatically.
- # The default value is '$confdir/localconfig'.
- localconfig = $vardir/localconfig
diff --git a/conf/gentoo/puppet/puppetmasterd.conf b/conf/gentoo/puppet/puppetmasterd.conf
deleted file mode 100755
index 35f4abf1a..000000000
--- a/conf/gentoo/puppet/puppetmasterd.conf
+++ /dev/null
@@ -1,29 +0,0 @@
-[puppet]
- # Where Puppet stores dynamic and growing data.
- # The default value is '/var/puppet'.
- vardir = /var/lib/puppet
-
- # The Puppet log directory.
- # The default value is '$vardir/log'.
- logdir = /var/log/puppet
-
- # Where Puppet PID files are kept.
- # The default value is '$vardir/run'.
- rundir = /var/run/puppet
-
- # Where SSL certificates are kept.
- # The default value is '$confdir/ssl'.
- ssldir = $vardir/ssl
-
-[puppetd]
- # The file in which puppetd stores a list of the classes
- # associated with the retrieved configuratiion. Can be loaded in
- # the separate ``puppet`` executable using the ``--loadclasses``
- # option.
- # The default value is '$confdir/classes.txt'.
- classfile = $vardir/classes.txt
-
- # Where puppetd caches the local configuration. An
- # extension indicating the cache format is added automatically.
- # The default value is '$confdir/localconfig'.
- localconfig = $vardir/localconfig
diff --git a/examples/root/etc/puppet/puppetmasterd.conf b/examples/root/etc/puppet/puppet.conf
index b3182075c..151364ebd 100644
--- a/examples/root/etc/puppet/puppetmasterd.conf
+++ b/examples/root/etc/puppet/puppet.conf
@@ -1,7 +1,10 @@
+[puppetd]
+report = true
+factsync = true
+pluginsync = true
+
[puppetmasterd]
reports = store,rrdgraph,tagmail,log
-
-[ldap]
-ldapnodes = true
+node_terminus = ldap
ldapserver = culain.madstop.com
ldapbase = dc=madstop,dc=com
diff --git a/examples/root/etc/puppet/puppetd.conf b/examples/root/etc/puppet/puppetd.conf
deleted file mode 100644
index ce988cfa1..000000000
--- a/examples/root/etc/puppet/puppetd.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-[puppet]
-report = true
-factsync = true
-pluginsync = true
diff --git a/ext/logcheck/puppet b/ext/logcheck/puppet
index 8b854dc48..449ec70f5 100644
--- a/ext/logcheck/puppet
+++ b/ext/logcheck/puppet
@@ -15,3 +15,8 @@
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Restarting with .*$
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Starting catalog run$
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Finished catalog run in [.0-9]+ seconds$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Loading fact .*$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Ignoring cache$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Ignoring --listen on onetime run$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Retrieving plugins$
+
diff --git a/ext/puppet-test b/ext/puppet-test
index 0f33e0cbb..e18dd1c57 100755
--- a/ext/puppet-test
+++ b/ext/puppet-test
@@ -211,11 +211,11 @@ end
Suite.new :parser, "Manifest parsing" do
def prepare
- @parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment])
- @parser.file = Puppet[:manifest]
end
newtest :parse, "Parsed files" do
+ @parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment])
+ @parser.file = Puppet[:manifest]
@parser.parse
end
end
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index cfbdf7bc7..4fb03f164 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,
@@ -228,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/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
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
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/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
diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb
index 9601309d8..b74947107 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
@@ -58,14 +62,14 @@ 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.catalog = self unless is_relationship_graph
- add_vertex!(resource)
+
+ @resource_table[ref] = resource
+
+ resource.catalog = self if resource.respond_to?(:catalog=) and ! is_relationship_graph
+ add_vertex(resource)
end
end
@@ -268,7 +272,6 @@ class Puppet::Node::Catalog < Puppet::PGraph
super()
@name = name if name
@extraction_format ||= :transportable
- @tags = []
@classes = []
@resource_table = {}
@transient_resources = []
@@ -313,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
@@ -325,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
@@ -381,25 +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
-
- # Return the list of tags.
- def tags
- @tags.dup
- end
-
# Convert our catalog into a RAL catalog.
def to_ral
to_catalog :to_type
@@ -447,6 +431,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.
@@ -481,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/ast.rb b/lib/puppet/parser/ast.rb
index 14b686e2f..c9bd7c9e8 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?
- }
+ def evaluate(*options)
+ raise Puppet::DevError, "Did not override #evaluate in %s" % self.class
end
# Throw a parse error.
@@ -75,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
@@ -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
@@ -107,13 +71,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'
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..9e795a33c 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -9,18 +9,16 @@ 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
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/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..2b7506446 100644
--- a/lib/puppet/parser/ast/definition.rb
+++ b/lib/puppet/parser/ast/definition.rb
@@ -1,155 +1,148 @@
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(options)
- origscope = options[:scope]
- resource = options[:resource]
+ # 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(self.class.name, self.classname)
- # Create a new scope.
- scope = subscope(origscope, resource)
+ resource = Puppet::Parser::Resource.new(:type => self.class.name, :title => self.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.catalog.tag(*resource.tags)
- [resource.name, resource.title].each do |str|
- unless str.nil? or str =~ /[^\w]/ or str == ""
- scope.resource.tag(str)
- end
- end
+ scope.compiler.add_resource(scope, resource)
- set_resource_parameters(scope, resource)
+ return resource
+ end
- if self.code
- return self.code.safeevaluate(:scope => scope)
- else
- return nil
- end
+ # Now evaluate the code associated with this class or definition.
+ def evaluate_code(resource)
+ # Create a new scope.
+ scope = subscope(resource.scope, resource)
+
+ set_resource_parameters(scope, resource)
+
+ if self.code
+ return self.code.safeevaluate(scope)
+ else
+ return nil
end
+ end
- def initialize(hash = {})
- @arguments = nil
- @parentclass = nil
- super
+ 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
+ return nil unless @parentclass
- @parentobj = tmp
- end
- @parentobj
- else
- nil
+ # Cache our result, since it should never change.
+ unless defined?(@parentobj)
+ unless tmp = find_parentclass
+ parsefail "Could not find %s parent %s" % [self.class.name, @parentclass]
+ end
+
+ if tmp == self
+ parsefail "Parent classes must have dissimilar names"
end
+
+ @parentobj = tmp
end
+ @parentobj
+ end
- # Create a new subscope in which to evaluate our code.
- def subscope(scope, resource)
- args = {
- :resource => resource,
- :keyword => self.keyword,
- :namespace => self.namespace,
- :source => self
- }
+ # 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 != []
@@ -160,53 +153,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 => 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/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..8d4d01660 100644
--- a/lib/puppet/parser/ast/hostclass.rb
+++ b/lib/puppet/parser/ast/hostclass.rb
@@ -1,80 +1,80 @@
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(options)
- scope = options[:scope]
- raise(ArgumentError, "Classes require resources") unless options[: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)
+ # Make sure our parent class has been evaluated, if we have one.
+ def evaluate(scope)
+ if parentclass and ! scope.catalog.resource(self.class.name, parentclass)
+ resource = parentobj.evaluate(scope)
+ end
- pnames = nil
- if pklass = self.parentobj
- pklass.safeevaluate :scope => scope, :resource => options[:resource]
+ super
+ end
- scope = parent_scope(scope, pklass)
- pnames = scope.namespaces
- end
+ # Evaluate the code associated with this class.
+ def evaluate_code(resource)
+ scope = resource.scope
+ # Verify that we haven't already been evaluated. This is
+ # what provides the singleton aspect.
+ if existing_scope = scope.compiler.class_scope(self)
+ Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname)
+ return nil
+ end
- # 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])
- end
+ pnames = nil
+ if pklass = self.parentobj
+ parent_resource = resource.scope.compiler.catalog.resource(self.class.name, pklass.classname)
+ # This shouldn't evaluate if the class has already been evaluated.
+ pklass.evaluate_code(parent_resource)
- if pnames
- pnames.each do |ns|
- scope.add_namespace(ns)
- end
- end
+ scope = parent_scope(scope, pklass)
+ pnames = scope.namespaces
+ 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)
+ # 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
- # Now evaluate our code, yo.
- if self.code
- return self.code.evaluate(:scope => scope)
- else
- return nil
+ # Add the parent scope namespaces to our own.
+ if pnames
+ pnames.each do |ns|
+ scope.add_namespace(ns)
end
end
- def initialize(options)
- @parentclass = nil
- super
+ # Set the class before we evaluate the code, so that it's set during
+ # the evaluation and can be inspected.
+ scope.compiler.class_set(self.classname, scope)
+
+ # Now evaluate our code, yo.
+ if self.code
+ return self.code.safeevaluate(scope)
+ else
+ return nil
end
+ end
- def parent_scope(scope, klass)
- if s = scope.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.compiler.class_scope(klass)
+ return s
+ else
+ raise Puppet::DevError, "Could not find scope for %s" % klass.classname
end
end
end
diff --git a/lib/puppet/parser/ast/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..2bf6c1882 100644
--- a/lib/puppet/parser/ast/node.rb
+++ b/lib/puppet/parser/ast/node.rb
@@ -1,67 +1,35 @@
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(options)
- scope = options[:scope]
-
- #pscope = if ! Puppet[:lexical] or options[:asparent]
- # @scope
- #else
- # origscope
- #end
-
- # 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]
- end
-
- scope = scope.newscope(
- :resource => options[: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 => 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
+
+ def initialize(options)
+ @parentclass = nil
+ super
+
+ # Do some validation on the node name
+ if @name =~ /[^-\w.]/
+ raise Puppet::ParseError, "Invalid node name %s" % @name
end
+ end
- def initialize(options)
- @parentclass = nil
- super
+ def namespace
+ ""
+ end
- # 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
+ scope
+ end
- # Make sure node scopes are marked as such.
- def subscope(*args)
- scope = super
- scope.nodescope = true
- end
+ private
- private
- # Search for the object matching our parent class.
- def find_parentclass
- @parser.findnode(parentclass)
- end
+ # Search for the object matching our parent class.
+ def find_parentclass
+ @parser.findnode(parentclass)
end
end
diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb
index c53ab0a68..8a60522a3 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)
@@ -50,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.store_resource(scope, obj)
+ scope.compiler.add_resource(scope, obj)
obj
end
}.reject { |obj| obj.nil? }
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..f9464acda 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
@@ -44,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.compiler.add_override(obj)
obj
end
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/collector.rb b/lib/puppet/parser/collector.rb
index b8165a84f..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.store_resource(scope, resource)
+ scope.compiler.add_resource(scope, resource)
return resource
end
diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compiler.rb
index f76103a28..132ec15db 100644
--- a/lib/puppet/parser/compile.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -7,7 +7,7 @@ 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
+class Puppet::Parser::Compiler
include Puppet::Util
include Puppet::Util::Errors
attr_reader :parser, :node, :facts, :collections, :catalog, :node_scope
@@ -17,6 +17,29 @@ 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)
+ # 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
+ # 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
@@ -26,10 +49,10 @@ class Puppet::Parser::Compile
# 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
@@ -54,7 +77,7 @@ class Puppet::Parser::Compile
return @catalog.classes
end
- # Compile our catalog. This mostly revolves around finding and evaluating classes.
+ # 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.
@@ -68,10 +91,10 @@ class Puppet::Parser::Compile
evaluate_generators()
- fail_on_unevaluated()
-
finish()
+ fail_on_unevaluated()
+
if Puppet[:storeconfigs]
store()
end
@@ -84,11 +107,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
@@ -120,16 +138,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]
@@ -140,10 +153,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
@@ -158,7 +169,7 @@ class Puppet::Parser::Compile
begin
send(param.to_s + "=", value)
rescue NoMethodError
- raise ArgumentError, "Compile objects do not accept %s" % param
+ raise ArgumentError, "Compiler objects do not accept %s" % param
end
end
@@ -171,10 +182,10 @@ class Puppet::Parser::Compile
# its parent to the graph.
def newscope(parent, options = {})
parent ||= topscope
- options[:compile] = self
+ 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
@@ -195,35 +206,7 @@ class Puppet::Parser::Compile
# Return a list of all resources.
def resources
- @resource_table.values
- end
-
- # 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)
- 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)
- # This might throw an exception
- verify_uniqueness(resource)
-
- # Store it in the global table.
- @resource_table[resource.ref] = 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)
+ @catalog.vertices
end
# The top scope is usually the top-level scope, but if we're using AST nodes,
@@ -250,9 +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)
- @catalog.tag(astnode.classname)
+ resource = astnode.evaluate(topscope)
resource.evaluate
@@ -285,11 +266,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
@@ -309,6 +294,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
@@ -322,9 +310,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
@@ -380,14 +366,29 @@ 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) }
+ @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)
+ @topscope = Puppet::Parser::Scope.new(:compiler => self, :parser => self.parser)
+ @scope_graph.add_vertex(@topscope)
end
# Set up all of our internal variables.
@@ -396,9 +397,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 = {}
@@ -412,9 +410,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
@@ -443,7 +438,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.
@@ -466,9 +461,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
@@ -476,33 +469,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/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/lexer.rb b/lib/puppet/parser/lexer.rb
index 086d82c09..6661650ba 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -1,4 +1,3 @@
-
# the scanner/lexer
require 'strscan'
@@ -7,326 +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 = {
- "{" => "}",
- "(" => ")",
- "[" => "]",
- "<|" => "|>",
- "<<|" => "|>>"
- }
-
- @@reverse_pairs = @@pairs.inject({}) { |hash, pair| hash[pair[1]] = pair[0]; hash }
-
- @@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
- #Puppet.debug("got token '%s' => '%s'" % [token,str])
- if token.nil?
- return array
- else
- array.push([token,str])
- end
- }
- return array
- end
+class Puppet::Parser::Lexer
+ attr_reader :last, :file
+
+ attr_accessor :line, :indefine
- # 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)
- }
+ # Our base token class.
+ class Token
+ attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text
+
+ 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
- # Go up one in the namespace.
- def namepop
- @namestack.pop
+ # Look up a token by its value, rather than name.
+ def lookup(string)
+ @tokens_by_string[string]
+ end
+
+ # Define more tokens.
+ def add_tokens(hash)
+ hash.each do |regex, name|
+ add_token(name, regex)
end
+ end
- # Collect the current namespace.
- def namespace
- @namestack.join("::")
+ # Sort our tokens by length, so we know once we match, we're done.
+ # This helps us avoid the O(n^2) nature of token matching.
+ def sort_tokens
+ @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
+ end
+ end
+
+ TOKENS = TokenList.new
+ TOKENS.add_tokens(
+ '[' => :LBRACK,
+ ']' => :RBRACK,
+ '{' => :LBRACE,
+ '}' => :RBRACE,
+ '(' => :LPAREN,
+ ')' => :RPAREN,
+ '=' => :EQUALS,
+ '==' => :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
- # 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
+ 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
+
+ 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")
- if @scanner.nil?
- raise TypeError.new("Invalid or empty string")
- end
+ return matched_token, value
+ end
- @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
- tmp = @scanner.check(regex)
- if tmp.nil?
- #puppet.debug("did not match %s to '%s'" %
- # [regex,@scanner.rest])
- next
- end
-
- # 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
+ # Find the next token, returning the string and the token.
+ def find_token
+ @find += 1
+ matched_token, value = find_regex_token
- value = @scanner.scan(sregex)
+ unless matched_token
+ matched_token, value = find_string_token
+ end
- if value == ""
- raise "Didn't match regex on token %s" % stoken
- end
+ return matched_token, value
+ end
- # 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
+ def indefine?
+ if defined? @indefine
+ @indefine
+ else
+ false
+ end
+ end
- 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
+ def initialize
+ @find = 0
+ @regex = 0
+ initvars()
+ end
- yield [ptoken, value]
+ 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
- if @lasttoken == :CLASS
- namestack(value)
- end
+ # Make any necessary changes to the token and/or value.
+ def munge_token(token, value)
+ @line += 1 if token.incr_line
- if @lasttoken == :DEFINE
- if indefine?
- msg = "Cannot nest definition %s inside %s" % [value, @indefine]
- self.indefine = false
- raise Puppet::ParseError, msg
- end
+ skip() if token.skip_text
- @indefine = value
- end
+ return if token.skip
- @last = value
- @lasttoken = ptoken
+ token, value = token.convert(self, value) if token.respond_to?(:convert)
- @scanner.skip(@skip)
- end
- @scanner = nil
- yield [false,false]
- end
+ 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 b7c68e630..ccfc4d48a 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
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
index 3f346166e..fb0799011 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)
@@ -58,8 +58,7 @@ class Puppet::Parser::Resource
def evaluate
if klass = @ref.definedtype
finish()
- scope.compile.delete_resource(self)
- return klass.evaluate(:scope => scope, :resource => self)
+ return klass.evaluate_code(self)
elsif builtin?
devfail "Cannot evaluate a builtin type"
else
@@ -83,9 +82,9 @@ 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()
validate()
end
@@ -130,13 +129,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 +217,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]
@@ -260,6 +237,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)
}
@@ -361,16 +340,9 @@ 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
+ def add_scope_tags
+ if scope_resource = scope.resource
+ tag(*scope_resource.tags)
end
end
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/resource/reference.rb b/lib/puppet/parser/resource/reference.rb
index 6e70d23b7..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)
@@ -49,7 +53,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
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index 028414cc0..a6e43e7b3 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -17,15 +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
+ 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
@@ -72,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.
@@ -147,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)
@@ -184,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
@@ -199,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,
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/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
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
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
diff --git a/lib/puppet/resource_reference.rb b/lib/puppet/resource_reference.rb
index 3e92662b2..771a91be7 100644
--- a/lib/puppet/resource_reference.rb
+++ b/lib/puppet/resource_reference.rb
@@ -36,7 +36,7 @@ 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 =~ /^(.+)\[(.+)\]$/
+ if value =~ /^([^\[\]]+)\[(.+)\]$/
self.type = $1
@title = $2
else
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/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/transaction.rb b/lib/puppet/transaction.rb
index 6a4981298..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
@@ -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/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/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
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 5bb3158c4..7d3b1abe1 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -229,6 +229,15 @@ module Puppet
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
the ``path`` attribute. Multiple environment variables should be
@@ -554,32 +563,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]
diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb
index be5c2ed72..3e34c0b60 100755
--- a/lib/puppet/type/host.rb
+++ b/lib/puppet/type/host.rb
@@ -4,6 +4,13 @@ module Puppet
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 +85,12 @@ module Puppet
desc "The host name."
isnamevar
+
+ validate do |value|
+ unless value =~ /^\w+-?[\w+]?\.?[\w+.{1}]*\w+$/
+ raise Puppet::Error, "Invalid host name"
+ end
+ end
end
@doc = "Installs and manages host entries. For most systems, these
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
}
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/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
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
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)
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index f87f96980..2c8fc682a 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -421,19 +421,19 @@ class Puppet::Util::Settings
objects += add_user_resources(section, obj, done)
end
+ value = obj.value
+
# 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 and 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
@@ -1036,7 +1036,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
@@ -1065,12 +1065,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")
diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb
new file mode 100644
index 000000000..9abb3fb2b
--- /dev/null
+++ b/lib/puppet/util/tagging.rb
@@ -0,0 +1,39 @@
+# 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
+
+ # 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
+ @tags ||= []
+ @tags.dup
+ end
+
+ private
+
+ def valid_tag?(tag)
+ tag =~ /^\w[-\w:]*$/
+ end
+end
diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb
index 3833890f7..aa49909e2 100755
--- a/spec/unit/node/catalog.rb
+++ b/spec/unit/node/catalog.rb
@@ -57,11 +57,11 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do
def mkscope
@parser = Puppet::Parser::Parser.new :Code => ""
@node = Puppet::Node.new("mynode")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
# XXX This is ridiculous.
- @compile.send(:evaluate_main)
- @scope = @compile.topscope
+ @compiler.send(:evaluate_main)
+ @scope = @compiler.topscope
end
def mkresource(type, name)
@@ -75,7 +75,7 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do
@source = mock 'source'
main = mkresource("class", :main)
- config.add_vertex!(main)
+ config.add_vertex(main)
bucket = mock 'bucket'
bucket.expects(:classes=).with(config.classes)
@@ -95,7 +95,7 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do
defined = mkresource("class", :main)
builtin = mkresource("file", "/yay")
- config.add_edge!(defined, builtin)
+ config.add_edge(defined, builtin)
bucket = []
bucket.expects(:classes=).with(config.classes)
@@ -121,21 +121,21 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do
top.expects(:to_trans).returns(topbucket)
topres = mkresource "file", "/top"
topres.expects(:to_trans).returns(:topres)
- config.add_edge! top, topres
+ config.add_edge top, topres
middle = mkresource "class", "middle"
middle.expects(:to_trans).returns([])
- config.add_edge! top, middle
+ config.add_edge top, middle
midres = mkresource "file", "/mid"
midres.expects(:to_trans).returns(:midres)
- config.add_edge! middle, midres
+ config.add_edge middle, midres
bottom = mkresource "class", "bottom"
bottom.expects(:to_trans).returns([])
- config.add_edge! middle, bottom
+ config.add_edge middle, bottom
botres = mkresource "file", "/bot"
botres.expects(:to_trans).returns(:botres)
- config.add_edge! bottom, botres
+ config.add_edge bottom, botres
toparray = config.extract_to_transportable
@@ -196,13 +196,13 @@ describe Puppet::Node::Catalog, " when converting to a transobject catalog" do
@resources = [@top, @topobject, @middle, @middleobject, @bottom, @bottomobject]
- @original.add_edge!(@top, @topobject)
- @original.add_edge!(@top, @virtual)
- @original.add_edge!(@virtual, @virtualobject)
- @original.add_edge!(@top, @middle)
- @original.add_edge!(@middle, @middleobject)
- @original.add_edge!(@middle, @bottom)
- @original.add_edge!(@bottom, @bottomobject)
+ @original.add_edge(@top, @topobject)
+ @original.add_edge(@top, @virtual)
+ @original.add_edge(@virtual, @virtualobject)
+ @original.add_edge(@top, @middle)
+ @original.add_edge(@middle, @middleobject)
+ @original.add_edge(@middle, @bottom)
+ @original.add_edge(@bottom, @bottomobject)
@catalog = @original.to_transportable
end
@@ -261,11 +261,11 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do
@original.add_resource(*@resources)
- @original.add_edge!(@top, @topobject)
- @original.add_edge!(@top, @middle)
- @original.add_edge!(@middle, @middleobject)
- @original.add_edge!(@middle, @bottom)
- @original.add_edge!(@bottom, @bottomobject)
+ @original.add_edge(@top, @topobject)
+ @original.add_edge(@top, @middle)
+ @original.add_edge(@middle, @middleobject)
+ @original.add_edge(@middle, @bottom)
+ @original.add_edge(@bottom, @bottomobject)
@catalog = @original.to_ral
end
@@ -300,7 +300,7 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do
config.add_resource(changer)
config.add_resource(@top)
- config.add_edge!(@top, changer)
+ config.add_edge(@top, changer)
resource = stub 'resource', :name => "changer2", :title => "changer2", :ref => "Test[changer2]", :catalog= => nil, :remove => nil
@@ -365,6 +365,12 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
it "should not allow two resources with the same resource reference" do
@catalog.add_resource(@one)
+
+ # These are used to build the failure
+ @dupe.stubs(:file)
+ @dupe.stubs(:line)
+ @one.stubs(:file)
+ @one.stubs(:line)
proc { @catalog.add_resource(@dupe) }.should raise_error(ArgumentError)
end
@@ -591,8 +597,8 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@file = Puppet::Type.type(:file)
@one = @file.create :path => "/one"
@two = @file.create :path => "/two"
- @catalog.add_edge! @compone, @one
- @catalog.add_edge! @comptwo, @two
+ @catalog.add_edge @compone, @one
+ @catalog.add_edge @comptwo, @two
@three = @file.create :path => "/three"
@four = @file.create :path => "/four", :require => ["file", "/three"]
@@ -765,7 +771,7 @@ end
describe Puppet::Node::Catalog, " when converting to yaml" do
before do
@catalog = Puppet::Node::Catalog.new("me")
- @catalog.add_edge!("one", "two")
+ @catalog.add_edge("one", "two")
end
it "should be able to be dumped to yaml" do
@@ -776,7 +782,7 @@ end
describe Puppet::Node::Catalog, " when converting from yaml" do
before do
@catalog = Puppet::Node::Catalog.new("me")
- @catalog.add_edge!("one", "two")
+ @catalog.add_edge("one", "two")
text = YAML.dump(@catalog)
@newcatalog = YAML.load(text)
diff --git a/spec/unit/other/pgraph.rb b/spec/unit/other/pgraph.rb
index 252a807ec..7d66ae331 100755
--- a/spec/unit/other/pgraph.rb
+++ b/spec/unit/other/pgraph.rb
@@ -35,8 +35,8 @@ describe Puppet::PGraph do
end
it "should correctly clear vertices and edges when asked" do
- @graph.add_edge!("a", "b")
- @graph.add_vertex! "c"
+ @graph.add_edge("a", "b")
+ @graph.add_vertex "c"
@graph.clear
@graph.vertices.should be_empty
@graph.edges.should be_empty
@@ -52,7 +52,7 @@ describe Puppet::PGraph, " when matching edges" do
@edges = {}
@edges["a/b"] = Puppet::Relationship.new("a", "b", {:event => :yay, :callback => :refresh})
@edges["a/c"] = Puppet::Relationship.new("a", "c", {:event => :yay, :callback => :refresh})
- @graph.add_edge!(@edges["a/b"])
+ @graph.add_edge(@edges["a/b"])
end
it "should match edges whose source matches the source of the event" do
@@ -64,7 +64,7 @@ describe Puppet::PGraph, " when matching edges" do
end
it "should match multiple edges" do
- @graph.add_edge!(@edges["a/c"])
+ @graph.add_edge(@edges["a/c"])
edges = @graph.matching_edges([@event])
edges.should be_include(@edges["a/b"])
edges.should be_include(@edges["a/c"])
@@ -75,9 +75,9 @@ describe Puppet::PGraph, " when determining dependencies" do
before do
@graph = Puppet::PGraph.new
- @graph.add_edge!("a", "b")
- @graph.add_edge!("a", "c")
- @graph.add_edge!("b", "d")
+ @graph.add_edge("a", "b")
+ @graph.add_edge("a", "c")
+ @graph.add_edge("b", "d")
end
it "should find all dependents when they are on multiple levels" do
@@ -118,19 +118,19 @@ describe Puppet::PGraph, " when splicing the relationship graph" do
# We have to add the container to the main graph, else it won't
# be spliced in the dependency graph.
- @contgraph.add_vertex!(@empty)
+ @contgraph.add_vertex(@empty)
end
def dependency_graph
@depgraph = Puppet::PGraph.new
@contgraph.vertices.each do |v|
- @depgraph.add_vertex!(v)
+ @depgraph.add_vertex(v)
end
# We have to specify a relationship to our empty container, else it
# never makes it into the dep graph in the first place.
{@one => @two, "f" => "c", "h" => @middle, "c" => @empty}.each do |source, target|
- @depgraph.add_edge!(source, target, :callback => :refresh)
+ @depgraph.add_edge(source, target, :callback => :refresh)
end
end
@@ -176,13 +176,13 @@ describe Puppet::PGraph, " when splicing the relationship graph" do
end
it "should not add labels to edges that have none" do
- @depgraph.add_edge!(@two, @three)
+ @depgraph.add_edge(@two, @three)
splice
@depgraph.edge_label("c", "i").should == {}
end
it "should copy labels over edges that have none" do
- @depgraph.add_edge!("c", @three, {:callback => :refresh})
+ @depgraph.add_edge("c", @three, {:callback => :refresh})
splice
# And make sure the label got copied.
@depgraph.edge_label("c", "i").should == {:callback => :refresh}
@@ -190,18 +190,18 @@ describe Puppet::PGraph, " when splicing the relationship graph" do
it "should not replace a label with a nil label" do
# Lastly, add some new label-less edges and make sure the label stays.
- @depgraph.add_edge!(@middle, @three)
- @depgraph.add_edge!("c", @three, {:callback => :refresh})
+ @depgraph.add_edge(@middle, @three)
+ @depgraph.add_edge("c", @three, {:callback => :refresh})
splice
@depgraph.edge_label("c", "i").should == {:callback => :refresh}
end
it "should copy labels to all created edges" do
- @depgraph.add_edge!(@middle, @three)
- @depgraph.add_edge!("c", @three, {:callback => :refresh})
+ @depgraph.add_edge(@middle, @three)
+ @depgraph.add_edge("c", @three, {:callback => :refresh})
splice
@three.each do |child|
- edge = @depgraph.edge_class.new("c", child)
+ edge = Puppet::Relationship.new("c", child)
@depgraph.should be_edge(edge.source, edge.target)
@depgraph.edge_label(edge.source, edge.target).should == {:callback => :refresh}
end
diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb
index a27fb4721..f236e23b7 100755
--- a/spec/unit/parser/ast/definition.rb
+++ b/spec/unit/parser/ast/definition.rb
@@ -12,8 +12,8 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do
@source = @parser.newclass ""
@definition = @parser.newdefine "mydefine"
@node = Puppet::Node.new("yaynode")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- @scope = @compile.topscope
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
+ @scope = @compiler.topscope
@resource = Puppet::Parser::Resource.new(:type => "mydefine", :title => "myresource", :scope => @scope, :source => @source)
end
@@ -21,12 +21,12 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do
it "should create a new scope" do
scope = nil
code = mock 'code'
- code.expects(:safeevaluate).with do |options|
- options[:scope].object_id.should_not == @scope.object_id
+ code.expects(:safeevaluate).with do |scope|
+ scope.object_id.should_not == @scope.object_id
true
end
@definition.stubs(:code).returns(code)
- @definition.evaluate(:scope => @scope, :resource => @resource)
+ @definition.evaluate_code(@resource)
end
# it "should copy its namespace to the scope"
@@ -44,4 +44,152 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do
# it "should not copy the resource's title as the name if 'name' is one of the resource parameters"
#
# it "should evaluate the associated code with the new scope"
+
+ def test_initialize
+ parser = mkparser
+
+ # Create a new definition
+ klass = parser.newdefine "yayness",
+ :arguments => [["owner", stringobj("nobody")], %w{mode}],
+ :code => AST::ASTArray.new(
+ :children => [resourcedef("file", "/tmp/$name",
+ "owner" => varref("owner"), "mode" => varref("mode"))]
+ )
+
+ # Test validattr? a couple different ways
+ [:owner, "owner", :schedule, "schedule"].each do |var|
+ assert(klass.validattr?(var), "%s was not considered valid" % var.inspect)
+ end
+
+ [:random, "random"].each do |var|
+ assert(! klass.validattr?(var), "%s was considered valid" % var.inspect)
+ end
+
+ end
+
+ def test_evaluate
+ parser = mkparser
+ config = mkcompiler
+ config.send(:evaluate_main)
+ scope = config.topscope
+ klass = parser.newdefine "yayness",
+ :arguments => [["owner", stringobj("nobody")], %w{mode}],
+ :code => AST::ASTArray.new(
+ :children => [resourcedef("file", "/tmp/$name",
+ "owner" => varref("owner"), "mode" => varref("mode"))]
+ )
+
+ resource = Puppet::Parser::Resource.new(
+ :title => "first",
+ :type => "yayness",
+ :exported => false,
+ :virtual => false,
+ :scope => scope,
+ :source => scope.source
+ )
+ resource.send(:set_parameter, "name", "first")
+ resource.send(:set_parameter, "mode", "755")
+
+ resource.stubs(:title)
+ assert_nothing_raised do
+ klass.evaluate_code(resource)
+ end
+
+ firstobj = config.findresource("File[/tmp/first]")
+ assert(firstobj, "Did not create /tmp/first obj")
+
+ assert_equal("File", firstobj.type)
+ assert_equal("/tmp/first", firstobj.title)
+ assert_equal("nobody", firstobj[:owner])
+ assert_equal("755", firstobj[:mode])
+
+ # Make sure we can't evaluate it with the same args
+ assert_raise(Puppet::ParseError) do
+ klass.evaluate_code(resource)
+ end
+
+ # Now create another with different args
+ resource2 = Puppet::Parser::Resource.new(
+ :title => "second",
+ :type => "yayness",
+ :exported => false,
+ :virtual => false,
+ :scope => scope,
+ :source => scope.source
+ )
+ resource2.send(:set_parameter, "name", "second")
+ resource2.send(:set_parameter, "mode", "755")
+ resource2.send(:set_parameter, "owner", "daemon")
+
+ assert_nothing_raised do
+ klass.evaluate_code(resource2)
+ end
+
+ secondobj = config.findresource("File[/tmp/second]")
+ assert(secondobj, "Did not create /tmp/second obj")
+
+ assert_equal("File", secondobj.type)
+ assert_equal("/tmp/second", secondobj.title)
+ assert_equal("daemon", secondobj[:owner])
+ assert_equal("755", secondobj[:mode])
+ end
+
+ # #539 - definitions should support both names and titles
+ def test_names_and_titles
+ parser = mkparser
+ scope = mkscope :parser => parser
+
+ [
+ {:name => "one", :title => "two"},
+ {:title => "mytitle"}
+ ].each_with_index do |hash, i|
+ # Create a definition that uses both name and title. Put this
+ # inside the loop so the subscope expectations work.
+ klass = parser.newdefine "yayness%s" % i
+
+ resource = Puppet::Parser::Resource.new(
+ :title => hash[:title],
+ :type => "yayness%s" % i,
+ :exported => false,
+ :virtual => false,
+ :scope => scope,
+ :source => scope.source
+ )
+
+ subscope = klass.subscope(scope, resource)
+
+ klass.expects(:subscope).returns(subscope)
+
+ if hash[:name]
+ resource.stubs(:to_hash).returns({:name => hash[:name]})
+ end
+
+ assert_nothing_raised("Could not evaluate definition with %s" % hash.inspect) do
+ klass.evaluate_code(resource)
+ end
+
+ name = hash[:name] || hash[:title]
+ title = hash[:title]
+
+ assert_equal(name, subscope.lookupvar("name"),
+ "Name did not get set correctly")
+ assert_equal(title, subscope.lookupvar("title"),
+ "title did not get set correctly")
+
+ [:name, :title].each do |param|
+ val = resource.send(param)
+ assert(subscope.tags.include?(val),
+ "Scope was not tagged with %s '%s'" % [param, val])
+ end
+ end
+ end
+
+ # Testing the root cause of #615. We should be using the fqname for the type, instead
+ # of just the short name.
+ def test_fully_qualified_types
+ parser = mkparser
+ klass = parser.newclass("one::two")
+
+ assert_equal("one::two", klass.classname, "Class did not get fully qualified class name")
+ end
end
diff --git a/spec/unit/parser/ast/hostclass.rb b/spec/unit/parser/ast/hostclass.rb
new file mode 100755
index 000000000..422861857
--- /dev/null
+++ b/spec/unit/parser/ast/hostclass.rb
@@ -0,0 +1,131 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+module HostClassTesting
+ def setup
+ @node = Puppet::Node.new "testnode"
+ @parser = Puppet::Parser::Parser.new :environment => "development"
+ @scope_resource = stub 'scope_resource', :builtin? => true
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
+
+ @scope = @compiler.topscope
+ end
+end
+
+describe Puppet::Parser::AST::HostClass, "when evaluating" do
+ include HostClassTesting
+
+ before do
+ @top = @parser.newclass "top"
+ @middle = @parser.newclass "middle", :parent => "top"
+ end
+
+ it "should create a resource that references itself" do
+ @top.evaluate(@scope)
+
+ @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should evaluate the parent class if one exists" do
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should fail to evaluate if a parent class is defined but cannot be found" do
+ othertop = @parser.newclass "something", :parent => "yay"
+ lambda { othertop.evaluate(@scope) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should not create a new resource if one already exists" do
+ @compiler.catalog.expects(:resource).with(:class, "top").returns("something")
+ @compiler.catalog.expects(:add_resource).never
+ @top.evaluate(@scope)
+ end
+
+ it "should not create a new parent resource if one already exists and it has a parent class" do
+ @top.evaluate(@scope)
+
+ top_resource = @compiler.catalog.resource(:class, "top")
+
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.resource(:class, "top").should equal(top_resource)
+ end
+
+ # #795 - tag before evaluation.
+ it "should tag the catalog with the resource tags when it is evaluated" do
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.should be_tagged("middle")
+ end
+
+ it "should tag the catalog with the parent class tags when it is evaluated" do
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.should be_tagged("top")
+ end
+end
+
+describe Puppet::Parser::AST::HostClass, "when evaluating code" do
+ include HostClassTesting
+
+ before do
+ @top_resource = stub "top_resource"
+ @top = @parser.newclass "top", :code => @top_resource
+
+ @middle_resource = stub "middle_resource"
+ @middle = @parser.newclass "top::middle", :parent => "top", :code => @middle_resource
+ end
+
+ it "should set its namespace to its fully qualified name" do
+ @middle.namespace.should == "top::middle"
+ end
+
+ it "should evaluate the code referred to by the class" do
+ @top_resource.expects(:safeevaluate)
+
+ resource = @top.evaluate(@scope)
+
+ @top.evaluate_code(resource)
+ end
+
+ it "should evaluate the parent class's code if it has a parent" do
+ @top_resource.expects(:safeevaluate)
+ @middle_resource.expects(:safeevaluate)
+
+ resource = @middle.evaluate(@scope)
+
+ @middle.evaluate_code(resource)
+ end
+
+ it "should not evaluate the parent class's code if the parent has already been evaluated" do
+ @top_resource.stubs(:safeevaluate)
+ resource = @top.evaluate(@scope)
+ @top.evaluate_code(resource)
+
+ @top_resource.expects(:safeevaluate).never
+ @middle_resource.stubs(:safeevaluate)
+ resource = @middle.evaluate(@scope)
+ @middle.evaluate_code(resource)
+ end
+
+ it "should use the parent class's scope as its parent scope" do
+ @top_resource.stubs(:safeevaluate)
+ @middle_resource.stubs(:safeevaluate)
+ resource = @middle.evaluate(@scope)
+ @middle.evaluate_code(resource)
+
+ @compiler.class_scope(@middle).parent.should equal(@compiler.class_scope(@top))
+ end
+
+ it "should add the parent class's namespace to its namespace search path" do
+ @top_resource.stubs(:safeevaluate)
+ @middle_resource.stubs(:safeevaluate)
+ resource = @middle.evaluate(@scope)
+ @middle.evaluate_code(resource)
+
+ @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace)
+ end
+end
diff --git a/spec/unit/parser/ast/node.rb b/spec/unit/parser/ast/node.rb
new file mode 100755
index 000000000..340630194
--- /dev/null
+++ b/spec/unit/parser/ast/node.rb
@@ -0,0 +1,127 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+module ASTNodeTesting
+ def setup
+ @node = Puppet::Node.new "testnode"
+ @parser = Puppet::Parser::Parser.new :environment => "development"
+ @scope_resource = stub 'scope_resource', :builtin? => true
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
+
+ @scope = @compiler.topscope
+ end
+end
+
+describe Puppet::Parser::AST::Node, "when evaluating" do
+ include ASTNodeTesting
+
+ before do
+ @top = @parser.newnode("top").shift
+ @middle = @parser.newnode("middle", :parent => "top").shift
+ end
+
+ it "should create a resource that references itself" do
+ @top.evaluate(@scope)
+
+ @compiler.catalog.resource(:node, "top").should be_an_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should evaluate the parent class if one exists" do
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.resource(:node, "top").should be_an_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should fail to evaluate if a parent class is defined but cannot be found" do
+ othertop = @parser.newnode("something", :parent => "yay").shift
+ lambda { othertop.evaluate(@scope) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should not create a new resource if one already exists" do
+ @compiler.catalog.expects(:resource).with(:node, "top").returns("something")
+ @compiler.catalog.expects(:add_resource).never
+ @top.evaluate(@scope)
+ end
+
+ it "should not create a new parent resource if one already exists and it has a parent class" do
+ @top.evaluate(@scope)
+
+ top_resource = @compiler.catalog.resource(:node, "top")
+
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.resource(:node, "top").should equal(top_resource)
+ end
+
+ # #795 - tag before evaluation.
+ it "should tag the catalog with the resource tags when it is evaluated" do
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.should be_tagged("middle")
+ end
+
+ it "should tag the catalog with the parent class tags when it is evaluated" do
+ @middle.evaluate(@scope)
+
+ @compiler.catalog.should be_tagged("top")
+ end
+end
+
+describe Puppet::Parser::AST::Node, "when evaluating code" do
+ include ASTNodeTesting
+
+ before do
+ @top_resource = stub "top_resource"
+ @top = @parser.newnode("top", :code => @top_resource).shift
+
+ @middle_resource = stub "middle_resource"
+ @middle = @parser.newnode("middle", :parent => "top", :code => @middle_resource).shift
+ end
+
+ it "should evaluate the code referred to by the class" do
+ @top_resource.expects(:safeevaluate)
+
+ resource = @top.evaluate(@scope)
+
+ @top.evaluate_code(resource)
+ end
+
+ it "should evaluate the parent class's code if it has a parent" do
+ @top_resource.expects(:safeevaluate)
+ @middle_resource.expects(:safeevaluate)
+
+ resource = @middle.evaluate(@scope)
+
+ @middle.evaluate_code(resource)
+ end
+
+ it "should not evaluate the parent class's code if the parent has already been evaluated" do
+ @top_resource.stubs(:safeevaluate)
+ resource = @top.evaluate(@scope)
+ @top.evaluate_code(resource)
+
+ @top_resource.expects(:safeevaluate).never
+ @middle_resource.stubs(:safeevaluate)
+ resource = @middle.evaluate(@scope)
+ @middle.evaluate_code(resource)
+ end
+
+ it "should use the parent class's scope as its parent scope" do
+ @top_resource.stubs(:safeevaluate)
+ @middle_resource.stubs(:safeevaluate)
+ resource = @middle.evaluate(@scope)
+ @middle.evaluate_code(resource)
+
+ @compiler.class_scope(@middle).parent.should equal(@compiler.class_scope(@top))
+ end
+
+ it "should add the parent class's namespace to its namespace search path" do
+ @top_resource.stubs(:safeevaluate)
+ @middle_resource.stubs(:safeevaluate)
+ resource = @middle.evaluate(@scope)
+ @middle.evaluate_code(resource)
+
+ @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace)
+ end
+end
diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb
index 9b5eab1f4..e1ceb23ed 100755
--- a/spec/unit/parser/collector.rb
+++ b/spec/unit/parser/collector.rb
@@ -79,8 +79,8 @@ describe Puppet::Parser::Collector, "when collecting specific virtual resources"
@collector.resources = ["File[virtual1]"]
one = mock 'one'
one.stubs(:virtual=)
- @compile.expects(:delete_collection).with(@collector)
- @scope.expects(:compile).returns(@compile)
+ @compiler.expects(:delete_collection).with(@collector)
+ @scope.expects(:compiler).returns(@compiler)
@scope.stubs(:findresource).with("File[virtual1]").returns(one)
@collector.evaluate
end
@@ -89,7 +89,7 @@ describe Puppet::Parser::Collector, "when collecting specific virtual resources"
@collector.resources = ["File[virtual1]"]
one = mock 'one'
one.stubs(:virtual=)
- @compile.expects(:delete_collection).never
+ @compiler.expects(:delete_collection).never
@scope.stubs(:findresource).with("File[virtual1]").returns(nil)
@collector.evaluate
end
@@ -98,8 +98,8 @@ end
describe Puppet::Parser::Collector, "when collecting virtual resources" do
before do
@scope = mock 'scope'
- @compile = mock 'compile'
- @scope.stubs(:compile).returns(@compile)
+ @compiler = mock 'compile'
+ @scope.stubs(:compiler).returns(@compiler)
@resource_type = "Mytype"
@vquery = proc { |res| true }
@@ -113,7 +113,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.stubs(:virtual=)
two.stubs(:virtual=)
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector.evaluate.should == [one, two]
end
@@ -123,7 +123,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.expects(:virtual=).with(false)
- @compile.expects(:resources).returns([one])
+ @compiler.expects(:resources).returns([one])
@collector.evaluate
end
@@ -135,7 +135,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.stubs(:virtual=)
two.stubs(:virtual=)
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector.evaluate.should == [one, two]
end
@@ -147,7 +147,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.expects(:virtual=).with(false)
two.expects(:virtual=).with(false)
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector = Puppet::Parser::Collector.new(@scope, @resource_type, nil, nil, :virtual)
@@ -161,7 +161,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.expects(:virtual=).with(false)
two.expects(:virtual=).never
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector.evaluate.should == [one]
end
@@ -173,7 +173,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.expects(:virtual=).never
two.expects(:virtual=).never
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector.evaluate.should be_false
end
@@ -187,7 +187,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do
one.expects(:virtual=).with(false)
two.expects(:virtual=).never
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector.evaluate.should == [one]
end
@@ -198,8 +198,8 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
before do
@scope = stub 'scope', :host => "myhost", :debug => nil
- @compile = mock 'compile'
- @scope.stubs(:compile).returns(@compile)
+ @compiler = mock 'compile'
+ @scope.stubs(:compiler).returns(@compiler)
@resource_type = "Mytype"
@equery = "test = true"
@vquery = proc { |r| true }
@@ -218,7 +218,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
end
it "should use initialize the Rails support if ActiveRecord is not connected" do
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
ActiveRecord::Base.expects(:connected?).returns(false)
Puppet::Rails.expects(:init)
Puppet::Rails::Host.stubs(:find_by_name).returns(nil)
@@ -238,7 +238,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
two.stubs(:exported=)
two.stubs(:virtual=)
- @compile.expects(:resources).returns([one, two])
+ @compiler.expects(:resources).returns([one, two])
@collector.evaluate.should == [one, two]
end
@@ -251,7 +251,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
one.stubs(:exported=)
one.expects(:virtual=).with(false)
- @compile.expects(:resources).returns([one])
+ @compiler.expects(:resources).returns([one])
@collector.evaluate.should == [one]
end
@@ -268,10 +268,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
resource.stubs(:exported=)
resource.stubs(:virtual=)
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
@scope.stubs(:findresource).returns(nil)
- @compile.stubs(:store_resource)
+ @compiler.stubs(:add_resource)
@collector.evaluate.should == [resource]
end
@@ -288,10 +288,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
resource.stubs(:exported=)
resource.stubs(:virtual=)
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
@scope.stubs(:findresource).returns(nil)
- @compile.expects(:store_resource).with(@scope, resource)
+ @compiler.expects(:add_resource).with(@scope, resource)
@collector.evaluate.should == [resource]
end
@@ -309,10 +309,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
resource.expects(:exported=).with(false)
resource.stubs(:virtual=)
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
@scope.stubs(:findresource).returns(nil)
- @compile.stubs(:store_resource)
+ @compiler.stubs(:add_resource)
@collector.evaluate
end
@@ -328,10 +328,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
resource = mock 'resource'
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
@scope.stubs(:findresource).returns(inmemory)
- @compile.stubs(:store_resource)
+ @compiler.stubs(:add_resource)
proc { @collector.evaluate }.should raise_error(Puppet::ParseError)
end
@@ -347,10 +347,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
resource = mock 'resource'
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
@scope.stubs(:findresource).returns(inmemory)
- @compile.stubs(:store_resource)
+ @compiler.stubs(:add_resource)
proc { @collector.evaluate }.should_not raise_error(Puppet::ParseError)
end
@@ -361,14 +361,14 @@ describe Puppet::Parser::Collector, "when building its ActiveRecord query for co
before do
@scope = stub 'scope', :host => "myhost", :debug => nil
- @compile = mock 'compile'
- @scope.stubs(:compile).returns(@compile)
+ @compiler = mock 'compile'
+ @scope.stubs(:compiler).returns(@compiler)
@resource_type = "Mytype"
@equery = nil
@vquery = proc { |r| true }
@collector = Puppet::Parser::Collector.new(@scope, @resource_type, @equery, @vquery, :exported)
- @compile.stubs(:resources).returns([])
+ @compiler.stubs(:resources).returns([])
ActiveRecord::Base.stubs(:connected?).returns(false)
diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb
deleted file mode 100755
index 092bece0c..000000000
--- a/spec/unit/parser/compile.rb
+++ /dev/null
@@ -1,281 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../spec_helper'
-
-describe Puppet::Parser::Compile, " when compiling" do
- before do
- @node = stub 'node', :name => 'mynode'
- @parser = stub 'parser', :version => "1.0"
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- end
-
- def compile_methods
- [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated,
- :finish, :store, :extract]
- end
-
- # Stub all of the main compile methods except the ones we're specifically interested in.
- def compile_stub(*except)
- (compile_methods - except).each { |m| @compile.stubs(m) }
- end
-
- it "should set node parameters as variables in the top scope" do
- params = {"a" => "b", "c" => "d"}
- @node.stubs(:parameters).returns(params)
- compile_stub(:set_node_parameters)
- @compile.compile
- @compile.topscope.lookupvar("a").should == "b"
- @compile.topscope.lookupvar("c").should == "d"
- end
-
- it "should evaluate any existing classes named in the node" do
- classes = %w{one two three four}
- main = stub 'main'
- one = stub 'one', :classname => "one"
- three = stub 'three', :classname => "three"
- @node.stubs(:name).returns("whatever")
- @node.stubs(:classes).returns(classes)
-
- @compile.expects(:evaluate_classes).with(classes, @compile.topscope)
- @compile.send :evaluate_node_classes
- end
-
- it "should enable ast_nodes if the parser has any nodes" do
- @parser.expects(:nodes).returns(:one => :yay)
- @compile.ast_nodes?.should be_true
- end
-
- it "should disable ast_nodes if the parser has no nodes" do
- @parser.expects(:nodes).returns({})
- @compile.ast_nodes?.should be_false
- end
-end
-
-describe Puppet::Parser::Compile, " when evaluating classes" do
- before do
- @node = stub 'node', :name => 'mynode'
- @parser = stub 'parser', :version => "1.0"
- @scope = stub 'scope', :source => mock("source")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- end
-
- it "should fail if there's no source listed for the scope" do
- scope = stub 'scope', :source => nil
- proc { @compile.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError)
- end
-
- it "should tag the catalog with the name of each not-found class" do
- @compile.catalog.expects(:tag).with("notfound")
- @scope.expects(:findclass).with("notfound").returns(nil)
- @compile.evaluate_classes(%w{notfound}, @scope)
- end
-end
-
-describe Puppet::Parser::Compile, " when evaluating collections" do
- before do
- @node = stub 'node', :name => 'mynode'
- @parser = stub 'parser', :version => "1.0"
- @scope = stub 'scope', :source => mock("source")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- end
-
- it "should evaluate each collection" do
- 2.times { |i|
- coll = mock 'coll%s' % i
- @compile.add_collection(coll)
-
- # This is the hard part -- we have to emulate the fact that
- # collections delete themselves if they are done evaluating.
- coll.expects(:evaluate).with do
- @compile.delete_collection(coll)
- end
- }
-
- @compile.class.publicize_methods(:evaluate_collections) { @compile.evaluate_collections }
- end
-end
-
-
-describe Puppet::Parser::Compile, " when evaluating found classes" do
- before do
- @node = stub 'node', :name => 'mynode'
- @parser = stub 'parser', :version => "1.0"
- @scope = stub 'scope', :source => mock("source")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
-
- @class = stub 'class', :classname => "my::class"
- @scope.stubs(:findclass).with("myclass").returns(@class)
-
- @resource = stub 'resource', :ref => 'Class[myclass]'
- end
-
- it "should create a resource for each found class" do
- @compile.catalog.stubs(:tag)
-
- @compile.stubs :store_resource
-
- Puppet::Parser::Resource.expects(:new).with(:scope => @scope, :source => @scope.source, :title => "my::class", :type => "class").returns(@resource)
- @compile.evaluate_classes(%w{myclass}, @scope)
- end
-
- it "should store each created resource in the compile" do
- @compile.catalog.stubs(:tag)
-
- @compile.expects(:store_resource).with(@scope, @resource)
-
- Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @compile.evaluate_classes(%w{myclass}, @scope)
- end
-
- it "should tag the catalog with the fully-qualified name of each found class" do
- @compile.catalog.expects(:tag).with("my::class")
-
- @compile.stubs(:store_resource)
-
- Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @compile.evaluate_classes(%w{myclass}, @scope)
- end
-
- it "should not evaluate the resources created for found classes unless asked" do
- @compile.catalog.stubs(:tag)
-
- @compile.stubs(:store_resource)
- @resource.expects(:evaluate).never
-
- Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @compile.evaluate_classes(%w{myclass}, @scope)
- end
-
- it "should immediately evaluate the resources created for found classes when asked" do
- @compile.catalog.stubs(:tag)
-
- @compile.stubs(:store_resource)
- @resource.expects(:evaluate)
-
- Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @compile.evaluate_classes(%w{myclass}, @scope, false)
- end
-
- it "should skip classes that have already been evaluated" do
- @compile.catalog.stubs(:tag)
-
- @compile.expects(:class_scope).with(@class).returns("something")
-
- @compile.expects(:store_resource).never
-
- @resource.expects(:evaluate).never
-
- Puppet::Parser::Resource.expects(:new).never
- @compile.evaluate_classes(%w{myclass}, @scope, false)
- end
-
- it "should return the list of found classes" do
- @compile.catalog.stubs(:tag)
-
- @compile.stubs(:store_resource)
- @scope.stubs(:findclass).with("notfound").returns(nil)
-
- Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @compile.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass}
- end
-end
-
-describe Puppet::Parser::Compile, " when evaluating AST nodes with no AST nodes present" do
- before do
- @node = stub 'node', :name => "foo"
- @parser = stub 'parser', :version => "1.0", :nodes => {}
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- end
-
- it "should do nothing" do
- @compile.expects(:ast_nodes?).returns(false)
- @compile.parser.expects(:nodes).never
- Puppet::Parser::Resource.expects(:new).never
-
- @compile.send(:evaluate_ast_node)
- end
-end
-
-describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes present" do
- before do
- @node = stub 'node', :name => "foo"
- @parser = stub 'parser', :version => "1.0", :nodes => {}
- @compile = Puppet::Parser::Compile.new(@node, @parser)
-
- @nodes = mock 'node_hash'
- @compile.stubs(:ast_nodes?).returns(true)
- @compile.parser.stubs(:nodes).returns(@nodes)
-
- # Set some names for our test
- @node.stubs(:names).returns(%w{a b c})
- @nodes.stubs(:[]).with("a").returns(nil)
- @nodes.stubs(:[]).with("b").returns(nil)
- @nodes.stubs(:[]).with("c").returns(nil)
-
- # It should check this last, of course.
- @nodes.stubs(:[]).with("default").returns(nil)
- end
-
- it "should fail if the named node cannot be found" do
- proc { @compile.send(:evaluate_ast_node) }.should raise_error(Puppet::ParseError)
- end
-
- it "should create a resource for the first node class matching the node name" do
- node_class = stub 'node', :classname => "c"
- @nodes.stubs(:[]).with("c").returns(node_class)
-
- node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil
- Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == "c" and args[:type] == "node" }.returns(node_resource)
-
- @compile.send(:evaluate_ast_node)
- end
-
- it "should match the default node if no matching node can be found" do
- node_class = stub 'node', :classname => "default"
- @nodes.stubs(:[]).with("default").returns(node_class)
-
- node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil
- Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == "default" and args[:type] == "node" }.returns(node_resource)
-
- @compile.send(:evaluate_ast_node)
- end
-
- it "should tag the catalog with the found node name" do
- node_class = stub 'node', :classname => "c"
- @nodes.stubs(:[]).with("c").returns(node_class)
-
- node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil
- Puppet::Parser::Resource.stubs(:new).returns(node_resource)
-
- @compile.catalog.expects(:tag).with("c")
- @compile.send(:evaluate_ast_node)
- end
-
- it "should evaluate the node resource immediately rather than using lazy evaluation" do
- node_class = stub 'node', :classname => "c"
- @nodes.stubs(:[]).with("c").returns(node_class)
-
- node_resource = stub 'node resource', :ref => "Node[c]"
- Puppet::Parser::Resource.stubs(:new).returns(node_resource)
-
- node_resource.expects(:evaluate)
-
- @compile.send(:evaluate_ast_node)
- end
-
- it "should set the node's scope as the top scope" do
- node_class = stub 'node', :classname => "c"
- @nodes.stubs(:[]).with("c").returns(node_class)
-
- node_resource = stub 'node resource', :ref => "Node[c]"
- Puppet::Parser::Resource.stubs(:new).returns(node_resource)
-
- # The #evaluate method normally does this.
- @compile.class_set(node_class.classname, :my_node_scope)
- node_resource.stubs(:evaluate)
-
- @compile.send(:evaluate_ast_node)
-
- @compile.topscope.should == :my_node_scope
- end
-end
diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb
new file mode 100755
index 000000000..6b821977d
--- /dev/null
+++ b/spec/unit/parser/compiler.rb
@@ -0,0 +1,544 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+module CompilerTesting
+ def setup
+ @node = Puppet::Node.new "testnode"
+ @parser = Puppet::Parser::Parser.new :environment => "development"
+
+ @scope_resource = stub 'scope_resource', :builtin? => true
+ @scope = stub 'scope', :resource => @scope_resource, :source => mock("source")
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
+ end
+end
+
+describe Puppet::Parser::Compiler do
+ include CompilerTesting
+
+ it "should be able to store references to class scopes" do
+ lambda { @compiler.class_set "myname", "myscope" }.should_not raise_error
+ end
+
+ it "should be able to retrieve class scopes by name" do
+ @compiler.class_set "myname", "myscope"
+ @compiler.class_scope("myname").should == "myscope"
+ end
+
+ it "should be able to retrieve class scopes by object" do
+ klass = mock 'ast_class'
+ klass.expects(:classname).returns("myname")
+ @compiler.class_set "myname", "myscope"
+ @compiler.class_scope(klass).should == "myscope"
+ end
+
+ it "should be able to return a class list containing all set classes" do
+ @compiler.class_set "", "empty"
+ @compiler.class_set "one", "yep"
+ @compiler.class_set "two", "nope"
+
+ @compiler.classlist.sort.should == %w{one two}.sort
+ end
+end
+
+describe Puppet::Parser::Compiler, " when initializing" do
+ include CompilerTesting
+
+ it "should set its node attribute" do
+ @compiler.node.should equal(@node)
+ end
+
+ it "should set its parser attribute" do
+ @compiler.parser.should equal(@parser)
+ end
+
+ it "should detect when ast nodes are absent" do
+ @compiler.ast_nodes?.should be_false
+ end
+
+ it "should detect when ast nodes are present" do
+ @parser.nodes["testing"] = "yay"
+ @compiler.ast_nodes?.should be_true
+ end
+end
+
+describe Puppet::Parser::Compiler, "when managing scopes" do
+ include CompilerTesting
+
+ it "should create a top scope" do
+ @compiler.topscope.should be_instance_of(Puppet::Parser::Scope)
+ end
+
+ it "should be able to create new scopes" do
+ @compiler.newscope(@compiler.topscope).should be_instance_of(Puppet::Parser::Scope)
+ end
+
+ it "should correctly set the level of newly created scopes" do
+ @compiler.newscope(@compiler.topscope, :level => 5).level.should == 5
+ end
+
+ it "should set the parent scope of the new scope to be the passed-in parent" do
+ scope = mock 'scope'
+ newscope = @compiler.newscope(scope)
+
+ @compiler.parent(newscope).should equal(scope)
+ end
+end
+
+describe Puppet::Parser::Compiler, " when compiling" do
+ include CompilerTesting
+
+ def compile_methods
+ [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated,
+ :finish, :store, :extract]
+ end
+
+ # Stub all of the main compile methods except the ones we're specifically interested in.
+ def compile_stub(*except)
+ (compile_methods - except).each { |m| @compiler.stubs(m) }
+ end
+
+ it "should set node parameters as variables in the top scope" do
+ params = {"a" => "b", "c" => "d"}
+ @node.stubs(:parameters).returns(params)
+ compile_stub(:set_node_parameters)
+ @compiler.compile
+ @compiler.topscope.lookupvar("a").should == "b"
+ @compiler.topscope.lookupvar("c").should == "d"
+ end
+
+ it "should evaluate any existing classes named in the node" do
+ classes = %w{one two three four}
+ main = stub 'main'
+ one = stub 'one', :classname => "one"
+ three = stub 'three', :classname => "three"
+ @node.stubs(:name).returns("whatever")
+ @node.stubs(:classes).returns(classes)
+
+ @compiler.expects(:evaluate_classes).with(classes, @compiler.topscope)
+ @compiler.class.publicize_methods(:evaluate_node_classes) { @compiler.evaluate_node_classes }
+ end
+
+ it "should enable ast_nodes if the parser has any nodes" do
+ @parser.expects(:nodes).returns(:one => :yay)
+ @compiler.ast_nodes?.should be_true
+ end
+
+ it "should disable ast_nodes if the parser has no nodes" do
+ @parser.expects(:nodes).returns({})
+ @compiler.ast_nodes?.should be_false
+ end
+
+ it "should evaluate the main class if it exists" do
+ compile_stub(:evaluate_main)
+ main_class = mock 'main_class'
+ main_class.expects(:evaluate_code).with { |r| r.is_a?(Puppet::Parser::Resource) }
+ @compiler.topscope.expects(:source=).with(main_class)
+ @parser.stubs(:findclass).with("", "").returns(main_class)
+
+ @compiler.compile
+ end
+
+ it "should evaluate any node classes" do
+ @node.stubs(:classes).returns(%w{one two three four})
+ @compiler.expects(:evaluate_classes).with(%w{one two three four}, @compiler.topscope)
+ @compiler.send(:evaluate_node_classes)
+ end
+
+ it "should evaluate all added collections" do
+ colls = []
+ # And when the collections fail to evaluate.
+ colls << mock("coll1-false")
+ colls << mock("coll2-false")
+ colls.each { |c| c.expects(:evaluate).returns(false) }
+
+ @compiler.add_collection(colls[0])
+ @compiler.add_collection(colls[1])
+
+ compile_stub(:evaluate_generators)
+ @compiler.compile
+ end
+
+ it "should ignore builtin resources" do
+ resource = stub 'builtin', :ref => "File[testing]", :builtin? => true
+
+ @compiler.add_resource(@scope, resource)
+ resource.expects(:evaluate).never
+
+ @compiler.compile
+ end
+
+ it "should evaluate unevaluated resources" do
+ resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => false
+ @compiler.add_resource(@scope, resource)
+
+ # We have to now mark the resource as evaluated
+ resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true }
+
+ @compiler.compile
+ end
+
+ it "should not evaluate already-evaluated resources" do
+ resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true, :virtual? => false
+ @compiler.add_resource(@scope, resource)
+ resource.expects(:evaluate).never
+
+ @compiler.compile
+ end
+
+ it "should evaluate unevaluated resources created by evaluating other resources" do
+ resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => false
+ @compiler.add_resource(@scope, resource)
+
+ resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false, :virtual? => false
+
+ # We have to now mark the resource as evaluated
+ resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compiler.add_resource(@scope, resource2) }
+ resource2.expects(:evaluate).with { |*whatever| resource2.stubs(:evaluated?).returns(true) }
+
+
+ @compiler.compile
+ end
+
+ it "should call finish() on all resources" do
+ # Add a resource that does respond to :finish
+ resource = Puppet::Parser::Resource.new :scope => @scope, :type => "file", :title => "finish"
+ resource.expects(:finish)
+
+ @compiler.add_resource(@scope, resource)
+
+ # And one that does not
+ dnf = stub "dnf", :ref => "File[dnf]"
+
+ @compiler.add_resource(@scope, dnf)
+
+ @compiler.send(:finish)
+ end
+
+ it "should add resources that do not conflict with existing resources" do
+ resource = stub "noconflict", :ref => "File[yay]"
+ @compiler.add_resource(@scope, resource)
+
+ @compiler.catalog.should be_vertex(resource)
+ end
+
+ it "should fail to add resources that conflict with existing resources" do
+ type = stub 'faketype', :isomorphic? => true, :name => "mytype"
+ Puppet::Type.stubs(:type).with("mytype").returns(type)
+
+ resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0
+ resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0
+
+ @compiler.add_resource(@scope, resource1)
+ lambda { @compiler.add_resource(@scope, resource2) }.should raise_error(ArgumentError)
+ end
+
+ it "should have a method for looking up resources" do
+ resource = stub 'resource', :ref => "Yay[foo]"
+ @compiler.add_resource(@scope, resource)
+ @compiler.findresource("Yay[foo]").should equal(resource)
+ end
+
+ it "should be able to look resources up by type and title" do
+ resource = stub 'resource', :ref => "Yay[foo]"
+ @compiler.add_resource(@scope, resource)
+ @compiler.findresource("Yay", "foo").should equal(resource)
+ end
+
+ it "should not evaluate virtual defined resources" do
+ resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => true
+ @compiler.add_resource(@scope, resource)
+
+ resource.expects(:evaluate).never
+
+ @compiler.compile
+ end
+end
+
+describe Puppet::Parser::Compiler, " when evaluating collections" do
+ include CompilerTesting
+
+ it "should evaluate each collection" do
+ 2.times { |i|
+ coll = mock 'coll%s' % i
+ @compiler.add_collection(coll)
+
+ # This is the hard part -- we have to emulate the fact that
+ # collections delete themselves if they are done evaluating.
+ coll.expects(:evaluate).with do
+ @compiler.delete_collection(coll)
+ end
+ }
+
+ @compiler.class.publicize_methods(:evaluate_collections) { @compiler.evaluate_collections }
+ end
+
+ it "should not fail when there are unevaluated resource collections that do not refer to specific resources" do
+ coll = stub 'coll', :evaluate => false
+ coll.expects(:resources).returns(nil)
+
+ @compiler.add_collection(coll)
+
+ lambda { @compiler.compile }.should_not raise_error
+ end
+
+ it "should fail when there are unevaluated resource collections that refer to a specific resource" do
+ coll = stub 'coll', :evaluate => false
+ coll.expects(:resources).returns(:something)
+
+ @compiler.add_collection(coll)
+
+ lambda { @compiler.compile }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should fail when there are unevaluated resource collections that refer to multiple specific resources" do
+ coll = stub 'coll', :evaluate => false
+ coll.expects(:resources).returns([:one, :two])
+
+ @compiler.add_collection(coll)
+
+ lambda { @compiler.compile }.should raise_error(Puppet::ParseError)
+ end
+end
+
+describe Puppet::Parser::Compiler, "when told to evaluate missing classes" do
+ include CompilerTesting
+
+ it "should fail if there's no source listed for the scope" do
+ scope = stub 'scope', :source => nil
+ proc { @compiler.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError)
+ end
+
+ it "should tag the catalog with the name of each not-found class" do
+ @compiler.catalog.expects(:tag).with("notfound")
+ @scope.expects(:findclass).with("notfound").returns(nil)
+ @compiler.evaluate_classes(%w{notfound}, @scope)
+ end
+end
+
+describe Puppet::Parser::Compiler, " when evaluating found classes" do
+ include CompilerTesting
+
+ before do
+ @class = stub 'class', :classname => "my::class"
+ @scope.stubs(:findclass).with("myclass").returns(@class)
+
+ @resource = stub 'resource', :ref => "Class[myclass]"
+ end
+
+ it "should evaluate each class" do
+ @compiler.catalog.stubs(:tag)
+
+ @class.expects(:evaluate).with(@scope)
+
+ @compiler.evaluate_classes(%w{myclass}, @scope)
+ end
+
+ it "should not evaluate the resources created for found classes unless asked" do
+ @compiler.catalog.stubs(:tag)
+
+ @resource.expects(:evaluate).never
+
+ @class.expects(:evaluate).returns(@resource)
+
+ @compiler.evaluate_classes(%w{myclass}, @scope)
+ end
+
+ it "should immediately evaluate the resources created for found classes when asked" do
+ @compiler.catalog.stubs(:tag)
+
+ @resource.expects(:evaluate)
+ @class.expects(:evaluate).returns(@resource)
+
+ @compiler.evaluate_classes(%w{myclass}, @scope, false)
+ end
+
+ it "should skip classes that have already been evaluated" do
+ @compiler.catalog.stubs(:tag)
+
+ @compiler.expects(:class_scope).with(@class).returns("something")
+
+ @compiler.expects(:add_resource).never
+
+ @resource.expects(:evaluate).never
+
+ Puppet::Parser::Resource.expects(:new).never
+ @compiler.evaluate_classes(%w{myclass}, @scope, false)
+ end
+
+ it "should return the list of found classes" do
+ @compiler.catalog.stubs(:tag)
+
+ @compiler.stubs(:add_resource)
+ @scope.stubs(:findclass).with("notfound").returns(nil)
+
+ Puppet::Parser::Resource.stubs(:new).returns(@resource)
+ @class.stubs :evaluate
+ @compiler.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass}
+ end
+end
+
+describe Puppet::Parser::Compiler, " when evaluating AST nodes with no AST nodes present" do
+ include CompilerTesting
+
+ it "should do nothing" do
+ @compiler.expects(:ast_nodes?).returns(false)
+ @compiler.parser.expects(:nodes).never
+ Puppet::Parser::Resource.expects(:new).never
+
+ @compiler.send(:evaluate_ast_node)
+ end
+end
+
+describe Puppet::Parser::Compiler, " when evaluating AST nodes with AST nodes present" do
+ include CompilerTesting
+
+ before do
+ @nodes = mock 'node_hash'
+ @compiler.stubs(:ast_nodes?).returns(true)
+ @compiler.parser.stubs(:nodes).returns(@nodes)
+
+ # Set some names for our test
+ @node.stubs(:names).returns(%w{a b c})
+ @nodes.stubs(:[]).with("a").returns(nil)
+ @nodes.stubs(:[]).with("b").returns(nil)
+ @nodes.stubs(:[]).with("c").returns(nil)
+
+ # It should check this last, of course.
+ @nodes.stubs(:[]).with("default").returns(nil)
+ end
+
+ it "should fail if the named node cannot be found" do
+ proc { @compiler.send(:evaluate_ast_node) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should evaluate the first node class matching the node name" do
+ node_class = stub 'node', :classname => "c", :evaluate_code => nil
+ @nodes.stubs(:[]).with("c").returns(node_class)
+
+ node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil
+ node_class.expects(:evaluate).returns(node_resource)
+
+ @compiler.compile
+ end
+
+ it "should match the default node if no matching node can be found" do
+ node_class = stub 'node', :classname => "default", :evaluate_code => nil
+ @nodes.stubs(:[]).with("default").returns(node_class)
+
+ node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil
+ node_class.expects(:evaluate).returns(node_resource)
+
+ @compiler.compile
+ end
+
+ it "should evaluate the node resource immediately rather than using lazy evaluation" do
+ node_class = stub 'node', :classname => "c"
+ @nodes.stubs(:[]).with("c").returns(node_class)
+
+ node_resource = stub 'node resource', :ref => "Node[c]"
+ node_class.expects(:evaluate).returns(node_resource)
+
+ node_resource.expects(:evaluate)
+
+ @compiler.send(:evaluate_ast_node)
+ end
+
+ it "should set the node's scope as the top scope" do
+ node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil
+ node_class = stub 'node', :classname => "c", :evaluate => node_resource
+
+ @nodes.stubs(:[]).with("c").returns(node_class)
+
+ # The #evaluate method normally does this.
+ scope = stub 'scope', :source => "mysource"
+ @compiler.class_set(node_class.classname, scope)
+ node_resource.stubs(:evaluate)
+
+ @compiler.compile
+
+ @compiler.topscope.should equal(scope)
+ end
+end
+
+describe Puppet::Parser::Compiler, "when storing compiled resources" do
+ include CompilerTesting
+
+ it "should store the resources" do
+ Puppet.features.expects(:rails?).returns(true)
+ Puppet::Rails.expects(:connect)
+
+ @compiler.catalog.expects(:vertices).returns(:resources)
+
+ @compiler.expects(:store_to_active_record).with(@node, :resources)
+ @compiler.send(:store)
+ end
+
+ it "should store to active_record" do
+ @node.expects(:name).returns("myname")
+ Puppet::Rails::Host.stubs(:transaction).yields
+ Puppet::Rails::Host.expects(:store).with(@node, :resources)
+ @compiler.send(:store_to_active_record, @node, :resources)
+ end
+end
+
+describe Puppet::Parser::Compiler, "when managing resource overrides" do
+ include CompilerTesting
+
+ before do
+ @override = stub 'override', :ref => "My[ref]"
+ @resource = stub 'resource', :ref => "My[ref]", :builtin? => true
+ end
+
+ it "should be able to store overrides" do
+ lambda { @compiler.add_override(@override) }.should_not raise_error
+ end
+
+ it "should apply overrides to the appropriate resources" do
+ @compiler.add_resource(@scope, @resource)
+ @resource.expects(:merge).with(@override)
+
+ @compiler.add_override(@override)
+
+ @compiler.compile
+ end
+
+ it "should accept overrides before the related resource has been created" do
+ @resource.expects(:merge).with(@override)
+
+ # First store the override
+ @compiler.add_override(@override)
+
+ # Then the resource
+ @compiler.add_resource(@scope, @resource)
+
+ # And compile, so they get resolved
+ @compiler.compile
+ end
+
+ it "should fail if the compile is finished and resource overrides have not been applied" do
+ @compiler.add_override(@override)
+
+ lambda { @compiler.compile }.should raise_error(Puppet::ParseError)
+ end
+end
+
+# #620 - Nodes and classes should conflict, else classes don't get evaluated
+describe Puppet::Parser::Compiler, "when evaluating nodes and classes with the same name (#620)" do
+ include CompilerTesting
+
+ before do
+ @node = stub :nodescope? => true
+ @class = stub :nodescope? => false
+ end
+
+ it "should fail if a node already exists with the same name as the class being evaluated" do
+ @compiler.class_set("one", @node)
+ lambda { @compiler.class_set("one", @class) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should fail if a class already exists with the same name as the node being evaluated" do
+ @compiler.class_set("one", @class)
+ lambda { @compiler.class_set("one", @node) }.should raise_error(Puppet::ParseError)
+ end
+end
diff --git a/spec/unit/parser/interpreter.rb b/spec/unit/parser/interpreter.rb
index ed30ced93..7885f0542 100755
--- a/spec/unit/parser/interpreter.rb
+++ b/spec/unit/parser/interpreter.rb
@@ -115,14 +115,14 @@ describe Puppet::Parser::Interpreter, " when compiling catalog" do
before do
@interp = Puppet::Parser::Interpreter.new
@node = stub 'node', :environment => :myenv
- @compile = mock 'compile'
+ @compiler = mock 'compile'
@parser = mock 'parser'
end
it "should create a compile with the node and parser" do
- @compile.expects(:compile).returns(:config)
+ @compiler.expects(:compile).returns(:config)
@interp.expects(:parser).with(:myenv).returns(@parser)
- Puppet::Parser::Compile.expects(:new).with(@node, @parser).returns(@compile)
+ Puppet::Parser::Compiler.expects(:new).with(@node, @parser).returns(@compiler)
@interp.compile(@node)
end
diff --git a/spec/unit/parser/lexer.rb b/spec/unit/parser/lexer.rb
new file mode 100755
index 000000000..cddbef1ed
--- /dev/null
+++ b/spec/unit/parser/lexer.rb
@@ -0,0 +1,465 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/parser/lexer'
+
+describe Puppet::Parser::Lexer::Token do
+ before do
+ @token = Puppet::Parser::Lexer::Token.new(%r{something}, :NAME)
+ end
+
+ [:regex, :name, :string, :skip, :incr_line, :skip_text].each do |param|
+ it "should have a #{param.to_s} reader" do
+ @token.should respond_to?(param)
+ end
+
+ it "should have a #{param.to_s} writer" do
+ @token.should respond_to?(param.to_s + "=")
+ end
+ end
+end
+
+describe Puppet::Parser::Lexer::Token, "when initializing" do
+ it "should create a regex if the first argument is a string" do
+ Puppet::Parser::Lexer::Token.new("something", :NAME).regex.should == %r{something}
+ end
+
+ it "should set the string if the first argument is one" do
+ Puppet::Parser::Lexer::Token.new("something", :NAME).string.should == "something"
+ end
+
+ it "should set the regex if the first argument is one" do
+ Puppet::Parser::Lexer::Token.new(%r{something}, :NAME).regex.should == %r{something}
+ end
+end
+
+describe Puppet::Parser::Lexer::TokenList do
+ before do
+ @list = Puppet::Parser::Lexer::TokenList.new
+ end
+
+ it "should have a method for retrieving tokens by the name" do
+ token = @list.add_token :name, "whatever"
+ @list[:name].should equal(token)
+ end
+
+ it "should have a method for retrieving string tokens by the string" do
+ token = @list.add_token :name, "whatever"
+ @list.lookup("whatever").should equal(token)
+ end
+
+ it "should add tokens to the list when directed" do
+ token = @list.add_token :name, "whatever"
+ @list[:name].should equal(token)
+ end
+
+ it "should have a method for adding multiple tokens at once" do
+ @list.add_tokens "whatever" => :name, "foo" => :bar
+ @list[:name].should_not be_nil
+ @list[:bar].should_not be_nil
+ end
+
+ it "should fail to add tokens sharing a name with an existing token" do
+ @list.add_token :name, "whatever"
+ lambda { @list.add_token :name, "whatever" }.should raise_error(ArgumentError)
+ end
+
+ it "should set provided options on tokens being added" do
+ token = @list.add_token :name, "whatever", :skip_text => true
+ token.skip_text.should == true
+ end
+
+ it "should define any provided blocks as a :convert method" do
+ token = @list.add_token(:name, "whatever") do "foo" end
+ token.convert.should == "foo"
+ end
+
+ it "should store all string tokens in the :string_tokens list" do
+ one = @list.add_token(:name, "1")
+ @list.string_tokens.should be_include(one)
+ end
+
+ it "should store all regex tokens in the :regex_tokens list" do
+ one = @list.add_token(:name, %r{one})
+ @list.regex_tokens.should be_include(one)
+ end
+
+ it "should not store string tokens in the :regex_tokens list" do
+ one = @list.add_token(:name, "1")
+ @list.regex_tokens.should_not be_include(one)
+ end
+
+ it "should not store regex tokens in the :string_tokens list" do
+ one = @list.add_token(:name, %r{one})
+ @list.string_tokens.should_not be_include(one)
+ end
+
+ it "should sort the string tokens inversely by length when asked" do
+ one = @list.add_token(:name, "1")
+ two = @list.add_token(:other, "12")
+ @list.sort_tokens
+ @list.string_tokens.should == [two, one]
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS do
+ before do
+ @lexer = Puppet::Parser::Lexer.new()
+ end
+
+ {
+ :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 => '+>'
+ }.each do |name, string|
+ it "should have a token named #{name.to_s}" do
+ Puppet::Parser::Lexer::TOKENS[name].should_not be_nil
+ end
+
+ it "should match '#{string}' for the token #{name.to_s}" do
+ Puppet::Parser::Lexer::TOKENS[name].string.should == string
+ end
+ end
+
+ {
+ "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
+ }.each do |string, name|
+ it "should have a keyword named #{name.to_s}" do
+ Puppet::Parser::Lexer::KEYWORDS[name].should_not be_nil
+ end
+
+ it "should have the keyword for #{name.to_s} set to #{string}" do
+ Puppet::Parser::Lexer::KEYWORDS[name].string.should == string
+ end
+ end
+
+ # These tokens' strings don't matter, just that the tokens exist.
+ [:DQTEXT, :SQTEXT, :BOOLEAN, :NAME, :NUMBER, :COMMENT, :RETURN, :SQUOTE, :DQUOTE, :VARIABLE].each do |name|
+ it "should have a token named #{name.to_s}" do
+ Puppet::Parser::Lexer::TOKENS[name].should_not be_nil
+ end
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:NAME] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:NAME] }
+
+ it "should match against lower-case alpha-numeric terms" do
+ @token.regex.should =~ "one-two"
+ end
+
+ it "should return itself and the value if the matched term is not a keyword" do
+ Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(nil)
+ @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"]
+ end
+
+ it "should return the keyword token and the value if the matched term is a keyword" do
+ keyword = stub 'keyword', :name => :testing
+ Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword)
+ @token.convert(stub("lexer"), "myval").should == [keyword, "myval"]
+ end
+
+ it "should return the BOOLEAN token and 'true' if the matched term is the string 'true'" do
+ keyword = stub 'keyword', :name => :TRUE
+ Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword)
+ @token.convert(stub('lexer'), "true").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], true]
+ end
+
+ it "should return the BOOLEAN token and 'false' if the matched term is the string 'false'" do
+ keyword = stub 'keyword', :name => :FALSE
+ Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword)
+ @token.convert(stub('lexer'), "false").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], false]
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:NUMBER] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:NUMBER] }
+
+ it "should match against numeric terms" do
+ @token.regex.should =~ "2982383139"
+ end
+
+ it "should return the NAME token and the value" do
+ @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"]
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:COMMENT] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:COMMENT] }
+
+ it "should match against lines starting with '#'" do
+ @token.regex.should =~ "# this is a comment"
+ end
+
+ it "should be marked to get skipped" do
+ @token.skip?.should be_true
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:RETURN] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:RETURN] }
+
+ it "should match against carriage returns" do
+ @token.regex.should =~ "\n"
+ end
+
+ it "should be marked to initiate text skipping" do
+ @token.skip_text.should be_true
+ end
+
+ it "should be marked to increment the line" do
+ @token.incr_line.should be_true
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:SQUOTE] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:SQUOTE] }
+
+ it "should match against single quotes" do
+ @token.regex.should =~ "'"
+ end
+
+ it "should slurp the rest of the quoted string" do
+ lexer = stub("lexer")
+ lexer.expects(:slurpstring).with("myval").returns("otherval")
+ @token.convert(lexer, "myval")
+ end
+
+ it "should return the SQTEXT token with the slurped string" do
+ lexer = stub("lexer")
+ lexer.stubs(:slurpstring).with("myval").returns("otherval")
+ @token.convert(lexer, "myval").should == [Puppet::Parser::Lexer::TOKENS[:SQTEXT], "otherval"]
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:DQUOTE] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:DQUOTE] }
+
+ it "should match against single quotes" do
+ @token.regex.should =~ '"'
+ end
+
+ it "should slurp the rest of the quoted string" do
+ lexer = stub("lexer")
+ lexer.expects(:slurpstring).with("myval").returns("otherval")
+ @token.convert(lexer, "myval")
+ end
+
+ it "should return the DQTEXT token with the slurped string" do
+ lexer = stub("lexer")
+ lexer.stubs(:slurpstring).with("myval").returns("otherval")
+ @token.convert(lexer, "myval").should == [Puppet::Parser::Lexer::TOKENS[:DQTEXT], "otherval"]
+ end
+end
+
+describe Puppet::Parser::Lexer::TOKENS[:VARIABLE] do
+ before { @token = Puppet::Parser::Lexer::TOKENS[:VARIABLE] }
+
+ it "should match against alpha words prefixed with '$'" do
+ @token.regex.should =~ '$this_var'
+ end
+
+ it "should return the VARIABLE token and the variable name stripped of the '$'" do
+ @token.convert(stub("lexer"), "$myval").should == [Puppet::Parser::Lexer::TOKENS[:VARIABLE], "myval"]
+ end
+end
+
+# FIXME: We need to rewrite all of these tests, but I just don't want to take the time right now.
+describe "Puppet::Parser::Lexer in the old tests" do
+ before { @lexer = Puppet::Parser::Lexer.new }
+
+ it "should do simple lexing" do
+ strings = {
+%q{\\} => [[:BACKSLASH,"\\"],[false,false]],
+%q{simplest scanner test} => [[:NAME,"simplest"],[:NAME,"scanner"],[:NAME,"test"],[false,false]],
+%q{returned scanner test
+} => [[:NAME,"returned"],[:NAME,"scanner"],[:NAME,"test"],[false,false]]
+ }
+ strings.each { |str,ary|
+ @lexer.string = str
+ @lexer.fullscan().should == ary
+ }
+ end
+
+ it "should correctly lex quoted strings" do
+ strings = {
+%q{a simple "scanner" test
+} => [[:NAME,"a"],[:NAME,"simple"],[:DQTEXT,"scanner"],[:NAME,"test"],[false,false]],
+%q{a simple 'single quote scanner' test
+} => [[:NAME,"a"],[:NAME,"simple"],[:SQTEXT,"single quote scanner"],[:NAME,"test"],[false,false]],
+%q{a harder 'a $b \c"'
+} => [[:NAME,"a"],[:NAME,"harder"],[:SQTEXT,'a $b \c"'],[false,false]],
+%q{a harder "scanner test"
+} => [[:NAME,"a"],[:NAME,"harder"],[:DQTEXT,"scanner test"],[false,false]],
+%q{a hardest "scanner \"test\""
+} => [[:NAME,"a"],[:NAME,"hardest"],[:DQTEXT,'scanner "test"'],[false,false]],
+%q{a hardestest "scanner \"test\"
+"
+} => [[:NAME,"a"],[:NAME,"hardestest"],[:DQTEXT,'scanner "test"
+'],[false,false]],
+%q{function("call")} => [[:NAME,"function"],[:LPAREN,"("],[:DQTEXT,'call'],[:RPAREN,")"],[false,false]]
+}
+ strings.each { |str,array|
+ @lexer.string = str
+ @lexer.fullscan().should == array
+ }
+ end
+
+ it "should fail usefully" do
+ strings = %w{
+ ^
+ }
+ strings.each { |str|
+ @lexer.string = str
+ lambda { @lexer.fullscan() }.should raise_error(RuntimeError)
+ }
+ end
+
+ it "should fail if the string is not set" do
+ lambda { @lexer.fullscan() }.should raise_error(Puppet::LexError)
+ end
+
+ it "should correctly identify keywords" do
+ @lexer.string = "case"
+ @lexer.fullscan.should == [[:CASE, "case"], [false, false]]
+ end
+
+ it "should correctly match strings" do
+ names = %w{this is a bunch of names}
+ types = %w{Many Different Words A Word}
+ words = %w{differently Cased words A a}
+
+ names.each { |t|
+ @lexer.string = t
+ @lexer.fullscan.should == [[:NAME,t],[false,false]]
+ }
+ types.each { |t|
+ @lexer.string = t
+ @lexer.fullscan.should == [[:CLASSREF,t],[false,false]]
+ }
+ end
+
+ it "should correctly parse empty strings" do
+ bit = '$var = ""'
+
+ @lexer.string = bit
+
+ lambda { @lexer.fullscan }.should_not raise_error
+ end
+
+ it "should correctly parse virtual resources" do
+ string = "@type {"
+
+ @lexer.string = string
+
+ @lexer.fullscan.should == [[:AT, "@"], [:NAME, "type"], [:LBRACE, "{"], [false,false]]
+ end
+
+ it "should correctly deal with namespaces" do
+ @lexer.string = %{class myclass}
+
+ @lexer.fullscan
+
+ @lexer.namespace.should == "myclass"
+
+ @lexer.namepop
+
+ @lexer.namespace.should == ""
+
+ @lexer.string = "class base { class sub { class more"
+
+ @lexer.fullscan
+
+ @lexer.namespace.should == "base::sub::more"
+
+ @lexer.namepop
+
+ @lexer.namespace.should == "base::sub"
+ end
+
+ it "should correctly handle fully qualified names" do
+ @lexer.string = "class base { class sub::more {"
+
+ @lexer.fullscan
+
+ @lexer.namespace.should == "base::sub::more"
+
+ @lexer.namepop
+
+ @lexer.namespace.should == "base"
+ end
+
+ it "should correctly lex variables" do
+ ["$variable", "$::variable", "$qualified::variable", "$further::qualified::variable"].each do |string|
+ @lexer.string = string
+
+ @lexer.scan do |t, s|
+ t.should == :VARIABLE
+ string.sub(/^\$/, '').should == s
+ break
+ end
+ end
+ end
+
+ # #774
+ it "should correctly parse the CLASSREF token" do
+ string = ["Foo", "::Foo","Foo::Bar","::Foo::Bar"]
+
+ string.each do |foo|
+ @lexer.string = foo
+ @lexer.fullscan[0].should == [:CLASSREF, foo]
+ end
+ end
+end
+
+require 'puppettest/support/utils'
+describe "Puppet::Parser::Lexer in the old tests when lexing example files" do
+ extend PuppetTest
+ extend PuppetTest::Support::Utils
+ textfiles() do |file|
+ it "should correctly lex #{file}" do
+ lexer = Puppet::Parser::Lexer.new()
+ lexer.file = file
+ lambda { lexer.fullscan() }.should_not raise_error
+ end
+ end
+end
diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb
index 3d048f7e6..a5a49e2a6 100755
--- a/spec/unit/parser/resource.rb
+++ b/spec/unit/parser/resource.rb
@@ -4,6 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper'
# LAK: FIXME This is just new tests for resources; I have
# not moved all tests over yet.
+
describe Puppet::Parser::Resource, " when evaluating" do
before do
@type = Puppet::Parser::Resource
@@ -14,26 +15,26 @@ describe Puppet::Parser::Resource, " when evaluating" do
@class = @parser.newclass "myclass"
@nodedef = @parser.newnode("mynode")[0]
@node = Puppet::Node.new("yaynode")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- @scope = @compile.topscope
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
+ @scope = @compiler.topscope
end
it "should evaluate the associated AST definition" do
res = @type.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source)
- @definition.expects(:evaluate).with(:scope => @scope, :resource => res)
+ @definition.expects(:evaluate_code).with(res)
res.evaluate
end
it "should evaluate the associated AST class" do
res = @type.new(:type => "class", :title => "myclass", :scope => @scope, :source => @source)
- @class.expects(:evaluate).with(:scope => @scope, :resource => res)
+ @class.expects(:evaluate_code).with(res)
res.evaluate
end
it "should evaluate the associated AST node" do
res = @type.new(:type => "node", :title => "mynode", :scope => @scope, :source => @source)
- @nodedef.expects(:evaluate).with(:scope => @scope, :resource => res)
+ @nodedef.expects(:evaluate_code).with(res)
res.evaluate
end
end
@@ -46,8 +47,8 @@ describe Puppet::Parser::Resource, " when finishing" do
@class = @parser.newclass "myclass"
@nodedef = @parser.newnode("mynode")[0]
@node = Puppet::Node.new("yaynode")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
- @scope = @compile.topscope
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
+ @scope = @compiler.topscope
@resource = Puppet::Parser::Resource.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source)
end
@@ -86,4 +87,63 @@ describe Puppet::Parser::Resource, " when finishing" do
@resource["require"].sort.should == %w{container1 container2 resource1 resource2}
end
+
+ it "should add any tags from the scope resource" do
+ scope_resource = stub 'scope_resource', :tags => %w{one two}
+ @scope.stubs(:resource).returns(scope_resource)
+
+ @resource.class.publicize_methods(:add_scope_tags) { @resource.add_scope_tags }
+
+ @resource.tags.should be_include("one")
+ @resource.tags.should be_include("two")
+ end
+end
+
+describe Puppet::Parser::Resource, "when being tagged" do
+ before do
+ @scope_resource = stub 'scope_resource', :tags => %w{srone srtwo}
+ @scope = stub 'scope', :resource => @scope_resource
+ @resource = Puppet::Parser::Resource.new(:type => "file", :title => "yay", :scope => @scope, :source => mock('source'))
+ end
+
+ it "should get tagged with the resource type" do
+ @resource.tags.should be_include("file")
+ end
+
+ it "should get tagged with the title" do
+ @resource.tags.should be_include("yay")
+ end
+
+ it "should get tagged with each name in the title if the title is a qualified class name" do
+ resource = Puppet::Parser::Resource.new(:type => "file", :title => "one::two", :scope => @scope, :source => mock('source'))
+ resource.tags.should be_include("one")
+ resource.tags.should be_include("two")
+ end
+
+ it "should get tagged with each name in the type if the type is a qualified class name" do
+ resource = Puppet::Parser::Resource.new(:type => "one::two", :title => "whatever", :scope => @scope, :source => mock('source'))
+ resource.tags.should be_include("one")
+ resource.tags.should be_include("two")
+ end
+
+ it "should not get tagged with non-alphanumeric titles" do
+ resource = Puppet::Parser::Resource.new(:type => "file", :title => "this is a test", :scope => @scope, :source => mock('source'))
+ resource.tags.should_not be_include("this is a test")
+ end
+
+ it "should fail on tags containing '*' characters" do
+ lambda { @resource.tag("bad*tag") }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should fail on tags starting with '-' characters" do
+ lambda { @resource.tag("-badtag") }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should fail on tags containing ' ' characters" do
+ lambda { @resource.tag("bad tag") }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should allow alpha tags" do
+ lambda { @resource.tag("good_tag") }.should_not raise_error(Puppet::ParseError)
+ end
end
diff --git a/spec/unit/parser/resource/reference.rb b/spec/unit/parser/resource/reference.rb
index e7385f796..147f772d1 100755
--- a/spec/unit/parser/resource/reference.rb
+++ b/spec/unit/parser/resource/reference.rb
@@ -52,23 +52,23 @@ describe Puppet::Parser::Resource::Reference, " when modeling defined types" do
@nodedef = @parser.newnode("mynode")[0]
@node = Puppet::Node.new("yaynode")
- @compile = Puppet::Parser::Compile.new(@node, @parser)
+ @compiler = Puppet::Parser::Compiler.new(@node, @parser)
end
it "should be able to find defined types" do
- ref = @type.new(:type => "mydefine", :title => "/tmp/yay", :scope => @compile.topscope)
+ ref = @type.new(:type => "mydefine", :title => "/tmp/yay", :scope => @compiler.topscope)
ref.builtin?.should be_false
ref.definedtype.should equal(@definition)
end
it "should be able to find classes" do
- ref = @type.new(:type => "class", :title => "myclass", :scope => @compile.topscope)
+ ref = @type.new(:type => "class", :title => "myclass", :scope => @compiler.topscope)
ref.builtin?.should be_false
ref.definedtype.should equal(@class)
end
it "should be able to find nodes" do
- ref = @type.new(:type => "node", :title => "mynode", :scope => @compile.topscope)
+ ref = @type.new(:type => "node", :title => "mynode", :scope => @compiler.topscope)
ref.builtin?.should be_false
ref.definedtype.object_id.should == @nodedef.object_id
end
diff --git a/spec/unit/ral/type.rb b/spec/unit/ral/type.rb
index 25f8cbaf1..5980167d6 100755
--- a/spec/unit/ral/type.rb
+++ b/spec/unit/ral/type.rb
@@ -11,8 +11,8 @@ describe Puppet::Type, " when in a configuration" do
@catalog.add_resource @container
@catalog.add_resource @one
@catalog.add_resource @two
- @catalog.add_edge! @container, @one
- @catalog.add_edge! @container, @two
+ @catalog.add_edge @container, @one
+ @catalog.add_edge @container, @two
end
it "should have no parent if there is no in edge" do
diff --git a/spec/unit/resource_reference.rb b/spec/unit/resource_reference.rb
index ef172d80a..cbbd6ef51 100755
--- a/spec/unit/resource_reference.rb
+++ b/spec/unit/resource_reference.rb
@@ -40,6 +40,12 @@ describe Puppet::ResourceReference do
ref.type.should == "Foo::Bar"
ref.title.should == "yay"
end
+
+ it "should interpret the title as a reference and assign appropriately if the type is nil and the title contains nested square brackets" do
+ ref = Puppet::ResourceReference.new(nil, "foo::bar[baz[yay]]")
+ ref.type.should == "Foo::Bar"
+ ref.title.should =="baz[yay]"
+ end
end
describe Puppet::ResourceReference, "when resolving resources without a catalog" do
diff --git a/spec/unit/simple_graph.rb b/spec/unit/simple_graph.rb
index 061a07458..c8fe14cf3 100755
--- a/spec/unit/simple_graph.rb
+++ b/spec/unit/simple_graph.rb
@@ -9,8 +9,8 @@ require 'puppet/simple_graph'
describe Puppet::SimpleGraph do
it "should return the number of its vertices as its length" do
@graph = Puppet::SimpleGraph.new
- @graph.add_vertex!("one")
- @graph.add_vertex!("two")
+ @graph.add_vertex("one")
+ @graph.add_vertex("two")
@graph.size.should == 2
end
@@ -20,13 +20,13 @@ describe Puppet::SimpleGraph do
it "should provide a method for reversing the graph" do
@graph = Puppet::SimpleGraph.new
- @graph.add_edge!(:one, :two)
+ @graph.add_edge(:one, :two)
@graph.reversal.edge?(:two, :one).should be_true
end
it "should be able to produce a dot graph" do
@graph = Puppet::SimpleGraph.new
- @graph.add_edge!(:one, :two)
+ @graph.add_edge(:one, :two)
proc { @graph.to_dot_graph }.should_not raise_error
end
@@ -38,17 +38,17 @@ describe Puppet::SimpleGraph, " when managing vertices" do
end
it "should provide a method to add a vertex" do
- @graph.add_vertex!(:test)
+ @graph.add_vertex(:test)
@graph.vertex?(:test).should be_true
end
it "should ignore already-present vertices when asked to add a vertex" do
- @graph.add_vertex!(:test)
- proc { @graph.add_vertex!(:test) }.should_not raise_error
+ @graph.add_vertex(:test)
+ proc { @graph.add_vertex(:test) }.should_not raise_error
end
it "should return true when asked if a vertex is present" do
- @graph.add_vertex!(:test)
+ @graph.add_vertex(:test)
@graph.vertex?(:test).should be_true
end
@@ -57,15 +57,15 @@ describe Puppet::SimpleGraph, " when managing vertices" do
end
it "should return all set vertices when asked" do
- @graph.add_vertex!(:one)
- @graph.add_vertex!(:two)
+ @graph.add_vertex(:one)
+ @graph.add_vertex(:two)
@graph.vertices.length.should == 2
@graph.vertices.should include(:one)
@graph.vertices.should include(:two)
end
it "should remove a given vertex when asked" do
- @graph.add_vertex!(:one)
+ @graph.add_vertex(:one)
@graph.remove_vertex!(:one)
@graph.vertex?(:one).should be_false
end
@@ -86,49 +86,49 @@ describe Puppet::SimpleGraph, " when managing edges" do
it "should provide a method to add an edge as an instance of the edge class" do
edge = Puppet::Relationship.new(:one, :two)
- @graph.add_edge!(edge)
+ @graph.add_edge(edge)
@graph.edge?(:one, :two).should be_true
end
it "should provide a method to add an edge by specifying the two vertices" do
- @graph.add_edge!(:one, :two)
+ @graph.add_edge(:one, :two)
@graph.edge?(:one, :two).should be_true
end
it "should provide a method to add an edge by specifying the two vertices and a label" do
- @graph.add_edge!(:one, :two, :stuff => :awesome)
+ @graph.add_edge(:one, :two, :stuff => :awesome)
@graph.edge?(:one, :two).should be_true
end
it "should provide a method for retrieving an edge label" do
edge = Puppet::Relationship.new(:one, :two, :stuff => :awesome)
- @graph.add_edge!(edge)
+ @graph.add_edge(edge)
@graph.edge_label(:one, :two).should == {:stuff => :awesome}
end
it "should provide a method for retrieving an edge" do
edge = Puppet::Relationship.new(:one, :two)
- @graph.add_edge!(edge)
+ @graph.add_edge(edge)
@graph.edge(:one, :two).should equal(edge)
end
it "should add the edge source as a vertex if it is not already" do
edge = Puppet::Relationship.new(:one, :two)
- @graph.add_edge!(edge)
+ @graph.add_edge(edge)
@graph.vertex?(:one).should be_true
end
it "should add the edge target as a vertex if it is not already" do
edge = Puppet::Relationship.new(:one, :two)
- @graph.add_edge!(edge)
+ @graph.add_edge(edge)
@graph.vertex?(:two).should be_true
end
it "should return all edges as edge instances when asked" do
one = Puppet::Relationship.new(:one, :two)
two = Puppet::Relationship.new(:two, :three)
- @graph.add_edge!(one)
- @graph.add_edge!(two)
+ @graph.add_edge(one)
+ @graph.add_edge(two)
edges = @graph.edges
edges.length.should == 2
edges.should include(one)
@@ -137,7 +137,7 @@ describe Puppet::SimpleGraph, " when managing edges" do
it "should remove an edge when asked" do
edge = Puppet::Relationship.new(:one, :two)
- @graph.add_edge!(edge)
+ @graph.add_edge(edge)
@graph.remove_edge!(edge)
@graph.edge?(edge.source, edge.target).should be_false
end
@@ -145,8 +145,8 @@ describe Puppet::SimpleGraph, " when managing edges" do
it "should remove all related edges when a vertex is removed" do
one = Puppet::Relationship.new(:one, :two)
two = Puppet::Relationship.new(:two, :three)
- @graph.add_edge!(one)
- @graph.add_edge!(two)
+ @graph.add_edge(one)
+ @graph.add_edge(two)
@graph.remove_vertex!(:two)
@graph.edge?(:one, :two).should be_false
@graph.edge?(:two, :three).should be_false
@@ -160,9 +160,9 @@ describe Puppet::SimpleGraph, " when finding adjacent vertices" do
@one_two = Puppet::Relationship.new(:one, :two)
@two_three = Puppet::Relationship.new(:two, :three)
@one_three = Puppet::Relationship.new(:one, :three)
- @graph.add_edge!(@one_two)
- @graph.add_edge!(@one_three)
- @graph.add_edge!(@two_three)
+ @graph.add_edge(@one_two)
+ @graph.add_edge(@one_three)
+ @graph.add_edge(@two_three)
end
it "should return adjacent vertices" do
@@ -193,8 +193,8 @@ describe Puppet::SimpleGraph, " when clearing" do
@graph = Puppet::SimpleGraph.new
one = Puppet::Relationship.new(:one, :two)
two = Puppet::Relationship.new(:two, :three)
- @graph.add_edge!(one)
- @graph.add_edge!(two)
+ @graph.add_edge(one)
+ @graph.add_edge(two)
@graph.clear
end
@@ -214,18 +214,18 @@ describe Puppet::SimpleGraph, " when reversing graphs" do
end
it "should provide a method for reversing the graph" do
- @graph.add_edge!(:one, :two)
+ @graph.add_edge(:one, :two)
@graph.reversal.edge?(:two, :one).should be_true
end
it "should add all vertices to the reversed graph" do
- @graph.add_edge!(:one, :two)
+ @graph.add_edge(:one, :two)
@graph.vertex?(:one).should be_true
@graph.vertex?(:two).should be_true
end
it "should retain labels on edges" do
- @graph.add_edge!(:one, :two, :stuff => :awesome)
+ @graph.add_edge(:one, :two, :stuff => :awesome)
edge = @graph.reversal.edge(:two, :one)
edge.label.should == {:stuff => :awesome}
end
@@ -238,7 +238,7 @@ describe Puppet::SimpleGraph, " when sorting the graph" do
def add_edges(hash)
hash.each do |a,b|
- @graph.add_edge!(a, b)
+ @graph.add_edge(a, b)
end
end
diff --git a/spec/unit/util/constant_inflector.rb b/spec/unit/util/constant_inflector.rb
new file mode 100755
index 000000000..5112e730f
--- /dev/null
+++ b/spec/unit/util/constant_inflector.rb
@@ -0,0 +1,70 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-02-12.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/util/constant_inflector'
+
+describe Puppet::Util::ConstantInflector, "when converting file names to constants" do
+ before do
+ @inflector = Object.new
+ @inflector.extend(Puppet::Util::ConstantInflector)
+ end
+
+ it "should capitalize terms" do
+ @inflector.file2constant("file").should == "File"
+ end
+
+ it "should switch all '/' characters to double colons" do
+ @inflector.file2constant("file/other").should == "File::Other"
+ end
+
+ it "should remove underscores and capitalize the proceeding letter" do
+ @inflector.file2constant("file_other").should == "FileOther"
+ end
+
+ it "should correctly replace as many underscores as exist in the file name" do
+ @inflector.file2constant("two_under_scores/with_some_more_underscores").should == "TwoUnderScores::WithSomeMoreUnderscores"
+ end
+
+ it "should collapse multiple underscores" do
+ @inflector.file2constant("many___scores").should == "ManyScores"
+ end
+
+ it "should correctly handle file names deeper than two directories" do
+ @inflector.file2constant("one_two/three_four/five_six").should == "OneTwo::ThreeFour::FiveSix"
+ end
+end
+
+describe Puppet::Util::ConstantInflector, "when converting constnats to file names" do
+ before do
+ @inflector = Object.new
+ @inflector.extend(Puppet::Util::ConstantInflector)
+ end
+
+ it "should convert them to a string if necessary" do
+ @inflector.constant2file(Puppet::Util::ConstantInflector).should be_instance_of(String)
+ end
+
+ it "should accept string inputs" do
+ @inflector.constant2file("Puppet::Util::ConstantInflector").should be_instance_of(String)
+ end
+
+ it "should downcase all terms" do
+ @inflector.constant2file("Puppet").should == "puppet"
+ end
+
+ it "should convert '::' to '/'" do
+ @inflector.constant2file("Puppet::Util::Constant").should == "puppet/util/constant"
+ end
+
+ it "should convert mid-word capitalization to an underscore" do
+ @inflector.constant2file("OneTwo::ThreeFour").should == "one_two/three_four"
+ end
+
+ it "should correctly handle constants with more than two parts" do
+ @inflector.constant2file("OneTwoThree::FourFiveSixSeven").should == "one_two_three/four_five_six_seven"
+ end
+end
diff --git a/spec/unit/util/settings.rb b/spec/unit/util/settings.rb
index a0cae936f..167c21c7e 100755
--- a/spec/unit/util/settings.rb
+++ b/spec/unit/util/settings.rb
@@ -592,6 +592,20 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
file.should be_nil
end
+ it "should not try to manage files in memory" do
+ main = Puppet::Type.type(:file).create(:path => "/maindir")
+
+ trans = @settings.to_transportable
+
+ lambda { trans.to_catalog }.should_not raise_error
+ end
+
+ it "should ignore file settings whose values are not strings" do
+ @settings[:maindir] = false
+
+ lambda { trans = @settings.to_transportable }.should_not raise_error
+ end
+
it "should be able to turn the current configuration into a parseable manifest"
it "should convert octal numbers correctly when producing a manifest"
@@ -630,4 +644,6 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
proc { @settings.use(:whatever) }.should raise_error(RuntimeError)
end
+
+ after { Puppet::Type.allclear }
end
diff --git a/spec/unit/util/tagging.rb b/spec/unit/util/tagging.rb
new file mode 100755
index 000000000..91cbb213d
--- /dev/null
+++ b/spec/unit/util/tagging.rb
@@ -0,0 +1,88 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-01-19.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/util/tagging'
+
+describe Puppet::Util::Tagging, "when adding tags" do
+ before do
+ @tagger = Object.new
+ @tagger.extend(Puppet::Util::Tagging)
+ end
+
+ it "should have a method for adding tags" do
+ @tagger.should be_respond_to(:tag)
+ end
+
+ it "should have a method for returning all tags" do
+ @tagger.should be_respond_to(:tags)
+ end
+
+ it "should add tags to the returned tag list" do
+ @tagger.tag("one")
+ @tagger.tags.should be_include("one")
+ end
+
+ it "should not add duplicate tags to the returned tag list" do
+ @tagger.tag("one")
+ @tagger.tag("one")
+ @tagger.tags.should == ["one"]
+ end
+
+ it "should return a duplicate of the tag list, rather than the original" do
+ @tagger.tag("one")
+ tags = @tagger.tags
+ tags << "two"
+ @tagger.tags.should_not be_include("two")
+ end
+
+ it "should add all provided tags to the tag list" do
+ @tagger.tag("one", "two")
+ @tagger.tags.should be_include("one")
+ @tagger.tags.should be_include("two")
+ end
+
+ it "should fail on tags containing '*' characters" do
+ lambda { @tagger.tag("bad*tag") }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should fail on tags starting with '-' characters" do
+ lambda { @tagger.tag("-badtag") }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should fail on tags containing ' ' characters" do
+ lambda { @tagger.tag("bad tag") }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should allow alpha tags" do
+ lambda { @tagger.tag("good_tag") }.should_not raise_error(Puppet::ParseError)
+ end
+
+ it "should provide a method for testing tag validity" do
+ @tagger.metaclass.publicize_methods(:valid_tag?) { @tagger.should be_respond_to(:valid_tag?) }
+ end
+
+ it "should add qualified classes as tags" do
+ @tagger.tag("one::two")
+ @tagger.tags.should be_include("one::two")
+ end
+
+ it "should add each part of qualified classes as tags" do
+ @tagger.tag("one::two::three")
+ @tagger.tags.should be_include("one")
+ @tagger.tags.should be_include("two")
+ @tagger.tags.should be_include("three")
+ end
+
+ it "should indicate when the object is tagged with a provided tag" do
+ @tagger.tag("one")
+ @tagger.should be_tagged("one")
+ end
+
+ it "should indicate when the object is not tagged with a provided tag" do
+ @tagger.should_not be_tagged("one")
+ end
+end
diff --git a/test/data/snippets/collection_within_virtual_definitions.pp b/test/data/snippets/collection_within_virtual_definitions.pp
new file mode 100644
index 000000000..3c21468b0
--- /dev/null
+++ b/test/data/snippets/collection_within_virtual_definitions.pp
@@ -0,0 +1,20 @@
+define test($name) {
+ file {"/tmp/collection_within_virtual_definitions1_$name.txt":
+ content => "File name $name\n"
+ }
+ Test2 <||>
+}
+
+define test2() {
+ file {"/tmp/collection_within_virtual_definitions2_$name.txt":
+ content => "This is a test\n"
+ }
+}
+
+node default {
+ @test {"foo":
+ name => "foo"
+ }
+ @test2 {"foo2": }
+ Test <||>
+}
diff --git a/test/data/snippets/realize_defined_types.pp b/test/data/snippets/realize_defined_types.pp
deleted file mode 100644
index a4b562258..000000000
--- a/test/data/snippets/realize_defined_types.pp
+++ /dev/null
@@ -1,13 +0,0 @@
-define testing {
- file { "/tmp/realize_defined_test1": ensure => file }
-}
-@testing { yay: }
-
-define deeper {
- file { "/tmp/realize_defined_test2": ensure => file }
-}
-
-@deeper { boo: }
-
-realize Testing[yay]
-realize File["/tmp/realize_defined_test2"]
diff --git a/test/language/ast.rb b/test/language/ast.rb
index b31012d38..8c0f31aba 100755
--- a/test/language/ast.rb
+++ b/test/language/ast.rb
@@ -35,14 +35,14 @@ class TestAST < Test::Unit::TestCase
# We initialized it to true, so we should get that first
ret = nil
assert_nothing_raised {
- ret = astif.evaluate(:scope => "yay")
+ ret = astif.evaluate("yay")
}
assert_equal(:if, ret)
# Now set it to false and check that
faketest.evaluate = false
assert_nothing_raised {
- ret = astif.evaluate(:scope => "yay")
+ ret = astif.evaluate("yay")
}
assert_equal(:else, ret)
end
@@ -57,10 +57,10 @@ class TestAST < Test::Unit::TestCase
end
Puppet::Parser::Resource.expects(:new).with { |o| o.is_a?(Hash) }.returns(:override)
- scope.compile.expects(:store_override).with(:override)
+ scope.compiler.expects(:add_override).with(:override)
ret = nil
assert_nothing_raised do
- ret = ref.evaluate :scope => scope
+ ret = ref.evaluate scope
end
assert_equal(:override, ret, "Did not return override")
@@ -74,7 +74,7 @@ class TestAST < Test::Unit::TestCase
args = {:source => "/yay/ness", :group => "yayness"}
assert_nothing_raised do
obj = defaultobj "file", args
- obj.evaluate :scope => scope
+ obj.evaluate scope
end
hash = nil
@@ -93,56 +93,6 @@ class TestAST < Test::Unit::TestCase
end
end
- def test_node
- scope = mkscope
- parser = scope.compile.parser
-
- # Define a base node
- basenode = parser.newnode "basenode", :code => AST::ASTArray.new(:children => [
- resourcedef("file", "/tmp/base", "owner" => "root")
- ])
-
- # Now define a subnode
- nodes = parser.newnode ["mynode", "othernode"],
- :code => AST::ASTArray.new(:children => [
- resourcedef("file", "/tmp/mynode", "owner" => "root"),
- resourcedef("file", "/tmp/basenode", "owner" => "daemon")
- ])
-
- assert_instance_of(Array, nodes)
-
- # Make sure we can find them all.
- %w{mynode othernode}.each do |node|
- assert(parser.nodes[node], "Could not find %s" % node)
- end
- mynode = parser.nodes["mynode"]
-
- # Now try evaluating the node
- assert_nothing_raised do
- mynode.evaluate :scope => scope, :resource => scope.resource
- end
-
- # Make sure that we can find each of the files
- myfile = scope.findresource "File[/tmp/mynode]"
- assert(myfile, "Could not find file from node")
- assert_equal("root", myfile[:owner])
-
- basefile = scope.findresource "File[/tmp/basenode]"
- assert(basefile, "Could not find file from base node")
- assert_equal("daemon", basefile[:owner])
-
- # Now make sure we can evaluate nodes with parents
- child = parser.newnode(%w{child}, :parent => "basenode").shift
-
- newscope = mkscope :parser => parser
- assert_nothing_raised do
- child.evaluate :scope => newscope, :resource => scope.resource
- end
-
- assert(newscope.findresource("File[/tmp/base]"),
- "Could not find base resource")
- end
-
def test_collection
scope = mkscope
@@ -155,13 +105,13 @@ class TestAST < Test::Unit::TestCase
ret = nil
assert_nothing_raised do
- ret = coll.evaluate :scope => scope
+ ret = coll.evaluate scope
end
assert_instance_of(Puppet::Parser::Collector, ret)
# Now make sure we get it back from the scope
- colls = scope.compile.instance_variable_get("@collections")
+ colls = scope.compiler.instance_variable_get("@collections")
assert_equal([ret], colls, "Did not store collector in config's collection list")
end
@@ -175,7 +125,7 @@ class TestAST < Test::Unit::TestCase
run_collection_queries(:virtual) do |string, result, query|
code = nil
assert_nothing_raised do
- str, code = query.evaluate :scope => scope
+ str, code = query.evaluate scope
end
assert_instance_of(Proc, code)
diff --git a/test/language/ast/casestatement.rb b/test/language/ast/casestatement.rb
index 0a744b686..d95d788d9 100755
--- a/test/language/ast/casestatement.rb
+++ b/test/language/ast/casestatement.rb
@@ -45,7 +45,7 @@ class TestCaseStatement < Test::Unit::TestCase
result = nil
assert_nothing_raised do
- result = ast.evaluate :scope => scope
+ result = ast.evaluate scope
end
assert(result, "did not get valid result")
assert_equal(["upper"], $evaluated, "Did not match case-sensitively")
@@ -56,7 +56,7 @@ class TestCaseStatement < Test::Unit::TestCase
$evaluated.clear
hash["MyParam"].reset
assert_nothing_raised do
- result = ast.evaluate :scope => scope
+ result = ast.evaluate scope
end
assert(result, "did not get valid result")
assert_equal(["lower"], result, "Did not match case-insensitively")
@@ -92,7 +92,7 @@ class TestCaseStatement < Test::Unit::TestCase
scope = mkscope
scope.setvar("testparam", value)
assert_nothing_raised do
- result = ast.evaluate(:scope => scope)
+ result = ast.evaluate(scope)
end
assert_equal(should, result, "Got incorrect result for %s" % value)
diff --git a/test/language/ast/definition.rb b/test/language/ast/definition.rb
deleted file mode 100755
index 2a71aaa45..000000000
--- a/test/language/ast/definition.rb
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke A. Kanies on 2006-02-20.
-# Copyright (c) 2006. All rights reserved.
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'mocha'
-require 'puppettest/parsertesting'
-require 'puppettest/resourcetesting'
-
-class TestASTDefinition < Test::Unit::TestCase
- include PuppetTest
- include PuppetTest::ParserTesting
- include PuppetTest::ResourceTesting
- AST = Puppet::Parser::AST
-
- def test_initialize
- parser = mkparser
-
- # Create a new definition
- klass = parser.newdefine "yayness",
- :arguments => [["owner", stringobj("nobody")], %w{mode}],
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp/$name",
- "owner" => varref("owner"), "mode" => varref("mode"))]
- )
-
- # Test validattr? a couple different ways
- [:owner, "owner", :schedule, "schedule"].each do |var|
- assert(klass.validattr?(var), "%s was not considered valid" % var.inspect)
- end
-
- [:random, "random"].each do |var|
- assert(! klass.validattr?(var), "%s was considered valid" % var.inspect)
- end
-
- end
-
- def test_evaluate
- parser = mkparser
- config = mkcompile
- config.send(:evaluate_main)
- scope = config.topscope
- klass = parser.newdefine "yayness",
- :arguments => [["owner", stringobj("nobody")], %w{mode}],
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp/$name",
- "owner" => varref("owner"), "mode" => varref("mode"))]
- )
-
- resource = Puppet::Parser::Resource.new(
- :title => "first",
- :type => "yayness",
- :exported => false,
- :virtual => false,
- :scope => scope,
- :source => scope.source
- )
- resource.send(:set_parameter, "name", "first")
- resource.send(:set_parameter, "mode", "755")
-
- resource.stubs(:title)
- assert_nothing_raised do
- klass.evaluate(:scope => scope, :resource => resource)
- end
-
- firstobj = config.findresource("File[/tmp/first]")
- assert(firstobj, "Did not create /tmp/first obj")
-
- assert_equal("File", firstobj.type)
- assert_equal("/tmp/first", firstobj.title)
- assert_equal("nobody", firstobj[:owner])
- assert_equal("755", firstobj[:mode])
-
- # Make sure we can't evaluate it with the same args
- assert_raise(Puppet::ParseError) do
- klass.evaluate(:scope => scope, :resource => resource)
- end
-
- # Now create another with different args
- resource2 = Puppet::Parser::Resource.new(
- :title => "second",
- :type => "yayness",
- :exported => false,
- :virtual => false,
- :scope => scope,
- :source => scope.source
- )
- resource2.send(:set_parameter, "name", "second")
- resource2.send(:set_parameter, "mode", "755")
- resource2.send(:set_parameter, "owner", "daemon")
-
- assert_nothing_raised do
- klass.evaluate(:scope => scope, :resource => resource2)
- end
-
- secondobj = config.findresource("File[/tmp/second]")
- assert(secondobj, "Did not create /tmp/second obj")
-
- assert_equal("File", secondobj.type)
- assert_equal("/tmp/second", secondobj.title)
- assert_equal("daemon", secondobj[:owner])
- assert_equal("755", secondobj[:mode])
- end
-
- # #539 - definitions should support both names and titles
- def test_names_and_titles
- parser = mkparser
- scope = mkscope :parser => parser
-
- [
- {:name => "one", :title => "two"},
- {:title => "mytitle"}
- ].each_with_index do |hash, i|
- # Create a definition that uses both name and title. Put this
- # inside the loop so the subscope expectations work.
- klass = parser.newdefine "yayness%s" % i
-
- resource = Puppet::Parser::Resource.new(
- :title => hash[:title],
- :type => "yayness%s" % i,
- :exported => false,
- :virtual => false,
- :scope => scope,
- :source => scope.source
- )
-
- subscope = klass.subscope(scope, resource)
-
- klass.expects(:subscope).returns(subscope)
-
- if hash[:name]
- resource.stubs(:to_hash).returns({:name => hash[:name]})
- end
-
- assert_nothing_raised("Could not evaluate definition with %s" % hash.inspect) do
- klass.evaluate(:scope => scope, :resource => resource)
- end
-
- name = hash[:name] || hash[:title]
- title = hash[:title]
-
- assert_equal(name, subscope.lookupvar("name"),
- "Name did not get set correctly")
- assert_equal(title, subscope.lookupvar("title"),
- "title did not get set correctly")
-
- [:name, :title].each do |param|
- val = resource.send(param)
- assert(subscope.tags.include?(val),
- "Scope was not tagged with %s '%s'" % [param, val])
- end
- end
- end
-
- # Testing the root cause of #615. We should be using the fqname for the type, instead
- # of just the short name.
- def test_fully_qualified_types
- parser = mkparser
- klass = parser.newclass("one::two")
-
- assert_equal("one::two", klass.classname, "Class did not get fully qualified class name")
- end
-end
diff --git a/test/language/ast/hostclass.rb b/test/language/ast/hostclass.rb
deleted file mode 100755
index 80032f30c..000000000
--- a/test/language/ast/hostclass.rb
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke A. Kanies on 2006-02-20.
-# Copyright (c) 2006. All rights reserved.
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'puppettest/parsertesting'
-require 'puppettest/resourcetesting'
-require 'mocha'
-
-class TestASTHostClass < Test::Unit::TestCase
- include PuppetTest
- include PuppetTest::ParserTesting
- include PuppetTest::ResourceTesting
- AST = Puppet::Parser::AST
-
- def test_hostclass
- scope = mkscope
- parser = scope.compile.parser
-
- # Create the class we're testing, first with no parent
- klass = parser.newclass "first",
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp",
- "owner" => "nobody", "mode" => "755")]
- )
-
- resource = Puppet::Parser::Resource.new(:type => "class", :title => "first", :scope => scope)
- assert_nothing_raised do
- klass.evaluate(:scope => scope, :resource => resource)
- end
-
- # Then try it again
- assert_nothing_raised do
- klass.evaluate(:scope => scope, :resource => resource)
- end
-
- assert(scope.compile.class_scope(klass), "Class was not considered evaluated")
-
- tmp = scope.findresource("File[/tmp]")
- assert(tmp, "Could not find file /tmp")
- assert_equal("nobody", tmp[:owner])
- assert_equal("755", tmp[:mode])
-
- # Now create a couple more classes.
- newbase = parser.newclass "newbase",
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp/other",
- "owner" => "nobody", "mode" => "644")]
- )
-
- newsub = parser.newclass "newsub",
- :parent => "newbase",
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp/yay",
- "owner" => "nobody", "mode" => "755"),
- resourceoverride("file", "/tmp/other",
- "owner" => "daemon")
- ]
- )
-
- # Override a different variable in the top scope.
- moresub = parser.newclass "moresub",
- :parent => "newbase",
- :code => AST::ASTArray.new(
- :children => [resourceoverride("file", "/tmp/other",
- "mode" => "755")]
- )
-
- assert_nothing_raised do
- newsub.evaluate(:scope => scope, :resource => resource)
- end
-
- assert_nothing_raised do
- moresub.evaluate(:scope => scope, :resource => resource)
- end
-
- assert(scope.compile.class_scope(newbase), "Did not eval newbase")
- assert(scope.compile.class_scope(newsub), "Did not eval newsub")
-
- yay = scope.findresource("File[/tmp/yay]")
- assert(yay, "Did not find file /tmp/yay")
- assert_equal("nobody", yay[:owner])
- assert_equal("755", yay[:mode])
-
- other = scope.findresource("File[/tmp/other]")
- assert(other, "Did not find file /tmp/other")
- assert_equal("daemon", other[:owner])
- assert_equal("755", other[:mode])
- end
-
- # Make sure that classes set their namespaces to themselves. This
- # way they start looking for definitions in their own namespace.
- def test_hostclass_namespace
- scope = mkscope
- parser = scope.compile.parser
-
- # Create a new class
- klass = nil
- assert_nothing_raised do
- klass = parser.newclass "funtest"
- end
-
- # Now define a definition in that namespace
-
- define = nil
- assert_nothing_raised do
- define = parser.newdefine "funtest::mydefine"
- end
-
- assert_equal("funtest", klass.namespace,
- "component namespace was not set in the class")
-
- assert_equal("funtest", define.namespace,
- "component namespace was not set in the definition")
-
- newscope = klass.subscope(scope, mock("resource"))
-
- assert_equal(["funtest"], newscope.namespaces,
- "Scope did not inherit namespace")
-
- # Now make sure we can find the define
- assert(newscope.finddefine("mydefine"),
- "Could not find definition in my enclosing class")
- end
-
- # Make sure that our scope is a subscope of the parentclass's scope.
- # At the same time, make sure definitions in the parent class can be
- # found within the subclass (#517).
- def test_parent_scope_from_parentclass
- scope = mkscope
- parser = scope.compile.parser
-
- source = parser.newclass ""
- parser.newclass("base")
- fun = parser.newdefine("base::fun")
- parser.newclass("middle", :parent => "base")
- parser.newclass("sub", :parent => "middle")
- scope = mkscope :parser => parser
-
- ret = nil
- assert_nothing_raised do
- ret = scope.compile.evaluate_classes(["sub"], scope)
- end
- scope.compile.send(:evaluate_generators)
-
- subscope = scope.compile.class_scope(scope.findclass("sub"))
- assert(subscope, "could not find sub scope")
- mscope = scope.compile.class_scope(scope.findclass("middle"))
- assert(mscope, "could not find middle scope")
- pscope = scope.compile.class_scope(scope.findclass("base"))
- assert(pscope, "could not find parent scope")
-
- assert(pscope == mscope.parent, "parent scope of middle was not set correctly")
- assert(mscope == subscope.parent, "parent scope of sub was not set correctly")
-
- result = mscope.finddefine("fun")
- assert(result, "could not find parent-defined definition from middle")
- assert(fun == result, "found incorrect parent-defined definition from middle")
-
- result = subscope.finddefine("fun")
- assert(result, "could not find parent-defined definition from sub")
- assert(fun == result, "found incorrect parent-defined definition from sub")
- end
-
- # #795 - make sure the subclass's tags get set before we
- # evaluate the parent class, so we can be sure that the parent
- # class can switch based on the sub classes.
- def test_tags_set_before_parent_is_evaluated
- scope = mkscope
- parser = scope.compile.parser
- base = parser.newclass "base"
- sub = parser.newclass "sub", :parent => "base"
-
- base.expects(:safeevaluate).with do |args|
- assert(scope.compile.catalog.tags.include?("sub"), "Did not tag with sub class name before evaluating base class")
- base.evaluate(args)
- true
- end
- sub.evaluate :scope => scope, :resource => scope.resource
- end
-end
diff --git a/test/language/ast/resource.rb b/test/language/ast/resource.rb
index c99d98eeb..97541d92f 100755
--- a/test/language/ast/resource.rb
+++ b/test/language/ast/resource.rb
@@ -16,8 +16,7 @@ class TestASTResource< Test::Unit::TestCase
def setup
super
@scope = mkscope
- @parser = @scope.compile.parser
- @scope.compile.send(:evaluate_main)
+ @parser = @scope.compiler.parser
end
def newdef(type, title, params = nil)
@@ -36,24 +35,24 @@ class TestASTResource< Test::Unit::TestCase
title = "title"
# First try a qualified type
- assert_equal("One::Two", newdef("two", title).evaluate(:scope => twoscope)[0].type,
+ assert_equal("One::Two", newdef("two", title).evaluate(twoscope)[0].type,
"Defined type was not made fully qualified")
# Then try a type that does not need to be qualified
- assert_equal("One", newdef("one", title).evaluate(:scope => twoscope)[0].type,
+ assert_equal("One", newdef("one", title).evaluate(twoscope)[0].type,
"Unqualified defined type was not handled correctly")
# Then an unqualified type from within the one namespace
- assert_equal("Three", newdef("three", title).evaluate(:scope => twoscope)[0].type,
+ assert_equal("Three", newdef("three", title).evaluate(twoscope)[0].type,
"Defined type was not made fully qualified")
# Then a builtin type
- assert_equal("File", newdef("file", title).evaluate(:scope => twoscope)[0].type,
+ assert_equal("File", newdef("file", title).evaluate(twoscope)[0].type,
"Builtin type was not handled correctly")
# Now try a type that does not exist, which should throw an error.
assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do
- newdef("nosuchtype", title).evaluate(:scope => twoscope)
+ newdef("nosuchtype", title).evaluate(twoscope)
end
end
end
diff --git a/test/language/ast/resource_reference.rb b/test/language/ast/resource_reference.rb
index c9fde078f..1f554d90f 100755
--- a/test/language/ast/resource_reference.rb
+++ b/test/language/ast/resource_reference.rb
@@ -20,7 +20,7 @@ class TestASTResourceReference < Test::Unit::TestCase
def setup
super
@scope = mkscope
- @parser = @scope.compile.parser
+ @parser = @scope.compiler.parser
end
def test_evaluate
@@ -31,7 +31,7 @@ class TestASTResourceReference < Test::Unit::TestCase
evaled = nil
assert_nothing_raised("Could not evaluate resource ref") do
- evaled = ref.evaluate(:scope => @scope)
+ evaled = ref.evaluate(@scope)
end
assert_equal(type, evaled.type, "Type did not translate correctly")
@@ -44,7 +44,7 @@ class TestASTResourceReference < Test::Unit::TestCase
ref = newref("Class", "one")
evaled = nil
assert_nothing_raised("Could not evaluate resource ref") do
- evaled = ref.evaluate(:scope => @scope)
+ evaled = ref.evaluate(@scope)
end
assert_equal("Class", evaled.type, "Did not set type to 'class'")
@@ -61,24 +61,24 @@ class TestASTResourceReference < Test::Unit::TestCase
title = "title"
# First try a qualified type
- assert_equal("One::Two", newref("two", title).evaluate(:scope => twoscope).type,
+ assert_equal("One::Two", newref("two", title).evaluate(twoscope).type,
"Defined type was not made fully qualified")
# Then try a type that does not need to be qualified
- assert_equal("One", newref("one", title).evaluate(:scope => twoscope).type,
+ assert_equal("One", newref("one", title).evaluate(twoscope).type,
"Unqualified defined type was not handled correctly")
# Then an unqualified type from within the one namespace
- assert_equal("Three", newref("three", title).evaluate(:scope => twoscope).type,
+ assert_equal("Three", newref("three", title).evaluate(twoscope).type,
"Defined type was not made fully qualified")
# Then a builtin type
- assert_equal("File", newref("file", title).evaluate(:scope => twoscope).type,
+ assert_equal("File", newref("file", title).evaluate(twoscope).type,
"Builtin type was not handled correctly")
# Now try a type that does not exist, which should throw an error.
assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do
- newref("nosuchtype", title).evaluate(:scope => twoscope)
+ newref("nosuchtype", title).evaluate(twoscope)
end
# Now run the same tests, but with the classes
@@ -86,20 +86,20 @@ class TestASTResourceReference < Test::Unit::TestCase
@parser.newclass "one::five"
# First try an unqualified type
- assert_equal("four", newref("class", "four").evaluate(:scope => twoscope).title,
+ assert_equal("four", newref("class", "four").evaluate(twoscope).title,
"Unqualified class was not found")
# Then a qualified class
- assert_equal("one::five", newref("class", "five").evaluate(:scope => twoscope).title,
+ assert_equal("one::five", newref("class", "five").evaluate(twoscope).title,
"Class was not made fully qualified")
# Then try a type that does not need to be qualified
- assert_equal("four", newref("class", "four").evaluate(:scope => twoscope).title,
+ assert_equal("four", newref("class", "four").evaluate(twoscope).title,
"Unqualified class was not handled correctly")
# Now try a type that does not exist, which should throw an error.
assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do
- newref("class", "nosuchclass").evaluate(:scope => twoscope)
+ newref("class", "nosuchclass").evaluate(twoscope)
end
end
end
diff --git a/test/language/ast/selector.rb b/test/language/ast/selector.rb
index 535fcbf70..6e923bdcb 100755
--- a/test/language/ast/selector.rb
+++ b/test/language/ast/selector.rb
@@ -37,7 +37,7 @@ class TestSelector < Test::Unit::TestCase
params = maker.call()
sel = AST::Selector.new(:param => param, :values => params.values)
result = nil
- assert_nothing_raised { result = sel.evaluate(:scope => scope) }
+ assert_nothing_raised { result = sel.evaluate(scope) }
assert_equal(should[str], result, "did not case-sensitively match %s" % str)
end
@@ -53,7 +53,7 @@ class TestSelector < Test::Unit::TestCase
params.delete(:upper)
sel = AST::Selector.new(:param => param, :values => params.values)
result = nil
- assert_nothing_raised { result = sel.evaluate(:scope => scope) }
+ assert_nothing_raised { result = sel.evaluate(scope) }
assert_equal("lower", result, "did not case-insensitively match %s" % str)
end
end
diff --git a/test/language/ast/variable.rb b/test/language/ast/variable.rb
index 09122ce16..bde397bb4 100755
--- a/test/language/ast/variable.rb
+++ b/test/language/ast/variable.rb
@@ -22,9 +22,9 @@ class TestVariable < Test::Unit::TestCase
end
def test_evaluate
- assert_equal("", @var.evaluate(:scope => @scope), "did not return empty string on unset var")
+ assert_equal("", @var.evaluate(@scope), "did not return empty string on unset var")
@scope.setvar(@name, "something")
- assert_equal("something", @var.evaluate(:scope => @scope), "incorrect variable value")
+ assert_equal("something", @var.evaluate(@scope), "incorrect variable value")
end
end
diff --git a/test/language/compile.rb b/test/language/compile.rb
deleted file mode 100755
index 298493c0a..000000000
--- a/test/language/compile.rb
+++ /dev/null
@@ -1,569 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'mocha'
-require 'puppettest'
-require 'puppettest/parsertesting'
-require 'puppet/parser/compile'
-
-# Test our compile object.
-class TestCompile < Test::Unit::TestCase
- include PuppetTest
- include PuppetTest::ParserTesting
-
- Compile = Puppet::Parser::Compile
- Scope = Puppet::Parser::Scope
- Node = Puppet::Network::Handler.handler(:node)
- SimpleNode = Puppet::Node
-
- def mknode(name = "foo")
- @node = SimpleNode.new(name)
- end
-
- def mkparser
- # This should mock an interpreter
- @parser = stub 'parser', :version => "1.0", :nodes => {}
- end
-
- def mkcompile(options = {})
- if node = options[:node]
- options.delete(:node)
- else
- node = mknode
- end
- @compile = Compile.new(node, mkparser, options)
- end
-
- def test_initialize
- compile = nil
- node = stub 'node', :name => "foo"
- parser = stub 'parser', :version => "1.0", :nodes => {}
- assert_nothing_raised("Could not init compile with all required options") do
- compile = Compile.new(node, parser)
- end
-
- assert_equal(node, compile.node, "Did not set node correctly")
- assert_equal(parser, compile.parser, "Did not set parser correctly")
-
- # We're not testing here whether we call initvars, because it's too difficult to
- # mock.
-
- # Now try it with some options
- assert_nothing_raised("Could not init compile with extra options") do
- compile = Compile.new(node, parser)
- end
-
- assert_equal(false, compile.ast_nodes?, "Did not set ast_nodes? correctly")
- end
-
- def test_initvars
- compile = mkcompile
- [:class_scopes, :resource_table, :exported_resources, :resource_overrides].each do |table|
- assert_instance_of(Hash, compile.send(:instance_variable_get, "@#{table}"), "Did not set %s table correctly" % table)
- end
- assert_instance_of(Scope, compile.topscope, "Did not create a topscope")
- graph = compile.instance_variable_get("@scope_graph")
- assert_instance_of(GRATR::Digraph, graph, "Did not create scope graph")
- assert(graph.vertex?(compile.topscope), "Did not add top scope as a vertex in the graph")
- end
-
- # Make sure we store and can retrieve references to classes and their scopes.
- def test_class_set_and_class_scope
- klass = mock 'ast_class'
- klass.expects(:classname).returns("myname")
-
- compile = mkcompile
- compile.catalog.expects(:tag).with("myname")
-
- assert_nothing_raised("Could not set class") do
- compile.class_set "myname", "myscope"
- end
- # First try to retrieve it by name.
- assert_equal("myscope", compile.class_scope("myname"), "Could not retrieve class scope by name")
-
- # Then by object
- assert_equal("myscope", compile.class_scope(klass), "Could not retrieve class scope by object")
- end
-
- def test_classlist
- compile = mkcompile
-
- compile.class_set "", "empty"
- compile.class_set "one", "yep"
- compile.class_set "two", "nope"
-
- # Make sure our class list is correct
- assert_equal(%w{one two}.sort, compile.classlist.sort, "Did not get correct class list")
- end
-
- # Make sure collections get added to our internal array
- def test_add_collection
- compile = mkcompile
- assert_nothing_raised("Could not add collection") do
- compile.add_collection "nope"
- end
- assert_equal(%w{nope}, compile.instance_variable_get("@collections"), "Did not add collection")
- end
-
- # Make sure we create a graph of scopes.
- def test_newscope
- compile = mkcompile
- graph = compile.instance_variable_get("@scope_graph")
- assert_instance_of(Scope, compile.topscope, "Did not create top scope")
- assert_instance_of(GRATR::Digraph, graph, "Did not create graph")
-
- assert(graph.vertex?(compile.topscope), "The top scope is not a vertex in the graph")
-
- # Now that we've got the top scope, create a new, subscope
- subscope = nil
- assert_nothing_raised("Could not create subscope") do
- subscope = compile.newscope(compile.topscope)
- end
- assert_instance_of(Scope, subscope, "Did not create subscope")
- assert(graph.edge?(compile.topscope, subscope), "An edge between top scope and subscope was not added")
-
- # Make sure a scope can find its parent.
- assert(compile.parent(subscope), "Could not look up parent scope on compile")
- assert_equal(compile.topscope.object_id, compile.parent(subscope).object_id, "Did not get correct parent scope from compile")
- assert_equal(compile.topscope.object_id, subscope.parent.object_id, "Scope did not correctly retrieve its parent scope")
-
- # Now create another, this time specifying options
- another = nil
- assert_nothing_raised("Could not create subscope") do
- another = compile.newscope(subscope, :level => 5)
- end
- assert_equal(5, another.level, "did not set scope option correctly")
- assert_instance_of(Scope, another, "Did not create second subscope")
- assert(graph.edge?(subscope, another), "An edge between parent scope and second subscope was not added")
-
- # Make sure it can find its parent.
- assert(compile.parent(another), "Could not look up parent scope of second subscope on compile")
- assert_equal(subscope.object_id, compile.parent(another).object_id, "Did not get correct parent scope of second subscope from compile")
- assert_equal(subscope.object_id, another.parent.object_id, "Second subscope did not correctly retrieve its parent scope")
-
- # And make sure both scopes show up in the right order in the search path
- assert_equal([another.object_id, subscope.object_id, compile.topscope.object_id], another.scope_path.collect { |p| p.object_id },
- "Did not get correct scope path")
- end
-
- # The heart of the action.
- def test_compile
- compile = mkcompile
- [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated, :finish].each do |method|
- compile.expects(method)
- end
- assert_instance_of(Puppet::Node::Catalog, compile.compile, "Did not return the catalog")
- end
-
- # Test setting the node's parameters into the top scope.
- def test_set_node_parameters
- compile = mkcompile
- @node.parameters = {"a" => "b", "c" => "d"}
- scope = compile.topscope
- @node.parameters.each do |param, value|
- scope.expects(:setvar).with(param, value)
- end
-
- assert_nothing_raised("Could not call 'set_node_parameters'") do
- compile.send(:set_node_parameters)
- end
- end
-
- # Test that we can evaluate the main class, which is the one named "" in namespace
- # "".
- def test_evaluate_main
- compile = mkcompile
- main_class = mock 'main_class'
- compile.topscope.expects(:source=).with(main_class)
- @parser.expects(:findclass).with("", "").returns(main_class)
-
- main_resource = mock 'main resource'
- Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == :main }.returns(main_resource)
-
- main_resource.expects(:evaluate)
-
- assert_nothing_raised("Could not call evaluate_main") do
- compile.send(:evaluate_main)
- end
- end
-
- def test_evaluate_node_classes
- compile = mkcompile
- @node.classes = %w{one two three four}
- compile.expects(:evaluate_classes).with(%w{one two three four}, compile.topscope)
- assert_nothing_raised("could not call evaluate_node_classes") do
- compile.send(:evaluate_node_classes)
- end
- end
-
- def test_evaluate_collections
- compile = mkcompile
-
- colls = []
-
- # Make sure we return false when there's nothing there.
- assert(! compile.send(:evaluate_collections), "Returned true when there were no collections")
-
- # And when the collections fail to evaluate.
- colls << mock("coll1-false")
- colls << mock("coll2-false")
- colls.each { |c| c.expects(:evaluate).returns(false) }
-
- compile.instance_variable_set("@collections", colls)
- assert(! compile.send(:evaluate_collections), "Returned true when collections both evaluated nothing")
-
- # Now have one of the colls evaluate
- colls.clear
- colls << mock("coll1-one-true")
- colls << mock("coll2-one-true")
- colls[0].expects(:evaluate).returns(true)
- colls[1].expects(:evaluate).returns(false)
- assert(compile.send(:evaluate_collections), "Did not return true when one collection evaluated true")
-
- # And have them both eval true
- colls.clear
- colls << mock("coll1-both-true")
- colls << mock("coll2-both-true")
- colls[0].expects(:evaluate).returns(true)
- colls[1].expects(:evaluate).returns(true)
- assert(compile.send(:evaluate_collections), "Did not return true when both collections evaluated true")
- end
-
- def test_unevaluated_resources
- compile = mkcompile
- resources = {}
- compile.instance_variable_set("@resource_table", resources)
-
- # First test it when the table is empty
- assert_nil(compile.send(:unevaluated_resources), "Somehow found unevaluated resources in an empty table")
-
- # Then add a builtin resources
- resources["one"] = mock("builtin only")
- resources["one"].expects(:builtin?).returns(true)
- assert_nil(compile.send(:unevaluated_resources), "Considered a builtin resource unevaluated")
-
- # And do both builtin and non-builtin but already evaluated
- resources.clear
- resources["one"] = mock("builtin (with eval)")
- resources["one"].expects(:builtin?).returns(true)
- resources["two"] = mock("evaled (with builtin)")
- resources["two"].expects(:builtin?).returns(false)
- resources["two"].expects(:evaluated?).returns(true)
- assert_nil(compile.send(:unevaluated_resources), "Considered either a builtin or evaluated resource unevaluated")
-
- # Now a single unevaluated resource.
- resources.clear
- resources["one"] = mock("unevaluated")
- resources["one"].expects(:builtin?).returns(false)
- resources["one"].expects(:evaluated?).returns(false)
- assert_equal([resources["one"]], compile.send(:unevaluated_resources), "Did not find unevaluated resource")
-
- # With two uneval'ed resources, and an eval'ed one thrown in
- resources.clear
- resources["one"] = mock("unevaluated one")
- resources["one"].expects(:builtin?).returns(false)
- resources["one"].expects(:evaluated?).returns(false)
- resources["two"] = mock("unevaluated two")
- resources["two"].expects(:builtin?).returns(false)
- resources["two"].expects(:evaluated?).returns(false)
- resources["three"] = mock("evaluated")
- resources["three"].expects(:builtin?).returns(false)
- resources["three"].expects(:evaluated?).returns(true)
-
- result = compile.send(:unevaluated_resources)
- %w{one two}.each do |name|
- assert(result.include?(resources[name]), "Did not find %s in the unevaluated list" % name)
- end
- end
-
- def test_evaluate_definitions
- # First try the case where there's nothing to return
- compile = mkcompile
- compile.expects(:unevaluated_resources).returns(nil)
-
- assert_nothing_raised("Could not test for unevaluated resources") do
- assert(! compile.send(:evaluate_definitions), "evaluate_definitions returned true when no resources were evaluated")
- end
-
- # Now try it with resources left to evaluate
- resources = []
- res1 = mock("resource1")
- res1.expects(:evaluate)
- res2 = mock("resource2")
- res2.expects(:evaluate)
- resources << res1 << res2
- compile = mkcompile
- compile.expects(:unevaluated_resources).returns(resources)
-
- assert_nothing_raised("Could not test for unevaluated resources") do
- assert(compile.send(:evaluate_definitions), "evaluate_definitions returned false when resources were evaluated")
- end
- end
-
- def test_evaluate_generators
- # First try the case where we have nothing to do
- compile = mkcompile
- compile.expects(:evaluate_definitions).returns(false)
- compile.expects(:evaluate_collections).returns(false)
-
- assert_nothing_raised("Could not call :eval_iterate") do
- compile.send(:evaluate_generators)
- end
-
- # FIXME I could not get this test to work, but the code is short
- # enough that I'm ok with it.
- # It's important that collections are evaluated before definitions,
- # so make sure that's the case by verifying that collections get tested
- # twice but definitions only once.
- #compile = mkcompile
- #compile.expects(:evaluate_collections).returns(true).returns(false)
- #compile.expects(:evaluate_definitions).returns(false)
- #compile.send(:eval_iterate)
- end
-
- def test_store
- compile = mkcompile
- Puppet.features.expects(:rails?).returns(true)
- Puppet::Rails.expects(:connect)
-
- node = mock 'node'
- resource_table = mock 'resources'
- resource_table.expects(:values).returns(:resources)
- compile.instance_variable_set("@node", node)
- compile.instance_variable_set("@resource_table", resource_table)
- compile.expects(:store_to_active_record).with(node, :resources)
- compile.send(:store)
- end
-
- def test_store_to_active_record
- compile = mkcompile
- node = mock 'node'
- node.expects(:name).returns("myname")
- Puppet::Rails::Host.stubs(:transaction).yields
- Puppet::Rails::Host.expects(:store).with(node, :resources)
- compile.send(:store_to_active_record, node, :resources)
- end
-
- # Make sure that 'finish' gets called on all of our resources.
- def test_finish
- compile = mkcompile
- table = compile.instance_variable_get("@resource_table")
-
- # Add a resource that does respond to :finish
- yep = mock("finisher")
- yep.expects(:respond_to?).with(:finish).returns(true)
- yep.expects(:finish)
- table["yep"] = yep
-
- # And one that does not
- dnf = mock("dnf")
- dnf.expects(:respond_to?).with(:finish).returns(false)
- table["dnf"] = dnf
-
- compile.send(:finish)
- end
-
- def test_verify_uniqueness
- compile = mkcompile
-
- resources = compile.instance_variable_get("@resource_table")
- resource = mock("noconflict")
- resource.expects(:ref).returns("File[yay]")
- assert_nothing_raised("Raised an exception when there should have been no conflict") do
- compile.send(:verify_uniqueness, resource)
- end
-
- # Now try the case where our type is isomorphic
- resources["thing"] = true
-
- isoconflict = mock("isoconflict")
- isoconflict.expects(:ref).returns("thing")
- isoconflict.expects(:type).returns("testtype")
- faketype = mock("faketype")
- faketype.expects(:isomorphic?).returns(false)
- faketype.expects(:name).returns("whatever")
- Puppet::Type.expects(:type).with("testtype").returns(faketype)
- assert_nothing_raised("Raised an exception when was a conflict in non-isomorphic types") do
- compile.send(:verify_uniqueness, isoconflict)
- end
-
- # Now test for when we actually have an exception
- initial = mock("initial")
- resources["thing"] = initial
- initial.expects(:file).returns(false)
-
- conflict = mock("conflict")
- conflict.expects(:ref).returns("thing").times(2)
- conflict.expects(:type).returns("conflict")
- conflict.expects(:file).returns(false)
- conflict.expects(:line).returns(false)
-
- faketype = mock("faketype")
- faketype.expects(:isomorphic?).returns(true)
- Puppet::Type.expects(:type).with("conflict").returns(faketype)
- assert_raise(Puppet::ParseError, "Did not fail when two isomorphic resources conflicted") do
- compile.send(:verify_uniqueness, conflict)
- end
- end
-
- def test_store_resource
- # Run once when there's no conflict
- compile = mkcompile
- table = compile.instance_variable_get("@resource_table")
- resource = mock("resource")
- resource.expects(:ref).returns("yay")
- compile.expects(:verify_uniqueness).with(resource)
- scope = stub("scope", :resource => mock('resource'))
-
- compile.catalog.expects(:add_edge!).with(scope.resource, resource)
-
- assert_nothing_raised("Could not store resource") do
- compile.store_resource(scope, resource)
- end
- assert_equal(resource, table["yay"], "Did not store resource in table")
-
- # Now for conflicts
- compile = mkcompile
- table = compile.instance_variable_get("@resource_table")
- resource = mock("resource")
- compile.expects(:verify_uniqueness).with(resource).raises(ArgumentError)
-
- assert_raise(ArgumentError, "Did not raise uniqueness exception") do
- compile.store_resource(scope, resource)
- end
- assert(table.empty?, "Conflicting resource was stored in table")
- end
-
- def test_fail_on_unevaluated
- compile = mkcompile
- compile.expects(:fail_on_unevaluated_overrides)
- compile.expects(:fail_on_unevaluated_resource_collections)
- compile.send :fail_on_unevaluated
- end
-
- def test_store_override
- # First test the case when the resource is not present.
- compile = mkcompile
- overrides = compile.instance_variable_get("@resource_overrides")
- override = Object.new
- override.expects(:ref).returns(:myref).times(2)
- override.expects(:override=).with(true)
-
- assert_nothing_raised("Could not call store_override") do
- compile.store_override(override)
- end
- assert_instance_of(Array, overrides[:myref], "Overrides table is not a hash of arrays")
- assert_equal(override, overrides[:myref][0], "Did not store override in appropriately named array")
-
- # And when the resource already exists.
- resource = mock 'resource'
- resources = compile.instance_variable_get("@resource_table")
- resources[:resref] = resource
-
- override = mock 'override'
- resource.expects(:merge).with(override)
- override.expects(:override=).with(true)
- override.expects(:ref).returns(:resref)
- assert_nothing_raised("Could not call store_override when the resource already exists.") do
- compile.store_override(override)
- end
- end
-
- def test_resource_overrides
- compile = mkcompile
- overrides = compile.instance_variable_get("@resource_overrides")
- overrides[:test] = :yay
- resource = mock 'resource'
- resource.expects(:ref).returns(:test)
-
- assert_equal(:yay, compile.resource_overrides(resource), "Did not return overrides from table")
- end
-
- def test_fail_on_unevaluated_resource_collections
- compile = mkcompile
- collections = compile.instance_variable_get("@collections")
-
- # Make sure we're fine when the list is empty
- assert_nothing_raised("Failed when no collections were present") do
- compile.send :fail_on_unevaluated_resource_collections
- end
-
- # And that we're fine when we've got collections but with no resources
- collections << mock('coll')
- collections[0].expects(:resources).returns(nil)
- assert_nothing_raised("Failed when no resource collections were present") do
- compile.send :fail_on_unevaluated_resource_collections
- end
-
- # But that we do fail when we've got resource collections left.
- collections.clear
-
- # return both an array and a string, because that's tested internally
- collections << mock('coll returns one')
- collections[0].expects(:resources).returns(:something)
-
- collections << mock('coll returns many')
- collections[1].expects(:resources).returns([:one, :two])
-
- assert_raise(Puppet::ParseError, "Did not fail on unevaluated resource collections") do
- compile.send :fail_on_unevaluated_resource_collections
- end
- end
-
- def test_fail_on_unevaluated_overrides
- compile = mkcompile
- overrides = compile.instance_variable_get("@resource_overrides")
-
- # Make sure we're fine when the list is empty
- assert_nothing_raised("Failed when no collections were present") do
- compile.send :fail_on_unevaluated_overrides
- end
-
- # But that we fail if there are any overrides left in the table.
- overrides[:yay] = []
- overrides[:foo] = []
- overrides[:bar] = [mock("override")]
- overrides[:bar][0].expects(:ref).returns("yay")
- assert_raise(Puppet::ParseError, "Failed to fail when overrides remain") do
- compile.send :fail_on_unevaluated_overrides
- end
- end
-
- def test_find_resource
- compile = mkcompile
- resources = compile.instance_variable_get("@resource_table")
-
- assert_nothing_raised("Could not call findresource when the resource table was empty") do
- assert_nil(compile.findresource("yay", "foo"), "Returned a non-existent resource")
- assert_nil(compile.findresource("yay[foo]"), "Returned a non-existent resource")
- end
-
- resources["Foo[bar]"] = :yay
- assert_nothing_raised("Could not call findresource when the resource table was not empty") do
- assert_equal(:yay, compile.findresource("foo", "bar"), "Returned a non-existent resource")
- assert_equal(:yay, compile.findresource("Foo[bar]"), "Returned a non-existent resource")
- end
- end
-
- # #620 - Nodes and classes should conflict, else classes don't get evaluated
- def test_nodes_and_classes_name_conflict
- # Test node then class
- compile = mkcompile
- node = stub :nodescope? => true
- klass = stub :nodescope? => false
- compile.class_set("one", node)
- assert_raise(Puppet::ParseError, "Did not fail when replacing node with class") do
- compile.class_set("one", klass)
- end
-
- # and class then node
- compile = mkcompile
- node = stub :nodescope? => true
- klass = stub :nodescope? => false
- compile.class_set("two", klass)
- assert_raise(Puppet::ParseError, "Did not fail when replacing node with class") do
- compile.class_set("two", node)
- end
- end
-end
diff --git a/test/language/functions.rb b/test/language/functions.rb
index 132ee97ac..a5d52d7ac 100755
--- a/test/language/functions.rb
+++ b/test/language/functions.rb
@@ -41,7 +41,7 @@ class TestLangFunctions < Test::Unit::TestCase
scope = mkscope
val = nil
assert_nothing_raised do
- val = func.evaluate(:scope => scope)
+ val = func.evaluate(scope)
end
assert_equal("output avalue", val)
@@ -57,7 +57,7 @@ class TestLangFunctions < Test::Unit::TestCase
val = nil
assert_nothing_raised do
- val = func.evaluate(:scope => scope)
+ val = func.evaluate(scope)
end
assert_equal(retval, val, "'tagged' returned %s for %s" % [val, tag])
@@ -66,7 +66,7 @@ class TestLangFunctions < Test::Unit::TestCase
# Now make sure we correctly get tags.
scope.resource.tag("resourcetag")
assert(scope.function_tagged("resourcetag"), "tagged function did not catch resource tags")
- scope.compile.catalog.tag("configtag")
+ scope.compiler.catalog.tag("configtag")
assert(scope.function_tagged("configtag"), "tagged function did not catch catalog tags")
end
@@ -86,7 +86,7 @@ class TestLangFunctions < Test::Unit::TestCase
scope = mkscope
val = nil
assert_raise(Puppet::ParseError) do
- val = func.evaluate(:scope => scope)
+ val = func.evaluate(scope)
end
end
@@ -117,16 +117,16 @@ class TestLangFunctions < Test::Unit::TestCase
scope = mkscope
assert_raise(Puppet::ParseError) do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
scope.setvar("one", "One")
assert_raise(Puppet::ParseError) do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
scope.setvar("two", "Two")
assert_nothing_raised do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
assert_equal("template One\ntemplate Two\n", scope.lookupvar("output"),
@@ -155,13 +155,13 @@ class TestLangFunctions < Test::Unit::TestCase
scope = mkscope
assert_raise(Puppet::ParseError) do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
scope.setvar("yayness", "this is yayness")
assert_nothing_raised do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
assert_equal("template this is yayness\n", scope.lookupvar("output"),
@@ -191,7 +191,7 @@ class TestLangFunctions < Test::Unit::TestCase
scope = mkscope
scope.setvar("myvar", "this is yayness")
assert_raise(Puppet::ParseError) do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
end
@@ -264,14 +264,14 @@ class TestLangFunctions < Test::Unit::TestCase
}.each do |string, value|
scope = mkscope
assert_raise(Puppet::ParseError) do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
scope.setvar("yayness", string)
assert_equal(string, scope.lookupvar("yayness", false))
assert_nothing_raised("An empty string was not a valid variable value") do
- ast.evaluate(:scope => scope)
+ ast.evaluate(scope)
end
assert_equal("template #{value}\n", scope.lookupvar("output"),
@@ -308,7 +308,7 @@ class TestLangFunctions < Test::Unit::TestCase
def test_realize
scope = mkscope
- parser = scope.compile.parser
+ parser = scope.compiler.parser
# Make a definition
parser.newdefine("mytype")
@@ -318,7 +318,7 @@ class TestLangFunctions < Test::Unit::TestCase
virtual = mkresource(:type => type, :title => title,
:virtual => true, :params => {}, :scope => scope)
- scope.compile.store_resource(scope, virtual)
+ scope.compiler.add_resource(scope, virtual)
ref = Puppet::Parser::Resource::Reference.new(
:type => type, :title => title,
@@ -330,13 +330,13 @@ class TestLangFunctions < Test::Unit::TestCase
end
# Make sure it created a collection
- assert_equal(1, scope.compile.collections.length,
+ assert_equal(1, scope.compiler.collections.length,
"Did not set collection")
assert_nothing_raised do
- scope.compile.collections.each do |coll| coll.evaluate end
+ scope.compiler.collections.each do |coll| coll.evaluate end
end
- scope.compile.collections.clear
+ scope.compiler.collections.clear
# Now make sure the virtual resource is no longer virtual
assert(! virtual.virtual?, "Did not make virtual resource real")
@@ -354,17 +354,17 @@ class TestLangFunctions < Test::Unit::TestCase
end
# Make sure it created a collection
- assert_equal(1, scope.compile.collections.length,
+ assert_equal(1, scope.compiler.collections.length,
"Did not set collection")
# And the collection has our resource in it
- assert_equal([none.to_s], scope.compile.collections[0].resources,
+ assert_equal([none.to_s], scope.compiler.collections[0].resources,
"Did not set resources in collection")
end
def test_defined
scope = mkscope
- parser = scope.compile.parser
+ parser = scope.compiler.parser
parser.newclass("yayness")
parser.newdefine("rahness")
@@ -385,7 +385,7 @@ class TestLangFunctions < Test::Unit::TestCase
"Multiple falses were somehow true")
# Now make sure we can test resources
- scope.compile.store_resource(scope, mkresource(:type => "file", :title => "/tmp/rahness",
+ scope.compiler.add_resource(scope, mkresource(:type => "file", :title => "/tmp/rahness",
:scope => scope, :source => scope.source,
:params => {:owner => "root"}))
@@ -420,7 +420,7 @@ class TestLangFunctions < Test::Unit::TestCase
def test_include
scope = mkscope
- parser = scope.compile.parser
+ parser = scope.compiler.parser
assert_raise(Puppet::ParseError, "did not throw error on missing class") do
scope.function_include("nosuchclass")
@@ -428,7 +428,7 @@ class TestLangFunctions < Test::Unit::TestCase
parser.newclass("myclass")
- scope.compile.expects(:evaluate_classes).with(%w{myclass otherclass}, scope, false).returns(%w{myclass otherclass})
+ scope.compiler.expects(:evaluate_classes).with(%w{myclass otherclass}, scope, false).returns(%w{myclass otherclass})
assert_nothing_raised do
scope.function_include(["myclass", "otherclass"])
@@ -480,7 +480,7 @@ class TestLangFunctions < Test::Unit::TestCase
assert_equal("yay-foo\n", %x{#{command} foo}, "command did not work")
scope = mkscope
- parser = scope.compile.parser
+ parser = scope.compiler.parser
val = nil
assert_nothing_raised("Could not call generator with no args") do
diff --git a/test/language/lexer.rb b/test/language/lexer.rb
deleted file mode 100755
index e09828d51..000000000
--- a/test/language/lexer.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppet'
-require 'puppet/parser/lexer'
-require 'puppettest'
-
-#%q{service("telnet") = \{
-# port => "23",
-# protocol => "tcp",
-# name => "telnet",
-#\}
-#} => [[:NAME, "service"], [:LPAREN, "("], [:DQUOTE, "\""], [:NAME, "telnet"], [:DQUOTE, "\""], [:RPAREN, ")"], [:EQUALS, "="], [:lbrace, "{"], [:NAME, "port"], [:FARROW, "=>"], [:DQUOTE, "\""], [:NAME, "23"], [:DQUOTE, "\""], [:COMMA, ","], [:NAME, "protocol"], [:FARROW, "=>"], [:DQUOTE, "\""], [:NAME, "tcp"], [:DQUOTE, "\""], [:COMMA, ","], [:NAME, "name"], [:FARROW, "=>"], [:DQUOTE, "\""], [:NAME, "telnet"], [:DQUOTE, "\""], [:COMMA, ","], [:RBRACE, "}"]]
-
-class TestLexer < Test::Unit::TestCase
- include PuppetTest
- def setup
- super
- mklexer
- end
-
- def mklexer
- @lexer = Puppet::Parser::Lexer.new()
- end
-
- def test_simple_lex
- strings = {
-%q{\\} => [[:BACKSLASH,"\\"],[false,false]],
-%q{simplest scanner test} => [[:NAME,"simplest"],[:NAME,"scanner"],[:NAME,"test"],[false,false]],
-%q{returned scanner test
-} => [[:NAME,"returned"],[:NAME,"scanner"],[:NAME,"test"],[false,false]]
- }
- strings.each { |str,ary|
- @lexer.string = str
- assert_equal(
- ary,
- @lexer.fullscan()
- )
- }
- end
-
- def test_quoted_strings
- strings = {
-%q{a simple "scanner" test
-} => [[:NAME,"a"],[:NAME,"simple"],[:DQTEXT,"scanner"],[:NAME,"test"],[false,false]],
-%q{a simple 'single quote scanner' test
-} => [[:NAME,"a"],[:NAME,"simple"],[:SQTEXT,"single quote scanner"],[:NAME,"test"],[false,false]],
-%q{a harder 'a $b \c"'
-} => [[:NAME,"a"],[:NAME,"harder"],[:SQTEXT,'a $b \c"'],[false,false]],
-%q{a harder "scanner test"
-} => [[:NAME,"a"],[:NAME,"harder"],[:DQTEXT,"scanner test"],[false,false]],
-%q{a hardest "scanner \"test\""
-} => [[:NAME,"a"],[:NAME,"hardest"],[:DQTEXT,'scanner "test"'],[false,false]],
-%q{a hardestest "scanner \"test\"
-"
-} => [[:NAME,"a"],[:NAME,"hardestest"],[:DQTEXT,'scanner "test"
-'],[false,false]],
-%q{function("call")} => [[:NAME,"function"],[:LPAREN,"("],[:DQTEXT,'call'],[:RPAREN,")"],[false,false]]
-}
- strings.each { |str,array|
- @lexer.string = str
- assert_equal(
- array,
- @lexer.fullscan()
- )
- }
- end
-
- def test_errors
- strings = %w{
- ^
- }
- strings.each { |str|
- @lexer.string = str
- assert_raise(RuntimeError) {
- @lexer.fullscan()
- }
- }
- end
-
- def test_more_error
- assert_raise(TypeError) {
- @lexer.fullscan()
- }
- end
-
- def test_files
- textfiles() { |file|
- lexer = Puppet::Parser::Lexer.new()
- lexer.file = file
- assert_nothing_raised("Failed to lex %s" % file) {
- lexer.fullscan()
- }
- Puppet::Type.allclear
- }
- end
-
- def test_strings
- names = %w{this is a bunch of names}
- types = %w{Many Different Words A Word}
- words = %w{differently Cased words A a}
-
- names.each { |t|
- @lexer.string = t
- assert_equal(
- [[:NAME,t],[false,false]],
- @lexer.fullscan
- )
- }
- types.each { |t|
- @lexer.string = t
- assert_equal(
- [[:CLASSREF,t],[false,false]],
- @lexer.fullscan
- )
- }
- end
-
- def test_emptystring
- bit = '$var = ""'
-
- assert_nothing_raised {
- @lexer.string = bit
- }
-
- assert_nothing_raised {
- @lexer.fullscan
- }
- end
-
- def test_collectlexing
- {"@" => :AT, "<|" => :LCOLLECT, "|>" => :RCOLLECT}.each do |string, token|
- assert_nothing_raised {
- @lexer.string = string
- }
-
- ret = nil
- assert_nothing_raised {
- ret = @lexer.fullscan
- }
-
- assert_equal([[token, string],[false, false]], ret)
- end
- end
-
- def test_collectabletype
- string = "@type {"
-
- assert_nothing_raised {
- @lexer.string = string
- }
-
- ret = nil
- assert_nothing_raised {
- ret = @lexer.fullscan
- }
-
- assert_equal([[:AT, "@"], [:NAME, "type"], [:LBRACE, "{"], [false,false]],ret)
- end
-
- def test_namespace
- @lexer.string = %{class myclass}
-
- assert_nothing_raised {
- @lexer.fullscan
- }
-
- assert_equal("myclass", @lexer.namespace)
-
- assert_nothing_raised do
- @lexer.namepop
- end
-
- assert_equal("", @lexer.namespace)
-
- @lexer.string = "class base { class sub { class more"
-
- assert_nothing_raised {
- @lexer.fullscan
- }
-
- assert_equal("base::sub::more", @lexer.namespace)
-
- assert_nothing_raised do
- @lexer.namepop
- end
-
- assert_equal("base::sub", @lexer.namespace)
-
- # Now try it with some fq names
- mklexer
-
- @lexer.string = "class base { class sub::more {"
-
- assert_nothing_raised {
- @lexer.fullscan
- }
-
- assert_equal("base::sub::more", @lexer.namespace)
-
- assert_nothing_raised do
- @lexer.namepop
- end
-
- assert_equal("base", @lexer.namespace)
- end
-
- def test_indefine
- @lexer.string = %{define me}
-
- assert_nothing_raised {
- @lexer.scan { |t,s| }
- }
-
- assert(@lexer.indefine?, "Lexer not considered in define")
-
- # Now make sure we throw an error when trying to nest defines.
- assert_raise(Puppet::ParseError) do
- @lexer.string = %{define another}
- @lexer.scan { |t,s| }
- end
-
- assert_nothing_raised do
- @lexer.indefine = false
- end
-
- assert(! @lexer.indefine?, "Lexer still considered in define")
- end
-
- # Make sure the different qualified variables work.
- def test_variable
- ["$variable", "$::variable", "$qualified::variable", "$further::qualified::variable"].each do |string|
- @lexer.string = string
-
- assert_nothing_raised("Could not lex %s" % string) do
- @lexer.scan do |t, s|
- assert_equal(:VARIABLE, t, "did not get variable as token")
- assert_equal(string.sub(/^\$/, ''), s, "did not get correct string back")
- break
- end
- end
- end
- end
-
- # Make sure the expected stack works as it should
- def test_expected
- @lexer.string = "[a{"
- expected = @lexer.instance_variable_get("@expected")
- @lexer.scan {}
- assert_equal("}", @lexer.expected, "expected value is wrong")
-
- @lexer.string = "}"
- @lexer.scan {}
- assert_equal("]", @lexer.expected, "expected value is wrong after pop")
- end
-
- # #774
- def test_classref_token
- string = ["Foo", "::Foo","Foo::Bar","::Foo::Bar"]
-
- string.each do |foo|
- assert_nothing_raised {
- @lexer.string = foo
- }
-
- ret = nil
- assert_nothing_raised {
- ret = @lexer.fullscan
- }
-
- assert_equal([:CLASSREF, foo],ret[0], "Did not correctly tokenize '%s'" % foo)
- end
- end
-end
-
diff --git a/test/language/parser.rb b/test/language/parser.rb
index 1bbd894e4..2a0e9c02d 100755
--- a/test/language/parser.rb
+++ b/test/language/parser.rb
@@ -45,9 +45,9 @@ class TestParser < Test::Unit::TestCase
assert_raise(Puppet::ParseError, "Did not fail while parsing %s" % file) {
parser.file = file
ast = parser.parse
- config = mkcompile(parser)
+ config = mkcompiler(parser)
config.compile
- #ast.classes[""].evaluate :scope => config.topscope
+ #ast.classes[""].evaluate config.topscope
}
Puppet::Type.allclear
}
@@ -868,7 +868,7 @@ file { "/tmp/yayness":
def test_newclass
scope = mkscope
- parser = scope.compile.parser
+ parser = scope.compiler.parser
mkcode = proc do |ary|
classes = ary.collect do |string|
@@ -891,7 +891,7 @@ file { "/tmp/yayness":
assert(parser.classes["myclass"], "Could not find definition")
assert_equal("myclass", parser.classes["myclass"].classname)
assert_equal(%w{original code},
- parser.classes["myclass"].code.evaluate(:scope => scope))
+ parser.classes["myclass"].code.evaluate(scope))
# Newclass behaves differently than the others -- it just appends
# the code to the existing class.
@@ -901,7 +901,7 @@ file { "/tmp/yayness":
end
assert(klass, "Did not return class when appending")
assert_equal(%w{original code something new},
- parser.classes["myclass"].code.evaluate(:scope => scope))
+ parser.classes["myclass"].code.evaluate(scope))
# Now create the same class name in a different scope
assert_nothing_raised {
@@ -914,7 +914,7 @@ file { "/tmp/yayness":
assert_equal("other::myclass", other.classname)
assert_equal("other::myclass", other.namespace)
assert_equal(%w{something diff},
- other.code.evaluate(:scope => scope))
+ other.code.evaluate(scope))
# Make sure newclass deals correctly with nodes with no code
klass = parser.newclass("nocode")
@@ -925,7 +925,7 @@ file { "/tmp/yayness":
end
assert(klass, "Did not return class with no code")
assert_equal(%w{yay test},
- parser.classes["nocode"].code.evaluate(:scope => scope))
+ parser.classes["nocode"].code.evaluate(scope))
# Then try merging something into nothing
parser.newclass("nocode2", :code => mkcode.call(%w{foo test}))
@@ -936,7 +936,7 @@ file { "/tmp/yayness":
end
assert(klass, "Did not return class with no code")
assert_equal(%w{foo test},
- parser.classes["nocode2"].code.evaluate(:scope => scope))
+ parser.classes["nocode2"].code.evaluate(scope))
# And lastly, nothing and nothing
klass = parser.newclass("nocode3")
diff --git a/test/language/resource.rb b/test/language/resource.rb
index 84a30b029..608e7c995 100755
--- a/test/language/resource.rb
+++ b/test/language/resource.rb
@@ -106,7 +106,6 @@ class TestResource < PuppetTest::TestCase
def test_finish
res = mkresource
- res.expects(:add_overrides)
res.expects(:add_defaults)
res.expects(:add_metaparams)
res.expects(:validate)
@@ -266,48 +265,12 @@ class TestResource < PuppetTest::TestCase
ref.expects(:definedtype).returns(type)
res.expects(:finish)
res.scope = mock("scope")
- config = mock("config")
- res.scope.expects(:compile).returns(config)
- config.expects(:delete_resource).with(res)
- args = {:scope => res.scope, :resource => res}
- type.expects(:evaluate).with(args)
+ type.expects(:evaluate_code).with(res)
res.evaluate
end
- def test_add_overrides
- # Try it with nil
- res = mkresource
- res.scope = mock('scope')
- config = mock("config")
- res.scope.expects(:compile).returns(config)
- config.expects(:resource_overrides).with(res).returns(nil)
- res.expects(:merge).never
- res.send(:add_overrides)
-
- # And an empty array
- res = mkresource
- res.scope = mock('scope')
- config = mock("config")
- res.scope.expects(:compile).returns(config)
- config.expects(:resource_overrides).with(res).returns([])
- res.expects(:merge).never
- res.send(:add_overrides)
-
- # And with some overrides
- res = mkresource
- res.scope = mock('scope')
- config = mock("config")
- res.scope.expects(:compile).returns(config)
- returns = %w{a b}
- config.expects(:resource_overrides).with(res).returns(returns)
- res.expects(:merge).with("a")
- res.expects(:merge).with("b")
- res.send(:add_overrides)
- assert(returns.empty?, "Did not clear overrides")
- end
-
def test_proxymethods
res = Parser::Resource.new :type => "evaltest", :title => "yay",
:source => mock("source"), :scope => mkscope
@@ -378,7 +341,7 @@ class TestResource < PuppetTest::TestCase
{:name => "one", :title => "two"},
{:title => "three"},
].each do |hash|
- config = mkcompile parser
+ config = mkcompiler parser
args = {:type => "yayness", :title => hash[:title],
:source => klass, :scope => config.topscope}
if hash[:name]
@@ -425,7 +388,7 @@ class TestResource < PuppetTest::TestCase
:code => resourcedef("file", varref("name"),
"mode" => "644"))
- config = mkcompile(parser)
+ config = mkcompiler(parser)
res = mkresource :type => "yayness", :title => "foo", :params => {}, :scope => config.topscope
res.virtual = true
@@ -464,8 +427,8 @@ class TestResource < PuppetTest::TestCase
scope = stub 'scope', :resource => scope_resource
resource = Puppet::Parser::Resource.new(:type => "file", :title => "yay", :scope => scope, :source => mock('source'))
- # Make sure we get the scope resource's tags, plus the type and title
- %w{srone srtwo yay file}.each do |tag|
+ # Make sure we get the type and title
+ %w{yay file}.each do |tag|
assert(resource.tags.include?(tag), "Did not tag resource with %s" % tag)
end
diff --git a/test/language/scope.rb b/test/language/scope.rb
index ec11a864e..c96581a23 100755
--- a/test/language/scope.rb
+++ b/test/language/scope.rb
@@ -27,7 +27,7 @@ class TestScope < Test::Unit::TestCase
end
def test_variables
- config = mkcompile
+ config = mkcompiler
topscope = config.topscope
midscope = config.newscope(topscope)
botscope = config.newscope(midscope)
@@ -94,7 +94,7 @@ class TestScope < Test::Unit::TestCase
classes = ["", "one", "one::two", "one::two::three"].each do |name|
klass = parser.newclass(name)
Puppet::Parser::Resource.new(:type => "class", :title => name, :scope => scope, :source => mock('source')).evaluate
- scopes[name] = scope.compile.class_scope(klass)
+ scopes[name] = scope.compiler.class_scope(klass)
end
classes.each do |name|
@@ -125,7 +125,7 @@ class TestScope < Test::Unit::TestCase
end
def test_setdefaults
- config = mkcompile
+ config = mkcompiler
scope = config.topscope
@@ -151,7 +151,7 @@ class TestScope < Test::Unit::TestCase
end
def test_lookupdefaults
- config = mkcompile
+ config = mkcompiler
top = config.topscope
# Make a subscope
@@ -179,7 +179,7 @@ class TestScope < Test::Unit::TestCase
end
def test_parent
- config = mkcompile
+ config = mkcompiler
top = config.topscope
# Make a subscope
@@ -205,7 +205,7 @@ class TestScope < Test::Unit::TestCase
%w{one one::two one::two::three}.each do |name|
klass = parser.newclass(name)
Puppet::Parser::Resource.new(:type => "class", :title => name, :scope => scope, :source => mock('source')).evaluate
- scopes[name] = scope.compile.class_scope(klass)
+ scopes[name] = scope.compiler.class_scope(klass)
scopes[name].setvar("test", "value-%s" % name.sub(/.+::/,''))
end
@@ -284,13 +284,13 @@ class TestScope < Test::Unit::TestCase
)
assert_nothing_raised do
- function.evaluate :scope => scope
+ function.evaluate scope
end
- scope.compile.send(:evaluate_generators)
+ scope.compiler.send(:evaluate_generators)
[myclass, otherclass].each do |klass|
- assert(scope.compile.class_scope(klass),
+ assert(scope.compiler.class_scope(klass),
"%s was not set" % klass.classname)
end
end
@@ -328,18 +328,17 @@ class TestScope < Test::Unit::TestCase
"undef considered true")
end
- if defined? ActiveRecord
# Verify that we recursively mark as exported the results of collectable
# components.
- def test_exportedcomponents
- config = mkcompile
+ def test_virtual_definitions_do_not_get_evaluated
+ config = mkcompiler
parser = config.parser
# Create a default source
config.topscope.source = parser.newclass "", ""
# And a scope resource
- scope_res = stub 'scope_resource', :virtual? => true, :exported? => false, :tags => []
+ scope_res = stub 'scope_resource', :virtual? => true, :exported? => false, :tags => [], :builtin? => true, :type => "eh", :title => "bee"
config.topscope.resource = scope_res
args = AST::ASTArray.new(
@@ -348,7 +347,7 @@ class TestScope < Test::Unit::TestCase
:children => [nameobj("arg")]
)
- # Create a top-level component
+ # Create a top-level define
parser.newdefine "one", :arguments => [%w{arg}],
:code => AST::ASTArray.new(
:children => [
@@ -356,41 +355,26 @@ class TestScope < Test::Unit::TestCase
]
)
- # And a component that calls it
- parser.newdefine "two", :arguments => [%w{arg}],
- :code => AST::ASTArray.new(
- :children => [
- resourcedef("one", "ptest", {"arg" => varref("arg")})
- ]
- )
-
- # And then a third component that calls the second
- parser.newdefine "three", :arguments => [%w{arg}],
- :code => AST::ASTArray.new(
- :children => [
- resourcedef("two", "yay", {"arg" => varref("arg")})
- ]
- )
-
- # lastly, create an object that calls our third component
- obj = resourcedef("three", "boo", {"arg" => "parentfoo"})
+ # create a resource that calls our third define
+ obj = resourcedef("one", "boo", {"arg" => "parentfoo"})
- # And mark it as exported
- obj.exported = true
+ # And mark it as virtual
+ obj.virtual = true
# And then evaluate it
- obj.evaluate :scope => config.topscope
+ obj.evaluate config.topscope
# And run the loop.
config.send(:evaluate_generators)
%w{File}.each do |type|
- objects = config.resources.find_all { |r| r.type == type and r.exported }
+ objects = config.resources.find_all { |r| r.type == type and r.virtual }
- assert(!objects.empty?, "Did not get an exported %s" % type)
+ assert(objects.empty?, "Virtual define got evaluated")
end
end
+ if defined? ActiveRecord
# Verify that we can both store and collect an object in the same
# run, whether it's in the same scope as a collection or a different
# scope.
diff --git a/test/language/snippets.rb b/test/language/snippets.rb
index 2a4ba0220..982ddfec4 100755
--- a/test/language/snippets.rb
+++ b/test/language/snippets.rb
@@ -15,6 +15,8 @@ class TestSnippets < Test::Unit::TestCase
def setup
super
@file = Puppet::Type.type(:file)
+ Facter.stubs(:to_hash).returns({})
+ Facter.stubs(:value).returns("whatever")
end
def self.snippetdir
@@ -422,6 +424,11 @@ class TestSnippets < Test::Unit::TestCase
assert_file("/tmp/realize_defined_test2")
end
+ def snippet_collection_within_virtual_definitions
+ assert_file("/tmp/collection_within_virtual_definitions1_foo.txt")
+ assert_file("/tmp/collection_within_virtual_definitions2_foo2.txt")
+ end
+
def snippet_fqparents
assert_file("/tmp/fqparent1", "Did not make file from parent class")
assert_file("/tmp/fqparent2", "Did not make file from subclass")
diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb
index 36bb68a77..1a08ecbae 100644
--- a/test/lib/puppettest/parsertesting.rb
+++ b/test/lib/puppettest/parsertesting.rb
@@ -5,7 +5,7 @@ module PuppetTest::ParserTesting
include PuppetTest
AST = Puppet::Parser::AST
- Compile = Puppet::Parser::Compile
+ Compiler = Puppet::Parser::Compiler
# A fake class that we can use for testing evaluation.
class FakeAST
@@ -41,10 +41,10 @@ module PuppetTest::ParserTesting
)
end
- def mkcompile(parser = nil)
+ def mkcompiler(parser = nil)
parser ||= mkparser
node = mknode
- return Compile.new(node, parser)
+ return Compiler.new(node, parser)
end
def mknode(name = nil)
@@ -64,15 +64,15 @@ module PuppetTest::ParserTesting
def mkscope(hash = {})
hash[:parser] ||= mkparser
- compile ||= mkcompile(hash[:parser])
- compile.topscope.source = (hash[:parser].findclass("", "") || hash[:parser].newclass(""))
+ compiler ||= mkcompiler(hash[:parser])
+ compiler.topscope.source = (hash[:parser].findclass("", "") || hash[:parser].newclass(""))
- unless compile.topscope.source
+ unless compiler.topscope.source
raise "Could not find source for scope"
end
# Make the 'main' stuff
- compile.send(:evaluate_main)
- compile.topscope
+ compiler.send(:evaluate_main)
+ compiler.topscope
end
def classobj(name, hash = {})
diff --git a/test/lib/puppettest/support/resources.rb b/test/lib/puppettest/support/resources.rb
index 384f61c33..255c55569 100755
--- a/test/lib/puppettest/support/resources.rb
+++ b/test/lib/puppettest/support/resources.rb
@@ -18,7 +18,7 @@ module PuppetTest::Support::Resources
if resource.is_a?(String)
resource = tree_resource(resource)
end
- config.add_edge!(comp, resource)
+ config.add_edge(comp, resource)
config.add_resource resource unless config.resource(resource.ref)
end
return comp
diff --git a/test/other/transactions.rb b/test/other/transactions.rb
index 79971a28b..105698da1 100755
--- a/test/other/transactions.rb
+++ b/test/other/transactions.rb
@@ -348,12 +348,12 @@ class TestTransactions < Test::Unit::TestCase
fcomp = Puppet::Type.type(:component).create(:name => "file")
config.add_resource fcomp
config.add_resource file
- config.add_edge!(fcomp, file)
+ config.add_edge(fcomp, file)
ecomp = Puppet::Type.type(:component).create(:name => "exec")
config.add_resource ecomp
config.add_resource exec
- config.add_edge!(ecomp, exec)
+ config.add_edge(ecomp, exec)
# 'subscribe' expects an array of arrays
#component[:require] = [[file.class.name,file.name]]
@@ -828,10 +828,10 @@ class TestTransactions < Test::Unit::TestCase
c = trigger.new(:c)
nope = Puppet::Relationship.new(a, b)
yep = Puppet::Relationship.new(a, c, {:callback => :refresh})
- graph.add_edge!(nope)
+ graph.add_edge(nope)
# And a triggering one.
- graph.add_edge!(yep)
+ graph.add_edge(yep)
# Create our transaction
trans = Puppet::Transaction.new(graph)
diff --git a/test/ral/manager/type.rb b/test/ral/manager/type.rb
index 6a044687e..6c5587ddd 100755
--- a/test/ral/manager/type.rb
+++ b/test/ral/manager/type.rb
@@ -708,7 +708,7 @@ class TestType < Test::Unit::TestCase
res = type.create(hash)
config.add_resource res
if parent
- config.add_edge!(parent, res)
+ config.add_edge(parent, res)
end
res
end
@@ -741,7 +741,7 @@ class TestType < Test::Unit::TestCase
newcomp = Puppet::Type.newcomponent :type => "yay", :name => "Good[bad]"
config.add_resource newcomp
- config.add_edge! comp, newcomp
+ config.add_edge comp, newcomp
exec = mk.call(6, :parent => newcomp)
assert_equal("//Good[bad]/Exec[exec6]", exec.path)
end
diff --git a/test/ral/types/basic.rb b/test/ral/types/basic.rb
index 7bbadc5bc..3c5faeee0 100755
--- a/test/ral/types/basic.rb
+++ b/test/ral/types/basic.rb
@@ -36,8 +36,8 @@ class TestBasic < Test::Unit::TestCase
)
}
@config = mk_catalog(@component, @configfile, @command)
- @config.add_edge! @component, @configfile
- @config.add_edge! @component, @command
+ @config.add_edge @component, @configfile
+ @config.add_edge @component, @command
end
def teardown
diff --git a/test/ral/types/exec.rb b/test/ral/types/exec.rb
index f718f944e..4133d8519 100755
--- a/test/ral/types/exec.rb
+++ b/test/ral/types/exec.rb
@@ -587,6 +587,46 @@ and stuff"
assert_equal("A B\n", output)
end
+ def test_environmentparam
+ exec = Puppet::Type.newexec(
+ :command => "echo $environmenttest",
+ :path => ENV["PATH"],
+ :environment => "environmenttest=yayness"
+ )
+
+ assert(exec, "Could not make exec")
+
+ output = status = nil
+ assert_nothing_raised {
+ output, status = exec.run("echo $environmenttest")
+ }
+
+ assert_equal("yayness\n", output)
+
+ # Now check whether we can do multiline settings
+ assert_nothing_raised do
+ exec[:environment] = "environmenttest=a list of things
+and stuff"
+ end
+
+ output = status = nil
+ assert_nothing_raised {
+ output, status = exec.run('echo "$environmenttest"')
+ }
+ assert_equal("a list of things\nand stuff\n", output)
+
+ # Now test arrays
+ assert_nothing_raised do
+ exec[:environment] = ["funtest=A", "yaytest=B"]
+ end
+
+ output = status = nil
+ assert_nothing_raised {
+ output, status = exec.run('echo "$funtest" "$yaytest"')
+ }
+ assert_equal("A B\n", output)
+ end
+
def test_timeout
exec = Puppet::Type.type(:exec).create(:command => "sleep 1", :path => ENV["PATH"], :timeout => "0.2")
time = Time.now
diff --git a/test/ral/types/host.rb b/test/ral/types/host.rb
index 088f93c1f..a5d645bd1 100755
--- a/test/ral/types/host.rb
+++ b/test/ral/types/host.rb
@@ -138,8 +138,24 @@ class TestHost < Test::Unit::TestCase
host[:ensure] = :absent
assert_events([:host_removed], host)
end
+
+ def test_invalid_ipaddress
+ host = mkhost()
+
+ assert_raise(Puppet::Error) {
+ host[:ip] = "abc.def.ghi.jkl"
+ }
+ end
+
+ def test_invalid_hostname
+ host = mkhost()
+
+ assert_raise(Puppet::Error) {
+ host[:name] = "!invalid.hostname.$$$"
+ }
end
+ end
def test_aliasisproperty
assert_equal(:property, @hosttype.attrtype(:alias))
end