test-kitchen-rsync 3.0.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +21 -0
- data/LICENSE +15 -0
- data/Rakefile +53 -0
- data/bin/zl-kitchen +11 -0
- data/lib/kitchen/base64_stream.rb +48 -0
- data/lib/kitchen/chef_utils_wiring.rb +40 -0
- data/lib/kitchen/cli.rb +413 -0
- data/lib/kitchen/collection.rb +52 -0
- data/lib/kitchen/color.rb +63 -0
- data/lib/kitchen/command/action.rb +41 -0
- data/lib/kitchen/command/console.rb +54 -0
- data/lib/kitchen/command/diagnose.rb +84 -0
- data/lib/kitchen/command/doctor.rb +39 -0
- data/lib/kitchen/command/exec.rb +37 -0
- data/lib/kitchen/command/list.rb +148 -0
- data/lib/kitchen/command/login.rb +39 -0
- data/lib/kitchen/command/package.rb +32 -0
- data/lib/kitchen/command/sink.rb +50 -0
- data/lib/kitchen/command/test.rb +47 -0
- data/lib/kitchen/command.rb +207 -0
- data/lib/kitchen/config.rb +344 -0
- data/lib/kitchen/configurable.rb +616 -0
- data/lib/kitchen/data_munger.rb +1024 -0
- data/lib/kitchen/diagnostic.rb +138 -0
- data/lib/kitchen/driver/base.rb +133 -0
- data/lib/kitchen/driver/dummy.rb +105 -0
- data/lib/kitchen/driver/exec.rb +70 -0
- data/lib/kitchen/driver/proxy.rb +70 -0
- data/lib/kitchen/driver/ssh_base.rb +351 -0
- data/lib/kitchen/driver.rb +40 -0
- data/lib/kitchen/errors.rb +243 -0
- data/lib/kitchen/generator/init.rb +254 -0
- data/lib/kitchen/instance.rb +726 -0
- data/lib/kitchen/lazy_hash.rb +148 -0
- data/lib/kitchen/lifecycle_hook/base.rb +78 -0
- data/lib/kitchen/lifecycle_hook/local.rb +53 -0
- data/lib/kitchen/lifecycle_hook/remote.rb +39 -0
- data/lib/kitchen/lifecycle_hooks.rb +92 -0
- data/lib/kitchen/loader/yaml.rb +377 -0
- data/lib/kitchen/logger.rb +422 -0
- data/lib/kitchen/logging.rb +52 -0
- data/lib/kitchen/login_command.rb +49 -0
- data/lib/kitchen/metadata_chopper.rb +49 -0
- data/lib/kitchen/platform.rb +64 -0
- data/lib/kitchen/plugin.rb +76 -0
- data/lib/kitchen/plugin_base.rb +60 -0
- data/lib/kitchen/provisioner/base.rb +269 -0
- data/lib/kitchen/provisioner/chef/berkshelf.rb +116 -0
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +350 -0
- data/lib/kitchen/provisioner/chef/policyfile.rb +163 -0
- data/lib/kitchen/provisioner/chef_apply.rb +121 -0
- data/lib/kitchen/provisioner/chef_base.rb +705 -0
- data/lib/kitchen/provisioner/chef_infra.rb +167 -0
- data/lib/kitchen/provisioner/chef_solo.rb +82 -0
- data/lib/kitchen/provisioner/chef_zero.rb +12 -0
- data/lib/kitchen/provisioner/dummy.rb +75 -0
- data/lib/kitchen/provisioner/shell.rb +157 -0
- data/lib/kitchen/provisioner.rb +42 -0
- data/lib/kitchen/rake_tasks.rb +80 -0
- data/lib/kitchen/shell_out.rb +90 -0
- data/lib/kitchen/ssh.rb +289 -0
- data/lib/kitchen/state_file.rb +112 -0
- data/lib/kitchen/suite.rb +48 -0
- data/lib/kitchen/thor_tasks.rb +63 -0
- data/lib/kitchen/transport/base.rb +236 -0
- data/lib/kitchen/transport/dummy.rb +78 -0
- data/lib/kitchen/transport/exec.rb +145 -0
- data/lib/kitchen/transport/ssh.rb +579 -0
- data/lib/kitchen/transport/winrm.rb +546 -0
- data/lib/kitchen/transport.rb +40 -0
- data/lib/kitchen/util.rb +229 -0
- data/lib/kitchen/verifier/base.rb +243 -0
- data/lib/kitchen/verifier/busser.rb +275 -0
- data/lib/kitchen/verifier/dummy.rb +75 -0
- data/lib/kitchen/verifier/shell.rb +99 -0
- data/lib/kitchen/verifier.rb +39 -0
- data/lib/kitchen/version.rb +20 -0
- data/lib/kitchen/which.rb +26 -0
- data/lib/kitchen.rb +152 -0
- data/lib/vendor/hash_recursive_merge.rb +79 -0
- data/support/busser_install_command.ps1 +14 -0
- data/support/busser_install_command.sh +21 -0
- data/support/chef-client-fail-if-update-handler.rb +15 -0
- data/support/chef_base_init_command.ps1 +18 -0
- data/support/chef_base_init_command.sh +1 -0
- data/support/chef_base_install_command.ps1 +85 -0
- data/support/chef_base_install_command.sh +229 -0
- data/support/download_helpers.sh +109 -0
- data/support/dummy-validation.pem +27 -0
- data/templates/driver/CHANGELOG.md.erb +3 -0
- data/templates/driver/Gemfile.erb +3 -0
- data/templates/driver/README.md.erb +64 -0
- data/templates/driver/Rakefile.erb +21 -0
- data/templates/driver/driver.rb.erb +23 -0
- data/templates/driver/gemspec.erb +29 -0
- data/templates/driver/gitignore.erb +17 -0
- data/templates/driver/license_apachev2.erb +15 -0
- data/templates/driver/license_lgplv3.erb +16 -0
- data/templates/driver/license_mit.erb +22 -0
- data/templates/driver/license_reserved.erb +5 -0
- data/templates/driver/tailor.erb +4 -0
- data/templates/driver/travis.yml.erb +11 -0
- data/templates/driver/version.rb.erb +12 -0
- data/templates/init/chefignore.erb +2 -0
- data/templates/init/kitchen.yml.erb +18 -0
- data/test-kitchen.gemspec +52 -0
- metadata +528 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2013, Fletcher Nichol
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require "erb" unless defined?(Erb)
|
|
19
|
+
require_relative "../../vendor/hash_recursive_merge"
|
|
20
|
+
require "psych" unless defined?(Psych)
|
|
21
|
+
require "yaml" unless defined?(YAML)
|
|
22
|
+
|
|
23
|
+
module Kitchen
|
|
24
|
+
module Loader
|
|
25
|
+
# YAML file loader for Test Kitchen configuration. This class is
|
|
26
|
+
# responisble for parsing the main YAML file and the local YAML if it
|
|
27
|
+
# exists. Local file configuration will win over the default configuration.
|
|
28
|
+
# The client of this class should not require any YAML loading or parsing
|
|
29
|
+
# logic.
|
|
30
|
+
#
|
|
31
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
|
32
|
+
class YAML
|
|
33
|
+
# Creates a new loader that can parse and load YAML files.
|
|
34
|
+
#
|
|
35
|
+
# @param options [Hash] configuration for a new loader
|
|
36
|
+
# @option options [String] :project_config path to the Kitchen
|
|
37
|
+
# config YAML file (default: `./kitchen.yml`)
|
|
38
|
+
# @option options [String] :local_config path to the Kitchen local
|
|
39
|
+
# config YAML file (default: `./kitchen.local.yml`)
|
|
40
|
+
# @option options [String] :global_config path to the Kitchen global
|
|
41
|
+
# config YAML file (default: `$HOME/.kitchen/config.yml`)
|
|
42
|
+
# @option options [String] :process_erb whether or not to process YAML
|
|
43
|
+
# through an ERB processor (default: `true`)
|
|
44
|
+
# @option options [String] :process_local whether or not to process a
|
|
45
|
+
# local kitchen YAML file, if it exists (default: `true`)
|
|
46
|
+
def initialize(options = {})
|
|
47
|
+
@config_file =
|
|
48
|
+
File.expand_path(options[:project_config] || default_config_file)
|
|
49
|
+
@local_config_file =
|
|
50
|
+
File.expand_path(options[:local_config] || default_local_config_file)
|
|
51
|
+
@global_config_file =
|
|
52
|
+
File.expand_path(options[:global_config] || default_global_config_file)
|
|
53
|
+
|
|
54
|
+
@process_erb = options.fetch(:process_erb, true)
|
|
55
|
+
@process_local = options.fetch(:process_local, true)
|
|
56
|
+
@process_global = options.fetch(:process_global, true)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Reads, parses, and merges YAML configuration files and returns a Hash
|
|
60
|
+
# of tne merged data.
|
|
61
|
+
#
|
|
62
|
+
# @return [Hash] merged configuration data
|
|
63
|
+
def read
|
|
64
|
+
unless File.exist?(config_file)
|
|
65
|
+
raise UserError, "Kitchen YAML file #{config_file} does not exist."
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Util.symbolized_hash(combined_hash)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Returns a Hash of configuration and other useful diagnostic information.
|
|
72
|
+
#
|
|
73
|
+
# @return [Hash] a diagnostic hash
|
|
74
|
+
def diagnose
|
|
75
|
+
result = {}
|
|
76
|
+
result[:process_erb] = @process_erb
|
|
77
|
+
result[:process_local] = @process_local
|
|
78
|
+
result[:process_global] = @process_global
|
|
79
|
+
result[:global_config] = diagnose_component(:global_yaml, global_config_file)
|
|
80
|
+
result[:project_config] = diagnose_component(:yaml, config_file)
|
|
81
|
+
result[:local_config] = diagnose_component(:local_yaml, local_config_file)
|
|
82
|
+
result[:combined_config] = diagnose_component(:combined_hash)
|
|
83
|
+
result
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
# @return [String] the absolute path to the Kitchen config YAML file
|
|
89
|
+
# @api private
|
|
90
|
+
attr_reader :config_file
|
|
91
|
+
|
|
92
|
+
# @return [String] the absolute path to the Kitchen local config YAML
|
|
93
|
+
# file
|
|
94
|
+
# @api private
|
|
95
|
+
attr_reader :local_config_file
|
|
96
|
+
|
|
97
|
+
# @return [String] the absolute path to the Kitchen global config YAML
|
|
98
|
+
# file
|
|
99
|
+
# @api private
|
|
100
|
+
attr_reader :global_config_file
|
|
101
|
+
|
|
102
|
+
# Performed a prioritized recursive merge of several source Hashes and
|
|
103
|
+
# returns a new merged Hash. There are 3 sources of configuration data:
|
|
104
|
+
#
|
|
105
|
+
# 1. local config
|
|
106
|
+
# 2. project config
|
|
107
|
+
# 3. global config
|
|
108
|
+
#
|
|
109
|
+
# The merge order is local -> project -> global, meaning that elements at
|
|
110
|
+
# the top of the above list will be merged last, and have greater
|
|
111
|
+
# precedence than elements at the bottom of the list.
|
|
112
|
+
#
|
|
113
|
+
# @return [Hash] a new merged Hash
|
|
114
|
+
# @api private
|
|
115
|
+
def combined_hash
|
|
116
|
+
y = if @process_global
|
|
117
|
+
normalize(global_yaml).rmerge(normalize(yaml))
|
|
118
|
+
else
|
|
119
|
+
normalize(yaml)
|
|
120
|
+
end
|
|
121
|
+
@process_local ? y.rmerge(normalize(local_yaml)) : y
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Loads and returns the Kitchen config YAML as a Hash.
|
|
125
|
+
#
|
|
126
|
+
# @return [Hash] the config hash
|
|
127
|
+
# @api private
|
|
128
|
+
def yaml
|
|
129
|
+
parse_yaml_string(yaml_string(config_file), config_file)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Loads and returns the Kitchen local config YAML as a Hash.
|
|
133
|
+
#
|
|
134
|
+
# @return [Hash] the config hash
|
|
135
|
+
# @api private
|
|
136
|
+
def local_yaml
|
|
137
|
+
parse_yaml_string(yaml_string(local_config_file), local_config_file)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Loads and returns the Kitchen global config YAML as a Hash.
|
|
141
|
+
#
|
|
142
|
+
# @return [Hash] the config hash
|
|
143
|
+
# @api private
|
|
144
|
+
def global_yaml
|
|
145
|
+
parse_yaml_string(yaml_string(global_config_file), global_config_file)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Loads a file to a string and optionally passes it through an ERb
|
|
149
|
+
# process.
|
|
150
|
+
#
|
|
151
|
+
# @return [String] a file's contents as a string
|
|
152
|
+
# @api private
|
|
153
|
+
def yaml_string(file)
|
|
154
|
+
string = read_file(file)
|
|
155
|
+
|
|
156
|
+
@process_erb ? process_erb(string, file) : string
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Passes a string through ERb to evaulate any ERb blocks.
|
|
160
|
+
#
|
|
161
|
+
# @param string [String] the string to process
|
|
162
|
+
# @param file [String] an absolute path to the file represented as the
|
|
163
|
+
# passed in string, used for error reporting
|
|
164
|
+
# @return [String] a new string, passed through an ERb process
|
|
165
|
+
# @raise [UserError] if an ERb parsing error occurs
|
|
166
|
+
# @api private
|
|
167
|
+
def process_erb(string, file)
|
|
168
|
+
tpl = ERB.new(string)
|
|
169
|
+
tpl.filename = file
|
|
170
|
+
tpl.result
|
|
171
|
+
rescue => e
|
|
172
|
+
raise UserError, "Error parsing ERB content in #{file} " \
|
|
173
|
+
"(#{e.class}: #{e.message}).\n" \
|
|
174
|
+
"Please run `kitchen diagnose --no-instances --loader' to help " \
|
|
175
|
+
"debug your issue."
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Reads a file and returns its contents as a string.
|
|
179
|
+
#
|
|
180
|
+
# @param file [String] a path to a file
|
|
181
|
+
# @return [String] the files contents, or an empty string if the file
|
|
182
|
+
# does not exist
|
|
183
|
+
# @api private
|
|
184
|
+
def read_file(file)
|
|
185
|
+
File.exist?(file.to_s) ? IO.read(file) : ""
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Determines the default absolute path to the Kitchen config YAML file,
|
|
189
|
+
# based on current working directory. We prefer `kitchen.yml` to the
|
|
190
|
+
# older `.kitchen.yml`.
|
|
191
|
+
#
|
|
192
|
+
# @return [String] an absolute path to a Kitchen config YAML file
|
|
193
|
+
# @api private
|
|
194
|
+
def default_config_file
|
|
195
|
+
if File.exist?(kitchen_yml) && File.exist?(dot_kitchen_yml)
|
|
196
|
+
raise UserError, "Both #{kitchen_yml} and #{dot_kitchen_yml} found. Please use the un-dotted variant: #{kitchen_yml}."
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if !File.exist?(kitchen_yml) && !File.exist?(dot_kitchen_yml)
|
|
200
|
+
return kitchen_yml
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
File.exist?(kitchen_yml) ? kitchen_yml : dot_kitchen_yml
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# The absolute path to an un-hidden Kitchen config YAML file.
|
|
207
|
+
def kitchen_yml
|
|
208
|
+
File.join(Dir.pwd, "kitchen.yml")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# The absolute path to an hidden Kitchen config YAML file.
|
|
212
|
+
def dot_kitchen_yml
|
|
213
|
+
File.join(Dir.pwd, ".kitchen.yml")
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Determines the default absolute path to the Kitchen local YAML file,
|
|
217
|
+
# based on the base Kitchen config YAML file.
|
|
218
|
+
|
|
219
|
+
# @return [String] an absolute path to a Kitchen local YAML file
|
|
220
|
+
# @raise [UserError] if both dotted and undotted versions of the default
|
|
221
|
+
# local YAML file exist, e.g. both kitchen.local.yml and .kitchen.local.yml
|
|
222
|
+
# @api private
|
|
223
|
+
def default_local_config_file
|
|
224
|
+
config_dir, default_local_config = File.split(config_file.sub(/(#{File.extname(config_file)})$/, '.local\1'))
|
|
225
|
+
|
|
226
|
+
undot_config = default_local_config.sub(/^\./, "")
|
|
227
|
+
dot_config = ".#{undot_config}"
|
|
228
|
+
|
|
229
|
+
if File.exist?(File.join(config_dir, undot_config)) && File.exist?(File.join(config_dir, dot_config))
|
|
230
|
+
raise UserError, "Both #{undot_config} and #{dot_config} found in #{config_dir}. Please use #{default_local_config} which matches your #{config_file}."
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
File.exist?(File.join(config_dir, dot_config)) ? File.join(config_dir, dot_config) : File.join(config_dir, undot_config)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Determines the default absolute path to the Kitchen global YAML file,
|
|
237
|
+
# based on the base Kitchen config YAML file.
|
|
238
|
+
#
|
|
239
|
+
# @return [String] an absolute path to a Kitchen global YAML file
|
|
240
|
+
# @api private
|
|
241
|
+
def default_global_config_file
|
|
242
|
+
File.join(File.expand_path(ENV["HOME"]), ".kitchen", "config.yml")
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Generate a diganose Hash for a particular YAML file Hash. If an error
|
|
246
|
+
# occurs when loading the data, then a failure hash will be inserted
|
|
247
|
+
# into the `:raw_data` sub-hash.
|
|
248
|
+
#
|
|
249
|
+
# @param component [Symbol] a YAML source component
|
|
250
|
+
# @param file [String] the absolute path to a file which is used for
|
|
251
|
+
# reporting (default: `nil`)
|
|
252
|
+
# @return [Hash] a hash data structure
|
|
253
|
+
# @api private
|
|
254
|
+
def diagnose_component(component, file = nil)
|
|
255
|
+
return if file && !File.exist?(file)
|
|
256
|
+
|
|
257
|
+
hash = begin
|
|
258
|
+
send(component)
|
|
259
|
+
rescue => e
|
|
260
|
+
failure_hash(e, file)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
{ filename: file, raw_data: hash }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Generates a Hash respresenting a failure, given an Exception object.
|
|
267
|
+
#
|
|
268
|
+
# @param e [Exception] an exception
|
|
269
|
+
# @param file [String] the absolute path to a file (default: `nil`)
|
|
270
|
+
# @return [Hash] a hash data structure
|
|
271
|
+
# @api private
|
|
272
|
+
def failure_hash(e, file = nil)
|
|
273
|
+
result = {
|
|
274
|
+
error: {
|
|
275
|
+
exception: e.inspect,
|
|
276
|
+
message: e.message,
|
|
277
|
+
backtrace: e.backtrace,
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
result[:error][:raw_file] = IO.read(file) unless file.nil?
|
|
281
|
+
result
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Destructively modify an object containing one or more hashes so that
|
|
285
|
+
# the resulting formatted data can be consumed upstream.
|
|
286
|
+
#
|
|
287
|
+
# @param obj [Object] an object
|
|
288
|
+
# @return [Object] an object
|
|
289
|
+
# @api private
|
|
290
|
+
def normalize(obj)
|
|
291
|
+
if obj.is_a?(Hash)
|
|
292
|
+
obj.inject({}) { |h, (k, v)| normalize_hash(h, k, v); h }
|
|
293
|
+
else
|
|
294
|
+
obj
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Normalizes certain keys in the root of a data hash to be a proper
|
|
299
|
+
# sub-hash in all cases. Specifically handled are the following cases:
|
|
300
|
+
#
|
|
301
|
+
# * If the value for certain keys (`"driver"`, `"provisioner"`,
|
|
302
|
+
# `"busser"`) are set to `nil`, a new Hash will be put in its place.
|
|
303
|
+
# * If the value for certain keys is a String, then the value is
|
|
304
|
+
# converted to a new Hash with a default key pointing to the original
|
|
305
|
+
# String.
|
|
306
|
+
#
|
|
307
|
+
# Given a hash:
|
|
308
|
+
#
|
|
309
|
+
# { "driver" => nil }
|
|
310
|
+
#
|
|
311
|
+
# this method would return:
|
|
312
|
+
#
|
|
313
|
+
# { "driver" => {} }
|
|
314
|
+
#
|
|
315
|
+
# Given a hash:
|
|
316
|
+
#
|
|
317
|
+
# { :driver => "coolbeans" }
|
|
318
|
+
#
|
|
319
|
+
# this method would return:
|
|
320
|
+
#
|
|
321
|
+
# { :name => { "driver" => "coolbeans" } }
|
|
322
|
+
#
|
|
323
|
+
#
|
|
324
|
+
# @param hash [Hash] the Hash to normalize
|
|
325
|
+
# @param key [Symbol] the key to normalize
|
|
326
|
+
# @param value [Object] the value to normalize
|
|
327
|
+
# @api private
|
|
328
|
+
def normalize_hash(hash, key, value)
|
|
329
|
+
case key
|
|
330
|
+
when "driver", "provisioner", "busser"
|
|
331
|
+
hash[key] = if value.nil?
|
|
332
|
+
{}
|
|
333
|
+
elsif value.is_a?(String)
|
|
334
|
+
default_key = key == "busser" ? "version" : "name"
|
|
335
|
+
{ default_key => value }
|
|
336
|
+
else
|
|
337
|
+
normalize(value)
|
|
338
|
+
end
|
|
339
|
+
else
|
|
340
|
+
hash[key] = normalize(value)
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Parses a YAML string and returns a Hash.
|
|
345
|
+
#
|
|
346
|
+
# @param string [String] a yaml document as a string
|
|
347
|
+
# @param file_name [String] an absolute path to the file represented as
|
|
348
|
+
# the passed in string, used for error reporting
|
|
349
|
+
# @return [Hash] a hash
|
|
350
|
+
# @raise [UserError] if the string document cannot be parsed
|
|
351
|
+
# @api private
|
|
352
|
+
def parse_yaml_string(string, file_name)
|
|
353
|
+
return {} if string.nil? || string.empty?
|
|
354
|
+
|
|
355
|
+
result =
|
|
356
|
+
if Gem::Requirement.new(">= 3.1.0").satisfied_by?(Gem::Version.new(Psych::VERSION))
|
|
357
|
+
# ruby >= 2.6.0
|
|
358
|
+
::YAML.safe_load(string, permitted_classes: [Symbol], permitted_symbols: [], aliases: true) || {}
|
|
359
|
+
else
|
|
360
|
+
# ruby < 2.6.0
|
|
361
|
+
::YAML.safe_load(string, [Symbol], [], true) || {}
|
|
362
|
+
end
|
|
363
|
+
unless result.is_a?(Hash)
|
|
364
|
+
raise UserError, "Error parsing #{file_name} as YAML " \
|
|
365
|
+
"(Result of parse was not a Hash, but was a #{result.class}).\n" \
|
|
366
|
+
"Please run `kitchen diagnose --no-instances --loader' to help " \
|
|
367
|
+
"debug your issue."
|
|
368
|
+
end
|
|
369
|
+
result
|
|
370
|
+
rescue SyntaxError, Psych::SyntaxError, Psych::DisallowedClass
|
|
371
|
+
raise UserError, "Error parsing #{file_name} as YAML.\n" \
|
|
372
|
+
"Please run `kitchen diagnose --no-instances --loader' to help " \
|
|
373
|
+
"debug your issue."
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|