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 77 def initialize(program_model, context = {}) 78 @program_model = program_model 79 @context = context 80 @ast_transformer ||= Puppet::Pops::Model::AstTransformer.new(@context[:file]) 81 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 115 def each 116 yield self 117 end
# File lib/puppet/parser/ast/pops_bridge.rb 108 def evaluate(scope) 109 Puppet::Pops::Parser::EvaluatingParser.singleton.evaluate(scope, program_model) 110 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 87 def instantiate(modname) 88 89 @program_model.definitions.map do |d| 90 case d 91 when Puppet::Pops::Model::HostClassDefinition 92 instantiate_HostClassDefinition(d, modname) 93 when Puppet::Pops::Model::ResourceTypeDefinition 94 instantiate_ResourceTypeDefinition(d, modname) 95 when Puppet::Pops::Model::NodeDefinition 96 instantiate_NodeDefinition(d, modname) 97 else 98 loaders = Puppet::Pops::Loaders.loaders 99 loaders.instantiate_definition(d, loaders.find_loader(modname)) 100 101 # The 3x logic calling this will not know what to do with the result, it is compacted away at the end 102 nil 103 end 104 end.flatten().compact() # flatten since node definition may have returned an array 105 # Compact since 4x definitions are not understood by compiler 106 end
Returns true if this Program
only contains definitions
# File lib/puppet/parser/ast/pops_bridge.rb 120 def is_definitions_only? 121 is_definition?(program_model) 122 end
Private Instance Methods
# File lib/puppet/parser/ast/pops_bridge.rb 237 def absolute_reference(ref) 238 if ref.nil? || ref.empty? || ref.start_with?('::') 239 ref 240 else 241 "::#{ref}" 242 end 243 end
Produces a hash with data for Definition and HostClass
# File lib/puppet/parser/ast/pops_bridge.rb 187 def args_from_definition(o, modname, expr_class = Expression) 188 args = { 189 :arguments => o.parameters.collect {|p| instantiate_Parameter(p) }, 190 :argument_types => create_type_map(o), 191 :module_name => modname 192 } 193 unless is_nop?(o.body) 194 args[:code] = expr_class.new(:value => o.body) 195 end 196 @ast_transformer.merge_location(args, o) 197 end
# File lib/puppet/parser/ast/pops_bridge.rb 229 def code() 230 Expression.new(:value => @value) 231 end
# File lib/puppet/parser/ast/pops_bridge.rb 148 def create_type_map(definition) 149 result = {} 150 # No need to do anything if there are no parameters 151 return result unless definition.parameters.size > 0 152 153 # No need to do anything if there are no typed parameters 154 typed_parameters = definition.parameters.select {|p| p.type_expr } 155 return result if typed_parameters.empty? 156 157 # If there are typed parameters, they need to be evaluated to produce the corresponding type 158 # instances. This evaluation requires a scope. A scope is not available when doing deserialization 159 # (there is also no initialized evaluator). When running apply and test however, the environment is 160 # reused and we may reenter without a scope (which is fine). A debug message is then output in case 161 # there is the need to track down the odd corner case. See {#obtain_scope}. 162 # 163 scope = obtain_scope 164 if scope 165 evaluator = Puppet::Pops::Parser::EvaluatingParser.singleton 166 typed_parameters.each do |p| 167 result[p.name] = evaluator.evaluate(scope, p.type_expr) 168 end 169 end 170 result 171 end
# File lib/puppet/parser/ast/pops_bridge.rb 199 def instantiate_HostClassDefinition(o, modname) 200 args = args_from_definition(o, modname, ExpressionSupportingReturn) 201 args[:parent] = absolute_reference(o.parent_class) 202 Puppet::Resource::Type.new(:hostclass, o.name, @context.merge(args)) 203 end
# File lib/puppet/parser/ast/pops_bridge.rb 211 def instantiate_NodeDefinition(o, modname) 212 args = { :module_name => modname } 213 214 unless is_nop?(o.body) 215 args[:code] = Expression.new(:value => o.body) 216 end 217 218 unless is_nop?(o.parent) 219 args[:parent] = @ast_transformer.hostname(o.parent) 220 end 221 args = @ast_transformer.merge_location(args, o) 222 223 host_matches = @ast_transformer.hostname(o.host_matches) 224 host_matches.collect do |name| 225 Puppet::Resource::Type.new(:node, name, @context.merge(args)) 226 end 227 end
# File lib/puppet/parser/ast/pops_bridge.rb 139 def instantiate_Parameter(o) 140 # 3x needs parameters as an array of `[name]` or `[name, value_expr]` 141 if o.value 142 [o.name, Expression.new(:value => o.value)] 143 else 144 [o.name] 145 end 146 end
# File lib/puppet/parser/ast/pops_bridge.rb 205 def instantiate_ResourceTypeDefinition(o, modname) 206 instance = Puppet::Resource::Type.new(:definition, o.name, @context.merge(args_from_definition(o, modname, ExpressionSupportingReturn))) 207 Puppet::Pops::Loaders.register_runtime3_type(instance.name, o.locator.to_uri(o)) 208 instance 209 end
# File lib/puppet/parser/ast/pops_bridge.rb 126 def is_definition?(o) 127 case o 128 when Puppet::Pops::Model::Program 129 is_definition?(o.body) 130 when Puppet::Pops::Model::BlockExpression 131 o.statements.all {|s| is_definition?(s) } 132 when Puppet::Pops::Model::Definition 133 true 134 else 135 false 136 end 137 end
# File lib/puppet/parser/ast/pops_bridge.rb 233 def is_nop?(o) 234 @ast_transformer.is_nop?(o) 235 end
Obtains the scope or issues a warning if :global_scope is not bound
# File lib/puppet/parser/ast/pops_bridge.rb 174 def obtain_scope 175 scope = Puppet.lookup(:global_scope) do 176 # This occurs when testing and when applying a catalog (there is no scope available then), and 177 # when running tests that run a partial setup. 178 # This is bad if the logic is trying to compile, but a warning can not be issues since it is a normal 179 # use case that there is no scope when requesting the type in order to just get the parameters. 180 Puppet.debug {_("Instantiating Resource with type checked parameters - scope is missing, skipping type checking.")} 181 nil 182 end 183 scope 184 end