puppet 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CHANGELOG +0 -0
- data/COPYING +340 -0
- data/LICENSE +17 -0
- data/README +24 -0
- data/Rakefile +294 -0
- data/TODO +4 -0
- data/bin/cf2puppet +186 -0
- data/bin/puppet +176 -0
- data/bin/puppetca +213 -0
- data/bin/puppetd +246 -0
- data/bin/puppetdoc +184 -0
- data/bin/puppetmasterd +258 -0
- data/examples/code/allatonce +13 -0
- data/examples/code/assignments +11 -0
- data/examples/code/classing +35 -0
- data/examples/code/components +73 -0
- data/examples/code/execs +16 -0
- data/examples/code/failers/badclassnoparam +10 -0
- data/examples/code/failers/badclassparam +10 -0
- data/examples/code/failers/badcompnoparam +9 -0
- data/examples/code/failers/badcompparam +9 -0
- data/examples/code/failers/badtypeparam +3 -0
- data/examples/code/file.bl +11 -0
- data/examples/code/filedefaults +10 -0
- data/examples/code/fileparsing +116 -0
- data/examples/code/filerecursion +15 -0
- data/examples/code/functions +3 -0
- data/examples/code/groups +7 -0
- data/examples/code/head +30 -0
- data/examples/code/importing +8 -0
- data/examples/code/nodes +20 -0
- data/examples/code/one +8 -0
- data/examples/code/relationships +34 -0
- data/examples/code/selectors +28 -0
- data/examples/code/simpletests +11 -0
- data/examples/code/snippets/argumentdefaults +14 -0
- data/examples/code/snippets/casestatement +39 -0
- data/examples/code/snippets/classheirarchy.pp +15 -0
- data/examples/code/snippets/classincludes.pp +17 -0
- data/examples/code/snippets/classpathtest +11 -0
- data/examples/code/snippets/dirchmod +19 -0
- data/examples/code/snippets/failmissingexecpath.pp +13 -0
- data/examples/code/snippets/falsevalues.pp +3 -0
- data/examples/code/snippets/filecreate +11 -0
- data/examples/code/snippets/implicititeration +15 -0
- data/examples/code/snippets/multipleinstances +7 -0
- data/examples/code/snippets/namevartest +9 -0
- data/examples/code/snippets/scopetest +13 -0
- data/examples/code/snippets/selectorvalues.pp +22 -0
- data/examples/code/snippets/simpledefaults +5 -0
- data/examples/code/snippets/simpleselector +38 -0
- data/examples/code/svncommit +13 -0
- data/examples/root/bin/sleeper +69 -0
- data/examples/root/etc/configfile +0 -0
- data/examples/root/etc/debian-passwd +29 -0
- data/examples/root/etc/debian-syslog.conf +71 -0
- data/examples/root/etc/init.d/sleeper +65 -0
- data/examples/root/etc/otherfile +0 -0
- data/examples/root/etc/puppet/fileserver.conf +3 -0
- data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
- data/ext/module:puppet +195 -0
- data/install.rb +270 -0
- data/lib/puppet.rb +249 -0
- data/lib/puppet/base64.rb +19 -0
- data/lib/puppet/client.rb +519 -0
- data/lib/puppet/config.rb +49 -0
- data/lib/puppet/daemon.rb +208 -0
- data/lib/puppet/element.rb +71 -0
- data/lib/puppet/event.rb +259 -0
- data/lib/puppet/log.rb +321 -0
- data/lib/puppet/metric.rb +250 -0
- data/lib/puppet/parsedfile.rb +38 -0
- data/lib/puppet/parser/ast.rb +1560 -0
- data/lib/puppet/parser/interpreter.rb +150 -0
- data/lib/puppet/parser/lexer.rb +226 -0
- data/lib/puppet/parser/parser.rb +1354 -0
- data/lib/puppet/parser/scope.rb +755 -0
- data/lib/puppet/server.rb +170 -0
- data/lib/puppet/server/authstore.rb +227 -0
- data/lib/puppet/server/ca.rb +140 -0
- data/lib/puppet/server/filebucket.rb +147 -0
- data/lib/puppet/server/fileserver.rb +477 -0
- data/lib/puppet/server/logger.rb +43 -0
- data/lib/puppet/server/master.rb +103 -0
- data/lib/puppet/server/servlet.rb +247 -0
- data/lib/puppet/sslcertificates.rb +737 -0
- data/lib/puppet/statechange.rb +150 -0
- data/lib/puppet/storage.rb +95 -0
- data/lib/puppet/transaction.rb +179 -0
- data/lib/puppet/transportable.rb +151 -0
- data/lib/puppet/type.rb +1354 -0
- data/lib/puppet/type/component.rb +141 -0
- data/lib/puppet/type/cron.rb +543 -0
- data/lib/puppet/type/exec.rb +316 -0
- data/lib/puppet/type/group.rb +152 -0
- data/lib/puppet/type/nameservice.rb +3 -0
- data/lib/puppet/type/nameservice/netinfo.rb +173 -0
- data/lib/puppet/type/nameservice/objectadd.rb +146 -0
- data/lib/puppet/type/nameservice/posix.rb +200 -0
- data/lib/puppet/type/package.rb +420 -0
- data/lib/puppet/type/package/apt.rb +70 -0
- data/lib/puppet/type/package/dpkg.rb +108 -0
- data/lib/puppet/type/package/rpm.rb +81 -0
- data/lib/puppet/type/package/sun.rb +117 -0
- data/lib/puppet/type/package/yum.rb +58 -0
- data/lib/puppet/type/pfile.rb +569 -0
- data/lib/puppet/type/pfile/checksum.rb +219 -0
- data/lib/puppet/type/pfile/create.rb +108 -0
- data/lib/puppet/type/pfile/group.rb +129 -0
- data/lib/puppet/type/pfile/mode.rb +131 -0
- data/lib/puppet/type/pfile/source.rb +264 -0
- data/lib/puppet/type/pfile/type.rb +31 -0
- data/lib/puppet/type/pfile/uid.rb +166 -0
- data/lib/puppet/type/pfilebucket.rb +80 -0
- data/lib/puppet/type/pprocess.rb +97 -0
- data/lib/puppet/type/service.rb +347 -0
- data/lib/puppet/type/service/base.rb +17 -0
- data/lib/puppet/type/service/debian.rb +50 -0
- data/lib/puppet/type/service/init.rb +145 -0
- data/lib/puppet/type/service/smf.rb +29 -0
- data/lib/puppet/type/state.rb +182 -0
- data/lib/puppet/type/symlink.rb +183 -0
- data/lib/puppet/type/tidy.rb +183 -0
- data/lib/puppet/type/typegen.rb +149 -0
- data/lib/puppet/type/typegen/filerecord.rb +243 -0
- data/lib/puppet/type/typegen/filetype.rb +316 -0
- data/lib/puppet/type/user.rb +290 -0
- data/lib/puppet/util.rb +138 -0
- data/test/certmgr/certmgr.rb +265 -0
- data/test/client/client.rb +203 -0
- data/test/executables/puppetbin.rb +53 -0
- data/test/executables/puppetca.rb +79 -0
- data/test/executables/puppetd.rb +71 -0
- data/test/executables/puppetmasterd.rb +153 -0
- data/test/executables/puppetmodule.rb +60 -0
- data/test/language/ast.rb +412 -0
- data/test/language/interpreter.rb +71 -0
- data/test/language/scope.rb +412 -0
- data/test/language/snippets.rb +445 -0
- data/test/other/events.rb +111 -0
- data/test/other/log.rb +195 -0
- data/test/other/metrics.rb +92 -0
- data/test/other/overrides.rb +115 -0
- data/test/other/parsedfile.rb +31 -0
- data/test/other/relationships.rb +113 -0
- data/test/other/state.rb +106 -0
- data/test/other/storage.rb +39 -0
- data/test/other/transactions.rb +235 -0
- data/test/parser/lexer.rb +120 -0
- data/test/parser/parser.rb +180 -0
- data/test/puppet/conffiles.rb +104 -0
- data/test/puppet/defaults.rb +100 -0
- data/test/puppet/error.rb +23 -0
- data/test/puppet/utiltest.rb +120 -0
- data/test/puppettest.rb +774 -0
- data/test/server/authstore.rb +209 -0
- data/test/server/bucket.rb +227 -0
- data/test/server/ca.rb +201 -0
- data/test/server/fileserver.rb +710 -0
- data/test/server/logger.rb +175 -0
- data/test/server/master.rb +150 -0
- data/test/server/server.rb +130 -0
- data/test/tagging/tagging.rb +80 -0
- data/test/test +51 -0
- data/test/types/basic.rb +119 -0
- data/test/types/component.rb +272 -0
- data/test/types/cron.rb +261 -0
- data/test/types/exec.rb +273 -0
- data/test/types/file.rb +616 -0
- data/test/types/filebucket.rb +167 -0
- data/test/types/fileignoresource.rb +287 -0
- data/test/types/filesources.rb +587 -0
- data/test/types/filetype.rb +162 -0
- data/test/types/group.rb +271 -0
- data/test/types/package.rb +205 -0
- data/test/types/query.rb +101 -0
- data/test/types/service.rb +100 -0
- data/test/types/symlink.rb +93 -0
- data/test/types/tidy.rb +124 -0
- data/test/types/type.rb +135 -0
- data/test/types/user.rb +371 -0
- metadata +243 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# A simple class that tells us when a file has changed and thus whether we
|
2
|
+
# should reload it
|
3
|
+
|
4
|
+
require 'puppet'
|
5
|
+
|
6
|
+
module Puppet
|
7
|
+
class ParsedFile
|
8
|
+
attr_reader :file
|
9
|
+
|
10
|
+
# Determine whether the file has changed and thus whether it should
|
11
|
+
# be reparsed
|
12
|
+
def changed?
|
13
|
+
tmp = self.stamp
|
14
|
+
retval = false
|
15
|
+
if tmp != @stamp
|
16
|
+
retval = true
|
17
|
+
@stamp = tmp
|
18
|
+
end
|
19
|
+
@statted = Time.now
|
20
|
+
|
21
|
+
return retval
|
22
|
+
end
|
23
|
+
|
24
|
+
# Create the file. Must be passed the file path.
|
25
|
+
def initialize(file)
|
26
|
+
@file = file
|
27
|
+
unless FileTest.exists?(@file)
|
28
|
+
raise Puppet::DevError, "Can not use a non-existent file for parsing"
|
29
|
+
end
|
30
|
+
@stamp = self.stamp
|
31
|
+
@statted = Time.now
|
32
|
+
end
|
33
|
+
|
34
|
+
def stamp
|
35
|
+
File.stat(@file).ctime
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,1560 @@
|
|
1
|
+
# the parent class for all of our syntactical objects
|
2
|
+
|
3
|
+
require 'puppet'
|
4
|
+
|
5
|
+
module Puppet
|
6
|
+
module Parser
|
7
|
+
|
8
|
+
# The base class for all of the objects that make up the parse trees.
|
9
|
+
# Handles things like file name, line #, and also does the initialization
|
10
|
+
# for all of the parameters of all of the child objects.
|
11
|
+
class AST
|
12
|
+
Puppet.setdefault(:typecheck, true)
|
13
|
+
Puppet.setdefault(:paramcheck, true)
|
14
|
+
attr_accessor :line, :file, :parent
|
15
|
+
|
16
|
+
# Just used for 'tree', which is only used in debugging.
|
17
|
+
@@pink = "[0;31m"
|
18
|
+
@@green = "[0;32m"
|
19
|
+
@@yellow = "[0;33m"
|
20
|
+
@@slate = "[0;34m"
|
21
|
+
@@reset = "[0m"
|
22
|
+
|
23
|
+
# Just used for 'tree', which is only used in debugging.
|
24
|
+
@@indent = " " * 4
|
25
|
+
@@indline = @@pink + ("-" * 4) + @@reset
|
26
|
+
@@midline = @@slate + ("-" * 4) + @@reset
|
27
|
+
|
28
|
+
@@settypes = {}
|
29
|
+
|
30
|
+
# Just used for 'tree', which is only used in debugging.
|
31
|
+
def AST.indention
|
32
|
+
return @@indent * @@indention
|
33
|
+
end
|
34
|
+
|
35
|
+
# Just used for 'tree', which is only used in debugging.
|
36
|
+
def AST.midline
|
37
|
+
return @@midline
|
38
|
+
end
|
39
|
+
|
40
|
+
# Evaluate the current object. Basically just iterates across all
|
41
|
+
# of the contained children and evaluates them in turn, returning a
|
42
|
+
# list of all of the collected values, rejecting nil values
|
43
|
+
def evaluate(scope)
|
44
|
+
#Puppet.debug("Evaluating ast %s" % @name)
|
45
|
+
value = self.collect { |obj|
|
46
|
+
obj.safeevaluate(scope)
|
47
|
+
}.reject { |obj|
|
48
|
+
obj.nil?
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# The version of the evaluate method that should be called, because it
|
53
|
+
# correctly handles errors. It is critical to use this method because
|
54
|
+
# it can enable you to catch the error where it happens, rather than
|
55
|
+
# much higher up the stack.
|
56
|
+
def safeevaluate(*args)
|
57
|
+
begin
|
58
|
+
self.evaluate(*args)
|
59
|
+
rescue Puppet::DevError
|
60
|
+
raise
|
61
|
+
rescue Puppet::ParseError
|
62
|
+
raise
|
63
|
+
rescue => detail
|
64
|
+
if Puppet[:debug]
|
65
|
+
puts caller
|
66
|
+
end
|
67
|
+
error = Puppet::DevError.new(
|
68
|
+
"Child of type %s failed with error %s: %s" %
|
69
|
+
[self.class, detail.class, detail.to_s]
|
70
|
+
)
|
71
|
+
error.stack = caller
|
72
|
+
raise error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Again, just used for printing out the parse tree.
|
77
|
+
def typewrap(string)
|
78
|
+
#return self.class.to_s.sub(/.+::/,'') +
|
79
|
+
#"(" + @@green + string.to_s + @@reset + ")"
|
80
|
+
return @@green + string.to_s + @@reset +
|
81
|
+
"(" + self.class.to_s.sub(/.+::/,'') + ")"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Initialize the object. Requires a hash as the argument, and takes
|
85
|
+
# each of the parameters of the hash and calls the settor method for
|
86
|
+
# them. This is probably pretty inefficient and should likely be changed
|
87
|
+
# at some point.
|
88
|
+
def initialize(args)
|
89
|
+
@file = nil
|
90
|
+
@line = nil
|
91
|
+
args.each { |param,value|
|
92
|
+
method = param.to_s + "="
|
93
|
+
unless self.respond_to?(method)
|
94
|
+
error = Puppet::DevError.new(
|
95
|
+
"Invalid parameter %s to object class %s" %
|
96
|
+
[param,self.class.to_s]
|
97
|
+
)
|
98
|
+
error.line = self.line
|
99
|
+
error.file = self.file
|
100
|
+
error.stack = caller
|
101
|
+
raise error
|
102
|
+
end
|
103
|
+
|
104
|
+
begin
|
105
|
+
#Puppet.debug("sending %s to %s" % [method, self.class])
|
106
|
+
self.send(method,value)
|
107
|
+
rescue => detail
|
108
|
+
error = Puppet::DevError.new(
|
109
|
+
"Could not set parameter %s on class %s: %s" %
|
110
|
+
[method,self.class.to_s,detail]
|
111
|
+
)
|
112
|
+
error.stack = caller
|
113
|
+
raise error
|
114
|
+
end
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
# The parent class of all AST objects that contain other AST objects.
|
119
|
+
# Everything but the really simple objects descend from this. It is
|
120
|
+
# important to note that Branch objects contain other AST objects only --
|
121
|
+
# if you want to contain values, use a descendent of the AST::Leaf class.
|
122
|
+
class Branch < AST
|
123
|
+
include Enumerable
|
124
|
+
attr_accessor :pin, :children
|
125
|
+
|
126
|
+
# Yield each contained AST node in turn. Used mostly by 'evaluate'.
|
127
|
+
# This definition means that I don't have to override 'evaluate'
|
128
|
+
# every time, but each child of Branch will likely need to override
|
129
|
+
# this method.
|
130
|
+
def each
|
131
|
+
@children.each { |child|
|
132
|
+
yield child
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
# Initialize our object. Largely relies on the method from the base
|
137
|
+
# class, but also does some verification.
|
138
|
+
def initialize(arghash)
|
139
|
+
super(arghash)
|
140
|
+
|
141
|
+
# Create the hash, if it was not set at initialization time.
|
142
|
+
unless defined? @children
|
143
|
+
@children = []
|
144
|
+
end
|
145
|
+
|
146
|
+
# Verify that we only got valid AST nodes.
|
147
|
+
@children.each { |child|
|
148
|
+
unless child.is_a?(AST)
|
149
|
+
raise Puppet::DevError,
|
150
|
+
"child %s is not an ast" % child
|
151
|
+
end
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
# Pretty-print the parse tree.
|
156
|
+
def tree(indent = 0)
|
157
|
+
return ((@@indline * indent) +
|
158
|
+
self.typewrap(self.pin)) + "\n" + self.collect { |child|
|
159
|
+
child.tree(indent + 1)
|
160
|
+
}.join("\n")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# The basic container class. This object behaves almost identically
|
165
|
+
# to a normal array except at initialization time. Note that its name
|
166
|
+
# is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many
|
167
|
+
# bugs when it was just 'AST::Array', because things like
|
168
|
+
# 'object.is_a?(Array)' never behaved as I expected.
|
169
|
+
class ASTArray < AST::Branch
|
170
|
+
include Enumerable
|
171
|
+
|
172
|
+
# Return a child by index. Probably never used.
|
173
|
+
def [](index)
|
174
|
+
@children[index]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Evaluate our children.
|
178
|
+
def evaluate(scope)
|
179
|
+
rets = nil
|
180
|
+
# We basically always operate declaratively, and when we
|
181
|
+
# do we need to evaluate the settor-like statements first. This
|
182
|
+
# is basically variable and type-default declarations.
|
183
|
+
if scope.declarative?
|
184
|
+
test = [
|
185
|
+
AST::VarDef, AST::TypeDefaults
|
186
|
+
]
|
187
|
+
|
188
|
+
settors = []
|
189
|
+
others = []
|
190
|
+
@children.each { |child|
|
191
|
+
if test.include?(child.class)
|
192
|
+
settors.push child
|
193
|
+
else
|
194
|
+
others.push child
|
195
|
+
end
|
196
|
+
}
|
197
|
+
rets = [settors,others].flatten.collect { |child|
|
198
|
+
child.safeevaluate(scope)
|
199
|
+
}
|
200
|
+
else
|
201
|
+
# If we're not declarative, just do everything in order.
|
202
|
+
rets = @children.collect { |item|
|
203
|
+
item.safeevaluate(scope)
|
204
|
+
}
|
205
|
+
end
|
206
|
+
rets = rets.reject { |obj| obj.nil? }
|
207
|
+
end
|
208
|
+
|
209
|
+
def push(*ary)
|
210
|
+
ary.each { |child|
|
211
|
+
#Puppet.debug "adding %s(%s) of type %s to %s" %
|
212
|
+
# [child, child.object_id, child.class.to_s.sub(/.+::/,''),
|
213
|
+
# self.object_id]
|
214
|
+
@children.push(child)
|
215
|
+
}
|
216
|
+
|
217
|
+
return self
|
218
|
+
end
|
219
|
+
|
220
|
+
# Convert to a string. Only used for printing the parse tree.
|
221
|
+
def to_s
|
222
|
+
return "[" + @children.collect { |child|
|
223
|
+
child.to_s
|
224
|
+
}.join(", ") + "]"
|
225
|
+
end
|
226
|
+
|
227
|
+
# Print the parse tree.
|
228
|
+
def tree(indent = 0)
|
229
|
+
#puts((AST.indent * indent) + self.pin)
|
230
|
+
self.collect { |child|
|
231
|
+
child.tree(indent)
|
232
|
+
}.join("\n" + (AST.midline * (indent+1)) + "\n")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# A simple container class, containing the parameters for an object.
|
237
|
+
# Used for abstracting the grammar declarations. Basically unnecessary
|
238
|
+
# except that I kept finding bugs because I had too many arrays that
|
239
|
+
# meant completely different things.
|
240
|
+
class ObjectInst < ASTArray; end
|
241
|
+
|
242
|
+
# Another simple container class to make sure we can correctly arrayfy
|
243
|
+
# things.
|
244
|
+
class CompArgument < ASTArray; end
|
245
|
+
|
246
|
+
# The base class for all of the leaves of the parse trees. These
|
247
|
+
# basically just have types and values. Both of these parameters
|
248
|
+
# are simple values, not AST objects.
|
249
|
+
class Leaf < AST
|
250
|
+
attr_accessor :value, :type
|
251
|
+
|
252
|
+
# Return our value.
|
253
|
+
def evaluate(scope)
|
254
|
+
return @value
|
255
|
+
end
|
256
|
+
|
257
|
+
# Print the value in parse tree context.
|
258
|
+
def tree(indent = 0)
|
259
|
+
return ((@@indent * indent) + self.typewrap(self.value))
|
260
|
+
end
|
261
|
+
|
262
|
+
def to_s
|
263
|
+
return @value
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# The boolean class. True or false. Converts the string it receives
|
268
|
+
# to a Ruby boolean.
|
269
|
+
class Boolean < AST::Leaf
|
270
|
+
|
271
|
+
# Use the parent method, but then convert to a real boolean.
|
272
|
+
def initialize(hash)
|
273
|
+
super
|
274
|
+
|
275
|
+
unless @value == 'true' or @value == 'false'
|
276
|
+
error = Puppet::DevError.new(
|
277
|
+
"'%s' is not a boolean" % @value
|
278
|
+
)
|
279
|
+
error.stack = caller
|
280
|
+
raise error
|
281
|
+
end
|
282
|
+
if @value == 'true'
|
283
|
+
@value = true
|
284
|
+
else
|
285
|
+
@value = false
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# The base string class.
|
291
|
+
class String < AST::Leaf
|
292
|
+
# Interpolate the string looking for variables, and then return
|
293
|
+
# the result.
|
294
|
+
def evaluate(scope)
|
295
|
+
return scope.strinterp(@value)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
#---------------------------------------------------------------
|
299
|
+
|
300
|
+
# The 'default' option on case statements and selectors.
|
301
|
+
class Default < AST::Leaf; end
|
302
|
+
|
303
|
+
# Capitalized words; used mostly for type-defaults, but also
|
304
|
+
# get returned by the lexer any other time an unquoted capitalized
|
305
|
+
# word is found.
|
306
|
+
class Type < AST::Leaf; end
|
307
|
+
|
308
|
+
# Lower-case words.
|
309
|
+
class Name < AST::Leaf; end
|
310
|
+
|
311
|
+
# A simple variable. This object is only used during interpolation;
|
312
|
+
# the VarDef class is used for assignment.
|
313
|
+
class Variable < Name
|
314
|
+
# Looks up the value of the object in the scope tree (does
|
315
|
+
# not include syntactical constructs, like '$' and '{}').
|
316
|
+
def evaluate(scope)
|
317
|
+
begin
|
318
|
+
return scope.lookupvar(@value)
|
319
|
+
rescue Puppet::ParseError => except
|
320
|
+
except.line = self.line
|
321
|
+
except.file = self.file
|
322
|
+
raise except
|
323
|
+
rescue => detail
|
324
|
+
error = Puppet::DevError.new(detail)
|
325
|
+
error.line = self.line
|
326
|
+
error.file = self.file
|
327
|
+
error.stack = caller
|
328
|
+
raise error
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Any normal puppet object declaration. Can result in a class or a
|
334
|
+
# component, in addition to builtin types.
|
335
|
+
class ObjectDef < AST::Branch
|
336
|
+
attr_accessor :name, :type
|
337
|
+
attr_reader :params
|
338
|
+
|
339
|
+
# probably not used at all
|
340
|
+
def []=(index,obj)
|
341
|
+
@params[index] = obj
|
342
|
+
end
|
343
|
+
|
344
|
+
# probably not used at all
|
345
|
+
def [](index)
|
346
|
+
return @params[index]
|
347
|
+
end
|
348
|
+
|
349
|
+
# Auto-generate a name
|
350
|
+
def autoname(type, object)
|
351
|
+
case object
|
352
|
+
when Puppet::Type:
|
353
|
+
raise Puppet::Error,
|
354
|
+
"Built-in types must be provided with a name"
|
355
|
+
when HostClass:
|
356
|
+
return type
|
357
|
+
else
|
358
|
+
Puppet.info "Autogenerating name for object of type %s" %
|
359
|
+
type
|
360
|
+
return [type, "-", self.object_id].join("")
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# Iterate across all of our children.
|
365
|
+
def each
|
366
|
+
[@type,@name,@params].flatten.each { |param|
|
367
|
+
#Puppet.debug("yielding param %s" % param)
|
368
|
+
yield param
|
369
|
+
}
|
370
|
+
end
|
371
|
+
|
372
|
+
# Does not actually return an object; instead sets an object
|
373
|
+
# in the current scope.
|
374
|
+
def evaluate(scope)
|
375
|
+
hash = {}
|
376
|
+
|
377
|
+
# Get our type and name.
|
378
|
+
objtype = @type.safeevaluate(scope)
|
379
|
+
|
380
|
+
# If the type was a variable, we wouldn't have typechecked yet.
|
381
|
+
# Do it now, if so.
|
382
|
+
unless @checked
|
383
|
+
self.typecheck(objtype)
|
384
|
+
end
|
385
|
+
|
386
|
+
# See if our object was defined
|
387
|
+
begin
|
388
|
+
object = scope.lookuptype(objtype)
|
389
|
+
rescue Puppet::ParseError => except
|
390
|
+
except.line = self.line
|
391
|
+
except.file = self.file
|
392
|
+
raise except
|
393
|
+
rescue => detail
|
394
|
+
error = Puppet::ParseError.new(detail)
|
395
|
+
error.line = self.line
|
396
|
+
error.file = self.file
|
397
|
+
error.stack = caller
|
398
|
+
raise error
|
399
|
+
end
|
400
|
+
|
401
|
+
unless object
|
402
|
+
# If not, verify that it's a builtin type
|
403
|
+
begin
|
404
|
+
object = Puppet::Type.type(objtype)
|
405
|
+
rescue TypeError
|
406
|
+
# otherwise, the user specified an invalid type
|
407
|
+
error = Puppet::ParseError.new(
|
408
|
+
"Invalid type %s" % objtype
|
409
|
+
)
|
410
|
+
error.line = @line
|
411
|
+
error.file = @file
|
412
|
+
raise error
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Autogenerate the name if one was not passed.
|
417
|
+
if defined? @name
|
418
|
+
objnames = @name.safeevaluate(scope)
|
419
|
+
else
|
420
|
+
objnames = self.autoname(objtype, object)
|
421
|
+
end
|
422
|
+
|
423
|
+
# it's easier to always use an array, even for only one name
|
424
|
+
unless objnames.is_a?(Array)
|
425
|
+
objnames = [objnames]
|
426
|
+
end
|
427
|
+
|
428
|
+
# Retrieve the defaults for our type
|
429
|
+
hash = getdefaults(objtype, scope)
|
430
|
+
|
431
|
+
# then set all of the specified params
|
432
|
+
@params.each { |param|
|
433
|
+
ary = param.safeevaluate(scope)
|
434
|
+
hash[ary[0]] = ary[1]
|
435
|
+
}
|
436
|
+
|
437
|
+
# this is where our implicit iteration takes place;
|
438
|
+
# if someone passed an array as the name, then we act
|
439
|
+
# just like the called us many times
|
440
|
+
objnames.collect { |objname|
|
441
|
+
# If the object is a class, that means it's a builtin type
|
442
|
+
if object.is_a?(Class)
|
443
|
+
begin
|
444
|
+
Puppet.debug(
|
445
|
+
("Setting object '%s' " +
|
446
|
+
"in scope %s " +
|
447
|
+
"with arguments %s") %
|
448
|
+
[objname, scope.object_id, hash.inspect]
|
449
|
+
)
|
450
|
+
obj = scope.setobject(
|
451
|
+
objtype,
|
452
|
+
objname,
|
453
|
+
hash,
|
454
|
+
@file,
|
455
|
+
@line
|
456
|
+
)
|
457
|
+
rescue Puppet::ParseError => except
|
458
|
+
except.line = self.line
|
459
|
+
except.file = self.file
|
460
|
+
raise except
|
461
|
+
rescue => detail
|
462
|
+
error = Puppet::ParseError.new(detail)
|
463
|
+
error.line = self.line
|
464
|
+
error.file = self.file
|
465
|
+
error.stack = caller
|
466
|
+
raise error
|
467
|
+
end
|
468
|
+
else
|
469
|
+
# but things like components create a new type; if we find
|
470
|
+
# one of those, evaluate that with our arguments
|
471
|
+
Puppet.debug("Calling object '%s' with arguments %s" %
|
472
|
+
[object.name, hash.inspect])
|
473
|
+
object.safeevaluate(scope,hash,objtype,objname)
|
474
|
+
end
|
475
|
+
}.reject { |obj| obj.nil? }
|
476
|
+
end
|
477
|
+
|
478
|
+
# Retrieve the defaults for our type
|
479
|
+
def getdefaults(objtype, scope)
|
480
|
+
# first, retrieve the defaults
|
481
|
+
begin
|
482
|
+
defaults = scope.lookupdefaults(objtype)
|
483
|
+
if defaults.length > 0
|
484
|
+
Puppet.debug "Got defaults for %s: %s" %
|
485
|
+
[objtype,defaults.inspect]
|
486
|
+
end
|
487
|
+
rescue => detail
|
488
|
+
raise Puppet::DevError,
|
489
|
+
"Could not lookup defaults for %s: %s" %
|
490
|
+
[objtype, detail.to_s]
|
491
|
+
end
|
492
|
+
|
493
|
+
hash = {}
|
494
|
+
# Add any found defaults to our argument list
|
495
|
+
defaults.each { |var,value|
|
496
|
+
Puppet.debug "Found default %s for %s" %
|
497
|
+
[var,objtype]
|
498
|
+
|
499
|
+
hash[var] = value
|
500
|
+
}
|
501
|
+
|
502
|
+
return hash
|
503
|
+
end
|
504
|
+
|
505
|
+
# Create our ObjectDef. Handles type checking for us.
|
506
|
+
def initialize(hash)
|
507
|
+
@checked = false
|
508
|
+
super
|
509
|
+
|
510
|
+
if @type.is_a?(Variable)
|
511
|
+
Puppet.debug "Delaying typecheck"
|
512
|
+
return
|
513
|
+
else
|
514
|
+
self.typecheck(@type.value)
|
515
|
+
|
516
|
+
objtype = @type.value
|
517
|
+
end
|
518
|
+
|
519
|
+
end
|
520
|
+
|
521
|
+
# Verify that all passed parameters are valid
|
522
|
+
def paramcheck(builtin, objtype)
|
523
|
+
# This defaults to true
|
524
|
+
unless Puppet[:paramcheck]
|
525
|
+
return
|
526
|
+
end
|
527
|
+
|
528
|
+
@params.each { |param|
|
529
|
+
if builtin
|
530
|
+
self.parambuiltincheck(builtin, param)
|
531
|
+
else
|
532
|
+
self.paramdefinedcheck(objtype, param)
|
533
|
+
end
|
534
|
+
}
|
535
|
+
end
|
536
|
+
|
537
|
+
def parambuiltincheck(type, param)
|
538
|
+
unless param.is_a?(AST::ObjectParam)
|
539
|
+
raise Puppet::DevError,
|
540
|
+
"Got something other than param"
|
541
|
+
end
|
542
|
+
begin
|
543
|
+
pname = param.param.value
|
544
|
+
rescue => detail
|
545
|
+
raise Puppet::DevError, detail.to_s
|
546
|
+
end
|
547
|
+
next if pname == "name" # always allow these
|
548
|
+
unless type.validarg?(pname)
|
549
|
+
error = Puppet::ParseError.new(
|
550
|
+
"Invalid parameter '%s' for type '%s'" %
|
551
|
+
[pname,type.name]
|
552
|
+
)
|
553
|
+
error.stack = caller
|
554
|
+
error.line = self.line
|
555
|
+
error.file = self.file
|
556
|
+
raise error
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
def paramdefinedcheck(objtype, param)
|
561
|
+
# FIXME we might need to do more here eventually...
|
562
|
+
if Puppet::Type.metaparam?(param.param.value.intern)
|
563
|
+
next
|
564
|
+
end
|
565
|
+
|
566
|
+
begin
|
567
|
+
pname = param.param.value
|
568
|
+
rescue => detail
|
569
|
+
raise Puppet::DevError, detail.to_s
|
570
|
+
end
|
571
|
+
|
572
|
+
unless @@settypes[objtype].validarg?(pname)
|
573
|
+
error = Puppet::ParseError.new(
|
574
|
+
"Invalid parameter '%s' for type '%s'" %
|
575
|
+
[pname,objtype]
|
576
|
+
)
|
577
|
+
error.stack = caller
|
578
|
+
error.line = self.line
|
579
|
+
error.file = self.file
|
580
|
+
raise error
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
# Set the parameters for our object.
|
585
|
+
def params=(params)
|
586
|
+
if params.is_a?(AST::ASTArray)
|
587
|
+
@params = params
|
588
|
+
else
|
589
|
+
@params = AST::ASTArray.new(
|
590
|
+
:line => params.line,
|
591
|
+
:file => params.file,
|
592
|
+
:children => [params]
|
593
|
+
)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
# Print this object out.
|
598
|
+
def tree(indent = 0)
|
599
|
+
return [
|
600
|
+
@type.tree(indent + 1),
|
601
|
+
@name.tree(indent + 1),
|
602
|
+
((@@indline * indent) + self.typewrap(self.pin)),
|
603
|
+
@params.collect { |param|
|
604
|
+
begin
|
605
|
+
param.tree(indent + 1)
|
606
|
+
rescue NoMethodError => detail
|
607
|
+
Puppet.err @params.inspect
|
608
|
+
error = Puppet::DevError.new(
|
609
|
+
"failed to tree a %s" % self.class
|
610
|
+
)
|
611
|
+
error.stack = caller
|
612
|
+
raise error
|
613
|
+
end
|
614
|
+
}.join("\n")
|
615
|
+
].join("\n")
|
616
|
+
end
|
617
|
+
|
618
|
+
# Verify that the type is valid. This throws an error if there's
|
619
|
+
# a problem, so the return value doesn't matter
|
620
|
+
def typecheck(objtype)
|
621
|
+
# This will basically always be on, but I wanted to make it at
|
622
|
+
# least simple to turn off if it came to that
|
623
|
+
unless Puppet[:typecheck]
|
624
|
+
return
|
625
|
+
end
|
626
|
+
|
627
|
+
builtin = false
|
628
|
+
begin
|
629
|
+
builtin = Puppet::Type.type(objtype)
|
630
|
+
rescue TypeError
|
631
|
+
# nothing; we've already set builtin to false
|
632
|
+
end
|
633
|
+
|
634
|
+
unless builtin or @@settypes.include?(objtype)
|
635
|
+
error = Puppet::ParseError.new(
|
636
|
+
"Unknown type '%s'" % objtype
|
637
|
+
)
|
638
|
+
error.line = self.line
|
639
|
+
error.file = self.file
|
640
|
+
error.stack = caller
|
641
|
+
raise error
|
642
|
+
end
|
643
|
+
|
644
|
+
unless builtin
|
645
|
+
Puppet.debug "%s is a defined type" % objtype
|
646
|
+
end
|
647
|
+
|
648
|
+
self.paramcheck(builtin, objtype)
|
649
|
+
|
650
|
+
@checked = true
|
651
|
+
end
|
652
|
+
|
653
|
+
def to_s
|
654
|
+
return "%s => { %s }" % [@name,
|
655
|
+
@params.collect { |param|
|
656
|
+
param.to_s
|
657
|
+
}.join("\n")
|
658
|
+
]
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
# A reference to an object. Only valid as an rvalue.
|
663
|
+
class ObjectRef < AST::Branch
|
664
|
+
attr_accessor :name, :type
|
665
|
+
|
666
|
+
def each
|
667
|
+
[@type,@name].flatten.each { |param|
|
668
|
+
#Puppet.debug("yielding param %s" % param)
|
669
|
+
yield param
|
670
|
+
}
|
671
|
+
end
|
672
|
+
|
673
|
+
# Evaluate our object, but just return a simple array of the type
|
674
|
+
# and name.
|
675
|
+
def evaluate(scope)
|
676
|
+
objtype = @type.safeevaluate(scope)
|
677
|
+
objnames = @name.safeevaluate(scope)
|
678
|
+
|
679
|
+
# it's easier to always use an array, even for only one name
|
680
|
+
unless objnames.is_a?(Array)
|
681
|
+
objnames = [objnames]
|
682
|
+
end
|
683
|
+
|
684
|
+
# Verify we can find the object.
|
685
|
+
begin
|
686
|
+
object = scope.lookuptype(objtype)
|
687
|
+
rescue Puppet::ParseError => except
|
688
|
+
except.line = self.line
|
689
|
+
except.file = self.file
|
690
|
+
raise except
|
691
|
+
rescue => detail
|
692
|
+
error = Puppet::ParseError.new(detail)
|
693
|
+
error.line = self.line
|
694
|
+
error.file = self.file
|
695
|
+
error.stack = caller
|
696
|
+
raise error
|
697
|
+
end
|
698
|
+
Puppet.debug "ObjectRef returned type %s" % object
|
699
|
+
|
700
|
+
# should we implicitly iterate here?
|
701
|
+
# yes, i believe that we essentially have to...
|
702
|
+
objnames.collect { |objname|
|
703
|
+
if object.is_a?(AST::Component)
|
704
|
+
objname = "%s[%s]" % [objtype,objname]
|
705
|
+
objtype = "component"
|
706
|
+
end
|
707
|
+
[objtype,objname]
|
708
|
+
}.reject { |obj| obj.nil? }
|
709
|
+
end
|
710
|
+
|
711
|
+
def tree(indent = 0)
|
712
|
+
return [
|
713
|
+
@type.tree(indent + 1),
|
714
|
+
@name.tree(indent + 1),
|
715
|
+
((@@indline * indent) + self.typewrap(self.pin))
|
716
|
+
].join("\n")
|
717
|
+
end
|
718
|
+
|
719
|
+
def to_s
|
720
|
+
return "%s[%s]" % [@name,@type]
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
# The AST object for the parameters inside ObjectDefs and Selectors.
|
725
|
+
class ObjectParam < AST::Branch
|
726
|
+
attr_accessor :value, :param
|
727
|
+
|
728
|
+
def each
|
729
|
+
[@param,@value].each { |child| yield child }
|
730
|
+
end
|
731
|
+
|
732
|
+
# Return the parameter and the value.
|
733
|
+
def evaluate(scope)
|
734
|
+
param = @param.safeevaluate(scope)
|
735
|
+
value = @value.safeevaluate(scope)
|
736
|
+
return [param, value]
|
737
|
+
end
|
738
|
+
|
739
|
+
def tree(indent = 0)
|
740
|
+
return [
|
741
|
+
@param.tree(indent + 1),
|
742
|
+
((@@indline * indent) + self.typewrap(self.pin)),
|
743
|
+
@value.tree(indent + 1)
|
744
|
+
].join("\n")
|
745
|
+
end
|
746
|
+
|
747
|
+
def to_s
|
748
|
+
return "%s => %s" % [@param,@value]
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
# The basic logical structure in Puppet. Supports a list of
|
753
|
+
# tests and statement arrays.
|
754
|
+
class CaseStatement < AST::Branch
|
755
|
+
attr_accessor :test, :options, :default
|
756
|
+
|
757
|
+
# Short-curcuit evaluation. Return the value of the statements for
|
758
|
+
# the first option that matches.
|
759
|
+
def evaluate(scope)
|
760
|
+
value = @test.safeevaluate(scope)
|
761
|
+
|
762
|
+
retvalue = nil
|
763
|
+
found = false
|
764
|
+
|
765
|
+
# Iterate across the options looking for a match.
|
766
|
+
@options.each { |option|
|
767
|
+
if option.eachvalue { |opval| break true if opval == value }
|
768
|
+
# we found a matching option
|
769
|
+
retvalue = option.safeevaluate(scope)
|
770
|
+
found = true
|
771
|
+
break
|
772
|
+
end
|
773
|
+
}
|
774
|
+
|
775
|
+
# Unless we found something, look for the default.
|
776
|
+
unless found
|
777
|
+
if defined? @default
|
778
|
+
retvalue = @default.safeevaluate(scope)
|
779
|
+
else
|
780
|
+
Puppet.debug "No true answers and no default"
|
781
|
+
end
|
782
|
+
end
|
783
|
+
return retvalue
|
784
|
+
end
|
785
|
+
|
786
|
+
# Do some input validation on our options.
|
787
|
+
def initialize(hash)
|
788
|
+
values = {}
|
789
|
+
|
790
|
+
super
|
791
|
+
# this won't work if we move away from only allowing constants
|
792
|
+
# here
|
793
|
+
# but for now, it's fine and useful
|
794
|
+
@options.each { |option|
|
795
|
+
if option.default?
|
796
|
+
@default = option
|
797
|
+
end
|
798
|
+
option.eachvalue { |val|
|
799
|
+
if values.include?(val)
|
800
|
+
raise Puppet::ParseError,
|
801
|
+
"Value %s appears twice in case statement" %
|
802
|
+
val
|
803
|
+
else
|
804
|
+
values[val] = true
|
805
|
+
end
|
806
|
+
}
|
807
|
+
}
|
808
|
+
end
|
809
|
+
|
810
|
+
def tree(indent = 0)
|
811
|
+
rettree = [
|
812
|
+
@test.tree(indent + 1),
|
813
|
+
((@@indline * indent) + self.typewrap(self.pin)),
|
814
|
+
@options.tree(indent + 1)
|
815
|
+
]
|
816
|
+
|
817
|
+
return rettree.flatten.join("\n")
|
818
|
+
end
|
819
|
+
|
820
|
+
def each
|
821
|
+
[@test,@options].each { |child| yield child }
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
# Each individual option in a case statement.
|
826
|
+
class CaseOpt < AST::Branch
|
827
|
+
attr_accessor :value, :statements
|
828
|
+
|
829
|
+
# CaseOpt is a bit special -- we just want the value first,
|
830
|
+
# so that CaseStatement can compare, and then it will selectively
|
831
|
+
# decide whether to fully evaluate this option
|
832
|
+
|
833
|
+
def each
|
834
|
+
[@value,@statements].each { |child| yield child }
|
835
|
+
end
|
836
|
+
|
837
|
+
# Are we the default option?
|
838
|
+
def default?
|
839
|
+
if defined? @default
|
840
|
+
return @default
|
841
|
+
end
|
842
|
+
|
843
|
+
if @value.is_a?(AST::ASTArray)
|
844
|
+
@value.each { |subval|
|
845
|
+
if subval.is_a?(AST::Default)
|
846
|
+
@default = true
|
847
|
+
break
|
848
|
+
end
|
849
|
+
}
|
850
|
+
else
|
851
|
+
if @value.is_a?(AST::Default)
|
852
|
+
@default = true
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
unless defined? @default
|
857
|
+
@default = false
|
858
|
+
end
|
859
|
+
|
860
|
+
return @default
|
861
|
+
end
|
862
|
+
|
863
|
+
# You can specify a list of values; return each in turn.
|
864
|
+
def eachvalue
|
865
|
+
if @value.is_a?(AST::ASTArray)
|
866
|
+
@value.each { |subval|
|
867
|
+
yield subval.value
|
868
|
+
}
|
869
|
+
else
|
870
|
+
yield @value.value
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
# Evaluate the actual statements; this only gets called if
|
875
|
+
# our option matched.
|
876
|
+
def evaluate(scope)
|
877
|
+
return @statements.safeevaluate(scope.newscope)
|
878
|
+
end
|
879
|
+
|
880
|
+
def tree(indent = 0)
|
881
|
+
rettree = [
|
882
|
+
@value.tree(indent + 1),
|
883
|
+
((@@indline * indent) + self.typewrap(self.pin)),
|
884
|
+
@statements.tree(indent + 1)
|
885
|
+
]
|
886
|
+
return rettree.flatten.join("\n")
|
887
|
+
end
|
888
|
+
end
|
889
|
+
|
890
|
+
# The inline conditional operator. Unlike CaseStatement, which executes
|
891
|
+
# code, we just return a value.
|
892
|
+
class Selector < AST::Branch
|
893
|
+
attr_accessor :param, :values
|
894
|
+
|
895
|
+
def each
|
896
|
+
[@param,@values].each { |child| yield child }
|
897
|
+
end
|
898
|
+
|
899
|
+
# Find the value that corresponds with the test.
|
900
|
+
def evaluate(scope)
|
901
|
+
retvalue = nil
|
902
|
+
found = nil
|
903
|
+
|
904
|
+
# Get our parameter.
|
905
|
+
paramvalue = @param.safeevaluate(scope)
|
906
|
+
|
907
|
+
default = nil
|
908
|
+
|
909
|
+
# Then look for a match in the options.
|
910
|
+
@values.each { |obj|
|
911
|
+
param = obj.param.safeevaluate(scope)
|
912
|
+
if param == paramvalue
|
913
|
+
# we found a matching option
|
914
|
+
retvalue = obj.value.safeevaluate(scope)
|
915
|
+
found = true
|
916
|
+
break
|
917
|
+
elsif obj.param.is_a?(Default)
|
918
|
+
default = obj
|
919
|
+
end
|
920
|
+
}
|
921
|
+
|
922
|
+
# Unless we found something, look for the default.
|
923
|
+
unless found
|
924
|
+
if default
|
925
|
+
retvalue = default.value.safeevaluate(scope)
|
926
|
+
else
|
927
|
+
error = Puppet::ParseError.new(
|
928
|
+
"No value for selector param '%s'" % paramvalue
|
929
|
+
)
|
930
|
+
error.line = self.line
|
931
|
+
error.file = self.file
|
932
|
+
raise error
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
936
|
+
return retvalue
|
937
|
+
end
|
938
|
+
|
939
|
+
def tree(indent = 0)
|
940
|
+
return [
|
941
|
+
@param.tree(indent + 1),
|
942
|
+
((@@indline * indent) + self.typewrap(self.pin)),
|
943
|
+
@values.tree(indent + 1)
|
944
|
+
].join("\n")
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
# Define a variable. Stores the value in the current scope.
|
949
|
+
class VarDef < AST::Branch
|
950
|
+
attr_accessor :name, :value
|
951
|
+
|
952
|
+
# Look up our name and value, and store them appropriately. The
|
953
|
+
# lexer strips off the syntax stuff like '$'.
|
954
|
+
def evaluate(scope)
|
955
|
+
name = @name.safeevaluate(scope)
|
956
|
+
value = @value.safeevaluate(scope)
|
957
|
+
|
958
|
+
begin
|
959
|
+
scope.setvar(name,value)
|
960
|
+
rescue Puppet::ParseError => except
|
961
|
+
except.line = self.line
|
962
|
+
except.file = self.file
|
963
|
+
raise except
|
964
|
+
rescue => detail
|
965
|
+
error = Puppet::ParseError.new(detail)
|
966
|
+
error.line = self.line
|
967
|
+
error.file = self.file
|
968
|
+
error.stack = caller
|
969
|
+
raise error
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
def each
|
974
|
+
[@name,@value].each { |child| yield child }
|
975
|
+
end
|
976
|
+
|
977
|
+
def tree(indent = 0)
|
978
|
+
return [
|
979
|
+
@name.tree(indent + 1),
|
980
|
+
((@@indline * 4 * indent) + self.typewrap(self.pin)),
|
981
|
+
@value.tree(indent + 1)
|
982
|
+
].join("\n")
|
983
|
+
end
|
984
|
+
|
985
|
+
def to_s
|
986
|
+
return "%s => %s" % [@name,@value]
|
987
|
+
end
|
988
|
+
end
|
989
|
+
|
990
|
+
# A statement syntactically similar to an ObjectDef, but uses a
|
991
|
+
# capitalized object type and cannot have a name.
|
992
|
+
class TypeDefaults < AST::Branch
|
993
|
+
attr_accessor :type, :params
|
994
|
+
|
995
|
+
def each
|
996
|
+
[@type,@params].each { |child| yield child }
|
997
|
+
end
|
998
|
+
|
999
|
+
# As opposed to ObjectDef, this stores each default for the given
|
1000
|
+
# object type.
|
1001
|
+
def evaluate(scope)
|
1002
|
+
type = @type.safeevaluate(scope)
|
1003
|
+
params = @params.safeevaluate(scope)
|
1004
|
+
|
1005
|
+
begin
|
1006
|
+
scope.setdefaults(type.downcase,params)
|
1007
|
+
rescue Puppet::ParseError => except
|
1008
|
+
except.line = self.line
|
1009
|
+
except.file = self.file
|
1010
|
+
raise except
|
1011
|
+
rescue => detail
|
1012
|
+
error = Puppet::ParseError.new(detail)
|
1013
|
+
error.line = self.line
|
1014
|
+
error.file = self.file
|
1015
|
+
error.stack = caller
|
1016
|
+
raise error
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
def tree(indent = 0)
|
1021
|
+
return [
|
1022
|
+
@type.tree(indent + 1),
|
1023
|
+
((@@indline * 4 * indent) + self.typewrap(self.pin)),
|
1024
|
+
@params.tree(indent + 1)
|
1025
|
+
].join("\n")
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
def to_s
|
1029
|
+
return "%s { %s }" % [@type,@params]
|
1030
|
+
end
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
# Define a new component. This basically just stores the
|
1034
|
+
# associated parse tree by name in our current scope. Note that
|
1035
|
+
# there is currently a mismatch in how we look up components -- it
|
1036
|
+
# usually uses scopes, but sometimes uses '@@settypes'.
|
1037
|
+
# FIXME This class should verify that each of its direct children
|
1038
|
+
# has an abstractable name -- i.e., if a file does not include a
|
1039
|
+
# variable in its name, then the user is essentially guaranteed to
|
1040
|
+
# encounter an error if the component is instantiated more than
|
1041
|
+
# once.
|
1042
|
+
class CompDef < AST::Branch
|
1043
|
+
attr_accessor :name, :args, :code
|
1044
|
+
|
1045
|
+
def each
|
1046
|
+
[@name,@args,@code].each { |child| yield child }
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
# Store the parse tree.
|
1050
|
+
def evaluate(scope)
|
1051
|
+
name = @name.safeevaluate(scope)
|
1052
|
+
args = @args.safeevaluate(scope)
|
1053
|
+
|
1054
|
+
begin
|
1055
|
+
scope.settype(name,
|
1056
|
+
AST::Component.new(
|
1057
|
+
:name => name,
|
1058
|
+
:args => args,
|
1059
|
+
:code => @code
|
1060
|
+
)
|
1061
|
+
)
|
1062
|
+
rescue Puppet::ParseError => except
|
1063
|
+
except.line = self.line
|
1064
|
+
except.file = self.file
|
1065
|
+
raise except
|
1066
|
+
rescue => detail
|
1067
|
+
error = Puppet::ParseError.new(detail)
|
1068
|
+
error.line = self.line
|
1069
|
+
error.file = self.file
|
1070
|
+
error.stack = caller
|
1071
|
+
raise error
|
1072
|
+
end
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
def initialize(hash)
|
1076
|
+
@parentclass = nil
|
1077
|
+
super
|
1078
|
+
|
1079
|
+
Puppet.debug "Defining type %s" % @name.value
|
1080
|
+
|
1081
|
+
# we need to both mark that a given argument is valid,
|
1082
|
+
# and we need to also store any provided default arguments
|
1083
|
+
# FIXME This creates a global list of types and their
|
1084
|
+
# acceptable arguments. This should really be scoped
|
1085
|
+
# instead.
|
1086
|
+
@@settypes[@name.value] = self
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
def tree(indent = 0)
|
1090
|
+
return [
|
1091
|
+
@name.tree(indent + 1),
|
1092
|
+
((@@indline * 4 * indent) + self.typewrap("define")),
|
1093
|
+
@args.tree(indent + 1),
|
1094
|
+
@code.tree(indent + 1),
|
1095
|
+
].join("\n")
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
def to_s
|
1099
|
+
return "define %s(%s) {\n%s }" % [@name, @args, @code]
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
# Check whether a given argument is valid. Searches up through
|
1103
|
+
# any parent classes that might exist.
|
1104
|
+
def validarg?(param)
|
1105
|
+
found = false
|
1106
|
+
if @args.is_a?(AST::ASTArray)
|
1107
|
+
found = @args.detect { |arg|
|
1108
|
+
if arg.is_a?(AST::ASTArray)
|
1109
|
+
arg[0].value == param
|
1110
|
+
else
|
1111
|
+
arg.value == param
|
1112
|
+
end
|
1113
|
+
}
|
1114
|
+
else
|
1115
|
+
found = @args.value == param
|
1116
|
+
#Puppet.warning "got arg %s" % @args.inspect
|
1117
|
+
#hash[@args.value] += 1
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
if found
|
1121
|
+
return true
|
1122
|
+
# a nil parentclass is an empty astarray
|
1123
|
+
# stupid but true
|
1124
|
+
elsif @parentclass
|
1125
|
+
parent = @@settypes[@parentclass.value]
|
1126
|
+
if parent and parent != []
|
1127
|
+
return parent.validarg?(param)
|
1128
|
+
else
|
1129
|
+
raise Puppet::Error, "Could not find parent class %s" %
|
1130
|
+
@parentclass.value
|
1131
|
+
end
|
1132
|
+
else
|
1133
|
+
return false
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
end
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
# Define a new class. Syntactically similar to component definitions,
|
1140
|
+
# but classes are always singletons -- only one can exist on a given
|
1141
|
+
# host.
|
1142
|
+
class ClassDef < AST::CompDef
|
1143
|
+
attr_accessor :parentclass
|
1144
|
+
|
1145
|
+
def each
|
1146
|
+
if @parentclass
|
1147
|
+
#[@name,@args,@parentclass,@code].each { |child| yield child }
|
1148
|
+
[@name,@parentclass,@code].each { |child| yield child }
|
1149
|
+
else
|
1150
|
+
#[@name,@args,@code].each { |child| yield child }
|
1151
|
+
[@name,@code].each { |child| yield child }
|
1152
|
+
end
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
# Store our parse tree according to name.
|
1156
|
+
def evaluate(scope)
|
1157
|
+
name = @name.safeevaluate(scope)
|
1158
|
+
#args = @args.safeevaluate(scope)
|
1159
|
+
|
1160
|
+
#:args => args,
|
1161
|
+
arghash = {
|
1162
|
+
:name => name,
|
1163
|
+
:code => @code
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
if @parentclass
|
1167
|
+
arghash[:parentclass] = @parentclass.safeevaluate(scope)
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
#Puppet.debug("defining hostclass '%s' with arguments [%s]" %
|
1171
|
+
# [name,args])
|
1172
|
+
|
1173
|
+
begin
|
1174
|
+
scope.settype(name,
|
1175
|
+
HostClass.new(arghash)
|
1176
|
+
)
|
1177
|
+
rescue Puppet::ParseError => except
|
1178
|
+
except.line = self.line
|
1179
|
+
except.file = self.file
|
1180
|
+
raise except
|
1181
|
+
rescue => detail
|
1182
|
+
error = Puppet::ParseError.new(detail)
|
1183
|
+
error.line = self.line
|
1184
|
+
error.file = self.file
|
1185
|
+
error.stack = caller
|
1186
|
+
raise error
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
def initialize(hash)
|
1191
|
+
@parentclass = nil
|
1192
|
+
super
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def tree(indent = 0)
|
1196
|
+
#@args.tree(indent + 1),
|
1197
|
+
return [
|
1198
|
+
@name.tree(indent + 1),
|
1199
|
+
((@@indline * 4 * indent) + self.typewrap("class")),
|
1200
|
+
@parentclass ? @parentclass.tree(indent + 1) : "",
|
1201
|
+
@code.tree(indent + 1),
|
1202
|
+
].join("\n")
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
def to_s
|
1206
|
+
return "class %s(%s) inherits %s {\n%s }" %
|
1207
|
+
[@name, @parentclass, @code]
|
1208
|
+
#[@name, @args, @parentclass, @code]
|
1209
|
+
end
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
# Define a node. The node definition stores a parse tree for each
|
1213
|
+
# specified node, and this parse tree is only ever looked up when
|
1214
|
+
# a client connects.
|
1215
|
+
class NodeDef < AST::Branch
|
1216
|
+
attr_accessor :names, :code, :parentclass
|
1217
|
+
|
1218
|
+
def each
|
1219
|
+
[@names,@code].each { |child| yield child }
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
# Do implicit iteration over each of the names passed.
|
1223
|
+
def evaluate(scope)
|
1224
|
+
names = @names.safeevaluate(scope)
|
1225
|
+
|
1226
|
+
unless names.is_a?(Array)
|
1227
|
+
names = [names]
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
names.each { |name|
|
1231
|
+
Puppet.debug("defining host '%s' in scope %s" %
|
1232
|
+
[name, scope.object_id])
|
1233
|
+
arghash = {
|
1234
|
+
:name => name,
|
1235
|
+
:code => @code
|
1236
|
+
}
|
1237
|
+
|
1238
|
+
if @parentclass
|
1239
|
+
arghash[:parentclass] = @parentclass.safeevaluate(scope)
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
begin
|
1243
|
+
scope.setnode(name,
|
1244
|
+
Node.new(arghash)
|
1245
|
+
)
|
1246
|
+
rescue Puppet::ParseError => except
|
1247
|
+
except.line = self.line
|
1248
|
+
except.file = self.file
|
1249
|
+
raise except
|
1250
|
+
rescue => detail
|
1251
|
+
error = Puppet::ParseError.new(detail)
|
1252
|
+
error.line = self.line
|
1253
|
+
error.file = self.file
|
1254
|
+
error.stack = caller
|
1255
|
+
raise error
|
1256
|
+
end
|
1257
|
+
}
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
def initialize(hash)
|
1261
|
+
@parentclass = nil
|
1262
|
+
super
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
def tree(indent = 0)
|
1266
|
+
return [
|
1267
|
+
@names.tree(indent + 1),
|
1268
|
+
((@@indline * 4 * indent) + self.typewrap("node")),
|
1269
|
+
@code.tree(indent + 1),
|
1270
|
+
].join("\n")
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
def to_s
|
1274
|
+
return "node %s {\n%s }" % [@name, @code]
|
1275
|
+
end
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
# Evaluate the stored parse tree for a given component. This will
|
1279
|
+
# receive the arguments passed to the component and also the type and
|
1280
|
+
# name of the component.
|
1281
|
+
class Component < AST::Branch
|
1282
|
+
class << self
|
1283
|
+
attr_accessor :name
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
# The class name
|
1287
|
+
@name = :component
|
1288
|
+
|
1289
|
+
attr_accessor :name, :args, :code, :scope
|
1290
|
+
|
1291
|
+
def evaluate(scope,hash,objtype,objname)
|
1292
|
+
|
1293
|
+
scope = scope.newscope
|
1294
|
+
|
1295
|
+
# The type is the component or class name
|
1296
|
+
scope.type = objtype
|
1297
|
+
|
1298
|
+
# The name is the name the user has chosen or that has
|
1299
|
+
# been dynamically generated. This is almost never used
|
1300
|
+
scope.name = objname
|
1301
|
+
|
1302
|
+
#if self.is_a?(Node)
|
1303
|
+
# scope.isnodescope
|
1304
|
+
#end
|
1305
|
+
|
1306
|
+
# Additionally, add a tag for whatever kind of class
|
1307
|
+
# we are
|
1308
|
+
scope.tag(objtype)
|
1309
|
+
|
1310
|
+
unless objname =~ /-\d+/ # it was generated
|
1311
|
+
scope.tag(objname)
|
1312
|
+
end
|
1313
|
+
#scope.base = self.class.name
|
1314
|
+
|
1315
|
+
|
1316
|
+
# define all of the arguments in our local scope
|
1317
|
+
if self.args
|
1318
|
+
|
1319
|
+
# Verify that all required arguments are either present or
|
1320
|
+
# have been provided with defaults.
|
1321
|
+
# FIXME This should probably also require each parent
|
1322
|
+
# class's arguments...
|
1323
|
+
self.args.each { |arg, default|
|
1324
|
+
unless hash.include?(arg)
|
1325
|
+
if defined? default and ! default.nil?
|
1326
|
+
hash[arg] = default
|
1327
|
+
Puppet.debug "Got default %s for %s in %s" %
|
1328
|
+
[default.inspect, arg.inspect, objname.inspect]
|
1329
|
+
else
|
1330
|
+
error = Puppet::ParseError.new(
|
1331
|
+
"Must pass %s to %s of type %s" %
|
1332
|
+
[arg.inspect,name,objtype]
|
1333
|
+
)
|
1334
|
+
error.line = self.line
|
1335
|
+
error.file = self.file
|
1336
|
+
error.stack = caller
|
1337
|
+
raise error
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
}
|
1341
|
+
end
|
1342
|
+
|
1343
|
+
# Set each of the provided arguments as variables in the
|
1344
|
+
# component's scope.
|
1345
|
+
hash["name"] = objname
|
1346
|
+
hash.each { |arg,value|
|
1347
|
+
begin
|
1348
|
+
scope.setvar(arg,hash[arg])
|
1349
|
+
rescue Puppet::ParseError => except
|
1350
|
+
except.line = self.line
|
1351
|
+
except.file = self.file
|
1352
|
+
raise except
|
1353
|
+
rescue Puppet::ParseError => except
|
1354
|
+
except.line = self.line
|
1355
|
+
except.file = self.file
|
1356
|
+
raise except
|
1357
|
+
rescue => except
|
1358
|
+
error = Puppet::ParseError.new(except.message)
|
1359
|
+
error.line = self.line
|
1360
|
+
error.file = self.file
|
1361
|
+
error.stack = caller
|
1362
|
+
raise error
|
1363
|
+
end
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
# Now just evaluate the code with our new bindings.
|
1367
|
+
self.code.safeevaluate(scope)
|
1368
|
+
|
1369
|
+
# We return the scope, so that our children can make their scopes
|
1370
|
+
# under ours. This allows them to find our definitions.
|
1371
|
+
return scope
|
1372
|
+
end
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
# The code associated with a class. This is different from components
|
1376
|
+
# in that each class is a singleton -- only one will exist for a given
|
1377
|
+
# node.
|
1378
|
+
class HostClass < AST::Component
|
1379
|
+
@name = :class
|
1380
|
+
attr_accessor :parentclass
|
1381
|
+
|
1382
|
+
def evaluate(scope,hash,objtype,objname)
|
1383
|
+
if scope.lookupclass(@name)
|
1384
|
+
Puppet.debug "%s class already evaluated" % @name
|
1385
|
+
return nil
|
1386
|
+
end
|
1387
|
+
|
1388
|
+
if tmp = self.evalparent(scope, hash, objname)
|
1389
|
+
# Override our scope binding with the parent scope
|
1390
|
+
# binding. This is quite hackish, but I can't think
|
1391
|
+
# of another way to make sure our scopes end up under
|
1392
|
+
# our parent scopes.
|
1393
|
+
scope = tmp
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
# just use the Component evaluate method, but change the type
|
1397
|
+
# to our own type
|
1398
|
+
retval = super(scope,hash,@name,objname)
|
1399
|
+
|
1400
|
+
# Set the mark after we evaluate, so we don't record it but
|
1401
|
+
# then encounter an error
|
1402
|
+
scope.setclass(@name)
|
1403
|
+
return retval
|
1404
|
+
end
|
1405
|
+
|
1406
|
+
# Evaluate our parent class. Parent classes are evaluated in the
|
1407
|
+
# exact same scope as the children. This is maybe not a good idea
|
1408
|
+
# but, eh.
|
1409
|
+
def evalparent(scope, args, name)
|
1410
|
+
if @parentclass
|
1411
|
+
parentobj = nil
|
1412
|
+
|
1413
|
+
begin
|
1414
|
+
parentobj = scope.lookuptype(@parentclass)
|
1415
|
+
rescue Puppet::ParseError => except
|
1416
|
+
except.line = self.line
|
1417
|
+
except.file = self.file
|
1418
|
+
raise except
|
1419
|
+
rescue => detail
|
1420
|
+
error = Puppet::ParseError.new(detail)
|
1421
|
+
error.line = self.line
|
1422
|
+
error.file = self.file
|
1423
|
+
raise error
|
1424
|
+
end
|
1425
|
+
unless parentobj
|
1426
|
+
error = Puppet::ParseError.new(
|
1427
|
+
"Could not find parent '%s' of '%s'" %
|
1428
|
+
[@parentclass,@name])
|
1429
|
+
error.line = self.line
|
1430
|
+
error.file = self.file
|
1431
|
+
raise error
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
# Verify that the parent and child are of the same type
|
1435
|
+
unless parentobj.class == self.class
|
1436
|
+
error = Puppet::ParseError.new(
|
1437
|
+
"Class %s has incompatible parent type, %s vs %s" %
|
1438
|
+
[@name, parentobj.class, self.class]
|
1439
|
+
)
|
1440
|
+
error.file = self.file
|
1441
|
+
error.line = self.line
|
1442
|
+
raise error
|
1443
|
+
end
|
1444
|
+
return parentobj.safeevaluate(scope,args,@parentclass,name)
|
1445
|
+
end
|
1446
|
+
end
|
1447
|
+
|
1448
|
+
def initialize(hash)
|
1449
|
+
@parentclass = nil
|
1450
|
+
super
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
# The specific code associated with a host. Nodes are annoyingly unlike
|
1456
|
+
# other objects. That's just the way it is, at least for now.
|
1457
|
+
class Node < AST::HostClass
|
1458
|
+
@name = :node
|
1459
|
+
attr_accessor :name, :args, :code, :parentclass
|
1460
|
+
|
1461
|
+
def evaluate(scope, facts = {})
|
1462
|
+
scope = scope.newscope
|
1463
|
+
|
1464
|
+
# nodes are never instantiated like a normal object,
|
1465
|
+
# but we need the type to be the name users would use for
|
1466
|
+
# instantiation, otherwise tags don't work out
|
1467
|
+
|
1468
|
+
# The name has already been evaluated, so it's a normal
|
1469
|
+
# string.
|
1470
|
+
scope.type = @name
|
1471
|
+
scope.name = @name
|
1472
|
+
|
1473
|
+
# Mark this scope as a nodescope, so that classes will be
|
1474
|
+
# singletons within it
|
1475
|
+
scope.isnodescope
|
1476
|
+
|
1477
|
+
# Now set all of the facts inside this scope
|
1478
|
+
facts.each { |var, value|
|
1479
|
+
scope.setvar(var, value)
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
if tmp = self.evalparent(scope)
|
1483
|
+
# Again, override our scope with the parent scope, if
|
1484
|
+
# there is one.
|
1485
|
+
scope = tmp
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
#scope.tag(@name)
|
1489
|
+
|
1490
|
+
# We never pass the facts to the parent class, because they've
|
1491
|
+
# already been defined at this top-level scope.
|
1492
|
+
#super(scope, facts, @name, @name)
|
1493
|
+
|
1494
|
+
# And then evaluate our code.
|
1495
|
+
@code.safeevaluate(scope)
|
1496
|
+
|
1497
|
+
return scope
|
1498
|
+
end
|
1499
|
+
|
1500
|
+
# Evaluate our parent class.
|
1501
|
+
def evalparent(scope)
|
1502
|
+
if @parentclass
|
1503
|
+
# This is pretty messed up. I don't know if this will
|
1504
|
+
# work in the long term, but we need to evaluate the node
|
1505
|
+
# in our own scope, even though our parent node has
|
1506
|
+
# a scope associated with it, because otherwise we 1) won't
|
1507
|
+
# get our facts defined, and 2) we won't actually get the
|
1508
|
+
# objects returned, based on how nodes work.
|
1509
|
+
|
1510
|
+
# We also can't just evaluate the node itself, because
|
1511
|
+
# it would create a node scope within this scope,
|
1512
|
+
# and that would cause mass havoc.
|
1513
|
+
node = nil
|
1514
|
+
|
1515
|
+
# The 'node' method just returns a hash of the node
|
1516
|
+
# code and name. It's used here, and in 'evalnode'.
|
1517
|
+
unless hash = scope.node(@parentclass)
|
1518
|
+
raise Puppet::ParseError,
|
1519
|
+
"Could not find parent node %s" %
|
1520
|
+
@parentclass
|
1521
|
+
end
|
1522
|
+
|
1523
|
+
node = hash[:node]
|
1524
|
+
# Tag the scope with the parent's name/type.
|
1525
|
+
name = node.name
|
1526
|
+
#Puppet.info "Tagging with parent node %s" % name
|
1527
|
+
scope.tag(name)
|
1528
|
+
|
1529
|
+
begin
|
1530
|
+
code = node.code
|
1531
|
+
code.safeevaluate(scope)
|
1532
|
+
rescue Puppet::ParseError => except
|
1533
|
+
except.line = self.line
|
1534
|
+
except.file = self.file
|
1535
|
+
raise except
|
1536
|
+
rescue => detail
|
1537
|
+
error = Puppet::ParseError.new(detail)
|
1538
|
+
error.line = self.line
|
1539
|
+
error.file = self.file
|
1540
|
+
raise error
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
if node.parentclass
|
1544
|
+
node.evalparent(scope)
|
1545
|
+
end
|
1546
|
+
end
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
def initialize(hash)
|
1550
|
+
@parentclass = nil
|
1551
|
+
super
|
1552
|
+
|
1553
|
+
end
|
1554
|
+
end
|
1555
|
+
#---------------------------------------------------------------
|
1556
|
+
end
|
1557
|
+
end
|
1558
|
+
end
|
1559
|
+
|
1560
|
+
# $Id: ast.rb 736 2005-10-30 01:12:03Z luke $
|