puppet 3.2.4 → 3.3.0.rc2

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 (562) hide show
  1. data/COMMITTERS.md +101 -42
  2. data/Gemfile +15 -4
  3. data/README.md +5 -1
  4. data/README_DEVELOPER.md +117 -54
  5. data/Rakefile +4 -0
  6. data/ext/build_defaults.yaml +3 -2
  7. data/ext/debian/puppet-common.manpages +33 -1
  8. data/ext/gentoo/init.d/puppet +1 -1
  9. data/ext/gentoo/init.d/puppetmaster +1 -1
  10. data/ext/redhat/puppet.spec.erb +0 -1
  11. data/install.rb +2 -1
  12. data/lib/hiera/backend/puppet_backend.rb +1 -1
  13. data/lib/puppet/application.rb +10 -9
  14. data/lib/puppet/application/agent.rb +87 -93
  15. data/lib/puppet/application/apply.rb +0 -2
  16. data/lib/puppet/application/device.rb +3 -3
  17. data/lib/puppet/application/kick.rb +2 -2
  18. data/lib/puppet/application/master.rb +41 -19
  19. data/lib/puppet/application/queue.rb +5 -3
  20. data/lib/puppet/bindings.rb +147 -0
  21. data/lib/puppet/configurer.rb +25 -15
  22. data/lib/puppet/configurer/fact_handler.rb +2 -9
  23. data/lib/puppet/daemon.rb +44 -33
  24. data/lib/puppet/defaults.rb +57 -26
  25. data/lib/puppet/error.rb +1 -1
  26. data/lib/puppet/external/dot.rb +2 -2
  27. data/lib/puppet/external/nagios/base.rb +1 -6
  28. data/lib/puppet/external/pson/common.rb +2 -2
  29. data/lib/puppet/external/pson/pure/generator.rb +2 -2
  30. data/lib/puppet/external/pson/pure/parser.rb +1 -1
  31. data/lib/puppet/face/ca.rb +1 -1
  32. data/lib/puppet/face/config.rb +1 -1
  33. data/lib/puppet/face/help.rb +2 -2
  34. data/lib/puppet/face/module/list.rb +2 -2
  35. data/lib/puppet/feature/rails.rb +1 -1
  36. data/lib/puppet/file_bucket/dipper.rb +0 -1
  37. data/lib/puppet/file_serving/base.rb +1 -1
  38. data/lib/puppet/file_serving/configuration/parser.rb +20 -14
  39. data/lib/puppet/forge.rb +0 -32
  40. data/lib/puppet/forge/cache.rb +1 -1
  41. data/lib/puppet/forge/errors.rb +3 -3
  42. data/lib/puppet/forge/repository.rb +7 -42
  43. data/lib/puppet/graph.rb +11 -0
  44. data/lib/puppet/graph/key.rb +26 -0
  45. data/lib/puppet/graph/prioritizer.rb +29 -0
  46. data/lib/puppet/graph/random_prioritizer.rb +16 -0
  47. data/lib/puppet/{rb_tree_map.rb → graph/rb_tree_map.rb} +3 -3
  48. data/lib/puppet/graph/relationship_graph.rb +246 -0
  49. data/lib/puppet/graph/sequential_prioritizer.rb +31 -0
  50. data/lib/puppet/{simple_graph.rb → graph/simple_graph.rb} +22 -3
  51. data/lib/puppet/graph/title_hash_prioritizer.rb +16 -0
  52. data/lib/puppet/indirector.rb +2 -2
  53. data/lib/puppet/indirector/catalog/compiler.rb +10 -7
  54. data/lib/puppet/indirector/catalog/static_compiler.rb +50 -0
  55. data/lib/puppet/indirector/certificate/rest.rb +1 -1
  56. data/lib/puppet/indirector/exec.rb +1 -1
  57. data/lib/puppet/indirector/facts/facter.rb +2 -2
  58. data/lib/puppet/indirector/facts/inventory_active_record.rb +0 -1
  59. data/lib/puppet/indirector/facts/network_device.rb +1 -1
  60. data/lib/puppet/indirector/file_bucket_file/file.rb +0 -1
  61. data/lib/puppet/indirector/indirection.rb +2 -2
  62. data/lib/puppet/indirector/memory.rb +9 -0
  63. data/lib/puppet/indirector/node/ldap.rb +2 -4
  64. data/lib/puppet/indirector/report/processor.rb +1 -2
  65. data/lib/puppet/indirector/report/rest.rb +1 -1
  66. data/lib/puppet/indirector/request.rb +32 -10
  67. data/lib/puppet/indirector/resource/rest.rb +1 -1
  68. data/lib/puppet/indirector/resource_type/parser.rb +31 -12
  69. data/lib/puppet/interface.rb +1 -1
  70. data/lib/puppet/interface/documentation.rb +7 -11
  71. data/lib/puppet/interface/option.rb +1 -1
  72. data/lib/puppet/interface/option_builder.rb +1 -1
  73. data/lib/puppet/metatype/manager.rb +2 -2
  74. data/lib/puppet/module.rb +7 -1
  75. data/lib/puppet/module_tool.rb +1 -1
  76. data/lib/puppet/module_tool/applications/application.rb +10 -0
  77. data/lib/puppet/module_tool/applications/installer.rb +6 -3
  78. data/lib/puppet/module_tool/dependency.rb +2 -0
  79. data/lib/puppet/module_tool/errors/upgrader.rb +1 -1
  80. data/lib/puppet/module_tool/metadata.rb +25 -13
  81. data/lib/puppet/module_tool/modulefile.rb +7 -7
  82. data/lib/puppet/module_tool/shared_behaviors.rb +4 -2
  83. data/lib/puppet/module_tool/skeleton.rb +1 -1
  84. data/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb +5 -5
  85. data/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb +5 -4
  86. data/lib/puppet/network/auth_config_parser.rb +3 -0
  87. data/lib/puppet/network/authconfig.rb +0 -1
  88. data/lib/puppet/network/authorization.rb +1 -1
  89. data/lib/puppet/network/authstore.rb +2 -2
  90. data/lib/puppet/network/format_handler.rb +25 -114
  91. data/lib/puppet/network/format_support.rb +106 -0
  92. data/lib/puppet/network/formats.rb +10 -4
  93. data/lib/puppet/network/http/compression.rb +1 -1
  94. data/lib/puppet/network/http/connection.rb +76 -32
  95. data/lib/puppet/network/http/handler.rb +122 -61
  96. data/lib/puppet/network/http/rack/rest.rb +1 -1
  97. data/lib/puppet/network/http/webrick/rest.rb +9 -3
  98. data/lib/puppet/network/http_pool.rb +2 -2
  99. data/lib/puppet/network/resolver.rb +1 -0
  100. data/lib/puppet/network/server.rb +5 -81
  101. data/lib/puppet/node/environment.rb +256 -13
  102. data/lib/puppet/node/facts.rb +28 -2
  103. data/lib/puppet/parameter.rb +27 -18
  104. data/lib/puppet/parameter/boolean.rb +20 -0
  105. data/lib/puppet/parameter/path.rb +1 -1
  106. data/lib/puppet/parameter/value.rb +1 -1
  107. data/lib/puppet/parameter/value_collection.rb +1 -1
  108. data/lib/puppet/parser/ast/arithmetic_operator.rb +8 -0
  109. data/lib/puppet/parser/ast/casestatement.rb +0 -3
  110. data/lib/puppet/parser/ast/lambda.rb +25 -6
  111. data/lib/puppet/parser/ast/leaf.rb +10 -3
  112. data/lib/puppet/parser/ast/nop.rb +1 -1
  113. data/lib/puppet/parser/ast/resource_override.rb +0 -2
  114. data/lib/puppet/parser/compiler.rb +92 -34
  115. data/lib/puppet/parser/files.rb +0 -5
  116. data/lib/puppet/parser/functions/create_resources.rb +23 -46
  117. data/lib/puppet/parser/functions/each.rb +0 -2
  118. data/lib/puppet/parser/functions/extlookup.rb +2 -2
  119. data/lib/puppet/parser/functions/foreach.rb +0 -2
  120. data/lib/puppet/parser/functions/hiera_include.rb +1 -1
  121. data/lib/puppet/parser/functions/lookup.rb +44 -0
  122. data/lib/puppet/parser/functions/slice.rb +1 -1
  123. data/lib/puppet/parser/grammar.ra +0 -1
  124. data/lib/puppet/parser/lexer.rb +0 -1
  125. data/lib/puppet/parser/parser.rb +0 -1
  126. data/lib/puppet/parser/parser_factory.rb +3 -2
  127. data/lib/puppet/parser/parser_support.rb +1 -1
  128. data/lib/puppet/parser/relationship.rb +1 -1
  129. data/lib/puppet/parser/scope.rb +49 -24
  130. data/lib/puppet/parser/type_loader.rb +13 -18
  131. data/lib/puppet/pops.rb +45 -0
  132. data/lib/puppet/pops/adaptable.rb +2 -2
  133. data/lib/puppet/pops/adapters.rb +4 -0
  134. data/lib/puppet/pops/binder/binder.rb +421 -0
  135. data/lib/puppet/pops/binder/binder_issues.rb +142 -0
  136. data/lib/puppet/pops/binder/bindings_checker.rb +217 -0
  137. data/lib/puppet/pops/binder/bindings_composer.rb +241 -0
  138. data/lib/puppet/pops/binder/bindings_factory.rb +847 -0
  139. data/lib/puppet/pops/binder/bindings_label_provider.rb +46 -0
  140. data/lib/puppet/pops/binder/bindings_loader.rb +79 -0
  141. data/lib/puppet/pops/binder/bindings_model.rb +215 -0
  142. data/lib/puppet/pops/binder/bindings_model_dumper.rb +205 -0
  143. data/lib/puppet/pops/binder/bindings_validator_factory.rb +28 -0
  144. data/lib/puppet/pops/binder/config/binder_config.rb +139 -0
  145. data/lib/puppet/pops/binder/config/binder_config_checker.rb +183 -0
  146. data/lib/puppet/pops/binder/config/diagnostic_producer.rb +32 -0
  147. data/lib/puppet/pops/binder/config/issues.rb +106 -0
  148. data/lib/puppet/pops/binder/hiera2.rb +10 -0
  149. data/lib/puppet/pops/binder/hiera2/bindings_provider.rb +148 -0
  150. data/lib/puppet/pops/binder/hiera2/config.rb +69 -0
  151. data/lib/puppet/pops/binder/hiera2/config_checker.rb +68 -0
  152. data/lib/puppet/pops/binder/hiera2/diagnostic_producer.rb +36 -0
  153. data/lib/puppet/pops/binder/hiera2/issues.rb +67 -0
  154. data/lib/puppet/pops/binder/hiera2/json_backend.rb +18 -0
  155. data/lib/puppet/pops/binder/hiera2/yaml_backend.rb +21 -0
  156. data/lib/puppet/pops/binder/injector.rb +688 -0
  157. data/lib/puppet/pops/binder/injector_entry.rb +53 -0
  158. data/lib/puppet/pops/binder/key_factory.rb +61 -0
  159. data/lib/puppet/pops/binder/producers.rb +829 -0
  160. data/lib/puppet/pops/binder/scheme_handler/confdir_hiera_scheme.rb +67 -0
  161. data/lib/puppet/pops/binder/scheme_handler/confdir_scheme.rb +34 -0
  162. data/lib/puppet/pops/binder/scheme_handler/module_hiera_scheme.rb +92 -0
  163. data/lib/puppet/pops/binder/scheme_handler/module_scheme.rb +84 -0
  164. data/lib/puppet/pops/binder/scheme_handler/symbolic_scheme.rb +54 -0
  165. data/lib/puppet/pops/binder/system_bindings.rb +72 -0
  166. data/lib/puppet/pops/issue_reporter.rb +75 -0
  167. data/lib/puppet/pops/issues.rb +9 -5
  168. data/lib/puppet/pops/model/ast_transformer.rb +4 -4
  169. data/lib/puppet/pops/model/ast_tree_dumper.rb +1 -1
  170. data/lib/puppet/pops/model/factory.rb +25 -13
  171. data/lib/puppet/pops/model/model.rb +1 -1
  172. data/lib/puppet/pops/model/tree_dumper.rb +2 -2
  173. data/lib/puppet/pops/parser/egrammar.ra +0 -1
  174. data/lib/puppet/pops/parser/eparser.rb +1 -2
  175. data/lib/puppet/pops/parser/evaluating_parser.rb +162 -0
  176. data/lib/puppet/pops/parser/lexer.rb +8 -6
  177. data/lib/puppet/pops/types/class_loader.rb +118 -0
  178. data/lib/puppet/pops/types/type_calculator.rb +557 -0
  179. data/lib/puppet/pops/types/type_factory.rb +147 -0
  180. data/lib/puppet/pops/types/type_parser.rb +117 -0
  181. data/lib/puppet/pops/types/types.rb +132 -0
  182. data/lib/puppet/pops/validation.rb +146 -17
  183. data/lib/puppet/pops/validation/checker3_1.rb +1 -1
  184. data/lib/puppet/pops/validation/validator_factory_3_1.rb +6 -16
  185. data/lib/puppet/property.rb +3 -3
  186. data/lib/puppet/property/keyvalue.rb +1 -1
  187. data/lib/puppet/provider.rb +2 -2
  188. data/lib/puppet/provider/aixobject.rb +19 -21
  189. data/lib/puppet/provider/augeas/augeas.rb +3 -1
  190. data/lib/puppet/provider/command.rb +2 -2
  191. data/lib/puppet/provider/group/aix.rb +1 -1
  192. data/lib/puppet/provider/group/ldap.rb +1 -1
  193. data/lib/puppet/provider/macauthorization/macauthorization.rb +1 -1
  194. data/lib/puppet/provider/mailalias/aliases.rb +3 -8
  195. data/lib/puppet/provider/mcx/mcxcontent.rb +7 -1
  196. data/lib/puppet/provider/mount.rb +8 -3
  197. data/lib/puppet/provider/nameservice.rb +1 -1
  198. data/lib/puppet/provider/nameservice/directoryservice.rb +5 -5
  199. data/lib/puppet/provider/package/appdmg.rb +1 -1
  200. data/lib/puppet/provider/package/apt.rb +0 -1
  201. data/lib/puppet/provider/package/dpkg.rb +86 -32
  202. data/lib/puppet/provider/package/fink.rb +0 -2
  203. data/lib/puppet/provider/package/freebsd.rb +0 -2
  204. data/lib/puppet/provider/package/openbsd.rb +57 -10
  205. data/lib/puppet/provider/package/opkg.rb +0 -1
  206. data/lib/puppet/provider/package/pacman.rb +0 -1
  207. data/lib/puppet/provider/package/pip.rb +1 -1
  208. data/lib/puppet/provider/package/pkgdmg.rb +17 -6
  209. data/lib/puppet/provider/package/pkgutil.rb +1 -1
  210. data/lib/puppet/provider/package/portage.rb +9 -1
  211. data/lib/puppet/provider/package/ports.rb +2 -2
  212. data/lib/puppet/provider/package/rpm.rb +29 -12
  213. data/lib/puppet/provider/package/rug.rb +1 -1
  214. data/lib/puppet/provider/package/urpmi.rb +11 -15
  215. data/lib/puppet/provider/package/windows/exe_package.rb +1 -1
  216. data/lib/puppet/provider/package/windows/package.rb +1 -26
  217. data/lib/puppet/provider/package/yum.rb +1 -1
  218. data/lib/puppet/provider/package/zypper.rb +22 -3
  219. data/lib/puppet/provider/parsedfile.rb +1 -12
  220. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +1 -1
  221. data/lib/puppet/provider/service/base.rb +1 -1
  222. data/lib/puppet/provider/service/daemontools.rb +3 -3
  223. data/lib/puppet/provider/service/debian.rb +1 -1
  224. data/lib/puppet/provider/service/init.rb +14 -20
  225. data/lib/puppet/provider/service/openrc.rb +3 -1
  226. data/lib/puppet/provider/service/redhat.rb +5 -8
  227. data/lib/puppet/provider/service/runit.rb +3 -2
  228. data/lib/puppet/provider/service/systemd.rb +1 -1
  229. data/lib/puppet/provider/ssh_authorized_key/parsed.rb +1 -1
  230. data/lib/puppet/provider/sshkey/parsed.rb +0 -2
  231. data/lib/puppet/provider/user/aix.rb +25 -12
  232. data/lib/puppet/provider/user/directoryservice.rb +4 -7
  233. data/lib/puppet/provider/user/ldap.rb +0 -1
  234. data/lib/puppet/provider/user/user_role_add.rb +2 -0
  235. data/lib/puppet/provider/user/useradd.rb +1 -1
  236. data/lib/puppet/provider/zone/solaris.rb +1 -2
  237. data/lib/puppet/reference/metaparameter.rb +1 -1
  238. data/lib/puppet/reference/type.rb +1 -1
  239. data/lib/puppet/reports/rrdgraph.rb +1 -1
  240. data/lib/puppet/reports/tagmail.rb +1 -1
  241. data/lib/puppet/resource.rb +16 -4
  242. data/lib/puppet/resource/catalog.rb +111 -173
  243. data/lib/puppet/resource/status.rb +42 -3
  244. data/lib/puppet/resource/type.rb +33 -46
  245. data/lib/puppet/resource/type_collection.rb +19 -15
  246. data/lib/puppet/run.rb +5 -1
  247. data/lib/puppet/scheduler/scheduler.rb +14 -15
  248. data/lib/puppet/settings.rb +78 -41
  249. data/lib/puppet/settings/boolean_setting.rb +0 -2
  250. data/lib/puppet/settings/config_file.rb +0 -2
  251. data/lib/puppet/settings/directory_setting.rb +0 -2
  252. data/lib/puppet/settings/duration_setting.rb +0 -2
  253. data/lib/puppet/settings/enum_setting.rb +16 -0
  254. data/lib/puppet/settings/file_setting.rb +0 -2
  255. data/lib/puppet/settings/path_setting.rb +0 -2
  256. data/lib/puppet/settings/string_setting.rb +0 -3
  257. data/lib/puppet/settings/terminus_setting.rb +0 -2
  258. data/lib/puppet/ssl/certificate_authority.rb +102 -9
  259. data/lib/puppet/test/test_helper.rb +1 -0
  260. data/lib/puppet/transaction.rb +130 -292
  261. data/lib/puppet/transaction/additional_resource_generator.rb +126 -0
  262. data/lib/puppet/transaction/event.rb +16 -1
  263. data/lib/puppet/transaction/report.rb +34 -14
  264. data/lib/puppet/transaction/resource_harness.rb +16 -19
  265. data/lib/puppet/type.rb +59 -53
  266. data/lib/puppet/type/component.rb +0 -2
  267. data/lib/puppet/type/cron.rb +13 -2
  268. data/lib/puppet/type/exec.rb +5 -7
  269. data/lib/puppet/type/file.rb +9 -32
  270. data/lib/puppet/type/file/content.rb +4 -1
  271. data/lib/puppet/type/file/ctime.rb +3 -1
  272. data/lib/puppet/type/file/ensure.rb +1 -1
  273. data/lib/puppet/type/file/mode.rb +0 -1
  274. data/lib/puppet/type/file/mtime.rb +2 -1
  275. data/lib/puppet/type/group.rb +7 -9
  276. data/lib/puppet/type/host.rb +1 -2
  277. data/lib/puppet/type/mcx.rb +0 -1
  278. data/lib/puppet/type/mount.rb +38 -6
  279. data/lib/puppet/type/package.rb +2 -2
  280. data/lib/puppet/type/resources.rb +5 -4
  281. data/lib/puppet/type/schedule.rb +1 -4
  282. data/lib/puppet/type/selmodule.rb +1 -1
  283. data/lib/puppet/type/service.rb +1 -3
  284. data/lib/puppet/type/tidy.rb +3 -3
  285. data/lib/puppet/type/user.rb +9 -13
  286. data/lib/puppet/type/yumrepo.rb +11 -7
  287. data/lib/puppet/util.rb +14 -7
  288. data/lib/puppet/util/autoload.rb +0 -1
  289. data/lib/puppet/util/backups.rb +1 -3
  290. data/lib/puppet/util/classgen.rb +1 -1
  291. data/lib/puppet/util/command_line/puppet_option_parser.rb +1 -3
  292. data/lib/puppet/util/command_line/trollop.rb +1 -1
  293. data/lib/puppet/util/constant_inflector.rb +1 -2
  294. data/lib/puppet/util/errors.rb +1 -0
  295. data/lib/puppet/util/file_watcher.rb +28 -0
  296. data/lib/puppet/util/fileparsing.rb +1 -3
  297. data/lib/puppet/util/filetype.rb +0 -1
  298. data/lib/puppet/util/http_proxy.rb +38 -0
  299. data/lib/puppet/util/ldap/manager.rb +1 -2
  300. data/lib/puppet/util/log.rb +31 -10
  301. data/lib/puppet/util/log/destinations.rb +0 -50
  302. data/lib/puppet/util/metric.rb +8 -1
  303. data/lib/puppet/util/monkey_patches.rb +14 -148
  304. data/lib/puppet/util/network_device/cisco/facts.rb +1 -1
  305. data/lib/puppet/util/network_device/config.rb +6 -9
  306. data/lib/puppet/util/network_device/transport/ssh.rb +1 -1
  307. data/lib/puppet/util/pidlock.rb +3 -0
  308. data/lib/puppet/util/posix.rb +1 -1
  309. data/lib/puppet/util/profiler.rb +1 -1
  310. data/lib/puppet/util/rdoc.rb +1 -1
  311. data/lib/puppet/util/rdoc/generators/puppet_generator.rb +0 -1
  312. data/lib/puppet/util/rdoc/generators/template/puppet/puppet.rb +50 -42
  313. data/lib/puppet/util/retryaction.rb +0 -1
  314. data/lib/puppet/util/symbolic_file_mode.rb +5 -1
  315. data/lib/puppet/util/tagging.rb +0 -2
  316. data/lib/puppet/util/warnings.rb +3 -0
  317. data/lib/puppet/util/watched_file.rb +37 -0
  318. data/lib/puppet/util/watcher.rb +17 -0
  319. data/lib/puppet/util/watcher/change_watcher.rb +33 -0
  320. data/lib/puppet/util/watcher/periodic_watcher.rb +37 -0
  321. data/lib/puppet/util/watcher/timer.rb +19 -0
  322. data/lib/puppet/util/windows/user.rb +1 -1
  323. data/lib/puppet/version.rb +1 -1
  324. data/lib/puppetx.rb +109 -0
  325. data/lib/puppetx/puppet/bindings_scheme_handler.rb +130 -0
  326. data/lib/puppetx/puppet/hiera2_backend.rb +31 -0
  327. data/lib/puppetx/puppet/syntax_checker.rb +91 -0
  328. data/lib/puppetx/puppetlabs/syntax_checkers/json.rb +39 -0
  329. data/lib/semver.rb +1 -1
  330. data/man/man8/puppet-kick.8 +1 -1
  331. data/spec/fixtures/integration/provider/cron/crontab/unspecialized +15 -0
  332. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/binder_config.yaml +18 -0
  333. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/hiera.yaml +8 -0
  334. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/modules/good/common.yaml +1 -0
  335. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/modules/good/hiera.yaml +10 -0
  336. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/binder_config.yaml +19 -0
  337. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/common.yaml +1 -0
  338. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/hiera.yaml +11 -0
  339. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/localhost.yaml +1 -0
  340. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/common.yaml +3 -0
  341. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/hiera.yaml +13 -0
  342. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppet/bindings/awesome/default.rb +4 -0
  343. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppetx/awesome/echo_backend.rb +11 -0
  344. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppetx/awesome/echo_scheme_handler.rb +18 -0
  345. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/localhost.yaml +1 -0
  346. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/bad/common.yaml +3 -0
  347. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/bad/hiera_config.yaml +9 -0
  348. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/good/common.yaml +2 -0
  349. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/good/hiera.yaml +11 -0
  350. data/spec/fixtures/unit/pops/binder/config/binder_config/ok/binder_config.yaml +9 -0
  351. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/hiera.yaml +9 -0
  352. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/node.example.com.json +9 -0
  353. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/node.example.com.yaml +5 -0
  354. data/spec/fixtures/unit/pops/binder/hiera2/config/bad_syntax/hiera.yaml +10 -0
  355. data/spec/fixtures/unit/pops/binder/hiera2/config/malformed_hierarchy/hiera.yaml +8 -0
  356. data/spec/fixtures/unit/pops/binder/hiera2/config/missing/foo.txt +1 -0
  357. data/spec/fixtures/unit/pops/binder/hiera2/config/no_backends/hiera.yaml +7 -0
  358. data/spec/fixtures/unit/pops/binder/hiera2/config/no_hierarchy/hiera.yaml +4 -0
  359. data/spec/fixtures/unit/pops/binder/hiera2/config/not_a_hash/hiera.yaml +2 -0
  360. data/spec/fixtures/unit/pops/binder/hiera2/config/ok/hiera.yaml +8 -0
  361. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/empty/common.yaml +0 -0
  362. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/invalid/common.yaml +1 -0
  363. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/ok/common.yaml +2 -0
  364. data/spec/fixtures/unit/provider/package/openbsd/pkginfo_flavors.list +2 -0
  365. data/spec/integration/agent/logging_spec.rb +178 -0
  366. data/spec/integration/configurer_spec.rb +1 -1
  367. data/spec/integration/defaults_spec.rb +0 -6
  368. data/spec/integration/network/authconfig_spec.rb +19 -0
  369. data/spec/integration/network/server/webrick_spec.rb +10 -11
  370. data/spec/integration/parser/catalog_spec.rb +85 -0
  371. data/spec/integration/provider/cron/crontab_spec.rb +11 -0
  372. data/spec/integration/provider/mount_spec.rb +1 -0
  373. data/spec/integration/transaction_spec.rb +8 -8
  374. data/spec/integration/type/file_spec.rb +1 -1
  375. data/spec/integration/util/settings_spec.rb +58 -11
  376. data/spec/lib/matchers/include_in_order.rb +21 -0
  377. data/spec/lib/matchers/include_in_order_spec.rb +30 -0
  378. data/spec/lib/matchers/relationship_graph_matchers.rb +48 -0
  379. data/spec/lib/puppet_spec/compiler.rb +24 -0
  380. data/spec/lib/puppet_spec/pops.rb +16 -0
  381. data/spec/spec_helper.rb +0 -1
  382. data/spec/unit/application/agent_spec.rb +145 -145
  383. data/spec/unit/application/apply_spec.rb +1 -1
  384. data/spec/unit/application/doc_spec.rb +1 -1
  385. data/spec/unit/application/face_base_spec.rb +3 -3
  386. data/spec/unit/application/facts_spec.rb +1 -0
  387. data/spec/unit/application/master_spec.rb +0 -15
  388. data/spec/unit/application/queue_spec.rb +6 -12
  389. data/spec/unit/application/resource_spec.rb +1 -1
  390. data/spec/unit/configurer/fact_handler_spec.rb +19 -50
  391. data/spec/unit/configurer_spec.rb +23 -7
  392. data/spec/unit/daemon_spec.rb +97 -121
  393. data/spec/unit/defaults_spec.rb +44 -0
  394. data/spec/unit/face/node_spec.rb +2 -2
  395. data/spec/unit/file_serving/configuration/parser_spec.rb +23 -33
  396. data/spec/unit/file_serving/configuration_spec.rb +2 -2
  397. data/spec/unit/file_serving/mount/file_spec.rb +4 -4
  398. data/spec/unit/forge/repository_spec.rb +9 -29
  399. data/spec/unit/graph/key_spec.rb +41 -0
  400. data/spec/unit/{rb_tree_map_spec.rb → graph/rb_tree_map_spec.rb} +7 -7
  401. data/spec/unit/graph/relationship_graph_spec.rb +393 -0
  402. data/spec/unit/graph/sequential_prioritizer_spec.rb +32 -0
  403. data/spec/unit/{simple_graph_spec.rb → graph/simple_graph.rb} +42 -254
  404. data/spec/unit/graph/title_hash_prioritizer_spec.rb +49 -0
  405. data/spec/unit/hiera_puppet_spec.rb +1 -1
  406. data/spec/unit/indirector/catalog/active_record_spec.rb +4 -2
  407. data/spec/unit/indirector/catalog/compiler_spec.rb +20 -26
  408. data/spec/unit/indirector/face_spec.rb +1 -1
  409. data/spec/unit/indirector/facts/facter_spec.rb +11 -1
  410. data/spec/unit/indirector/facts/network_device_spec.rb +11 -1
  411. data/spec/unit/indirector/hiera_spec.rb +1 -1
  412. data/spec/unit/indirector/instrumentation_data/local_spec.rb +1 -1
  413. data/spec/unit/indirector/instrumentation_listener/local_spec.rb +1 -1
  414. data/spec/unit/indirector/request_spec.rb +92 -39
  415. data/spec/unit/indirector/rest_spec.rb +1 -0
  416. data/spec/unit/indirector_spec.rb +2 -2
  417. data/spec/unit/interface/option_builder_spec.rb +1 -0
  418. data/spec/unit/interface/option_spec.rb +1 -0
  419. data/spec/unit/interface_spec.rb +2 -2
  420. data/spec/unit/module_tool/applications/installer_spec.rb +49 -2
  421. data/spec/unit/module_tool/metadata_spec.rb +13 -0
  422. data/spec/unit/network/authstore_spec.rb +1 -1
  423. data/spec/unit/network/format_handler_spec.rb +33 -282
  424. data/spec/unit/network/format_support_spec.rb +199 -0
  425. data/spec/unit/network/formats_spec.rb +2 -2
  426. data/spec/unit/network/http/connection_spec.rb +88 -7
  427. data/spec/unit/network/http/handler_spec.rb +271 -249
  428. data/spec/unit/network/http/rack/rest_spec.rb +1 -1
  429. data/spec/unit/network/http/webrick/rest_spec.rb +73 -22
  430. data/spec/unit/network/http_pool_spec.rb +40 -0
  431. data/spec/unit/network/server_spec.rb +18 -207
  432. data/spec/unit/node/facts_spec.rb +68 -17
  433. data/spec/unit/other/selinux_spec.rb +24 -20
  434. data/spec/unit/parameter/boolean_spec.rb +25 -0
  435. data/spec/unit/parameter/value_collection_spec.rb +7 -7
  436. data/spec/unit/parameter_spec.rb +10 -13
  437. data/spec/unit/parser/ast/function_spec.rb +4 -4
  438. data/spec/unit/parser/ast/leaf_spec.rb +45 -6
  439. data/spec/unit/parser/collector_spec.rb +3 -3
  440. data/spec/unit/parser/compiler_spec.rb +4 -3
  441. data/spec/unit/parser/functions/create_resources_spec.rb +9 -25
  442. data/spec/unit/parser/functions/extlookup_spec.rb +2 -2
  443. data/spec/unit/parser/functions/hiera_include_spec.rb +12 -0
  444. data/spec/unit/parser/functions/lookup_spec.rb +96 -0
  445. data/spec/unit/parser/functions/regsubst_spec.rb +2 -2
  446. data/spec/unit/parser/functions/split_spec.rb +2 -2
  447. data/spec/unit/parser/functions/sprintf_spec.rb +1 -1
  448. data/spec/unit/parser/functions/versioncmp_spec.rb +2 -2
  449. data/spec/unit/parser/functions_spec.rb +7 -7
  450. data/spec/unit/parser/lexer_spec.rb +1 -1
  451. data/spec/unit/parser/methods/collect_spec.rb +43 -0
  452. data/spec/unit/parser/resource_spec.rb +9 -9
  453. data/spec/unit/parser/scope_spec.rb +45 -2
  454. data/spec/unit/parser/type_loader_spec.rb +159 -175
  455. data/spec/unit/pops/binder/binder_spec.rb +62 -0
  456. data/spec/unit/pops/binder/bindings_checker_spec.rb +196 -0
  457. data/spec/unit/pops/binder/bindings_composer_spec.rb +89 -0
  458. data/spec/unit/pops/binder/bindings_validator_factory_spec.rb +18 -0
  459. data/spec/unit/pops/binder/config/binder_config_spec.rb +48 -0
  460. data/spec/unit/pops/binder/hiera2/bindings_provider_spec.rb +74 -0
  461. data/spec/unit/pops/binder/hiera2/config_spec.rb +61 -0
  462. data/spec/unit/pops/binder/hiera2/yaml_backend_spec.rb +33 -0
  463. data/spec/unit/pops/binder/injector_spec.rb +789 -0
  464. data/spec/unit/pops/containment_spec.rb +1 -0
  465. data/spec/unit/pops/issues_spec.rb +1 -1
  466. data/spec/unit/pops/parser/evaluating_parser_spec.rb +88 -0
  467. data/spec/unit/pops/parser/lexer_spec.rb +1 -1
  468. data/spec/unit/pops/parser/parse_calls_spec.rb +4 -0
  469. data/spec/unit/pops/parser/parser_spec.rb +1 -1
  470. data/spec/unit/pops/types/type_calculator_spec.rb +484 -0
  471. data/spec/unit/pops/types/type_factory_spec.rb +65 -0
  472. data/spec/unit/pops/types/type_parser_spec.rb +93 -0
  473. data/spec/unit/property/list_spec.rb +1 -1
  474. data/spec/unit/property/ordered_list_spec.rb +1 -1
  475. data/spec/unit/provider/aixobject_spec.rb +101 -0
  476. data/spec/unit/provider/augeas/augeas_spec.rb +14 -3
  477. data/spec/unit/provider/mcx/mcxcontent_spec.rb +52 -16
  478. data/spec/unit/provider/mount/parsed_spec.rb +44 -56
  479. data/spec/unit/provider/mount_spec.rb +11 -2
  480. data/spec/unit/provider/naginator_spec.rb +8 -0
  481. data/spec/unit/provider/package/apt_spec.rb +5 -1
  482. data/spec/unit/provider/package/aptitude_spec.rb +9 -5
  483. data/spec/unit/provider/package/aptrpm_spec.rb +2 -2
  484. data/spec/unit/provider/package/dpkg_spec.rb +274 -99
  485. data/spec/unit/provider/package/openbsd_spec.rb +84 -1
  486. data/spec/unit/provider/package/opkg_spec.rb +3 -3
  487. data/spec/unit/provider/package/pip_spec.rb +16 -0
  488. data/spec/unit/provider/package/pkgdmg_spec.rb +62 -7
  489. data/spec/unit/provider/package/rpm_spec.rb +112 -21
  490. data/spec/unit/provider/package/urpmi.rb +80 -0
  491. data/spec/unit/provider/package/windows/exe_package_spec.rb +1 -1
  492. data/spec/unit/provider/package/yum_spec.rb +85 -0
  493. data/spec/unit/provider/package/zypper_spec.rb +25 -6
  494. data/spec/unit/provider/parsedfile_spec.rb +3 -2
  495. data/spec/unit/provider/service/init_spec.rb +10 -10
  496. data/spec/unit/provider/service/openrc_spec.rb +16 -0
  497. data/spec/unit/provider/service/openwrt_spec.rb +1 -1
  498. data/spec/unit/provider/service/redhat_spec.rb +7 -0
  499. data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +2 -2
  500. data/spec/unit/provider/user/aix_spec.rb +89 -0
  501. data/spec/unit/provider/user/directoryservice_spec.rb +11 -4
  502. data/spec/unit/provider/user/user_role_add_spec.rb +18 -0
  503. data/spec/unit/provider_spec.rb +2 -13
  504. data/spec/unit/reports/http_spec.rb +1 -1
  505. data/spec/unit/resource/catalog_spec.rb +23 -97
  506. data/spec/unit/resource/resource_type.json +34 -0
  507. data/spec/unit/resource/status_spec.rb +56 -0
  508. data/spec/unit/resource/type_collection_spec.rb +6 -6
  509. data/spec/unit/resource/type_spec.rb +25 -5
  510. data/spec/unit/resource_spec.rb +68 -24
  511. data/spec/unit/run_spec.rb +16 -0
  512. data/spec/unit/scheduler/scheduler_spec.rb +14 -27
  513. data/spec/unit/semver_spec.rb +5 -0
  514. data/spec/unit/settings/enum_setting_spec.rb +27 -0
  515. data/spec/unit/settings_spec.rb +53 -44
  516. data/spec/unit/ssl/certificate_authority_spec.rb +155 -19
  517. data/spec/unit/transaction/additional_resource_generator_spec.rb +419 -0
  518. data/spec/unit/transaction/event_manager_spec.rb +2 -2
  519. data/spec/unit/transaction/event_spec.rb +57 -0
  520. data/spec/unit/transaction/report_spec.rb +66 -0
  521. data/spec/unit/transaction/resource_harness_spec.rb +27 -20
  522. data/spec/unit/transaction_spec.rb +182 -390
  523. data/spec/unit/type/augeas_spec.rb +3 -3
  524. data/spec/unit/type/component_spec.rb +0 -9
  525. data/spec/unit/type/computer_spec.rb +1 -1
  526. data/spec/unit/type/cron_spec.rb +2 -2
  527. data/spec/unit/type/exec_spec.rb +4 -2
  528. data/spec/unit/type/file/content_spec.rb +11 -0
  529. data/spec/unit/type/file/group_spec.rb +1 -1
  530. data/spec/unit/type/file_spec.rb +16 -8
  531. data/spec/unit/type/mount_spec.rb +445 -259
  532. data/spec/unit/type/package_spec.rb +4 -4
  533. data/spec/unit/type/resources_spec.rb +30 -1
  534. data/spec/unit/type/user_spec.rb +26 -3
  535. data/spec/unit/type/yumrepo_spec.rb +7 -27
  536. data/spec/unit/type/zone_spec.rb +4 -1
  537. data/spec/unit/type_spec.rb +66 -33
  538. data/spec/unit/util/backups_spec.rb +3 -3
  539. data/spec/unit/util/http_proxy_spec.rb +83 -0
  540. data/spec/unit/util/log_spec.rb +79 -8
  541. data/spec/unit/util/metric_spec.rb +12 -0
  542. data/spec/unit/util/monkey_patches_spec.rb +6 -0
  543. data/spec/unit/util/network_device/config_spec.rb +26 -64
  544. data/spec/unit/util/pidlock_spec.rb +4 -1
  545. data/spec/unit/util/tagging_spec.rb +5 -9
  546. data/spec/unit/util/warnings_spec.rb +1 -1
  547. data/spec/unit/util/watched_file_spec.rb +52 -0
  548. data/spec/unit/util/watcher/periodic_watcher_spec.rb +52 -0
  549. data/spec/unit/util/watcher_spec.rb +56 -0
  550. data/spec/unit/util_spec.rb +16 -0
  551. metadata +2767 -2576
  552. data/ext/debian/puppet.manpages +0 -32
  553. data/ext/osx/PackageInfo.plist +0 -36
  554. data/ext/osx/createpackage.sh +0 -187
  555. data/ext/redhat/rundir-perms.patch +0 -28
  556. data/lib/puppet/external/base64.rb +0 -19
  557. data/lib/puppet/util/graph.rb +0 -27
  558. data/lib/puppet/util/loadedfile.rb +0 -61
  559. data/lib/puppet/util/log_paths.rb +0 -22
  560. data/lib/puppet/util/subclass_loader.rb +0 -78
  561. data/spec/monkey_patches/publicize_methods.rb +0 -11
  562. data/spec/unit/util/loadedfile_spec.rb +0 -71
@@ -0,0 +1,53 @@
1
+ # Represents an entry in the injectors internal data.
2
+ #
3
+ # @api public
4
+ #
5
+ class Puppet::Pops::Binder::InjectorEntry
6
+ # @return [Object] An opaque object representing the precedence
7
+ # @api public
8
+ attr_reader :precedence
9
+
10
+ # @return [Puppet::Pops::Binder::Bindings::Binding] The binding for this entry
11
+ # @api public
12
+ attr_reader :binding
13
+
14
+ # @api private
15
+ attr_accessor :resolved
16
+
17
+ # @api private
18
+ attr_accessor :cached_producer
19
+
20
+ # @api private
21
+ def initialize(precedence, binding)
22
+ @precedence = precedence.freeze
23
+ @binding = binding
24
+ @cached_producer = nil
25
+ end
26
+
27
+ # Marks an overriding entry as resolved (if not an overriding entry, the marking has no effect).
28
+ # @api private
29
+ #
30
+ def mark_override_resolved()
31
+ @resolved = true
32
+ end
33
+
34
+ # The binding is resolved if it is non-override, or if the override has been resolved
35
+ # @api private
36
+ #
37
+ def is_resolved?()
38
+ !binding.override || resolved
39
+ end
40
+
41
+ def is_abstract?
42
+ binding.abstract
43
+ end
44
+
45
+ # Compares against another InjectorEntry by comparing precedence.
46
+ # @param injector_entry [InjectorEntry] entry to compare against.
47
+ # @return [Integer] 1, if this entry has higher precedence, 0 if equal, and -1 if given entry has higher precedence.
48
+ # @api public
49
+ #
50
+ def <=> (injector_entry)
51
+ precedence <=> injector_entry.precedence
52
+ end
53
+ end
@@ -0,0 +1,61 @@
1
+ # The KeyFactory is responsible for creating keys used for lookup of bindings.
2
+ # @api public
3
+ #
4
+ class Puppet::Pops::Binder::KeyFactory
5
+
6
+ attr_reader :type_calculator
7
+ # @api public
8
+ def initialize(type_calculator = Puppet::Pops::Types::TypeCalculator.new())
9
+ @type_calculator = type_calculator
10
+ end
11
+
12
+ # @api public
13
+ def binding_key(binding)
14
+ named_key(binding.type, binding.name)
15
+ end
16
+
17
+ # @api public
18
+ def named_key(type, name)
19
+ [(@type_calculator.assignable?(@type_calculator.data, type) ? @type_calculator.data : type), name]
20
+ end
21
+
22
+ # @api public
23
+ def data_key(name)
24
+ [@type_calculator.data, name]
25
+ end
26
+
27
+ # @api public
28
+ def is_contributions_key?(s)
29
+ return false unless s.is_a?(String)
30
+ s.start_with?('mc_')
31
+ end
32
+
33
+ # @api public
34
+ def multibind_contributions(multibind_id)
35
+ "mc_#{multibind_id}"
36
+ end
37
+
38
+ # @api public
39
+ def is_named?(key)
40
+ key.is_a?(Array) && key[1] && !key[1].empty?
41
+ end
42
+
43
+ # @api public
44
+ def is_data?(key)
45
+ return false unless key.is_a?(Array) && key[0].is_a?(Puppet::Pops::Types::PObjectType)
46
+ type_calculator.assignable?(type_calculator.data(), key[0])
47
+ end
48
+
49
+ # @api public
50
+ def is_ruby?(key)
51
+ return key.is_a?(Array) && key[0].is_a?(Puppet::Pops::Types::PRubyType)
52
+ end
53
+
54
+ # Returns the type of the key
55
+ # @api public
56
+ #
57
+ def get_type(key)
58
+ return nil unless key.is_a?(Array)
59
+ key[0]
60
+ end
61
+ end
@@ -0,0 +1,829 @@
1
+ # This module contains the various producers used by Puppet Bindings.
2
+ # The main (abstract) class is {Puppet::Pops::Binder::Producers::Producer} which documents the
3
+ # Producer API and serves as a base class for all other producers.
4
+ # It is required that custom producers inherit from this producer (directly or indirectly).
5
+ #
6
+ # The selection of a Producer is typically performed by the Innjector when it configures itself
7
+ # from a Bindings model where a {Puppet::Pops::Binder::Bindings::ProducerDescriptor} describes
8
+ # which producer to use. The configuration uses this to create the concrete producer.
9
+ # It is possible to describe that a particular producer class is to be used, and also to describe that
10
+ # a custom producer (derived from Producer) should be used. This is available for both regular
11
+ # bindings as well as multi-bindings.
12
+ #
13
+ #
14
+ # @api public
15
+ #
16
+ module Puppet::Pops::Binder::Producers
17
+ # Producer is an abstract base class representing the base contract for a bound producer.
18
+ # Typically, when a lookup is performed it is the value that is returned (via a producer), but
19
+ # it is also possible to lookup the producer, and ask it to produce the value (the producer may
20
+ # return a series of values, which makes this especially useful).
21
+ #
22
+ # When looking up a producer, it is of importance to only use the API of the Producer class
23
+ # unless it is known that a particular custom producer class has been bound.
24
+ #
25
+ # Custom Producers
26
+ # ----------------
27
+ # The intent is that this class is derived for custom producers that require additional
28
+ # options/arguments when producing an instance. Such a custom producer may raise an error if called
29
+ # with too few arguments, or may implement specific `produce` methods and always raise an
30
+ # error on #produce indicating that this producer requires custom calls and that it can not
31
+ # be used as an implicit producer.
32
+ #
33
+ # Features of Producer
34
+ # --------------------
35
+ # The Producer class is abstract, but offers the ability to transform the produced result
36
+ # by passing the option `:transformer` which should be a Puppet Lambda Expression taking one argument
37
+ # and producing the transformed (wanted) result.
38
+ #
39
+ # @abstract
40
+ # @api public
41
+ #
42
+ class Producer
43
+ # A Puppet 3 AST Lambda Expression
44
+ # @api public
45
+ #
46
+ attr_reader :transformer
47
+
48
+ # Creates a Producer.
49
+ # Derived classes should call this constructor to get support for transformer lambda.
50
+ #
51
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
52
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
53
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
54
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
55
+ # @api public
56
+ #
57
+ def initialize(injector, binding, scope, options)
58
+ if transformer_lambda = options[:transformer]
59
+ if transformer_lambda.is_a?(Proc)
60
+ raise ArgumentError, "Transformer Proc must take two arguments; scope, value." unless transformer_lambda.arity == 2
61
+ @transformer = transformer_lambda
62
+ else
63
+ raise ArgumentError, "Transformer must be a LambdaExpression" unless transformer_lambda.is_a?(Puppet::Pops::Model::LambdaExpression)
64
+ raise ArgumentError, "Transformer lambda must take one argument; value." unless transformer_lambda.parameters.size() == 1
65
+ # NOTE: This depends on Puppet 3 AST Lambda
66
+ @transformer = Puppet::Pops::Model::AstTransformer.new().transform(transformer_lambda)
67
+ end
68
+ end
69
+ end
70
+
71
+ # Produces an instance.
72
+ # @param scope [Puppet::Parser:Scope] the scope to use for evaluation
73
+ # @param args [Object] arguments to custom producers, always empty for implicit productions
74
+ # @return [Object] the produced instance (should never be nil).
75
+ # @api public
76
+ #
77
+ def produce(scope, *args)
78
+ do_transformation(scope, internal_produce(scope))
79
+ end
80
+
81
+ # Returns the producer after possibly having recreated an internal/wrapped producer.
82
+ # This implementation returns `self`. A derived class may want to override this method
83
+ # to perform initialization/refresh of its internal state. This method is called when
84
+ # a producer is requested.
85
+ # @see Puppet::Pops::Binder::ProducerProducer for an example of implementation.
86
+ # @param scope [Puppet::Parser:Scope] the scope to use for evaluation
87
+ # @return [Puppet::Pops::Binder::Producer] the producer to use
88
+ # @api public
89
+ #
90
+ def producer(scope)
91
+ self
92
+ end
93
+
94
+ protected
95
+
96
+ # Derived classes should implement this method to do the production of a value
97
+ # @param scope [Puppet::Parser::Scope] the scope to use when performing lookup and evaluation
98
+ # @raise [NotImplementedError] this implementation always raises an error
99
+ # @abstract
100
+ # @api private
101
+ #
102
+ def internal_produce(scope)
103
+ raise NotImplementedError, "Producer-class '#{self.class.name}' should implement #internal_produce(scope)"
104
+ end
105
+
106
+ # Transforms the produced value if a transformer has been defined.
107
+ # @param scope [Puppet::Parser::Scope] the scope used for evaluation
108
+ # @param produced_value [Object, nil] the produced value (possibly nil)
109
+ # @return [Object] the transformed value if a transformer is defined, else the given `produced_value`
110
+ # @api private
111
+ #
112
+ def do_transformation(scope, produced_value)
113
+ return produced_value unless transformer
114
+ produced_value = :undef if produced_value.nil?
115
+ transformer.call(scope, produced_value)
116
+ end
117
+ end
118
+
119
+ # Abstract Producer holding a value
120
+ # @abstract
121
+ # @api public
122
+ #
123
+ class AbstractValueProducer < Producer
124
+
125
+ # @api public
126
+ attr_reader :value
127
+
128
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
129
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
130
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
131
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
132
+ # @option options [Puppet::Pops::Model::LambdaExpression, nil] :value (nil) the value to produce
133
+ # @api public
134
+ #
135
+ def initialize(injector, binding, scope, options)
136
+ super
137
+ # nil is ok here, as an abstract value producer may be used to signal "not found"
138
+ @value = options[:value]
139
+ end
140
+ end
141
+
142
+ # Produces the same/singleton value on each production
143
+ # @api public
144
+ #
145
+ class SingletonProducer < AbstractValueProducer
146
+ protected
147
+
148
+ # @api private
149
+ def internal_produce(scope)
150
+ value()
151
+ end
152
+ end
153
+
154
+ # Produces a deep clone of its value on each production.
155
+ # @api public
156
+ #
157
+ class DeepCloningProducer < AbstractValueProducer
158
+ protected
159
+
160
+ # @api private
161
+ def internal_produce(scope)
162
+ case value
163
+ when Integer, Float, TrueClass, FalseClass, Symbol
164
+ # These are immutable
165
+ return value
166
+ when String
167
+ # ok if frozen, else fall through to default
168
+ return value() if value.frozen?
169
+ end
170
+ # The default: serialize/deserialize to get a deep copy
171
+ Marshal.load(Marshal.dump(value()))
172
+ end
173
+ end
174
+
175
+ # This abstract producer class remembers the injector and binding.
176
+ # @abstract
177
+ # @api public
178
+ #
179
+ class AbstractArgumentedProducer < Producer
180
+
181
+ # @api public
182
+ attr_reader :injector
183
+
184
+ # @api public
185
+ attr_reader :binding
186
+
187
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
188
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
189
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
190
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
191
+ # @api public
192
+ #
193
+ def initialize(injector, binding, scope, options)
194
+ super
195
+ @injector = injector
196
+ @binding = binding
197
+ end
198
+ end
199
+
200
+ # @api public
201
+ class InstantiatingProducer < AbstractArgumentedProducer
202
+
203
+ # @api public
204
+ attr_reader :the_class
205
+
206
+ # @api public
207
+ attr_reader :init_args
208
+
209
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
210
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
211
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
212
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
213
+ # @option options [String] :class_name The name of the class to create instance of
214
+ # @option options [Array<Object>] :init_args ([]) Optional arguments to class constructor
215
+ # @api public
216
+ #
217
+ def initialize(injector, binding, scope, options)
218
+ # Better do this, even if a transformation of a created instance is kind of an odd thing to do, one can imagine
219
+ # sending it to a function for further detailing.
220
+ #
221
+ super
222
+ class_name = options[:class_name]
223
+ raise ArgumentError, "Option 'class_name' must be given for an InstantiatingProducer" unless class_name
224
+ # get class by name
225
+ @the_class = Puppet::Pops::Types::ClassLoader.provide(class_name)
226
+ @init_args = options[:init_args] || []
227
+ raise ArgumentError, "Can not load the class #{class_name} specified in binding named: '#{binding.name}'" unless @the_class
228
+ end
229
+
230
+ protected
231
+
232
+ # Performs initialization the same way as Assisted Inject does (but handle arguments to
233
+ # constructor)
234
+ # @api private
235
+ #
236
+ def internal_produce(scope)
237
+ result = nil
238
+ # A class :inject method wins over an instance :initialize if it is present, unless a more specific
239
+ # constructor exists. (i.e do not pick :inject from superclass if class has a constructor).
240
+ #
241
+ if the_class.respond_to?(:inject)
242
+ inject_method = the_class.method(:inject)
243
+ initialize_method = the_class.instance_method(:initialize)
244
+ if inject_method.owner <= initialize_method.owner
245
+ result = the_class.inject(injector, scope, binding, *init_args)
246
+ end
247
+ end
248
+ if result.nil?
249
+ result = the_class.new(*init_args)
250
+ end
251
+ result
252
+ end
253
+ end
254
+
255
+ # @api public
256
+ class FirstFoundProducer < Producer
257
+ # @api public
258
+ attr_reader :producers
259
+
260
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
261
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
262
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
263
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
264
+ # @option options [Array<Puppet::Pops::Binder::Producers::Producer>] :producers list of producers to consult. Required.
265
+ # @api public
266
+ #
267
+ def initialize(injector, binding, scope, options)
268
+ super
269
+ @producers = options[:producers]
270
+ raise ArgumentError, "Option :producers' must be set to a list of producers." if @producers.nil?
271
+ raise ArgumentError, "Given 'producers' option is not an Array" unless @producers.is_a?(Array)
272
+ end
273
+
274
+ protected
275
+
276
+ # @api private
277
+ def internal_produce(scope)
278
+ # return the first produced value that is non-nil (unfortunately there is no such enumerable method)
279
+ producers.reduce(nil) {|memo, p| break memo unless memo.nil?; p.produce(scope)}
280
+ end
281
+ end
282
+
283
+ # Evaluates a Puppet Expression and returns the result.
284
+ # This is typically used for strings with interpolated expressions.
285
+ # @api public
286
+ #
287
+ class EvaluatingProducer < Producer
288
+ # A Puppet 3 AST Expression
289
+ # @api public
290
+ #
291
+ attr_reader :expression
292
+
293
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
294
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
295
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
296
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
297
+ # @option options [Array<Puppet::Pops::Model::Expression>] :expression The expression to evaluate
298
+ # @api public
299
+ #
300
+ def initialize(injector, binding, scope, options)
301
+ super
302
+ expr = options[:expression]
303
+ raise ArgumentError, "Option 'expression' must be given to an EvaluatingProducer." unless expr
304
+ @expression = Puppet::Pops::Model::AstTransformer.new().transform(expr)
305
+ end
306
+
307
+ # @api private
308
+ def internal_produce(scope)
309
+ expression.evaluate(scope)
310
+ end
311
+ end
312
+
313
+ # @api public
314
+ class LookupProducer < AbstractArgumentedProducer
315
+
316
+ # @api public
317
+ attr_reader :type
318
+
319
+ # @api public
320
+ attr_reader :name
321
+
322
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
323
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
324
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
325
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
326
+ # @option options [Puppet::Pops::Types::PObjectType] :type The type to lookup
327
+ # @option options [String] :name ('') The name to lookup
328
+ # @api public
329
+ #
330
+ def initialize(injector, binder, scope, options)
331
+ super
332
+ @type = options[:type]
333
+ @name = options[:name] || ''
334
+ raise ArgumentError, "Option 'type' must be given in a LookupProducer." unless @type
335
+ end
336
+
337
+ protected
338
+
339
+ # @api private
340
+ def internal_produce(scope)
341
+ injector.lookup_type(scope, type, name)
342
+ end
343
+ end
344
+
345
+ # @api public
346
+ class LookupKeyProducer < LookupProducer
347
+
348
+ # @api public
349
+ attr_reader :key
350
+
351
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
352
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
353
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
354
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
355
+ # @option options [Puppet::Pops::Types::PObjectType] :type The type to lookup
356
+ # @option options [String] :name ('') The name to lookup
357
+ # @option options [Puppet::Pops::Types::PObjectType] :key The key to lookup in the hash
358
+ # @api public
359
+ #
360
+ def initialize(injector, binder, scope, options)
361
+ super
362
+ @key = options[:key]
363
+ raise ArgumentError, "Option 'key' must be given in a LookupKeyProducer." if key.nil?
364
+ end
365
+
366
+ protected
367
+
368
+ # @api private
369
+ def internal_produce(scope)
370
+
371
+ result = super
372
+ result.is_a?(Hash) ? result[key] : nil
373
+ end
374
+ end
375
+
376
+ # Produces the given producer, then uses that producer.
377
+ # @see ProducerProducer for the non singleton version
378
+ # @api public
379
+ #
380
+ class SingletonProducerProducer < Producer
381
+
382
+ # @api public
383
+ attr_reader :value_producer
384
+
385
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
386
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
387
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
388
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
389
+ # @option options [Puppet::Pops::Model::LambdaExpression] :producer_producer a producer of a value producer (required)
390
+ # @api public
391
+ #
392
+ def initialize(injector, binding, scope, options)
393
+ super
394
+ p = options[:producer_producer]
395
+ raise ArgumentError, "Option :producer_producer must be given in a SingletonProducerProducer" unless p
396
+ @value_producer = p.produce(scope)
397
+ end
398
+
399
+ protected
400
+
401
+ # @api private
402
+ def internal_produce(scope)
403
+ value_producer.produce(scope)
404
+ end
405
+ end
406
+
407
+ # A ProducerProducer creates a producer via another producer, and then uses this created producer
408
+ # to produce values. This is useful for custom production of series of values.
409
+ # On each request for a producer, this producer will reset its internal producer (i.e. restarting
410
+ # the series).
411
+ #
412
+ # @param producer_producer [#produce(scope)] the producer of the producer
413
+ #
414
+ # @api public
415
+ #
416
+ class ProducerProducer < Producer
417
+
418
+ # @api public
419
+ attr_reader :producer_producer
420
+
421
+ # @api public
422
+ attr_reader :value_producer
423
+
424
+ # Creates new ProducerProducer given a producer.
425
+ #
426
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
427
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
428
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
429
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
430
+ # @option options [Puppet::Pops::Binder::Producer] :producer_producer a producer of a value producer (required)
431
+ #
432
+ # @api public
433
+ #
434
+ def initialize(injector, binding, scope, options)
435
+ super
436
+ unless producer_producer = options[:producer_producer]
437
+ raise ArgumentError, "The option :producer_producer must be set in a ProducerProducer"
438
+ end
439
+ raise ArgumentError, "Argument must be a Producer" unless producer_producer.is_a?(Producer)
440
+
441
+ @producer_producer = producer_producer
442
+ @value_producer = nil
443
+ end
444
+
445
+ # Updates the internal state to use a new instance of the wrapped producer.
446
+ # @api public
447
+ #
448
+ def producer(scope)
449
+ @value_producer = @producer_producer.produce(scope)
450
+ self
451
+ end
452
+
453
+ protected
454
+
455
+ # Produces a value after having created an instance of the wrapped producer (if not already created).
456
+ # @api private
457
+ #
458
+ def internal_produce(scope, *args)
459
+ producer() unless value_producer
460
+ value_producer.produce(scope)
461
+ end
462
+ end
463
+
464
+ # This type of producer should only be created by the Injector.
465
+ #
466
+ # @api private
467
+ #
468
+ class AssistedInjectProducer < Producer
469
+ # An Assisted Inject Producer is created when a lookup is made of a type that is
470
+ # not bound. It does not support a transformer lambda.
471
+ # @note This initializer has a different signature than all others. Do not use in regular logic.
472
+ # @api private
473
+ #
474
+ def initialize(injector, clazz)
475
+ raise ArgumentError, "class must be given" unless clazz.is_a?(Class)
476
+
477
+ @injector = injector
478
+ @clazz = clazz
479
+ @inst = nil
480
+ end
481
+
482
+ def produce(scope, *args)
483
+ producer(scope, *args) unless @inst
484
+ @inst
485
+ end
486
+
487
+ # @api private
488
+ def producer(scope, *args)
489
+ @inst = nil
490
+ # A class :inject method wins over an instance :initialize if it is present, unless a more specific zero args
491
+ # constructor exists. (i.e do not pick :inject from superclass if class has a zero args constructor).
492
+ #
493
+ if @clazz.respond_to?(:inject)
494
+ inject_method = @clazz.method(:inject)
495
+ initialize_method = @clazz.instance_method(:initialize)
496
+ if inject_method.owner <= initialize_method.owner || initialize_method.arity != 0
497
+ @inst = @clazz.inject(@injector, scope, nil, *args)
498
+ end
499
+ end
500
+ if @inst.nil?
501
+ unless args.empty?
502
+ raise ArgumentError, "Assisted Inject can not pass arguments to no-args constructor when there is no class inject method."
503
+ end
504
+ @inst = @clazz.new()
505
+ end
506
+ self
507
+ end
508
+ end
509
+
510
+ # Abstract base class for multibind producers.
511
+ # Is suitable as base class for custom implementations of multibind producers.
512
+ # @abstract
513
+ # @api public
514
+ #
515
+ class MultibindProducer < AbstractArgumentedProducer
516
+ attr_reader :contributions_key
517
+
518
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
519
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
520
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
521
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
522
+ #
523
+ # @api public
524
+ #
525
+ def initialize(injector, binding, scope, options)
526
+ super
527
+ @contributions_key = injector.key_factory.multibind_contributions(binding.id)
528
+ end
529
+
530
+ # @param expected [Array<Puppet::Pops::Types::PObjectType>, Puppet::Pops::Types::PObjectType] expected type or types
531
+ # @param actual [Object, Puppet::Pops::Types::PObjectType> the actual value (or its type)
532
+ # @return [String] a formatted string for inclusion as detail in an error message
533
+ # @api private
534
+ #
535
+ def type_error_detail(expected, actual)
536
+ tc = injector.type_calculator
537
+ expected = [expected] unless expected.is_a?(Array)
538
+ actual_t = tc.is_ptype?(actual) ? actual : tc.infer(actual)
539
+ expstrs = expected.collect {|t| tc.string(t) }
540
+ "expected: #{expstrs.join(', or ')}, got: #{tc.string(actual_t)}"
541
+ end
542
+ end
543
+
544
+ # A configurable multibind producer for Array type multibindings.
545
+ #
546
+ # This implementation collects all contributions to the multibind and then combines them using the following rules:
547
+ #
548
+ # - all *unnamed* entries are added unless the option `:priority_on_unnamed` is set to true, in which case the unnamed
549
+ # contribution with the highest priority is added, and the rest are ignored (unless they have the same priority in which
550
+ # case an error is raised).
551
+ # - all *named* entries are handled the same way as *unnamed* but the option `:priority_on_named` controls their handling.
552
+ # - the option `:uniq` post processes the result to only contain unique entries
553
+ # - the option `:flatten` post processes the result by flattening all nested arrays.
554
+ # - If both `:flatten` and `:uniq` are true, flattening is done first.
555
+ #
556
+ # @note
557
+ # Collection accepts elements that comply with the array's element type, or the entire type (i.e. Array[element_type]).
558
+ # If the type is restrictive - e.g. Array[String] and an Array[String] is contributed, the result will not be type
559
+ # compliant without also using the `:flatten` option, and a type error will be raised. For an array with relaxed typing
560
+ # i.e. Array[Data], it it valid to produce a result such as `['a', ['b', 'c'], 'd']` and no flattening is required
561
+ # and no error is raised (but using the array needs to be aware of potential array, non-array entries.
562
+ # The use of the option `:flatten` controls how the result is flattened.
563
+ #
564
+ # @api public
565
+ #
566
+ class ArrayMultibindProducer < MultibindProducer
567
+
568
+ # @return [Boolean] whether the result should be made contain unique (non-equal) entries or not
569
+ # @api public
570
+ attr_reader :uniq
571
+
572
+ # @return [Boolean, Integer] If result should be flattened (true), or not (false), or flattened to given level (0 = none, -1 = all)
573
+ # @api public
574
+ attr_reader :flatten
575
+
576
+ # @return [Boolean] whether priority should be considered for named contributions
577
+ # @api public
578
+ attr_reader :priority_on_named
579
+
580
+ # @return [Boolean] whether priority should be considered for unnamed contributions
581
+ # @api public
582
+ attr_reader :priority_on_unnamed
583
+
584
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
585
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
586
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
587
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
588
+ # @option options [Boolean] :uniq (false) if collected result should be post-processed to contain only unique entries
589
+ # @option options [Boolean, Integer] :flatten (false) if collected result should be post-processed so all contained arrays
590
+ # are flattened. May be set to an Integer value to indicate the level of recursion (-1 is endless, 0 is none).
591
+ # @option options [Boolean] :priority_on_named (true) if highest precedented named element should win or if all should be included
592
+ # @option options [Boolean] :priority_on_unnamed (false) if highest precedented unnamed element should win or if all should be included
593
+ # @api public
594
+ #
595
+ def initialize(injector, binding, scope, options)
596
+ super
597
+ @uniq = !!options[:uniq]
598
+ @flatten = options[:flatten]
599
+ @priority_on_named = options[:priority_on_named].nil? ? true : options[:priority_on_name]
600
+ @priority_on_unnamed = !!options[:priority_on_unnamed]
601
+
602
+ case @flatten
603
+ when Integer
604
+ when true
605
+ @flatten = -1
606
+ when false
607
+ @flatten = nil
608
+ when NilClass
609
+ @flatten = nil
610
+ else
611
+ raise ArgumentError, "Option :flatten must be nil, Boolean, or an integer value" unless @flatten.is_a?(Integer)
612
+ end
613
+ end
614
+
615
+ protected
616
+
617
+ # @api private
618
+ def internal_produce(scope)
619
+ seen = {}
620
+ included_keys = []
621
+
622
+ injector.get_contributions(scope, contributions_key).each do |element|
623
+ key = element[0]
624
+ entry = element[1]
625
+
626
+ name = entry.binding.name
627
+ existing = seen[name]
628
+ empty_name = name.nil? || name.empty?
629
+ if existing
630
+ if empty_name && priority_on_unnamed
631
+ if (seen[name] <=> entry) >= 0
632
+ raise ArgumentError, "Duplicate key (same priority) contributed to Array Multibinding '#{binding.name}' with unnamed entry."
633
+ end
634
+ next
635
+ elsif !empty_name && priority_on_named
636
+ if (seen[name] <=> entry) >= 0
637
+ raise ArgumentError, "Duplicate key (same priority) contributed to Array Multibinding '#{binding.name}', key: '#{name}'."
638
+ end
639
+ next
640
+ end
641
+ else
642
+ seen[name] = entry
643
+ end
644
+ included_keys << key
645
+ end
646
+ result = included_keys.collect do |k|
647
+ x = injector.lookup_key(scope, k)
648
+ assert_type(binding(), injector.type_calculator(), x)
649
+ x
650
+ end
651
+
652
+ result.flatten!(flatten) if flatten
653
+ result.uniq! if uniq
654
+ result
655
+ end
656
+
657
+ # @api private
658
+ def assert_type(binding, tc, value)
659
+ infered = tc.infer(value)
660
+ unless tc.assignable?(binding.type.element_type, infered) || tc.assignable?(binding.type, infered)
661
+ raise ArgumentError, ["Type Error: contribution to '#{binding.name}' does not match type of multibind, ",
662
+ "#{type_error_detail([binding.type.element_type, binding.type], value)}"].join()
663
+ end
664
+ end
665
+ end
666
+
667
+ # @api public
668
+ class HashMultibindProducer < MultibindProducer
669
+
670
+ # @return [Symbol] One of `:error`, `:merge`, `:append`, `:priority`, `:ignore`
671
+ # @api public
672
+ attr_reader :conflict_resolution
673
+
674
+ # @return [Boolean]
675
+ # @api public
676
+ attr_reader :uniq
677
+
678
+ # @return [Boolean, Integer] Flatten all if true, or none if false, or to given level (0 = none, -1 = all)
679
+ # @api public
680
+ attr_reader :flatten
681
+
682
+ # The hash multibind producer provides options to control conflict resolution.
683
+ # By default, the hash is produced using `:priority` resolution - the highest entry is selected, the rest are
684
+ # ignored unless they have the same priority which is an error.
685
+ #
686
+ # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
687
+ # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
688
+ # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
689
+ # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
690
+ # @option options [Symbol, String] :conflict_resolution (:priority) One of `:error`, `:merge`, `:append`, `:priority`, `:ignore`
691
+ # <ul><li> `ignore` the first found highest priority contribution is used, the rest are ignored</li>
692
+ # <li>`error` any duplicate key is an error</li>
693
+ # <li>`append` element type must be compatible with Array, makes elements be arrays and appends all found</li>
694
+ # <li>`merge` element type must be compatible with hash, merges hashes with retention of highest priority hash content</li>
695
+ # <li>`priority` the first found highest priority contribution is used, duplicates with same priority raises and error, the rest are
696
+ # ignored.</li></ul>
697
+ # @option options [Boolean, Integer] :flatten (false) If appended should be flattened. Also see {#flatten}.
698
+ # @option options [Boolean] :uniq (false) If appended result should be made unique.
699
+ #
700
+ # @api public
701
+ #
702
+ def initialize(injector, binding, scope, options)
703
+ super
704
+ @conflict_resolution = options[:conflict_resolution].nil? ? :priority : options[:conflict_resolution]
705
+ @uniq = !!options[:uniq]
706
+ @flatten = options[:flatten]
707
+
708
+ unless [:error, :merge, :append, :priority, :ignore].include?(@conflict_resolution)
709
+ raise ArgumentError, "Unknown conflict_resolution for Multibind Hash: '#{@conflict_resolution}."
710
+ end
711
+
712
+ case @flatten
713
+ when Integer
714
+ when true
715
+ @flatten = -1
716
+ when false
717
+ @flatten = nil
718
+ when NilClass
719
+ @flatten = nil
720
+ else
721
+ raise ArgumentError, "Option :flatten must be nil, Boolean, or an integer value" unless @flatten.is_a?(Integer)
722
+ end
723
+
724
+ if uniq || flatten || conflict_resolution.to_s == 'append'
725
+ etype = binding.type.element_type
726
+ unless etype.class == Puppet::Pops::Types::PDataType || etype.is_a?(Puppet::Pops::Types::PArrayType)
727
+ detail = []
728
+ detail << ":uniq" if uniq
729
+ detail << ":flatten" if flatten
730
+ detail << ":conflict_resolution => :append" if conflict_resolution.to_s == 'append'
731
+ raise ArgumentError, ["Options #{detail.join(', and ')} cannot be used with a Multibind ",
732
+ "of type #{injector.type_calculator.string(binding.type)}"].join()
733
+ end
734
+ end
735
+ end
736
+
737
+ protected
738
+
739
+ # @api private
740
+ def internal_produce(scope)
741
+ seen = {}
742
+ included_entries = []
743
+
744
+ injector.get_contributions(scope, contributions_key).each do |element|
745
+ key = element[0]
746
+ entry = element[1]
747
+
748
+ name = entry.binding.name
749
+ raise ArgumentError, "A Hash Multibind contribution to '#{binding.name}' must have a name." if name.nil? || name.empty?
750
+
751
+ existing = seen[name]
752
+ if existing
753
+ case conflict_resolution.to_s
754
+ when 'priority'
755
+ # skip if duplicate has lower prio
756
+ if (comparison = (seen[name] <=> entry)) <= 0
757
+ raise ArgumentError, "Internal Error: contributions not given in decreasing precedence order" unless comparison == 0
758
+ raise ArgumentError, "Duplicate key (same priority) contributed to Hash Multibinding '#{binding.name}', key: '#{name}'."
759
+ end
760
+ next
761
+
762
+ when 'ignore'
763
+ # skip, ignore conflict if prio is the same
764
+ next
765
+
766
+ when 'error'
767
+ raise ArgumentError, "Duplicate key contributed to Hash Multibinding '#{binding.name}', key: '#{name}'."
768
+
769
+ end
770
+ else
771
+ seen[name] = entry
772
+ end
773
+ included_entries << [key, entry]
774
+ end
775
+ result = {}
776
+ included_entries.each do |element|
777
+ k = element[ 0 ]
778
+ entry = element[ 1 ]
779
+ x = injector.lookup_key(scope, k)
780
+ name = entry.binding.name
781
+ assert_type(binding(), injector.type_calculator(), name, x)
782
+ if result[ name ]
783
+ merge(result, name, result[ name ], x)
784
+ else
785
+ result[ name ] = conflict_resolution().to_s == 'append' ? [x] : x
786
+ end
787
+ end
788
+ result
789
+ end
790
+
791
+ # @api private
792
+ def merge(result, name, higher, lower)
793
+ case conflict_resolution.to_s
794
+ when 'append'
795
+ unless higher.is_a?(Array)
796
+ higher = [higher]
797
+ end
798
+ tmp = higher + [lower]
799
+ tmp.flatten!(flatten) if flatten
800
+ tmp.uniq! if uniq
801
+ result[name] = tmp
802
+
803
+ when 'merge'
804
+ result[name] = lower.merge(higher)
805
+
806
+ end
807
+ end
808
+
809
+ # @api private
810
+ def assert_type(binding, tc, key, value)
811
+ unless tc.instance?(binding.type.key_type, key)
812
+ raise ArgumentError, ["Type Error: key contribution to #{binding.name}['#{key}'] ",
813
+ "is incompatible with key type: #{tc.label(binding.type)}, ",
814
+ type_error_detail(binding.type.key_type, key)].join()
815
+ end
816
+
817
+ if key.nil? || !key.is_a?(String) || key.empty?
818
+ raise ArgumentError, "Entry contributing to multibind hash with id '#{binding.id}' must have a name."
819
+ end
820
+
821
+ unless tc.instance?(binding.type.element_type, value)
822
+ raise ArgumentError, ["Type Error: value contribution to #{binding.name}['#{key}'] ",
823
+ "is incompatible, ",
824
+ type_error_detail(binding.type.element_type, value)].join()
825
+ end
826
+ end
827
+ end
828
+
829
+ end