test-kitchen-rsync 3.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +21 -0
  3. data/LICENSE +15 -0
  4. data/Rakefile +53 -0
  5. data/bin/zl-kitchen +11 -0
  6. data/lib/kitchen/base64_stream.rb +48 -0
  7. data/lib/kitchen/chef_utils_wiring.rb +40 -0
  8. data/lib/kitchen/cli.rb +413 -0
  9. data/lib/kitchen/collection.rb +52 -0
  10. data/lib/kitchen/color.rb +63 -0
  11. data/lib/kitchen/command/action.rb +41 -0
  12. data/lib/kitchen/command/console.rb +54 -0
  13. data/lib/kitchen/command/diagnose.rb +84 -0
  14. data/lib/kitchen/command/doctor.rb +39 -0
  15. data/lib/kitchen/command/exec.rb +37 -0
  16. data/lib/kitchen/command/list.rb +148 -0
  17. data/lib/kitchen/command/login.rb +39 -0
  18. data/lib/kitchen/command/package.rb +32 -0
  19. data/lib/kitchen/command/sink.rb +50 -0
  20. data/lib/kitchen/command/test.rb +47 -0
  21. data/lib/kitchen/command.rb +207 -0
  22. data/lib/kitchen/config.rb +344 -0
  23. data/lib/kitchen/configurable.rb +616 -0
  24. data/lib/kitchen/data_munger.rb +1024 -0
  25. data/lib/kitchen/diagnostic.rb +138 -0
  26. data/lib/kitchen/driver/base.rb +133 -0
  27. data/lib/kitchen/driver/dummy.rb +105 -0
  28. data/lib/kitchen/driver/exec.rb +70 -0
  29. data/lib/kitchen/driver/proxy.rb +70 -0
  30. data/lib/kitchen/driver/ssh_base.rb +351 -0
  31. data/lib/kitchen/driver.rb +40 -0
  32. data/lib/kitchen/errors.rb +243 -0
  33. data/lib/kitchen/generator/init.rb +254 -0
  34. data/lib/kitchen/instance.rb +726 -0
  35. data/lib/kitchen/lazy_hash.rb +148 -0
  36. data/lib/kitchen/lifecycle_hook/base.rb +78 -0
  37. data/lib/kitchen/lifecycle_hook/local.rb +53 -0
  38. data/lib/kitchen/lifecycle_hook/remote.rb +39 -0
  39. data/lib/kitchen/lifecycle_hooks.rb +92 -0
  40. data/lib/kitchen/loader/yaml.rb +377 -0
  41. data/lib/kitchen/logger.rb +422 -0
  42. data/lib/kitchen/logging.rb +52 -0
  43. data/lib/kitchen/login_command.rb +49 -0
  44. data/lib/kitchen/metadata_chopper.rb +49 -0
  45. data/lib/kitchen/platform.rb +64 -0
  46. data/lib/kitchen/plugin.rb +76 -0
  47. data/lib/kitchen/plugin_base.rb +60 -0
  48. data/lib/kitchen/provisioner/base.rb +269 -0
  49. data/lib/kitchen/provisioner/chef/berkshelf.rb +116 -0
  50. data/lib/kitchen/provisioner/chef/common_sandbox.rb +350 -0
  51. data/lib/kitchen/provisioner/chef/policyfile.rb +163 -0
  52. data/lib/kitchen/provisioner/chef_apply.rb +121 -0
  53. data/lib/kitchen/provisioner/chef_base.rb +705 -0
  54. data/lib/kitchen/provisioner/chef_infra.rb +167 -0
  55. data/lib/kitchen/provisioner/chef_solo.rb +82 -0
  56. data/lib/kitchen/provisioner/chef_zero.rb +12 -0
  57. data/lib/kitchen/provisioner/dummy.rb +75 -0
  58. data/lib/kitchen/provisioner/shell.rb +157 -0
  59. data/lib/kitchen/provisioner.rb +42 -0
  60. data/lib/kitchen/rake_tasks.rb +80 -0
  61. data/lib/kitchen/shell_out.rb +90 -0
  62. data/lib/kitchen/ssh.rb +289 -0
  63. data/lib/kitchen/state_file.rb +112 -0
  64. data/lib/kitchen/suite.rb +48 -0
  65. data/lib/kitchen/thor_tasks.rb +63 -0
  66. data/lib/kitchen/transport/base.rb +236 -0
  67. data/lib/kitchen/transport/dummy.rb +78 -0
  68. data/lib/kitchen/transport/exec.rb +145 -0
  69. data/lib/kitchen/transport/ssh.rb +579 -0
  70. data/lib/kitchen/transport/winrm.rb +546 -0
  71. data/lib/kitchen/transport.rb +40 -0
  72. data/lib/kitchen/util.rb +229 -0
  73. data/lib/kitchen/verifier/base.rb +243 -0
  74. data/lib/kitchen/verifier/busser.rb +275 -0
  75. data/lib/kitchen/verifier/dummy.rb +75 -0
  76. data/lib/kitchen/verifier/shell.rb +99 -0
  77. data/lib/kitchen/verifier.rb +39 -0
  78. data/lib/kitchen/version.rb +20 -0
  79. data/lib/kitchen/which.rb +26 -0
  80. data/lib/kitchen.rb +152 -0
  81. data/lib/vendor/hash_recursive_merge.rb +79 -0
  82. data/support/busser_install_command.ps1 +14 -0
  83. data/support/busser_install_command.sh +21 -0
  84. data/support/chef-client-fail-if-update-handler.rb +15 -0
  85. data/support/chef_base_init_command.ps1 +18 -0
  86. data/support/chef_base_init_command.sh +1 -0
  87. data/support/chef_base_install_command.ps1 +85 -0
  88. data/support/chef_base_install_command.sh +229 -0
  89. data/support/download_helpers.sh +109 -0
  90. data/support/dummy-validation.pem +27 -0
  91. data/templates/driver/CHANGELOG.md.erb +3 -0
  92. data/templates/driver/Gemfile.erb +3 -0
  93. data/templates/driver/README.md.erb +64 -0
  94. data/templates/driver/Rakefile.erb +21 -0
  95. data/templates/driver/driver.rb.erb +23 -0
  96. data/templates/driver/gemspec.erb +29 -0
  97. data/templates/driver/gitignore.erb +17 -0
  98. data/templates/driver/license_apachev2.erb +15 -0
  99. data/templates/driver/license_lgplv3.erb +16 -0
  100. data/templates/driver/license_mit.erb +22 -0
  101. data/templates/driver/license_reserved.erb +5 -0
  102. data/templates/driver/tailor.erb +4 -0
  103. data/templates/driver/travis.yml.erb +11 -0
  104. data/templates/driver/version.rb.erb +12 -0
  105. data/templates/init/chefignore.erb +2 -0
  106. data/templates/init/kitchen.yml.erb +18 -0
  107. data/test-kitchen.gemspec +52 -0
  108. metadata +528 -0
@@ -0,0 +1,76 @@
1
+ #
2
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
+ #
4
+ # Copyright (C) 2012, Fletcher Nichol
5
+ # Copyright (C) 2018, Chef Software
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative "errors"
20
+ require_relative "util"
21
+
22
+ module Kitchen
23
+ module Plugin
24
+ # Returns an instance of a plugin given a type, name, and config.
25
+ #
26
+ # @param type [Module] a Kitchen::<Module> of one of the plugin types
27
+ # (Driver, Provisioner, Transport, Verifier)
28
+ # @param plugin [String] a plugin name, which will be constantized
29
+ # @param config [Hash] a configuration hash to initialize the plugin
30
+ # @return [Kitchen::<Module>::Base] a plugin instance
31
+ # @raise [ClientError] if a plugin instance could not be created
32
+ # @raise [UserError] if the plugin's dependencies could not be met
33
+ def self.load(type, plugin, config)
34
+ type_name = Kitchen::Util.snake_case(type.name.split("::").last)
35
+ first_load = require("kitchen/#{type_name}/#{plugin}")
36
+
37
+ str_const = Kitchen::Util.camel_case(plugin)
38
+ klass = type.const_get(str_const)
39
+ object = klass.new(config)
40
+ object.verify_dependencies if first_load
41
+ object
42
+ rescue UserError
43
+ raise
44
+ rescue NameError => e
45
+ raise ClientError, "Could not load the '#{plugin}' #{type_name}. Error: #{e.message}"
46
+ rescue LoadError => e
47
+ available_plugins = plugins_available(type_name)
48
+ error_message = if available_plugins.include?(plugin)
49
+ e.message
50
+ else
51
+ " Did you mean: #{available_plugins.join(", ")} ?" \
52
+ " Please ensure that your #{type_name} is installed as a gem or included" \
53
+ " in your Gemfile if using Bundler."
54
+ end
55
+ raise ClientError, "Could not load the '#{plugin}' #{type_name} from the load path." + error_message
56
+ end
57
+
58
+ # given a type of plugin, searches the Ruby load path for plugins of that
59
+ # type based on the path+naming convention that plugin loading is based upon
60
+ #
61
+ # @param plugin_type [String] the name of a plugin type (e.g. driver,
62
+ # provisioner, transport, verifier)
63
+ # @return [Array<String>] a collection of Ruby filenames that are probably
64
+ # plugins of the given type
65
+ def self.plugins_available(plugin_type)
66
+ $LOAD_PATH.map { |load_path| Dir[File.expand_path("kitchen/#{plugin_type}/*.rb", load_path)] }
67
+ .reject(&:empty?)
68
+ .flatten
69
+ .uniq
70
+ .select { |plugin_path| File.readlines(plugin_path).grep(/^\s*class \w* </).any? }
71
+ .map { |plugin_path| File.basename(plugin_path).gsub(/\.rb$/, "") }
72
+ .reject { |plugin_name| plugin_name == "base" }
73
+ .sort
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
+ #
4
+ # Copyright (C) 2014, 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
+ module Kitchen
19
+ module Plugin
20
+ class Base
21
+ class << self
22
+ # @return [Array<Symbol>] an array of action method names that cannot
23
+ # be run concurrently and must be run in serial via a shared mutex
24
+ attr_reader :serial_actions
25
+ end
26
+
27
+ # Registers certain driver actions that cannot be safely run concurrently
28
+ # in threads across multiple instances. Typically this might be used
29
+ # for create or destroy actions that use an underlying resource that
30
+ # cannot be used at the same time.
31
+ #
32
+ # A shared mutex for this driver object will be used to synchronize all
33
+ # registered methods.
34
+ #
35
+ # @example a single action method that cannot be run concurrently
36
+ #
37
+ # no_parallel_for :create
38
+ #
39
+ # @example multiple action methods that cannot be run concurrently
40
+ #
41
+ # no_parallel_for :create, :destroy
42
+ #
43
+ # @param methods [Array<Symbol>] one or more actions as symbols
44
+ # @raise [ClientError] if any method is not a valid action method name
45
+ def self.no_parallel_for(*methods)
46
+ action_methods = %i{create setup converge verify destroy}
47
+
48
+ Array(methods).each do |meth|
49
+ next if action_methods.include?(meth)
50
+
51
+ raise ClientError, "##{meth} is not a valid no_parallel_for method"
52
+ end
53
+
54
+ @serial_actions ||= []
55
+ @serial_actions += methods
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,269 @@
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_relative "../configurable"
19
+ require_relative "../errors"
20
+ require_relative "../logging"
21
+ require_relative "../plugin_base"
22
+
23
+ module Kitchen
24
+ module Provisioner
25
+ # Base class for a provisioner.
26
+ #
27
+ # @author Fletcher Nichol <fnichol@nichol.ca>
28
+ class Base < Kitchen::Plugin::Base
29
+ include Configurable
30
+ include Logging
31
+
32
+ default_config :http_proxy, nil
33
+ default_config :https_proxy, nil
34
+ default_config :ftp_proxy, nil
35
+
36
+ default_config :retry_on_exit_code, []
37
+ default_config :max_retries, 1
38
+ default_config :wait_for_retry, 30
39
+
40
+ default_config :root_path do |provisioner|
41
+ provisioner.windows_os? ? '$env:TEMP\\kitchen' : "/tmp/kitchen"
42
+ end
43
+
44
+ default_config :sudo do |provisioner|
45
+ provisioner.windows_os? ? nil : true
46
+ end
47
+
48
+ default_config :sudo_command do |provisioner|
49
+ provisioner.windows_os? ? nil : "sudo -E"
50
+ end
51
+
52
+ default_config :command_prefix, nil
53
+
54
+ default_config :uploads, {}
55
+ default_config :downloads, {}
56
+
57
+ expand_path_for :test_base_path
58
+
59
+ # Constructs a new provisioner by providing a configuration hash.
60
+ #
61
+ # @param config [Hash] initial provided configuration
62
+ def initialize(config = {})
63
+ init_config(config)
64
+ end
65
+
66
+ # Runs the provisioner on the instance.
67
+ #
68
+ # @param state [Hash] mutable instance state
69
+ # @raise [ActionFailed] if the action could not be completed
70
+ # rubocop:disable Metrics/AbcSize
71
+ def call(state)
72
+ create_sandbox
73
+ sandbox_dirs = Util.list_directory(sandbox_path)
74
+
75
+ instance.transport.connection(state) do |conn|
76
+ config[:uploads].to_h.each do |locals, remote|
77
+ debug("Uploading #{Array(locals).join(", ")} to #{remote}")
78
+ conn.upload(locals.to_s, remote)
79
+ end
80
+ conn.execute(install_command)
81
+ conn.execute(init_command)
82
+ info("Transferring files to #{instance.to_str} using rsync")
83
+ conn.rsyn_chef_repo(sandbox_path, config[:root_path])
84
+ debug("Transfer complete")
85
+ conn.execute(prepare_command)
86
+ conn.execute_with_retry(
87
+ run_command,
88
+ config[:retry_on_exit_code],
89
+ config[:max_retries],
90
+ config[:wait_for_retry]
91
+ )
92
+ info("Downloading files from #{instance.to_str}")
93
+ config[:downloads].to_h.each do |remotes, local|
94
+ debug("Downloading #{Array(remotes).join(", ")} to #{local}")
95
+ conn.download(remotes, local)
96
+ end
97
+ debug("Download complete")
98
+ end
99
+ rescue Kitchen::Transport::TransportFailed => ex
100
+ raise ActionFailed, ex.message
101
+ ensure
102
+ cleanup_sandbox
103
+ end
104
+
105
+ # Check system and configuration for common errors.
106
+ #
107
+ # @param state [Hash] mutable instance state
108
+ # @returns [Boolean] Return true if a problem is found.
109
+ def doctor(state)
110
+ false
111
+ end
112
+
113
+ # Certain products that Test Kitchen uses to provision require accepting
114
+ # a license to use. Overwrite this method in the specific provisioner
115
+ # to implement this check.
116
+ def check_license; end
117
+
118
+ # Generates a command string which will install and configure the
119
+ # provisioner software on an instance. If no work is required, then `nil`
120
+ # will be returned.
121
+ #
122
+ # @return [String] a command string
123
+ def install_command; end
124
+
125
+ # Generates a command string which will perform any data initialization
126
+ # or configuration required after the provisioner software is installed
127
+ # but before the sandbox has been transferred to the instance. If no work
128
+ # is required, then `nil` will be returned.
129
+ #
130
+ # @return [String] a command string
131
+ def init_command; end
132
+
133
+ # Generates a command string which will perform any commands or
134
+ # configuration required just before the main provisioner run command but
135
+ # after the sandbox has been transferred to the instance. If no work is
136
+ # required, then `nil` will be returned.
137
+ #
138
+ # @return [String] a command string
139
+ def prepare_command; end
140
+
141
+ # Generates a command string which will invoke the main provisioner
142
+ # command on the prepared instance. If no work is required, then `nil`
143
+ # will be returned.
144
+ #
145
+ # @return [String] a command string
146
+ def run_command; end
147
+
148
+ # Creates a temporary directory on the local workstation into which
149
+ # provisioner related files and directories can be copied or created. The
150
+ # contents of this directory will be copied over to the instance before
151
+ # invoking the provisioner's run command. After this method completes, it
152
+ # is expected that the contents of the sandbox is complete and ready for
153
+ # copy to the remote instance.
154
+ #
155
+ # **Note:** any subclasses would be well advised to call super first when
156
+ # overriding this method, for example:
157
+ #
158
+ # @example overriding `#create_sandbox`
159
+ #
160
+ # class MyProvisioner < Kitchen::Provisioner::Base
161
+ # def create_sandbox
162
+ # super
163
+ # # any further file copies, preparations, etc.
164
+ # end
165
+ # end
166
+ def create_sandbox
167
+ @sandbox_path = Dir.mktmpdir("#{instance.name}-sandbox-")
168
+ File.chmod(0755, sandbox_path)
169
+ info("Preparing files for transfer")
170
+ debug("Creating local sandbox in #{sandbox_path}")
171
+ end
172
+
173
+ # Returns the absolute path to the sandbox directory or raises an
174
+ # exception if `#create_sandbox` has not yet been called.
175
+ #
176
+ # @return [String] the absolute path to the sandbox directory
177
+ # @raise [ClientError] if the sandbox directory has no yet been created
178
+ # by calling `#create_sandbox`
179
+ def sandbox_path
180
+ @sandbox_path ||= raise ClientError, "Sandbox directory has not yet " \
181
+ "been created. Please run #{self.class}#create_sandox before " \
182
+ "trying to access the path."
183
+ end
184
+
185
+ # Deletes the sandbox path. Without calling this method, the sandbox path
186
+ # will persist after the process terminates. In other words, cleanup is
187
+ # explicit. This method is safe to call multiple times.
188
+ def cleanup_sandbox
189
+ return if sandbox_path.nil?
190
+
191
+ debug("Cleaning up local sandbox in #{sandbox_path}")
192
+ FileUtils.rmtree(sandbox_path)
193
+ end
194
+
195
+ # Sets the API version for this provisioner. If the provisioner does not
196
+ # set this value, then `nil` will be used and reported.
197
+ #
198
+ # Sets the API version for this provisioner
199
+ #
200
+ # @example setting an API version
201
+ #
202
+ # module Kitchen
203
+ # module Provisioner
204
+ # class NewProvisioner < Kitchen::Provisioner::Base
205
+ #
206
+ # kitchen_provisioner_api_version 2
207
+ #
208
+ # end
209
+ # end
210
+ # end
211
+ #
212
+ # @param version [Integer,String] a version number
213
+ #
214
+ def self.kitchen_provisioner_api_version(version)
215
+ @api_version = version
216
+ end
217
+
218
+ private
219
+
220
+ # Builds a complete command given a variables String preamble and a file
221
+ # containing shell code.
222
+ #
223
+ # @param vars [String] shell variables, as a String
224
+ # @param file [String] file basename (without extension) containing
225
+ # shell code
226
+ # @return [String] command
227
+ # @api private
228
+ def shell_code_from_file(vars, file)
229
+ src_file = File.join(
230
+ File.dirname(__FILE__),
231
+ %w{.. .. .. support},
232
+ file + (powershell_shell? ? ".ps1" : ".sh")
233
+ )
234
+
235
+ wrap_shell_code([vars, "", IO.read(src_file)].join("\n"))
236
+ end
237
+
238
+ # Conditionally prefixes a command with a sudo command.
239
+ #
240
+ # @param command [String] command to be prefixed
241
+ # @return [String] the command, conditionally prefixed with sudo
242
+ # @api private
243
+ def sudo(script)
244
+ "#{sudo_command} #{script}".lstrip
245
+ end
246
+
247
+ # Returns the sudo command to use or empty string if sudo is not configured
248
+ #
249
+ # @return [String] the sudo command if sudo config is true
250
+ # @api private
251
+ def sudo_command
252
+ config[:sudo] ? config[:sudo_command].to_s : ""
253
+ end
254
+
255
+ # Conditionally prefixes a command with a command prefix.
256
+ # This should generally be done after a command has been
257
+ # conditionally prefixed by #sudo as certain platforms, such as
258
+ # Cisco Nexus, require all commands to be run with a prefix to
259
+ # obtain outbound network access.
260
+ #
261
+ # @param command [String] command to be prefixed
262
+ # @return [String] the command, conditionally prefixed with the configured prefix
263
+ # @api private
264
+ def prefix_command(script)
265
+ config[:command_prefix] ? "#{config[:command_prefix]} #{script}" : script
266
+ end
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,116 @@
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_relative "../../errors"
19
+ require_relative "../../logging"
20
+
21
+ module Kitchen
22
+ module Provisioner
23
+ module Chef
24
+ # Chef cookbook resolver that uses Berkshelf and a Berksfile to calculate
25
+ # dependencies.
26
+ #
27
+ # @author Fletcher Nichol <fnichol@nichol.ca>
28
+ class Berkshelf
29
+ include Logging
30
+
31
+ # Creates a new cookbook resolver.
32
+ #
33
+ # @param berksfile [String] path to a Berksfile
34
+ # @param path [String] path in which to vendor the resulting
35
+ # cookbooks
36
+ # @param logger [Kitchen::Logger] a logger to use for output, defaults
37
+ # to `Kitchen.logger`
38
+ def initialize(berksfile, path, logger: Kitchen.logger, always_update: false)
39
+ @berksfile = berksfile
40
+ @path = path
41
+ @logger = logger
42
+ @always_update = always_update
43
+ end
44
+
45
+ # Loads the library code required to use the resolver.
46
+ #
47
+ # @param logger [Kitchen::Logger] a logger to use for output, defaults
48
+ # to `Kitchen.logger`
49
+ def self.load!(logger: Kitchen.logger)
50
+ load_berkshelf!(logger)
51
+ end
52
+
53
+ # Performs the cookbook resolution and vendors the resulting cookbooks
54
+ # in the desired path.
55
+ def resolve
56
+ version = ::Berkshelf::VERSION
57
+ info("Resolving cookbook dependencies with Berkshelf #{version}...")
58
+ debug("Using Berksfile from #{berksfile}")
59
+
60
+ ::Berkshelf.ui.mute do
61
+ berksfile_obj = ::Berkshelf::Berksfile.from_file(berksfile)
62
+ berksfile_obj.update if always_update && berksfile_obj.lockfile.present?
63
+ # Berkshelf requires the directory to not exist
64
+ FileUtils.rm_rf(path)
65
+ berksfile_obj.vendor(path)
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ # @return [String] path to a Berksfile
72
+ # @api private
73
+ attr_reader :berksfile
74
+
75
+ # @return [String] path in which to vendor the resulting cookbooks
76
+ # @api private
77
+ attr_reader :path
78
+
79
+ # @return [Kitchen::Logger] a logger to use for output
80
+ # @api private
81
+ attr_reader :logger
82
+
83
+ # @return [Boolean] If true, always update cookbooks in Berkshelf.
84
+ # @api private
85
+ attr_reader :always_update
86
+
87
+ class << self
88
+ private
89
+
90
+ # Load the Berkshelf-specific libary code.
91
+ #
92
+ # @param logger [Kitchen::Logger] the logger to use
93
+ # @raise [UserError] if the library couldn't be loaded
94
+ # @api private
95
+ def load_berkshelf!(logger)
96
+ first_load = require "berkshelf"
97
+
98
+ version = ::Berkshelf::VERSION
99
+ if first_load
100
+ logger.debug("Berkshelf #{version} library loaded")
101
+ else
102
+ logger.debug("Berkshelf #{version} previously loaded")
103
+ end
104
+ rescue LoadError => e
105
+ logger.fatal("The `berkshelf' gem is missing and must be installed" \
106
+ " or cannot be properly activated. Run" \
107
+ " `gem install berkshelf` or add the following to your" \
108
+ " Gemfile if you are using Bundler: `gem 'berkshelf'`.")
109
+ raise UserError,
110
+ "Could not load or activate Berkshelf (#{e.message})"
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end