puppet 3.7.4 → 3.7.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +11 -6
  3. data/ext/build_defaults.yaml +2 -2
  4. data/ext/systemd/puppet.service +1 -0
  5. data/lib/hiera/puppet_function.rb +71 -0
  6. data/lib/puppet.rb +12 -0
  7. data/lib/puppet/application/device.rb +22 -5
  8. data/lib/puppet/daemon.rb +13 -4
  9. data/lib/puppet/defaults.rb +27 -4
  10. data/lib/puppet/environments.rb +1 -1
  11. data/lib/puppet/error.rb +4 -0
  12. data/lib/puppet/functions.rb +118 -65
  13. data/lib/puppet/functions/assert_type.rb +5 -5
  14. data/lib/puppet/functions/each.rb +12 -12
  15. data/lib/puppet/functions/epp.rb +3 -4
  16. data/lib/puppet/functions/filter.rb +12 -12
  17. data/lib/puppet/functions/hiera.rb +29 -0
  18. data/lib/puppet/functions/hiera_array.rb +34 -0
  19. data/lib/puppet/functions/hiera_hash.rb +36 -0
  20. data/lib/puppet/functions/hiera_include.rb +50 -0
  21. data/lib/puppet/functions/inline_epp.rb +2 -3
  22. data/lib/puppet/functions/map.rb +12 -12
  23. data/lib/puppet/functions/reduce.rb +6 -6
  24. data/lib/puppet/functions/scanf.rb +3 -3
  25. data/lib/puppet/functions/slice.rb +10 -9
  26. data/lib/puppet/functions/with.rb +3 -4
  27. data/lib/puppet/graph/simple_graph.rb +5 -5
  28. data/lib/puppet/metatype/manager.rb +1 -1
  29. data/lib/puppet/node/environment.rb +1 -1
  30. data/lib/puppet/parser/ast/arithmetic_operator.rb +1 -1
  31. data/lib/puppet/parser/ast/collexpr.rb +1 -1
  32. data/lib/puppet/parser/compiler.rb +3 -3
  33. data/lib/puppet/parser/functions/create_resources.rb +1 -9
  34. data/lib/puppet/parser/functions/defined.rb +1 -1
  35. data/lib/puppet/parser/functions/hiera.rb +20 -11
  36. data/lib/puppet/parser/functions/hiera_array.rb +23 -13
  37. data/lib/puppet/parser/functions/hiera_hash.rb +25 -15
  38. data/lib/puppet/parser/functions/hiera_include.rb +20 -9
  39. data/lib/puppet/parser/functions/lookup.rb +1 -1
  40. data/lib/puppet/parser/functions/realize.rb +1 -1
  41. data/lib/puppet/parser/functions/scanf.rb +21 -12
  42. data/lib/puppet/parser/parser_factory.rb +2 -2
  43. data/lib/puppet/parser/relationship.rb +1 -1
  44. data/lib/puppet/parser/scope.rb +34 -7
  45. data/lib/puppet/pops.rb +2 -0
  46. data/lib/puppet/pops/binder/lookup.rb +24 -7
  47. data/lib/puppet/pops/binder/producers.rb +2 -2
  48. data/lib/puppet/pops/evaluator/closure.rb +1 -1
  49. data/lib/puppet/pops/evaluator/evaluator_impl.rb +109 -17
  50. data/lib/puppet/pops/evaluator/puppet_proc.rb +69 -0
  51. data/lib/puppet/pops/evaluator/runtime3_converter.rb +175 -0
  52. data/lib/puppet/pops/evaluator/runtime3_support.rb +15 -128
  53. data/lib/puppet/pops/functions/dispatch.rb +21 -17
  54. data/lib/puppet/pops/functions/dispatcher.rb +3 -3
  55. data/lib/puppet/pops/functions/function.rb +46 -14
  56. data/lib/puppet/pops/issues.rb +2 -2
  57. data/lib/puppet/pops/model/model_label_provider.rb +1 -1
  58. data/lib/puppet/pops/parser/egrammar.ra +2 -0
  59. data/lib/puppet/pops/parser/eparser.rb +732 -724
  60. data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
  61. data/lib/puppet/pops/parser/lexer2.rb +20 -22
  62. data/lib/puppet/pops/types/class_loader.rb +1 -1
  63. data/lib/puppet/pops/types/type_calculator.rb +104 -37
  64. data/lib/puppet/pops/types/type_factory.rb +1 -1
  65. data/lib/puppet/pops/types/types.rb +4 -1
  66. data/lib/puppet/pops/types/types_meta.rb +2 -2
  67. data/lib/puppet/pops/validation/checker4_0.rb +5 -3
  68. data/lib/puppet/provider/service/systemd.rb +1 -0
  69. data/lib/puppet/provider/yumrepo/inifile.rb +4 -1
  70. data/lib/puppet/resource.rb +3 -2
  71. data/lib/puppet/resource/catalog.rb +3 -2
  72. data/lib/puppet/resource/type.rb +1 -1
  73. data/lib/puppet/settings/environment_conf.rb +12 -4
  74. data/lib/puppet/type/package.rb +23 -13
  75. data/lib/puppet/util/autoload.rb +7 -7
  76. data/lib/puppet/util/errors.rb +4 -2
  77. data/lib/puppet/util/network_device/config.rb +5 -0
  78. data/lib/puppet/version.rb +1 -1
  79. data/lib/puppetx.rb +2 -2
  80. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee.rb +8 -0
  81. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee_ws.rb +8 -0
  82. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/metadata.json +9 -0
  83. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller.rb +5 -0
  84. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller_ws.rb +12 -0
  85. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/metadata.json +9 -0
  86. data/spec/integration/parser/environment_spec.rb +47 -0
  87. data/spec/integration/parser/future_compiler_spec.rb +11 -6
  88. data/spec/unit/application/device_spec.rb +52 -14
  89. data/spec/unit/daemon_spec.rb +0 -2
  90. data/spec/unit/environments_spec.rb +2 -2
  91. data/spec/unit/functions/assert_type_spec.rb +4 -25
  92. data/spec/unit/functions/hiera_spec.rb +127 -0
  93. data/spec/unit/functions/with_spec.rb +9 -4
  94. data/spec/unit/functions4_spec.rb +98 -35
  95. data/spec/unit/hiera/backend/puppet_backend_spec.rb +1 -1
  96. data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
  97. data/spec/unit/parser/functions/defined_spec.rb +5 -0
  98. data/spec/unit/parser/functions/lookup_spec.rb +5 -1
  99. data/spec/unit/parser/functions/scanf_spec.rb +30 -0
  100. data/spec/unit/parser/scope_spec.rb +5 -0
  101. data/spec/unit/pops/binder/injector_spec.rb +1 -1
  102. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +33 -5
  103. data/spec/unit/pops/loaders/loaders_spec.rb +22 -1
  104. data/spec/unit/pops/parser/lexer2_spec.rb +28 -16
  105. data/spec/unit/pops/parser/parse_heredoc_spec.rb +21 -0
  106. data/spec/unit/pops/types/type_calculator_spec.rb +141 -19
  107. data/spec/unit/pops/types/type_factory_spec.rb +2 -2
  108. data/spec/unit/pops/validator/validator_spec.rb +25 -3
  109. data/spec/unit/provider/service/systemd_spec.rb +20 -4
  110. data/spec/unit/provider/user/hpux_spec.rb +1 -1
  111. data/spec/unit/provider/yumrepo/inifile_spec.rb +1 -0
  112. data/spec/unit/settings/environment_conf_spec.rb +12 -1
  113. data/spec/unit/type/package_spec.rb +0 -20
  114. data/spec/unit/util/network_device/config_spec.rb +6 -0
  115. metadata +3422 -3405
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f35aa37f286ceab033a202d14fbf844afec75f18
4
+ data.tar.gz: 5430d6624f88720053d913dbb1d5cc0b4c2622f5
5
+ SHA512:
6
+ metadata.gz: 6ed0a9019235a4f7766cf5be591386846daaf8829cb3082f50689c9a99cdc47add53d72cfe5730dffe882c670d636c8289c95f589bc7a51fd9fef70b1d210c5b
7
+ data.tar.gz: 6944a721ef0d81d257b08fb42ed7d1f9fc50949afc99e5308d1f32bdd0240415fc13846fa1bb6024dba254bd22734b0b5d8c8320a5030166ccd2709ef5f632f5
@@ -53,7 +53,7 @@ top of things.
53
53
  For changes of a trivial nature to comments and documentation, it is not
54
54
  always necessary to create a new ticket in Jira. In this case, it is
55
55
  appropriate to start the first line of a commit with '(doc)' instead of
56
- a ticket number.
56
+ a ticket number.
57
57
 
58
58
  ````
59
59
  (doc) Add documentation commit example to CONTRIBUTING
@@ -63,7 +63,7 @@ a ticket number.
63
63
  is left to assume how a commit of this nature may appear.
64
64
 
65
65
  The first line is a real life imperative statement with '(doc)' in
66
- place of what would have been the ticket number in a
66
+ place of what would have been the ticket number in a
67
67
  non-documentation related commit. The body describes the nature of
68
68
  the new documentation or comments added.
69
69
  ````
@@ -77,15 +77,20 @@ a ticket number.
77
77
  * Include a link to the pull request in the ticket.
78
78
  * The core team looks at Pull Requests on a regular basis in a weekly triage
79
79
  meeting that we hold in a public Google Hangout. The hangout is announced in
80
- the weekly status updates that are sent to the puppet-dev list.
80
+ the weekly status updates that are sent to the puppet-dev list. Notes are
81
+ posted to the [Puppet Community community-triage
82
+ repo](https://github.com/puppet-community/community-triage/tree/master/core/notes)
83
+ and include a link to a YouTube recording of the hangout.
81
84
  * After feedback has been given we expect responses within two weeks. After two
82
- weeks will may close the pull request if it isn't showing any activity.
85
+ weeks we may close the pull request if it isn't showing any activity.
83
86
 
84
87
  # Additional Resources
85
88
 
86
- * [More information on contributing](http://links.puppetlabs.com/contribute-to-puppet)
89
+ * [Puppet Labs community guildelines](http://docs.puppetlabs.com/community/community_guidelines.html)
87
90
  * [Bug tracker (Jira)](http://tickets.puppetlabs.com)
88
91
  * [Contributor License Agreement](http://links.puppetlabs.com/cla)
89
92
  * [General GitHub documentation](http://help.github.com/)
90
93
  * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
91
- * #puppet-dev IRC channel on freenode.org
94
+ * #puppet-dev IRC channel on freenode.org ([Archive](https://botbot.me/freenode/puppet-dev/))
95
+ * [puppet-dev mailing list](https://groups.google.com/forum/#!forum/puppet-dev)
96
+ * [Community PR Triage notes](https://github.com/puppet-community/community-triage/tree/master/core/notes)
@@ -26,8 +26,8 @@ build_msi:
26
26
  repo: 'git://github.com/puppetlabs/hiera.git'
27
27
  sys:
28
28
  ref:
29
- x86: '57068e7b7c87288c51ff39d96c80cfb509a42091'
30
- x64: '531319f5c121e98990772e018eb9781bf7dc6316'
29
+ x86: '8db9d84da9950760144b5dfcd807213eecee4842'
30
+ x64: '12030f11e9bb2f085c68108bff34be6956b25df9'
31
31
  repo: 'git://github.com/puppetlabs/puppet-win32-ruby.git'
32
32
  apt_host: 'apt.puppetlabs.com'
33
33
  apt_repo_url: 'http://apt.puppetlabs.com'
@@ -7,6 +7,7 @@ After=basic.target network.target puppetmaster.service
7
7
  EnvironmentFile=-/etc/sysconfig/puppetagent
8
8
  EnvironmentFile=-/etc/sysconfig/puppet
9
9
  ExecStart=/usr/bin/puppet agent ${PUPPET_EXTRA_OPTS} --no-daemonize
10
+ KillMode=process
10
11
 
11
12
  [Install]
12
13
  WantedBy=multi-user.target
@@ -0,0 +1,71 @@
1
+ require 'hiera_puppet'
2
+
3
+ # Provides the base class for the puppet functions hiera, hiera_array, hiera_hash, and hiera_include.
4
+ # The actual function definitions will call init_dispatch and override the merge_type and post_lookup methods.
5
+ #
6
+ # @see hiera_array.rb, hiera_include.rb under lib/puppet/functions for sample usage
7
+ #
8
+ class Hiera::PuppetFunction < Puppet::Functions::InternalFunction
9
+ def self.init_dispatch
10
+ dispatch :hiera_splat do
11
+ scope_param
12
+ param 'Tuple[String, Any, Any, 1, 3]', :args
13
+ end
14
+
15
+ dispatch :hiera do
16
+ scope_param
17
+ param 'String',:key
18
+ optional_param 'Any', :default
19
+ optional_param 'Any', :override
20
+ end
21
+
22
+ dispatch :hiera_block1 do
23
+ scope_param
24
+ param 'String', :key
25
+ block_param 'Callable[1,1]', :default_block
26
+ end
27
+
28
+ dispatch :hiera_block2 do
29
+ scope_param
30
+ param 'String', :key
31
+ param 'Any', :override
32
+ block_param 'Callable[1,1]', :default_block
33
+ end
34
+ end
35
+
36
+ def hiera_splat(scope, args)
37
+ hiera(scope, *args)
38
+ end
39
+
40
+ def hiera(scope, key, default = nil, override = nil)
41
+ post_lookup(key, lookup(scope, key, default, override))
42
+ end
43
+
44
+ def hiera_block1(scope, key, &default_block)
45
+ common(scope, key, nil, default_block)
46
+ end
47
+
48
+ def hiera_block2(scope, key, override, &default_block)
49
+ common(scope, key, override, default_block)
50
+ end
51
+
52
+ def common(scope, key, override, default_block)
53
+ undefined = (@@undefined_value ||= Object.new)
54
+ result = lookup(scope, key, undefined, override)
55
+ post_lookup(key, result.equal?(undefined) ? default_block.call(key) : result)
56
+ end
57
+
58
+ private :common
59
+
60
+ def lookup(scope, key, default, override)
61
+ HieraPuppet.lookup(key, default,scope, override, merge_type)
62
+ end
63
+
64
+ def merge_type
65
+ :priority
66
+ end
67
+
68
+ def post_lookup(key, result)
69
+ result
70
+ end
71
+ end
@@ -258,6 +258,18 @@ module Puppet
258
258
 
259
259
  # The single instance used for normal operation
260
260
  @context = Puppet::Context.new(bootstrap_context)
261
+
262
+ def self.future_parser?
263
+ env = Puppet.lookup(:current_environment) { return Puppet[:parser] == 'future' }
264
+ env_conf = Puppet.lookup(:environments).get_conf(env.name)
265
+
266
+ if env_conf.nil?
267
+ # Case for non-directory environments
268
+ Puppet[:parser] == 'future'
269
+ else
270
+ env_conf.parser == 'future'
271
+ end
272
+ end
261
273
  end
262
274
 
263
275
  # This feels weird to me; I would really like for us to get to a state where there is never a "require" statement
@@ -115,9 +115,10 @@ parameter, so you can specify '--server <servername>' as an argument.
115
115
 
116
116
  * --detailed-exitcodes:
117
117
  Provide transaction information via exit codes. If this is enabled, an exit
118
- code of '2' means there were changes, an exit code of '4' means there were
119
- failures during the transaction, and an exit code of '6' means there were both
120
- changes and failures.
118
+ code of '1' means at least one device had a compile failure, an exit code of
119
+ '2' means at least one device had resource changes, and an exit code of '4'
120
+ means at least one device had resource failures. Exit codes of '3', '5', '6',
121
+ or '7' means that a bitwise combination of the preceeding exit codes happened.
121
122
 
122
123
  * --help:
123
124
  Print this help message
@@ -167,9 +168,13 @@ Licensed under the Apache 2.0 License
167
168
  Puppet.err "No device found in #{Puppet[:deviceconfig]}"
168
169
  exit(1)
169
170
  end
170
- devices.each_value do |device|
171
+ returns = devices.collect do |devicename,device|
171
172
  begin
172
- Puppet.info "starting applying configuration to #{device.name} at #{device.url}"
173
+ device_url = URI.parse(device.url)
174
+ # Handle nil scheme & port
175
+ scheme = "#{device_url.scheme}://" if device_url.scheme
176
+ port = ":#{device_url.port}" if device_url.port
177
+ Puppet.info "starting applying configuration to #{device.name} at #{scheme}#{device_url.host}#{port}#{device_url.path}"
173
178
 
174
179
  # override local $vardir and $certname
175
180
  Puppet[:confdir] = ::File.join(Puppet[:devicedir], device.name)
@@ -192,6 +197,8 @@ Licensed under the Apache 2.0 License
192
197
  configurer.run(:network_device => true, :pluginsync => Puppet[:pluginsync])
193
198
  rescue => detail
194
199
  Puppet.log_exception(detail)
200
+ # If we rescued an error, then we return 1 as the exit code
201
+ 1
195
202
  ensure
196
203
  Puppet[:vardir] = vardir
197
204
  Puppet[:confdir] = confdir
@@ -199,6 +206,16 @@ Licensed under the Apache 2.0 License
199
206
  Puppet::SSL::Host.reset
200
207
  end
201
208
  end
209
+ if ! returns or returns.compact.empty?
210
+ exit(1)
211
+ elsif options[:detailed_exitcodes]
212
+ # Bitwise OR the return codes together, puppet style
213
+ exit(returns.compact.reduce(:|))
214
+ elsif returns.include? 1
215
+ exit(1)
216
+ else
217
+ exit(0)
218
+ end
202
219
  end
203
220
 
204
221
  def setup_host
@@ -21,11 +21,14 @@ require 'puppet/scheduler'
21
21
  #
22
22
  # @api private
23
23
  class Puppet::Daemon
24
+ SIGNAL_CHECK_INTERVAL = 5
25
+
24
26
  attr_accessor :agent, :server, :argv
25
27
 
26
28
  def initialize(pidfile, scheduler = Puppet::Scheduler::Scheduler.new())
27
29
  @scheduler = scheduler
28
30
  @pidfile = pidfile
31
+ @signals = []
29
32
  end
30
33
 
31
34
  def daemonname
@@ -109,8 +112,8 @@ class Puppet::Daemon
109
112
  signals.update({:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs }) unless Puppet.features.microsoft_windows?
110
113
  signals.each do |signal, method|
111
114
  Signal.trap(signal) do
112
- Puppet.notice "Caught #{signal}; calling #{method}"
113
- send(method)
115
+ Puppet.notice "Caught #{signal}; storing #{method}"
116
+ @signals << method
114
117
  end
115
118
  end
116
119
  end
@@ -173,10 +176,16 @@ class Puppet::Daemon
173
176
  end
174
177
  end
175
178
 
179
+ signal_loop = Puppet::Scheduler.create_job(SIGNAL_CHECK_INTERVAL) do
180
+ while method = @signals.shift
181
+ Puppet.notice "Processing #{method}"
182
+ send(method)
183
+ end
184
+ end
185
+
176
186
  reparse_run.disable if Puppet[:filetimeout] == 0
177
187
  agent_run.disable unless agent
178
188
 
179
- @scheduler.run_loop([reparse_run, agent_run])
189
+ @scheduler.run_loop([reparse_run, agent_run, signal_loop])
180
190
  end
181
191
  end
182
-
@@ -452,12 +452,35 @@ module Puppet
452
452
  a file (such as manifests or templates) has changed on disk. #{AS_DURATION}",
453
453
  },
454
454
  :environment_timeout => {
455
- :default => "3m",
455
+ :default => "0",
456
456
  :type => :ttl,
457
- :desc => "The time to live for a cached environment.
457
+ :desc => "How long the Puppet master should cache data it loads from an
458
+ environment.
458
459
  #{AS_DURATION}
459
- This setting can also be set to `unlimited`, which causes the environment to
460
- be cached until the master is restarted."
460
+ A value of `0` will disable caching. This setting can also be set to
461
+ `unlimited`, which will cache environments until the master is restarted
462
+ or told to refresh the cache.
463
+
464
+ You should change this setting once your Puppet deployment is doing
465
+ non-trivial work. We chose the default value of `0` because it lets new
466
+ users update their code without any extra steps, but it lowers the
467
+ performance of your Puppet master.
468
+
469
+ We recommend setting this to `unlimited` and explicitly refreshing your
470
+ Puppet master as part of your code deployment process.
471
+
472
+ * With Puppet Server, you should refresh environments by calling the
473
+ `environment-cache` API endpoint. See the docs for the Puppet Server
474
+ administrative API.
475
+ * With a Rack Puppet master, you should restart the web server or the
476
+ application server. Passenger lets you touch a `restart.txt` file to
477
+ refresh an application without restarting Apache; see the Passenger docs
478
+ for details.
479
+
480
+ We don't recommend using any value other than `0` or `unlimited`, since
481
+ most Puppet masters use a pool of Ruby interpreters which all have their
482
+ own cache timers. When these timers drift out of sync, agents can be served
483
+ inconsistent catalogs."
461
484
  },
462
485
  :queue_type => {
463
486
  :default => "stomp",
@@ -107,7 +107,7 @@ module Puppet::Environments
107
107
  def get_conf(name)
108
108
  env = get(name)
109
109
  if env
110
- Puppet::Settings::EnvironmentConf.static_for(env)
110
+ Puppet::Settings::EnvironmentConf.static_for(env, Puppet[:parser])
111
111
  else
112
112
  nil
113
113
  end
@@ -54,6 +54,10 @@ module Puppet
54
54
  include ExternalFileError
55
55
  end
56
56
 
57
+ # An error that already contains location information in the message text
58
+ class PreformattedError < Puppet::ParseError
59
+ end
60
+
57
61
  # An error class for when I don't know what happened. Automatically
58
62
  # prints a stack trace when in debug mode.
59
63
  class DevError < Puppet::Error
@@ -57,13 +57,13 @@
57
57
  # @example Dispatching to different methods by type
58
58
  # Puppet::Functions.create_function('math::min') do
59
59
  # dispatch :numeric_min do
60
- # param 'Numeric', 'a'
61
- # param 'Numeric', 'b'
60
+ # param 'Numeric', :a
61
+ # param 'Numeric', :b
62
62
  # end
63
63
  #
64
64
  # dispatch :string_min do
65
- # param 'String', 'a'
66
- # param 'String', 'b'
65
+ # param 'String', :a
66
+ # param 'String', :b
67
67
  # end
68
68
  #
69
69
  # def numeric_min(a, b)
@@ -82,25 +82,33 @@
82
82
  # be the same as the number of parameters, and all of the parameters are of
83
83
  # type 'Any'.
84
84
  #
85
- # To express that the last parameter captures the rest, the method
86
- # `last_captures_rest` can be called. This indicates that the last parameter is
87
- # a varargs parameter and will be passed to the implementing method as an array
88
- # of the given type.
85
+ # The following methods can be used to define a parameter
89
86
  #
90
- # When defining a dispatch for a function, the resulting dispatch matches
91
- # against the specified argument types and min/max occurrence of optional
92
- # entries. When the dispatch makes the call to the implementation method the
93
- # arguments are simply passed and it is the responsibility of the method's
94
- # implementor to ensure it can handle those arguments (i.e. there is no check
95
- # that what was declared as optional actually has a default value, and that
96
- # a "captures rest" is declared using a `*`).
87
+ # - _param_ - the argument must be given in the call.
88
+ # - _optional_param_ - the argument may be missing in the call. May not be followed by a required parameter
89
+ # - _repeated_param_ - the type specifies a repeating type that occurs 0 to "infinite" number of times. It may only appear last or just before a block parameter.
90
+ # - _block_param_ - a block must be given in the call. May only appear last.
91
+ # - _optional_block_param_ - a block may be given in the call. May only appear last.
97
92
  #
98
- # @example Varargs
93
+ # The method name _required_param_ is an alias for _param_ and _required_block_param_ is an alias for _block_param_
94
+ #
95
+ # A parameter definition takes 2 arguments:
96
+ # - _type_ A string that must conform to a type in the puppet language
97
+ # - _name_ A symbol denoting the parameter name
98
+ #
99
+ # Both arguments are optional when defining a block parameter. The _type_ defaults to "Callable"
100
+ # and the _name_ to :block.
101
+ #
102
+ # Note that the dispatch definition is used to match arguments given in a call to the function with the defined
103
+ # parameters. It then dispatches the call to the implementation method simply passing the given arguments on to
104
+ # that method without any further processing and it is the responsibility of that method's implementor to ensure
105
+ # that it can handle those arguments.
106
+ #
107
+ # @example Variable number of arguments
99
108
  # Puppet::Functions.create_function('foo') do
100
109
  # dispatch :foo do
101
- # param 'Numeric', 'first'
102
- # param 'Numeric', 'values'
103
- # last_captures_rest
110
+ # param 'Numeric', :first
111
+ # repeated_param 'Numeric', :values
104
112
  # end
105
113
  #
106
114
  # def foo(first, *values)
@@ -108,6 +116,23 @@
108
116
  # end
109
117
  # end
110
118
  #
119
+ # There is no requirement for direct mapping between parameter definitions and the parameters in the
120
+ # receiving implementation method so the following example is also legal. Here the dispatch will ensure
121
+ # that `*values` in the receiver will be an array with at least one entry of type String and that any
122
+ # remaining entries are of type Numeric:
123
+ #
124
+ # @example Inexact mapping or parameters
125
+ # Puppet::Functions.create_function('foo') do
126
+ # dispatch :foo do
127
+ # param 'String', :first
128
+ # repeated_param 'Numeric', :values
129
+ # end
130
+ #
131
+ # def foo(*values)
132
+ # # do something
133
+ # end
134
+ # end
135
+ #
111
136
  # Access to Scope
112
137
  # ---
113
138
  # In general, functions should not need access to scope; they should be
@@ -260,24 +285,51 @@ module Puppet::Functions
260
285
  @dispatcher = dispatcher
261
286
  end
262
287
 
263
- # Defines a positional parameter with type and name
288
+ # Defines a required positional parameter with _type_ and _name_.
264
289
  #
265
290
  # @param type [String] The type specification for the parameter.
266
- # @param name [String] The name of the parameter. This is primarily used
267
- # for error message output and does not have to match the name of the
268
- # parameter on the implementation method.
291
+ # @param name [Symbol] The name of the parameter. This is primarily used
292
+ # for error message output and does not have to match an implementation
293
+ # method parameter.
269
294
  # @return [Void]
270
295
  #
271
296
  # @api public
272
297
  def param(type, name)
273
- if type.is_a?(String)
274
- @types << type
275
- @names << name
276
- # mark what should be picked for this position when dispatching
277
- @weaving << @names.size()-1
278
- else
279
- raise ArgumentError, "Type signature argument must be a String reference to a Puppet Data Type. Got #{type.class}"
280
- end
298
+ internal_param(type, name)
299
+ raise ArgumentError, 'A required parameter cannot be added after an optional parameter' if @min != @max
300
+ @min += 1
301
+ @max += 1
302
+ end
303
+ alias required_param param
304
+
305
+ # Defines an optional positional parameter with _type_ and _name_.
306
+ # May not be followed by a required parameter.
307
+ #
308
+ # @param type [String] The type specification for the parameter.
309
+ # @param name [Symbol] The name of the parameter. This is primarily used
310
+ # for error message output and does not have to match an implementation
311
+ # method parameter.
312
+ # @return [Void]
313
+ #
314
+ # @api public
315
+ def optional_param(type, name)
316
+ internal_param(type, name)
317
+ @max += 1
318
+ end
319
+
320
+ # Defines a repeated positional parameter with _type_ and _name_ that may occur 0 to "infinite" number of times.
321
+ # It may only appear last or just before a block parameter.
322
+ #
323
+ # @param type [String] The type specification for the parameter.
324
+ # @param name [Symbol] The name of the parameter. This is primarily used
325
+ # for error message output and does not have to match an implementation
326
+ # method parameter.
327
+ # @return [Void]
328
+ #
329
+ # @api public
330
+ def repeated_param(type, name)
331
+ internal_param(type, name)
332
+ @max = :default
281
333
  end
282
334
 
283
335
  # Defines one required block parameter that may appear last. If type and name is missing the
@@ -285,7 +337,7 @@ module Puppet::Functions
285
337
  # parameter is given, then that is the name and the type is "Callable".
286
338
  #
287
339
  # @api public
288
- def required_block_param(*type_and_name)
340
+ def block_param(*type_and_name)
289
341
  case type_and_name.size
290
342
  when 0
291
343
  # the type must be an independent instance since it will be contained in another type
@@ -314,9 +366,10 @@ module Puppet::Functions
314
366
  @block_type = type
315
367
  @block_name = name
316
368
  else
317
- raise ArgumentError, "Attempt to redefine block"
369
+ raise ArgumentError, 'Attempt to redefine block'
318
370
  end
319
371
  end
372
+ alias required_block_param block_param
320
373
 
321
374
  # Defines one optional block parameter that may appear last. If type or name is missing the
322
375
  # defaults are "any callable", and the name is "block". The implementor of the dispatch target
@@ -329,36 +382,22 @@ module Puppet::Functions
329
382
  @block_type = Puppet::Pops::Types::TypeFactory.optional(@block_type)
330
383
  end
331
384
 
332
- # Specifies the min and max occurance of arguments (of the specified types)
333
- # if something other than the exact count from the number of specified
334
- # types). The max value may be specified as :default if an infinite number of
335
- # arguments are supported. When max is > than the number of specified
336
- # types, the last specified type repeats.
337
- #
338
- # @api public
339
- def arg_count(min_occurs, max_occurs)
340
- @min = min_occurs
341
- @max = max_occurs
342
- unless min_occurs.is_a?(Integer) && min_occurs >= 0
343
- raise ArgumentError, "min arg_count of function parameter must be an Integer >=0, got #{min_occurs.class} '#{min_occurs}'"
344
- end
345
- unless max_occurs == :default || (max_occurs.is_a?(Integer) && max_occurs >= 0)
346
- raise ArgumentError, "max arg_count of function parameter must be an Integer >= 0, or :default, got #{max_occurs.class} '#{max_occurs}'"
347
- end
348
- unless max_occurs == :default || (max_occurs.is_a?(Integer) && max_occurs >= min_occurs)
349
- raise ArgumentError, "max arg_count must be :default (infinite) or >= min arg_count, got min: '#{min_occurs}, max: '#{max_occurs}'"
350
- end
351
- end
385
+ private
352
386
 
353
- # Specifies that the last argument captures the rest.
354
- #
355
- # @api public
356
- def last_captures_rest
357
- @last_captures = true
387
+ # @api private
388
+ def internal_param(type, name)
389
+ raise ArgumentError, 'Parameters cannot be added after a block parameter' unless @block_type.nil?
390
+ raise ArgumentError, 'Parameters cannot be added after a repeated parameter' if @max == :default
391
+ if type.is_a?(String)
392
+ @types << type
393
+ @names << name
394
+ # mark what should be picked for this position when dispatching
395
+ @weaving << @names.size()-1
396
+ else
397
+ raise ArgumentError, "Parameter 'type' must be a String reference to a Puppet Data Type. Got #{type.class}"
398
+ end
358
399
  end
359
400
 
360
- private
361
-
362
401
  # @api private
363
402
  def dispatch(meth_name, &block)
364
403
  # an array of either an index into names/types, or an array with
@@ -369,14 +408,13 @@ module Puppet::Functions
369
408
  @names = []
370
409
  @weaving = []
371
410
  @injections = []
372
- @min = nil
373
- @max = nil
374
- @last_captures = false
411
+ @min = 0
412
+ @max = 0
375
413
  @block_type = nil
376
414
  @block_name = nil
377
415
  self.instance_eval &block
378
416
  callable_t = create_callable(@types, @block_type, @min, @max)
379
- @dispatcher.add_dispatch(callable_t, meth_name, @names, @block_name, @injections, @weaving, @last_captures)
417
+ @dispatcher.add_dispatch(callable_t, meth_name, @names, @block_name, @injections, @weaving, @max == :default)
380
418
  end
381
419
 
382
420
  # Handles creation of a callable type from strings specifications of puppet
@@ -390,7 +428,8 @@ module Puppet::Functions
390
428
  @type_parser.parse(t)
391
429
  end
392
430
 
393
- if !(from.nil? && to.nil?)
431
+ if from != to
432
+ # :optional and/or :repeated parameters are present.
394
433
  mapped_types << from
395
434
  mapped_types << to
396
435
  end
@@ -471,6 +510,20 @@ module Puppet::Functions
471
510
  instance_variable_get(ivar)
472
511
  end
473
512
  end
513
+
514
+ # Allows the implementation of a function to call other functions by name and pass the caller
515
+ # scope. The callable functions are those visible to the same loader that loaded this function
516
+ # (the calling function).
517
+ #
518
+ # @param scope [Puppet::Parser::Scope] The caller scope
519
+ # @param function_name [String] The name of the function
520
+ # @param *args [Object] splat of arguments
521
+ # @return [Object] The result returned by the called function
522
+ #
523
+ # @api public
524
+ def call_function_with_scope(scope, function_name, *args)
525
+ internal_call_function(scope, function_name, args)
526
+ end
474
527
  end
475
528
 
476
529
  # @note WARNING: This style of creating functions is not public. It is a system