puppet 3.7.4 → 3.7.5

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +11 -6
  3. data/ext/build_defaults.yaml +2 -2
  4. data/ext/systemd/puppet.service +1 -0
  5. data/lib/hiera/puppet_function.rb +71 -0
  6. data/lib/puppet.rb +12 -0
  7. data/lib/puppet/application/device.rb +22 -5
  8. data/lib/puppet/daemon.rb +13 -4
  9. data/lib/puppet/defaults.rb +27 -4
  10. data/lib/puppet/environments.rb +1 -1
  11. data/lib/puppet/error.rb +4 -0
  12. data/lib/puppet/functions.rb +118 -65
  13. data/lib/puppet/functions/assert_type.rb +5 -5
  14. data/lib/puppet/functions/each.rb +12 -12
  15. data/lib/puppet/functions/epp.rb +3 -4
  16. data/lib/puppet/functions/filter.rb +12 -12
  17. data/lib/puppet/functions/hiera.rb +29 -0
  18. data/lib/puppet/functions/hiera_array.rb +34 -0
  19. data/lib/puppet/functions/hiera_hash.rb +36 -0
  20. data/lib/puppet/functions/hiera_include.rb +50 -0
  21. data/lib/puppet/functions/inline_epp.rb +2 -3
  22. data/lib/puppet/functions/map.rb +12 -12
  23. data/lib/puppet/functions/reduce.rb +6 -6
  24. data/lib/puppet/functions/scanf.rb +3 -3
  25. data/lib/puppet/functions/slice.rb +10 -9
  26. data/lib/puppet/functions/with.rb +3 -4
  27. data/lib/puppet/graph/simple_graph.rb +5 -5
  28. data/lib/puppet/metatype/manager.rb +1 -1
  29. data/lib/puppet/node/environment.rb +1 -1
  30. data/lib/puppet/parser/ast/arithmetic_operator.rb +1 -1
  31. data/lib/puppet/parser/ast/collexpr.rb +1 -1
  32. data/lib/puppet/parser/compiler.rb +3 -3
  33. data/lib/puppet/parser/functions/create_resources.rb +1 -9
  34. data/lib/puppet/parser/functions/defined.rb +1 -1
  35. data/lib/puppet/parser/functions/hiera.rb +20 -11
  36. data/lib/puppet/parser/functions/hiera_array.rb +23 -13
  37. data/lib/puppet/parser/functions/hiera_hash.rb +25 -15
  38. data/lib/puppet/parser/functions/hiera_include.rb +20 -9
  39. data/lib/puppet/parser/functions/lookup.rb +1 -1
  40. data/lib/puppet/parser/functions/realize.rb +1 -1
  41. data/lib/puppet/parser/functions/scanf.rb +21 -12
  42. data/lib/puppet/parser/parser_factory.rb +2 -2
  43. data/lib/puppet/parser/relationship.rb +1 -1
  44. data/lib/puppet/parser/scope.rb +34 -7
  45. data/lib/puppet/pops.rb +2 -0
  46. data/lib/puppet/pops/binder/lookup.rb +24 -7
  47. data/lib/puppet/pops/binder/producers.rb +2 -2
  48. data/lib/puppet/pops/evaluator/closure.rb +1 -1
  49. data/lib/puppet/pops/evaluator/evaluator_impl.rb +109 -17
  50. data/lib/puppet/pops/evaluator/puppet_proc.rb +69 -0
  51. data/lib/puppet/pops/evaluator/runtime3_converter.rb +175 -0
  52. data/lib/puppet/pops/evaluator/runtime3_support.rb +15 -128
  53. data/lib/puppet/pops/functions/dispatch.rb +21 -17
  54. data/lib/puppet/pops/functions/dispatcher.rb +3 -3
  55. data/lib/puppet/pops/functions/function.rb +46 -14
  56. data/lib/puppet/pops/issues.rb +2 -2
  57. data/lib/puppet/pops/model/model_label_provider.rb +1 -1
  58. data/lib/puppet/pops/parser/egrammar.ra +2 -0
  59. data/lib/puppet/pops/parser/eparser.rb +732 -724
  60. data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
  61. data/lib/puppet/pops/parser/lexer2.rb +20 -22
  62. data/lib/puppet/pops/types/class_loader.rb +1 -1
  63. data/lib/puppet/pops/types/type_calculator.rb +104 -37
  64. data/lib/puppet/pops/types/type_factory.rb +1 -1
  65. data/lib/puppet/pops/types/types.rb +4 -1
  66. data/lib/puppet/pops/types/types_meta.rb +2 -2
  67. data/lib/puppet/pops/validation/checker4_0.rb +5 -3
  68. data/lib/puppet/provider/service/systemd.rb +1 -0
  69. data/lib/puppet/provider/yumrepo/inifile.rb +4 -1
  70. data/lib/puppet/resource.rb +3 -2
  71. data/lib/puppet/resource/catalog.rb +3 -2
  72. data/lib/puppet/resource/type.rb +1 -1
  73. data/lib/puppet/settings/environment_conf.rb +12 -4
  74. data/lib/puppet/type/package.rb +23 -13
  75. data/lib/puppet/util/autoload.rb +7 -7
  76. data/lib/puppet/util/errors.rb +4 -2
  77. data/lib/puppet/util/network_device/config.rb +5 -0
  78. data/lib/puppet/version.rb +1 -1
  79. data/lib/puppetx.rb +2 -2
  80. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee.rb +8 -0
  81. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee_ws.rb +8 -0
  82. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/metadata.json +9 -0
  83. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller.rb +5 -0
  84. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller_ws.rb +12 -0
  85. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/metadata.json +9 -0
  86. data/spec/integration/parser/environment_spec.rb +47 -0
  87. data/spec/integration/parser/future_compiler_spec.rb +11 -6
  88. data/spec/unit/application/device_spec.rb +52 -14
  89. data/spec/unit/daemon_spec.rb +0 -2
  90. data/spec/unit/environments_spec.rb +2 -2
  91. data/spec/unit/functions/assert_type_spec.rb +4 -25
  92. data/spec/unit/functions/hiera_spec.rb +127 -0
  93. data/spec/unit/functions/with_spec.rb +9 -4
  94. data/spec/unit/functions4_spec.rb +98 -35
  95. data/spec/unit/hiera/backend/puppet_backend_spec.rb +1 -1
  96. data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
  97. data/spec/unit/parser/functions/defined_spec.rb +5 -0
  98. data/spec/unit/parser/functions/lookup_spec.rb +5 -1
  99. data/spec/unit/parser/functions/scanf_spec.rb +30 -0
  100. data/spec/unit/parser/scope_spec.rb +5 -0
  101. data/spec/unit/pops/binder/injector_spec.rb +1 -1
  102. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +33 -5
  103. data/spec/unit/pops/loaders/loaders_spec.rb +22 -1
  104. data/spec/unit/pops/parser/lexer2_spec.rb +28 -16
  105. data/spec/unit/pops/parser/parse_heredoc_spec.rb +21 -0
  106. data/spec/unit/pops/types/type_calculator_spec.rb +141 -19
  107. data/spec/unit/pops/types/type_factory_spec.rb +2 -2
  108. data/spec/unit/pops/validator/validator_spec.rb +25 -3
  109. data/spec/unit/provider/service/systemd_spec.rb +20 -4
  110. data/spec/unit/provider/user/hpux_spec.rb +1 -1
  111. data/spec/unit/provider/yumrepo/inifile_spec.rb +1 -0
  112. data/spec/unit/settings/environment_conf_spec.rb +12 -1
  113. data/spec/unit/type/package_spec.rb +0 -20
  114. data/spec/unit/util/network_device/config_spec.rb +6 -0
  115. metadata +3422 -3405
@@ -0,0 +1,175 @@
1
+ module Puppet::Pops::Evaluator
2
+ # Converts nested 4x supported values to 3x values. This is required because
3
+ # resources and other objects do not know about the new type system, and does not support
4
+ # regular expressions. Unfortunately this has to be done for array and hash as well.
5
+ # A complication is that catalog types needs to be resolved against the scope.
6
+ #
7
+ # Users should not create instances of this class. Instead the class methods {Runtime3Converter.convert},
8
+ # {Runtime3Converter.map_args}, or {Runtime3Converter.instance} should be used
9
+ class Runtime3Converter
10
+ # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.map_args(...)
11
+ #
12
+ # @param args [Array] Array of values to convert
13
+ # @param scope [Puppet::Parser::Scope] The scope to use when converting
14
+ # @param undef_value [Object] The value that nil is converted to
15
+ # @return [Array] The converted values
16
+ #
17
+ def self.map_args(args, scope, undef_value)
18
+ @@instance.map_args(args, scope, undef_value)
19
+ end
20
+
21
+ # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.convert(...)
22
+ #
23
+ # @param o [Object]The value to convert
24
+ # @param scope [Puppet::Parser::Scope] The scope to use when converting
25
+ # @param undef_value [Object] The value that nil is converted to
26
+ # @return [Object] The converted value
27
+ #
28
+ def self.convert(o, scope, undef_value)
29
+ @@instance.convert(o, scope, undef_value)
30
+ end
31
+
32
+ # Returns the singleton instance of this class.
33
+ # @return [Runtime3Converter] The singleton instance
34
+ def self.instance
35
+ @@instance
36
+ end
37
+
38
+ # Converts 4x supported values to a 3x values.
39
+ #
40
+ # @param args [Array] Array of values to convert
41
+ # @param scope [Puppet::Parser::Scope] The scope to use when converting
42
+ # @param undef_value [Object] The value that nil is converted to
43
+ # @return [Array] The converted values
44
+ #
45
+ def map_args(args, scope, undef_value)
46
+ args.map {|a| convert(a, scope, undef_value) }
47
+ end
48
+
49
+ # Converts a 4x supported value to a 3x value.
50
+ #
51
+ # @param o [Object]The value to convert
52
+ # @param scope [Puppet::Parser::Scope] The scope to use when converting
53
+ # @param undef_value [Object] The value that nil is converted to
54
+ # @return [Object] The converted value
55
+ #
56
+ def convert(o, scope, undef_value)
57
+ @convert_visitor.visit_this_2(self, o, scope, undef_value)
58
+ end
59
+
60
+ def convert_NilClass(o, scope, undef_value)
61
+ undef_value
62
+ end
63
+
64
+ def convert2_NilClass(o, scope, undef_value)
65
+ :undef
66
+ end
67
+
68
+ def convert_String(o, scope, undef_value)
69
+ # although wasteful, needed because user code may mutate these strings in Resources
70
+ o.frozen? ? o.dup : o
71
+ end
72
+ alias convert2_String :convert_String
73
+
74
+ def convert_Object(o, scope, undef_value)
75
+ o
76
+ end
77
+ alias :convert2_Object :convert_Object
78
+
79
+ def convert_Array(o, scope, undef_value)
80
+ o.map {|x| convert2(x, scope, undef_value) }
81
+ end
82
+ alias :convert2_Array :convert_Array
83
+
84
+ def convert_Hash(o, scope, undef_value)
85
+ result = {}
86
+ o.each {|k,v| result[convert2(k, scope, undef_value)] = convert2(v, scope, undef_value) }
87
+ result
88
+ end
89
+ alias :convert2_Hash :convert_Hash
90
+
91
+ def convert_Regexp(o, scope, undef_value)
92
+ # Puppet 3x cannot handle parameter values that are reqular expressions. Turn into regexp string in
93
+ # source form
94
+ o.inspect
95
+ end
96
+ alias :convert2_Regexp :convert_Regexp
97
+
98
+ def convert_Symbol(o, scope, undef_value)
99
+ case o
100
+ # Support :undef since it may come from a 3x structure
101
+ when :undef
102
+ undef_value # 3x wants undef as either empty string or :undef
103
+ else
104
+ o # :default, and all others are verbatim since they are new in future evaluator
105
+ end
106
+ end
107
+
108
+ # The :undef symbol should not be converted when nested in arrays or hashes
109
+ def convert2_Symbol(o, scope, undef_value)
110
+ o
111
+ end
112
+
113
+ def convert_PAnyType(o, scope, undef_value)
114
+ o
115
+ end
116
+ alias :convert2_PAnyType :convert_PAnyType
117
+
118
+ def convert_PCatalogEntryType(o, scope, undef_value)
119
+ # Since 4x does not support dynamic scoping, all names are absolute and can be
120
+ # used as is (with some check/transformation/mangling between absolute/relative form
121
+ # due to Puppet::Resource's idiosyncratic behavior where some references must be
122
+ # absolute and others cannot be.
123
+ # Thus there is no need to call scope.resolve_type_and_titles to do dynamic lookup.
124
+
125
+ Puppet::Resource.new(*catalog_type_to_split_type_title(o))
126
+ end
127
+ alias :convert2_PCatalogEntryType :convert_PCatalogEntryType
128
+
129
+ # Produces an array with [type, title] from a PCatalogEntryType
130
+ # This method is used to produce the arguments for creation of reference resource instances
131
+ # (used when 3x is operating on a resource).
132
+ # Ensures that resources are *not* absolute.
133
+ #
134
+ def catalog_type_to_split_type_title(catalog_type)
135
+ split_type = catalog_type.is_a?(Puppet::Pops::Types::PType) ? catalog_type.type : catalog_type
136
+ case split_type
137
+ when Puppet::Pops::Types::PHostClassType
138
+ class_name = split_type.class_name
139
+ ['class', class_name.nil? ? nil : class_name.sub(/^::/, '')]
140
+ when Puppet::Pops::Types::PResourceType
141
+ type_name = split_type.type_name
142
+ title = split_type.title
143
+ if type_name =~ /^(::)?[Cc]lass/
144
+ ['class', title.nil? ? nil : title.sub(/^::/, '')]
145
+ else
146
+ # Ensure that title is '' if nil
147
+ # Resources with absolute name always results in error because tagging does not support leading ::
148
+ [type_name.nil? ? nil : type_name.sub(/^::/, ''), title.nil? ? '' : title]
149
+ end
150
+ else
151
+ raise ArgumentError, "Cannot split the type #{catalog_type.class}, it represents neither a PHostClassType, nor a PResourceType."
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ def initialize
158
+ @convert_visitor = Puppet::Pops::Visitor.new(self, 'convert', 2, 2)
159
+ @convert2_visitor = Puppet::Pops::Visitor.new(self, 'convert2', 2, 2)
160
+ end
161
+
162
+ @@instance = self.new
163
+
164
+ # Converts a nested 4x supported value to a 3x value.
165
+ #
166
+ # @param o [Object]The value to convert
167
+ # @param scope [Puppet::Parser::Scope] The scope to use when converting
168
+ # @param undef_value [Object] The value that nil is converted to
169
+ # @return [Object] The converted value
170
+ #
171
+ def convert2(o, scope, undef_value)
172
+ @convert2_visitor.visit_this_2(self, o, scope, undef_value)
173
+ end
174
+ end
175
+ end
@@ -199,7 +199,7 @@ module Puppet::Pops::Evaluator::Runtime3Support
199
199
  source_resource = source
200
200
  else
201
201
  # transform into the wonderful String representation in 3x
202
- type, title = catalog_type_to_split_type_title(source)
202
+ type, title = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(source)
203
203
  source_resource = Puppet::Resource.new(type, title)
204
204
  end
205
205
  if target.is_a?(Puppet::Parser::Collector) || target.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector)
@@ -207,7 +207,7 @@ module Puppet::Pops::Evaluator::Runtime3Support
207
207
  target_resource = target
208
208
  else
209
209
  # transform into the wonderful String representation in 3x
210
- type, title = catalog_type_to_split_type_title(target)
210
+ type, title = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(target)
211
211
  target_resource = Puppet::Resource.new(type, title)
212
212
  end
213
213
  # Add the relationship to the compiler for later evaluation.
@@ -229,14 +229,14 @@ module Puppet::Pops::Evaluator::Runtime3Support
229
229
  n
230
230
  end
231
231
 
232
- def call_function(name, args, o, scope)
232
+ def call_function(name, args, o, scope, &block)
233
233
  # Call via 4x API if the function exists there
234
234
  loaders = scope.compiler.loaders
235
235
  # find the loader that loaded the code, or use the private_environment_loader (sees env + all modules)
236
236
  adapter = Puppet::Pops::Utils.find_adapter(o, Puppet::Pops::Adapters::LoaderAdapter)
237
237
  loader = adapter.nil? ? loaders.private_environment_loader : adapter.loader
238
238
  if loader && func = loader.load(:function, name)
239
- return func.call(scope, *args)
239
+ return func.call(scope, *args, &block)
240
240
  end
241
241
 
242
242
  # Call via 3x API if function exists there
@@ -244,8 +244,8 @@ module Puppet::Pops::Evaluator::Runtime3Support
244
244
 
245
245
  # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
246
246
  # NOTE: Passing an empty string last converts nil/:undef to empty string
247
- mapped_args = args.map {|a| convert(a, scope, '') }
248
- result = scope.send("function_#{name}", mapped_args)
247
+ mapped_args = Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, scope, '')
248
+ result = scope.send("function_#{name}", mapped_args, &block)
249
249
  # Prevent non r-value functions from leaking their result (they are not written to care about this)
250
250
  Puppet::Parser::Functions.rvalue?(name) ? result : nil
251
251
  end
@@ -261,6 +261,10 @@ module Puppet::Pops::Evaluator::Runtime3Support
261
261
  )
262
262
  end
263
263
 
264
+ def convert(value, scope, undef_value)
265
+ Puppet::Pops::Evaluator::Runtime3Converter.convert(value, scope, undef_value)
266
+ end
267
+
264
268
  CLASS_STRING = 'class'.freeze
265
269
 
266
270
  def create_resources(o, scope, virtual, exported, type_name, resource_titles, evaluated_parameters)
@@ -423,127 +427,6 @@ module Puppet::Pops::Evaluator::Runtime3Support
423
427
  x.is_a?(TrueClass) || x.is_a?(FalseClass)
424
428
  end
425
429
 
426
- def initialize
427
- @@convert_visitor ||= Puppet::Pops::Visitor.new(self, "convert", 2, 2)
428
- @@convert2_visitor ||= Puppet::Pops::Visitor.new(self, "convert2", 2, 2)
429
- end
430
-
431
- # Converts 4x supported values to 3x values. This is required because
432
- # resources and other objects do not know about the new type system, and does not support
433
- # regular expressions. Unfortunately this has to be done for array and hash as well.
434
- # A complication is that catalog types needs to be resolved against the scope.
435
- #
436
- def convert(o, scope, undef_value)
437
- @@convert_visitor.visit_this_2(self, o, scope, undef_value)
438
- end
439
-
440
- # Converts nested 4x supported values to 3x values. This is required because
441
- # resources and other objects do not know about the new type system, and does not support
442
- # regular expressions. Unfortunately this has to be done for array and hash as well.
443
- # A complication is that catalog types needs to be resolved against the scope.
444
- #
445
- def convert2(o, scope, undef_value)
446
- @@convert2_visitor.visit_this_2(self, o, scope, undef_value)
447
- end
448
-
449
-
450
- def convert_NilClass(o, scope, undef_value)
451
- undef_value
452
- end
453
-
454
- def convert2_NilClass(o, scope, undef_value)
455
- :undef
456
- end
457
-
458
- def convert_String(o, scope, undef_value)
459
- # although wasteful, needed because user code may mutate these strings in Resources
460
- o.frozen? ? o.dup : o
461
- end
462
- alias convert2_String :convert_String
463
-
464
- def convert_Object(o, scope, undef_value)
465
- o
466
- end
467
- alias :convert2_Object :convert_Object
468
-
469
- def convert_Array(o, scope, undef_value)
470
- o.map {|x| convert2(x, scope, undef_value) }
471
- end
472
- alias :convert2_Array :convert_Array
473
-
474
- def convert_Hash(o, scope, undef_value)
475
- result = {}
476
- o.each {|k,v| result[convert2(k, scope, undef_value)] = convert2(v, scope, undef_value) }
477
- result
478
- end
479
- alias :convert2_Hash :convert_Hash
480
-
481
- def convert_Regexp(o, scope, undef_value)
482
- # Puppet 3x cannot handle parameter values that are reqular expressions. Turn into regexp string in
483
- # source form
484
- o.inspect
485
- end
486
- alias :convert2_Regexp :convert_Regexp
487
-
488
- def convert_Symbol(o, scope, undef_value)
489
- case o
490
- # Support :undef since it may come from a 3x structure
491
- when :undef
492
- undef_value # 3x wants undef as either empty string or :undef
493
- else
494
- o # :default, and all others are verbatim since they are new in future evaluator
495
- end
496
- end
497
-
498
- # The :undef symbol should not be converted when nested in arrays or hashes
499
- def convert2_Symbol(o, scope, undef_value)
500
- o
501
- end
502
-
503
- def convert_PAnyType(o, scope, undef_value)
504
- o
505
- end
506
- alias :convert2_PAnyType :convert_PAnyType
507
-
508
- def convert_PCatalogEntryType(o, scope, undef_value)
509
- # Since 4x does not support dynamic scoping, all names are absolute and can be
510
- # used as is (with some check/transformation/mangling between absolute/relative form
511
- # due to Puppet::Resource's idiosyncratic behavior where some references must be
512
- # absolute and others cannot be.
513
- # Thus there is no need to call scope.resolve_type_and_titles to do dynamic lookup.
514
-
515
- Puppet::Resource.new(*catalog_type_to_split_type_title(o))
516
- end
517
- alias :convert2_PCatalogEntryType :convert_PCatalogEntryType
518
-
519
- private
520
-
521
- # Produces an array with [type, title] from a PCatalogEntryType
522
- # This method is used to produce the arguments for creation of reference resource instances
523
- # (used when 3x is operating on a resource).
524
- # Ensures that resources are *not* absolute.
525
- #
526
- def catalog_type_to_split_type_title(catalog_type)
527
- split_type = catalog_type.is_a?(Puppet::Pops::Types::PType) ? catalog_type.type : catalog_type
528
- case split_type
529
- when Puppet::Pops::Types::PHostClassType
530
- class_name = split_type.class_name
531
- ['class', class_name.nil? ? nil : class_name.sub(/^::/, '')]
532
- when Puppet::Pops::Types::PResourceType
533
- type_name = split_type.type_name
534
- title = split_type.title
535
- if type_name =~ /^(::)?[Cc]lass/
536
- ['class', title.nil? ? nil : title.sub(/^::/, '')]
537
- else
538
- # Ensure that title is '' if nil
539
- # Resources with absolute name always results in error because tagging does not support leading ::
540
- [type_name.nil? ? nil : type_name.sub(/^::/, ''), title.nil? ? '' : title]
541
- end
542
- else
543
- raise ArgumentError, "Cannot split the type #{catalog_type.class}, it represents neither a PHostClassType, nor a PResourceType."
544
- end
545
- end
546
-
547
430
  def extract_file_line(o)
548
431
  source_pos = Puppet::Pops::Utils.find_closest_positioned(o)
549
432
  return [nil, -1] unless source_pos
@@ -587,7 +470,11 @@ module Puppet::Pops::Evaluator::Runtime3Support
587
470
  class ExceptionRaisingAcceptor < Puppet::Pops::Validation::Acceptor
588
471
  def accept(diagnostic)
589
472
  super
590
- Puppet::Pops::IssueReporter.assert_and_report(self, {:message => "Evaluation Error:", :emit_warnings => true })
473
+ Puppet::Pops::IssueReporter.assert_and_report(self, {
474
+ :message => "Evaluation Error:",
475
+ :emit_warnings => true, # log warnings
476
+ :exception_class => Puppet::PreformattedError
477
+ })
591
478
  if errors?
592
479
  raise ArgumentError, "Internal Error: Configuration of runtime error handling wrong: should have raised exception"
593
480
  end
@@ -41,36 +41,40 @@ class Puppet::Pops::Functions::Dispatch < Puppet::Pops::Evaluator::CallableSigna
41
41
  end
42
42
 
43
43
  # @api private
44
- def invoke(instance, calling_scope, args)
45
- instance.send(@method_name, *weave(calling_scope, args))
44
+ def invoke(instance, calling_scope, args, &block)
45
+ instance.send(@method_name, *weave(calling_scope, args), &block)
46
46
  end
47
47
 
48
48
  # @api private
49
49
  def weave(scope, args)
50
50
  # no need to weave if there are no injections
51
- if injections.empty?
51
+ if @injections.empty?
52
52
  args
53
53
  else
54
54
  injector = nil # lazy lookup of injector Puppet.lookup(:injector)
55
- weaving.map do |knit|
55
+ new_args = []
56
+ @weaving.each do |knit|
56
57
  if knit.is_a?(Array)
57
58
  injection_data = @injections[knit[0]]
58
- case injection_data[3]
59
- when :dispatcher_internal
60
- # currently only supports :scope injection
61
- scope
62
- when :producer
63
- injector ||= Puppet.lookup(:injector)
64
- injector.lookup_producer(scope, injection_data[0], injection_data[2])
65
- else
66
- injector ||= Puppet.lookup(:injector)
67
- injector.lookup(scope, injection_data[0], injection_data[2])
68
- end
59
+ new_args <<
60
+ case injection_data[3]
61
+ when :dispatcher_internal
62
+ # currently only supports :scope injection
63
+ scope
64
+ when :producer
65
+ injector ||= Puppet.lookup(:injector)
66
+ injector.lookup_producer(scope, injection_data[0], injection_data[2])
67
+ else
68
+ injector ||= Puppet.lookup(:injector)
69
+ injector.lookup(scope, injection_data[0], injection_data[2])
70
+ end
69
71
  else
70
- # pick that argument (injection of static value)
71
- args[knit]
72
+ # Careful so no new nil arguments are added since they would override default
73
+ # parameter values in the received
74
+ new_args << args[knit] if knit < args.size
72
75
  end
73
76
  end
77
+ new_args
74
78
  end
75
79
  end
76
80
  end
@@ -27,12 +27,12 @@ class Puppet::Pops::Functions::Dispatcher
27
27
  # @return [Object] - what the called function produced
28
28
  #
29
29
  # @api private
30
- def dispatch(instance, calling_scope, args)
30
+ def dispatch(instance, calling_scope, args, &block)
31
31
  tc = Puppet::Pops::Types::TypeCalculator
32
- actual = tc.infer_set(args)
32
+ actual = tc.infer_set(block_given? ? args + [block] : args)
33
33
  found = @dispatchers.find { |d| tc.callable?(d.type, actual) }
34
34
  if found
35
- found.invoke(instance, calling_scope, args)
35
+ found.invoke(instance, calling_scope, args, &block)
36
36
  else
37
37
  raise ArgumentError, "function '#{instance.class.name}' called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string(instance.class.name, actual, @dispatchers)}"
38
38
  end
@@ -40,25 +40,21 @@ class Puppet::Pops::Functions::Function
40
40
  # is defined) is available via the method `closure_scope`).
41
41
  #
42
42
  # @api public
43
- def call(scope, *args)
44
- self.class.dispatcher.dispatch(self, scope, args)
43
+ def call(scope, *args, &block)
44
+ self.class.dispatcher.dispatch(self, scope, args, &block)
45
45
  end
46
46
 
47
47
  # Allows the implementation of a function to call other functions by name. The callable functions
48
- # are those visible to the same loader that loaded this function (the calling function).
48
+ # are those visible to the same loader that loaded this function (the calling function). The
49
+ # referenced function is called with the calling functions closure scope as the caller's scope.
50
+ #
51
+ # @param function_name [String] The name of the function
52
+ # @param *args [Object] splat of arguments
53
+ # @return [Object] The result returned by the called function
49
54
  #
50
55
  # @api public
51
- def call_function(function_name, *args)
52
- if the_loader = loader
53
- func = the_loader.load(:function, function_name)
54
- if func
55
- return func.call(closure_scope, *args)
56
- end
57
- end
58
- # Raise a generic error to allow upper layers to fill in the details about where in a puppet manifest this
59
- # error originates. (Such information is not available here).
60
- #
61
- raise ArgumentError, "Function #{self.class.name}(): cannot call function '#{function_name}' - not found"
56
+ def call_function(function_name, *args, &block)
57
+ internal_call_function(closure_scope, function_name, args, &block)
62
58
  end
63
59
 
64
60
  # The dispatcher for the function
@@ -74,4 +70,40 @@ class Puppet::Pops::Functions::Function
74
70
  def self.signatures
75
71
  @dispatcher.signatures
76
72
  end
73
+
74
+ protected
75
+
76
+ # Allows the implementation of a function to call other functions by name and pass the caller
77
+ # scope. The callable functions are those visible to the same loader that loaded this function
78
+ # (the calling function).
79
+ #
80
+ # @param scope [Puppet::Parser::Scope] The caller scope
81
+ # @param function_name [String] The name of the function
82
+ # @param args [Array] array of arguments
83
+ # @return [Object] The result returned by the called function
84
+ #
85
+ # @api public
86
+ def internal_call_function(scope, function_name, args, &block)
87
+
88
+ the_loader = loader
89
+ raise ArgumentError, "Function #{self.class.name}(): cannot call function '#{function_name}' - no loader specified" unless the_loader
90
+
91
+ func = the_loader.load(:function, function_name)
92
+ return func.call(scope, *args, &block) if func
93
+
94
+ # 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
+ # about where in a puppet manifest this error originates. (Such information is not available here).
96
+ loader_scope = closure_scope
97
+ 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
99
+
100
+ # Call via 3x API
101
+ # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
102
+ # NOTE: Passing an empty string last converts nil/:undef to empty string
103
+ result = scope.send(func_3x, Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, loader_scope, ''), &block)
104
+
105
+ # Prevent non r-value functions from leaking their result (they are not written to care about this)
106
+ Puppet::Parser::Functions.rvalue?(function_name) ? result : nil
107
+ end
108
+
77
109
  end