puppet 4.3.1 → 4.3.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.

Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/ext/build_defaults.yaml +1 -1
  3. data/lib/hiera/scope.rb +1 -1
  4. data/lib/puppet/application/lookup.rb +41 -43
  5. data/lib/puppet/data_providers/lookup_adapter.rb +73 -26
  6. data/lib/puppet/functions/lookup.rb +126 -150
  7. data/lib/puppet/functions/match.rb +1 -0
  8. data/lib/puppet/indirector/hiera.rb +3 -1
  9. data/lib/puppet/indirector/indirection.rb +6 -2
  10. data/lib/puppet/indirector/json.rb +2 -2
  11. data/lib/puppet/module.rb +3 -2
  12. data/lib/puppet/node.rb +11 -2
  13. data/lib/puppet/parser/compiler.rb +1 -8
  14. data/lib/puppet/parser/functions/lookup.rb +128 -149
  15. data/lib/puppet/parser/functions/match.rb +1 -0
  16. data/lib/puppet/plugins/data_providers/data_provider.rb +3 -2
  17. data/lib/puppet/pops/adapters.rb +43 -0
  18. data/lib/puppet/pops/evaluator/access_operator.rb +3 -3
  19. data/lib/puppet/pops/evaluator/closure.rb +51 -51
  20. data/lib/puppet/pops/evaluator/collector_transformer.rb +16 -0
  21. data/lib/puppet/pops/evaluator/runtime3_support.rb +11 -2
  22. data/lib/puppet/pops/functions/function.rb +6 -2
  23. data/lib/puppet/pops/issues.rb +16 -0
  24. data/lib/puppet/pops/loader/puppet_function_instantiator.rb +3 -2
  25. data/lib/puppet/pops/lookup.rb +3 -0
  26. data/lib/puppet/pops/lookup/explainer.rb +73 -3
  27. data/lib/puppet/pops/lookup/invocation.rb +21 -19
  28. data/lib/puppet/pops/model/factory.rb +153 -155
  29. data/lib/puppet/pops/model/model.rb +9 -0
  30. data/lib/puppet/pops/model/model_label_provider.rb +1 -0
  31. data/lib/puppet/pops/parser/evaluating_parser.rb +3 -3
  32. data/lib/puppet/pops/parser/lexer2.rb +411 -393
  33. data/lib/puppet/pops/parser/slurp_support.rb +5 -1
  34. data/lib/puppet/pops/types/type_calculator.rb +2 -6
  35. data/lib/puppet/pops/types/types.rb +3 -9
  36. data/lib/puppet/pops/validation/checker4_0.rb +36 -12
  37. data/lib/puppet/provider/group/windows_adsi.rb +2 -2
  38. data/lib/puppet/provider/package/pip.rb +11 -1
  39. data/lib/puppet/provider/package/rpm.rb +0 -1
  40. data/lib/puppet/provider/package/yum.rb +1 -1
  41. data/lib/puppet/provider/service/debian.rb +5 -18
  42. data/lib/puppet/provider/service/init.rb +7 -0
  43. data/lib/puppet/provider/service/launchd.rb +6 -0
  44. data/lib/puppet/provider/service/systemd.rb +1 -1
  45. data/lib/puppet/provider/user/windows_adsi.rb +2 -2
  46. data/lib/puppet/provider/yumrepo/inifile.rb +6 -3
  47. data/lib/puppet/resource/type.rb +2 -1
  48. data/lib/puppet/transaction/additional_resource_generator.rb +17 -3
  49. data/lib/puppet/type/group.rb +6 -2
  50. data/lib/puppet/util/windows.rb +4 -0
  51. data/lib/puppet/util/windows/adsi.rb +61 -24
  52. data/lib/puppet/util/windows/principal.rb +181 -0
  53. data/lib/puppet/util/windows/registry.rb +21 -15
  54. data/lib/puppet/util/windows/sid.rb +42 -11
  55. data/lib/puppet/version.rb +1 -1
  56. data/spec/fixtures/unit/application/environments/production/data/common.yaml +4 -0
  57. data/spec/fixtures/unit/application/environments/production/manifests/site.pp +1 -0
  58. data/spec/fixtures/unit/application/environments/puppet_func_provider/environment.conf +1 -0
  59. data/spec/fixtures/unit/application/environments/puppet_func_provider/functions/data.pp +10 -0
  60. data/spec/fixtures/unit/application/environments/puppet_func_provider/manifests/site.pp +1 -0
  61. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/data/common.yaml +4 -0
  62. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/data/specific.yaml +4 -0
  63. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/hiera.yaml +7 -0
  64. data/spec/fixtures/unit/data_providers/environments/hiera_modules/data/common.yaml +4 -0
  65. data/spec/fixtures/unit/data_providers/environments/hiera_modules/data/specific.yaml +4 -0
  66. data/spec/fixtures/unit/data_providers/environments/hiera_modules/environment.conf +2 -0
  67. data/spec/fixtures/unit/data_providers/environments/hiera_modules/hiera.yaml +7 -0
  68. data/spec/fixtures/unit/data_providers/environments/hiera_modules/manifests/site.pp +1 -0
  69. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/data/common.yaml +6 -0
  70. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/hiera.yaml +5 -0
  71. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/manifests/init.pp +2 -0
  72. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/metadata.json +9 -0
  73. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/data/common.yaml +4 -0
  74. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/hiera.yaml +5 -0
  75. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/manifests/init.pp +3 -0
  76. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/metadata.json +9 -0
  77. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/functions/usee_puppet.pp +3 -0
  78. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/{usee → modules/usee}/lib/puppet/functions/usee/callee.rb +0 -0
  79. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/lib/puppet/functions/usee/usee_ruby.rb +6 -0
  80. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/manifests/init.pp +6 -0
  81. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee2/lib/puppet/functions/usee2/callee.rb +5 -0
  82. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/functions/puppet_calling_puppet.pp +5 -0
  83. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/functions/puppet_calling_puppet_init.pp +5 -0
  84. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/functions/puppet_calling_ruby.pp +5 -0
  85. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/{user → modules/user}/lib/puppet/functions/user/caller.rb +0 -0
  86. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/caller2.rb +5 -0
  87. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/ruby_calling_puppet.rb +5 -0
  88. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/ruby_calling_puppet_init.rb +5 -0
  89. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/ruby_calling_ruby.rb +5 -0
  90. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/manifests/init.pp +81 -0
  91. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/{user → modules/user}/metadata.json +2 -1
  92. data/spec/integration/parser/collection_spec.rb +8 -0
  93. data/spec/integration/util/windows/principal_spec.rb +115 -0
  94. data/spec/{unit → integration}/util/windows/registry_spec.rb +91 -1
  95. data/spec/integration/util/windows/security_spec.rb +2 -2
  96. data/spec/unit/application/lookup_spec.rb +138 -28
  97. data/spec/unit/data_providers/hiera_data_provider_spec.rb +182 -5
  98. data/spec/unit/face/epp_face_spec.rb +2 -2
  99. data/spec/unit/functions/epp_spec.rb +6 -6
  100. data/spec/unit/functions/inline_epp_spec.rb +4 -4
  101. data/spec/unit/functions/lookup_spec.rb +30 -3
  102. data/spec/unit/functions4_spec.rb +1 -1
  103. data/spec/unit/hiera/scope_spec.rb +5 -2
  104. data/spec/unit/indirector/json_spec.rb +1 -1
  105. data/spec/unit/node_spec.rb +8 -0
  106. data/spec/unit/parser/compiler_spec.rb +0 -18
  107. data/spec/unit/pops/evaluator/access_ops_spec.rb +4 -4
  108. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +1 -1
  109. data/spec/unit/pops/loaders/loaders_spec.rb +84 -2
  110. data/spec/unit/pops/parser/lexer2_spec.rb +6 -0
  111. data/spec/unit/pops/parser/parser_rspec_helper.rb +5 -0
  112. data/spec/unit/pops/types/type_calculator_spec.rb +0 -17
  113. data/spec/unit/pops/validator/validator_spec.rb +87 -0
  114. data/spec/unit/provider/group/windows_adsi_spec.rb +8 -8
  115. data/spec/unit/provider/package/pip_spec.rb +41 -13
  116. data/spec/unit/provider/package/rpm_spec.rb +2 -25
  117. data/spec/unit/provider/package/yum_spec.rb +1 -1
  118. data/spec/unit/provider/service/debian_spec.rb +6 -24
  119. data/spec/unit/provider/service/init_spec.rb +11 -1
  120. data/spec/unit/provider/service/launchd_spec.rb +11 -0
  121. data/spec/unit/provider/service/systemd_spec.rb +18 -12
  122. data/spec/unit/provider/service/upstart_spec.rb +57 -0
  123. data/spec/unit/provider/user/windows_adsi_spec.rb +5 -5
  124. data/spec/unit/provider/yumrepo/inifile_spec.rb +16 -0
  125. data/spec/unit/resource_spec.rb +12 -2
  126. data/spec/unit/util/windows/adsi_spec.rb +44 -36
  127. data/spec/unit/util/windows/sid_spec.rb +47 -10
  128. metadata +77 -10
@@ -23,6 +23,7 @@ module Puppet::Pops::Adapters
23
23
  #
24
24
  class SourcePosAdapter < Puppet::Pops::Adaptable::Adapter
25
25
  attr_accessor :locator
26
+ attr_reader :adapted
26
27
 
27
28
  def self.create_adapter(o)
28
29
  new(o)
@@ -117,5 +118,47 @@ module Puppet::Pops::Adapters
117
118
  class LoaderAdapter < Puppet::Pops::Adaptable::Adapter
118
119
  # @return [Puppet::Pops::Loader::Loader] the loader
119
120
  attr_accessor :loader
121
+
122
+ # Attempts to find the module that `instance` originates from by looking at it's {SourcePosAdapter} and
123
+ # compare the `locator.file` found there with the module paths given in the environment found in the
124
+ # given `scope`. If the file is found to be relative to a path, then the first segment of the relative
125
+ # path is interpreted as the name of a module. The object that the {SourcePosAdapter} is adapted to
126
+ # will then be adapted to the private loader for that module and that adapter is returned.
127
+ #
128
+ # The method returns `nil` when no module could be found.
129
+ #
130
+ # @param scope
131
+ # @param instance
132
+ def self.adapt_by_source(scope, instance)
133
+ source_pos = Puppet::Pops::Utils.find_adapter(instance, SourcePosAdapter)
134
+ unless source_pos.nil?
135
+ mod = find_module_for_file(scope.environment, source_pos.locator.file)
136
+ unless mod.nil?
137
+ adapter = LoaderAdapter.adapt(source_pos.adapted)
138
+ adapter.loader = scope.compiler.loaders.private_loader_for_module(mod.name)
139
+ return adapter
140
+ end
141
+ end
142
+ nil
143
+ end
144
+
145
+ def self.find_module_for_file(environment, file)
146
+ return nil if file.nil?
147
+ file_path = Pathname.new(file)
148
+ environment.modulepath.each do |path|
149
+ begin
150
+ relative_path = file_path.relative_path_from(Pathname.new(path)).to_s.split(File::SEPARATOR)
151
+ rescue ArgumentError
152
+ # file_path was not relative to the module_path. That's OK.
153
+ next
154
+ end
155
+ if relative_path.length > 1
156
+ mod = environment.module(relative_path[0])
157
+ return mod unless mod.nil?
158
+ end
159
+ end
160
+ nil
161
+ end
162
+ private_class_method :find_module_for_file
120
163
  end
121
164
  end
@@ -39,7 +39,7 @@ class Puppet::Pops::Evaluator::AccessOperator
39
39
  fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
40
40
  when 1
41
41
  # Note that Ruby 1.8.7 requires a length of 1 to produce a String
42
- k1 = coerce_numeric(keys[0], @semantic.keys, scope)
42
+ k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
43
43
  bad_access_key_type(o, 0, k1, Integer) unless k1.is_a?(Integer)
44
44
  k2 = 1
45
45
  k1 = k1 < 0 ? o.length + k1 : k1 # abs pos
@@ -50,8 +50,8 @@ class Puppet::Pops::Evaluator::AccessOperator
50
50
  o[ k1, k2 ]
51
51
  end
52
52
  when 2
53
- k1 = coerce_numeric(keys[0], @semantic.keys, scope)
54
- k2 = coerce_numeric(keys[1], @semantic.keys, scope)
53
+ k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
54
+ k2 = coerce_numeric(keys[1], @semantic.keys[1], scope)
55
55
  [k1, k2].each_with_index { |k,i| bad_access_key_type(o, i, k, Integer) unless k.is_a?(Integer) }
56
56
 
57
57
  k1 = k1 < 0 ? o.length + k1 : k1 # abs pos (negative is count from end)
@@ -54,40 +54,17 @@ class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignat
54
54
  # Call closure with argument assignment by name
55
55
  def call_by_name(args_hash, enforce_parameters)
56
56
  if enforce_parameters
57
- if args_hash.size > parameters.size
58
- raise ArgumentError, "Too many arguments: #{args_hash.size} for #{parameters.size}"
59
- end
60
-
61
- # associate values with parameters
62
- scope_hash = {}
57
+ args_hash = args_hash.dup
63
58
  parameters.each do |p|
64
59
  name = p.name
65
- if (arg_value = args_hash[name]).nil?
66
- # only set result of default expr if it is defined (it is otherwise not possible to differentiate
67
- # between explicit undef and no default expression
68
- unless p.value.nil?
69
- scope_hash[name] = @evaluator.evaluate(p.value, @enclosing_scope)
70
- end
71
- else
72
- scope_hash[name] = arg_value
73
- end
74
- end
75
-
76
- missing = parameters.select { |p| !scope_hash.include?(p.name) }
77
- if missing.any?
78
- raise ArgumentError, "Too few arguments; no value given for required parameters #{missing.collect(&:name).join(" ,")}"
79
- end
80
-
81
- tc = Puppet::Pops::Types::TypeCalculator.singleton
82
- final_args = tc.infer_set(parameter_names.collect { |param| scope_hash[param] })
83
- if !type.callable?(final_args)
84
- raise ArgumentError, Puppet::Pops::Types::TypeMismatchDescriber.describe_signatures(closure_name, [self], final_args)
60
+ # only set result of default expr if it is defined (it is otherwise not possible to differentiate
61
+ # between explicit undef and no default expression
62
+ args_hash[name] = @evaluator.evaluate(p.value, @enclosing_scope) if args_hash[name].nil? && !p.value.nil?
85
63
  end
86
- else
87
- scope_hash = args_hash
64
+ Puppet::Pops::Types::TypeMismatchDescriber.validate_parameters(closure_name, params_struct, args_hash)
88
65
  end
89
66
 
90
- @evaluator.evaluate_block_with_bindings(@enclosing_scope, scope_hash, @model.body)
67
+ @evaluator.evaluate_block_with_bindings(@enclosing_scope, args_hash, @model.body)
91
68
  end
92
69
 
93
70
  def parameters
@@ -111,6 +88,11 @@ class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignat
111
88
  @callable ||= create_callable_type
112
89
  end
113
90
 
91
+ # @api public
92
+ def params_struct
93
+ @params_struct ||= create_params_struct
94
+ end
95
+
114
96
  # @api public
115
97
  def last_captures_rest?
116
98
  last = @model.parameters[-1]
@@ -196,28 +178,7 @@ class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignat
196
178
  range = [0, 0]
197
179
  in_optional_parameters = false
198
180
  parameters.each do |param|
199
- type = if param.type_expr
200
- @evaluator.evaluate(param.type_expr, @enclosing_scope)
201
- else
202
- Puppet::Pops::Types::PAnyType::DEFAULT
203
- end
204
-
205
- if param.captures_rest && type.is_a?(Puppet::Pops::Types::PArrayType)
206
- # An array on a slurp parameter is how a size range is defined for a
207
- # slurp (Array[Integer, 1, 3] *$param). However, the callable that is
208
- # created can't have the array in that position or else type checking
209
- # will require the parameters to be arrays, which isn't what is
210
- # intended. The array type contains the intended information and needs
211
- # to be unpacked.
212
- param_range = type.size_range
213
- type = type.element_type
214
- elsif param.captures_rest && !type.is_a?(Puppet::Pops::Types::PArrayType)
215
- param_range = ANY_NUMBER_RANGE
216
- elsif param.value
217
- param_range = OPTIONAL_SINGLE_RANGE
218
- else
219
- param_range = REQUIRED_SINGLE_RANGE
220
- end
181
+ type, param_range = create_param_type(param)
221
182
 
222
183
  types << type
223
184
 
@@ -238,6 +199,45 @@ class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignat
238
199
  Puppet::Pops::Types::TypeFactory.callable(*(types + range))
239
200
  end
240
201
 
202
+ def create_params_struct
203
+ type_factory = Puppet::Pops::Types::TypeFactory
204
+ members = {}
205
+
206
+ parameters.each do |param|
207
+ arg_type, param_range = create_param_type(param)
208
+ key_type = type_factory.string(nil, param.name.to_s)
209
+ key_type = type_factory.optional(key_type) unless param.value.nil?
210
+ members[key_type] = arg_type
211
+ end
212
+ type_factory.struct(members)
213
+ end
214
+
215
+ def create_param_type(param)
216
+ type = if param.type_expr
217
+ @evaluator.evaluate(param.type_expr, @enclosing_scope)
218
+ else
219
+ Puppet::Pops::Types::PAnyType::DEFAULT
220
+ end
221
+
222
+ if param.captures_rest && type.is_a?(Puppet::Pops::Types::PArrayType)
223
+ # An array on a slurp parameter is how a size range is defined for a
224
+ # slurp (Array[Integer, 1, 3] *$param). However, the callable that is
225
+ # created can't have the array in that position or else type checking
226
+ # will require the parameters to be arrays, which isn't what is
227
+ # intended. The array type contains the intended information and needs
228
+ # to be unpacked.
229
+ param_range = type.size_range
230
+ type = type.element_type
231
+ elsif param.captures_rest && !type.is_a?(Puppet::Pops::Types::PArrayType)
232
+ param_range = ANY_NUMBER_RANGE
233
+ elsif param.value
234
+ param_range = OPTIONAL_SINGLE_RANGE
235
+ else
236
+ param_range = REQUIRED_SINGLE_RANGE
237
+ end
238
+ [type, param_range]
239
+ end
240
+
241
241
  # Produces information about parameters compatible with a 4x Function (which can have multiple signatures)
242
242
  def signatures
243
243
  [ self ]
@@ -125,6 +125,14 @@ protected
125
125
  end
126
126
  end
127
127
 
128
+ def query_AccessExpression(o, scope)
129
+ pops_object = @@evaluator.evaluate(o, scope)
130
+
131
+ # Convert to Puppet 3 style objects since that is how they are represented
132
+ # in the catalog.
133
+ @@evaluator.convert(pops_object, scope, nil)
134
+ end
135
+
128
136
  def query_VariableExpression(o, scope)
129
137
  @@evaluator.evaluate(o, scope)
130
138
  end
@@ -157,6 +165,14 @@ protected
157
165
  raise ArgumentError, "Cannot transform object of class #{o.class}"
158
166
  end
159
167
 
168
+ def match_AccessExpression(o, scope)
169
+ pops_object = @@evaluator.evaluate(o, scope)
170
+
171
+ # Convert to Puppet 3 style objects since that is how they are represented
172
+ # in the catalog.
173
+ @@evaluator.convert(pops_object, scope, nil)
174
+ end
175
+
160
176
  def match_AndExpression(o, scope)
161
177
  left_match = match(o.left_expr, scope)
162
178
  right_match = match(o.right_expr, scope)
@@ -248,7 +248,9 @@ module Puppet::Pops::Evaluator::Runtime3Support
248
248
  # this is done from the perspective of the environment.
249
249
  loader = loaders.private_environment_loader
250
250
  if loader && func = loader.load(:function, name)
251
- return func.call(scope, *args, &block)
251
+ Puppet::Util::Profiler.profile(name, [:functions, name]) do
252
+ return func.call(scope, *args, &block)
253
+ end
252
254
  end
253
255
 
254
256
  # Call via 3x API if function exists there
@@ -267,9 +269,16 @@ module Puppet::Pops::Evaluator::Runtime3Support
267
269
  loaders = scope.compiler.loaders
268
270
  # find the loader that loaded the code, or use the private_environment_loader (sees env + all modules)
269
271
  adapter = Puppet::Pops::Utils.find_adapter(o, Puppet::Pops::Adapters::LoaderAdapter)
272
+
273
+ # Use source location to determine calling module, or use the private_environment_loader (sees env + all modules)
274
+ # This is necessary since not all .pp files are loaded by a Puppet::Pops::Loader (see PUP-1833)
275
+ adapter ||= Puppet::Pops::Adapters::LoaderAdapter.adapt_by_source(scope, o)
276
+
270
277
  loader = adapter.nil? ? loaders.private_environment_loader : adapter.loader
271
278
  if loader && func = loader.load(:function, name)
272
- return func.call(scope, *args, &block)
279
+ Puppet::Util::Profiler.profile(name, [:functions, name]) do
280
+ return func.call(scope, *args, &block)
281
+ end
273
282
  end
274
283
 
275
284
  # Call via 3x API if function exists there
@@ -89,13 +89,17 @@ class Puppet::Pops::Functions::Function
89
89
  raise ArgumentError, "Function #{self.class.name}(): cannot call function '#{function_name}' - no loader specified" unless the_loader
90
90
 
91
91
  func = the_loader.load(:function, function_name)
92
- return func.call(scope, *args, &block) if func
92
+ if func
93
+ Puppet::Util::Profiler.profile(function_name, [:functions, function_name]) do
94
+ return func.call(scope, *args, &block)
95
+ end
96
+ end
93
97
 
94
98
  # Check if a 3x function is present. Raise a generic error if it's not to allow upper layers to fill in the details
95
99
  # about where in a puppet manifest this error originates. (Such information is not available here).
96
100
  loader_scope = closure_scope
97
101
  func_3x = Puppet::Parser::Functions.function(function_name, loader_scope.environment) if loader_scope.is_a?(Puppet::Parser::Scope)
98
- raise ArgumentError, "Function #{self.class.name}(): cannot call function '#{function_name}' - not found" unless func_3x
102
+ raise ArgumentError, "Function #{self.class.name}(): Unknown function: '#{function_name}'" unless func_3x
99
103
 
100
104
  # Call via 3x API
101
105
  # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
@@ -151,6 +151,10 @@ module Puppet::Pops::Issues
151
151
  "Classes, definitions, and nodes may only appear at toplevel or inside other classes"
152
152
  end
153
153
 
154
+ NOT_ABSOLUTE_TOP_LEVEL = hard_issue :NOT_ABSOLUTE_TOP_LEVEL do
155
+ "#{label.a_an_uc(semantic)} may only appear at toplevel"
156
+ end
157
+
154
158
  CROSS_SCOPE_ASSIGNMENT = hard_issue :CROSS_SCOPE_ASSIGNMENT, :name do
155
159
  "Illegal attempt to assign to '#{name}'. Cannot assign to variables in other namespaces"
156
160
  end
@@ -536,6 +540,10 @@ module Puppet::Pops::Issues
536
540
  "This #{label.label(semantic)} has no effect. A value was produced and then forgotten (one or more preceding expressions may have the wrong form)"
537
541
  end
538
542
 
543
+ RESOURCE_WITHOUT_TITLE = issue :RESOURCE_WITHOUT_TITLE, :name do
544
+ "This expression is invalid. Did you try declaring a '#{name}' resource without a title?"
545
+ end
546
+
539
547
  IDEM_NOT_ALLOWED_LAST = hard_issue :IDEM_NOT_ALLOWED_LAST, :container do
540
548
  "This #{label.label(semantic)} has no effect. #{label.a_an_uc(container)} can not end with a value-producing expression without other effect"
541
549
  end
@@ -564,6 +572,10 @@ module Puppet::Pops::Issues
564
572
  "Resource Override can only operate on resources, got: #{label.label(actual)}"
565
573
  end
566
574
 
575
+ DUPLICATE_PARAMETER = hard_issue :DUPLICATE_PARAMETER, :param_name do
576
+ "The parameter '#{param_name}' is declared more than once in the parameter list"
577
+ end
578
+
567
579
  RESERVED_PARAMETER = hard_issue :RESERVED_PARAMETER, :container, :param_name do
568
580
  "The parameter $#{param_name} redefines a built in parameter in #{label.the(container)}"
569
581
  end
@@ -632,6 +644,10 @@ module Puppet::Pops::Issues
632
644
  "Unclosed quote after #{after} followed by '#{followed_by}'"
633
645
  end
634
646
 
647
+ UNCLOSED_MLCOMMENT = hard_issue :UNCLOSED_MLCOMMENT do
648
+ 'Unclosed multiline comment'
649
+ end
650
+
635
651
  EPP_INTERNAL_ERROR = hard_issue :EPP_INTERNAL_ERROR, :error do
636
652
  "Internal error: #{error}"
637
653
  end
@@ -43,7 +43,8 @@ class Puppet::Pops::Loader::PuppetFunctionInstantiator
43
43
  # Adapt the function definition with loader - this is used from logic contained in it body to find the
44
44
  # loader to use when making calls to the new function API. Such logic have a hard time finding the closure (where
45
45
  # the loader is known - hence this mechanism
46
- Puppet::Pops::Adapters::LoaderAdapter.adapt(the_function_definition).loader = loader
46
+ private_loader = loader.private_loader
47
+ Puppet::Pops::Adapters::LoaderAdapter.adapt(the_function_definition).loader = private_loader
47
48
 
48
49
  # TODO: Cheating wrt. scope - assuming it is found in the context
49
50
  closure_scope = Puppet.lookup(:global_scope) { {} }
@@ -53,7 +54,7 @@ class Puppet::Pops::Loader::PuppetFunctionInstantiator
53
54
  # when calling functions etc.
54
55
  # It should be bound to global scope
55
56
 
56
- created.new(closure_scope, loader)
57
+ created.new(closure_scope, private_loader)
57
58
  end
58
59
 
59
60
  # Creates Function class and instantiates it based on a FunctionDefinition model
@@ -2,6 +2,9 @@
2
2
  # See puppet/functions/lookup.rb for documentation.
3
3
  #
4
4
  module Puppet::Pops::Lookup
5
+ LOOKUP_OPTIONS = 'lookup_options'.freeze
6
+ GLOBAL = '__global__'.freeze
7
+
5
8
  # Performs a lookup in the configured scopes and optionally merges the default.
6
9
  #
7
10
  # This is a backing function and all parameters are assumed to have been type checked.
@@ -28,7 +28,8 @@ module Puppet::Pops::Lookup
28
28
  end
29
29
 
30
30
  class ExplainTreeNode < ExplainNode
31
- attr_reader :parent, :event, :key, :value
31
+ attr_reader :parent, :event, :value
32
+ attr_accessor :key
32
33
 
33
34
  def initialize(parent)
34
35
  @parent = parent
@@ -133,6 +134,55 @@ module Puppet::Pops::Lookup
133
134
  end
134
135
  end
135
136
 
137
+ class ExplainTop < ExplainTreeNode
138
+ def initialize(parent, type, key)
139
+ super(parent)
140
+ @type = type
141
+ self.key = key
142
+ end
143
+
144
+ def dump_on(io, indent, first_indent)
145
+ io << first_indent << 'Searching for "' << key << "\"\n"
146
+ indent = increase_indent(indent)
147
+ branches.each {|b| b.dump_on(io, indent, indent)}
148
+ end
149
+ end
150
+
151
+ class ExplainInvalidKey < ExplainTreeNode
152
+ def initialize(parent, key)
153
+ super(parent)
154
+ @key = key
155
+ end
156
+
157
+ def dump_on(io, indent, first_indent)
158
+ io << first_indent << "Invalid key \"" << @key << "\"\n"
159
+ end
160
+
161
+ def type
162
+ :invalid_key
163
+ end
164
+ end
165
+
166
+ class ExplainMergeSource < ExplainNode
167
+ attr_reader :merge_source
168
+
169
+ def initialize(merge_source)
170
+ @merge_source = merge_source
171
+ end
172
+
173
+ def dump_on(io, indent, first_indent)
174
+ io << first_indent << 'Using merge options from "' << merge_source << "\" hash\n"
175
+ end
176
+
177
+ def to_hash
178
+ { :type => type, :merge_source => merge_source }
179
+ end
180
+
181
+ def type
182
+ :merge_source
183
+ end
184
+ end
185
+
136
186
  class ExplainInterpolate < ExplainTreeNode
137
187
  def initialize(parent, expression)
138
188
  super(parent)
@@ -163,6 +213,8 @@ module Puppet::Pops::Lookup
163
213
  end
164
214
 
165
215
  def dump_on(io, indent, first_indent)
216
+ return if branches.size == 0
217
+
166
218
  # It's pointless to report a merge where there's only one branch
167
219
  return branches[0].dump_on(io, indent, first_indent) if branches.size == 1
168
220
 
@@ -297,7 +349,7 @@ module Puppet::Pops::Lookup
297
349
  def dump_on(io, indent, first_indent)
298
350
  io << indent << 'Path "' << @path.path << "\"\n"
299
351
  indent = increase_indent(indent)
300
- io << indent << 'Original path: ' << @path.original_path << "\n"
352
+ io << indent << 'Original path: "' << @path.original_path << "\"\n"
301
353
  branches.each {|b| b.dump_on(io, indent, indent)}
302
354
  io << indent << "Path not found\n" if @event == :path_not_found
303
355
  dump_outcome(io, indent)
@@ -332,8 +384,10 @@ module Puppet::Pops::Lookup
332
384
  end
333
385
 
334
386
  class Explainer < ExplainNode
335
- def initialize
387
+ def initialize(explain_options = false, only_explain_options = false)
336
388
  @current = self
389
+ @explain_options = explain_options
390
+ @only_explain_options = only_explain_options
337
391
  end
338
392
 
339
393
  def push(qualifier_type, qualifier)
@@ -352,6 +406,10 @@ module Puppet::Pops::Lookup
352
406
  ExplainMerge.new(@current, qualifier)
353
407
  when :scope
354
408
  ExplainScope.new(@current)
409
+ when :meta, :data
410
+ ExplainTop.new(@current, qualifier_type, qualifier)
411
+ when :invalid_key
412
+ ExplainInvalidKey.new(@current, qualifier)
355
413
  else
356
414
  raise ArgumentError, "Unknown Explain type #{qualifier_type}"
357
415
  end
@@ -359,6 +417,14 @@ module Puppet::Pops::Lookup
359
417
  @current = node
360
418
  end
361
419
 
420
+ def only_explain_options?
421
+ @only_explain_options
422
+ end
423
+
424
+ def explain_options?
425
+ @explain_options
426
+ end
427
+
362
428
  def pop
363
429
  @current = @current.parent unless @current.parent.nil?
364
430
  end
@@ -375,6 +441,10 @@ module Puppet::Pops::Lookup
375
441
  @current.found(key, value)
376
442
  end
377
443
 
444
+ def accept_merge_source(merge_source)
445
+ @current.branches << ExplainMergeSource.new(merge_source)
446
+ end
447
+
378
448
  def accept_not_found(key)
379
449
  @current.not_found(key)
380
450
  end