puppet 4.4.2 → 4.5.0

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 (218) hide show
  1. data/CONTRIBUTING.md +5 -5
  2. data/Gemfile +2 -2
  3. data/LICENSE +2 -2
  4. data/README.md +5 -0
  5. data/ext/project_data.yaml +2 -0
  6. data/lib/hiera_puppet.rb +6 -14
  7. data/lib/puppet/application/agent.rb +2 -3
  8. data/lib/puppet/data_providers/hiera_config.rb +2 -4
  9. data/lib/puppet/data_providers/hiera_interpolate.rb +12 -154
  10. data/lib/puppet/data_providers/json_data_provider_factory.rb +0 -7
  11. data/lib/puppet/data_providers/yaml_data_provider_factory.rb +2 -8
  12. data/lib/puppet/defaults.rb +70 -7
  13. data/lib/puppet/functions.rb +69 -0
  14. data/lib/puppet/functions/dig.rb +39 -0
  15. data/lib/puppet/functions/lest.rb +53 -0
  16. data/lib/puppet/functions/lookup.rb +40 -27
  17. data/lib/puppet/functions/new.rb +502 -0
  18. data/lib/puppet/functions/regsubst.rb +11 -10
  19. data/lib/puppet/functions/then.rb +74 -0
  20. data/lib/puppet/functions/type.rb +4 -4
  21. data/lib/puppet/functions/with.rb +1 -1
  22. data/lib/puppet/indirector/catalog/compiler.rb +2 -0
  23. data/lib/puppet/indirector/resource_type/parser.rb +5 -0
  24. data/lib/puppet/indirector/rest.rb +5 -1
  25. data/lib/puppet/loaders.rb +2 -0
  26. data/lib/puppet/metatype/manager.rb +19 -2
  27. data/lib/puppet/module_tool/applications/application.rb +1 -1
  28. data/lib/puppet/module_tool/skeleton/templates/generator/Gemfile +6 -2
  29. data/lib/puppet/module_tool/skeleton/templates/generator/Rakefile +19 -4
  30. data/lib/puppet/module_tool/skeleton/templates/generator/{tests → examples}/init.pp.erb +1 -1
  31. data/lib/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb +0 -1
  32. data/lib/puppet/network/http/api/master/v3/environment.rb +6 -2
  33. data/lib/puppet/parser/ast/pops_bridge.rb +20 -3
  34. data/lib/puppet/parser/compiler/catalog_validator/relationship_validator.rb +24 -2
  35. data/lib/puppet/parser/e4_parser_adapter.rb +13 -12
  36. data/lib/puppet/parser/environment_compiler.rb +2 -2
  37. data/lib/puppet/parser/resource.rb +14 -5
  38. data/lib/puppet/parser/scope.rb +18 -15
  39. data/lib/puppet/plugins/data_providers/data_provider.rb +19 -8
  40. data/lib/puppet/pops.rb +6 -0
  41. data/lib/puppet/pops/adapters.rb +5 -1
  42. data/lib/puppet/pops/evaluator/access_operator.rb +52 -14
  43. data/lib/puppet/pops/evaluator/compare_operator.rb +34 -4
  44. data/lib/puppet/pops/evaluator/evaluator_impl.rb +75 -22
  45. data/lib/puppet/pops/evaluator/literal_evaluator.rb +7 -6
  46. data/lib/puppet/pops/evaluator/runtime3_converter.rb +13 -1
  47. data/lib/puppet/pops/evaluator/runtime3_support.rb +14 -4
  48. data/lib/puppet/pops/functions/dispatcher.rb +1 -1
  49. data/lib/puppet/pops/issues.rb +18 -2
  50. data/lib/puppet/pops/loader/base_loader.rb +48 -7
  51. data/lib/puppet/pops/loader/dependency_loader.rb +27 -2
  52. data/lib/puppet/pops/loader/loader.rb +12 -0
  53. data/lib/puppet/pops/loader/predefined_loader.rb +29 -0
  54. data/lib/puppet/pops/loader/runtime3_type_loader.rb +57 -0
  55. data/lib/puppet/pops/loader/static_loader.rb +92 -5
  56. data/lib/puppet/pops/loader/type_definition_instantiator.rb +25 -3
  57. data/lib/puppet/pops/loaders.rb +84 -14
  58. data/lib/puppet/pops/lookup/explainer.rb +38 -1
  59. data/lib/puppet/pops/lookup/interpolation.rb +115 -0
  60. data/lib/puppet/pops/lookup/sub_lookup.rb +86 -0
  61. data/lib/puppet/pops/model/ast_transformer.rb +8 -1
  62. data/lib/puppet/pops/model/factory.rb +31 -8
  63. data/lib/puppet/pops/model/model.rb +8 -0
  64. data/lib/puppet/pops/model/model_label_provider.rb +1 -0
  65. data/lib/puppet/pops/model/model_meta.rb +7 -1
  66. data/lib/puppet/pops/model/model_tree_dumper.rb +4 -0
  67. data/lib/puppet/pops/parser/egrammar.ra +24 -7
  68. data/lib/puppet/pops/parser/eparser.rb +863 -798
  69. data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
  70. data/lib/puppet/pops/parser/locator.rb +8 -4
  71. data/lib/puppet/pops/pcore.rb +30 -0
  72. data/lib/puppet/pops/types/class_loader.rb +2 -4
  73. data/lib/puppet/pops/types/implementation_registry.rb +146 -0
  74. data/lib/puppet/pops/types/iterable.rb +4 -4
  75. data/lib/puppet/pops/types/p_object_type.rb +846 -0
  76. data/lib/puppet/pops/types/p_runtime_type.rb +102 -0
  77. data/lib/puppet/pops/types/p_sem_ver_range_type.rb +164 -0
  78. data/lib/puppet/pops/types/p_sem_ver_type.rb +113 -0
  79. data/lib/puppet/pops/types/puppet_object.rb +21 -0
  80. data/lib/puppet/pops/types/ruby_generator.rb +258 -0
  81. data/lib/puppet/pops/types/string_converter.rb +922 -0
  82. data/lib/puppet/pops/types/type_calculator.rb +29 -5
  83. data/lib/puppet/pops/types/type_conversion_error.rb +15 -0
  84. data/lib/puppet/pops/types/type_factory.rb +49 -16
  85. data/lib/puppet/pops/types/type_formatter.rb +335 -112
  86. data/lib/puppet/pops/types/type_mismatch_describer.rb +110 -29
  87. data/lib/puppet/pops/types/type_parser.rb +205 -197
  88. data/lib/puppet/pops/types/types.rb +481 -103
  89. data/lib/puppet/pops/validation.rb +1 -1
  90. data/lib/puppet/pops/validation/checker4_0.rb +66 -4
  91. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  92. data/lib/puppet/pops/visitor.rb +3 -1
  93. data/lib/puppet/property.rb +1 -1
  94. data/lib/puppet/provider/augeas/augeas.rb +1 -1
  95. data/lib/puppet/provider/package/pip.rb +64 -20
  96. data/lib/puppet/provider/package/rpm.rb +112 -0
  97. data/lib/puppet/provider/package/yum.rb +7 -68
  98. data/lib/puppet/provider/service/daemontools.rb +3 -3
  99. data/lib/puppet/provider/service/init.rb +4 -2
  100. data/lib/puppet/provider/service/runit.rb +3 -3
  101. data/lib/puppet/provider/service/smf.rb +6 -3
  102. data/lib/puppet/provider/service/systemd.rb +59 -73
  103. data/lib/puppet/reference/providers.rb +1 -2
  104. data/lib/puppet/resource.rb +54 -37
  105. data/lib/puppet/resource/catalog.rb +31 -29
  106. data/lib/puppet/resource/type_collection.rb +23 -8
  107. data/lib/puppet/settings.rb +4 -2
  108. data/lib/puppet/settings/base_setting.rb +9 -3
  109. data/lib/puppet/settings/symbolic_enum_setting.rb +17 -0
  110. data/lib/puppet/test/test_helper.rb +0 -1
  111. data/lib/puppet/type.rb +9 -3
  112. data/lib/puppet/type/exec.rb +17 -17
  113. data/lib/puppet/type/file.rb +12 -0
  114. data/lib/puppet/type/file/content.rb +6 -6
  115. data/lib/puppet/type/file/ensure.rb +4 -4
  116. data/lib/puppet/type/file/source.rb +4 -4
  117. data/lib/puppet/type/file/target.rb +2 -2
  118. data/lib/puppet/type/mount.rb +18 -1
  119. data/lib/puppet/type/package.rb +3 -3
  120. data/lib/puppet/type/schedule.rb +4 -4
  121. data/lib/puppet/type/service.rb +15 -0
  122. data/lib/puppet/type/sshkey.rb +5 -3
  123. data/lib/puppet/type/tidy.rb +3 -3
  124. data/lib/puppet/type/zone.rb +5 -5
  125. data/lib/puppet/util/feature.rb +1 -1
  126. data/lib/puppet/util/monkey_patches.rb +8 -0
  127. data/lib/puppet/util/network_device/cisco/device.rb +16 -6
  128. data/lib/puppet/util/network_device/cisco/interface.rb +5 -6
  129. data/lib/puppet/util/plist.rb +3 -3
  130. data/lib/puppet/version.rb +1 -1
  131. data/spec/fixtures/unit/application/environments/production/data/common.yaml +13 -0
  132. data/spec/fixtures/unit/data_providers/environments/production/modules/abc/lib/puppet/functions/abc/data.rb +2 -1
  133. data/spec/fixtures/unit/data_providers/environments/production/modules/abc/manifests/init.pp +2 -1
  134. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/data/empty_key.json +1 -0
  135. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/hiera.yaml +5 -0
  136. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/manifests/init.pp +2 -0
  137. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/metadata.json +9 -0
  138. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/data/empty_key.yaml +1 -0
  139. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/hiera.yaml +5 -0
  140. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/manifests/init.pp +2 -0
  141. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/metadata.json +9 -0
  142. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_yaml/data/empty.yaml +1 -0
  143. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/lib/puppet/type/usee_type.rb +5 -0
  144. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/manifests/init.pp +6 -0
  145. data/spec/fixtures/unit/provider/service/smf/svcs.out +4 -3
  146. data/spec/integration/module_tool/tar/mini_spec.rb +27 -27
  147. data/spec/integration/parser/catalog_spec.rb +14 -2
  148. data/spec/integration/parser/compiler_spec.rb +94 -3
  149. data/spec/integration/parser/resource_expressions_spec.rb +1 -1
  150. data/spec/integration/resource/type_collection_spec.rb +8 -0
  151. data/spec/lib/puppet_spec/compiler.rb +11 -4
  152. data/spec/shared_contexts/types_setup.rb +4 -0
  153. data/spec/unit/application/lookup_spec.rb +91 -9
  154. data/spec/unit/appmgmt_spec.rb +44 -35
  155. data/spec/unit/capability_spec.rb +33 -53
  156. data/spec/unit/data_providers/function_data_provider_spec.rb +19 -1
  157. data/spec/unit/data_providers/hiera_data_provider_spec.rb +1 -1
  158. data/spec/unit/defaults_spec.rb +18 -0
  159. data/spec/unit/functions/assert_type_spec.rb +1 -1
  160. data/spec/unit/functions/dig_spec.rb +58 -0
  161. data/spec/unit/functions/lest_spec.rb +34 -0
  162. data/spec/unit/functions/lookup_spec.rb +108 -2
  163. data/spec/unit/functions/new_spec.rb +543 -0
  164. data/spec/unit/functions/regsubst_spec.rb +8 -0
  165. data/spec/unit/functions/then_spec.rb +40 -0
  166. data/spec/unit/functions4_spec.rb +78 -10
  167. data/spec/unit/hiera_puppet_spec.rb +49 -8
  168. data/spec/unit/indirector/resource_type/parser_spec.rb +5 -0
  169. data/spec/unit/indirector/rest_spec.rb +12 -0
  170. data/spec/unit/network/http/api/master/v3/environment_spec.rb +60 -0
  171. data/spec/unit/node/environment_spec.rb +10 -0
  172. data/spec/unit/parser/compiler_spec.rb +20 -1
  173. data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
  174. data/spec/unit/parser/functions/shared.rb +1 -1
  175. data/spec/unit/parser/resource_spec.rb +8 -1
  176. data/spec/unit/parser/scope_spec.rb +45 -0
  177. data/spec/unit/pops/evaluator/access_ops_spec.rb +14 -0
  178. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +13 -5
  179. data/spec/unit/pops/loaders/static_loader_spec.rb +92 -1
  180. data/spec/unit/{data_providers/hiera_interpolation_spec.rb → pops/lookup/interpolation_spec.rb} +7 -5
  181. data/spec/unit/pops/parser/lexer2_spec.rb +2 -9
  182. data/spec/unit/pops/parser/parse_application_spec.rb +3 -8
  183. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +19 -0
  184. data/spec/unit/pops/parser/parse_capabilities_spec.rb +3 -10
  185. data/spec/unit/pops/parser/parse_site_spec.rb +19 -10
  186. data/spec/unit/pops/parser/parser_rspec_helper.rb +0 -4
  187. data/spec/unit/pops/types/enumeration_spec.rb +13 -12
  188. data/spec/unit/pops/types/iterable_spec.rb +2 -2
  189. data/spec/unit/pops/types/p_object_type_spec.rb +1060 -0
  190. data/spec/unit/pops/types/p_sem_ver_type_spec.rb +285 -0
  191. data/spec/unit/pops/types/recursion_guard_spec.rb +19 -17
  192. data/spec/unit/pops/types/ruby_generator_spec.rb +261 -0
  193. data/spec/unit/pops/types/string_converter_spec.rb +904 -0
  194. data/spec/unit/pops/types/type_calculator_spec.rb +430 -406
  195. data/spec/unit/pops/types/type_factory_spec.rb +119 -104
  196. data/spec/unit/pops/types/type_formatter_spec.rb +73 -6
  197. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +2 -2
  198. data/spec/unit/pops/types/type_parser_spec.rb +54 -15
  199. data/spec/unit/pops/types/types_spec.rb +113 -8
  200. data/spec/unit/pops/validator/validator_spec.rb +84 -10
  201. data/spec/unit/provider/package/pip3_spec.rb +9 -270
  202. data/spec/unit/provider/package/pip_spec.rb +85 -30
  203. data/spec/unit/provider/package/rpm_spec.rb +160 -3
  204. data/spec/unit/provider/package/yum_spec.rb +23 -134
  205. data/spec/unit/provider/service/smf_spec.rb +14 -2
  206. data/spec/unit/provider/service/systemd_spec.rb +33 -41
  207. data/spec/unit/resource/capability_finder_spec.rb +10 -2
  208. data/spec/unit/settings/file_setting_spec.rb +6 -0
  209. data/spec/unit/transaction/additional_resource_generator_spec.rb +80 -65
  210. data/spec/unit/type/mount_spec.rb +51 -10
  211. data/spec/unit/type/service_spec.rb +16 -0
  212. data/spec/unit/type_spec.rb +14 -0
  213. data/spec/unit/util/feature_spec.rb +1 -1
  214. data/spec/unit/util/monkey_patches_spec.rb +60 -0
  215. data/spec/unit/util/network_device/cisco/device_spec.rb +1 -1
  216. metadata +63 -11
  217. data/lib/puppet/pops/types/types_meta.rb +0 -0
  218. data/spec/integration/provider/package_spec.rb +0 -35
@@ -17,8 +17,10 @@ module Types
17
17
  self.class == o.class && key == o.key
18
18
  end
19
19
 
20
- alias :eql? :==
21
- end
20
+ def eql?(o)
21
+ self == o
22
+ end
23
+ end
22
24
 
23
25
  class SubjectPathElement < TypePathElement
24
26
  def to_s
@@ -26,15 +28,15 @@ module Types
26
28
  end
27
29
  end
28
30
 
29
- class MemberPathElement < TypePathElement
31
+ class EntryValuePathElement < TypePathElement
30
32
  def to_s
31
- "struct member '#{key}'"
33
+ "entry '#{key}'"
32
34
  end
33
35
  end
34
36
 
35
- class MemberKeyPathElement < TypePathElement
37
+ class EntryKeyPathElement < TypePathElement
36
38
  def to_s
37
- "struct member key '#{key}'"
39
+ "key of entry '#{key}'"
38
40
  end
39
41
  end
40
42
 
@@ -104,6 +106,15 @@ module Types
104
106
  'did not have a'
105
107
  end
106
108
  end
109
+
110
+ def it_references(tense)
111
+ case tense
112
+ when :present
113
+ 'references'
114
+ else
115
+ 'referenced'
116
+ end
117
+ end
107
118
  end
108
119
 
109
120
  class Mismatch
@@ -130,7 +141,9 @@ module Types
130
141
  self.class == o.class && canonical_path == o.canonical_path
131
142
  end
132
143
 
133
- alias :eql? :==
144
+ def eql?(o)
145
+ self == o
146
+ end
134
147
 
135
148
  def hash
136
149
  canonical_path.hash
@@ -201,7 +214,7 @@ module Types
201
214
 
202
215
  class ExtraneousKey < KeyMismatch
203
216
  def message(variant, position, tense = :present)
204
- "#{variant}#{position} #{it_has_no(tense)} '#{@key}' key"
217
+ "#{variant}#{position} unrecognized key '#{@key}'"
205
218
  end
206
219
  end
207
220
 
@@ -223,12 +236,33 @@ module Types
223
236
  end
224
237
  end
225
238
 
239
+ class UnresolvedTypeReference < Mismatch
240
+ attr_reader :unresolved
241
+
242
+ def initialize(path, unresolved)
243
+ super(path)
244
+ @unresolved = unresolved
245
+ end
246
+
247
+ def ==(o)
248
+ super.==(o) && @unresolved == o.unresolved
249
+ end
250
+
251
+ def hash
252
+ @unresolved.hash
253
+ end
254
+
255
+ def message(variant, position, tense = :present)
256
+ "#{variant}#{position} #{it_references(tense)} an unresolved type '#{@unresolved}'"
257
+ end
258
+ end
259
+
226
260
  class ExpectedActualMismatch < Mismatch
227
261
  attr_reader :expected, :actual
228
262
 
229
263
  def initialize(path, expected, actual)
230
264
  super(path)
231
- @expected = (expected.is_a?(Array) ? PVariantType.new(expected) : expected).normalize
265
+ @expected = (expected.is_a?(Array) ? PVariantType.maybe_create(expected) : expected).normalize
232
266
  @actual = actual.normalize
233
267
  end
234
268
 
@@ -711,6 +745,28 @@ module Types
711
745
  end
712
746
  end
713
747
 
748
+ def describe_PHashType(expected, actual, path)
749
+ descriptions = []
750
+ key_type = expected.key_type || PAnyType::DEFAULT
751
+ value_type = expected.element_type || PAnyType::DEFAULT
752
+ if actual.is_a?(PStructType)
753
+ elements = actual.elements
754
+ expected_size = expected.size_type || PCollectionType::DEFAULT_SIZE
755
+ actual_size = PIntegerType.new(elements.count { |a| !a.key_type.assignable?(PUndefType::DEFAULT) }, elements.size)
756
+ if expected_size.assignable?(actual_size)
757
+ elements.each do |a|
758
+ descriptions.concat(describe(key_type, a.key_type, path + [EntryKeyPathElement.new(a.name)])) unless key_type.assignable?(a.key_type)
759
+ descriptions.concat(describe(value_type, a.value_type, path + [EntryValuePathElement.new(a.name)])) unless value_type.assignable?(a.value_type)
760
+ end
761
+ else
762
+ descriptions << SizeMismatch.new(path, expected_size, actual_size)
763
+ end
764
+ else
765
+ descriptions << TypeMismatch.new(path, expected, actual)
766
+ end
767
+ descriptions
768
+ end
769
+
714
770
  def describe_PStructType(expected, actual, path)
715
771
  elements = expected.elements
716
772
  descriptions = []
@@ -722,8 +778,8 @@ module Types
722
778
  if e2.nil?
723
779
  descriptions << MissingKey.new(path, key) unless e1.key_type.assignable?(PUndefType::DEFAULT)
724
780
  else
725
- descriptions.concat(describe(e1.key_type, e2.key_type, path + [MemberKeyPathElement.new(key)])) unless e1.key_type.assignable?(e2.key_type)
726
- descriptions.concat(describe(e1.value_type, e2.value_type, path + [MemberPathElement.new(key)])) unless e1.value_type.assignable?(e2.value_type)
781
+ descriptions.concat(describe(e1.key_type, e2.key_type, path + [EntryKeyPathElement.new(key)])) unless e1.key_type.assignable?(e2.key_type)
782
+ descriptions.concat(describe(e1.value_type, e2.value_type, path + [EntryValuePathElement.new(key)])) unless e1.value_type.assignable?(e2.value_type)
727
783
  end
728
784
  end
729
785
  h2.each_key { |key| descriptions << ExtraneousKey.new(path, key) }
@@ -827,26 +883,51 @@ module Types
827
883
  expected.assignable?(actual) ? EMPTY_ARRAY : [TypeMismatch.new(path, expected, actual)]
828
884
  end
829
885
 
886
+ class UnresolvedTypeFinder
887
+ include TypeAcceptor
888
+
889
+ attr_reader :unresolved
890
+
891
+ def initialize
892
+ @unresolved = nil
893
+ end
894
+
895
+ def visit(type, guard)
896
+ if @unresolved.nil? && type.is_a?(PTypeReferenceType)
897
+ @unresolved = type.type_string
898
+ end
899
+ end
900
+ end
901
+
830
902
  def describe(expected, actual, path)
831
- case expected
832
- when PVariantType
833
- describe_PVariantType(expected, actual, path)
834
- when PStructType
835
- describe_PStructType(expected, actual, path)
836
- when PTupleType
837
- describe_PTupleType(expected, actual, path)
838
- when PCallableType
839
- describe_PCallableType(expected, actual, path)
840
- when POptionalType
841
- describe_POptionalType(expected, actual, path)
842
- when PPatternType
843
- describe_PPatternType(expected, actual, path)
844
- when PEnumType
845
- describe_PEnumType(expected, actual, path)
846
- when PTypeAliasType
847
- describe_PTypeAliasType(expected, actual, path)
903
+ ures_finder = UnresolvedTypeFinder.new
904
+ expected.accept(ures_finder, nil)
905
+ unresolved = ures_finder.unresolved
906
+ if unresolved
907
+ [UnresolvedTypeReference.new(path, unresolved)]
848
908
  else
849
- describe_PAnyType(expected, actual, path)
909
+ case expected
910
+ when PVariantType
911
+ describe_PVariantType(expected, actual, path)
912
+ when PStructType
913
+ describe_PStructType(expected, actual, path)
914
+ when PHashType
915
+ describe_PHashType(expected, actual, path)
916
+ when PTupleType
917
+ describe_PTupleType(expected, actual, path)
918
+ when PCallableType
919
+ describe_PCallableType(expected, actual, path)
920
+ when POptionalType
921
+ describe_POptionalType(expected, actual, path)
922
+ when PPatternType
923
+ describe_PPatternType(expected, actual, path)
924
+ when PEnumType
925
+ describe_PEnumType(expected, actual, path)
926
+ when PTypeAliasType
927
+ describe_PTypeAliasType(expected, actual, path)
928
+ else
929
+ describe_PAnyType(expected, actual, path)
930
+ end
850
931
  end
851
932
  end
852
933
 
@@ -29,25 +29,14 @@ class TypeParser
29
29
  # @api public
30
30
  #
31
31
  def parse(string, context = nil)
32
- # TODO: This state (@string) can be removed since the parse result of newer future parser
33
- # contains a Locator in its SourcePosAdapter and the Locator keeps the string.
34
- # This way, there is no difference between a parsed "string" and something that has been parsed
35
- # earlier and fed to 'interpret'
36
- #
37
- @string = string
38
- model = @parser.parse_string(@string)
39
- if model
40
- interpret(model.current, context)
41
- else
42
- raise_invalid_type_specification_error
43
- end
32
+ model = @parser.parse_string(string)
33
+ interpret(model.current.body, context)
44
34
  end
45
35
 
46
36
  # @api private
47
37
  def interpret(ast, context)
48
38
  result = @type_transformer.visit_this_1(self, ast, context)
49
- result = result.body if result.is_a?(Model::Program)
50
- raise_invalid_type_specification_error unless result.is_a?(PAnyType)
39
+ raise_invalid_type_specification_error(ast) unless result.is_a?(PAnyType)
51
40
  result
52
41
  end
53
42
 
@@ -58,31 +47,26 @@ class TypeParser
58
47
 
59
48
  # @api private
60
49
  def interpret_Object(o, context)
61
- raise_invalid_type_specification_error
50
+ raise_invalid_type_specification_error(o)
62
51
  end
63
52
 
64
53
  # @api private
65
54
  def interpret_Program(o, context)
66
- interpret(o.body, context)
55
+ interpret_any(o.body, context)
67
56
  end
68
57
 
69
- # @api private
70
- def interpret_QualifiedName(o, context)
71
- o.value
58
+ def interpret_LambdaExpression(o, context)
59
+ o
72
60
  end
73
61
 
74
62
  # @api private
75
- def interpret_LiteralString(o, context)
76
- o.value
77
- end
78
-
79
- def interpret_LiteralRegularExpression(o, context)
63
+ def interpret_QualifiedName(o, context)
80
64
  o.value
81
65
  end
82
66
 
83
67
  # @api private
84
- def interpret_String(o, context)
85
- o
68
+ def interpret_LiteralBoolean(o, context)
69
+ o.value
86
70
  end
87
71
 
88
72
  # @api private
@@ -90,16 +74,6 @@ class TypeParser
90
74
  :default
91
75
  end
92
76
 
93
- # @api private
94
- def interpret_LiteralInteger(o, context)
95
- o.value
96
- end
97
-
98
- # @api private
99
- def interpret_UnaryMinusExpression(o, context)
100
- -@type_transformer.visit_this_1(self, o.expr, context)
101
- end
102
-
103
77
  # @api private
104
78
  def interpret_LiteralFloat(o, context)
105
79
  o.value
@@ -115,167 +89,172 @@ class TypeParser
115
89
  end
116
90
 
117
91
  # @api private
118
- def interpret_QualifiedReference(name_ast, context)
119
- name = name_ast.value
120
- case name
121
- when 'integer'
122
- TypeFactory.integer
123
-
124
- when 'float'
125
- TypeFactory.float
126
-
127
- when 'numeric'
128
- TypeFactory.numeric
129
-
130
- when 'iterable'
131
- TypeFactory.iterable
132
-
133
- when 'iterator'
134
- TypeFactory.iterator
135
-
136
- when 'string'
137
- TypeFactory.string
138
-
139
- when 'enum'
140
- TypeFactory.enum
141
-
142
- when 'boolean'
143
- TypeFactory.boolean
144
-
145
- when 'pattern'
146
- TypeFactory.pattern
147
-
148
- when 'regexp'
149
- TypeFactory.regexp
150
-
151
- when 'data'
152
- TypeFactory.data
153
-
154
- when 'array'
155
- TypeFactory.array_of_data
156
-
157
- when 'hash'
158
- TypeFactory.hash_of_data
159
-
160
- when 'class'
161
- TypeFactory.host_class
162
-
163
- when 'resource'
164
- TypeFactory.resource
165
-
166
- when 'collection'
167
- TypeFactory.collection
168
-
169
- when 'scalar'
170
- TypeFactory.scalar
171
-
172
- when 'catalogentry'
173
- TypeFactory.catalog_entry
174
-
175
- when 'undef'
176
- TypeFactory.undef
177
-
178
- when 'notundef'
179
- TypeFactory.not_undef()
180
-
181
- when 'default'
182
- TypeFactory.default()
183
-
184
- when 'any'
185
- TypeFactory.any
92
+ def interpret_LiteralInteger(o, context)
93
+ o.value
94
+ end
186
95
 
187
- when 'variant'
188
- TypeFactory.variant
96
+ # @api private
97
+ def interpret_LiteralList(o, context)
98
+ o.values.map { |value| @type_transformer.visit_this_1(self, value, context) }
99
+ end
189
100
 
190
- when 'optional'
191
- TypeFactory.optional
101
+ # @api private
102
+ def interpret_LiteralRegularExpression(o, context)
103
+ o.value
104
+ end
192
105
 
193
- when 'runtime'
194
- TypeFactory.runtime
106
+ # @api private
107
+ def interpret_LiteralString(o, context)
108
+ o.value
109
+ end
195
110
 
196
- when 'type'
197
- TypeFactory.type_type
111
+ # @api private
112
+ def interpret_LiteralUndef(o, context)
113
+ nil
114
+ end
198
115
 
199
- when 'tuple'
200
- TypeFactory.tuple
116
+ # @api private
117
+ def interpret_String(o, context)
118
+ o
119
+ end
201
120
 
202
- when 'struct'
203
- TypeFactory.struct
121
+ # @api private
122
+ def interpret_UnaryMinusExpression(o, context)
123
+ -@type_transformer.visit_this_1(self, o.expr, context)
124
+ end
204
125
 
205
- when 'callable'
126
+ # @api private
127
+ def self.type_map
128
+ @type_map ||= {
129
+ 'integer' => TypeFactory.integer,
130
+ 'float' => TypeFactory.float,
131
+ 'numeric' => TypeFactory.numeric,
132
+ 'iterable' => TypeFactory.iterable,
133
+ 'iterator' => TypeFactory.iterator,
134
+ 'string' => TypeFactory.string,
135
+ 'enum' => TypeFactory.enum,
136
+ 'boolean' => TypeFactory.boolean,
137
+ 'pattern' => TypeFactory.pattern,
138
+ 'regexp' => TypeFactory.regexp,
139
+ 'data' => TypeFactory.data,
140
+ 'array' => TypeFactory.array_of_data,
141
+ 'hash' => TypeFactory.hash_of_data,
142
+ 'class' => TypeFactory.host_class,
143
+ 'resource' => TypeFactory.resource,
144
+ 'collection' => TypeFactory.collection,
145
+ 'scalar' => TypeFactory.scalar,
146
+ 'catalogentry' => TypeFactory.catalog_entry,
147
+ 'undef' => TypeFactory.undef,
148
+ 'notundef' => TypeFactory.not_undef(),
149
+ 'default' => TypeFactory.default(),
150
+ 'any' => TypeFactory.any,
151
+ 'variant' => TypeFactory.variant,
152
+ 'optional' => TypeFactory.optional,
153
+ 'runtime' => TypeFactory.runtime,
154
+ 'type' => TypeFactory.type_type,
155
+ 'tuple' => TypeFactory.tuple,
156
+ 'struct' => TypeFactory.struct,
157
+ 'object' => TypeFactory.object,
158
+ 'typealias' => TypeFactory.type_alias,
159
+ 'typereference' => TypeFactory.type_reference,
206
160
  # A generic callable as opposed to one that does not accept arguments
207
- TypeFactory.all_callables
161
+ 'callable' => TypeFactory.all_callables,
162
+ 'semver' => TypeFactory.sem_ver,
163
+ 'semverrange' => TypeFactory.sem_ver_range
164
+ }
165
+ end
208
166
 
167
+ # @api private
168
+ def interpret_QualifiedReference(name_ast, context)
169
+ name = name_ast.value
170
+ if found = self.class.type_map[name]
171
+ found
209
172
  else
210
- if context.nil?
211
- TypeFactory.type_reference(name.capitalize)
212
- else
213
- if context.is_a?(Puppet::Pops::Loader::Loader)
214
- loader = context
215
- else
216
- loader = Puppet::Pops::Adapters::LoaderAdapter.loader_for_model_object(name_ast, context)
217
- end
218
- unless loader.nil?
219
- type = loader.load(:type, name)
220
- type = type.resolve(self, loader) unless type.nil?
221
- end
222
- type || TypeFactory.resource(name)
173
+ loader = loader_from_context(name_ast, context)
174
+ unless loader.nil?
175
+ type = loader.load(:type, name)
176
+ type = type.resolve(self, loader) unless type.nil?
223
177
  end
178
+ type || TypeFactory.type_reference(name_ast.cased_value)
224
179
  end
225
180
  end
226
181
 
227
182
  # @api private
228
- def interpret_AccessExpression(parameterized_ast, context)
229
- parameters = parameterized_ast.keys.collect { |param| interpret_any(param, context) }
230
-
231
- unless parameterized_ast.left_expr.is_a?(Model::QualifiedReference)
232
- raise_invalid_type_specification_error
183
+ def loader_from_context(ast, context)
184
+ if context.nil?
185
+ nil
186
+ elsif context.is_a?(Puppet::Pops::Loader::Loader)
187
+ context
188
+ else
189
+ Puppet::Pops::Adapters::LoaderAdapter.loader_for_model_object(ast, context)
233
190
  end
191
+ end
192
+
193
+ # @api private
194
+ def interpret_AccessExpression(ast, context)
195
+ parameters = ast.keys.collect { |param| interpret_any(param, context) }
196
+
197
+ qref = ast.left_expr
198
+ raise_invalid_type_specification_error(ast) unless qref.is_a?(Model::QualifiedReference)
234
199
 
235
- case parameterized_ast.left_expr.value
200
+ type_name = qref.value
201
+ case type_name
236
202
  when 'array'
237
203
  case parameters.size
238
204
  when 1
205
+ type = assert_type(ast, parameters[0])
239
206
  when 2
240
- size_type =
241
- if parameters[1].is_a?(PIntegerType)
242
- parameters[1]
243
- else
244
- assert_range_parameter(parameters[1])
245
- TypeFactory.range(parameters[1], :default)
246
- end
207
+ if parameters[0].is_a?(PAnyType)
208
+ type = parameters[0]
209
+ size_type =
210
+ if parameters[1].is_a?(PIntegerType)
211
+ size_type = parameters[1]
212
+ else
213
+ assert_range_parameter(ast, parameters[1])
214
+ TypeFactory.range(parameters[1], :default)
215
+ end
216
+ else
217
+ type = :default
218
+ assert_range_parameter(ast, parameters[0])
219
+ assert_range_parameter(ast, parameters[1])
220
+ size_type = TypeFactory.range(parameters[0], parameters[1])
221
+ end
247
222
  when 3
248
- assert_range_parameter(parameters[1])
249
- assert_range_parameter(parameters[2])
223
+ type = assert_type(ast, parameters[0])
224
+ assert_range_parameter(ast, parameters[1])
225
+ assert_range_parameter(ast, parameters[2])
250
226
  size_type = TypeFactory.range(parameters[1], parameters[2])
251
227
  else
252
228
  raise_invalid_parameters_error('Array', '1 to 3', parameters.size)
253
229
  end
254
- assert_type(parameters[0])
255
- TypeFactory.array_of(parameters[0], size_type)
230
+ TypeFactory.array_of(type, size_type)
256
231
 
257
232
  when 'hash'
258
233
  case parameters.size
259
234
  when 2
260
- assert_type(parameters[0])
261
- assert_type(parameters[1])
262
- TypeFactory.hash_of(parameters[1], parameters[0])
235
+ if parameters[0].is_a?(PAnyType) && parameters[1].is_a?(PAnyType)
236
+ TypeFactory.hash_of(parameters[1], parameters[0])
237
+ else
238
+ assert_range_parameter(ast, parameters[0])
239
+ assert_range_parameter(ast, parameters[1])
240
+ TypeFactory.hash_of(:default, :default, TypeFactory.range(parameters[0], parameters[1]))
241
+ end
263
242
  when 3
264
243
  size_type =
265
244
  if parameters[2].is_a?(PIntegerType)
266
245
  parameters[2]
267
246
  else
268
- assert_range_parameter(parameters[2])
247
+ assert_range_parameter(ast, parameters[2])
269
248
  TypeFactory.range(parameters[2], :default)
270
249
  end
271
- assert_type(parameters[0])
272
- assert_type(parameters[1])
250
+ assert_type(ast, parameters[0])
251
+ assert_type(ast, parameters[1])
273
252
  TypeFactory.hash_of(parameters[1], parameters[0], size_type)
274
253
  when 4
275
- assert_range_parameter(parameters[2])
276
- assert_range_parameter(parameters[3])
277
- assert_type(parameters[0])
278
- assert_type(parameters[1])
254
+ assert_range_parameter(ast, parameters[2])
255
+ assert_range_parameter(ast, parameters[3])
256
+ assert_type(ast, parameters[0])
257
+ assert_type(ast, parameters[1])
279
258
  TypeFactory.hash_of(parameters[1], parameters[0], TypeFactory.range(parameters[2], parameters[3]))
280
259
  else
281
260
  raise_invalid_parameters_error('Hash', '2 to 4', parameters.size)
@@ -287,12 +266,12 @@ class TypeParser
287
266
  if parameters[0].is_a?(PIntegerType)
288
267
  parameters[0]
289
268
  else
290
- assert_range_parameter(parameters[0])
269
+ assert_range_parameter(ast, parameters[0])
291
270
  TypeFactory.range(parameters[0], :default)
292
271
  end
293
272
  when 2
294
- assert_range_parameter(parameters[0])
295
- assert_range_parameter(parameters[1])
273
+ assert_range_parameter(ast, parameters[0])
274
+ assert_range_parameter(ast, parameters[1])
296
275
  TypeFactory.range(parameters[0], parameters[1])
297
276
  else
298
277
  raise_invalid_parameters_error('Collection', '1 to 2', parameters.size)
@@ -306,13 +285,20 @@ class TypeParser
306
285
  TypeFactory.host_class(parameters[0])
307
286
 
308
287
  when 'resource'
309
- if parameters.size == 1
310
- TypeFactory.resource(parameters[0])
311
- elsif parameters.size != 2
312
- raise_invalid_parameters_error('Resource', '1 or 2', parameters.size)
313
- else
314
- TypeFactory.resource(parameters[0], parameters[1])
288
+ type = parameters[0]
289
+ if type.is_a?(PTypeReferenceType)
290
+ type_str = type.type_string
291
+ param_start = type_str.index('[')
292
+ if param_start.nil?
293
+ type = type_str
294
+ else
295
+ tps = interpret_any(@parser.parse_string(type_str[param_start..-1]).current, context)
296
+ raise_invalid_parameters_error(type.to_s, '1', tps.size) unless tps.size == 1
297
+ type = type_str[0..param_start-1]
298
+ parameters = [type] + tps
299
+ end
315
300
  end
301
+ create_resource(type, parameters)
316
302
 
317
303
  when 'regexp'
318
304
  # 1 parameter being a string, or regular expression
@@ -343,7 +329,7 @@ class TypeParser
343
329
  # min, max specification
344
330
  min = parameters[-2]
345
331
  min = (min == :default || min == 'default') ? 0 : min
346
- assert_range_parameter(parameters[-1])
332
+ assert_range_parameter(ast, parameters[-1])
347
333
  max = parameters[-1]
348
334
  max = max == :default ? nil : max
349
335
  parameters = parameters[0, length-2]
@@ -365,7 +351,7 @@ class TypeParser
365
351
  # 1..m parameters being types (last two optionally integer or literal default
366
352
  raise_invalid_parameters_error('Struct', '1', parameters.size) unless parameters.size == 1
367
353
  h = parameters[0]
368
- raise_invalid_type_specification_error unless h.is_a?(Hash)
354
+ raise_invalid_type_specification_error(ast) unless h.is_a?(Hash)
369
355
  TypeFactory.struct(h)
370
356
 
371
357
  when 'integer'
@@ -382,18 +368,22 @@ class TypeParser
382
368
  TypeFactory.range(parameters[0] == :default ? nil : parameters[0], parameters[1] == :default ? nil : parameters[1])
383
369
  end
384
370
 
371
+ when 'object'
372
+ raise_invalid_parameters_error('Object', 1, parameters.size) unless parameters.size == 1
373
+ TypeFactory.object(parameters[0])
374
+
385
375
  when 'iterable'
386
376
  if parameters.size != 1
387
377
  raise_invalid_parameters_error('Iterable', 1, parameters.size)
388
378
  end
389
- assert_type(parameters[0])
379
+ assert_type(ast, parameters[0])
390
380
  TypeFactory.iterable(parameters[0])
391
381
 
392
382
  when 'iterator'
393
383
  if parameters.size != 1
394
384
  raise_invalid_parameters_error('Iterator', 1, parameters.size)
395
385
  end
396
- assert_type(parameters[0])
386
+ assert_type(ast, parameters[0])
397
387
  TypeFactory.iterator(parameters[0])
398
388
 
399
389
  when 'float'
@@ -417,12 +407,12 @@ class TypeParser
417
407
  if parameters[0].is_a?(PIntegerType)
418
408
  parameters[0]
419
409
  else
420
- assert_range_parameter(parameters[0])
410
+ assert_range_parameter(ast, parameters[0])
421
411
  TypeFactory.range(parameters[0], :default)
422
412
  end
423
413
  when 2
424
- assert_range_parameter(parameters[0])
425
- assert_range_parameter(parameters[1])
414
+ assert_range_parameter(ast, parameters[0])
415
+ assert_range_parameter(ast, parameters[1])
426
416
  TypeFactory.range(parameters[0], parameters[1])
427
417
  else
428
418
  raise_invalid_parameters_error('String', '1 to 2', parameters.size)
@@ -434,11 +424,11 @@ class TypeParser
434
424
  raise_invalid_parameters_error('Optional', 1, parameters.size)
435
425
  end
436
426
  param = parameters[0]
437
- assert_type(param) unless param.is_a?(String)
427
+ assert_type(ast, param) unless param.is_a?(String)
438
428
  TypeFactory.optional(param)
439
429
 
440
- when 'any', 'data', 'catalogentry', 'boolean', 'scalar', 'undef', 'numeric', 'default'
441
- raise_unparameterized_type_error(parameterized_ast.left_expr)
430
+ when 'any', 'data', 'catalogentry', 'boolean', 'scalar', 'undef', 'numeric', 'default', 'semverrange'
431
+ raise_unparameterized_type_error(qref)
442
432
 
443
433
  when 'notundef'
444
434
  case parameters.size
@@ -446,7 +436,7 @@ class TypeParser
446
436
  TypeFactory.not_undef
447
437
  when 1
448
438
  param = parameters[0]
449
- assert_type(param) unless param.is_a?(String)
439
+ assert_type(ast, param) unless param.is_a?(String)
450
440
  TypeFactory.not_undef(param)
451
441
  else
452
442
  raise_invalid_parameters_error("NotUndef", "0 to 1", parameters.size)
@@ -456,43 +446,61 @@ class TypeParser
456
446
  if parameters.size != 1
457
447
  raise_invalid_parameters_error('Type', 1, parameters.size)
458
448
  end
459
- assert_type(parameters[0])
449
+ assert_type(ast, parameters[0])
460
450
  TypeFactory.type_type(parameters[0])
461
451
 
462
452
  when 'runtime'
463
453
  raise_invalid_parameters_error('Runtime', '2', parameters.size) unless parameters.size == 2
464
454
  TypeFactory.runtime(*parameters)
465
455
 
456
+ when 'semver'
457
+ raise_invalid_parameters_error('SemVer', '1 or more', parameters.size) unless parameters.size >= 1
458
+ TypeFactory.sem_ver(*parameters)
459
+
466
460
  else
467
- type_name = parameterized_ast.left_expr.value
468
- if context.nil?
469
- # Will be impossible to tell from a typed alias (when implemented) so a type reference
470
- # is returned here for now
471
- TypeFactory.type_reference(type_name.capitalize, parameters)
461
+ loader = loader_from_context(qref, context)
462
+ type = nil
463
+ unless loader.nil?
464
+ type = loader.load(:type, type_name)
465
+ type = type.resolve(self, loader) unless type.nil?
466
+ end
467
+
468
+ if type.nil?
469
+ TypeFactory.type_reference(original_text_of(qref.eContainer))
470
+ elsif type.is_a?(PResourceType)
471
+ raise_invalid_parameters_error(type_name, 1, parameters.size) unless parameters.size == 1
472
+ TypeFactory.resource(type.type_name, parameters[0])
472
473
  else
473
- # It is a resource such a File['/tmp/foo']
474
- if parameters.size != 1
475
- raise_invalid_parameters_error(type_name.capitalize, 1, parameters.size)
476
- end
477
- TypeFactory.resource(type_name, parameters[0])
474
+ # Must be a type alias. They can't use parameters (yet)
475
+ raise_unparameterized_type_error(qref)
478
476
  end
479
477
  end
480
478
  end
481
479
 
482
480
  private
483
481
 
484
- def assert_type(t)
485
- raise_invalid_type_specification_error unless t.is_a?(PAnyType)
486
- true
482
+ def create_resource(name, parameters)
483
+ if parameters.size == 1
484
+ TypeFactory.resource(name)
485
+ elsif parameters.size == 2
486
+ TypeFactory.resource(name, parameters[1])
487
+ else
488
+ raise_invalid_parameters_error('Resource', '1 or 2', parameters.size)
489
+ end
490
+ end
491
+
492
+ def assert_type(ast, t)
493
+ raise_invalid_type_specification_error(ast) unless t.is_a?(PAnyType)
494
+ t
487
495
  end
488
496
 
489
- def assert_range_parameter(t)
490
- raise_invalid_type_specification_error unless TypeFactory.is_range_parameter?(t)
497
+ def assert_range_parameter(ast, t)
498
+ raise_invalid_type_specification_error(ast) unless TypeFactory.is_range_parameter?(t)
491
499
  end
492
500
 
493
- def raise_invalid_type_specification_error
501
+ def raise_invalid_type_specification_error(ast)
494
502
  raise Puppet::ParseError,
495
- "The expression <#{@string}> is not a valid type specification."
503
+ "The expression <#{original_text_of(ast)}> is not a valid type specification."
496
504
  end
497
505
 
498
506
  def raise_invalid_parameters_error(type, required, given)
@@ -510,7 +518,7 @@ class TypeParser
510
518
 
511
519
  def original_text_of(ast)
512
520
  position = Adapters::SourcePosAdapter.adapt(ast)
513
- position.extract_text
521
+ position.extract_tree_text
514
522
  end
515
523
  end
516
524
  end