puppet 3.1.1 → 3.2.0.rc1

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 (477) hide show
  1. data/CONTRIBUTING.md +2 -2
  2. data/Gemfile +32 -19
  3. data/README_DEVELOPER.md +332 -14
  4. data/Rakefile +9 -5
  5. data/ext/build_defaults.yaml +2 -3
  6. data/ext/debian/changelog.erb +6 -0
  7. data/ext/debian/control +6 -6
  8. data/ext/envpuppet +4 -4
  9. data/ext/project_data.yaml +1 -0
  10. data/ext/puppet-nm-dispatcher +13 -0
  11. data/ext/redhat/puppet.spec.erb +17 -0
  12. data/ext/suse/client.init +1 -1
  13. data/ext/systemd/puppetagent.service +2 -2
  14. data/ext/systemd/puppetmaster.service +2 -2
  15. data/lib/hiera/scope.rb +29 -11
  16. data/lib/hiera_puppet.rb +1 -3
  17. data/lib/puppet/agent.rb +3 -3
  18. data/lib/puppet/application.rb +2 -2
  19. data/lib/puppet/application/agent.rb +27 -12
  20. data/lib/puppet/application/apply.rb +11 -1
  21. data/lib/puppet/application/describe.rb +1 -1
  22. data/lib/puppet/application/doc.rb +13 -9
  23. data/lib/puppet/application/filebucket.rb +0 -1
  24. data/lib/puppet/application/kick.rb +1 -0
  25. data/lib/puppet/application/master.rb +16 -8
  26. data/lib/puppet/daemon.rb +19 -64
  27. data/lib/puppet/defaults.rb +61 -5
  28. data/lib/puppet/error.rb +15 -4
  29. data/lib/puppet/external/nagios/grammar.ry +1 -1
  30. data/lib/puppet/external/nagios/makefile +1 -1
  31. data/lib/puppet/external/nagios/parser.rb +185 -618
  32. data/lib/puppet/external/pson/pure/parser.rb +47 -1
  33. data/lib/puppet/face/certificate.rb +3 -3
  34. data/lib/puppet/face/module.rb +1 -1
  35. data/lib/puppet/face/module/changes.rb +3 -1
  36. data/lib/puppet/face/module/uninstall.rb +1 -1
  37. data/lib/puppet/face/node/clean.rb +5 -5
  38. data/lib/puppet/feature/base.rb +3 -1
  39. data/lib/puppet/feature/libuser.rb +8 -0
  40. data/lib/puppet/file_serving/fileset.rb +9 -1
  41. data/lib/puppet/forge.rb +28 -5
  42. data/lib/puppet/forge/errors.rb +34 -0
  43. data/lib/puppet/forge/repository.rb +1 -1
  44. data/lib/puppet/indirector.rb +4 -1
  45. data/lib/puppet/indirector/catalog/compiler.rb +37 -30
  46. data/lib/puppet/indirector/facts/inventory_active_record.rb +1 -0
  47. data/lib/puppet/indirector/indirection.rb +28 -15
  48. data/lib/puppet/indirector/rest.rb +18 -10
  49. data/lib/puppet/interface.rb +11 -4
  50. data/lib/puppet/interface/action.rb +1 -3
  51. data/lib/puppet/interface/action_builder.rb +0 -3
  52. data/lib/puppet/interface/action_manager.rb +0 -3
  53. data/lib/puppet/interface/face_collection.rb +0 -2
  54. data/lib/puppet/interface/option.rb +0 -2
  55. data/lib/puppet/interface/option_builder.rb +0 -2
  56. data/lib/puppet/interface/option_manager.rb +0 -2
  57. data/lib/puppet/metatype/manager.rb +1 -1
  58. data/lib/puppet/module_tool.rb +1 -0
  59. data/lib/puppet/module_tool/applications/application.rb +0 -3
  60. data/lib/puppet/module_tool/applications/builder.rb +8 -20
  61. data/lib/puppet/module_tool/applications/checksummer.rb +1 -1
  62. data/lib/puppet/module_tool/applications/installer.rb +1 -0
  63. data/lib/puppet/module_tool/applications/unpacker.rb +3 -11
  64. data/lib/puppet/module_tool/checksums.rb +1 -1
  65. data/lib/puppet/module_tool/errors/installer.rb +18 -1
  66. data/lib/puppet/module_tool/modulefile.rb +2 -2
  67. data/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb +1 -1
  68. data/lib/puppet/module_tool/tar.rb +17 -0
  69. data/lib/puppet/module_tool/tar/gnu.rb +9 -0
  70. data/lib/puppet/module_tool/tar/mini.rb +39 -0
  71. data/lib/puppet/module_tool/tar/solaris.rb +5 -0
  72. data/lib/puppet/network/http.rb +1 -0
  73. data/lib/puppet/network/http/connection.rb +9 -23
  74. data/lib/puppet/network/http/handler.rb +38 -7
  75. data/lib/puppet/network/http/rack/rest.rb +14 -3
  76. data/lib/puppet/network/http/webrick.rb +3 -1
  77. data/lib/puppet/network/http/webrick/rest.rb +11 -2
  78. data/lib/puppet/node/environment.rb +3 -1
  79. data/lib/puppet/parameter.rb +32 -29
  80. data/lib/puppet/parameter/package_options.rb +1 -1
  81. data/lib/puppet/parameter/path.rb +1 -1
  82. data/lib/puppet/parameter/value.rb +1 -1
  83. data/lib/puppet/parameter/value_collection.rb +7 -3
  84. data/lib/puppet/parser/ast.rb +3 -1
  85. data/lib/puppet/parser/ast/arithmetic_operator.rb +56 -12
  86. data/lib/puppet/parser/ast/astarray.rb +1 -1
  87. data/lib/puppet/parser/ast/block_expression.rb +41 -0
  88. data/lib/puppet/parser/ast/function.rb +13 -2
  89. data/lib/puppet/parser/ast/lambda.rb +107 -0
  90. data/lib/puppet/parser/ast/leaf.rb +1 -2
  91. data/lib/puppet/parser/ast/method_call.rb +77 -0
  92. data/lib/puppet/parser/ast/vardef.rb +7 -0
  93. data/lib/puppet/parser/compiler.rb +27 -16
  94. data/lib/puppet/parser/e_parser_adapter.rb +120 -0
  95. data/lib/puppet/parser/files.rb +7 -6
  96. data/lib/puppet/parser/functions.rb +10 -8
  97. data/lib/puppet/parser/functions/collect.rb +43 -0
  98. data/lib/puppet/parser/functions/each.rb +96 -0
  99. data/lib/puppet/parser/functions/foreach.rb +96 -0
  100. data/lib/puppet/parser/functions/fqdn_rand.rb +2 -2
  101. data/lib/puppet/parser/functions/hiera.rb +20 -2
  102. data/lib/puppet/parser/functions/hiera_array.rb +21 -2
  103. data/lib/puppet/parser/functions/hiera_hash.rb +23 -2
  104. data/lib/puppet/parser/functions/hiera_include.rb +33 -2
  105. data/lib/puppet/parser/functions/inline_template.rb +4 -4
  106. data/lib/puppet/parser/functions/reduce.rb +74 -0
  107. data/lib/puppet/parser/functions/reject.rb +46 -0
  108. data/lib/puppet/parser/functions/select.rb +46 -0
  109. data/lib/puppet/parser/functions/slice.rb +96 -0
  110. data/lib/puppet/parser/functions/template.rb +2 -2
  111. data/lib/puppet/parser/grammar.ra +7 -4
  112. data/lib/puppet/parser/lexer.rb +10 -0
  113. data/lib/puppet/parser/methods.rb +69 -0
  114. data/lib/puppet/parser/parser.rb +855 -808
  115. data/lib/puppet/parser/parser_factory.rb +62 -0
  116. data/lib/puppet/parser/parser_support.rb +8 -2
  117. data/lib/puppet/parser/scope.rb +153 -47
  118. data/lib/puppet/parser/templatewrapper.rb +28 -21
  119. data/lib/puppet/parser/type_loader.rb +3 -1
  120. data/lib/puppet/pops.rb +40 -0
  121. data/lib/puppet/pops/adaptable.rb +190 -0
  122. data/lib/puppet/pops/adapters.rb +65 -0
  123. data/lib/puppet/pops/containment.rb +37 -0
  124. data/lib/puppet/pops/issues.rb +258 -0
  125. data/lib/puppet/pops/label_provider.rb +71 -0
  126. data/lib/puppet/pops/model/ast_transformer.rb +636 -0
  127. data/lib/puppet/pops/model/ast_tree_dumper.rb +378 -0
  128. data/lib/puppet/pops/model/factory.rb +804 -0
  129. data/lib/puppet/pops/model/model.rb +567 -0
  130. data/lib/puppet/pops/model/model_label_provider.rb +75 -0
  131. data/lib/puppet/pops/model/model_tree_dumper.rb +352 -0
  132. data/lib/puppet/pops/model/tree_dumper.rb +59 -0
  133. data/lib/puppet/pops/parser/egrammar.ra +723 -0
  134. data/lib/puppet/pops/parser/eparser.rb +2300 -0
  135. data/lib/puppet/pops/parser/grammar.ra +746 -0
  136. data/lib/puppet/pops/parser/lexer.rb +842 -0
  137. data/lib/puppet/pops/parser/makefile +13 -0
  138. data/lib/puppet/pops/parser/parser_support.rb +203 -0
  139. data/lib/puppet/pops/patterns.rb +35 -0
  140. data/lib/puppet/pops/utils.rb +104 -0
  141. data/lib/puppet/pops/validation.rb +297 -0
  142. data/lib/puppet/pops/validation/checker3_1.rb +551 -0
  143. data/lib/puppet/pops/validation/validator_factory_3_1.rb +41 -0
  144. data/lib/puppet/pops/visitable.rb +6 -0
  145. data/lib/puppet/pops/visitor.rb +50 -0
  146. data/lib/puppet/property.rb +37 -28
  147. data/lib/puppet/property/ensure.rb +2 -2
  148. data/lib/puppet/property/ordered_list.rb +1 -1
  149. data/lib/puppet/provider.rb +26 -30
  150. data/lib/puppet/provider/aixobject.rb +45 -44
  151. data/lib/puppet/provider/augeas/augeas.rb +0 -1
  152. data/lib/puppet/provider/confiner.rb +1 -1
  153. data/lib/puppet/provider/cron/crontab.rb +107 -67
  154. data/lib/puppet/provider/group/groupadd.rb +59 -3
  155. data/lib/puppet/provider/interface/cisco.rb +4 -4
  156. data/lib/puppet/provider/mount/parsed.rb +1 -1
  157. data/lib/puppet/provider/nameservice.rb +22 -6
  158. data/lib/puppet/provider/nameservice/pw.rb +1 -1
  159. data/lib/puppet/provider/package/aix.rb +28 -4
  160. data/lib/puppet/provider/package/gem.rb +0 -2
  161. data/lib/puppet/provider/package/macports.rb +1 -1
  162. data/lib/puppet/provider/package/nim.rb +249 -4
  163. data/lib/puppet/provider/package/opkg.rb +77 -0
  164. data/lib/puppet/provider/package/pacman.rb +2 -2
  165. data/lib/puppet/provider/package/rpm.rb +30 -16
  166. data/lib/puppet/provider/package/yum.rb +3 -3
  167. data/lib/puppet/provider/parsedfile.rb +80 -3
  168. data/lib/puppet/provider/selmodule/semodule.rb +2 -2
  169. data/lib/puppet/provider/service/debian.rb +0 -4
  170. data/lib/puppet/provider/service/freebsd.rb +2 -2
  171. data/lib/puppet/provider/service/gentoo.rb +0 -9
  172. data/lib/puppet/provider/service/init.rb +27 -2
  173. data/lib/puppet/provider/service/launchd.rb +1 -1
  174. data/lib/puppet/provider/service/openwrt.rb +36 -0
  175. data/lib/puppet/provider/service/redhat.rb +0 -9
  176. data/lib/puppet/provider/service/src.rb +38 -4
  177. data/lib/puppet/provider/service/systemd.rb +2 -2
  178. data/lib/puppet/provider/service/upstart.rb +1 -8
  179. data/lib/puppet/provider/user/aix.rb +4 -10
  180. data/lib/puppet/provider/user/pw.rb +6 -10
  181. data/lib/puppet/provider/user/useradd.rb +129 -31
  182. data/lib/puppet/provider/vlan/cisco.rb +4 -4
  183. data/lib/puppet/reference/function.rb +2 -2
  184. data/lib/puppet/reference/indirection.rb +46 -5
  185. data/lib/puppet/reference/metaparameter.rb +2 -2
  186. data/lib/puppet/reports.rb +5 -5
  187. data/lib/puppet/reports/rrdgraph.rb +4 -4
  188. data/lib/puppet/reports/tagmail.rb +1 -1
  189. data/lib/puppet/resource.rb +1 -1
  190. data/lib/puppet/resource/type.rb +13 -11
  191. data/lib/puppet/scheduler.rb +16 -0
  192. data/lib/puppet/scheduler/job.rb +53 -0
  193. data/lib/puppet/scheduler/scheduler.rb +45 -0
  194. data/lib/puppet/scheduler/splay_job.rb +32 -0
  195. data/lib/puppet/scheduler/timer.rb +13 -0
  196. data/lib/puppet/settings/base_setting.rb +1 -1
  197. data/lib/puppet/simple_graph.rb +4 -4
  198. data/lib/puppet/ssl/base.rb +12 -2
  199. data/lib/puppet/ssl/certificate.rb +4 -1
  200. data/lib/puppet/ssl/certificate_request.rb +4 -1
  201. data/lib/puppet/ssl/certificate_revocation_list.rb +4 -1
  202. data/lib/puppet/ssl/configuration.rb +32 -0
  203. data/lib/puppet/ssl/host.rb +18 -21
  204. data/lib/puppet/ssl/key.rb +4 -1
  205. data/lib/puppet/ssl/validator.rb +116 -0
  206. data/lib/puppet/transaction.rb +1 -1
  207. data/lib/puppet/transaction/event.rb +3 -10
  208. data/lib/puppet/transaction/event_manager.rb +8 -1
  209. data/lib/puppet/transaction/report.rb +17 -16
  210. data/lib/puppet/type.rb +77 -69
  211. data/lib/puppet/type/cron.rb +20 -8
  212. data/lib/puppet/type/exec.rb +9 -3
  213. data/lib/puppet/type/file.rb +95 -21
  214. data/lib/puppet/type/file/content.rb +1 -1
  215. data/lib/puppet/type/file/mode.rb +7 -1
  216. data/lib/puppet/type/file/source.rb +2 -2
  217. data/lib/puppet/type/group.rb +11 -0
  218. data/lib/puppet/type/scheduled_task.rb +5 -1
  219. data/lib/puppet/type/service.rb +1 -1
  220. data/lib/puppet/type/ssh_authorized_key.rb +2 -2
  221. data/lib/puppet/type/user.rb +24 -6
  222. data/lib/puppet/util.rb +12 -2
  223. data/lib/puppet/util/classgen.rb +4 -4
  224. data/lib/puppet/util/colors.rb +55 -0
  225. data/lib/puppet/util/command_line/trollop.rb +4 -4
  226. data/lib/puppet/util/errors.rb +39 -3
  227. data/lib/puppet/util/fileparsing.rb +5 -0
  228. data/lib/puppet/util/filetype.rb +11 -9
  229. data/lib/puppet/util/instrumentation/instrumentable.rb +2 -2
  230. data/lib/puppet/util/libuser.conf +15 -0
  231. data/lib/puppet/util/libuser.rb +12 -0
  232. data/lib/puppet/util/monkey_patches.rb +48 -0
  233. data/lib/puppet/util/network_device.rb +1 -1
  234. data/lib/puppet/util/network_device/base.rb +2 -2
  235. data/lib/puppet/util/network_device/cisco/device.rb +29 -19
  236. data/lib/puppet/util/network_device/config.rb +5 -2
  237. data/lib/puppet/util/network_device/ipcalc.rb +1 -1
  238. data/lib/puppet/util/network_device/transport/ssh.rb +4 -3
  239. data/lib/puppet/util/network_device/transport/telnet.rb +4 -2
  240. data/lib/puppet/util/plugins.rb +4 -4
  241. data/lib/puppet/util/posix.rb +1 -1
  242. data/lib/puppet/util/profiler.rb +28 -0
  243. data/lib/puppet/util/profiler/logging.rb +47 -0
  244. data/lib/puppet/util/profiler/none.rb +8 -0
  245. data/lib/puppet/util/profiler/object_counts.rb +17 -0
  246. data/lib/puppet/util/profiler/wall_clock.rb +34 -0
  247. data/lib/puppet/util/provider_features.rb +1 -1
  248. data/lib/puppet/util/rdoc/parser.rb +5 -5
  249. data/lib/puppet/util/ssl.rb +38 -0
  250. data/lib/puppet/util/subclass_loader.rb +1 -5
  251. data/lib/puppet/util/windows.rb +1 -0
  252. data/lib/puppet/util/windows/process.rb +3 -0
  253. data/lib/puppet/util/windows/root_certs.rb +86 -0
  254. data/lib/puppet/util/windows/security.rb +1 -0
  255. data/lib/puppet/version.rb +1 -1
  256. data/spec/fixtures/integration/provider/cron/crontab/create_normal_entry +19 -0
  257. data/spec/fixtures/integration/provider/cron/crontab/create_special_entry +18 -0
  258. data/spec/fixtures/integration/provider/cron/crontab/crontab_user1 +15 -0
  259. data/spec/fixtures/integration/provider/cron/crontab/crontab_user2 +4 -0
  260. data/spec/fixtures/integration/provider/cron/crontab/modify_entry +13 -0
  261. data/spec/fixtures/integration/provider/cron/crontab/moved_cronjob_input1 +15 -0
  262. data/spec/fixtures/integration/provider/cron/crontab/moved_cronjob_input2 +6 -0
  263. data/spec/fixtures/integration/provider/cron/crontab/remove_named_resource +12 -0
  264. data/spec/fixtures/integration/provider/cron/crontab/remove_unnamed_resource +14 -0
  265. data/spec/fixtures/unit/pops/parser/lexer/aliastest.pp +16 -0
  266. data/spec/fixtures/unit/pops/parser/lexer/append.pp +11 -0
  267. data/spec/fixtures/unit/pops/parser/lexer/argumentdefaults.pp +14 -0
  268. data/spec/fixtures/unit/pops/parser/lexer/arithmetic_expression.pp +8 -0
  269. data/spec/fixtures/unit/pops/parser/lexer/arraytrailingcomma.pp +3 -0
  270. data/spec/fixtures/unit/pops/parser/lexer/casestatement.pp +65 -0
  271. data/spec/fixtures/unit/pops/parser/lexer/classheirarchy.pp +15 -0
  272. data/spec/fixtures/unit/pops/parser/lexer/classincludes.pp +17 -0
  273. data/spec/fixtures/unit/pops/parser/lexer/classpathtest.pp +11 -0
  274. data/spec/fixtures/unit/pops/parser/lexer/collection.pp +10 -0
  275. data/spec/fixtures/unit/pops/parser/lexer/collection_override.pp +8 -0
  276. data/spec/fixtures/unit/pops/parser/lexer/collection_within_virtual_definitions.pp +20 -0
  277. data/spec/fixtures/unit/pops/parser/lexer/componentmetaparams.pp +11 -0
  278. data/spec/fixtures/unit/pops/parser/lexer/componentrequire.pp +8 -0
  279. data/spec/fixtures/unit/pops/parser/lexer/deepclassheirarchy.pp +23 -0
  280. data/spec/fixtures/unit/pops/parser/lexer/defineoverrides.pp +17 -0
  281. data/spec/fixtures/unit/pops/parser/lexer/emptyclass.pp +9 -0
  282. data/spec/fixtures/unit/pops/parser/lexer/emptyexec.pp +3 -0
  283. data/spec/fixtures/unit/pops/parser/lexer/emptyifelse.pp +9 -0
  284. data/spec/fixtures/unit/pops/parser/lexer/falsevalues.pp +3 -0
  285. data/spec/fixtures/unit/pops/parser/lexer/filecreate.pp +11 -0
  286. data/spec/fixtures/unit/pops/parser/lexer/fqdefinition.pp +5 -0
  287. data/spec/fixtures/unit/pops/parser/lexer/fqparents.pp +11 -0
  288. data/spec/fixtures/unit/pops/parser/lexer/funccomma.pp +5 -0
  289. data/spec/fixtures/unit/pops/parser/lexer/hash.pp +33 -0
  290. data/spec/fixtures/unit/pops/parser/lexer/ifexpression.pp +12 -0
  291. data/spec/fixtures/unit/pops/parser/lexer/implicititeration.pp +15 -0
  292. data/spec/fixtures/unit/pops/parser/lexer/multilinecomments.pp +10 -0
  293. data/spec/fixtures/unit/pops/parser/lexer/multipleclass.pp +9 -0
  294. data/spec/fixtures/unit/pops/parser/lexer/multipleinstances.pp +7 -0
  295. data/spec/fixtures/unit/pops/parser/lexer/multisubs.pp +13 -0
  296. data/spec/fixtures/unit/pops/parser/lexer/namevartest.pp +9 -0
  297. data/spec/fixtures/unit/pops/parser/lexer/scopetest.pp +13 -0
  298. data/spec/fixtures/unit/pops/parser/lexer/selectorvalues.pp +49 -0
  299. data/spec/fixtures/unit/pops/parser/lexer/simpledefaults.pp +5 -0
  300. data/spec/fixtures/unit/pops/parser/lexer/simpleselector.pp +38 -0
  301. data/spec/fixtures/unit/pops/parser/lexer/singleary.pp +19 -0
  302. data/spec/fixtures/unit/pops/parser/lexer/singlequote.pp +11 -0
  303. data/spec/fixtures/unit/pops/parser/lexer/singleselector.pp +22 -0
  304. data/spec/fixtures/unit/pops/parser/lexer/subclass_name_duplication.pp +11 -0
  305. data/spec/fixtures/unit/pops/parser/lexer/tag.pp +9 -0
  306. data/spec/fixtures/unit/pops/parser/lexer/tagged.pp +35 -0
  307. data/spec/fixtures/unit/pops/parser/lexer/virtualresources.pp +14 -0
  308. data/spec/fixtures/unit/provider/cron/crontab/single_line.yaml +4 -4
  309. data/spec/fixtures/unit/provider/cron/crontab/vixie_header.txt +3 -0
  310. data/spec/fixtures/unit/provider/cron/parsed/managed +6 -0
  311. data/spec/fixtures/unit/provider/cron/parsed/simple +9 -0
  312. data/spec/fixtures/unit/provider/parsedfile/simple.txt +4 -0
  313. data/spec/fixtures/unit/provider/service/systemd/list_units +18 -0
  314. data/spec/integration/parser/collector_spec.rb +1 -1
  315. data/spec/integration/parser/compiler_spec.rb +252 -227
  316. data/spec/integration/parser/parser_spec.rb +171 -53
  317. data/spec/integration/parser/scope_spec.rb +1 -1
  318. data/spec/integration/provider/cron/crontab_spec.rb +187 -0
  319. data/spec/integration/provider/service/systemd_spec.rb +20 -0
  320. data/spec/integration/type/file_spec.rb +21 -21
  321. data/spec/integration/type/package_spec.rb +1 -1
  322. data/spec/lib/puppet_spec/database.rb +2 -5
  323. data/spec/spec_helper.rb +6 -1
  324. data/spec/unit/application/apply_spec.rb +16 -1
  325. data/spec/unit/application/describe_spec.rb +1 -1
  326. data/spec/unit/application/doc_spec.rb +55 -32
  327. data/spec/unit/application/kick_spec.rb +8 -6
  328. data/spec/unit/application/master_spec.rb +4 -4
  329. data/spec/unit/daemon_spec.rb +1 -1
  330. data/spec/unit/forge/errors_spec.rb +40 -0
  331. data/spec/unit/forge/repository_spec.rb +11 -1
  332. data/spec/unit/forge_spec.rb +13 -3
  333. data/spec/unit/hiera/backend/puppet_backend_spec.rb +1 -0
  334. data/spec/unit/hiera/scope_spec.rb +48 -25
  335. data/spec/unit/indirector/catalog/active_record_spec.rb +6 -3
  336. data/spec/unit/indirector/catalog/compiler_spec.rb +3 -28
  337. data/spec/unit/indirector/catalog/static_compiler_spec.rb +1 -1
  338. data/spec/unit/indirector/facts/inventory_active_record_spec.rb +154 -150
  339. data/spec/unit/indirector/indirection_spec.rb +5 -0
  340. data/spec/unit/indirector/resource/active_record_spec.rb +5 -22
  341. data/spec/unit/indirector_spec.rb +7 -1
  342. data/spec/unit/interface/action_builder_spec.rb +1 -1
  343. data/spec/unit/interface/action_manager_spec.rb +0 -2
  344. data/spec/unit/interface/action_spec.rb +1 -1
  345. data/spec/unit/interface/documentation_spec.rb +0 -2
  346. data/spec/unit/interface/face_collection_spec.rb +1 -1
  347. data/spec/unit/interface/option_builder_spec.rb +1 -1
  348. data/spec/unit/interface/option_spec.rb +0 -1
  349. data/spec/unit/module_spec.rb +17 -19
  350. data/spec/unit/module_tool/application_spec.rb +1 -3
  351. data/spec/unit/module_tool/applications/builder_spec.rb +38 -0
  352. data/spec/unit/module_tool/applications/checksummer_spec.rb +134 -0
  353. data/spec/unit/module_tool/applications/installer_spec.rb +71 -91
  354. data/spec/unit/module_tool/applications/searcher_spec.rb +1 -3
  355. data/spec/unit/module_tool/applications/uninstaller_spec.rb +18 -26
  356. data/spec/unit/module_tool/applications/unpacker_spec.rb +19 -52
  357. data/spec/unit/module_tool/tar/gnu_spec.rb +19 -0
  358. data/spec/unit/module_tool/tar/mini_spec.rb +59 -0
  359. data/spec/unit/module_tool/tar/solaris_spec.rb +19 -0
  360. data/spec/unit/network/http/connection_spec.rb +17 -2
  361. data/spec/unit/network/http/handler_spec.rb +195 -167
  362. data/spec/unit/network/http/rack/rest_spec.rb +26 -4
  363. data/spec/unit/network/http/webrick/rest_spec.rb +28 -1
  364. data/spec/unit/network/http/webrick_spec.rb +12 -3
  365. data/spec/unit/node/environment_spec.rb +421 -404
  366. data/spec/unit/parser/ast/arithmetic_operator_spec.rb +98 -2
  367. data/spec/unit/parser/collector_spec.rb +4 -4
  368. data/spec/unit/parser/compiler_spec.rb +13 -13
  369. data/spec/unit/parser/eparser_adapter_spec.rb +407 -0
  370. data/spec/unit/parser/functions/extlookup_spec.rb +20 -17
  371. data/spec/unit/parser/functions/fqdn_rand_spec.rb +5 -0
  372. data/spec/unit/parser/functions/hiera_include_spec.rb +0 -2
  373. data/spec/unit/parser/functions/hiera_spec.rb +0 -2
  374. data/spec/unit/parser/functions_spec.rb +27 -15
  375. data/spec/unit/parser/methods/collect_spec.rb +110 -0
  376. data/spec/unit/parser/methods/each_spec.rb +91 -0
  377. data/spec/unit/parser/methods/foreach_spec.rb +91 -0
  378. data/spec/unit/parser/methods/reduce_spec.rb +67 -0
  379. data/spec/unit/parser/methods/reject_spec.rb +73 -0
  380. data/spec/unit/parser/methods/select_spec.rb +79 -0
  381. data/spec/unit/parser/methods/shared.rb +61 -0
  382. data/spec/unit/parser/methods/slice_spec.rb +97 -0
  383. data/spec/unit/parser/parser_spec.rb +2 -2
  384. data/spec/unit/parser/scope_spec.rb +39 -16
  385. data/spec/unit/parser/templatewrapper_spec.rb +6 -5
  386. data/spec/unit/parser/type_loader_spec.rb +191 -165
  387. data/spec/unit/pops/adaptable_spec.rb +143 -0
  388. data/spec/unit/pops/containment_spec.rb +25 -0
  389. data/spec/unit/pops/factory_rspec_helper.rb +77 -0
  390. data/spec/unit/pops/factory_spec.rb +329 -0
  391. data/spec/unit/pops/issues_spec.rb +26 -0
  392. data/spec/unit/pops/label_provider_spec.rb +42 -0
  393. data/spec/unit/pops/model/ast_transformer_spec.rb +65 -0
  394. data/spec/unit/pops/model/model_spec.rb +37 -0
  395. data/spec/unit/pops/parser/lexer_spec.rb +884 -0
  396. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +248 -0
  397. data/spec/unit/pops/parser/parse_calls_spec.rb +93 -0
  398. data/spec/unit/pops/parser/parse_conditionals_spec.rb +159 -0
  399. data/spec/unit/pops/parser/parse_containers_spec.rb +175 -0
  400. data/spec/unit/pops/parser/parse_resource_spec.rb +228 -0
  401. data/spec/unit/pops/parser/parser_rspec_helper.rb +11 -0
  402. data/spec/unit/pops/parser/parser_spec.rb +15 -0
  403. data/spec/unit/pops/parser/rgen_sanitycheck_spec.rb +16 -0
  404. data/spec/unit/pops/transformer/transform_basic_expressions_spec.rb +243 -0
  405. data/spec/unit/pops/transformer/transform_calls_spec.rb +80 -0
  406. data/spec/unit/pops/transformer/transform_conditionals_spec.rb +132 -0
  407. data/spec/unit/pops/transformer/transform_containers_spec.rb +182 -0
  408. data/spec/unit/pops/transformer/transform_resource_spec.rb +185 -0
  409. data/spec/unit/pops/transformer/transformer_rspec_helper.rb +27 -0
  410. data/spec/unit/pops/visitor_spec.rb +94 -0
  411. data/spec/unit/property_spec.rb +11 -0
  412. data/spec/unit/provider/augeas/augeas_spec.rb +3 -0
  413. data/spec/unit/provider/cron/crontab_spec.rb +97 -7
  414. data/spec/unit/provider/cron/parsed_spec.rb +325 -0
  415. data/spec/unit/provider/exec/posix_spec.rb +1 -1
  416. data/spec/unit/provider/group/groupadd_spec.rb +33 -3
  417. data/spec/unit/provider/group/pw_spec.rb +5 -5
  418. data/spec/unit/provider/nameservice_spec.rb +304 -0
  419. data/spec/unit/provider/package/aix_spec.rb +53 -11
  420. data/spec/unit/provider/package/aptrpm_spec.rb +6 -0
  421. data/spec/unit/provider/package/gem_spec.rb +6 -11
  422. data/spec/unit/provider/package/nim_spec.rb +216 -7
  423. data/spec/unit/provider/package/opkg_spec.rb +180 -0
  424. data/spec/unit/provider/package/rpm_spec.rb +149 -3
  425. data/spec/unit/provider/package/yum_spec.rb +6 -5
  426. data/spec/unit/provider/parsedfile_spec.rb +122 -28
  427. data/spec/unit/provider/service/freebsd_spec.rb +18 -0
  428. data/spec/unit/provider/service/init_spec.rb +108 -87
  429. data/spec/unit/provider/service/launchd_spec.rb +2 -2
  430. data/spec/unit/provider/service/openwrt_spec.rb +109 -0
  431. data/spec/unit/provider/service/src_spec.rb +117 -41
  432. data/spec/unit/provider/service/systemd_spec.rb +125 -17
  433. data/spec/unit/provider/service/upstart_spec.rb +1 -1
  434. data/spec/unit/provider/user/aix_spec.rb +42 -0
  435. data/spec/unit/provider/user/directoryservice_spec.rb +1 -0
  436. data/spec/unit/provider/user/pw_spec.rb +24 -12
  437. data/spec/unit/provider/user/user_role_add_spec.rb +1 -1
  438. data/spec/unit/provider/user/useradd_spec.rb +179 -15
  439. data/spec/unit/resource/type_spec.rb +3 -3
  440. data/spec/unit/scheduler/job_spec.rb +79 -0
  441. data/spec/unit/scheduler/scheduler_spec.rb +129 -0
  442. data/spec/unit/scheduler/splay_job_spec.rb +35 -0
  443. data/spec/unit/ssl/base_spec.rb +3 -9
  444. data/spec/unit/ssl/certificate_authority_spec.rb +1 -0
  445. data/spec/unit/ssl/certificate_request_spec.rb +3 -1
  446. data/spec/unit/ssl/certificate_spec.rb +3 -1
  447. data/spec/unit/ssl/configuration_spec.rb +74 -0
  448. data/spec/unit/ssl/host_spec.rb +28 -7
  449. data/spec/unit/ssl/validator_spec.rb +311 -0
  450. data/spec/unit/transaction/event_manager_spec.rb +49 -0
  451. data/spec/unit/transaction/event_spec.rb +20 -5
  452. data/spec/unit/transaction/report_spec.rb +8 -0
  453. data/spec/unit/type/cron_spec.rb +9 -0
  454. data/spec/unit/type/exec_spec.rb +11 -0
  455. data/spec/unit/type/file/content_spec.rb +20 -20
  456. data/spec/unit/type/file/mode_spec.rb +6 -0
  457. data/spec/unit/type/file/source_spec.rb +9 -7
  458. data/spec/unit/type/file_spec.rb +22 -3
  459. data/spec/unit/type/service_spec.rb +34 -21
  460. data/spec/unit/type_spec.rb +46 -1
  461. data/spec/unit/util/backups_spec.rb +2 -2
  462. data/spec/unit/util/execution_spec.rb +4 -1
  463. data/spec/unit/util/filetype_spec.rb +6 -0
  464. data/spec/unit/util/monkey_patches_spec.rb +18 -0
  465. data/spec/unit/util/network_device/cisco/device_spec.rb +37 -0
  466. data/spec/unit/util/network_device/config_spec.rb +14 -0
  467. data/spec/unit/util/network_device_spec.rb +3 -3
  468. data/spec/unit/util/profiler/logging_spec.rb +81 -0
  469. data/spec/unit/util/profiler/none_spec.rb +12 -0
  470. data/spec/unit/util/profiler/object_counts_spec.rb +14 -0
  471. data/spec/unit/util/profiler/wall_clock_spec.rb +13 -0
  472. data/spec/unit/util/pson_spec.rb +5 -0
  473. data/spec/unit/util/ssl_spec.rb +51 -0
  474. data/spec/unit/util/windows/root_certs_spec.rb +15 -0
  475. data/spec/unit/util_spec.rb +28 -0
  476. metadata +2593 -2307
  477. data/spec/unit/module_tool/applications/application_spec.rb +0 -19
@@ -0,0 +1,842 @@
1
+ # the scanner/lexer
2
+
3
+ require 'forwardable'
4
+ require 'strscan'
5
+ require 'puppet'
6
+ require 'puppet/util/methodhelper'
7
+
8
+ module Puppet
9
+ class LexError < RuntimeError; end
10
+ end
11
+
12
+ class Puppet::Pops::Parser::Lexer
13
+ extend Forwardable
14
+
15
+ attr_reader :file, :lexing_context, :token_queue
16
+
17
+ attr_reader :locator
18
+
19
+ attr_accessor :indefine
20
+ alias :indefine? :indefine
21
+
22
+ def lex_error msg
23
+ raise Puppet::LexError.new(msg)
24
+ end
25
+
26
+ class Token
27
+ ALWAYS_ACCEPTABLE = Proc.new { |context| true }
28
+
29
+ include Puppet::Util::MethodHelper
30
+
31
+ attr_accessor :regex, :name, :string, :skip, :skip_text
32
+ alias skip? skip
33
+
34
+ # @param string_or_regex[String] a literal string token matcher
35
+ # @param string_or_regex[Regexp] a regular expression token text matcher
36
+ # @param name [String] the token name (what it is known as in the grammar)
37
+ # @param options [Hash] see {#set_options}
38
+ #
39
+ def initialize(string_or_regex, name, options = {})
40
+ if string_or_regex.is_a?(String)
41
+ @name, @string = name, string_or_regex
42
+ @regex = Regexp.new(Regexp.escape(string_or_regex))
43
+ else
44
+ @name, @regex = name, string_or_regex
45
+ end
46
+
47
+ set_options(options)
48
+ @acceptable_when = ALWAYS_ACCEPTABLE
49
+ end
50
+
51
+ # @return [String] human readable token reference; the String if literal, else the token name
52
+ def to_s
53
+ string or @name.to_s
54
+ end
55
+
56
+ # @return [Boolean] if the token is acceptable in the given context or not.
57
+ # this implementation always returns true.
58
+ # @param context [Hash] ? ? ?
59
+ #
60
+ def acceptable?(context={})
61
+ @acceptable_when.call(context)
62
+ end
63
+
64
+
65
+ # Defines when the token is able to match.
66
+ # This provides context that cannot be expressed otherwise, such as feature flags.
67
+ #
68
+ # @param block [Proc] a proc that given a context returns a boolean
69
+ def acceptable_when(block)
70
+ @acceptable_when = block
71
+ end
72
+ end
73
+
74
+ # Maintains a list of tokens.
75
+ class TokenList
76
+ extend Forwardable
77
+
78
+ attr_reader :regex_tokens, :string_tokens
79
+ def_delegator :@tokens, :[]
80
+ # Adds a new token to the set of recognized tokens
81
+ # @param name [String] the token name
82
+ # @param regex [Regexp, String] source text token matcher, a litral string or regular expression
83
+ # @param options [Hash] see {Token::set_options}
84
+ # @param block [Proc] optional block set as the created tokens `convert` method
85
+ # @raise [ArgumentError] if the token with the given name is already defined
86
+ #
87
+ def add_token(name, regex, options = {}, &block)
88
+ raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name)
89
+ token = Token.new(regex, name, options)
90
+ @tokens[token.name] = token
91
+ if token.string
92
+ @string_tokens << token
93
+ @tokens_by_string[token.string] = token
94
+ else
95
+ @regex_tokens << token
96
+ end
97
+
98
+ token.meta_def(:convert, &block) if block_given?
99
+
100
+ token
101
+ end
102
+
103
+ # Creates an empty token list
104
+ #
105
+ def initialize
106
+ @tokens = {}
107
+ @regex_tokens = []
108
+ @string_tokens = []
109
+ @tokens_by_string = {}
110
+ end
111
+
112
+ # Look up a token by its literal (match) value, rather than name.
113
+ # @param string [String, nil] the literal match string to obtain a {Token} for, or nil if it does not exist.
114
+ def lookup(string)
115
+ @tokens_by_string[string]
116
+ end
117
+
118
+ # Adds tokens from a hash where key is a matcher (literal string or regexp) and the
119
+ # value is the token's name
120
+ # @param hash [Hash<{String => Symbol}, Hash<{Regexp => Symbol}] map token text matcher to token name
121
+ # @return [void]
122
+ #
123
+ def add_tokens(hash)
124
+ hash.each do |regex, name|
125
+ add_token(name, regex)
126
+ end
127
+ end
128
+
129
+ # Sort literal (string-) tokens by length, so we know once we match, we're done.
130
+ # This helps avoid the O(n^2) nature of token matching.
131
+ # The tokens are sorted in place.
132
+ # @return [void]
133
+ def sort_tokens
134
+ @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
135
+ end
136
+
137
+ # Yield each token name and value in turn.
138
+ def each
139
+ @tokens.each {|name, value| yield name, value }
140
+ end
141
+ end
142
+
143
+ TOKENS = TokenList.new
144
+ TOKENS.add_tokens(
145
+ '[' => :LBRACK,
146
+ ']' => :RBRACK,
147
+ # '{' => :LBRACE, # Specialized to handle lambda
148
+ '}' => :RBRACE,
149
+ '(' => :LPAREN,
150
+ ')' => :RPAREN,
151
+ '=' => :EQUALS,
152
+ '+=' => :APPENDS,
153
+ '==' => :ISEQUAL,
154
+ '>=' => :GREATEREQUAL,
155
+ '>' => :GREATERTHAN,
156
+ '<' => :LESSTHAN,
157
+ '<=' => :LESSEQUAL,
158
+ '!=' => :NOTEQUAL,
159
+ '!' => :NOT,
160
+ ',' => :COMMA,
161
+ '.' => :DOT,
162
+ ':' => :COLON,
163
+ '@' => :AT,
164
+ '|' => :PIPE,
165
+ '<<|' => :LLCOLLECT,
166
+ '|>>' => :RRCOLLECT,
167
+ '->' => :IN_EDGE,
168
+ '<-' => :OUT_EDGE,
169
+ '~>' => :IN_EDGE_SUB,
170
+ '<~' => :OUT_EDGE_SUB,
171
+ '<|' => :LCOLLECT,
172
+ '|>' => :RCOLLECT,
173
+ ';' => :SEMIC,
174
+ '?' => :QMARK,
175
+ '\\' => :BACKSLASH,
176
+ '=>' => :FARROW,
177
+ '+>' => :PARROW,
178
+ '+' => :PLUS,
179
+ '-' => :MINUS,
180
+ '/' => :DIV,
181
+ '*' => :TIMES,
182
+ '%' => :MODULO,
183
+ '<<' => :LSHIFT,
184
+ '>>' => :RSHIFT,
185
+ '=~' => :MATCH,
186
+ '!~' => :NOMATCH,
187
+ %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF,
188
+ "<string>" => :STRING,
189
+ "<dqstring up to first interpolation>" => :DQPRE,
190
+ "<dqstring between two interpolations>" => :DQMID,
191
+ "<dqstring after final interpolation>" => :DQPOST,
192
+ "<boolean>" => :BOOLEAN,
193
+ "<lambda start>" => :LAMBDA, # A LBRACE followed by '|'
194
+ "<select start>" => :SELBRACE # A QMARK followed by '{'
195
+ )
196
+
197
+ module Contextual
198
+ QUOTE_TOKENS = [:DQPRE,:DQMID]
199
+ REGEX_INTRODUCING_TOKENS = [:NODE,:LBRACE, :SELBRACE, :RBRACE,:MATCH,:NOMATCH,:COMMA]
200
+
201
+ NOT_INSIDE_QUOTES = Proc.new do |context|
202
+ !QUOTE_TOKENS.include? context[:after]
203
+ end
204
+
205
+ INSIDE_QUOTES = Proc.new do |context|
206
+ QUOTE_TOKENS.include? context[:after]
207
+ end
208
+
209
+ IN_REGEX_POSITION = Proc.new do |context|
210
+ REGEX_INTRODUCING_TOKENS.include? context[:after]
211
+ end
212
+
213
+ IN_STRING_INTERPOLATION = Proc.new do |context|
214
+ context[:string_interpolation_depth] > 0
215
+ end
216
+
217
+ DASHED_VARIABLES_ALLOWED = Proc.new do |context|
218
+ Puppet[:allow_variables_with_dashes]
219
+ end
220
+
221
+ VARIABLE_AND_DASHES_ALLOWED = Proc.new do |context|
222
+ Contextual::DASHED_VARIABLES_ALLOWED.call(context) and TOKENS[:VARIABLE].acceptable?(context)
223
+ end
224
+ end
225
+
226
+ # LBRACE needs look ahead to differentiate between '{' and a '{'
227
+ # followed by a '|' (start of lambda) The racc grammar can only do one
228
+ # token lookahead.
229
+ #
230
+ TOKENS.add_token :LBRACE, /\{/ do | lexer, value |
231
+ if lexer.match?(/[ \t\r]*\|/)
232
+ [TOKENS[:LAMBDA], value]
233
+ elsif lexer.lexing_context[:after] == :QMARK
234
+ [TOKENS[:SELBRACE], value]
235
+ else
236
+ [TOKENS[:LBRACE], value]
237
+ end
238
+ end
239
+
240
+ # Numbers are treated separately from names, so that they may contain dots.
241
+ TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value|
242
+ lexer.assert_numeric(value)
243
+ [TOKENS[:NAME], value]
244
+ end
245
+ TOKENS[:NUMBER].acceptable_when Contextual::NOT_INSIDE_QUOTES
246
+
247
+ TOKENS.add_token :NAME, %r{((::)?[a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*} do |lexer, value|
248
+ # A name starting with a number must be a valid numeric string (not that
249
+ # NUMBER token captures those names that do not comply with the name rule.
250
+ if value =~ /^[0-9].*$/
251
+ lexer.assert_numeric(value)
252
+ end
253
+
254
+ string_token = self
255
+ # we're looking for keywords here
256
+ if tmp = KEYWORDS.lookup(value)
257
+ string_token = tmp
258
+ if [:TRUE, :FALSE].include?(string_token.name)
259
+ value = eval(value)
260
+ string_token = TOKENS[:BOOLEAN]
261
+ end
262
+ end
263
+ [string_token, value]
264
+ end
265
+ [:NAME, :CLASSREF].each do |name_token|
266
+ TOKENS[name_token].acceptable_when Contextual::NOT_INSIDE_QUOTES
267
+ end
268
+
269
+ TOKENS.add_token :COMMENT, %r{#.*}, :skip => true do |lexer,value|
270
+ value.sub!(/# ?/,'')
271
+ [self, value]
272
+ end
273
+
274
+ TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :skip => true do |lexer, value|
275
+ value.sub!(/^\/\* ?/,'')
276
+ value.sub!(/ ?\*\/$/,'')
277
+ [self,value]
278
+ end
279
+
280
+ TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value|
281
+ # Make sure we haven't matched an escaped /
282
+ while value[-2..-2] == '\\'
283
+ other = lexer.scan_until(%r{/})
284
+ value += other
285
+ end
286
+ regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/")
287
+ [self, Regexp.new(regex)]
288
+ end
289
+ TOKENS[:REGEX].acceptable_when Contextual::IN_REGEX_POSITION
290
+
291
+ TOKENS.add_token :RETURN, "\n", :skip => true, :skip_text => true
292
+
293
+ TOKENS.add_token :SQUOTE, "'" do |lexer, value|
294
+ [TOKENS[:STRING], lexer.slurpstring(value,["'"],:ignore_invalid_escapes).first ]
295
+ end
296
+
297
+ DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING}
298
+ DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST}
299
+
300
+ TOKENS.add_token :DQUOTE, /"/ do |lexer, value|
301
+ lexer.tokenize_interpolated_string(DQ_initial_token_types)
302
+ end
303
+
304
+ TOKENS.add_token :DQCONT, /\}/ do |lexer, value|
305
+ lexer.tokenize_interpolated_string(DQ_continuation_token_types)
306
+ end
307
+ TOKENS[:DQCONT].acceptable_when Contextual::IN_STRING_INTERPOLATION
308
+
309
+ TOKENS.add_token :DOLLAR_VAR_WITH_DASH, %r{\$(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value|
310
+ lexer.warn_if_variable_has_hyphen(value)
311
+
312
+ [TOKENS[:VARIABLE], value[1..-1]]
313
+ end
314
+ TOKENS[:DOLLAR_VAR_WITH_DASH].acceptable_when Contextual::DASHED_VARIABLES_ALLOWED
315
+
316
+ TOKENS.add_token :DOLLAR_VAR, %r{\$(::)?(\w+::)*\w+} do |lexer, value|
317
+ [TOKENS[:VARIABLE],value[1..-1]]
318
+ end
319
+
320
+ TOKENS.add_token :VARIABLE_WITH_DASH, %r{(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value|
321
+ lexer.warn_if_variable_has_hyphen(value)
322
+ # If the varname (following $, or ${ is followed by (, it is a function call, and not a variable
323
+ # reference.
324
+ #
325
+ if lexer.match?(%r{[ \t\r]*\(})
326
+ [TOKENS[:NAME],value]
327
+ else
328
+ [TOKENS[:VARIABLE], value]
329
+ end
330
+ end
331
+ TOKENS[:VARIABLE_WITH_DASH].acceptable_when Contextual::VARIABLE_AND_DASHES_ALLOWED
332
+
333
+ TOKENS.add_token :VARIABLE, %r{(::)?(\w+::)*\w+} do |lexer, value|
334
+ # If the varname (following $, or ${ is followed by (, it is a function call, and not a variable
335
+ # reference.
336
+ #
337
+ if lexer.match?(%r{[ \t\r]*\(})
338
+ [TOKENS[:NAME],value]
339
+ else
340
+ [TOKENS[:VARIABLE],value]
341
+ end
342
+
343
+ end
344
+ TOKENS[:VARIABLE].acceptable_when Contextual::INSIDE_QUOTES
345
+
346
+ TOKENS.sort_tokens
347
+
348
+ @@pairs = {
349
+ "{" => "}",
350
+ "(" => ")",
351
+ "[" => "]",
352
+ "<|" => "|>",
353
+ "<<|" => "|>>",
354
+ "|" => "|"
355
+ }
356
+
357
+ KEYWORDS = TokenList.new
358
+ KEYWORDS.add_tokens(
359
+ "case" => :CASE,
360
+ "class" => :CLASS,
361
+ "default" => :DEFAULT,
362
+ "define" => :DEFINE,
363
+ # "import" => :IMPORT,
364
+ "if" => :IF,
365
+ "elsif" => :ELSIF,
366
+ "else" => :ELSE,
367
+ "inherits" => :INHERITS,
368
+ "node" => :NODE,
369
+ "and" => :AND,
370
+ "or" => :OR,
371
+ "undef" => :UNDEF,
372
+ "false" => :FALSE,
373
+ "true" => :TRUE,
374
+ "in" => :IN,
375
+ "unless" => :UNLESS
376
+ )
377
+
378
+ def clear
379
+ initvars
380
+ end
381
+
382
+ def expected
383
+ return nil if @expected.empty?
384
+ name = @expected[-1]
385
+ TOKENS.lookup(name) or lex_error "Internal Lexer Error: Could not find expected token #{name}"
386
+ end
387
+
388
+ # scan the whole file
389
+ # basically just used for testing
390
+ def fullscan
391
+ array = []
392
+
393
+ self.scan { |token, str|
394
+ # Ignore any definition nesting problems
395
+ @indefine = false
396
+ array.push([token,str])
397
+ }
398
+ array
399
+ end
400
+
401
+ def file=(file)
402
+ @file = file
403
+ contents = File.exists?(file) ? File.read(file) : ""
404
+ @scanner = StringScanner.new(contents)
405
+ @locator = Locator.new(contents, multibyte?)
406
+ end
407
+
408
+ def_delegator :@token_queue, :shift, :shift_token
409
+
410
+ def find_string_token
411
+ # We know our longest string token is three chars, so try each size in turn
412
+ # until we either match or run out of chars. This way our worst-case is three
413
+ # tries, where it is otherwise the number of string token we have. Also,
414
+ # the lookups are optimized hash lookups, instead of regex scans.
415
+ #
416
+ s = @scanner.peek(3)
417
+ token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1])
418
+ [ token, token && @scanner.scan(token.regex) ]
419
+ end
420
+
421
+ # Find the next token that matches a regex. We look for these first.
422
+ def find_regex_token
423
+ best_token = nil
424
+ best_length = 0
425
+
426
+ # I tried optimizing based on the first char, but it had
427
+ # a slightly negative affect and was a good bit more complicated.
428
+ TOKENS.regex_tokens.each do |token|
429
+ if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context)
430
+ # We've found a longer match
431
+ if length > best_length
432
+ best_length = length
433
+ best_token = token
434
+ end
435
+ end
436
+ end
437
+
438
+ return best_token, @scanner.scan(best_token.regex) if best_token
439
+ end
440
+
441
+ # Find the next token, returning the string and the token.
442
+ def find_token
443
+ shift_token || find_regex_token || find_string_token
444
+ end
445
+
446
+ def initialize
447
+ @multibyte = init_multibyte
448
+ initvars
449
+ end
450
+
451
+ def assert_numeric(value)
452
+ if value =~ /^0[xX].*$/
453
+ lex_error (positioned_message("Not a valid hex number #{value}")) unless value =~ /^0[xX][0-9A-Fa-f]+$/
454
+ elsif value =~ /^0[^.].*$/
455
+ lex_error(positioned_message("Not a valid octal number #{value}")) unless value =~ /^0[0-7]+$/
456
+ else
457
+ lex_error(positioned_message("Not a valid decimal number #{value}")) unless value =~ /0?\d+(?:\.\d+)?(?:[eE]-?\d+)?/
458
+ end
459
+ end
460
+
461
+ # Returns true if ruby version >= 1.9.3 since regexp supports multi-byte matches and expanded
462
+ # character categories like [[:blank:]].
463
+ #
464
+ # This implementation will fail if there are more than 255 minor or micro versions of ruby
465
+ #
466
+ def init_multibyte
467
+ numver = RUBY_VERSION.split(".").collect {|s| s.to_i }
468
+ return true if (numver[0] << 16 | numver[1] << 8 | numver[2]) >= (1 << 16 | 9 << 8 | 3)
469
+ false
470
+ end
471
+
472
+ def multibyte?
473
+ @multibyte
474
+ end
475
+
476
+ def initvars
477
+ @previous_token = nil
478
+ @scanner = nil
479
+ @file = nil
480
+
481
+ # AAARRGGGG! okay, regexes in ruby are bloody annoying
482
+ # no one else has "\n" =~ /\s/
483
+
484
+ if multibyte?
485
+ # Skip all kinds of space, and CR, but not newlines
486
+ @skip = %r{[[:blank:]\r]+}
487
+ else
488
+ @skip = %r{[ \t\r]+}
489
+ end
490
+
491
+ @namestack = []
492
+ @token_queue = []
493
+ @indefine = false
494
+ @expected = []
495
+ @lexing_context = {
496
+ :after => nil,
497
+ :start_of_line => true,
498
+ :offset => 0, # byte offset before where token starts
499
+ :end_offset => 0, # byte offset after scanned token
500
+ :string_interpolation_depth => 0
501
+ }
502
+ end
503
+
504
+ # Make any necessary changes to the token and/or value.
505
+ def munge_token(token, value)
506
+ # A token may already have been munged (converted and positioned)
507
+ #
508
+ return token, value if value.is_a? Hash
509
+
510
+ skip if token.skip_text
511
+
512
+ return if token.skip
513
+
514
+ token, value = token.convert(self, value) if token.respond_to?(:convert)
515
+
516
+ return unless token
517
+
518
+ return if token.skip
519
+
520
+ # If the conversion performed the munging/positioning
521
+ return token, value if value.is_a? Hash
522
+
523
+ pos_hash = position_in_source
524
+ pos_hash[:value] = value
525
+
526
+ # Add one to pos, first char on line is 1
527
+ return token, pos_hash
528
+ end
529
+
530
+ # Returns a hash with the current position in source based on the current lexing context
531
+ #
532
+ def position_in_source
533
+ pos = @locator.pos_on_line(lexing_context[:offset])
534
+ offset = @locator.char_offset(lexing_context[:offset])
535
+ length = @locator.char_length(lexing_context[:offset], lexing_context[:end_offset])
536
+ start_line = @locator.line_for_offset(lexing_context[:offset])
537
+
538
+ return { :line => start_line, :pos => pos, :offset => offset, :length => length}
539
+ end
540
+
541
+ def pos
542
+ @locator.pos_on_line(lexing_context[:offset])
543
+ end
544
+
545
+ # Handling the namespace stack
546
+ def_delegator :@namestack, :pop, :namepop
547
+
548
+ # This value might have :: in it, but we don't care -- it'll be handled
549
+ # normally when joining, and when popping we want to pop this full value,
550
+ # however long the namespace is.
551
+ def_delegator :@namestack, :<<, :namestack
552
+
553
+ # Collect the current namespace.
554
+ def namespace
555
+ @namestack.join("::")
556
+ end
557
+
558
+ def_delegator :@scanner, :rest
559
+ # this is the heart of the lexer
560
+ def scan
561
+ #Puppet.debug("entering scan")
562
+ lex_error "Internal Error: No string or file given to lexer to process." unless @scanner
563
+
564
+ # Skip any initial whitespace.
565
+ skip
566
+
567
+ until token_queue.empty? and @scanner.eos? do
568
+ yielded = false
569
+ offset = @scanner.pos
570
+ matched_token, value = find_token
571
+ end_offset = @scanner.pos
572
+
573
+ # error out if we didn't match anything at all
574
+ lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token
575
+
576
+ newline = matched_token.name == :RETURN
577
+
578
+ lexing_context[:start_of_line] = newline
579
+ lexing_context[:offset] = offset
580
+ lexing_context[:end_offset] = end_offset
581
+
582
+ final_token, token_value = munge_token(matched_token, value)
583
+ # update end position since munging may have moved the end offset
584
+ lexing_context[:end_offset] = @scanner.pos
585
+
586
+ unless final_token
587
+ skip
588
+ next
589
+ end
590
+
591
+ lexing_context[:after] = final_token.name unless newline
592
+ lexing_context[:string_interpolation_depth] += 1 if final_token.name == :DQPRE
593
+ lexing_context[:string_interpolation_depth] -= 1 if final_token.name == :DQPOST
594
+
595
+ value = token_value[:value]
596
+
597
+ if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE
598
+ @expected << match
599
+ elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE
600
+ @expected.pop
601
+ end
602
+
603
+ yield [final_token.name, token_value]
604
+
605
+ if @previous_token
606
+ namestack(value) if @previous_token.name == :CLASS and value != '{'
607
+
608
+ if @previous_token.name == :DEFINE
609
+ if indefine?
610
+ msg = "Cannot nest definition #{value} inside #{@indefine}"
611
+ self.indefine = false
612
+ raise Puppet::ParseError, msg
613
+ end
614
+
615
+ @indefine = value
616
+ end
617
+ end
618
+ @previous_token = final_token
619
+ skip
620
+ end
621
+ # Cannot reset @scanner to nil here - it is needed to answer questions about context after
622
+ # completed parsing.
623
+ # Seems meaningless to do this. Everything will be gc anyway.
624
+ #@scanner = nil
625
+
626
+ # This indicates that we're done parsing.
627
+ yield [false,false]
628
+ end
629
+
630
+ # Skip any skipchars in our remaining string.
631
+ def skip
632
+ @scanner.skip(@skip)
633
+ end
634
+
635
+ def match? r
636
+ @scanner.match?(r)
637
+ end
638
+
639
+ # Provide some limited access to the scanner, for those
640
+ # tokens that need it.
641
+ def_delegator :@scanner, :scan_until
642
+
643
+ # we've encountered the start of a string...
644
+ # slurp in the rest of the string and return it
645
+ def slurpstring(terminators,escapes=%w{ \\ $ ' " r n t s }+["\n"],ignore_invalid_escapes=false)
646
+ # we search for the next quote that isn't preceded by a
647
+ # backslash; the caret is there to match empty strings
648
+ last = @scanner.matched
649
+ tmp_offset = @scanner.pos
650
+ str = @scanner.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]/) || lex_error(positioned_message("Unclosed quote after #{format_quote(last)} followed by '#{followed_by}'"))
651
+ str.gsub!(/\\(.)/m) {
652
+ ch = $1
653
+ if escapes.include? ch
654
+ case ch
655
+ when 'r'; "\r"
656
+ when 'n'; "\n"
657
+ when 't'; "\t"
658
+ when 's'; " "
659
+ when "\n"; ''
660
+ else ch
661
+ end
662
+ else
663
+ Puppet.warning(positioned_message("Unrecognized escape sequence '\\#{ch}'")) unless ignore_invalid_escapes
664
+ "\\#{ch}"
665
+ end
666
+ }
667
+ [ str[0..-2],str[-1,1] ]
668
+ end
669
+
670
+ # Formats given message by appending file, line and position if available.
671
+ def positioned_message msg
672
+ result = [msg]
673
+ result << "in file #{file}" if file
674
+ result << "at line #{line}:#{pos}" if line
675
+ result.join(" ")
676
+ end
677
+
678
+ # Returns "<eof>" if at end of input, else the following 5 characters with \n \r \t escaped
679
+ def followed_by
680
+ return "<eof>" if @scanner.eos?
681
+ result = @scanner.rest[0,5] + "..."
682
+ result.gsub!("\t", '\t')
683
+ result.gsub!("\n", '\n')
684
+ result.gsub!("\r", '\r')
685
+ result
686
+ end
687
+
688
+ def format_quote q
689
+ if q == "'"
690
+ '"\'"'
691
+ else
692
+ "'#{q}'"
693
+ end
694
+ end
695
+
696
+ def tokenize_interpolated_string(token_type,preamble='')
697
+ # Expecting a (possibly empty) stretch of text terminated by end of string ", a variable $, or expression ${
698
+ # The length of this part includes the start and terminating characters.
699
+ value,terminator = slurpstring('"$')
700
+
701
+ # Advanced after '{' if this is in expression ${} interpolation
702
+ braced = terminator == '$' && @scanner.scan(/\{/)
703
+ # make offset to end_ofset be the length of the pre expression string including its start and terminating chars
704
+ lexing_context[:end_offset] = @scanner.pos
705
+
706
+ token_queue << [TOKENS[token_type[terminator]],position_in_source().merge!({:value => preamble+value})]
707
+ variable_regex = if Puppet[:allow_variables_with_dashes]
708
+ TOKENS[:VARIABLE_WITH_DASH].regex
709
+ else
710
+ TOKENS[:VARIABLE].regex
711
+ end
712
+ if terminator != '$' or braced
713
+ return token_queue.shift
714
+ end
715
+
716
+ tmp_offset = @scanner.pos
717
+ if var_name = @scanner.scan(variable_regex)
718
+ lexing_context[:offset] = tmp_offset
719
+ lexing_context[:end_offset] = @scanner.pos
720
+ warn_if_variable_has_hyphen(var_name)
721
+ # If the varname after ${ is followed by (, it is a function call, and not a variable
722
+ # reference.
723
+ #
724
+ if braced && @scanner.match?(%r{[ \t\r]*\(})
725
+ token_queue << [TOKENS[:NAME], position_in_source().merge!({:value=>var_name})]
726
+ else
727
+ token_queue << [TOKENS[:VARIABLE],position_in_source().merge!({:value=>var_name})]
728
+ end
729
+ lexing_context[:offset] = @scanner.pos
730
+ tokenize_interpolated_string(DQ_continuation_token_types)
731
+ else
732
+ tokenize_interpolated_string(token_type, replace_false_start_with_text(terminator))
733
+ end
734
+ end
735
+
736
+ def replace_false_start_with_text(appendix)
737
+ last_token = token_queue.pop
738
+ value = last_token.last
739
+ if value.is_a? Hash
740
+ value[:value] + appendix
741
+ else
742
+ value + appendix
743
+ end
744
+ end
745
+
746
+ # just parse a string, not a whole file
747
+ def string=(string)
748
+ @scanner = StringScanner.new(string)
749
+ @locator = Locator.new(string, multibyte?)
750
+ end
751
+
752
+ def warn_if_variable_has_hyphen(var_name)
753
+ if var_name.include?('-')
754
+ Puppet.deprecation_warning("Using `-` in variable names is deprecated at #{file || '<string>'}:#{line}. See http://links.puppetlabs.com/puppet-hyphenated-variable-deprecation")
755
+ end
756
+ end
757
+
758
+ # Returns the line number (starting from 1) for the current position
759
+ # in the scanned text (at the end of the last produced, but not necessarily
760
+ # consumed.
761
+ #
762
+ def line
763
+ return 1 unless lexing_context && locator
764
+ locator.line_for_offset(lexing_context[:end_offset])
765
+ end
766
+
767
+ # Helper class that keeps track of where line breaks are located and can answer questions about positions.
768
+ #
769
+ class Locator
770
+ attr_reader :line_index
771
+ attr_reader :string
772
+
773
+ # Create a locator based on a content string, and a boolean indicating if ruby version support multi-byte strings
774
+ # or not.
775
+ #
776
+ def initialize(string, multibyte)
777
+ @string = string
778
+ @multibyte = multibyte
779
+ compute_line_index
780
+ end
781
+
782
+ # Returns whether this a ruby version that supports multi-byte strings or not
783
+ #
784
+ def multibyte?
785
+ @multibyte
786
+ end
787
+
788
+ # Computes the start offset for each line.
789
+ #
790
+ def compute_line_index
791
+ scanner = StringScanner.new(@string)
792
+ result = [0] # first line starts at 0
793
+ while scanner.scan_until(/\n/)
794
+ result << scanner.pos
795
+ end
796
+ @line_index = result
797
+ end
798
+
799
+ # Returns the line number (first line is 1) for the given offset
800
+ def line_for_offset(offset)
801
+ if line_nbr = line_index.index {|x| x > offset}
802
+ return line_nbr
803
+ end
804
+ # If not found it is after last
805
+ return line_index.size
806
+ end
807
+
808
+ # Returns the offset on line (first offset on a line is 0).
809
+ #
810
+ def offset_on_line(offset)
811
+ line_offset = line_index[line_for_offset(offset)-1]
812
+ if multibyte?
813
+ @string.byteslice(line_offset, offset-line_offset).length
814
+ else
815
+ offset - line_offset
816
+ end
817
+ end
818
+
819
+ # Returns the position on line (first position on a line is 1)
820
+ def pos_on_line(offset)
821
+ offset_on_line(offset) +1
822
+ end
823
+
824
+ # Returns the character offset for a given byte offset
825
+ def char_offset(byte_offset)
826
+ if multibyte?
827
+ @string.byteslice(0, byte_offset).length
828
+ else
829
+ byte_offset
830
+ end
831
+ end
832
+
833
+ # Returns the length measured in number of characters from the given start and end byte offseta
834
+ def char_length(offset, end_offset)
835
+ if multibyte?
836
+ @string.byteslice(offset, end_offset - offset).length
837
+ else
838
+ end_offset - offset
839
+ end
840
+ end
841
+ end
842
+ end