puppet 6.8.1 → 6.9.0

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +10 -11
  4. data/ext/project_data.yaml +1 -0
  5. data/lib/puppet.rb +9 -1
  6. data/lib/puppet/application/agent.rb +12 -0
  7. data/lib/puppet/application_support.rb +1 -1
  8. data/lib/puppet/context.rb +120 -48
  9. data/lib/puppet/face/config.rb +10 -48
  10. data/lib/puppet/face/help.rb +1 -1
  11. data/lib/puppet/face/plugin.rb +9 -2
  12. data/lib/puppet/forge/repository.rb +1 -1
  13. data/lib/puppet/functions/regsubst.rb +58 -37
  14. data/lib/puppet/indirector/catalog/compiler.rb +10 -6
  15. data/lib/puppet/module_tool/applications/uninstaller.rb +2 -3
  16. data/lib/puppet/network/http/connection.rb +1 -1
  17. data/lib/puppet/network/http/factory.rb +1 -1
  18. data/lib/puppet/network/http_pool.rb +1 -0
  19. data/lib/puppet/provider/package/dnf.rb +1 -1
  20. data/lib/puppet/provider/package/rpm.rb +51 -13
  21. data/lib/puppet/provider/package/yum.rb +8 -4
  22. data/lib/puppet/provider/service/systemd.rb +1 -1
  23. data/lib/puppet/settings.rb +40 -0
  24. data/lib/puppet/ssl.rb +1 -1
  25. data/lib/puppet/ssl/base.rb +1 -1
  26. data/lib/puppet/ssl/openssl_loader.rb +28 -0
  27. data/lib/puppet/ssl/validator.rb +1 -1
  28. data/lib/puppet/ssl/validator/default_validator.rb +1 -1
  29. data/lib/puppet/ssl/validator/no_validator.rb +1 -1
  30. data/lib/puppet/thread_local.rb +7 -0
  31. data/lib/puppet/type/exec.rb +14 -6
  32. data/lib/puppet/type/group.rb +4 -2
  33. data/lib/puppet/type/package.rb +10 -0
  34. data/lib/puppet/type/user.rb +4 -2
  35. data/lib/puppet/util/checksums.rb +3 -3
  36. data/lib/puppet/util/http_proxy.rb +8 -6
  37. data/lib/puppet/util/monkey_patches.rb +53 -47
  38. data/lib/puppet/util/platform.rb +16 -0
  39. data/lib/puppet/util/ssl.rb +1 -1
  40. data/lib/puppet/util/windows/root_certs.rb +1 -1
  41. data/lib/puppet/version.rb +1 -1
  42. data/lib/puppet/x509.rb +1 -1
  43. data/locales/puppet.pot +119 -119
  44. data/man/man5/puppet.conf.5 +2 -2
  45. data/man/man8/puppet-agent.8 +1 -1
  46. data/man/man8/puppet-apply.8 +1 -1
  47. data/man/man8/puppet-catalog.8 +1 -1
  48. data/man/man8/puppet-config.8 +1 -1
  49. data/man/man8/puppet-describe.8 +1 -1
  50. data/man/man8/puppet-device.8 +1 -1
  51. data/man/man8/puppet-doc.8 +1 -1
  52. data/man/man8/puppet-epp.8 +1 -1
  53. data/man/man8/puppet-facts.8 +1 -1
  54. data/man/man8/puppet-filebucket.8 +1 -1
  55. data/man/man8/puppet-generate.8 +1 -1
  56. data/man/man8/puppet-help.8 +1 -1
  57. data/man/man8/puppet-key.8 +1 -1
  58. data/man/man8/puppet-lookup.8 +1 -1
  59. data/man/man8/puppet-man.8 +1 -1
  60. data/man/man8/puppet-module.8 +1 -1
  61. data/man/man8/puppet-node.8 +1 -1
  62. data/man/man8/puppet-parser.8 +1 -1
  63. data/man/man8/puppet-plugin.8 +1 -1
  64. data/man/man8/puppet-report.8 +1 -1
  65. data/man/man8/puppet-resource.8 +1 -1
  66. data/man/man8/puppet-script.8 +1 -1
  67. data/man/man8/puppet-ssl.8 +1 -1
  68. data/man/man8/puppet-status.8 +1 -1
  69. data/man/man8/puppet.8 +3 -3
  70. data/spec/integration/provider/service/systemd_spec.rb +7 -6
  71. data/spec/integration/util/execution_spec.rb +1 -1
  72. data/spec/lib/puppet_spec/matchers.rb +0 -13
  73. data/spec/spec_helper.rb +1 -3
  74. data/spec/unit/application/agent_spec.rb +19 -0
  75. data/spec/unit/context_spec.rb +119 -38
  76. data/spec/unit/face/help_spec.rb +1 -1
  77. data/spec/unit/face/plugin_spec.rb +8 -0
  78. data/spec/unit/forge/forge_spec.rb +1 -3
  79. data/spec/unit/forge/repository_spec.rb +1 -3
  80. data/spec/unit/functions/contain_spec.rb +1 -1
  81. data/spec/unit/indirector/catalog/compiler_spec.rb +62 -5
  82. data/spec/unit/module_tool/applications/uninstaller_spec.rb +16 -7
  83. data/spec/unit/node/environment_spec.rb +1 -1
  84. data/spec/unit/provider/package/aptrpm_spec.rb +1 -1
  85. data/spec/unit/provider/package/dnf_spec.rb +7 -0
  86. data/spec/unit/provider/package/pkgin_spec.rb +1 -1
  87. data/spec/unit/provider/package/rpm_spec.rb +150 -16
  88. data/spec/unit/provider/package/yum_spec.rb +7 -0
  89. data/spec/unit/type/exec_spec.rb +9 -0
  90. data/spec/unit/type/schedule_spec.rb +1 -1
  91. data/spec/unit/util/http_proxy_spec.rb +50 -0
  92. data/spec/unit/util/inifile_spec.rb +5 -5
  93. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 223acb5a42c2c6b961e58dd8ee941365737416998a0a326adf7dadd8690c3764
4
- data.tar.gz: dffdf32c5003e5ff2632c9423039571be609f3b4d65a2314d2ec21d3bd3bb9d2
3
+ metadata.gz: 0e29fb771008f2391db8072a7c609e3388d1941f07ce3726b1e4f46e224f419d
4
+ data.tar.gz: 016e177050c07c41fbd16447c027d8353f5fe02bc9169b849e26d5a4be54d4ae
5
5
  SHA512:
6
- metadata.gz: b460be876318cd94264d01a4eaf10c87fe12c0a377783c51a571706aec4f8779ec87fa94ef819dabc6029b63ff199234022a2a6ec60015084fc16c5874008d1a
7
- data.tar.gz: cf8f301bffaf5f4c71b5d68e4c09379a2933e17db54174e29c03985cc6adb15255aff62bdf22dcef11ee7d508e6d1688c76bbd74e35fdcb901d0cf7eae4dc1a6
6
+ metadata.gz: bd9d5695bbc4945aa90afe21df95b1b639ac049904e6595bdd9406e686a20eb0255773eed7476549c97a2aed29ee13cd4a1367705ec032e629addecc63ce6bf1
7
+ data.tar.gz: d89df5ab8202cc7c44e53ecbb6a35eb14cbbaf77312d43b30b0cd97ddaca243141e6c0e8994f9d22aaadefe0a70f3aabdb7addd1720066a423b5c8a4206aae6a
data/Gemfile CHANGED
@@ -39,7 +39,6 @@ group(:test) do
39
39
  gem "rake", *location_for(ENV['RAKE_LOCATION'] || '~> 12.2')
40
40
  gem "rspec", "~> 3.1", require: false
41
41
  gem "rspec-its", "~> 1.1", require: false
42
- gem "rspec-collection_matchers", "~> 1.1", require: false
43
42
  gem 'vcr', '~> 2.9', require: false
44
43
  gem 'webmock', '~> 1.24', require: false
45
44
  gem 'yard', require: false
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- puppet (6.8.1)
4
+ puppet (6.9.0)
5
5
  CFPropertyList (~> 2.2)
6
+ concurrent-ruby (~> 1.0)
6
7
  facter (>= 2.4.0, < 4)
7
8
  fast_gettext (~> 1.1)
8
9
  hiera (>= 3.2.1, < 4)
@@ -15,11 +16,12 @@ GEM
15
16
  remote: https://artifactory.delivery.puppetlabs.net/artifactory/api/gems/rubygems/
16
17
  specs:
17
18
  CFPropertyList (2.3.6)
18
- addressable (2.6.0)
19
- public_suffix (>= 2.0.2, < 4.0)
19
+ addressable (2.7.0)
20
+ public_suffix (>= 2.0.2, < 5.0)
20
21
  artifactory (2.8.2)
21
22
  ast (2.4.0)
22
23
  coderay (1.1.2)
24
+ concurrent-ruby (1.1.5)
23
25
  crack (0.4.3)
24
26
  safe_yaml (~> 1.0.0)
25
27
  diff-lcs (1.3)
@@ -46,22 +48,22 @@ GEM
46
48
  locale (2.1.2)
47
49
  memory_profiler (0.9.14)
48
50
  method_source (0.9.2)
49
- minitar (0.8)
51
+ minitar (0.9)
50
52
  msgpack (1.3.1)
51
53
  multi_json (1.13.1)
52
54
  mustache (1.1.0)
53
55
  optimist (3.0.0)
54
- packaging (0.99.39)
56
+ packaging (0.99.42)
55
57
  artifactory (~> 2)
56
58
  rake (~> 12.3)
57
59
  parallel (1.17.0)
58
- parser (2.6.3.0)
60
+ parser (2.6.4.1)
59
61
  ast (~> 2.4.0)
60
62
  powerpack (0.1.2)
61
63
  pry (0.12.2)
62
64
  coderay (~> 1.1.0)
63
65
  method_source (~> 0.9.0)
64
- public_suffix (3.1.1)
66
+ public_suffix (4.0.1)
65
67
  puppet-resource_api (1.8.6)
66
68
  hocon (>= 1.0)
67
69
  puppetserver-ca (1.4.0)
@@ -71,7 +73,7 @@ GEM
71
73
  rake
72
74
  rake (12.3.3)
73
75
  rdiscount (2.2.0.1)
74
- rdoc (6.1.1)
76
+ rdoc (6.2.0)
75
77
  ronn (0.7.3)
76
78
  hpricot (>= 0.8.2)
77
79
  mustache (>= 0.7.0)
@@ -80,8 +82,6 @@ GEM
80
82
  rspec-core (~> 3.8.0)
81
83
  rspec-expectations (~> 3.8.0)
82
84
  rspec-mocks (~> 3.8.0)
83
- rspec-collection_matchers (1.1.3)
84
- rspec-expectations (>= 2.99.0.beta1)
85
85
  rspec-core (3.8.2)
86
86
  rspec-support (~> 3.8.0)
87
87
  rspec-expectations (3.8.4)
@@ -138,7 +138,6 @@ DEPENDENCIES
138
138
  rdoc (~> 6.0)
139
139
  ronn (~> 0.7.3)
140
140
  rspec (~> 3.1)
141
- rspec-collection_matchers (~> 1.1)
142
141
  rspec-its (~> 1.1)
143
142
  rubocop (~> 0.49)
144
143
  rubocop-i18n (~> 1.2.0)
@@ -25,6 +25,7 @@ gem_runtime_dependencies:
25
25
  multi_json: '~> 1.10'
26
26
  httpclient: '~> 2.8'
27
27
  puppet-resource_api: '~>1.5'
28
+ concurrent-ruby: '~> 1.0'
28
29
  gem_rdoc_options:
29
30
  - --title
30
31
  - "Puppet - Configuration Management"
@@ -148,7 +148,7 @@ module Puppet
148
148
  Puppet.settings.initialize_global_settings(args, require_config)
149
149
  run_mode = Puppet::Util::RunMode[run_mode]
150
150
  Puppet.settings.initialize_app_defaults(Puppet::Settings.app_defaults_for_run_mode(run_mode))
151
- Puppet.push_context(Puppet.base_context(Puppet.settings), "Initial context after settings initialization")
151
+ push_context_global(Puppet.base_context(Puppet.settings), "Initial context after settings initialization")
152
152
  Puppet::Parser::Functions.reset
153
153
  end
154
154
  private_class_method :do_initialize_settings_for_run_mode
@@ -245,6 +245,14 @@ module Puppet
245
245
  @context.push(overrides, description)
246
246
  end
247
247
 
248
+ # Push something onto the the context and make it global across threads. This
249
+ # has the potential to convert threadlocal overrides earlier on the stack into
250
+ # global overrides.
251
+ # @api private
252
+ def self.push_context_global(overrides, description = '')
253
+ @context.unsafe_push_global(overrides, description)
254
+ end
255
+
248
256
  # Return to the previous context.
249
257
  # @raise [StackUnderflow] if the current context is the root
250
258
  # @api private
@@ -351,6 +351,8 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
351
351
  # Setup signal traps immediately after daemonization so we clean up the daemon
352
352
  daemon.set_signal_traps
353
353
 
354
+ log_config if Puppet[:daemonize]
355
+
354
356
  Puppet.override(ssl_context: wait_for_certificates) do
355
357
  if Puppet[:onetime]
356
358
  onetime(daemon)
@@ -361,6 +363,16 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
361
363
  end
362
364
  end
363
365
 
366
+ def log_config
367
+ #skip also config reading and parsing if debug is not enabled
368
+ return unless Puppet::Util::Log.sendlevel?(:debug)
369
+
370
+ Puppet.settings.stringify_settings(:agent, :all).each_pair do |k,v|
371
+ next if k.include?("password") || v.to_s.empty?
372
+ Puppet.debug("Using setting: #{k}=#{v}")
373
+ end
374
+ end
375
+
364
376
  def fingerprint
365
377
  Puppet::Util::Log.newdestination(:console)
366
378
  cert_provider = Puppet::X509::CertProvider.new
@@ -19,7 +19,7 @@ module Puppet
19
19
  # @return [void]
20
20
  # @api private
21
21
  def self.push_application_context(run_mode, environment_mode = :local)
22
- Puppet.push_context(Puppet.base_context(Puppet.settings), "Update for application settings (#{run_mode})")
22
+ Puppet.push_context_global(Puppet.base_context(Puppet.settings), "Update for application settings (#{run_mode})")
23
23
  # This use of configured environment is correct, this is used to establish
24
24
  # the defaults for an application that does not override, or where an override
25
25
  # has not been made from the command line.
@@ -1,3 +1,5 @@
1
+ require 'puppet/thread_local'
2
+
1
3
  # Puppet::Context is a system for tracking services and contextual information
2
4
  # that puppet needs to be able to run. Values are "bound" in a context when it is created
3
5
  # and cannot be changed; however a child context can be created, using
@@ -19,66 +21,47 @@ class Puppet::Context
19
21
 
20
22
  # @api private
21
23
  def initialize(initial_bindings)
22
- @table = initial_bindings
23
- @ignores = []
24
- @description = "root"
25
- @id = 0
26
- @rollbacks = {}
27
- @stack = [[0, nil, nil]]
24
+ @stack = Puppet::ThreadLocal.new(EmptyStack.new.push(initial_bindings))
25
+
26
+ # By initializing @rollbacks to nil and creating a hash lazily when #mark or
27
+ # #rollback are called we ensure that the hashes are never shared between
28
+ # threads and it's safe to mutate them
29
+ @rollbacks = Puppet::ThreadLocal.new(nil)
30
+ end
31
+
32
+ # @api private
33
+ def push(overrides, description = '')
34
+ @stack.value = @stack.value.push(overrides, description)
28
35
  end
29
36
 
37
+ # Push a context and make this global across threads
38
+ # Do not use in a context where multiple threads may already exist
39
+ #
30
40
  # @api private
31
- def push(overrides, description = "")
32
- @id += 1
33
- @stack.push([@id, @table, @description])
34
- @table = @table.merge(overrides || {})
35
- @description = description
41
+ def unsafe_push_global(overrides, description = '')
42
+ @stack = Puppet::ThreadLocal.new(
43
+ @stack.value.push(overrides, description)
44
+ )
36
45
  end
37
46
 
38
47
  # @api private
39
48
  def pop
40
- if @stack[-1][0] == 0
41
- raise(StackUnderflow, _("Attempted to pop, but already at root of the context stack."))
42
- else
43
- (_, @table, @description) = @stack.pop
44
- end
49
+ @stack.value = @stack.value.pop
45
50
  end
46
51
 
47
52
  # @api private
48
53
  def lookup(name, &block)
49
- if @table.include?(name) && !@ignores.include?(name)
50
- value = @table[name]
51
- value.is_a?(Proc) ? (@table[name] = value.call) : value
52
- elsif block
53
- block.call
54
- else
55
- raise UndefinedBindingError, _("Unable to lookup '%{name}'") % { name: name }
56
- end
54
+ @stack.value.lookup(name, &block)
57
55
  end
58
56
 
59
57
  # @api private
60
- def override(bindings, description = "", &block)
61
- mark_point = "override over #{@stack[-1][0]}"
62
- mark(mark_point)
58
+ def override(bindings, description = '', &block)
59
+ saved_point = @stack.value
63
60
  push(bindings, description)
64
61
 
65
62
  yield
66
63
  ensure
67
- rollback(mark_point)
68
- end
69
-
70
- # @api private
71
- def ignore(name)
72
- @ignores << name
73
- end
74
-
75
- # @api private
76
- def restore(name)
77
- if @ignores.include?(name)
78
- @ignores.delete(name)
79
- else
80
- raise UndefinedBindingError, _("no '%{name}' in ignores %{ignores} at top of %{stack}") % { name: name, ignores: @ignores.inspect, stack: @stack.inspect }
81
- end
64
+ @stack.value = saved_point
82
65
  end
83
66
 
84
67
  # Mark a place on the context stack to later return to with {rollback}.
@@ -87,8 +70,9 @@ class Puppet::Context
87
70
  #
88
71
  # @api private
89
72
  def mark(name)
90
- if @rollbacks[name].nil?
91
- @rollbacks[name] = @stack[-1][0]
73
+ @rollbacks.value ||= {}
74
+ if @rollbacks.value[name].nil?
75
+ @rollbacks.value[name] = @stack.value
92
76
  else
93
77
  raise DuplicateRollbackMarkError, _("Mark for '%{name}' already exists") % { name: name }
94
78
  end
@@ -103,14 +87,102 @@ class Puppet::Context
103
87
  #
104
88
  # @api private
105
89
  def rollback(name)
106
- if @rollbacks[name].nil?
90
+ @rollbacks.value ||= {}
91
+ if @rollbacks.value[name].nil?
107
92
  raise UnknownRollbackMarkError, _("Unknown mark '%{name}'") % { name: name }
108
93
  end
109
94
 
110
- while @stack[-1][0] != @rollbacks[name]
111
- pop
95
+ @stack.value = @rollbacks.value.delete(name)
96
+ end
97
+
98
+ # Base case for Puppet::Context::Stack.
99
+ #
100
+ # @api private
101
+ class EmptyStack
102
+ # Lookup a binding. Since there are none in EmptyStack, this always raises
103
+ # an exception unless a block is passed, in which case the block is called
104
+ # and its return value is used.
105
+ #
106
+ # @api private
107
+ def lookup(name, &block)
108
+ if block
109
+ block.call
110
+ else
111
+ raise UndefinedBindingError, _("Unable to lookup '%{name}'") % { name: name }
112
+ end
113
+ end
114
+
115
+ # Base case of #pop always raises an error since this is the bottom
116
+ #
117
+ # @api private
118
+ def pop
119
+ raise(StackUnderflow,
120
+ _('Attempted to pop, but already at root of the context stack.'))
121
+ end
122
+
123
+ # Push bindings onto the stack by creating a new Stack object with `self` as
124
+ # the parent
125
+ #
126
+ # @api private
127
+ def push(overrides, description = '')
128
+ Puppet::Context::Stack.new(self, overrides, description)
112
129
  end
113
130
 
114
- @rollbacks.delete(name)
131
+ # Return the bindings table, which is always empty here
132
+ #
133
+ # @api private
134
+ def bindings
135
+ {}
136
+ end
137
+ end
138
+
139
+ # Internal implementation of the bindings stack used by Puppet::Context. An
140
+ # instance of Puppet::Context::Stack represents one level of bindings. It
141
+ # caches a merged copy of all the bindings in the stack up to this point.
142
+ # Each element of the stack is immutable, allowing the base to be shared
143
+ # between threads.
144
+ #
145
+ # @api private
146
+ class Stack
147
+ attr_reader :bindings
148
+
149
+ def initialize(parent, bindings, description = '')
150
+ @parent = parent
151
+ @bindings = parent.bindings.merge(bindings || {})
152
+ @description = description
153
+ end
154
+
155
+ # Lookup a binding in the current stack. Return the value if it is present.
156
+ # If the value is a stored Proc, evaluate, cache, and return the result. If
157
+ # no binding is found and a block is passed evaluate it and return the
158
+ # result. Otherwise an exception is raised.
159
+ #
160
+ # @api private
161
+ def lookup(name, &block)
162
+ if @bindings.include?(name)
163
+ value = @bindings[name]
164
+ value.is_a?(Proc) ? (@bindings[name] = value.call) : value
165
+ elsif block
166
+ block.call
167
+ else
168
+ raise UndefinedBindingError,
169
+ _("Unable to lookup '%{name}'") % { name: name }
170
+ end
171
+ end
172
+
173
+ # Pop one level off the stack by returning the parent object.
174
+ #
175
+ # @api private
176
+ def pop
177
+ @parent
178
+ end
179
+
180
+ # Push bindings onto the stack by creating a new Stack object with `self` as
181
+ # the parent
182
+ #
183
+ # @api private
184
+ def push(overrides, description = '')
185
+ Puppet::Context::Stack.new(self, overrides, description)
186
+ end
115
187
  end
116
188
  end
@@ -66,41 +66,18 @@ Puppet::Face.define(:config, '0.0.1') do
66
66
  @default_section = true
67
67
  end
68
68
 
69
- render_all_settings = args.empty? || args == ['all']
70
-
71
- args = Puppet.settings.to_a.collect(&:first) if render_all_settings
72
-
73
- values_from_the_selected_section =
74
- Puppet.settings.values(nil, options[:section].to_sym)
75
-
76
- loader_settings = {
77
- :environmentpath => values_from_the_selected_section.interpolate(:environmentpath),
78
- :basemodulepath => values_from_the_selected_section.interpolate(:basemodulepath),
79
- }
80
-
81
- to_be_rendered = nil
82
- Puppet.override(Puppet.base_context(loader_settings),
83
- _("New environment loaders generated from the requested section.")) do
84
- # And now we can lookup values that include those from environments configured from
85
- # the requested section
86
- values = Puppet.settings.values(Puppet[:environment].to_sym, options[:section].to_sym)
87
-
88
- if Puppet::Util::Log.sendlevel?(:info)
89
- warn_default_section(options[:section]) if @default_section
90
- report_section_and_environment(options[:section], Puppet.settings[:environment])
91
- end
92
-
93
- to_be_rendered = {}
94
- args.sort.each do |setting_name|
95
- to_be_rendered[setting_name] = values.print(setting_name.to_sym)
96
- end
69
+ if Puppet::Util::Log.sendlevel?(:info)
70
+ warn_default_section(options[:section]) if @default_section
71
+ report_section_and_environment(options[:section], Puppet.settings[:environment])
97
72
  end
98
73
 
99
- # convert symbols to strings before formatting output
100
- if render_all_settings
101
- to_be_rendered = stringifyhash(to_be_rendered)
102
- end
103
- to_be_rendered
74
+ names = if args.empty? || args == ['all']
75
+ :all
76
+ else
77
+ args
78
+ end
79
+
80
+ Puppet.settings.stringify_settings(options[:section], names)
104
81
  end
105
82
 
106
83
  when_rendering :console do |to_be_rendered|
@@ -117,21 +94,6 @@ Puppet::Face.define(:config, '0.0.1') do
117
94
  end
118
95
  end
119
96
 
120
- def stringifyhash(hash)
121
- newhash = {}
122
- hash.each do |key, val|
123
- key = key.to_s
124
- if val.is_a? Hash
125
- newhash[key] = stringifyhash(val)
126
- elsif val.is_a? Symbol
127
- newhash[key] = val.to_s
128
- else
129
- newhash[key] = val
130
- end
131
- end
132
- newhash
133
- end
134
-
135
97
  def warn_default_section(section_name)
136
98
  messages = []
137
99
  messages << _("No section specified; defaulting to '%{section_name}'.") %