berkshelf 0.3.7 → 0.4.0.rc1
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.
- data/.gitignore +2 -1
- data/README.md +8 -0
- data/Thorfile +2 -2
- data/berkshelf.gemspec +1 -1
- data/features/install.feature +102 -2
- data/features/lockfile.feature +1 -1
- data/features/step_definitions/chef_server_steps.rb +8 -0
- data/features/step_definitions/cli_steps.rb +1 -1
- data/features/step_definitions/filesystem_steps.rb +12 -0
- data/features/support/env.rb +8 -10
- data/features/update.feature +1 -1
- data/lib/berkshelf.rb +19 -1
- data/lib/berkshelf/berksfile.rb +18 -6
- data/lib/berkshelf/cli.rb +3 -8
- data/lib/berkshelf/cookbook_source.rb +108 -23
- data/lib/berkshelf/cookbook_source/chef_api_location.rb +256 -0
- data/lib/berkshelf/cookbook_source/git_location.rb +14 -2
- data/lib/berkshelf/cookbook_source/location.rb +119 -2
- data/lib/berkshelf/cookbook_source/path_location.rb +6 -1
- data/lib/berkshelf/cookbook_source/site_location.rb +36 -105
- data/lib/berkshelf/cookbook_store.rb +7 -12
- data/lib/berkshelf/dsl.rb +1 -1
- data/lib/berkshelf/errors.rb +2 -0
- data/lib/berkshelf/init_generator.rb +6 -6
- data/lib/berkshelf/resolver.rb +8 -34
- data/lib/berkshelf/uploader.rb +7 -7
- data/lib/berkshelf/version.rb +1 -1
- data/spec/fixtures/reset.pem +27 -0
- data/spec/knife.rb.sample +12 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/support/chef_api.rb +32 -0
- data/spec/support/knife.rb +18 -0
- data/spec/unit/berkshelf/cookbook_source/chef_api_location_spec.rb +243 -0
- data/spec/unit/berkshelf/cookbook_source/git_location_spec.rb +2 -2
- data/spec/unit/berkshelf/cookbook_source/location_spec.rb +130 -2
- data/spec/unit/berkshelf/cookbook_source/path_location_spec.rb +2 -2
- data/spec/unit/berkshelf/cookbook_source/site_location_spec.rb +22 -105
- data/spec/unit/berkshelf/cookbook_source_spec.rb +140 -71
- data/spec/unit/berkshelf/cookbook_store_spec.rb +6 -6
- data/spec/unit/berkshelf/resolver_spec.rb +9 -30
- data/spec/unit/berkshelf/uploader_spec.rb +1 -10
- data/spec/unit/berkshelf_spec.rb +21 -1
- metadata +19 -15
- data/features/config.sample.yml +0 -3
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# Berkshelf
|
2
|
+
[](https://codeclimate.com/github/RiotGames/berkshelf)
|
2
3
|
|
3
4
|
Manage a Cookbook or an Application's Cookbook dependencies
|
4
5
|
|
@@ -33,8 +34,15 @@ Bundler will install all gems and their dependencies required for testing and de
|
|
33
34
|
|
34
35
|
### Running unit (RSpec) and acceptance (Cucumber) tests
|
35
36
|
|
37
|
+
Simply copy the `spec/knife.rb.sample` to `spec/knife.rb`, and point it at a
|
38
|
+
chef server. Berkshelf tests may upload and destroy cookbooks on your chef
|
39
|
+
server, so be sure to configure a server safe for this task.
|
40
|
+
|
36
41
|
$ bundle exec guard start
|
37
42
|
|
43
|
+
See [here](https://github.com/tdegrunt/vagrant-chef-server-bootstrap) for a
|
44
|
+
quick way to get a testing chef server up.
|
45
|
+
|
38
46
|
# Authors and Contributors
|
39
47
|
|
40
48
|
* Josiah Kiehl (<josiah@skirmisher.net>)
|
data/Thorfile
CHANGED
@@ -33,7 +33,7 @@ class Default < Thor
|
|
33
33
|
|
34
34
|
desc "cucumber", "Run Cucumber features"
|
35
35
|
def cucumber
|
36
|
-
exec "cucumber --color --format
|
36
|
+
exec "cucumber --color --format progress --tags ~@no_run"
|
37
37
|
end
|
38
38
|
|
39
39
|
class VCR < Thor
|
@@ -41,7 +41,7 @@ class Default < Thor
|
|
41
41
|
|
42
42
|
desc "clean", "clean VCR cassettes"
|
43
43
|
def clean
|
44
|
-
FileUtils.rm_rf("spec/fixtures/vcr_cassettes
|
44
|
+
FileUtils.rm_rf("spec/fixtures/vcr_cassettes")
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
data/berkshelf.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.version = Berkshelf::VERSION
|
17
17
|
s.required_ruby_version = ">= 1.9.1"
|
18
18
|
|
19
|
-
s.add_runtime_dependency '
|
19
|
+
s.add_runtime_dependency 'solve', '~> 0.2.1'
|
20
20
|
s.add_runtime_dependency 'chef', '~> 10.12.0'
|
21
21
|
s.add_runtime_dependency 'minitar'
|
22
22
|
s.add_runtime_dependency 'thor', '~> 0.15.2'
|
data/features/install.feature
CHANGED
@@ -71,8 +71,8 @@ Feature: install cookbooks from a Berksfile
|
|
71
71
|
cookbook "artifact", git: "git://github.com/RiotGames/artifact-cookbook.git", ref: "0.9.8"
|
72
72
|
"""
|
73
73
|
When I run the install command
|
74
|
-
Then the cookbook store should have the cookbooks:
|
75
|
-
| artifact | 0.9.8 |
|
74
|
+
Then the cookbook store should have the git cookbooks:
|
75
|
+
| artifact | 0.9.8 | c0a0b456a4716a81645bef1369f5fd1a4e62ce6d |
|
76
76
|
And the output should contain:
|
77
77
|
"""
|
78
78
|
Installing artifact (0.9.8) from git: 'git://github.com/RiotGames/artifact-cookbook.git' with branch: '0.9.8'
|
@@ -147,6 +147,29 @@ Feature: install cookbooks from a Berksfile
|
|
147
147
|
"""
|
148
148
|
And the exit status should be 0
|
149
149
|
|
150
|
+
Scenario: running install with --shims when current project is a cookbook and the 'metadata' is specified
|
151
|
+
Given a cookbook named "sparkle_motion"
|
152
|
+
And the cookbook "sparkle_motion" has the file "Berksfile" with:
|
153
|
+
"""
|
154
|
+
metadata
|
155
|
+
"""
|
156
|
+
When I cd to "sparkle_motion"
|
157
|
+
And I run the install command with flags:
|
158
|
+
| --shims |
|
159
|
+
Then the following directories should exist:
|
160
|
+
| cookbooks |
|
161
|
+
| cookbooks/sparkle_motion |
|
162
|
+
And the output should contain:
|
163
|
+
"""
|
164
|
+
Shims written to:
|
165
|
+
"""
|
166
|
+
And the output should contain:
|
167
|
+
"""
|
168
|
+
Using sparkle_motion (0.0.0) at path:
|
169
|
+
"""
|
170
|
+
And the exit status should be 0
|
171
|
+
|
172
|
+
|
150
173
|
Scenario: installing a Berksfile that has a Git location source with an invalid Git URI
|
151
174
|
Given I write to "Berksfile" with:
|
152
175
|
"""
|
@@ -197,3 +220,80 @@ Feature: install cookbooks from a Berksfile
|
|
197
220
|
Installing artifact (0.10.0) from git: 'git://github.com/RiotGames/artifact-cookbook.git' with branch: '0.10.0'
|
198
221
|
"""
|
199
222
|
And the exit status should be 0
|
223
|
+
|
224
|
+
Scenario: with a cookbook definition containing an invalid option
|
225
|
+
Given I write to "Berksfile" with:
|
226
|
+
"""
|
227
|
+
cookbook "artifact", whatisthis: "I don't even know", anotherwat: "isthat"
|
228
|
+
"""
|
229
|
+
When I run the install command
|
230
|
+
Then the output should contain:
|
231
|
+
"""
|
232
|
+
Invalid options for Cookbook Source: 'whatisthis', 'anotherwat'.
|
233
|
+
"""
|
234
|
+
And the CLI should exit with the status code for error "InternalError"
|
235
|
+
|
236
|
+
Scenario: with a cookbook definition containing a chef_api source location
|
237
|
+
Given I write to "Berksfile" with:
|
238
|
+
"""
|
239
|
+
cookbook "artifact", chef_api: :knife
|
240
|
+
"""
|
241
|
+
And the Chef server has cookbooks:
|
242
|
+
| artifact | 0.10.0 |
|
243
|
+
When I run the install command
|
244
|
+
Then the output should contain:
|
245
|
+
"""
|
246
|
+
Installing artifact (0.10.0) from chef_api:
|
247
|
+
"""
|
248
|
+
And the cookbook store should have the cookbooks:
|
249
|
+
| artifact | 0.10.0 |
|
250
|
+
And the exit status should be 0
|
251
|
+
|
252
|
+
Scenario: with a chef_api source location specifying :knife when a Knife config is not found at the given path
|
253
|
+
Given I write to "Berksfile" with:
|
254
|
+
"""
|
255
|
+
cookbook "artifact", chef_api: :knife
|
256
|
+
"""
|
257
|
+
When I run the install command with flags:
|
258
|
+
| -c /tmp/nothere.lol |
|
259
|
+
Then the output should contain:
|
260
|
+
"""
|
261
|
+
A Knife config is required when ':knife' is given for the value of a 'chef_api' location. Attempted to load configuration from: '/tmp/nothere.lol' but not found.
|
262
|
+
"""
|
263
|
+
And the CLI should exit with the status code for error "KnifeConfigNotFound"
|
264
|
+
|
265
|
+
Scenario: with a chef_api source location specifying a Chef API URL but missing a node_name option
|
266
|
+
Given I write to "Berksfile" with:
|
267
|
+
"""
|
268
|
+
cookbook "artifact", chef_api: "https://api.opscode.com/organizations/vialstudios", client_key: "/Users/reset/.chef/knife.rb"
|
269
|
+
"""
|
270
|
+
When I run the install command
|
271
|
+
Then the output should contain:
|
272
|
+
"""
|
273
|
+
Source 'artifact' is a 'chef_api' location with a URL for it's value but is missing options: 'node_name'.
|
274
|
+
"""
|
275
|
+
And the CLI should exit with the status code for error "InvalidChefAPILocation"
|
276
|
+
|
277
|
+
Scenario: with a chef_api source location specifying a Chef API URL but missing a client_key option
|
278
|
+
Given I write to "Berksfile" with:
|
279
|
+
"""
|
280
|
+
cookbook "artifact", chef_api: "https://api.opscode.com/organizations/vialstudios", node_name: "reset"
|
281
|
+
"""
|
282
|
+
When I run the install command
|
283
|
+
Then the output should contain:
|
284
|
+
"""
|
285
|
+
Source 'artifact' is a 'chef_api' location with a URL for it's value but is missing options: 'client_key'.
|
286
|
+
"""
|
287
|
+
And the CLI should exit with the status code for error "InvalidChefAPILocation"
|
288
|
+
|
289
|
+
Scenario: with a chef_api source location specifying a Chef API URL but missing a client_key option
|
290
|
+
Given I write to "Berksfile" with:
|
291
|
+
"""
|
292
|
+
cookbook "artifact", chef_api: "https://api.opscode.com/organizations/vialstudios"
|
293
|
+
"""
|
294
|
+
When I run the install command
|
295
|
+
Then the output should contain:
|
296
|
+
"""
|
297
|
+
Source 'artifact' is a 'chef_api' location with a URL for it's value but is missing options: 'node_name', 'client_key'.
|
298
|
+
"""
|
299
|
+
And the CLI should exit with the status code for error "InvalidChefAPILocation"
|
data/features/lockfile.feature
CHANGED
@@ -17,6 +17,6 @@ Feature: Berksfile.lock
|
|
17
17
|
cookbook 'ntp', :locked_version => '1.1.8'
|
18
18
|
cookbook 'mysql', :git => 'https://github.com/opscode-cookbooks/mysql.git', :ref => '190c0c2267785b7b9b303369b8a64ed04364d5f9'
|
19
19
|
cookbook 'openssl', :locked_version => '1.0.0'
|
20
|
-
cookbook 'windows', :locked_version => '1.3.
|
20
|
+
cookbook 'windows', :locked_version => '1.3.2'
|
21
21
|
cookbook 'chef_handler', :locked_version => '1.0.6'
|
22
22
|
"""
|
@@ -6,6 +6,14 @@ Given /^the Chef server does not have the cookbooks:$/ do |cookbooks|
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
+
Given /^the Chef server has cookbooks:$/ do |cookbooks|
|
10
|
+
cookbooks.raw.each do |name, version|
|
11
|
+
purge_cookbook(name, version)
|
12
|
+
cb_path = generate_cookbook(tmp_path, name, version)
|
13
|
+
upload_cookbook(cb_path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
Then /^the Chef server should have the cookbooks:$/ do |cookbooks|
|
10
18
|
cookbooks.raw.each do |name, version|
|
11
19
|
server_has_cookbook?(name, version).should be_true
|
@@ -43,7 +43,7 @@ When /^I run the install command$/ do
|
|
43
43
|
end
|
44
44
|
|
45
45
|
When /^I run the install command with flags:$/ do |flags|
|
46
|
-
run_simple(unescape("berks install #{flags.raw.join(" ")}"),
|
46
|
+
run_simple(unescape("berks install #{flags.raw.join(" ")}"), false)
|
47
47
|
end
|
48
48
|
|
49
49
|
When /^I run the update command$/ do
|
@@ -45,6 +45,18 @@ Then /^the cookbook store should have the cookbooks:$/ do |cookbooks|
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
Then /^the cookbook store should have the git cookbooks:$/ do |cookbooks|
|
49
|
+
cookbooks.raw.each do |name, version, sha1|
|
50
|
+
cookbook_store.should have_structure {
|
51
|
+
directory "#{name}-#{sha1}" do
|
52
|
+
file "metadata.rb" do
|
53
|
+
contains version
|
54
|
+
end
|
55
|
+
end
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
Then /^the cookbook store should not have the cookbooks:$/ do |cookbooks|
|
49
61
|
cookbooks.raw.each do |name, version|
|
50
62
|
cookbook_store.should_not have_structure {
|
data/features/support/env.rb
CHANGED
@@ -12,12 +12,6 @@ Spork.prefork do
|
|
12
12
|
|
13
13
|
ENV["BERKSHELF_PATH"] = File.join(APP_ROOT, "tmp", "berkshelf")
|
14
14
|
|
15
|
-
begin
|
16
|
-
CONFIG = YAML.load(File.read(File.join(APP_ROOT, "features", "config.yml")))
|
17
|
-
rescue Errno::ENOENT
|
18
|
-
raise "Please create a config file at features/config.yml from the sample found at features/config.sample.yml"
|
19
|
-
end
|
20
|
-
|
21
15
|
Dir[File.join(APP_ROOT, "spec/support/**/*.rb")].each {|f| require f}
|
22
16
|
|
23
17
|
Around do |scenario, block|
|
@@ -27,15 +21,13 @@ Spork.prefork do
|
|
27
21
|
end
|
28
22
|
|
29
23
|
Before do
|
30
|
-
Chef::Config[:chef_server_url] = CONFIG['chef_server_url']
|
31
|
-
Chef::Config[:client_key] = CONFIG['client_key']
|
32
|
-
Chef::Config[:node_name] = CONFIG['node_name']
|
33
24
|
clean_cookbook_store
|
34
25
|
@aruba_io_wait_seconds = 5
|
26
|
+
@aruba_timeout_seconds = 8
|
35
27
|
end
|
36
28
|
|
37
29
|
Before('@slow_process') do
|
38
|
-
@aruba_timeout_seconds =
|
30
|
+
@aruba_timeout_seconds = 60
|
39
31
|
@aruba_io_wait_seconds = 10
|
40
32
|
end
|
41
33
|
|
@@ -52,11 +44,17 @@ Spork.prefork do
|
|
52
44
|
Pathname.new(APP_ROOT)
|
53
45
|
end
|
54
46
|
|
47
|
+
def tmp_path
|
48
|
+
app_root_path.join('spec/tmp')
|
49
|
+
end
|
50
|
+
|
55
51
|
def fixtures_path
|
56
52
|
app_root_path.join('spec/fixtures')
|
57
53
|
end
|
58
54
|
end
|
59
55
|
|
60
56
|
Spork.each_run do
|
57
|
+
Berkshelf::RSpec::Knife.load_knife_config(File.join(APP_ROOT, 'spec/knife.rb'))
|
58
|
+
|
61
59
|
require 'berkshelf'
|
62
60
|
end
|
data/features/update.feature
CHANGED
@@ -18,6 +18,6 @@ Feature: update
|
|
18
18
|
"""
|
19
19
|
cookbook 'mysql', :locked_version => '1.2.6'
|
20
20
|
cookbook 'openssl', :locked_version => '1.0.0'
|
21
|
-
cookbook 'windows', :locked_version => '1.3.
|
21
|
+
cookbook 'windows', :locked_version => '1.3.2'
|
22
22
|
cookbook 'chef_handler', :locked_version => '1.0.6'
|
23
23
|
"""
|
data/lib/berkshelf.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require 'dep_selector'
|
3
2
|
require 'zlib'
|
4
3
|
require 'archive/tar/minitar'
|
4
|
+
require 'solve'
|
5
5
|
require 'chef/knife'
|
6
6
|
require 'chef/rest'
|
7
7
|
require 'chef/platform'
|
8
8
|
require 'chef/cookbook/metadata'
|
9
|
+
require 'chef/cookbook_version'
|
9
10
|
|
10
11
|
require 'berkshelf/version'
|
11
12
|
require 'berkshelf/core_ext'
|
@@ -14,6 +15,7 @@ require 'berkshelf/errors'
|
|
14
15
|
Chef::Config[:cache_options][:path] = Dir.mktmpdir
|
15
16
|
|
16
17
|
module Berkshelf
|
18
|
+
DEFAULT_CONFIG = File.expand_path(ENV["CHEF_CONFIG"] || "~/.chef/knife.rb")
|
17
19
|
DEFAULT_STORE_PATH = File.expand_path("~/.berkshelf").freeze
|
18
20
|
DEFAULT_FILENAME = 'Berksfile'.freeze
|
19
21
|
|
@@ -37,6 +39,8 @@ module Berkshelf
|
|
37
39
|
attr_accessor :cookbook_store
|
38
40
|
attr_accessor :downloader
|
39
41
|
|
42
|
+
attr_writer :config_path
|
43
|
+
|
40
44
|
def root
|
41
45
|
@root ||= Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
|
42
46
|
end
|
@@ -62,6 +66,20 @@ module Berkshelf
|
|
62
66
|
@downloader ||= Downloader.new(cookbook_store)
|
63
67
|
end
|
64
68
|
|
69
|
+
def config_path
|
70
|
+
@config_path ||= DEFAULT_CONFIG
|
71
|
+
end
|
72
|
+
|
73
|
+
# Load the config found at the given path as the Chef::Config. If no path is specified
|
74
|
+
# the value of Berkshelf.chef_config will be used.
|
75
|
+
#
|
76
|
+
# @param [String] path
|
77
|
+
def load_config(path = config_path)
|
78
|
+
Chef::Config.from_file(File.expand_path(path))
|
79
|
+
rescue Errno::ENOENT
|
80
|
+
raise KnifeConfigNotFound, "Attempted to load configuration from: '#{path}' but not found."
|
81
|
+
end
|
82
|
+
|
65
83
|
# Ascend the directory structure from the given path to find a
|
66
84
|
# metadata.rb file of a Chef Cookbook. If no metadata.rb file
|
67
85
|
# was found, nil is returned.
|
data/lib/berkshelf/berksfile.rb
CHANGED
@@ -185,21 +185,33 @@ module Berkshelf
|
|
185
185
|
# @param [Pathname, String] path
|
186
186
|
# @param [Array<Berkshelf::CachedCookbook>] cached_cookbooks
|
187
187
|
def write_shims(path, cached_cookbooks)
|
188
|
+
actual_path = nil
|
189
|
+
|
190
|
+
if descendant_directory?(path, Dir.pwd)
|
191
|
+
actual_path = path
|
192
|
+
FileUtils.rm_rf(actual_path)
|
193
|
+
path = Dir.mktmpdir("berkshelf-")
|
194
|
+
end
|
195
|
+
|
188
196
|
FileUtils.mkdir_p(path)
|
189
197
|
cached_cookbooks.each do |cached_cookbook|
|
190
198
|
destination = File.expand_path(File.join(path, cached_cookbook.cookbook_name))
|
191
199
|
FileUtils.rm_rf(destination)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
200
|
+
FileUtils.ln_r(cached_cookbook.path, destination, force: true)
|
201
|
+
end
|
202
|
+
|
203
|
+
if actual_path
|
204
|
+
FileUtils.mv(path, actual_path)
|
198
205
|
end
|
199
206
|
end
|
200
207
|
|
201
208
|
private
|
202
209
|
|
210
|
+
def descendant_directory?(candidate, parent)
|
211
|
+
hack = FileUtils::Entry_.new('/tmp')
|
212
|
+
hack.send(:descendant_diretory?, candidate, parent)
|
213
|
+
end
|
214
|
+
|
203
215
|
def lockfile_present?
|
204
216
|
File.exist?(Berkshelf::Lockfile::DEFAULT_FILENAME)
|
205
217
|
end
|
data/lib/berkshelf/cli.rb
CHANGED
@@ -8,6 +8,7 @@ module Berkshelf
|
|
8
8
|
super
|
9
9
|
# JW TODO: Replace Chef::Knife::UI with our own UI class
|
10
10
|
::Berkshelf.ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
|
11
|
+
::Berkshelf.config_path = @options[:config]
|
11
12
|
@options = options.dup # unfreeze frozen options Hash from Thor
|
12
13
|
rescue BerkshelfError => e
|
13
14
|
Berkshelf.ui.fatal e
|
@@ -23,7 +24,7 @@ module Berkshelf
|
|
23
24
|
|
24
25
|
class_option :config,
|
25
26
|
type: :string,
|
26
|
-
default:
|
27
|
+
default: Berkshelf::DEFAULT_CONFIG,
|
27
28
|
desc: "Path to Knife or Chef configuration to use.",
|
28
29
|
aliases: "-c",
|
29
30
|
banner: "PATH"
|
@@ -95,7 +96,7 @@ module Berkshelf
|
|
95
96
|
desc: "Upload all cookbooks even if a frozen one exists on the target Chef Server"
|
96
97
|
desc "upload", "Upload the Cookbooks specified by a Berksfile or a Berksfile.lock to a Chef Server."
|
97
98
|
def upload
|
98
|
-
load_config
|
99
|
+
Berkshelf.load_config
|
99
100
|
berksfile = ::Berkshelf::Berksfile.from_file(options[:berksfile])
|
100
101
|
berksfile.upload(Chef::Config[:chef_server_url], options)
|
101
102
|
rescue BerkshelfError => e
|
@@ -135,11 +136,5 @@ module Berkshelf
|
|
135
136
|
def license
|
136
137
|
File.read(Berkshelf.root.join('LICENSE'))
|
137
138
|
end
|
138
|
-
|
139
|
-
def load_config
|
140
|
-
Chef::Config.from_file(File.expand_path(options[:config]))
|
141
|
-
rescue Errno::ENOENT
|
142
|
-
raise KnifeConfigNotFound, "Unable to find a Knife config at #{options[:config]}. Specify a different path with --config."
|
143
|
-
end
|
144
139
|
end
|
145
140
|
end
|
@@ -1,14 +1,65 @@
|
|
1
1
|
module Berkshelf
|
2
2
|
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
3
|
class CookbookSource
|
4
|
-
|
4
|
+
class << self
|
5
|
+
@@valid_options = [:group, :locked_version]
|
6
|
+
@@location_keys = Hash.new
|
7
|
+
|
8
|
+
# Returns an array of valid options to pass to the initializer
|
9
|
+
#
|
10
|
+
# @return [Array<Symbol>]
|
11
|
+
def valid_options
|
12
|
+
@@valid_options
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns an array of the registered source location keys. Every source
|
16
|
+
# location is identified by a key (symbol) to differentiate which class
|
17
|
+
# to instantiate for the location of a CookbookSource at initialization.
|
18
|
+
#
|
19
|
+
# @return [Array<Symbol>]
|
20
|
+
def location_keys
|
21
|
+
@@location_keys
|
22
|
+
end
|
23
|
+
|
24
|
+
# Add a option to the list of valid options
|
25
|
+
# @see #valid_options
|
26
|
+
#
|
27
|
+
# @param [Symbol] option
|
28
|
+
#
|
29
|
+
# @return [Array<Symbol>]
|
30
|
+
def add_valid_option(option)
|
31
|
+
@@valid_options.push(option) unless @@valid_options.include?(option)
|
32
|
+
@@valid_options
|
33
|
+
end
|
5
34
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
35
|
+
# Register a location key with the CookbookSource class
|
36
|
+
# @see #location_keys
|
37
|
+
#
|
38
|
+
# @param [Symbol] location
|
39
|
+
#
|
40
|
+
# @raise [ArgumentError] if the location key has already been defined
|
41
|
+
#
|
42
|
+
# @return [Array<Symbol>]
|
43
|
+
def add_location_key(location, klass)
|
44
|
+
unless @@location_keys.has_key?(location)
|
45
|
+
add_valid_option(location)
|
46
|
+
@@location_keys[location] = klass
|
47
|
+
end
|
48
|
+
|
49
|
+
@@location_keys
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
extend Forwardable
|
10
54
|
|
11
|
-
|
55
|
+
# JW TODO: Move locations out of CookbookSource namespace.
|
56
|
+
# Move all locations into berkshelf/locations/*
|
57
|
+
# Autorequire all items in berkshelf/locations/
|
58
|
+
require 'berkshelf/cookbook_source/location'
|
59
|
+
require 'berkshelf/cookbook_source/site_location'
|
60
|
+
require 'berkshelf/cookbook_source/git_location'
|
61
|
+
require 'berkshelf/cookbook_source/path_location'
|
62
|
+
require 'berkshelf/cookbook_source/chef_api_location'
|
12
63
|
|
13
64
|
attr_reader :name
|
14
65
|
alias_method :to_s, :name
|
@@ -24,36 +75,59 @@ module Berkshelf
|
|
24
75
|
# @param [#to_s] name
|
25
76
|
# @param [#to_s] version_constraint
|
26
77
|
# @param [Hash] options
|
78
|
+
#
|
79
|
+
# @option options [String] :git
|
80
|
+
# the Git URL to clone
|
81
|
+
# @option options [String] :site
|
82
|
+
# a URL pointing to a community API endpoint
|
83
|
+
# @option options [String] :path
|
84
|
+
# a filepath to the cookbook on your local disk
|
85
|
+
# @option options [Symbol, Array] :group
|
86
|
+
# the group or groups that the cookbook belongs to
|
87
|
+
# @option options [String] :ref
|
88
|
+
# the commit hash or an alias to a commit hash to clone
|
89
|
+
# @option options [String] :branch
|
90
|
+
# same as ref
|
91
|
+
# @option options [String] :tag
|
92
|
+
# same as tag
|
93
|
+
# @option options [String] :locked_version
|
27
94
|
# @overload initialize(name, options = {})
|
28
95
|
# @param [#to_s] name
|
29
96
|
# @param [Hash] options
|
97
|
+
#
|
98
|
+
# @option options [String] :git
|
99
|
+
# the Git URL to clone
|
100
|
+
# @option options [String] :site
|
101
|
+
# a URL pointing to a community API endpoint
|
102
|
+
# @option options [String] :path
|
103
|
+
# a filepath to the cookbook on your local disk
|
104
|
+
# @option options [Symbol, Array] :group
|
105
|
+
# the group or groups that the cookbook belongs to
|
106
|
+
# @option options [String] :ref
|
107
|
+
# the commit hash or an alias to a commit hash to clone
|
108
|
+
# @option options [String] :branch
|
109
|
+
# same as ref
|
110
|
+
# @option options [String] :tag
|
111
|
+
# same as tag
|
112
|
+
# @option options [String] :locked_version
|
30
113
|
def initialize(*args)
|
31
114
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
32
115
|
name, constraint = args
|
33
116
|
|
34
117
|
@name = name
|
35
|
-
@version_constraint =
|
118
|
+
@version_constraint = Solve::Constraint.new(constraint || ">= 0.0.0")
|
36
119
|
@groups = []
|
37
120
|
@cached_cookbook = nil
|
38
121
|
|
39
|
-
|
40
|
-
raise ArgumentError, "Only one location key (#{LOCATION_KEYS.join(', ')}) may be specified"
|
41
|
-
end
|
122
|
+
validate_options(options)
|
42
123
|
|
43
|
-
@location =
|
44
|
-
when options[:git]
|
45
|
-
GitLocation.new(name, version_constraint, options)
|
46
|
-
when options[:path]
|
47
|
-
loc = PathLocation.new(name, version_constraint, options)
|
48
|
-
@cached_cookbook = CachedCookbook.from_path(loc.path)
|
49
|
-
loc
|
50
|
-
when options[:site]
|
51
|
-
SiteLocation.new(name, version_constraint, options)
|
52
|
-
else
|
53
|
-
SiteLocation.new(name, version_constraint, options)
|
54
|
-
end
|
124
|
+
@location = Location.init(name, version_constraint, options)
|
55
125
|
|
56
|
-
@
|
126
|
+
if @location.is_a?(PathLocation)
|
127
|
+
@cached_cookbook = CachedCookbook.from_path(@location.path)
|
128
|
+
end
|
129
|
+
|
130
|
+
@locked_version = Solve::Version.new(options[:locked_version]) if options[:locked_version]
|
57
131
|
|
58
132
|
add_group(options[:group]) if options[:group]
|
59
133
|
add_group(:default) if groups.empty?
|
@@ -98,5 +172,16 @@ module Berkshelf
|
|
98
172
|
def set_local_path(path)
|
99
173
|
@local_path = path
|
100
174
|
end
|
175
|
+
|
176
|
+
def validate_options(options)
|
177
|
+
invalid_options = options.keys - self.class.valid_options
|
178
|
+
|
179
|
+
unless invalid_options.empty?
|
180
|
+
invalid_options.collect! { |opt| "'#{opt}'" }
|
181
|
+
raise InternalError, "Invalid options for Cookbook Source: #{invalid_options.join(', ')}."
|
182
|
+
end
|
183
|
+
|
184
|
+
true
|
185
|
+
end
|
101
186
|
end
|
102
187
|
end
|