File: base_setting.rb

package info (click to toggle)
puppet-agent 8.10.0-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 27,404 kB
  • sloc: ruby: 286,820; sh: 492; xml: 116; makefile: 88; cs: 68
file content (228 lines) | stat: -rw-r--r-- 7,234 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# frozen_string_literal: true

require 'set'
require_relative '../../puppet/settings/errors'

# The base setting type
class Puppet::Settings::BaseSetting
  attr_writer :default
  attr_accessor :name, :desc, :section
  attr_reader :short, :deprecated, :call_hook

  # Hooks are called during different parts of the settings lifecycle:
  #
  # * :on_write_only - This is the default hook type. The hook will be called
  #   if its value is set in `main` or programmatically. If its value is set in
  #   a section that doesn't match the application's run mode, it will be
  #   ignored entirely. If the section does match the run mode, the value will
  #   be used, but the hook will not be called!
  #
  # * :on_define_and_write - The hook behaves the same as above, except it is
  #   also called immediately when the setting is defined in
  #   {Puppet::Settings.define_settings}. In that case, the hook receives the
  #   default value as specified.
  #
  # * :on_initialize_and_write - The hook will be called if the value is set in
  #   `main`, the section that matches the run mode, or programmatically.
  #
  HOOK_TYPES = Set.new([:on_define_and_write, :on_initialize_and_write, :on_write_only]).freeze

  def self.available_call_hook_values
    HOOK_TYPES.to_a
  end

  # Registers a hook to be called later based on the type of hook specified in `value`.
  #
  # @param value [Symbol] One of {HOOK_TYPES}
  def call_hook=(value)
    if value.nil?
      # TRANSLATORS ':%{name}', ':call_hook', and ':on_write_only' should not be translated
      Puppet.warning _("Setting :%{name} :call_hook is nil, defaulting to :on_write_only") % { name: name }
      value = :on_write_only
    end
    unless HOOK_TYPES.include?(value)
      # TRANSLATORS 'call_hook' is a Puppet option name and should not be translated
      raise ArgumentError, _("Invalid option %{value} for call_hook") % { value: value }
    end

    @call_hook = value
  end

  # @see {HOOK_TYPES}
  def call_hook_on_define?
    call_hook == :on_define_and_write
  end

  # @see {HOOK_TYPES}
  def call_hook_on_initialize?
    call_hook == :on_initialize_and_write
  end

  # get the arguments in getopt format
  def getopt_args
    if short
      [["--#{name}", "-#{short}", GetoptLong::REQUIRED_ARGUMENT]]
    else
      [["--#{name}", GetoptLong::REQUIRED_ARGUMENT]]
    end
  end

  # get the arguments in OptionParser format
  def optparse_args
    if short
      ["--#{name}", "-#{short}", desc, :REQUIRED]
    else
      ["--#{name}", desc, :REQUIRED]
    end
  end

  def hook=(block)
    @has_hook = true
    meta_def :handle, &block
  end

  def has_hook?
    @has_hook
  end

  # Create the new element.  Pretty much just sets the name.
  def initialize(args = {})
    @settings = args.delete(:settings)
    unless @settings
      raise ArgumentError, "You must refer to a settings object"
    end

    # explicitly set name prior to calling other param= methods to provide meaningful feedback during
    # other warnings
    @name = args[:name] if args.include? :name

    # set the default value for call_hook
    @call_hook = :on_write_only if args[:hook] and !(args[:call_hook])
    @has_hook = false

    if args[:call_hook] and !(args[:hook])
      # TRANSLATORS ':call_hook' and ':hook' are specific setting names and should not be translated
      raise ArgumentError, _("Cannot reference :call_hook for :%{name} if no :hook is defined") % { name: @name }
    end

    args.each do |param, value|
      method = param.to_s + "="
      unless respond_to? method
        raise ArgumentError, _("%{class_name} (setting '%{setting}') does not accept %{parameter}") %
                             { class_name: self.class, setting: args[:name], parameter: param }
      end

      send(method, value)
    end
    unless desc
      raise ArgumentError, _("You must provide a description for the %{class_name} config option") % { class_name: name }
    end
  end

  def iscreated
    @iscreated = true
  end

  def iscreated?
    @iscreated
  end

  # short name for the element
  def short=(value)
    raise ArgumentError, _("Short names can only be one character.") if value.to_s.length != 1

    @short = value.to_s
  end

  def default(check_application_defaults_first = false)
    if @default.is_a? Proc
      # Give unit tests a chance to reevaluate the call by removing the instance variable
      unless instance_variable_defined?(:@evaluated_default)
        @evaluated_default = @default.call
      end
      default_value = @evaluated_default
    else
      default_value = @default
    end
    return default_value unless check_application_defaults_first

    @settings.value(name, :application_defaults, true) || default_value
  end

  # Convert the object to a config statement.
  def to_config
    require_relative '../../puppet/util/docs'
    # Scrub any funky indentation; comment out description.
    str = Puppet::Util::Docs.scrub(@desc).gsub(/^/, "# ") + "\n"

    # Add in a statement about the default.
    str << "# The default value is '#{default(true)}'.\n" if default(true)

    # If the value has not been overridden, then print it out commented
    # and unconverted, so it's clear that that's the default and how it
    # works.
    value = @settings.value(name)

    if value != @default
      line = "#{@name} = #{value}"
    else
      line = "# #{@name} = #{@default}"
    end

    str << (line + "\n")

    # Indent
    str.gsub(/^/, "    ")
  end

  # @param bypass_interpolation [Boolean] Set this true to skip the
  #   interpolation step, returning the raw setting value.  Defaults to false.
  # @return [String] Retrieves the value, or if it's not set, retrieves the default.
  # @api public
  def value(bypass_interpolation = false)
    @settings.value(name, nil, bypass_interpolation)
  end

  # Modify the value when it is first evaluated
  def munge(value)
    value
  end

  # Print the value for the user in a config compatible format
  def print(value)
    munge(value)
  end

  def set_meta(meta)
    Puppet.notice("#{name} does not support meta data. Ignoring.")
  end

  def deprecated=(deprecation)
    unless [:completely, :allowed_on_commandline].include?(deprecation)
      # TRANSLATORS 'deprecated' is a Puppet setting and ':completely' and ':allowed_on_commandline' are possible values and should not be translated
      raise ArgumentError, _("Unsupported deprecated value '%{deprecation}'.") % { deprecation: deprecation } +
                           ' ' + _("Supported values for deprecated are ':completely' or ':allowed_on_commandline'")
    end
    @deprecated = deprecation
  end

  def deprecated?
    !!@deprecated
  end

  # True if we should raise a deprecation_warning if the setting is submitted
  # on the commandline or is set in puppet.conf.
  def completely_deprecated?
    @deprecated == :completely
  end

  # True if we should raise a deprecation_warning if the setting is found in
  # puppet.conf, but not if the user sets it on the commandline
  def allowed_on_commandline?
    @deprecated == :allowed_on_commandline
  end

  def inspect
    %Q(<#{self.class}:#{object_id} @name="#{@name}" @section="#{@section}" @default="#{@default}" @call_hook="#{@call_hook}">)
  end
end