berkshelf 2.0.18 → 3.0.0.beta1
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/.ruby-version +1 -1
- data/.travis.yml +4 -1
- data/CHANGELOG.md +2 -26
- data/Gemfile +12 -2
- data/README.md +9 -1
- data/berkshelf.gemspec +9 -18
- data/bin/berks +3 -13
- data/features/apply_command.feature +11 -9
- data/features/berksfile.feature +8 -10
- data/features/config.feature +1 -2
- data/features/configure_command.feature +13 -14
- data/features/contingent_command.feature +13 -1
- data/features/cookbook_command.feature +2 -4
- data/features/groups_install.feature +10 -2
- data/features/help.feature +1 -1
- data/features/init_command.feature +5 -7
- data/features/install_command.feature +157 -228
- data/features/json_formatter.feature +27 -15
- data/features/licenses.feature +18 -12
- data/features/list_command.feature +6 -1
- data/features/lockfile.feature +116 -72
- data/features/outdated_command.feature +3 -47
- data/features/package_command.feature +10 -7
- data/features/shelf/show.feature +2 -2
- data/features/shelf/uninstall.feature +2 -2
- data/features/show_command.feature +10 -3
- data/features/step_definitions/chef/config_steps.rb +12 -0
- data/features/step_definitions/chef_server_steps.rb +16 -16
- data/features/step_definitions/cli_steps.rb +3 -79
- data/features/step_definitions/config_steps.rb +43 -0
- data/features/step_definitions/environment_steps.rb +7 -0
- data/features/step_definitions/filesystem_steps.rb +12 -57
- data/features/step_definitions/gem_steps.rb +1 -2
- data/features/step_definitions/json_steps.rb +3 -1
- data/features/step_definitions/lockfile_steps.rb +4 -0
- data/features/step_definitions/utility_steps.rb +0 -19
- data/features/support/aruba.rb +12 -0
- data/features/support/env.rb +52 -57
- data/features/update_command.feature +37 -23
- data/features/upload_command.feature +96 -160
- data/generator_files/Berksfile.erb +2 -1
- data/generator_files/Vagrantfile.erb +3 -0
- data/generator_files/default_test.rb.erb +1 -1
- data/generator_files/helpers.rb.erb +1 -1
- data/lib/berkshelf.rb +43 -24
- data/lib/berkshelf/api_client.rb +67 -0
- data/lib/berkshelf/api_client/remote_cookbook.rb +42 -0
- data/lib/berkshelf/berksfile.rb +232 -420
- data/lib/berkshelf/cached_cookbook.rb +22 -10
- data/lib/berkshelf/chef/config.rb +1 -0
- data/lib/berkshelf/cli.rb +66 -68
- data/lib/berkshelf/commands/shelf.rb +1 -1
- data/lib/berkshelf/community_rest.rb +10 -17
- data/lib/berkshelf/config.rb +23 -27
- data/lib/berkshelf/cookbook_generator.rb +3 -4
- data/lib/berkshelf/cookbook_store.rb +74 -17
- data/lib/berkshelf/core_ext/file.rb +2 -2
- data/lib/berkshelf/core_ext/pathname.rb +7 -5
- data/lib/berkshelf/{cookbook_source.rb → dependency.rb} +47 -67
- data/lib/berkshelf/downloader.rb +49 -106
- data/lib/berkshelf/errors.rb +64 -71
- data/lib/berkshelf/formatters.rb +11 -9
- data/lib/berkshelf/formatters/human_readable.rb +9 -9
- data/lib/berkshelf/formatters/json.rb +14 -4
- data/lib/berkshelf/init_generator.rb +3 -3
- data/lib/berkshelf/installer.rb +136 -0
- data/lib/berkshelf/location.rb +91 -131
- data/lib/berkshelf/locations/git_location.rb +9 -11
- data/lib/berkshelf/locations/github_location.rb +1 -1
- data/lib/berkshelf/locations/path_location.rb +10 -27
- data/lib/berkshelf/lockfile.rb +92 -70
- data/lib/berkshelf/logger.rb +4 -7
- data/lib/berkshelf/mixin/config.rb +21 -4
- data/lib/berkshelf/resolver.rb +60 -150
- data/lib/berkshelf/resolver/graph.rb +44 -0
- data/lib/berkshelf/source.rb +55 -0
- data/lib/berkshelf/source_uri.rb +38 -0
- data/lib/berkshelf/version.rb +1 -1
- data/spec/config/knife.rb +1 -1
- data/spec/fixtures/cassettes/Berkshelf_Resolver/_initialize/adds_the_dependencies_of_the_dependency_as_dependencies.yml +3694 -0
- data/spec/fixtures/cookbooks/example_cookbook/Berksfile.lock +1 -1
- data/spec/fixtures/lockfiles/default.lock +1 -1
- data/spec/spec_helper.rb +20 -121
- data/spec/support/chef_api.rb +3 -4
- data/spec/support/chef_server.rb +20 -11
- data/spec/support/git.rb +127 -0
- data/spec/support/kitchen.rb +12 -0
- data/spec/support/path_helpers.rb +69 -0
- data/spec/unit/berkshelf/api_client/remote_cookbook_spec.rb +23 -0
- data/spec/unit/berkshelf/api_client_spec.rb +57 -0
- data/spec/unit/berkshelf/berksfile_spec.rb +206 -324
- data/spec/unit/berkshelf/cached_cookbook_spec.rb +73 -38
- data/spec/unit/berkshelf/community_rest_spec.rb +30 -71
- data/spec/unit/berkshelf/config_spec.rb +3 -14
- data/spec/unit/berkshelf/cookbook_generator_spec.rb +1 -2
- data/spec/unit/berkshelf/cookbook_store_spec.rb +12 -7
- data/spec/unit/berkshelf/dependency_spec.rb +285 -0
- data/spec/unit/berkshelf/downloader_spec.rb +4 -183
- data/spec/unit/berkshelf/formatters/null_spec.rb +1 -1
- data/spec/unit/berkshelf/formatters_spec.rb +4 -2
- data/spec/unit/berkshelf/git_spec.rb +15 -15
- data/spec/unit/berkshelf/installer_spec.rb +39 -0
- data/spec/unit/berkshelf/location_spec.rb +87 -114
- data/spec/unit/berkshelf/locations/git_location_spec.rb +41 -53
- data/spec/unit/berkshelf/locations/path_location_spec.rb +13 -23
- data/spec/unit/berkshelf/lockfile_spec.rb +38 -40
- data/spec/unit/berkshelf/resolver/graph_spec.rb +44 -0
- data/spec/unit/berkshelf/resolver_spec.rb +34 -83
- data/spec/unit/berkshelf/source_spec.rb +23 -0
- data/spec/unit/berkshelf/source_uri_spec.rb +29 -0
- metadata +149 -188
- checksums.yaml +0 -7
- data/features/default_locations.feature +0 -127
- data/features/step_definitions/berksfile_steps.rb +0 -8
- data/features/step_definitions/configure_cli_steps.rb +0 -19
- data/features/vendor_install.feature +0 -19
- data/lib/berkshelf/core_ext/openuri.rb +0 -36
- data/lib/berkshelf/core_ext/rbzip2.rb +0 -8
- data/lib/berkshelf/locations/chef_api_location.rb +0 -228
- data/lib/berkshelf/locations/site_location.rb +0 -92
- data/lib/berkshelf/test.rb +0 -35
- data/spec/knife.rb.sample +0 -12
- data/spec/support/test_generators.rb +0 -27
- data/spec/unit/berkshelf/cli_spec.rb +0 -16
- data/spec/unit/berkshelf/cookbook_source_spec.rb +0 -358
- data/spec/unit/berkshelf/core_ext/pathname_spec.rb +0 -46
- data/spec/unit/berkshelf/locations/chef_api_location_spec.rb +0 -139
- data/spec/unit/berkshelf/locations/site_location_spec.rb +0 -19
|
@@ -62,6 +62,9 @@ Vagrant.configure("2") do |config|
|
|
|
62
62
|
# View the documentation for the provider you're using for more
|
|
63
63
|
# information on available options.
|
|
64
64
|
|
|
65
|
+
config.ssh.max_tries = 40
|
|
66
|
+
config.ssh.timeout = 120
|
|
67
|
+
|
|
65
68
|
# The path to the Berksfile to use with Vagrant Berkshelf
|
|
66
69
|
# config.berkshelf.berksfile_path = "./Berksfile"
|
|
67
70
|
|
|
@@ -2,7 +2,7 @@ require File.expand_path('../support/helpers', __FILE__)
|
|
|
2
2
|
|
|
3
3
|
describe '<%= cookbook_name %>::default' do
|
|
4
4
|
|
|
5
|
-
include Helpers::<%= cookbook_name.capitalize.
|
|
5
|
+
include Helpers::<%= cookbook_name.capitalize.gsub('-','_') %>
|
|
6
6
|
|
|
7
7
|
# Example spec tests can be found at http://git.io/Fahwsw
|
|
8
8
|
it 'runs no tests by default' do
|
data/lib/berkshelf.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'buff/extensions'
|
|
2
2
|
require 'archive/tar/minitar'
|
|
3
|
-
require '
|
|
3
|
+
require 'celluloid'
|
|
4
4
|
require 'digest/md5'
|
|
5
5
|
require 'forwardable'
|
|
6
6
|
require 'hashie'
|
|
@@ -12,24 +12,24 @@ require 'thor'
|
|
|
12
12
|
require 'tmpdir'
|
|
13
13
|
require 'uri'
|
|
14
14
|
require 'zlib'
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
JSON.create_id = nil
|
|
16
17
|
|
|
17
18
|
require_relative 'berkshelf/core_ext'
|
|
18
|
-
require_relative 'berkshelf/errors'
|
|
19
|
-
require_relative 'berkshelf/mixin'
|
|
20
19
|
require_relative 'berkshelf/thor_ext'
|
|
21
20
|
|
|
22
|
-
JSON.create_id = nil
|
|
23
|
-
|
|
24
21
|
module Berkshelf
|
|
22
|
+
require_relative 'berkshelf/errors'
|
|
23
|
+
require_relative 'berkshelf/mixin'
|
|
24
|
+
|
|
25
25
|
DEFAULT_FILENAME = 'Berksfile'.freeze
|
|
26
26
|
|
|
27
27
|
class << self
|
|
28
28
|
include Berkshelf::Mixin::Logging
|
|
29
29
|
|
|
30
|
+
attr_writer :berkshelf_path
|
|
30
31
|
attr_accessor :ui
|
|
31
32
|
attr_accessor :logger
|
|
32
|
-
attr_writer :cookbook_store
|
|
33
33
|
|
|
34
34
|
# @return [Pathname]
|
|
35
35
|
def root
|
|
@@ -50,21 +50,42 @@ module Berkshelf
|
|
|
50
50
|
#
|
|
51
51
|
# @return [String]
|
|
52
52
|
def berkshelf_path
|
|
53
|
-
ENV['BERKSHELF_PATH'] || File.expand_path('~/.berkshelf')
|
|
53
|
+
@berkshelf_path || ENV['BERKSHELF_PATH'] || File.expand_path('~/.berkshelf')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# The Berkshelf configuration.
|
|
57
|
+
#
|
|
58
|
+
# @return [Berkshelf::Config]
|
|
59
|
+
def config
|
|
60
|
+
Berkshelf::Config.instance
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @param [Berkshelf::Config]
|
|
64
|
+
def config=(config)
|
|
65
|
+
Berkshelf::Config.set_config(config)
|
|
54
66
|
end
|
|
55
67
|
|
|
56
68
|
# The Chef configuration file.
|
|
57
69
|
#
|
|
58
70
|
# @return [Berkshelf::Chef::Config]
|
|
59
71
|
def chef_config
|
|
60
|
-
|
|
72
|
+
Berkshelf::Chef::Config.instance
|
|
61
73
|
end
|
|
62
74
|
|
|
63
|
-
#
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
# @param [Berkshelf::Chef::Config]
|
|
76
|
+
def chef_config=(config)
|
|
77
|
+
Berkshelf::Chef::Config.set_config(config)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Initialize the filepath for the Berkshelf path..
|
|
81
|
+
def initialize_filesystem
|
|
82
|
+
FileUtils.mkdir_p(berkshelf_path, mode: 0755)
|
|
83
|
+
|
|
84
|
+
unless File.writable?(berkshelf_path)
|
|
85
|
+
raise InsufficientPrivledges, "You do not have permission to write to '#{berkshelf_path}'!" +
|
|
86
|
+
" Please either chown the directory or use a different filepath."
|
|
87
|
+
end
|
|
88
|
+
end
|
|
68
89
|
|
|
69
90
|
# @return [String]
|
|
70
91
|
def tmp_dir
|
|
@@ -80,13 +101,9 @@ module Berkshelf
|
|
|
80
101
|
Dir.mktmpdir(nil, tmp_dir)
|
|
81
102
|
end
|
|
82
103
|
|
|
83
|
-
def cookbooks_dir
|
|
84
|
-
File.join(berkshelf_path, 'cookbooks')
|
|
85
|
-
end
|
|
86
|
-
|
|
87
104
|
# @return [Berkshelf::CookbookStore]
|
|
88
105
|
def cookbook_store
|
|
89
|
-
|
|
106
|
+
CookbookStore.instance
|
|
90
107
|
end
|
|
91
108
|
|
|
92
109
|
# Get the appropriate Formatter object based on the formatter
|
|
@@ -122,6 +139,7 @@ module Berkshelf
|
|
|
122
139
|
end
|
|
123
140
|
end
|
|
124
141
|
|
|
142
|
+
require_relative 'berkshelf/api_client'
|
|
125
143
|
require_relative 'berkshelf/base_generator'
|
|
126
144
|
require_relative 'berkshelf/berksfile'
|
|
127
145
|
require_relative 'berkshelf/cached_cookbook'
|
|
@@ -129,21 +147,22 @@ require_relative 'berkshelf/chef'
|
|
|
129
147
|
require_relative 'berkshelf/cli'
|
|
130
148
|
require_relative 'berkshelf/community_rest'
|
|
131
149
|
require_relative 'berkshelf/cookbook_generator'
|
|
132
|
-
require_relative 'berkshelf/cookbook_source'
|
|
133
150
|
require_relative 'berkshelf/cookbook_store'
|
|
134
151
|
require_relative 'berkshelf/config'
|
|
152
|
+
require_relative 'berkshelf/dependency'
|
|
135
153
|
require_relative 'berkshelf/downloader'
|
|
136
154
|
require_relative 'berkshelf/formatters'
|
|
137
155
|
require_relative 'berkshelf/git'
|
|
138
156
|
require_relative 'berkshelf/init_generator'
|
|
157
|
+
require_relative 'berkshelf/installer'
|
|
139
158
|
require_relative 'berkshelf/location'
|
|
140
159
|
require_relative 'berkshelf/lockfile'
|
|
141
160
|
require_relative 'berkshelf/logger'
|
|
142
161
|
require_relative 'berkshelf/resolver'
|
|
143
|
-
require_relative 'berkshelf/
|
|
162
|
+
require_relative 'berkshelf/source'
|
|
163
|
+
require_relative 'berkshelf/source_uri'
|
|
144
164
|
require_relative 'berkshelf/ui'
|
|
145
165
|
require_relative 'berkshelf/version'
|
|
146
166
|
|
|
147
|
-
Ridley.logger = Berkshelf.logger = Logger.new(STDOUT)
|
|
167
|
+
Ridley.logger = Celluloid.logger = Berkshelf.logger = Logger.new(STDOUT)
|
|
148
168
|
Berkshelf.logger.level = Logger::WARN
|
|
149
|
-
Celluloid.logger.level = Logger::FATAL if defined?(Celluloid)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'addressable/uri'
|
|
2
|
+
|
|
3
|
+
module Berkshelf
|
|
4
|
+
# Used to communicate with a remotely hosted [Berkshelf API Server](https://github.com/riotgames/berkshelf-api).
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# client = Berkshelf::APIClient.new("http://api.berkshelf.com")
|
|
8
|
+
# client.universe #=> [...]
|
|
9
|
+
class APIClient < Faraday::Connection
|
|
10
|
+
require_relative 'api_client/remote_cookbook'
|
|
11
|
+
|
|
12
|
+
# @return [Addressable::URI]
|
|
13
|
+
attr_reader :url
|
|
14
|
+
|
|
15
|
+
# @return [Integer]
|
|
16
|
+
# how many retries to attempt on HTTP requests
|
|
17
|
+
attr_reader :retries
|
|
18
|
+
|
|
19
|
+
# @return [Float]
|
|
20
|
+
# time to wait between retries
|
|
21
|
+
attr_reader :retry_interval
|
|
22
|
+
|
|
23
|
+
# @param [String, Addressable::URI] url
|
|
24
|
+
#
|
|
25
|
+
# @option options [Integer] :retries
|
|
26
|
+
# how many retries to perform before giving up
|
|
27
|
+
# @option options [Float] :retry_interval
|
|
28
|
+
# how long to wait (in seconds) between each retry
|
|
29
|
+
def initialize(url, options = {})
|
|
30
|
+
options = options.reverse_merge(retries: 5, retry_interval: 0.5)
|
|
31
|
+
@url = Addressable::URI.parse(url)
|
|
32
|
+
@retries = options[:retries]
|
|
33
|
+
@retry_interval = options[:retry_interval]
|
|
34
|
+
|
|
35
|
+
builder = Faraday::Builder.new do |b|
|
|
36
|
+
b.response :parse_json
|
|
37
|
+
b.response :gzip
|
|
38
|
+
b.request :retry,
|
|
39
|
+
max: self.retries,
|
|
40
|
+
interval: self.retry_interval,
|
|
41
|
+
exceptions: [ Faraday::Error::TimeoutError ]
|
|
42
|
+
|
|
43
|
+
b.adapter :net_http
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
super(self.url, builder: builder)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Retrieves the entire universe of known cookbooks from the API source
|
|
50
|
+
#
|
|
51
|
+
# @return [Array<APIClient::RemoteCookbook>]
|
|
52
|
+
def universe
|
|
53
|
+
response = get("universe")
|
|
54
|
+
|
|
55
|
+
case response.status
|
|
56
|
+
when 200
|
|
57
|
+
[].tap do |cookbooks|
|
|
58
|
+
response.body.each do |name, versions|
|
|
59
|
+
versions.each { |version, attributes| cookbooks << RemoteCookbook.new(name, version, attributes) }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
raise RuntimeError, "bad response #{response.inspect}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Berkshelf
|
|
2
|
+
class APIClient
|
|
3
|
+
# A representation of cookbook metadata indexed by a Berkshelf API Server. Returned
|
|
4
|
+
# by sending messages to a {Berkshelf::APIClient} and used to download cookbooks
|
|
5
|
+
# indexed by the Berkshelf API Server.
|
|
6
|
+
class RemoteCookbook
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_reader :name
|
|
9
|
+
# @return [String]
|
|
10
|
+
attr_reader :version
|
|
11
|
+
|
|
12
|
+
# @param [String] name
|
|
13
|
+
# @param [String] version
|
|
14
|
+
# @param [Hash] attributes
|
|
15
|
+
def initialize(name, version, attributes = {})
|
|
16
|
+
@name = name
|
|
17
|
+
@version = version
|
|
18
|
+
@attributes = attributes
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Hash]
|
|
22
|
+
def dependencies
|
|
23
|
+
@attributes[:dependencies]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Hash]
|
|
27
|
+
def platforms
|
|
28
|
+
@attributes[:platforms]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Symbol]
|
|
32
|
+
def location_type
|
|
33
|
+
@attributes[:location_type].to_sym
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [String]
|
|
37
|
+
def location_path
|
|
38
|
+
@attributes[:location_path]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/berkshelf/berksfile.rb
CHANGED
|
@@ -1,71 +1,38 @@
|
|
|
1
1
|
module Berkshelf
|
|
2
2
|
class Berksfile
|
|
3
3
|
class << self
|
|
4
|
+
# The sources to use if no sources are explicitly provided
|
|
5
|
+
#
|
|
6
|
+
# @return [Array<Berkshelf::Source>]
|
|
7
|
+
def default_sources
|
|
8
|
+
@default_sources ||= [ Source.new(DEFAULT_API_URL) ]
|
|
9
|
+
end
|
|
10
|
+
|
|
4
11
|
# @param [#to_s] file
|
|
5
12
|
# a path on disk to a Berksfile to instantiate from
|
|
6
13
|
#
|
|
7
14
|
# @return [Berksfile]
|
|
8
15
|
def from_file(file)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
raise BerksfileReadError.new(ex)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Copy all cached_cookbooks to the given directory. Each cookbook will be contained in
|
|
19
|
-
# a directory named after the name of the cookbook.
|
|
20
|
-
#
|
|
21
|
-
# @param [Array<CachedCookbook>] cookbooks
|
|
22
|
-
# an array of CachedCookbooks to be copied to a vendor directory
|
|
23
|
-
# @param [String] path
|
|
24
|
-
# filepath to vendor cookbooks to
|
|
25
|
-
#
|
|
26
|
-
# @return [String]
|
|
27
|
-
# expanded filepath to the vendor directory
|
|
28
|
-
def vendor(cookbooks, path)
|
|
29
|
-
chefignore = nil
|
|
30
|
-
path = File.expand_path(path)
|
|
31
|
-
scratch = Berkshelf.mktmpdir
|
|
32
|
-
|
|
33
|
-
FileUtils.mkdir_p(path)
|
|
34
|
-
|
|
35
|
-
unless (ignore_file = Berkshelf::Chef::Cookbook::Chefignore.find_relative_to(Dir.pwd)).nil?
|
|
36
|
-
chefignore = Berkshelf::Chef::Cookbook::Chefignore.new(ignore_file)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
cookbooks.each do |cb|
|
|
40
|
-
dest = File.join(scratch, cb.cookbook_name, '/')
|
|
41
|
-
FileUtils.mkdir_p(dest)
|
|
42
|
-
|
|
43
|
-
# Dir.glob does not support backslash as a File separator
|
|
44
|
-
src = cb.path.to_s.gsub('\\', '/')
|
|
45
|
-
files = Dir.glob(File.join(src, '*'))
|
|
46
|
-
|
|
47
|
-
# Filter out files using chefignore
|
|
48
|
-
files = chefignore.remove_ignores_from(files) if chefignore
|
|
49
|
-
|
|
50
|
-
FileUtils.cp_r(files, dest)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
FileUtils.remove_dir(path, force: true)
|
|
54
|
-
FileUtils.mv(scratch, path)
|
|
55
|
-
|
|
56
|
-
path
|
|
16
|
+
new(file).dsl_eval_file(file)
|
|
17
|
+
rescue Errno::ENOENT => ex
|
|
18
|
+
raise BerksfileNotFound, "No Berksfile or Berksfile.lock found at: #{file}"
|
|
19
|
+
rescue => ex
|
|
20
|
+
raise BerksfileReadError.new(ex)
|
|
57
21
|
end
|
|
58
22
|
end
|
|
59
23
|
|
|
24
|
+
DEFAULT_API_URL = "http://api.berkshelf.com".freeze
|
|
25
|
+
|
|
60
26
|
include Berkshelf::Mixin::Logging
|
|
61
27
|
include Berkshelf::Mixin::DSLEval
|
|
62
28
|
extend Forwardable
|
|
63
29
|
|
|
30
|
+
expose_method :source
|
|
31
|
+
expose_method :site # @todo remove in Berkshelf 4.0
|
|
32
|
+
expose_method :chef_api # @todo remove in Berkshelf 4.0
|
|
64
33
|
expose_method :metadata
|
|
65
|
-
expose_method :group
|
|
66
|
-
expose_method :site
|
|
67
|
-
expose_method :chef_api
|
|
68
34
|
expose_method :cookbook
|
|
35
|
+
expose_method :group
|
|
69
36
|
|
|
70
37
|
@@active_group = nil
|
|
71
38
|
|
|
@@ -73,90 +40,53 @@ module Berkshelf
|
|
|
73
40
|
# The path on disk to the file representing this instance of Berksfile
|
|
74
41
|
attr_reader :filepath
|
|
75
42
|
|
|
76
|
-
# @return [Berkshelf::Downloader]
|
|
77
|
-
attr_reader :downloader
|
|
78
|
-
|
|
79
43
|
# @return [Array<Berkshelf::CachedCookbook>]
|
|
80
44
|
attr_reader :cached_cookbooks
|
|
81
45
|
|
|
82
|
-
def_delegator :downloader, :add_location
|
|
83
|
-
def_delegator :downloader, :locations
|
|
84
|
-
|
|
85
46
|
# @param [String] path
|
|
86
47
|
# path on disk to the file containing the contents of this Berksfile
|
|
87
48
|
def initialize(path)
|
|
88
49
|
@filepath = path
|
|
89
|
-
@
|
|
90
|
-
@downloader = Downloader.new(Berkshelf.cookbook_store)
|
|
50
|
+
@dependencies = Hash.new
|
|
91
51
|
@cached_cookbooks = nil
|
|
52
|
+
@sources = Array.new
|
|
92
53
|
end
|
|
93
54
|
|
|
94
55
|
# Add a cookbook dependency to the Berksfile to be retrieved and have it's dependencies recursively retrieved
|
|
95
56
|
# and resolved.
|
|
96
57
|
#
|
|
97
|
-
# @example a cookbook
|
|
58
|
+
# @example a cookbook dependency that will be retrieved from one of the default locations
|
|
98
59
|
# cookbook 'artifact'
|
|
99
60
|
#
|
|
100
|
-
# @example a cookbook
|
|
61
|
+
# @example a cookbook dependency that will be retrieved from a path on disk
|
|
101
62
|
# cookbook 'artifact', path: '/Users/reset/code/artifact'
|
|
102
63
|
#
|
|
103
|
-
# @example a cookbook
|
|
104
|
-
# cookbook 'artifact', site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
|
|
105
|
-
#
|
|
106
|
-
# @example a cookbook source that will be retrieved from the latest API of the Opscode Community Site
|
|
107
|
-
# cookbook 'artifact', site: :opscode
|
|
108
|
-
#
|
|
109
|
-
# @example a cookbook source that will be retrieved from a Git server
|
|
64
|
+
# @example a cookbook dependency that will be retrieved from a Git server
|
|
110
65
|
# cookbook 'artifact', git: 'git://github.com/RiotGames/artifact-cookbook.git'
|
|
111
66
|
#
|
|
112
|
-
# @example a cookbook source that will be retrieved from a Chef API (Chef Server)
|
|
113
|
-
# cookbook 'artifact', chef_api: 'https://api.opscode.com/organizations/vialstudios',
|
|
114
|
-
# node_name: 'reset', client_key: '/Users/reset/.chef/knife.rb'
|
|
115
|
-
#
|
|
116
|
-
# @example a cookbook source that will be retrieved from a Chef API using your Berkshelf config
|
|
117
|
-
# cookbook 'artifact', chef_api: :config
|
|
118
|
-
#
|
|
119
67
|
# @overload cookbook(name, version_constraint, options = {})
|
|
120
68
|
# @param [#to_s] name
|
|
121
69
|
# @param [#to_s] version_constraint
|
|
122
|
-
# @param [Hash] options
|
|
123
70
|
#
|
|
124
71
|
# @option options [Symbol, Array] :group
|
|
125
72
|
# the group or groups that the cookbook belongs to
|
|
126
|
-
# @option options [String, Symbol] :chef_api
|
|
127
|
-
# a URL to a Chef API. Alternatively the symbol :config can be provided
|
|
128
|
-
# which will instantiate this location with the values found in your
|
|
129
|
-
# Berkshelf configuration.
|
|
130
|
-
# @option options [String] :site
|
|
131
|
-
# a URL pointing to a community API endpoint
|
|
132
73
|
# @option options [String] :path
|
|
133
74
|
# a filepath to the cookbook on your local disk
|
|
134
75
|
# @option options [String] :git
|
|
135
76
|
# the Git URL to clone
|
|
136
77
|
#
|
|
137
|
-
# @see ChefAPILocation
|
|
138
|
-
# @see SiteLocation
|
|
139
78
|
# @see PathLocation
|
|
140
79
|
# @see GitLocation
|
|
141
80
|
# @overload cookbook(name, options = {})
|
|
142
81
|
# @param [#to_s] name
|
|
143
|
-
# @param [Hash] options
|
|
144
82
|
#
|
|
145
83
|
# @option options [Symbol, Array] :group
|
|
146
84
|
# the group or groups that the cookbook belongs to
|
|
147
|
-
# @option options [String, Symbol] :chef_api
|
|
148
|
-
# a URL to a Chef API. Alternatively the symbol :config can be provided
|
|
149
|
-
# which will instantiate this location with the values found in your
|
|
150
|
-
# Berkshelf configuration.
|
|
151
|
-
# @option options [String] :site
|
|
152
|
-
# a URL pointing to a community API endpoint
|
|
153
85
|
# @option options [String] :path
|
|
154
86
|
# a filepath to the cookbook on your local disk
|
|
155
87
|
# @option options [String] :git
|
|
156
88
|
# the Git URL to clone
|
|
157
89
|
#
|
|
158
|
-
# @see ChefAPILocation
|
|
159
|
-
# @see SiteLocation
|
|
160
90
|
# @see PathLocation
|
|
161
91
|
# @see GitLocation
|
|
162
92
|
def cookbook(*args)
|
|
@@ -170,7 +100,7 @@ module Berkshelf
|
|
|
170
100
|
options[:group] += @@active_group
|
|
171
101
|
end
|
|
172
102
|
|
|
173
|
-
|
|
103
|
+
add_dependency(name, constraint, options)
|
|
174
104
|
end
|
|
175
105
|
|
|
176
106
|
def group(*args)
|
|
@@ -179,8 +109,8 @@ module Berkshelf
|
|
|
179
109
|
@@active_group = nil
|
|
180
110
|
end
|
|
181
111
|
|
|
182
|
-
# Use a Cookbook metadata file to determine additional cookbook
|
|
183
|
-
#
|
|
112
|
+
# Use a Cookbook metadata file to determine additional cookbook dependencies to retrieve. All
|
|
113
|
+
# dependencies found in the metadata will use the default locations set in the Berksfile (if any are set)
|
|
184
114
|
# or the default locations defined by Berkshelf.
|
|
185
115
|
#
|
|
186
116
|
# @param [Hash] options
|
|
@@ -195,68 +125,85 @@ module Berkshelf
|
|
|
195
125
|
|
|
196
126
|
name = metadata.name.presence || File.basename(File.expand_path(path))
|
|
197
127
|
|
|
198
|
-
|
|
128
|
+
add_dependency(name, nil, path: path, metadata: true)
|
|
199
129
|
end
|
|
200
130
|
|
|
201
|
-
# Add a
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
# @note
|
|
205
|
-
# specifying the symbol :opscode as the value of the site default location is an alias for the
|
|
206
|
-
# latest API of the Opscode Community Site.
|
|
131
|
+
# Add a Berkshelf API source to use when building the index of known cookbooks. The indexes will be
|
|
132
|
+
# searched in the order they are added. If a cookbook is found in the first source then a cookbook
|
|
133
|
+
# in a second source would not be used.
|
|
207
134
|
#
|
|
208
135
|
# @example
|
|
209
|
-
#
|
|
210
|
-
#
|
|
136
|
+
# source "http://api.berkshelf.com"
|
|
137
|
+
# source "http://berks-api.riotgames.com"
|
|
211
138
|
#
|
|
212
|
-
# @param [String
|
|
139
|
+
# @param [String] api_url
|
|
140
|
+
# url for the api to add
|
|
213
141
|
#
|
|
214
|
-
# @
|
|
215
|
-
|
|
216
|
-
|
|
142
|
+
# @raise [Berkshelf::InvalidSourceURI]
|
|
143
|
+
#
|
|
144
|
+
# @return [Array<SourceURI>]
|
|
145
|
+
def source(api_url)
|
|
146
|
+
new_source = Source.new(api_url)
|
|
147
|
+
@sources.push(new_source) unless @sources.include?(new_source)
|
|
217
148
|
end
|
|
218
149
|
|
|
219
|
-
#
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
# @
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
150
|
+
# @return [Array<SourceURI>]
|
|
151
|
+
def sources
|
|
152
|
+
@sources.empty? ? self.class.default_sources : @sources
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @todo remove in Berkshelf 4.0
|
|
156
|
+
#
|
|
157
|
+
# @raise [Berkshelf::DeprecatedError]
|
|
158
|
+
def site(*args)
|
|
159
|
+
if args.first == :opscode
|
|
160
|
+
Berkshelf.formatter.deprecation "Your Berksfile contains a site location pointing to the Opscode Community " +
|
|
161
|
+
"Site (site :opscode). Site locations have been replaced by the source location. Change this to: " +
|
|
162
|
+
"'source \"http://api.berkshelf.com\" to remove this warning. For more information visit " +
|
|
163
|
+
"https://github.com/RiotGames/berkshelf/wiki/deprecated-locations"
|
|
164
|
+
source(DEFAULT_API_URL)
|
|
165
|
+
return
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
raise Berkshelf::DeprecatedError.new "Your Berksfile contains a site location. Site locations have been " +
|
|
169
|
+
" replaced by the source location. Please remove your site location and try again. For more information " +
|
|
170
|
+
" visit https://github.com/RiotGames/berkshelf/wiki/deprecated-locations"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# @todo remove in Berkshelf 4.0
|
|
235
174
|
#
|
|
236
|
-
# @
|
|
237
|
-
def chef_api(
|
|
238
|
-
|
|
175
|
+
# @raise [Berkshelf::DeprecatedError]
|
|
176
|
+
def chef_api(*args)
|
|
177
|
+
raise Berkshelf::DeprecatedError.new "Your Berksfile contains a chef_api location. Chef API locations have " +
|
|
178
|
+
" been replaced by the source location. Please remove your site location and try again. For more " +
|
|
179
|
+
" information visit https://github.com/RiotGames/berkshelf/wiki/deprecated-locations"
|
|
239
180
|
end
|
|
240
181
|
|
|
241
|
-
# Add a
|
|
182
|
+
# Add a dependency of the given name and constraint to the array of dependencies.
|
|
242
183
|
#
|
|
243
184
|
# @param [String] name
|
|
244
|
-
# the name of the
|
|
185
|
+
# the name of the dependency to add
|
|
245
186
|
# @param [String, Solve::Constraint] constraint
|
|
246
|
-
# the constraint to lock the
|
|
247
|
-
#
|
|
187
|
+
# the constraint to lock the dependency to
|
|
188
|
+
#
|
|
189
|
+
# @option options [Symbol, Array] :group
|
|
190
|
+
# the group or groups that the cookbook belongs to
|
|
191
|
+
# @option options [String] :path
|
|
192
|
+
# a filepath to the cookbook on your local disk
|
|
193
|
+
# @option options [String] :git
|
|
194
|
+
# the Git URL to clone
|
|
248
195
|
#
|
|
249
|
-
# @raise [
|
|
250
|
-
# with a
|
|
196
|
+
# @raise [DuplicateDependencyDefined] if a dependency is added whose name conflicts
|
|
197
|
+
# with a dependency who has already been added.
|
|
251
198
|
#
|
|
252
|
-
# @return [Array<Berkshelf::
|
|
253
|
-
def
|
|
254
|
-
if
|
|
255
|
-
# Only raise an exception if the
|
|
199
|
+
# @return [Array<Berkshelf::Dependency]
|
|
200
|
+
def add_dependency(name, constraint = nil, options = {})
|
|
201
|
+
if has_dependency?(name)
|
|
202
|
+
# Only raise an exception if the dependency is a true duplicate
|
|
256
203
|
groups = (options[:group].nil? || options[:group].empty?) ? [:default] : options[:group]
|
|
257
|
-
if !(@
|
|
258
|
-
raise
|
|
259
|
-
"Berksfile contains multiple
|
|
204
|
+
if !(@dependencies[name].groups & groups).empty?
|
|
205
|
+
raise DuplicateDependencyDefined,
|
|
206
|
+
"Berksfile contains multiple entries named '#{name}'. Use only one, or put them in different groups."
|
|
260
207
|
end
|
|
261
208
|
end
|
|
262
209
|
|
|
@@ -266,47 +213,36 @@ module Berkshelf
|
|
|
266
213
|
|
|
267
214
|
options[:constraint] = constraint
|
|
268
215
|
|
|
269
|
-
@
|
|
216
|
+
@dependencies[name] = Berkshelf::Dependency.new(self, name, options)
|
|
270
217
|
end
|
|
271
218
|
|
|
272
|
-
# @param [#to_s]
|
|
273
|
-
# the
|
|
219
|
+
# @param [#to_s] dependency
|
|
220
|
+
# the dependency to remove
|
|
274
221
|
#
|
|
275
|
-
# @return [Berkshelf::
|
|
276
|
-
def
|
|
277
|
-
@
|
|
222
|
+
# @return [Berkshelf::Dependency]
|
|
223
|
+
def remove_dependency(dependency)
|
|
224
|
+
@dependencies.delete(dependency.to_s)
|
|
278
225
|
end
|
|
279
226
|
|
|
280
|
-
# @param [#to_s]
|
|
281
|
-
# the
|
|
227
|
+
# @param [#to_s] dependency
|
|
228
|
+
# the dependency to check presence of
|
|
282
229
|
#
|
|
283
230
|
# @return [Boolean]
|
|
284
|
-
def
|
|
285
|
-
@
|
|
231
|
+
def has_dependency?(dependency)
|
|
232
|
+
@dependencies.has_key?(dependency.to_s)
|
|
286
233
|
end
|
|
287
234
|
|
|
288
|
-
# The list of cookbook sources specified in this Berksfile
|
|
289
|
-
#
|
|
290
|
-
# @param [Array] sources
|
|
291
|
-
# the list of sources to filter
|
|
292
|
-
#
|
|
293
235
|
# @option options [Symbol, Array] :except
|
|
294
|
-
#
|
|
236
|
+
# Group(s) to exclude which will cause any dependencies marked as a member of the
|
|
295
237
|
# group to not be installed
|
|
296
238
|
# @option options [Symbol, Array] :only
|
|
297
|
-
#
|
|
239
|
+
# Group(s) to include which will cause any dependencies marked as a member of the
|
|
298
240
|
# group to be installed and all others to be ignored
|
|
299
241
|
# @option cookbooks [String, Array] :cookbooks
|
|
300
|
-
#
|
|
301
|
-
#
|
|
302
|
-
# @raise [Berkshelf::ArgumentError]
|
|
303
|
-
# if a value for both :except and :only is provided
|
|
242
|
+
# Names of the cookbooks to retrieve dependencies for
|
|
304
243
|
#
|
|
305
|
-
# @return [Array<Berkshelf::
|
|
306
|
-
|
|
307
|
-
def sources(options = {})
|
|
308
|
-
l_sources = @sources.values
|
|
309
|
-
|
|
244
|
+
# @return [Array<Berkshelf::Dependency>]
|
|
245
|
+
def dependencies(options = {})
|
|
310
246
|
cookbooks = Array(options[:cookbooks])
|
|
311
247
|
except = Array(options[:except]).collect(&:to_sym)
|
|
312
248
|
only = Array(options[:only]).collect(&:to_sym)
|
|
@@ -318,65 +254,65 @@ module Berkshelf
|
|
|
318
254
|
if !except.empty? && !only.empty?
|
|
319
255
|
Berkshelf.ui.warn 'Cookbooks were specified, ignoring :except and :only'
|
|
320
256
|
end
|
|
321
|
-
|
|
257
|
+
@dependencies.values.select { |dependency| cookbooks.include?(dependency.name) }
|
|
322
258
|
when !except.empty?
|
|
323
|
-
|
|
259
|
+
@dependencies.values.select { |dependency| (except & dependency.groups).empty? }
|
|
324
260
|
when !only.empty?
|
|
325
|
-
|
|
261
|
+
@dependencies.values.select { |dependency| !(only & dependency.groups).empty? }
|
|
326
262
|
else
|
|
327
|
-
|
|
263
|
+
@dependencies.values
|
|
328
264
|
end
|
|
329
265
|
end
|
|
330
266
|
|
|
331
|
-
# Find a
|
|
267
|
+
# Find a dependency defined in this berksfile by name.
|
|
332
268
|
#
|
|
333
269
|
# @param [String] name
|
|
334
|
-
# the name of the cookbook
|
|
335
|
-
# @return [Berkshelf::
|
|
336
|
-
# the cookbook
|
|
270
|
+
# the name of the cookbook dependency to search for
|
|
271
|
+
# @return [Berkshelf::Dependency, nil]
|
|
272
|
+
# the cookbook dependency, or nil if one does not exist
|
|
337
273
|
def find(name)
|
|
338
|
-
@
|
|
274
|
+
@dependencies[name]
|
|
339
275
|
end
|
|
340
276
|
|
|
341
277
|
# @return [Hash]
|
|
342
|
-
# a hash containing group names as keys and an array of
|
|
278
|
+
# a hash containing group names as keys and an array of Berkshelf::Dependencies
|
|
343
279
|
# that are a member of that group as values
|
|
344
280
|
#
|
|
345
281
|
# Example:
|
|
346
282
|
# {
|
|
347
283
|
# nautilus: [
|
|
348
|
-
# #<Berkshelf::
|
|
349
|
-
# #<Berkshelf::
|
|
284
|
+
# #<Berkshelf::Dependency: nginx (~> 1.0.0)>,
|
|
285
|
+
# #<Berkshelf::Dependency: mysql (~> 1.2.4)>
|
|
350
286
|
# ],
|
|
351
287
|
# skarner: [
|
|
352
|
-
# #<Berkshelf::
|
|
288
|
+
# #<Berkshelf::Dependency: nginx (~> 1.0.0)>
|
|
353
289
|
# ]
|
|
354
290
|
# }
|
|
355
291
|
def groups
|
|
356
292
|
{}.tap do |groups|
|
|
357
|
-
|
|
358
|
-
|
|
293
|
+
dependencies.each do |dependency|
|
|
294
|
+
dependency.groups.each do |group|
|
|
359
295
|
groups[group] ||= []
|
|
360
|
-
groups[group] <<
|
|
296
|
+
groups[group] << dependency
|
|
361
297
|
end
|
|
362
298
|
end
|
|
363
299
|
end
|
|
364
300
|
end
|
|
365
301
|
|
|
366
302
|
# @param [String] name
|
|
367
|
-
# name of the
|
|
303
|
+
# name of the dependency to return
|
|
368
304
|
#
|
|
369
|
-
# @return [Berkshelf::
|
|
305
|
+
# @return [Berkshelf::Dependency]
|
|
370
306
|
def [](name)
|
|
371
|
-
@
|
|
307
|
+
@dependencies[name]
|
|
372
308
|
end
|
|
373
|
-
alias_method :
|
|
309
|
+
alias_method :get_dependency, :[]
|
|
374
310
|
|
|
375
|
-
# Install the
|
|
311
|
+
# Install the dependencies listed in the Berksfile, respecting the locked
|
|
376
312
|
# versions in the Berksfile.lock.
|
|
377
313
|
#
|
|
378
314
|
# 1. Check that a lockfile exists. If a lockfile does not exist, all
|
|
379
|
-
#
|
|
315
|
+
# dependencies are considered to be "unlocked". If a lockfile is specified, a
|
|
380
316
|
# definition is created via the following algorithm:
|
|
381
317
|
#
|
|
382
318
|
# - For each source, see if there exists a locked version that still
|
|
@@ -390,98 +326,67 @@ module Berkshelf
|
|
|
390
326
|
# - Remove any locked sources that no longer exist in the Berksfile
|
|
391
327
|
# (i.e. a cookbook source was removed from the Berksfile).
|
|
392
328
|
#
|
|
393
|
-
# 2. Resolve the collection of locked and unlocked
|
|
329
|
+
# 2. Resolve the collection of locked and unlocked dependencies.
|
|
394
330
|
#
|
|
395
331
|
# 3. Write out a new lockfile.
|
|
396
332
|
#
|
|
397
333
|
# @option options [Symbol, Array] :except
|
|
398
|
-
# Group(s) to exclude which will cause any
|
|
334
|
+
# Group(s) to exclude which will cause any dependencies marked as a member of the
|
|
399
335
|
# group to not be installed
|
|
400
336
|
# @option options [Symbol, Array] :only
|
|
401
|
-
# Group(s) to include which will cause any
|
|
337
|
+
# Group(s) to include which will cause any dependencies marked as a member of the
|
|
402
338
|
# group to be installed and all others to be ignored
|
|
403
|
-
# @option
|
|
404
|
-
#
|
|
405
|
-
# is a technique for packaging all cookbooks resolved by a Berksfile.
|
|
406
|
-
# @option options [Boolean] :update_lockfile (true)
|
|
407
|
-
# a boolean method indicating whether we should update the lockfile
|
|
339
|
+
# @option cookbooks [String, Array] :cookbooks
|
|
340
|
+
# Names of the cookbooks to retrieve dependencies for
|
|
408
341
|
#
|
|
409
|
-
# @raise [Berkshelf::
|
|
342
|
+
# @raise [Berkshelf::OutdatedDependency]
|
|
410
343
|
# if the lockfile constraints do not satisfy the Berskfile constraints
|
|
411
|
-
# @raise [Berkshelf::ArgumentError]
|
|
412
|
-
# if there are missing or conflicting options
|
|
413
344
|
#
|
|
414
345
|
# @return [Array<Berkshelf::CachedCookbook>]
|
|
415
346
|
def install(options = {})
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
resolver = resolve(local_sources)
|
|
419
|
-
@cached_cookbooks = resolver[:solution]
|
|
420
|
-
local_sources = resolver[:sources]
|
|
421
|
-
|
|
422
|
-
verify_licenses!
|
|
423
|
-
|
|
424
|
-
self.class.vendor(@cached_cookbooks, options[:path]) if options[:path]
|
|
425
|
-
|
|
426
|
-
lockfile.update(local_sources) unless options[:update_lockfile] == false
|
|
427
|
-
|
|
428
|
-
self.cached_cookbooks
|
|
347
|
+
Installer.new(self).run(options)
|
|
429
348
|
end
|
|
430
349
|
|
|
431
350
|
# @option options [Symbol, Array] :except
|
|
432
|
-
# Group(s) to exclude which will cause any
|
|
351
|
+
# Group(s) to exclude which will cause any dependencies marked as a member of the
|
|
433
352
|
# group to not be installed
|
|
434
353
|
# @option options [Symbol, Array] :only
|
|
435
|
-
# Group(s) to include which will cause any
|
|
354
|
+
# Group(s) to include which will cause any dependencies marked as a member of the
|
|
436
355
|
# group to be installed and all others to be ignored
|
|
437
356
|
# @option cookbooks [String, Array] :cookbooks
|
|
438
|
-
# Names of the cookbooks to retrieve
|
|
357
|
+
# Names of the cookbooks to retrieve dependencies for
|
|
439
358
|
def update(options = {})
|
|
440
359
|
validate_cookbook_names!(options)
|
|
441
360
|
|
|
442
361
|
# Unlock any/all specified cookbooks
|
|
443
|
-
|
|
362
|
+
dependencies(options).each { |dependency| lockfile.unlock(dependency) }
|
|
444
363
|
|
|
445
364
|
# NOTE: We intentionally do NOT pass options to the installer
|
|
446
365
|
self.install
|
|
447
366
|
end
|
|
448
367
|
|
|
449
|
-
#
|
|
450
|
-
#
|
|
368
|
+
# List of all the cookbooks which have a newer version found at a source that satisfies
|
|
369
|
+
# the constraints of your dependencies
|
|
451
370
|
#
|
|
452
371
|
# @option options [Symbol, Array] :except
|
|
453
|
-
# Group(s) to exclude which will cause any
|
|
372
|
+
# Group(s) to exclude which will cause any dependencies marked as a member of the
|
|
454
373
|
# group to not be installed
|
|
455
374
|
# @option options [Symbol, Array] :only
|
|
456
|
-
# Group(s) to include which will cause any
|
|
375
|
+
# Group(s) to include which will cause any dependencies marked as a member of the
|
|
457
376
|
# group to be installed and all others to be ignored
|
|
458
377
|
# @option cookbooks [String, Array] :cookbooks
|
|
459
|
-
#
|
|
378
|
+
# Whitelist of cookbooks to to check for updated versions for
|
|
460
379
|
#
|
|
461
380
|
# @return [Hash]
|
|
462
381
|
# a hash of cached cookbooks and their latest version. An empty hash is returned
|
|
463
|
-
# if there are no newer cookbooks for any of your
|
|
382
|
+
# if there are no newer cookbooks for any of your dependencies
|
|
464
383
|
#
|
|
465
384
|
# @example
|
|
466
|
-
# berksfile.outdated
|
|
385
|
+
# berksfile.outdated #=> {
|
|
467
386
|
# #<CachedCookbook name="artifact"> => "0.11.2"
|
|
468
387
|
# }
|
|
469
388
|
def outdated(options = {})
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
sources(options).each do |cookbook|
|
|
473
|
-
location = cookbook.location || Location.init(cookbook.name, cookbook.version_constraint, site: :opscode)
|
|
474
|
-
|
|
475
|
-
if location.is_a?(SiteLocation)
|
|
476
|
-
latest_version = location.latest_version
|
|
477
|
-
|
|
478
|
-
unless cookbook.version_constraint.satisfies?(latest_version)
|
|
479
|
-
outdated[cookbook] = latest_version
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
end
|
|
483
|
-
|
|
484
|
-
outdated
|
|
389
|
+
raise RuntimeError, "not yet implemented"
|
|
485
390
|
end
|
|
486
391
|
|
|
487
392
|
# Upload the cookbooks installed by this Berksfile
|
|
@@ -492,66 +397,40 @@ module Berkshelf
|
|
|
492
397
|
# @option options [Boolean] :freeze (true)
|
|
493
398
|
# Freeze the uploaded Cookbook on the Chef Server so that it cannot be overwritten
|
|
494
399
|
# @option options [Symbol, Array] :except
|
|
495
|
-
# Group(s) to exclude which will cause any
|
|
400
|
+
# Group(s) to exclude which will cause any dependencies marked as a member of the
|
|
496
401
|
# group to not be installed
|
|
497
402
|
# @option options [Symbol, Array] :only
|
|
498
|
-
# Group(s) to include which will cause any
|
|
403
|
+
# Group(s) to include which will cause any dependencies marked as a member of the
|
|
499
404
|
# group to be installed and all others to be ignored
|
|
500
405
|
# @option options [String, Array] :cookbooks
|
|
501
|
-
# Names of the cookbooks to retrieve
|
|
406
|
+
# Names of the cookbooks to retrieve dependencies for
|
|
502
407
|
# @option options [Hash] :ssl_verify (true)
|
|
503
408
|
# Disable/Enable SSL verification during uploads
|
|
504
|
-
# @option options [Boolean] :skip_dependencies (false)
|
|
505
|
-
# Skip uploading dependent cookbook(s).
|
|
506
409
|
# @option options [Boolean] :halt_on_frozen (false)
|
|
507
410
|
# Raise a FrozenCookbook error if one of the cookbooks being uploaded is already located
|
|
508
411
|
# on the remote Chef Server and frozen.
|
|
509
412
|
# @option options [String] :server_url
|
|
510
413
|
# An overriding Chef Server to upload the cookbooks to
|
|
511
|
-
# @option options [String] :client_name
|
|
512
|
-
# An overriding client name to use for connecting to the chef server
|
|
513
|
-
# @option options [String] :client_key
|
|
514
|
-
# An overriding client key to use for connecting to the chef server
|
|
515
414
|
#
|
|
516
|
-
# @raise [UploadFailure]
|
|
415
|
+
# @raise [Berkshelf::UploadFailure]
|
|
517
416
|
# if you are uploading cookbooks with an invalid or not-specified client key
|
|
417
|
+
# @raise [Berkshelf::DependencyNotFound]
|
|
418
|
+
# if one of the given cookbooks is not a dependency defined in the Berksfile
|
|
518
419
|
# @raise [Berkshelf::FrozenCookbook]
|
|
519
420
|
# if an attempt to upload a cookbook which has been frozen on the target server is made
|
|
520
421
|
# and the :halt_on_frozen option was true
|
|
521
422
|
def upload(options = {})
|
|
522
|
-
options = options.reverse_merge(force: false, freeze: true,
|
|
423
|
+
options = options.reverse_merge(force: false, freeze: true, halt_on_frozen: false, cookbooks: [])
|
|
523
424
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
cached_cookbooks.each do |cookbook|
|
|
529
|
-
Berkshelf.formatter.upload(cookbook.cookbook_name, cookbook.version, conn.server_url)
|
|
530
|
-
validate_files!(cookbook)
|
|
531
|
-
|
|
532
|
-
begin
|
|
533
|
-
conn.cookbook.upload(cookbook.path, upload_opts.merge(name: cookbook.cookbook_name))
|
|
534
|
-
rescue Ridley::Errors::FrozenCookbook => ex
|
|
535
|
-
if options[:halt_on_frozen]
|
|
536
|
-
raise Berkshelf::FrozenCookbook, ex
|
|
537
|
-
end
|
|
425
|
+
options[:cookbooks].each do |cookbook|
|
|
426
|
+
unless dependency = find(cookbook)
|
|
427
|
+
raise DependencyNotFound, "Failed to upload cookbook '#{cookbook}'. Not defined in Berksfile."
|
|
538
428
|
end
|
|
539
429
|
end
|
|
540
430
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
msg = "Unable to upload cookbooks: #{missing_cookbooks.sort.join(', ')}\n"
|
|
545
|
-
msg << "Specified cookbooks must be defined within the Berkshelf file when using the"
|
|
546
|
-
msg << " `--skip-dependencies` option"
|
|
547
|
-
raise ExplicitCookbookNotFound.new(msg)
|
|
548
|
-
end
|
|
549
|
-
end
|
|
550
|
-
rescue Ridley::Errors::RidleyError => ex
|
|
551
|
-
log_exception(ex)
|
|
552
|
-
raise ChefConnectionError, ex # todo implement
|
|
553
|
-
ensure
|
|
554
|
-
conn.terminate if conn && conn.alive?
|
|
431
|
+
cached_cookbooks = install(options)
|
|
432
|
+
cached_cookbooks = filter_to_upload(cached_cookbooks, options[:cookbooks]) if options[:cookbooks]
|
|
433
|
+
do_upload(cached_cookbooks, options)
|
|
555
434
|
end
|
|
556
435
|
|
|
557
436
|
# Resolve this Berksfile and apply the locks found in the generated Berksfile.lock to the
|
|
@@ -562,38 +441,24 @@ module Berkshelf
|
|
|
562
441
|
# @option options [Hash] :ssl_verify (true)
|
|
563
442
|
# Disable/Enable SSL verification during uploads
|
|
564
443
|
#
|
|
565
|
-
# @raise [EnvironmentNotFound]
|
|
566
|
-
#
|
|
567
|
-
# @raise [
|
|
444
|
+
# @raise [EnvironmentNotFound]
|
|
445
|
+
# if the target environment was not found
|
|
446
|
+
# @raise [ChefConnectionError]
|
|
447
|
+
# if you are locking cookbooks with an invalid or not-specified client configuration
|
|
568
448
|
def apply(environment_name, options = {})
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
environment_path = options[:from_file]
|
|
573
|
-
begin
|
|
574
|
-
environment = conn.environment.from_file(environment_path)
|
|
575
|
-
rescue # Ridley::Errors::RidleyError => ex
|
|
576
|
-
raise EnvironmentFileNotFound, "Local environment file #{environment_path} not found."
|
|
449
|
+
ridley_connection(options) do |conn|
|
|
450
|
+
unless environment = conn.environment.find(environment_name)
|
|
451
|
+
raise EnvironmentNotFound.new(environment_name)
|
|
577
452
|
end
|
|
578
|
-
else
|
|
579
|
-
environment = conn.environment.find(environment_name)
|
|
580
|
-
end
|
|
581
453
|
|
|
582
|
-
if environment
|
|
583
454
|
install
|
|
584
455
|
|
|
585
456
|
environment.cookbook_versions = {}.tap do |cookbook_versions|
|
|
586
|
-
lockfile.
|
|
457
|
+
lockfile.dependencies.each { |dependency| cookbook_versions[dependency.name] = dependency.locked_version }
|
|
587
458
|
end
|
|
588
459
|
|
|
589
460
|
environment.save
|
|
590
|
-
else
|
|
591
|
-
raise EnvironmentNotFound.new(environment_name)
|
|
592
461
|
end
|
|
593
|
-
rescue Ridley::Errors::RidleyError => ex
|
|
594
|
-
raise ChefConnectionError, ex
|
|
595
|
-
ensure
|
|
596
|
-
conn.terminate if conn && conn.alive?
|
|
597
462
|
end
|
|
598
463
|
|
|
599
464
|
# Package the given cookbook for distribution outside of berkshelf. If the
|
|
@@ -607,8 +472,6 @@ module Berkshelf
|
|
|
607
472
|
#
|
|
608
473
|
# @option options [String] :output
|
|
609
474
|
# the path to output the tarball
|
|
610
|
-
# @option options [Boolean] :skip_dependencies
|
|
611
|
-
# package cookbook dependencies as well
|
|
612
475
|
# @option options [Boolean] :ignore_chefignore
|
|
613
476
|
# do not apply the chefignore file to the packed cookbooks
|
|
614
477
|
#
|
|
@@ -616,29 +479,25 @@ module Berkshelf
|
|
|
616
479
|
# the path to the package
|
|
617
480
|
def package(name = nil, options = {})
|
|
618
481
|
tar_name = "#{name || 'package'}.tar.gz"
|
|
619
|
-
output
|
|
482
|
+
output = File.expand_path(File.join(options[:output], tar_name))
|
|
620
483
|
|
|
621
|
-
unless name.nil?
|
|
622
|
-
|
|
623
|
-
|
|
484
|
+
cached_cookbooks = unless name.nil?
|
|
485
|
+
unless dependency = find(name)
|
|
486
|
+
raise CookbookNotFound, "Cookbook '#{name}' is not in your Berksfile"
|
|
487
|
+
end
|
|
624
488
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
}
|
|
489
|
+
options[:cookbooks] = name
|
|
490
|
+
Berkshelf.ui.mute { install(options) }
|
|
628
491
|
else
|
|
629
|
-
|
|
630
|
-
self.resolve(sources, options)[:solution]
|
|
631
|
-
}
|
|
492
|
+
Berkshelf.ui.mute { install(options) }
|
|
632
493
|
end
|
|
633
494
|
|
|
634
|
-
|
|
635
|
-
validate_files!(cookbook)
|
|
636
|
-
end
|
|
495
|
+
cached_cookbooks.each { |cookbook| validate_files!(cookbook) }
|
|
637
496
|
|
|
638
497
|
Dir.mktmpdir do |tmp|
|
|
639
|
-
|
|
640
|
-
path
|
|
641
|
-
destination = File.join(tmp,
|
|
498
|
+
cached_cookbooks.each do |cookbook|
|
|
499
|
+
path = cookbook.path.to_s
|
|
500
|
+
destination = File.join(tmp, cookbook.cookbook_name)
|
|
642
501
|
|
|
643
502
|
FileUtils.cp_r(path, destination)
|
|
644
503
|
|
|
@@ -663,25 +522,6 @@ module Berkshelf
|
|
|
663
522
|
output
|
|
664
523
|
end
|
|
665
524
|
|
|
666
|
-
# Finds a solution for the Berksfile and returns an array of CachedCookbooks.
|
|
667
|
-
#
|
|
668
|
-
# @param [Array<Berkshelf::CookbookSource>] sources
|
|
669
|
-
# Array of cookbook sources to resolve
|
|
670
|
-
#
|
|
671
|
-
# @option options [Boolean] :skip_dependencies
|
|
672
|
-
# Skip resolving of dependencies
|
|
673
|
-
#
|
|
674
|
-
# @return [Array<Berkshelf::CachedCookbooks>]
|
|
675
|
-
def resolve(sources = [], options = {})
|
|
676
|
-
resolver = Resolver.new(
|
|
677
|
-
self,
|
|
678
|
-
sources: sources,
|
|
679
|
-
skip_dependencies: options[:skip_dependencies]
|
|
680
|
-
)
|
|
681
|
-
|
|
682
|
-
{ solution: resolver.resolve, sources: resolver.sources }
|
|
683
|
-
end
|
|
684
|
-
|
|
685
525
|
# Get the lockfile corresponding to this Berksfile. This is necessary because
|
|
686
526
|
# the user can specify a different path to the Berksfile. So assuming the lockfile
|
|
687
527
|
# is named "Berksfile.lock" is a poor assumption.
|
|
@@ -695,12 +535,55 @@ module Berkshelf
|
|
|
695
535
|
|
|
696
536
|
private
|
|
697
537
|
|
|
698
|
-
def
|
|
538
|
+
def do_upload(cookbooks, options = {})
|
|
539
|
+
upload_opts = options.slice(:force, :freeze)
|
|
540
|
+
|
|
541
|
+
ridley_connection(options) do |conn|
|
|
542
|
+
cookbooks.each do |cookbook|
|
|
543
|
+
Berkshelf.formatter.upload(cookbook.cookbook_name, cookbook.version, conn.server_url)
|
|
544
|
+
validate_files!(cookbook)
|
|
545
|
+
|
|
546
|
+
begin
|
|
547
|
+
conn.cookbook.upload(cookbook.path, upload_opts.merge(name: cookbook.cookbook_name))
|
|
548
|
+
rescue Ridley::Errors::FrozenCookbook => ex
|
|
549
|
+
if options[:halt_on_frozen]
|
|
550
|
+
raise Berkshelf::FrozenCookbook, ex
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
# Filter the cookbooks to upload based on a set of given names. The dependencies of a cookbook
|
|
558
|
+
# will always be included in the filtered results even if the dependency's name is not
|
|
559
|
+
# explicitly provided.
|
|
560
|
+
#
|
|
561
|
+
# @param [Array<Berkshelf::CachedCookbooks>] cookbooks
|
|
562
|
+
# set of cookbooks to filter
|
|
563
|
+
# @param [Array<String>] names
|
|
564
|
+
# names of cookbooks to include in the filtered results
|
|
565
|
+
#
|
|
566
|
+
# @return [Array<Berkshelf::CachedCookbooks]
|
|
567
|
+
def filter_to_upload(cookbooks, names)
|
|
568
|
+
unless names.empty?
|
|
569
|
+
explicit = cookbooks.select { |cookbook| names.include?(cookbook.cookbook_name) }
|
|
570
|
+
explicit.each do |cookbook|
|
|
571
|
+
cookbook.dependencies.each do |name, version|
|
|
572
|
+
explicit += cookbooks.select { |cookbook| cookbook.cookbook_name == name }
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
cookbooks = explicit.uniq
|
|
576
|
+
end
|
|
577
|
+
cookbooks
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# @raise [Berkshelf::ChefConnectionError]
|
|
581
|
+
def ridley_connection(options = {}, &block)
|
|
699
582
|
ridley_options = options.slice(:ssl)
|
|
700
|
-
ridley_options[:server_url] = options[:server_url] || Berkshelf
|
|
701
|
-
ridley_options[:client_name] =
|
|
702
|
-
ridley_options[:client_key] =
|
|
703
|
-
ridley_options[:ssl] = { verify: (options[:ssl_verify] || Berkshelf
|
|
583
|
+
ridley_options[:server_url] = options[:server_url] || Berkshelf.config.chef.chef_server_url
|
|
584
|
+
ridley_options[:client_name] = Berkshelf.config.chef.node_name
|
|
585
|
+
ridley_options[:client_key] = Berkshelf.config.chef.client_key
|
|
586
|
+
ridley_options[:ssl] = { verify: (options[:ssl_verify] || Berkshelf.config.ssl.verify) }
|
|
704
587
|
|
|
705
588
|
unless ridley_options[:server_url].present?
|
|
706
589
|
raise ChefConnectionError, 'Missing required attribute in your Berkshelf configuration: chef.server_url'
|
|
@@ -714,12 +597,10 @@ module Berkshelf
|
|
|
714
597
|
raise ChefConnectionError, 'Missing required attribute in your Berkshelf configuration: chef.client_key'
|
|
715
598
|
end
|
|
716
599
|
|
|
717
|
-
Ridley.
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
hack = FileUtils::Entry_.new('/tmp')
|
|
722
|
-
hack.send(:descendant_diretory?, candidate, parent)
|
|
600
|
+
Ridley.open(ridley_options, &block)
|
|
601
|
+
rescue Ridley::Errors::RidleyError => ex
|
|
602
|
+
log_exception(ex)
|
|
603
|
+
raise ChefConnectionError, ex # todo implement
|
|
723
604
|
end
|
|
724
605
|
|
|
725
606
|
# Determine if any cookbooks were specified that aren't in our shelf.
|
|
@@ -730,52 +611,12 @@ module Berkshelf
|
|
|
730
611
|
# @raise [Berkshelf::CookbookNotFound]
|
|
731
612
|
# if a cookbook name is given that does not exist
|
|
732
613
|
def validate_cookbook_names!(options = {})
|
|
733
|
-
missing = (Array(options[:cookbooks]) -
|
|
614
|
+
missing = (Array(options[:cookbooks]) - dependencies.map(&:name))
|
|
734
615
|
unless missing.empty?
|
|
735
616
|
raise Berkshelf::CookbookNotFound,
|
|
736
|
-
"Could not find
|
|
737
|
-
"in any of the
|
|
738
|
-
end
|
|
739
|
-
end
|
|
740
|
-
|
|
741
|
-
# The list of sources "locked" by the lockfile.
|
|
742
|
-
#
|
|
743
|
-
# @return [Array<Berkshelf::CookbookSource>]
|
|
744
|
-
# the list of sources in this lockfile
|
|
745
|
-
def locked_sources
|
|
746
|
-
lockfile.sources
|
|
747
|
-
end
|
|
748
|
-
|
|
749
|
-
# Merge the locked sources against the given sources.
|
|
750
|
-
#
|
|
751
|
-
# For each the given sources, check if there's a locked version that
|
|
752
|
-
# still satisfies the version constraint. If it does, "lock" that source
|
|
753
|
-
# because we should just use the locked version.
|
|
754
|
-
#
|
|
755
|
-
# If a locked source exists, but doesn't satisfy the constraint, raise a
|
|
756
|
-
# {Berkshelf::OutdatedCookbookSource} and tell the user to run update.
|
|
757
|
-
def apply_lockfile(sources = [])
|
|
758
|
-
sources.collect do |source|
|
|
759
|
-
source_from_lockfile(source) || source
|
|
760
|
-
end
|
|
761
|
-
end
|
|
762
|
-
|
|
763
|
-
def source_from_lockfile(source)
|
|
764
|
-
locked_source = lockfile.find(source)
|
|
765
|
-
|
|
766
|
-
return nil unless locked_source
|
|
767
|
-
|
|
768
|
-
# If there's a locked_version, make sure it's still satisfied
|
|
769
|
-
# by the constraint
|
|
770
|
-
if locked_source.locked_version
|
|
771
|
-
unless source.version_constraint.satisfies?(locked_source.locked_version)
|
|
772
|
-
raise Berkshelf::OutdatedCookbookSource.new(locked_source, source)
|
|
773
|
-
end
|
|
617
|
+
"Could not find cookbook(s) #{missing.collect{ |c| "'#{c}'" }.join(', ')} " +
|
|
618
|
+
"in any of the configured dependencies. #{missing.size == 1 ? 'Is it' : 'Are they' } in your Berksfile?"
|
|
774
619
|
end
|
|
775
|
-
|
|
776
|
-
# Update to the new constraint (it might have changed, but still be satisfied)
|
|
777
|
-
locked_source.version_constraint = source.version_constraint
|
|
778
|
-
locked_source
|
|
779
620
|
end
|
|
780
621
|
|
|
781
622
|
# Validate that the given cookbook does not have "bad" files. Currently
|
|
@@ -793,34 +634,5 @@ module Berkshelf
|
|
|
793
634
|
|
|
794
635
|
raise Berkshelf::InvalidCookbookFiles.new(cookbook, files) unless files.empty?
|
|
795
636
|
end
|
|
796
|
-
|
|
797
|
-
# Verify that the licenses of all the cached cookbooks fall in the realm of
|
|
798
|
-
# allowed licenses from the Berkshelf Config.
|
|
799
|
-
#
|
|
800
|
-
# @raise [Berkshelf::LicenseNotAllowed]
|
|
801
|
-
# if the license is not permitted and `raise_license_exception` is true
|
|
802
|
-
def verify_licenses!
|
|
803
|
-
licenses = Array(Berkshelf::Config.instance.allowed_licenses)
|
|
804
|
-
return if licenses.empty?
|
|
805
|
-
|
|
806
|
-
sources.each do |source|
|
|
807
|
-
next if source.location.is_a?(Berkshelf::PathLocation)
|
|
808
|
-
cached = source.cached_cookbook
|
|
809
|
-
|
|
810
|
-
begin
|
|
811
|
-
unless licenses.include?(cached.metadata.license)
|
|
812
|
-
raise Berkshelf::LicenseNotAllowed.new(cached)
|
|
813
|
-
end
|
|
814
|
-
rescue Berkshelf::LicenseNotAllowed => e
|
|
815
|
-
if Berkshelf::Config.instance.raise_license_exception
|
|
816
|
-
FileUtils.rm_rf(cached.path)
|
|
817
|
-
raise
|
|
818
|
-
end
|
|
819
|
-
|
|
820
|
-
Berkshelf.ui.warn(e.to_s)
|
|
821
|
-
end
|
|
822
|
-
end
|
|
823
|
-
end
|
|
824
|
-
|
|
825
637
|
end
|
|
826
638
|
end
|