class Puppet::Parser::AST::PopsBridge::Program
Bridges the top level “Program” produced by the pops parser. Its main purpose is to give one point where all definitions are instantiated (actually defined since the Puppet 3x terminology is somewhat misleading - the definitions are instantiated, but instances of the created types are not created, that happens when classes are included / required, nodes are matched and when resources are instantiated by a resource expression (which is also used to instantiate a host class).
Attributes
Public Class Methods
# File lib/puppet/parser/ast/pops_bridge.rb 78 def initialize(program_model, context = {}) 79 @program_model = program_model 80 @context = context 81 @ast_transformer ||= Puppet::Pops::Model::AstTransformer.new(@context[:file]) 82 end
Public Instance Methods
Adapts to 3x where top level constructs needs to have each to iterate over children. Short circuit this by yielding self. This means that the HostClass container will call this bridge instance with `instantiate`.
# File lib/puppet/parser/ast/pops_bridge.rb 116 def each 117 yield self 118 end
# File lib/puppet/parser/ast/pops_bridge.rb 109 def evaluate(scope) 110 Puppet::Pops::Parser::EvaluatingParser.singleton.evaluate(scope, program_model) 111 end
This is the 3x API, the 3x AST searches through all code to find the instructions that can be instantiated. This Pops-model based instantiation relies on the parser to build this list while parsing (which is more efficient as it avoids one full scan of all logic via recursive enumeration/yield)
# File lib/puppet/parser/ast/pops_bridge.rb 88 def instantiate(modname) 89 90 @program_model.definitions.map do |d| 91 case d 92 when Puppet::Pops::Model::HostClassDefinition 93 instantiate_HostClassDefinition(d, modname) 94 when Puppet::Pops::Model::ResourceTypeDefinition 95 instantiate_ResourceTypeDefinition(d, modname) 96 when Puppet::Pops::Model::NodeDefinition 97 instantiate_NodeDefinition(d, modname) 98 else 99 loaders = Puppet::Pops::Loaders.loaders 100 loaders.instantiate_definition(d, loaders.find_loader(modname)) 101 102 # The 3x logic calling this will not know what to do with the result, it is compacted away at the end 103 nil 104 end 105 end.flatten().compact() # flatten since node definition may have returned an array 106 # Compact since 4x definitions are not understood by compiler 107 end
Returns true if this Program only contains definitions
# File lib/puppet/parser/ast/pops_bridge.rb 121 def is_definitions_only? 122 is_definition?(program_model) 123 end
Private Instance Methods
# File lib/puppet/parser/ast/pops_bridge.rb 238 def absolute_reference(ref) 239 if ref.nil? || ref.empty? || ref.start_with?('::') 240 ref 241 else 242 "::#{ref}" 243 end 244 end
Produces a hash with data for Definition and HostClass
# File lib/puppet/parser/ast/pops_bridge.rb 188 def args_from_definition(o, modname, expr_class = Expression) 189 args = { 190 :arguments => o.parameters.collect {|p| instantiate_Parameter(p) }, 191 :argument_types => create_type_map(o), 192 :module_name => modname 193 } 194 unless is_nop?(o.body) 195 args[:code] = expr_class.new(:value => o.body) 196 end 197 @ast_transformer.merge_location(args, o) 198 end
# File lib/puppet/parser/ast/pops_bridge.rb 230 def code() 231 Expression.new(:value => @value) 232 end
# File lib/puppet/parser/ast/pops_bridge.rb 149 def create_type_map(definition) 150 result = {} 151 # No need to do anything if there are no parameters 152 return result unless definition.parameters.size > 0 153 154 # No need to do anything if there are no typed parameters 155 typed_parameters = definition.parameters.select {|p| p.type_expr } 156 return result if typed_parameters.empty? 157 158 # If there are typed parameters, they need to be evaluated to produce the corresponding type 159 # instances. This evaluation requires a scope. A scope is not available when doing deserialization 160 # (there is also no initialized evaluator). When running apply and test however, the environment is 161 # reused and we may reenter without a scope (which is fine). A debug message is then output in case 162 # there is the need to track down the odd corner case. See {#obtain_scope}. 163 # 164 scope = obtain_scope 165 if scope 166 evaluator = Puppet::Pops::Parser::EvaluatingParser.singleton 167 typed_parameters.each do |p| 168 result[p.name] = evaluator.evaluate(scope, p.type_expr) 169 end 170 end 171 result 172 end
# File lib/puppet/parser/ast/pops_bridge.rb 200 def instantiate_HostClassDefinition(o, modname) 201 args = args_from_definition(o, modname, ExpressionSupportingReturn) 202 args[:parent] = absolute_reference(o.parent_class) 203 Puppet::Resource::Type.new(:hostclass, o.name, @context.merge(args)) 204 end
# File lib/puppet/parser/ast/pops_bridge.rb 212 def instantiate_NodeDefinition(o, modname) 213 args = { :module_name => modname } 214 215 unless is_nop?(o.body) 216 args[:code] = Expression.new(:value => o.body) 217 end 218 219 unless is_nop?(o.parent) 220 args[:parent] = @ast_transformer.hostname(o.parent) 221 end 222 args = @ast_transformer.merge_location(args, o) 223 224 host_matches = @ast_transformer.hostname(o.host_matches) 225 host_matches.collect do |name| 226 Puppet::Resource::Type.new(:node, name, @context.merge(args)) 227 end 228 end
# File lib/puppet/parser/ast/pops_bridge.rb 140 def instantiate_Parameter(o) 141 # 3x needs parameters as an array of `[name]` or `[name, value_expr]` 142 if o.value 143 [o.name, Expression.new(:value => o.value)] 144 else 145 [o.name] 146 end 147 end
# File lib/puppet/parser/ast/pops_bridge.rb 206 def instantiate_ResourceTypeDefinition(o, modname) 207 instance = Puppet::Resource::Type.new(:definition, o.name, @context.merge(args_from_definition(o, modname, ExpressionSupportingReturn))) 208 Puppet::Pops::Loaders.register_runtime3_type(instance.name, o.locator.to_uri(o)) 209 instance 210 end
# File lib/puppet/parser/ast/pops_bridge.rb 127 def is_definition?(o) 128 case o 129 when Puppet::Pops::Model::Program 130 is_definition?(o.body) 131 when Puppet::Pops::Model::BlockExpression 132 o.statements.all {|s| is_definition?(s) } 133 when Puppet::Pops::Model::Definition 134 true 135 else 136 false 137 end 138 end
# File lib/puppet/parser/ast/pops_bridge.rb 234 def is_nop?(o) 235 @ast_transformer.is_nop?(o) 236 end
Obtains the scope or issues a warning if :global_scope is not bound
# File lib/puppet/parser/ast/pops_bridge.rb 175 def obtain_scope 176 scope = Puppet.lookup(:global_scope) do 177 # This occurs when testing and when applying a catalog (there is no scope available then), and 178 # when running tests that run a partial setup. 179 # This is bad if the logic is trying to compile, but a warning can not be issues since it is a normal 180 # use case that there is no scope when requesting the type in order to just get the parameters. 181 Puppet.debug {_("Instantiating Resource with type checked parameters - scope is missing, skipping type checking.")} 182 nil 183 end 184 scope 185 end