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.
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +32 -19
- data/README_DEVELOPER.md +332 -14
- data/Rakefile +9 -5
- data/ext/build_defaults.yaml +2 -3
- data/ext/debian/changelog.erb +6 -0
- data/ext/debian/control +6 -6
- data/ext/envpuppet +4 -4
- data/ext/project_data.yaml +1 -0
- data/ext/puppet-nm-dispatcher +13 -0
- data/ext/redhat/puppet.spec.erb +17 -0
- data/ext/suse/client.init +1 -1
- data/ext/systemd/puppetagent.service +2 -2
- data/ext/systemd/puppetmaster.service +2 -2
- data/lib/hiera/scope.rb +29 -11
- data/lib/hiera_puppet.rb +1 -3
- data/lib/puppet/agent.rb +3 -3
- data/lib/puppet/application.rb +2 -2
- data/lib/puppet/application/agent.rb +27 -12
- data/lib/puppet/application/apply.rb +11 -1
- data/lib/puppet/application/describe.rb +1 -1
- data/lib/puppet/application/doc.rb +13 -9
- data/lib/puppet/application/filebucket.rb +0 -1
- data/lib/puppet/application/kick.rb +1 -0
- data/lib/puppet/application/master.rb +16 -8
- data/lib/puppet/daemon.rb +19 -64
- data/lib/puppet/defaults.rb +61 -5
- data/lib/puppet/error.rb +15 -4
- data/lib/puppet/external/nagios/grammar.ry +1 -1
- data/lib/puppet/external/nagios/makefile +1 -1
- data/lib/puppet/external/nagios/parser.rb +185 -618
- data/lib/puppet/external/pson/pure/parser.rb +47 -1
- data/lib/puppet/face/certificate.rb +3 -3
- data/lib/puppet/face/module.rb +1 -1
- data/lib/puppet/face/module/changes.rb +3 -1
- data/lib/puppet/face/module/uninstall.rb +1 -1
- data/lib/puppet/face/node/clean.rb +5 -5
- data/lib/puppet/feature/base.rb +3 -1
- data/lib/puppet/feature/libuser.rb +8 -0
- data/lib/puppet/file_serving/fileset.rb +9 -1
- data/lib/puppet/forge.rb +28 -5
- data/lib/puppet/forge/errors.rb +34 -0
- data/lib/puppet/forge/repository.rb +1 -1
- data/lib/puppet/indirector.rb +4 -1
- data/lib/puppet/indirector/catalog/compiler.rb +37 -30
- data/lib/puppet/indirector/facts/inventory_active_record.rb +1 -0
- data/lib/puppet/indirector/indirection.rb +28 -15
- data/lib/puppet/indirector/rest.rb +18 -10
- data/lib/puppet/interface.rb +11 -4
- data/lib/puppet/interface/action.rb +1 -3
- data/lib/puppet/interface/action_builder.rb +0 -3
- data/lib/puppet/interface/action_manager.rb +0 -3
- data/lib/puppet/interface/face_collection.rb +0 -2
- data/lib/puppet/interface/option.rb +0 -2
- data/lib/puppet/interface/option_builder.rb +0 -2
- data/lib/puppet/interface/option_manager.rb +0 -2
- data/lib/puppet/metatype/manager.rb +1 -1
- data/lib/puppet/module_tool.rb +1 -0
- data/lib/puppet/module_tool/applications/application.rb +0 -3
- data/lib/puppet/module_tool/applications/builder.rb +8 -20
- data/lib/puppet/module_tool/applications/checksummer.rb +1 -1
- data/lib/puppet/module_tool/applications/installer.rb +1 -0
- data/lib/puppet/module_tool/applications/unpacker.rb +3 -11
- data/lib/puppet/module_tool/checksums.rb +1 -1
- data/lib/puppet/module_tool/errors/installer.rb +18 -1
- data/lib/puppet/module_tool/modulefile.rb +2 -2
- data/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb +1 -1
- data/lib/puppet/module_tool/tar.rb +17 -0
- data/lib/puppet/module_tool/tar/gnu.rb +9 -0
- data/lib/puppet/module_tool/tar/mini.rb +39 -0
- data/lib/puppet/module_tool/tar/solaris.rb +5 -0
- data/lib/puppet/network/http.rb +1 -0
- data/lib/puppet/network/http/connection.rb +9 -23
- data/lib/puppet/network/http/handler.rb +38 -7
- data/lib/puppet/network/http/rack/rest.rb +14 -3
- data/lib/puppet/network/http/webrick.rb +3 -1
- data/lib/puppet/network/http/webrick/rest.rb +11 -2
- data/lib/puppet/node/environment.rb +3 -1
- data/lib/puppet/parameter.rb +32 -29
- data/lib/puppet/parameter/package_options.rb +1 -1
- data/lib/puppet/parameter/path.rb +1 -1
- data/lib/puppet/parameter/value.rb +1 -1
- data/lib/puppet/parameter/value_collection.rb +7 -3
- data/lib/puppet/parser/ast.rb +3 -1
- data/lib/puppet/parser/ast/arithmetic_operator.rb +56 -12
- data/lib/puppet/parser/ast/astarray.rb +1 -1
- data/lib/puppet/parser/ast/block_expression.rb +41 -0
- data/lib/puppet/parser/ast/function.rb +13 -2
- data/lib/puppet/parser/ast/lambda.rb +107 -0
- data/lib/puppet/parser/ast/leaf.rb +1 -2
- data/lib/puppet/parser/ast/method_call.rb +77 -0
- data/lib/puppet/parser/ast/vardef.rb +7 -0
- data/lib/puppet/parser/compiler.rb +27 -16
- data/lib/puppet/parser/e_parser_adapter.rb +120 -0
- data/lib/puppet/parser/files.rb +7 -6
- data/lib/puppet/parser/functions.rb +10 -8
- data/lib/puppet/parser/functions/collect.rb +43 -0
- data/lib/puppet/parser/functions/each.rb +96 -0
- data/lib/puppet/parser/functions/foreach.rb +96 -0
- data/lib/puppet/parser/functions/fqdn_rand.rb +2 -2
- data/lib/puppet/parser/functions/hiera.rb +20 -2
- data/lib/puppet/parser/functions/hiera_array.rb +21 -2
- data/lib/puppet/parser/functions/hiera_hash.rb +23 -2
- data/lib/puppet/parser/functions/hiera_include.rb +33 -2
- data/lib/puppet/parser/functions/inline_template.rb +4 -4
- data/lib/puppet/parser/functions/reduce.rb +74 -0
- data/lib/puppet/parser/functions/reject.rb +46 -0
- data/lib/puppet/parser/functions/select.rb +46 -0
- data/lib/puppet/parser/functions/slice.rb +96 -0
- data/lib/puppet/parser/functions/template.rb +2 -2
- data/lib/puppet/parser/grammar.ra +7 -4
- data/lib/puppet/parser/lexer.rb +10 -0
- data/lib/puppet/parser/methods.rb +69 -0
- data/lib/puppet/parser/parser.rb +855 -808
- data/lib/puppet/parser/parser_factory.rb +62 -0
- data/lib/puppet/parser/parser_support.rb +8 -2
- data/lib/puppet/parser/scope.rb +153 -47
- data/lib/puppet/parser/templatewrapper.rb +28 -21
- data/lib/puppet/parser/type_loader.rb +3 -1
- data/lib/puppet/pops.rb +40 -0
- data/lib/puppet/pops/adaptable.rb +190 -0
- data/lib/puppet/pops/adapters.rb +65 -0
- data/lib/puppet/pops/containment.rb +37 -0
- data/lib/puppet/pops/issues.rb +258 -0
- data/lib/puppet/pops/label_provider.rb +71 -0
- data/lib/puppet/pops/model/ast_transformer.rb +636 -0
- data/lib/puppet/pops/model/ast_tree_dumper.rb +378 -0
- data/lib/puppet/pops/model/factory.rb +804 -0
- data/lib/puppet/pops/model/model.rb +567 -0
- data/lib/puppet/pops/model/model_label_provider.rb +75 -0
- data/lib/puppet/pops/model/model_tree_dumper.rb +352 -0
- data/lib/puppet/pops/model/tree_dumper.rb +59 -0
- data/lib/puppet/pops/parser/egrammar.ra +723 -0
- data/lib/puppet/pops/parser/eparser.rb +2300 -0
- data/lib/puppet/pops/parser/grammar.ra +746 -0
- data/lib/puppet/pops/parser/lexer.rb +842 -0
- data/lib/puppet/pops/parser/makefile +13 -0
- data/lib/puppet/pops/parser/parser_support.rb +203 -0
- data/lib/puppet/pops/patterns.rb +35 -0
- data/lib/puppet/pops/utils.rb +104 -0
- data/lib/puppet/pops/validation.rb +297 -0
- data/lib/puppet/pops/validation/checker3_1.rb +551 -0
- data/lib/puppet/pops/validation/validator_factory_3_1.rb +41 -0
- data/lib/puppet/pops/visitable.rb +6 -0
- data/lib/puppet/pops/visitor.rb +50 -0
- data/lib/puppet/property.rb +37 -28
- data/lib/puppet/property/ensure.rb +2 -2
- data/lib/puppet/property/ordered_list.rb +1 -1
- data/lib/puppet/provider.rb +26 -30
- data/lib/puppet/provider/aixobject.rb +45 -44
- data/lib/puppet/provider/augeas/augeas.rb +0 -1
- data/lib/puppet/provider/confiner.rb +1 -1
- data/lib/puppet/provider/cron/crontab.rb +107 -67
- data/lib/puppet/provider/group/groupadd.rb +59 -3
- data/lib/puppet/provider/interface/cisco.rb +4 -4
- data/lib/puppet/provider/mount/parsed.rb +1 -1
- data/lib/puppet/provider/nameservice.rb +22 -6
- data/lib/puppet/provider/nameservice/pw.rb +1 -1
- data/lib/puppet/provider/package/aix.rb +28 -4
- data/lib/puppet/provider/package/gem.rb +0 -2
- data/lib/puppet/provider/package/macports.rb +1 -1
- data/lib/puppet/provider/package/nim.rb +249 -4
- data/lib/puppet/provider/package/opkg.rb +77 -0
- data/lib/puppet/provider/package/pacman.rb +2 -2
- data/lib/puppet/provider/package/rpm.rb +30 -16
- data/lib/puppet/provider/package/yum.rb +3 -3
- data/lib/puppet/provider/parsedfile.rb +80 -3
- data/lib/puppet/provider/selmodule/semodule.rb +2 -2
- data/lib/puppet/provider/service/debian.rb +0 -4
- data/lib/puppet/provider/service/freebsd.rb +2 -2
- data/lib/puppet/provider/service/gentoo.rb +0 -9
- data/lib/puppet/provider/service/init.rb +27 -2
- data/lib/puppet/provider/service/launchd.rb +1 -1
- data/lib/puppet/provider/service/openwrt.rb +36 -0
- data/lib/puppet/provider/service/redhat.rb +0 -9
- data/lib/puppet/provider/service/src.rb +38 -4
- data/lib/puppet/provider/service/systemd.rb +2 -2
- data/lib/puppet/provider/service/upstart.rb +1 -8
- data/lib/puppet/provider/user/aix.rb +4 -10
- data/lib/puppet/provider/user/pw.rb +6 -10
- data/lib/puppet/provider/user/useradd.rb +129 -31
- data/lib/puppet/provider/vlan/cisco.rb +4 -4
- data/lib/puppet/reference/function.rb +2 -2
- data/lib/puppet/reference/indirection.rb +46 -5
- data/lib/puppet/reference/metaparameter.rb +2 -2
- data/lib/puppet/reports.rb +5 -5
- data/lib/puppet/reports/rrdgraph.rb +4 -4
- data/lib/puppet/reports/tagmail.rb +1 -1
- data/lib/puppet/resource.rb +1 -1
- data/lib/puppet/resource/type.rb +13 -11
- data/lib/puppet/scheduler.rb +16 -0
- data/lib/puppet/scheduler/job.rb +53 -0
- data/lib/puppet/scheduler/scheduler.rb +45 -0
- data/lib/puppet/scheduler/splay_job.rb +32 -0
- data/lib/puppet/scheduler/timer.rb +13 -0
- data/lib/puppet/settings/base_setting.rb +1 -1
- data/lib/puppet/simple_graph.rb +4 -4
- data/lib/puppet/ssl/base.rb +12 -2
- data/lib/puppet/ssl/certificate.rb +4 -1
- data/lib/puppet/ssl/certificate_request.rb +4 -1
- data/lib/puppet/ssl/certificate_revocation_list.rb +4 -1
- data/lib/puppet/ssl/configuration.rb +32 -0
- data/lib/puppet/ssl/host.rb +18 -21
- data/lib/puppet/ssl/key.rb +4 -1
- data/lib/puppet/ssl/validator.rb +116 -0
- data/lib/puppet/transaction.rb +1 -1
- data/lib/puppet/transaction/event.rb +3 -10
- data/lib/puppet/transaction/event_manager.rb +8 -1
- data/lib/puppet/transaction/report.rb +17 -16
- data/lib/puppet/type.rb +77 -69
- data/lib/puppet/type/cron.rb +20 -8
- data/lib/puppet/type/exec.rb +9 -3
- data/lib/puppet/type/file.rb +95 -21
- data/lib/puppet/type/file/content.rb +1 -1
- data/lib/puppet/type/file/mode.rb +7 -1
- data/lib/puppet/type/file/source.rb +2 -2
- data/lib/puppet/type/group.rb +11 -0
- data/lib/puppet/type/scheduled_task.rb +5 -1
- data/lib/puppet/type/service.rb +1 -1
- data/lib/puppet/type/ssh_authorized_key.rb +2 -2
- data/lib/puppet/type/user.rb +24 -6
- data/lib/puppet/util.rb +12 -2
- data/lib/puppet/util/classgen.rb +4 -4
- data/lib/puppet/util/colors.rb +55 -0
- data/lib/puppet/util/command_line/trollop.rb +4 -4
- data/lib/puppet/util/errors.rb +39 -3
- data/lib/puppet/util/fileparsing.rb +5 -0
- data/lib/puppet/util/filetype.rb +11 -9
- data/lib/puppet/util/instrumentation/instrumentable.rb +2 -2
- data/lib/puppet/util/libuser.conf +15 -0
- data/lib/puppet/util/libuser.rb +12 -0
- data/lib/puppet/util/monkey_patches.rb +48 -0
- data/lib/puppet/util/network_device.rb +1 -1
- data/lib/puppet/util/network_device/base.rb +2 -2
- data/lib/puppet/util/network_device/cisco/device.rb +29 -19
- data/lib/puppet/util/network_device/config.rb +5 -2
- data/lib/puppet/util/network_device/ipcalc.rb +1 -1
- data/lib/puppet/util/network_device/transport/ssh.rb +4 -3
- data/lib/puppet/util/network_device/transport/telnet.rb +4 -2
- data/lib/puppet/util/plugins.rb +4 -4
- data/lib/puppet/util/posix.rb +1 -1
- data/lib/puppet/util/profiler.rb +28 -0
- data/lib/puppet/util/profiler/logging.rb +47 -0
- data/lib/puppet/util/profiler/none.rb +8 -0
- data/lib/puppet/util/profiler/object_counts.rb +17 -0
- data/lib/puppet/util/profiler/wall_clock.rb +34 -0
- data/lib/puppet/util/provider_features.rb +1 -1
- data/lib/puppet/util/rdoc/parser.rb +5 -5
- data/lib/puppet/util/ssl.rb +38 -0
- data/lib/puppet/util/subclass_loader.rb +1 -5
- data/lib/puppet/util/windows.rb +1 -0
- data/lib/puppet/util/windows/process.rb +3 -0
- data/lib/puppet/util/windows/root_certs.rb +86 -0
- data/lib/puppet/util/windows/security.rb +1 -0
- data/lib/puppet/version.rb +1 -1
- data/spec/fixtures/integration/provider/cron/crontab/create_normal_entry +19 -0
- data/spec/fixtures/integration/provider/cron/crontab/create_special_entry +18 -0
- data/spec/fixtures/integration/provider/cron/crontab/crontab_user1 +15 -0
- data/spec/fixtures/integration/provider/cron/crontab/crontab_user2 +4 -0
- data/spec/fixtures/integration/provider/cron/crontab/modify_entry +13 -0
- data/spec/fixtures/integration/provider/cron/crontab/moved_cronjob_input1 +15 -0
- data/spec/fixtures/integration/provider/cron/crontab/moved_cronjob_input2 +6 -0
- data/spec/fixtures/integration/provider/cron/crontab/remove_named_resource +12 -0
- data/spec/fixtures/integration/provider/cron/crontab/remove_unnamed_resource +14 -0
- data/spec/fixtures/unit/pops/parser/lexer/aliastest.pp +16 -0
- data/spec/fixtures/unit/pops/parser/lexer/append.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/argumentdefaults.pp +14 -0
- data/spec/fixtures/unit/pops/parser/lexer/arithmetic_expression.pp +8 -0
- data/spec/fixtures/unit/pops/parser/lexer/arraytrailingcomma.pp +3 -0
- data/spec/fixtures/unit/pops/parser/lexer/casestatement.pp +65 -0
- data/spec/fixtures/unit/pops/parser/lexer/classheirarchy.pp +15 -0
- data/spec/fixtures/unit/pops/parser/lexer/classincludes.pp +17 -0
- data/spec/fixtures/unit/pops/parser/lexer/classpathtest.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/collection.pp +10 -0
- data/spec/fixtures/unit/pops/parser/lexer/collection_override.pp +8 -0
- data/spec/fixtures/unit/pops/parser/lexer/collection_within_virtual_definitions.pp +20 -0
- data/spec/fixtures/unit/pops/parser/lexer/componentmetaparams.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/componentrequire.pp +8 -0
- data/spec/fixtures/unit/pops/parser/lexer/deepclassheirarchy.pp +23 -0
- data/spec/fixtures/unit/pops/parser/lexer/defineoverrides.pp +17 -0
- data/spec/fixtures/unit/pops/parser/lexer/emptyclass.pp +9 -0
- data/spec/fixtures/unit/pops/parser/lexer/emptyexec.pp +3 -0
- data/spec/fixtures/unit/pops/parser/lexer/emptyifelse.pp +9 -0
- data/spec/fixtures/unit/pops/parser/lexer/falsevalues.pp +3 -0
- data/spec/fixtures/unit/pops/parser/lexer/filecreate.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/fqdefinition.pp +5 -0
- data/spec/fixtures/unit/pops/parser/lexer/fqparents.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/funccomma.pp +5 -0
- data/spec/fixtures/unit/pops/parser/lexer/hash.pp +33 -0
- data/spec/fixtures/unit/pops/parser/lexer/ifexpression.pp +12 -0
- data/spec/fixtures/unit/pops/parser/lexer/implicititeration.pp +15 -0
- data/spec/fixtures/unit/pops/parser/lexer/multilinecomments.pp +10 -0
- data/spec/fixtures/unit/pops/parser/lexer/multipleclass.pp +9 -0
- data/spec/fixtures/unit/pops/parser/lexer/multipleinstances.pp +7 -0
- data/spec/fixtures/unit/pops/parser/lexer/multisubs.pp +13 -0
- data/spec/fixtures/unit/pops/parser/lexer/namevartest.pp +9 -0
- data/spec/fixtures/unit/pops/parser/lexer/scopetest.pp +13 -0
- data/spec/fixtures/unit/pops/parser/lexer/selectorvalues.pp +49 -0
- data/spec/fixtures/unit/pops/parser/lexer/simpledefaults.pp +5 -0
- data/spec/fixtures/unit/pops/parser/lexer/simpleselector.pp +38 -0
- data/spec/fixtures/unit/pops/parser/lexer/singleary.pp +19 -0
- data/spec/fixtures/unit/pops/parser/lexer/singlequote.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/singleselector.pp +22 -0
- data/spec/fixtures/unit/pops/parser/lexer/subclass_name_duplication.pp +11 -0
- data/spec/fixtures/unit/pops/parser/lexer/tag.pp +9 -0
- data/spec/fixtures/unit/pops/parser/lexer/tagged.pp +35 -0
- data/spec/fixtures/unit/pops/parser/lexer/virtualresources.pp +14 -0
- data/spec/fixtures/unit/provider/cron/crontab/single_line.yaml +4 -4
- data/spec/fixtures/unit/provider/cron/crontab/vixie_header.txt +3 -0
- data/spec/fixtures/unit/provider/cron/parsed/managed +6 -0
- data/spec/fixtures/unit/provider/cron/parsed/simple +9 -0
- data/spec/fixtures/unit/provider/parsedfile/simple.txt +4 -0
- data/spec/fixtures/unit/provider/service/systemd/list_units +18 -0
- data/spec/integration/parser/collector_spec.rb +1 -1
- data/spec/integration/parser/compiler_spec.rb +252 -227
- data/spec/integration/parser/parser_spec.rb +171 -53
- data/spec/integration/parser/scope_spec.rb +1 -1
- data/spec/integration/provider/cron/crontab_spec.rb +187 -0
- data/spec/integration/provider/service/systemd_spec.rb +20 -0
- data/spec/integration/type/file_spec.rb +21 -21
- data/spec/integration/type/package_spec.rb +1 -1
- data/spec/lib/puppet_spec/database.rb +2 -5
- data/spec/spec_helper.rb +6 -1
- data/spec/unit/application/apply_spec.rb +16 -1
- data/spec/unit/application/describe_spec.rb +1 -1
- data/spec/unit/application/doc_spec.rb +55 -32
- data/spec/unit/application/kick_spec.rb +8 -6
- data/spec/unit/application/master_spec.rb +4 -4
- data/spec/unit/daemon_spec.rb +1 -1
- data/spec/unit/forge/errors_spec.rb +40 -0
- data/spec/unit/forge/repository_spec.rb +11 -1
- data/spec/unit/forge_spec.rb +13 -3
- data/spec/unit/hiera/backend/puppet_backend_spec.rb +1 -0
- data/spec/unit/hiera/scope_spec.rb +48 -25
- data/spec/unit/indirector/catalog/active_record_spec.rb +6 -3
- data/spec/unit/indirector/catalog/compiler_spec.rb +3 -28
- data/spec/unit/indirector/catalog/static_compiler_spec.rb +1 -1
- data/spec/unit/indirector/facts/inventory_active_record_spec.rb +154 -150
- data/spec/unit/indirector/indirection_spec.rb +5 -0
- data/spec/unit/indirector/resource/active_record_spec.rb +5 -22
- data/spec/unit/indirector_spec.rb +7 -1
- data/spec/unit/interface/action_builder_spec.rb +1 -1
- data/spec/unit/interface/action_manager_spec.rb +0 -2
- data/spec/unit/interface/action_spec.rb +1 -1
- data/spec/unit/interface/documentation_spec.rb +0 -2
- data/spec/unit/interface/face_collection_spec.rb +1 -1
- data/spec/unit/interface/option_builder_spec.rb +1 -1
- data/spec/unit/interface/option_spec.rb +0 -1
- data/spec/unit/module_spec.rb +17 -19
- data/spec/unit/module_tool/application_spec.rb +1 -3
- data/spec/unit/module_tool/applications/builder_spec.rb +38 -0
- data/spec/unit/module_tool/applications/checksummer_spec.rb +134 -0
- data/spec/unit/module_tool/applications/installer_spec.rb +71 -91
- data/spec/unit/module_tool/applications/searcher_spec.rb +1 -3
- data/spec/unit/module_tool/applications/uninstaller_spec.rb +18 -26
- data/spec/unit/module_tool/applications/unpacker_spec.rb +19 -52
- data/spec/unit/module_tool/tar/gnu_spec.rb +19 -0
- data/spec/unit/module_tool/tar/mini_spec.rb +59 -0
- data/spec/unit/module_tool/tar/solaris_spec.rb +19 -0
- data/spec/unit/network/http/connection_spec.rb +17 -2
- data/spec/unit/network/http/handler_spec.rb +195 -167
- data/spec/unit/network/http/rack/rest_spec.rb +26 -4
- data/spec/unit/network/http/webrick/rest_spec.rb +28 -1
- data/spec/unit/network/http/webrick_spec.rb +12 -3
- data/spec/unit/node/environment_spec.rb +421 -404
- data/spec/unit/parser/ast/arithmetic_operator_spec.rb +98 -2
- data/spec/unit/parser/collector_spec.rb +4 -4
- data/spec/unit/parser/compiler_spec.rb +13 -13
- data/spec/unit/parser/eparser_adapter_spec.rb +407 -0
- data/spec/unit/parser/functions/extlookup_spec.rb +20 -17
- data/spec/unit/parser/functions/fqdn_rand_spec.rb +5 -0
- data/spec/unit/parser/functions/hiera_include_spec.rb +0 -2
- data/spec/unit/parser/functions/hiera_spec.rb +0 -2
- data/spec/unit/parser/functions_spec.rb +27 -15
- data/spec/unit/parser/methods/collect_spec.rb +110 -0
- data/spec/unit/parser/methods/each_spec.rb +91 -0
- data/spec/unit/parser/methods/foreach_spec.rb +91 -0
- data/spec/unit/parser/methods/reduce_spec.rb +67 -0
- data/spec/unit/parser/methods/reject_spec.rb +73 -0
- data/spec/unit/parser/methods/select_spec.rb +79 -0
- data/spec/unit/parser/methods/shared.rb +61 -0
- data/spec/unit/parser/methods/slice_spec.rb +97 -0
- data/spec/unit/parser/parser_spec.rb +2 -2
- data/spec/unit/parser/scope_spec.rb +39 -16
- data/spec/unit/parser/templatewrapper_spec.rb +6 -5
- data/spec/unit/parser/type_loader_spec.rb +191 -165
- data/spec/unit/pops/adaptable_spec.rb +143 -0
- data/spec/unit/pops/containment_spec.rb +25 -0
- data/spec/unit/pops/factory_rspec_helper.rb +77 -0
- data/spec/unit/pops/factory_spec.rb +329 -0
- data/spec/unit/pops/issues_spec.rb +26 -0
- data/spec/unit/pops/label_provider_spec.rb +42 -0
- data/spec/unit/pops/model/ast_transformer_spec.rb +65 -0
- data/spec/unit/pops/model/model_spec.rb +37 -0
- data/spec/unit/pops/parser/lexer_spec.rb +884 -0
- data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +248 -0
- data/spec/unit/pops/parser/parse_calls_spec.rb +93 -0
- data/spec/unit/pops/parser/parse_conditionals_spec.rb +159 -0
- data/spec/unit/pops/parser/parse_containers_spec.rb +175 -0
- data/spec/unit/pops/parser/parse_resource_spec.rb +228 -0
- data/spec/unit/pops/parser/parser_rspec_helper.rb +11 -0
- data/spec/unit/pops/parser/parser_spec.rb +15 -0
- data/spec/unit/pops/parser/rgen_sanitycheck_spec.rb +16 -0
- data/spec/unit/pops/transformer/transform_basic_expressions_spec.rb +243 -0
- data/spec/unit/pops/transformer/transform_calls_spec.rb +80 -0
- data/spec/unit/pops/transformer/transform_conditionals_spec.rb +132 -0
- data/spec/unit/pops/transformer/transform_containers_spec.rb +182 -0
- data/spec/unit/pops/transformer/transform_resource_spec.rb +185 -0
- data/spec/unit/pops/transformer/transformer_rspec_helper.rb +27 -0
- data/spec/unit/pops/visitor_spec.rb +94 -0
- data/spec/unit/property_spec.rb +11 -0
- data/spec/unit/provider/augeas/augeas_spec.rb +3 -0
- data/spec/unit/provider/cron/crontab_spec.rb +97 -7
- data/spec/unit/provider/cron/parsed_spec.rb +325 -0
- data/spec/unit/provider/exec/posix_spec.rb +1 -1
- data/spec/unit/provider/group/groupadd_spec.rb +33 -3
- data/spec/unit/provider/group/pw_spec.rb +5 -5
- data/spec/unit/provider/nameservice_spec.rb +304 -0
- data/spec/unit/provider/package/aix_spec.rb +53 -11
- data/spec/unit/provider/package/aptrpm_spec.rb +6 -0
- data/spec/unit/provider/package/gem_spec.rb +6 -11
- data/spec/unit/provider/package/nim_spec.rb +216 -7
- data/spec/unit/provider/package/opkg_spec.rb +180 -0
- data/spec/unit/provider/package/rpm_spec.rb +149 -3
- data/spec/unit/provider/package/yum_spec.rb +6 -5
- data/spec/unit/provider/parsedfile_spec.rb +122 -28
- data/spec/unit/provider/service/freebsd_spec.rb +18 -0
- data/spec/unit/provider/service/init_spec.rb +108 -87
- data/spec/unit/provider/service/launchd_spec.rb +2 -2
- data/spec/unit/provider/service/openwrt_spec.rb +109 -0
- data/spec/unit/provider/service/src_spec.rb +117 -41
- data/spec/unit/provider/service/systemd_spec.rb +125 -17
- data/spec/unit/provider/service/upstart_spec.rb +1 -1
- data/spec/unit/provider/user/aix_spec.rb +42 -0
- data/spec/unit/provider/user/directoryservice_spec.rb +1 -0
- data/spec/unit/provider/user/pw_spec.rb +24 -12
- data/spec/unit/provider/user/user_role_add_spec.rb +1 -1
- data/spec/unit/provider/user/useradd_spec.rb +179 -15
- data/spec/unit/resource/type_spec.rb +3 -3
- data/spec/unit/scheduler/job_spec.rb +79 -0
- data/spec/unit/scheduler/scheduler_spec.rb +129 -0
- data/spec/unit/scheduler/splay_job_spec.rb +35 -0
- data/spec/unit/ssl/base_spec.rb +3 -9
- data/spec/unit/ssl/certificate_authority_spec.rb +1 -0
- data/spec/unit/ssl/certificate_request_spec.rb +3 -1
- data/spec/unit/ssl/certificate_spec.rb +3 -1
- data/spec/unit/ssl/configuration_spec.rb +74 -0
- data/spec/unit/ssl/host_spec.rb +28 -7
- data/spec/unit/ssl/validator_spec.rb +311 -0
- data/spec/unit/transaction/event_manager_spec.rb +49 -0
- data/spec/unit/transaction/event_spec.rb +20 -5
- data/spec/unit/transaction/report_spec.rb +8 -0
- data/spec/unit/type/cron_spec.rb +9 -0
- data/spec/unit/type/exec_spec.rb +11 -0
- data/spec/unit/type/file/content_spec.rb +20 -20
- data/spec/unit/type/file/mode_spec.rb +6 -0
- data/spec/unit/type/file/source_spec.rb +9 -7
- data/spec/unit/type/file_spec.rb +22 -3
- data/spec/unit/type/service_spec.rb +34 -21
- data/spec/unit/type_spec.rb +46 -1
- data/spec/unit/util/backups_spec.rb +2 -2
- data/spec/unit/util/execution_spec.rb +4 -1
- data/spec/unit/util/filetype_spec.rb +6 -0
- data/spec/unit/util/monkey_patches_spec.rb +18 -0
- data/spec/unit/util/network_device/cisco/device_spec.rb +37 -0
- data/spec/unit/util/network_device/config_spec.rb +14 -0
- data/spec/unit/util/network_device_spec.rb +3 -3
- data/spec/unit/util/profiler/logging_spec.rb +81 -0
- data/spec/unit/util/profiler/none_spec.rb +12 -0
- data/spec/unit/util/profiler/object_counts_spec.rb +14 -0
- data/spec/unit/util/profiler/wall_clock_spec.rb +13 -0
- data/spec/unit/util/pson_spec.rb +5 -0
- data/spec/unit/util/ssl_spec.rb +51 -0
- data/spec/unit/util/windows/root_certs_spec.rb +15 -0
- data/spec/unit/util_spec.rb +28 -0
- metadata +2593 -2307
- 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
|