berkshelf 3.0.0.beta7 → 3.0.0.beta8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +4 -1
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +0 -1
- data/Guardfile +0 -8
- data/README.md +33 -13
- data/berkshelf.gemspec +3 -3
- data/features/commands/install.feature +16 -88
- data/features/commands/search.feature +15 -0
- data/features/commands/shelf/show.feature +2 -2
- data/features/commands/shelf/uninstall.feature +1 -1
- data/features/commands/show.feature +3 -3
- data/features/commands/update.feature +29 -1
- data/features/commands/upload.feature +172 -7
- data/features/commands/vendor.feature +32 -0
- data/features/json_formatter.feature +26 -24
- data/features/lifecycle.feature +285 -0
- data/features/lockfile.feature +9 -7
- data/features/step_definitions/chef_server_steps.rb +1 -0
- data/features/step_definitions/cli_steps.rb +2 -2
- data/features/step_definitions/filesystem_steps.rb +2 -4
- data/gem_graph.png +0 -0
- data/generator_files/chefignore +0 -2
- data/lib/berkshelf.rb +39 -14
- data/lib/berkshelf/berksfile.rb +161 -113
- data/lib/berkshelf/cached_cookbook.rb +2 -2
- data/lib/berkshelf/cli.rb +15 -3
- data/lib/berkshelf/commands/shelf.rb +3 -7
- data/lib/berkshelf/community_rest.rb +9 -9
- data/lib/berkshelf/config.rb +3 -3
- data/lib/berkshelf/cookbook_generator.rb +0 -8
- data/lib/berkshelf/cookbook_store.rb +1 -2
- data/lib/berkshelf/dependency.rb +25 -138
- data/lib/berkshelf/downloader.rb +41 -7
- data/lib/berkshelf/errors.rb +113 -214
- data/lib/berkshelf/formatters/base.rb +42 -0
- data/lib/berkshelf/formatters/human.rb +145 -0
- data/lib/berkshelf/formatters/json.rb +149 -133
- data/lib/berkshelf/formatters/null.rb +8 -18
- data/lib/berkshelf/init_generator.rb +1 -1
- data/lib/berkshelf/installer.rb +115 -104
- data/lib/berkshelf/location.rb +22 -121
- data/lib/berkshelf/locations/base.rb +75 -0
- data/lib/berkshelf/locations/git.rb +196 -0
- data/lib/berkshelf/locations/github.rb +8 -0
- data/lib/berkshelf/locations/path.rb +78 -0
- data/lib/berkshelf/lockfile.rb +452 -290
- data/lib/berkshelf/logger.rb +9 -3
- data/lib/berkshelf/mixin/logging.rb +4 -9
- data/lib/berkshelf/resolver.rb +12 -12
- data/lib/berkshelf/source.rb +13 -1
- data/lib/berkshelf/version.rb +1 -1
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +3 -7
- data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +3 -6
- data/spec/spec_helper.rb +5 -6
- data/spec/support/matchers/file_system_matchers.rb +4 -0
- data/spec/support/shared_examples/formatter.rb +11 -0
- data/spec/unit/berkshelf/berksfile_spec.rb +25 -28
- data/spec/unit/berkshelf/cli_spec.rb +19 -11
- data/spec/unit/berkshelf/dependency_spec.rb +4 -164
- data/spec/unit/berkshelf/formatters/base_spec.rb +35 -0
- data/spec/unit/berkshelf/formatters/human_spec.rb +7 -0
- data/spec/unit/berkshelf/formatters/json_spec.rb +7 -0
- data/spec/unit/berkshelf/formatters/null_spec.rb +7 -11
- data/spec/unit/berkshelf/location_spec.rb +16 -144
- data/spec/unit/berkshelf/locations/base_spec.rb +80 -0
- data/spec/unit/berkshelf/locations/git_spec.rb +249 -0
- data/spec/unit/berkshelf/locations/path_spec.rb +107 -0
- data/spec/unit/berkshelf/lockfile_parser_spec.rb +3 -3
- data/spec/unit/berkshelf/lockfile_spec.rb +55 -11
- data/spec/unit/berkshelf/logger_spec.rb +2 -2
- data/spec/unit/berkshelf/mixin/logging_spec.rb +5 -9
- data/spec/unit/berkshelf/source_spec.rb +32 -13
- data/spec/unit/berkshelf_spec.rb +6 -9
- metadata +33 -33
- data/.ruby-version +0 -1
- data/berkshelf-complete.sh +0 -75
- data/lib/berkshelf/formatters.rb +0 -110
- data/lib/berkshelf/formatters/human_readable.rb +0 -142
- data/lib/berkshelf/git.rb +0 -204
- data/lib/berkshelf/locations/git_location.rb +0 -135
- data/lib/berkshelf/locations/github_location.rb +0 -55
- data/lib/berkshelf/locations/mercurial_location.rb +0 -114
- data/lib/berkshelf/locations/path_location.rb +0 -88
- data/lib/berkshelf/mercurial.rb +0 -146
- data/lib/berkshelf/mixin.rb +0 -7
- data/spec/support/mercurial.rb +0 -123
- data/spec/unit/berkshelf/formatters_spec.rb +0 -114
- data/spec/unit/berkshelf/git_spec.rb +0 -312
- data/spec/unit/berkshelf/locations/git_location_spec.rb +0 -126
- data/spec/unit/berkshelf/locations/mercurial_location_spec.rb +0 -131
- data/spec/unit/berkshelf/locations/path_location_spec.rb +0 -25
- data/spec/unit/berkshelf/mercurial_spec.rb +0 -172
@@ -7,6 +7,7 @@ end
|
|
7
7
|
Given /^the Chef Server has cookbooks:$/ do |cookbooks|
|
8
8
|
cookbooks.raw.each do |name, version, dependencies|
|
9
9
|
metadata = []
|
10
|
+
metadata << "name '#{name}'"
|
10
11
|
metadata << "version '#{version}'"
|
11
12
|
dependencies.to_s.split(',').map { |d| d.split(' ', 2) }.each do |(name, constraint)|
|
12
13
|
metadata << "depends '#{name}', '#{constraint}'"
|
@@ -5,10 +5,8 @@ World(Berkshelf::RSpec::ChefAPI)
|
|
5
5
|
World(Berkshelf::RSpec::FileSystemMatchers)
|
6
6
|
|
7
7
|
Given /^a cookbook named "(.*?)"$/ do |name|
|
8
|
-
|
9
|
-
|
10
|
-
And an empty file named "#{name}/metadata.rb"
|
11
|
-
}
|
8
|
+
create_dir(name)
|
9
|
+
write_file(File.join(name, "metadata.rb"), "name '#{name}'")
|
12
10
|
end
|
13
11
|
|
14
12
|
Given /^the cookbook "(.*?)" has the file "(.*?)" with:$/ do |cookbook_name, file_name, content|
|
data/gem_graph.png
ADDED
Binary file
|
data/generator_files/chefignore
CHANGED
data/lib/berkshelf.rb
CHANGED
@@ -17,16 +17,30 @@ require_relative 'berkshelf/thor_ext'
|
|
17
17
|
module Berkshelf
|
18
18
|
require_relative 'berkshelf/version'
|
19
19
|
require_relative 'berkshelf/errors'
|
20
|
-
|
20
|
+
|
21
|
+
module Mixin
|
22
|
+
autoload :DSLEval, 'berkshelf/mixin/dsl_eval'
|
23
|
+
autoload :Logging, 'berkshelf/mixin/logging'
|
24
|
+
end
|
25
|
+
|
26
|
+
autoload :BaseFormatter, 'berkshelf/formatters/base'
|
27
|
+
autoload :HumanFormatter, 'berkshelf/formatters/human'
|
28
|
+
autoload :JsonFormatter, 'berkshelf/formatters/json'
|
29
|
+
autoload :NullFormatter, 'berkshelf/formatters/null'
|
30
|
+
|
31
|
+
autoload :Location, 'berkshelf/location'
|
32
|
+
autoload :BaseLocation, 'berkshelf/locations/base'
|
33
|
+
autoload :GitLocation, 'berkshelf/locations/git'
|
34
|
+
autoload :GithubLocation, 'berkshelf/locations/github'
|
35
|
+
autoload :PathLocation, 'berkshelf/locations/path'
|
21
36
|
|
22
37
|
DEFAULT_FILENAME = 'Berksfile'.freeze
|
23
38
|
|
24
39
|
class << self
|
25
|
-
include
|
40
|
+
include Mixin::Logging
|
26
41
|
|
27
42
|
attr_writer :berkshelf_path
|
28
43
|
attr_accessor :ui
|
29
|
-
attr_accessor :logger
|
30
44
|
|
31
45
|
# @return [Pathname]
|
32
46
|
def root
|
@@ -79,8 +93,7 @@ module Berkshelf
|
|
79
93
|
FileUtils.mkdir_p(berkshelf_path, mode: 0755)
|
80
94
|
|
81
95
|
unless File.writable?(berkshelf_path)
|
82
|
-
raise InsufficientPrivledges
|
83
|
-
" Please either chown the directory or use a different filepath."
|
96
|
+
raise InsufficientPrivledges.new(berkshelf_path)
|
84
97
|
end
|
85
98
|
end
|
86
99
|
|
@@ -108,7 +121,7 @@ module Berkshelf
|
|
108
121
|
#
|
109
122
|
# @return [~Formatter]
|
110
123
|
def formatter
|
111
|
-
@formatter ||=
|
124
|
+
@formatter ||= HumanFormatter.new
|
112
125
|
end
|
113
126
|
|
114
127
|
# @raise [Berkshelf::ChefConnectionError]
|
@@ -137,7 +150,7 @@ module Berkshelf
|
|
137
150
|
Celluloid.logger = nil unless ENV["DEBUG_CELLULOID"]
|
138
151
|
Ridley.open(ridley_options, &block)
|
139
152
|
rescue Ridley::Errors::RidleyError => ex
|
140
|
-
|
153
|
+
log.exception(ex)
|
141
154
|
raise ChefConnectionError, ex # todo implement
|
142
155
|
end
|
143
156
|
|
@@ -149,8 +162,24 @@ module Berkshelf
|
|
149
162
|
# @example Berkshelf.set_format :json
|
150
163
|
#
|
151
164
|
# @return [~Formatter]
|
152
|
-
def set_format(
|
153
|
-
|
165
|
+
def set_format(name)
|
166
|
+
id = name.to_s.capitalize
|
167
|
+
@formatter = Berkshelf.const_get("#{id}Formatter").new
|
168
|
+
end
|
169
|
+
|
170
|
+
# Location an executable in the current user's $PATH
|
171
|
+
#
|
172
|
+
# @return [String, nil]
|
173
|
+
# the path to the executable, or +nil+ if not present
|
174
|
+
def which(executable)
|
175
|
+
if File.file?(executable) && File.executable?(executable)
|
176
|
+
executable
|
177
|
+
elsif ENV['PATH']
|
178
|
+
path = ENV['PATH'].split(File::PATH_SEPARATOR).find do |p|
|
179
|
+
File.executable?(File.join(p, executable))
|
180
|
+
end
|
181
|
+
path && File.expand_path(executable, path)
|
182
|
+
end
|
154
183
|
end
|
155
184
|
|
156
185
|
private
|
@@ -177,17 +206,13 @@ require_relative 'berkshelf/cookbook_store'
|
|
177
206
|
require_relative 'berkshelf/config'
|
178
207
|
require_relative 'berkshelf/dependency'
|
179
208
|
require_relative 'berkshelf/downloader'
|
180
|
-
require_relative 'berkshelf/formatters'
|
181
|
-
require_relative 'berkshelf/git'
|
182
|
-
require_relative 'berkshelf/mercurial'
|
183
209
|
require_relative 'berkshelf/init_generator'
|
184
210
|
require_relative 'berkshelf/installer'
|
185
|
-
require_relative 'berkshelf/location'
|
186
211
|
require_relative 'berkshelf/logger'
|
187
212
|
require_relative 'berkshelf/resolver'
|
188
213
|
require_relative 'berkshelf/source'
|
189
214
|
require_relative 'berkshelf/source_uri'
|
190
215
|
require_relative 'berkshelf/ui'
|
191
216
|
|
192
|
-
Ridley.logger = Berkshelf.logger
|
217
|
+
Ridley.logger = Berkshelf.logger
|
193
218
|
Berkshelf.logger.level = Logger::WARN
|
data/lib/berkshelf/berksfile.rb
CHANGED
@@ -28,13 +28,14 @@ module Berkshelf
|
|
28
28
|
|
29
29
|
DEFAULT_API_URL = "https://api.berkshelf.com".freeze
|
30
30
|
|
31
|
-
include
|
32
|
-
include
|
31
|
+
include Mixin::Logging
|
32
|
+
include Mixin::DSLEval
|
33
33
|
extend Forwardable
|
34
34
|
|
35
35
|
expose_method :source
|
36
36
|
expose_method :site # @todo remove in Berkshelf 4.0
|
37
37
|
expose_method :chef_api # @todo remove in Berkshelf 4.0
|
38
|
+
expose_method :extension
|
38
39
|
expose_method :metadata
|
39
40
|
expose_method :cookbook
|
40
41
|
expose_method :group
|
@@ -60,7 +61,7 @@ module Berkshelf
|
|
60
61
|
@sources = Hash.new
|
61
62
|
|
62
63
|
if options[:except] && options[:only]
|
63
|
-
raise
|
64
|
+
raise ArgumentError, 'Cannot specify both :except and :only!'
|
64
65
|
elsif options[:except]
|
65
66
|
except = Array(options[:except]).collect(&:to_sym)
|
66
67
|
@filter = ->(dependency) { (except & dependency.groups).empty? }
|
@@ -72,6 +73,26 @@ module Berkshelf
|
|
72
73
|
end
|
73
74
|
end
|
74
75
|
|
76
|
+
# Activate a Berkshelf extension at runtime.
|
77
|
+
#
|
78
|
+
# @example Activate the Mercurial extension
|
79
|
+
# extension 'hg'
|
80
|
+
#
|
81
|
+
# @raise [LoadError]
|
82
|
+
# if the extension cannot be loaded
|
83
|
+
#
|
84
|
+
# @param [String] name
|
85
|
+
# the name of the extension to activate
|
86
|
+
#
|
87
|
+
# @return [true]
|
88
|
+
def extension(name)
|
89
|
+
require "berkshelf/#{name}"
|
90
|
+
true
|
91
|
+
rescue LoadError
|
92
|
+
raise LoadError, "Could not load an extension by the name `#{name}'. " \
|
93
|
+
"Please make sure it is installed."
|
94
|
+
end
|
95
|
+
|
75
96
|
# Add a cookbook dependency to the Berksfile to be retrieved and have its dependencies recursively retrieved
|
76
97
|
# and resolved.
|
77
98
|
#
|
@@ -159,14 +180,14 @@ module Berkshelf
|
|
159
180
|
# @param [String] api_url
|
160
181
|
# url for the api to add
|
161
182
|
#
|
162
|
-
# @raise [
|
183
|
+
# @raise [InvalidSourceURI]
|
163
184
|
#
|
164
|
-
# @return [Array<
|
185
|
+
# @return [Array<Source>]
|
165
186
|
def source(api_url)
|
166
187
|
@sources[api_url] = Source.new(api_url)
|
167
188
|
end
|
168
189
|
|
169
|
-
# @return [Array<
|
190
|
+
# @return [Array<Source>]
|
170
191
|
def sources
|
171
192
|
if @sources.empty?
|
172
193
|
raise NoAPISourcesDefined
|
@@ -183,7 +204,7 @@ module Berkshelf
|
|
183
204
|
|
184
205
|
# @todo remove in Berkshelf 4.0
|
185
206
|
#
|
186
|
-
# @raise [
|
207
|
+
# @raise [DeprecatedError]
|
187
208
|
def site(*args)
|
188
209
|
if args.first == :opscode
|
189
210
|
Berkshelf.formatter.deprecation "Your Berksfile contains a site location pointing to the Opscode Community " +
|
@@ -194,16 +215,16 @@ module Berkshelf
|
|
194
215
|
return
|
195
216
|
end
|
196
217
|
|
197
|
-
raise
|
218
|
+
raise DeprecatedError.new "Your Berksfile contains a site location. Site locations have been " +
|
198
219
|
" replaced by the source location. Please remove your site location and try again. For more information " +
|
199
220
|
" visit https://github.com/berkshelf/berkshelf/wiki/deprecated-locations"
|
200
221
|
end
|
201
222
|
|
202
223
|
# @todo remove in Berkshelf 4.0
|
203
224
|
#
|
204
|
-
# @raise [
|
225
|
+
# @raise [DeprecatedError]
|
205
226
|
def chef_api(*args)
|
206
|
-
raise
|
227
|
+
raise DeprecatedError.new "Your Berksfile contains a chef_api location. Chef API locations have " +
|
207
228
|
" been replaced by the source location. Please remove your site location and try again. For more " +
|
208
229
|
" information visit https://github.com/berkshelf/berkshelf/wiki/deprecated-locations"
|
209
230
|
end
|
@@ -225,14 +246,13 @@ module Berkshelf
|
|
225
246
|
# @raise [DuplicateDependencyDefined] if a dependency is added whose name conflicts
|
226
247
|
# with a dependency who has already been added.
|
227
248
|
#
|
228
|
-
# @return [Array<
|
249
|
+
# @return [Array<Dependency]
|
229
250
|
def add_dependency(name, constraint = nil, options = {})
|
230
|
-
if
|
251
|
+
if @dependencies[name]
|
231
252
|
# Only raise an exception if the dependency is a true duplicate
|
232
253
|
groups = (options[:group].nil? || options[:group].empty?) ? [:default] : options[:group]
|
233
254
|
if !(@dependencies[name].groups & groups).empty?
|
234
|
-
raise DuplicateDependencyDefined
|
235
|
-
"Berksfile contains multiple entries named '#{name}'. Use only one, or put them in different groups."
|
255
|
+
raise DuplicateDependencyDefined.new(name)
|
236
256
|
end
|
237
257
|
end
|
238
258
|
|
@@ -242,27 +262,22 @@ module Berkshelf
|
|
242
262
|
|
243
263
|
options[:constraint] = constraint
|
244
264
|
|
245
|
-
@dependencies[name] =
|
265
|
+
@dependencies[name] = Dependency.new(self, name, options)
|
246
266
|
end
|
247
267
|
|
248
|
-
#
|
249
|
-
#
|
268
|
+
# Check if the Berksfile has the given dependency, taking into account
|
269
|
+
# +group+ and --only/--except flags.
|
250
270
|
#
|
251
|
-
# @
|
252
|
-
|
253
|
-
@dependencies.delete(dependency.to_s)
|
254
|
-
end
|
255
|
-
|
256
|
-
# @param [#to_s] dependency
|
257
|
-
# the dependency to check presence of
|
271
|
+
# @param [String, Dependency] dependency
|
272
|
+
# the dependency or name of dependency to check presence of
|
258
273
|
#
|
259
274
|
# @return [Boolean]
|
260
275
|
def has_dependency?(dependency)
|
261
|
-
|
276
|
+
name = Dependency.name(dependency)
|
277
|
+
dependencies.map(&:name).include?(name)
|
262
278
|
end
|
263
279
|
|
264
|
-
|
265
|
-
# @return [Array<Berkshelf::Dependency>]
|
280
|
+
# @return [Array<Dependency>]
|
266
281
|
def dependencies
|
267
282
|
@dependencies.values.sort.select(&@filter)
|
268
283
|
end
|
@@ -288,30 +303,24 @@ module Berkshelf
|
|
288
303
|
#
|
289
304
|
# @param [String] name
|
290
305
|
# the name of the cookbook dependency to search for
|
291
|
-
# @return [
|
306
|
+
# @return [Dependency, nil]
|
292
307
|
# the cookbook dependency, or nil if one does not exist
|
293
308
|
def find(name)
|
294
309
|
@dependencies[name]
|
295
310
|
end
|
296
311
|
|
297
|
-
# Find a dependency, raising an exception if it is not found.
|
298
|
-
# @see {find}
|
299
|
-
def find!(name)
|
300
|
-
find(name) || raise(DependencyNotFound.new(name))
|
301
|
-
end
|
302
|
-
|
303
312
|
# @return [Hash]
|
304
|
-
# a hash containing group names as keys and an array of
|
313
|
+
# a hash containing group names as keys and an array of Dependencies
|
305
314
|
# that are a member of that group as values
|
306
315
|
#
|
307
316
|
# Example:
|
308
317
|
# {
|
309
318
|
# nautilus: [
|
310
|
-
# #<
|
311
|
-
# #<
|
319
|
+
# #<Dependency: nginx (~> 1.0.0)>,
|
320
|
+
# #<Dependency: mysql (~> 1.2.4)>
|
312
321
|
# ],
|
313
322
|
# skarner: [
|
314
|
-
# #<
|
323
|
+
# #<Dependency: nginx (~> 1.0.0)>
|
315
324
|
# ]
|
316
325
|
# }
|
317
326
|
def groups
|
@@ -328,7 +337,7 @@ module Berkshelf
|
|
328
337
|
# @param [String] name
|
329
338
|
# name of the dependency to return
|
330
339
|
#
|
331
|
-
# @return [
|
340
|
+
# @return [Dependency]
|
332
341
|
def [](name)
|
333
342
|
@dependencies[name]
|
334
343
|
end
|
@@ -347,7 +356,7 @@ module Berkshelf
|
|
347
356
|
# sources. If not, then either a version constraint has changed,
|
348
357
|
# or a new source has been added to the Berksfile. In the event that
|
349
358
|
# a locked_source exists, but it no longer satisfies the constraint,
|
350
|
-
# this method will raise a {
|
359
|
+
# this method will raise a {OutdatedCookbookSource}, and
|
351
360
|
# inform the user to run <tt>berks update COOKBOOK</tt> to remedy the issue.
|
352
361
|
# - Remove any locked sources that no longer exist in the Berksfile
|
353
362
|
# (i.e. a cookbook source was removed from the Berksfile).
|
@@ -356,10 +365,10 @@ module Berkshelf
|
|
356
365
|
#
|
357
366
|
# 3. Write out a new lockfile.
|
358
367
|
#
|
359
|
-
# @raise [
|
368
|
+
# @raise [OutdatedDependency]
|
360
369
|
# if the lockfile constraints do not satisfy the Berksfile constraints
|
361
370
|
#
|
362
|
-
# @return [Array<
|
371
|
+
# @return [Array<CachedCookbook>]
|
363
372
|
def install
|
364
373
|
Installer.new(self).run
|
365
374
|
end
|
@@ -405,12 +414,12 @@ module Berkshelf
|
|
405
414
|
|
406
415
|
# The cached cookbooks installed by this Berksfile.
|
407
416
|
#
|
408
|
-
# @raise [
|
417
|
+
# @raise [LockfileNotFound]
|
409
418
|
# if there is no lockfile
|
410
|
-
# @raise [
|
419
|
+
# @raise [CookbookNotFound]
|
411
420
|
# if a listed source could not be found
|
412
421
|
#
|
413
|
-
# @return [Hash<
|
422
|
+
# @return [Hash<Dependency, CachedCookbook>]
|
414
423
|
# the list of dependencies as keys and the cached cookbook as the value
|
415
424
|
def list
|
416
425
|
validate_lockfile_present!
|
@@ -465,47 +474,79 @@ module Berkshelf
|
|
465
474
|
|
466
475
|
# Upload the cookbooks installed by this Berksfile
|
467
476
|
#
|
468
|
-
# @
|
469
|
-
#
|
470
|
-
#
|
471
|
-
#
|
472
|
-
#
|
473
|
-
# @
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
#
|
478
|
-
#
|
479
|
-
#
|
480
|
-
#
|
481
|
-
#
|
482
|
-
#
|
483
|
-
#
|
484
|
-
#
|
485
|
-
#
|
486
|
-
#
|
487
|
-
#
|
477
|
+
# @overload upload(names = [])
|
478
|
+
# @param [Array<String>] names
|
479
|
+
# the list of cookbooks (by name) to upload to the remote Chef Server
|
480
|
+
#
|
481
|
+
#
|
482
|
+
# @overload upload(names = [], options = {})
|
483
|
+
# @param [Array<String>] names
|
484
|
+
# the list of cookbooks (by name) to upload to the remote Chef Server
|
485
|
+
# @param [Hash<Symbol, Object>] options
|
486
|
+
# the list of options to pass to the uploader
|
487
|
+
#
|
488
|
+
# @option options [Boolean] :force (false)
|
489
|
+
# upload the cookbooks even if the version already exists and is frozen
|
490
|
+
# on the remote Chef Server
|
491
|
+
# @option options [Boolean] :freeze (true)
|
492
|
+
# freeze the uploaded cookbooks on the remote Chef Server so that it
|
493
|
+
# cannot be overwritten on future uploads
|
494
|
+
# @option options [Hash] :ssl_verify (true)
|
495
|
+
# use SSL verification while connecting to the remote Chef Server
|
496
|
+
# @option options [Boolean] :halt_on_frozen (false)
|
497
|
+
# raise an exception ({FrozenCookbook}) if one of the cookbooks already
|
498
|
+
# exists on the remote Chef Server and is frozen
|
499
|
+
# @option options [String] :server_url
|
500
|
+
# the URL (endpoint) to the remote Chef Server
|
501
|
+
# @option options [String] :client_name
|
502
|
+
# the client name for the remote Chef Server
|
503
|
+
# @option options [String] :client_key
|
504
|
+
# the client key (pem) for the remote Chef Server
|
505
|
+
#
|
506
|
+
#
|
507
|
+
# @example Upload all cookbooks
|
508
|
+
# berksfile.upload
|
509
|
+
#
|
510
|
+
# @example Upload the 'apache2' and 'mysql' cookbooks
|
511
|
+
# berksfile.upload('apache2', 'mysql')
|
512
|
+
#
|
513
|
+
# @example Upload and freeze all cookbooks
|
514
|
+
# berksfile.upload(freeze: true)
|
515
|
+
#
|
516
|
+
# @example Upload and freeze the `chef-sugar` cookbook
|
517
|
+
# berksfile.upload('chef-sugar', freeze: true)
|
518
|
+
#
|
519
|
+
#
|
520
|
+
# @raise [UploadFailure]
|
488
521
|
# if you are uploading cookbooks with an invalid or not-specified client key
|
489
|
-
# @raise [
|
522
|
+
# @raise [DependencyNotFound]
|
490
523
|
# if one of the given cookbooks is not a dependency defined in the Berksfile
|
491
|
-
# @raise [
|
524
|
+
# @raise [FrozenCookbook]
|
492
525
|
# if the cookbook being uploaded is a {metadata} cookbook and is already
|
493
526
|
# frozen on the remote Chef Server; indirect dependencies or non-metadata
|
494
527
|
# dependencies are just skipped
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
validate: true
|
502
|
-
}.merge(options)
|
528
|
+
#
|
529
|
+
# @return [Array<CachedCookbook>]
|
530
|
+
# the list of cookbooks that were uploaded to the Chef Server
|
531
|
+
def upload(*args)
|
532
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
533
|
+
names = args.flatten
|
503
534
|
|
504
|
-
|
535
|
+
validate_lockfile_present!
|
536
|
+
validate_lockfile_trusted!
|
537
|
+
validate_dependencies_installed!
|
538
|
+
validate_cookbook_names!(names)
|
505
539
|
|
506
|
-
|
507
|
-
|
508
|
-
|
540
|
+
# Calculate the list of cookbooks from the given arguments
|
541
|
+
if names.empty?
|
542
|
+
list = dependencies
|
543
|
+
else
|
544
|
+
list = dependencies.select { |dependency| names.include?(dependency.name) }
|
545
|
+
end
|
546
|
+
|
547
|
+
cookbooks = cookbooks_for_upload(list)
|
548
|
+
ridley_upload(cookbooks, options)
|
549
|
+
cookbooks
|
509
550
|
end
|
510
551
|
|
511
552
|
# Package the given cookbook for distribution outside of berkshelf. If the
|
@@ -515,7 +556,7 @@ module Berkshelf
|
|
515
556
|
# @param [String] path
|
516
557
|
# the path where the tarball will be created
|
517
558
|
#
|
518
|
-
# @raise [
|
559
|
+
# @raise [PackageError]
|
519
560
|
#
|
520
561
|
# @return [String]
|
521
562
|
# the path to the package
|
@@ -524,10 +565,8 @@ module Berkshelf
|
|
524
565
|
packager.validate!
|
525
566
|
|
526
567
|
outdir = Dir.mktmpdir do |temp_dir|
|
527
|
-
|
528
|
-
|
529
|
-
end
|
530
|
-
packager.run(source)
|
568
|
+
Berkshelf.ui.mute { vendor(File.join(temp_dir, 'cookbooks')) }
|
569
|
+
packager.run(temp_dir)
|
531
570
|
end
|
532
571
|
|
533
572
|
Berkshelf.formatter.package(outdir)
|
@@ -603,7 +642,7 @@ module Berkshelf
|
|
603
642
|
# the user can specify a different path to the Berksfile. So assuming the lockfile
|
604
643
|
# is named "Berksfile.lock" is a poor assumption.
|
605
644
|
#
|
606
|
-
# @return [
|
645
|
+
# @return [Lockfile]
|
607
646
|
# the lockfile corresponding to this berksfile, or a new Lockfile if one does
|
608
647
|
# not exist
|
609
648
|
def lockfile
|
@@ -612,8 +651,15 @@ module Berkshelf
|
|
612
651
|
|
613
652
|
private
|
614
653
|
|
615
|
-
def
|
616
|
-
|
654
|
+
def ridley_upload(cookbooks, options = {})
|
655
|
+
options = {
|
656
|
+
force: false,
|
657
|
+
freeze: true,
|
658
|
+
halt_on_frozen: false,
|
659
|
+
validate: true,
|
660
|
+
}.merge(options)
|
661
|
+
|
662
|
+
skipped = []
|
617
663
|
|
618
664
|
Berkshelf.ridley_connection(options) do |conn|
|
619
665
|
cookbooks.each do |cookbook|
|
@@ -629,45 +675,47 @@ module Berkshelf
|
|
629
675
|
})
|
630
676
|
rescue Ridley::Errors::FrozenCookbook => ex
|
631
677
|
if options[:halt_on_frozen]
|
632
|
-
raise
|
678
|
+
raise FrozenCookbook.new(cookbook)
|
633
679
|
end
|
634
680
|
|
635
681
|
Berkshelf.formatter.skip(cookbook, conn)
|
636
|
-
|
682
|
+
skipped << cookbook
|
637
683
|
end
|
638
684
|
end
|
639
685
|
end
|
640
686
|
|
641
|
-
unless
|
687
|
+
unless skipped.empty?
|
642
688
|
Berkshelf.formatter.msg "Skipped uploading some cookbooks because they" <<
|
643
689
|
" already exist on the remote server and are frozen. Re-run with the `--force`" <<
|
644
690
|
" flag to force overwrite these cookbooks:" <<
|
645
691
|
"\n\n" <<
|
646
|
-
" * " <<
|
692
|
+
" * " << skipped.map { |c| "#{c.cookbook_name} (#{c.version})" }.join("\n * ")
|
647
693
|
end
|
648
694
|
end
|
649
695
|
|
650
|
-
# Filter the
|
651
|
-
# will always be included in the filtered results even if
|
652
|
-
# explicitly provided.
|
696
|
+
# Filter the given dependencies for upload. The dependencies of a cookbook
|
697
|
+
# will always be included in the filtered results, even if that
|
698
|
+
# dependency's name is not explicitly provided.
|
653
699
|
#
|
654
|
-
# @param [Array<
|
655
|
-
#
|
656
|
-
# @param [Array<String>] names
|
657
|
-
# names of cookbooks to include in the filtered results
|
700
|
+
# @param [Array<Dependency>] dependencies
|
701
|
+
# the list of dependencies to filter for upload
|
658
702
|
#
|
659
|
-
# @return [Array<
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
703
|
+
# @return [Array<CachedCookbook>]
|
704
|
+
# the cookbook objects for uploading
|
705
|
+
def cookbooks_for_upload(dependencies)
|
706
|
+
dependencies.reduce({}) do |hash, dependency|
|
707
|
+
if hash[dependency.name].nil?
|
708
|
+
# TODO: make this a configurable option for advanced users to save
|
709
|
+
# time.
|
710
|
+
lockfile.graph.find(dependency).dependencies.each do |direct, _|
|
711
|
+
hash[direct] ||= lockfile.retrieve(direct)
|
666
712
|
end
|
713
|
+
|
714
|
+
hash[dependency.name] = lockfile.retrieve(dependency)
|
667
715
|
end
|
668
|
-
|
669
|
-
|
670
|
-
|
716
|
+
|
717
|
+
hash
|
718
|
+
end.values
|
671
719
|
end
|
672
720
|
|
673
721
|
# Ensure the lockfile is present on disk.
|
@@ -705,7 +753,7 @@ module Berkshelf
|
|
705
753
|
# @return [true]
|
706
754
|
def validate_dependencies_installed!
|
707
755
|
lockfile.graph.locks.each do |_, dependency|
|
708
|
-
unless dependency.
|
756
|
+
unless dependency.installed?
|
709
757
|
raise DependencyNotInstalled.new(dependency)
|
710
758
|
end
|
711
759
|
end
|
@@ -718,20 +766,20 @@ module Berkshelf
|
|
718
766
|
# @param [Array<String>] names
|
719
767
|
# a list of cookbook names
|
720
768
|
#
|
721
|
-
# @raise [
|
769
|
+
# @raise [DependencyNotFound]
|
722
770
|
# if a cookbook name is given that does not exist
|
723
771
|
def validate_cookbook_names!(names)
|
724
772
|
missing = names - dependencies.map(&:name)
|
725
773
|
|
726
774
|
unless missing.empty?
|
727
|
-
raise
|
775
|
+
raise DependencyNotFound.new(missing)
|
728
776
|
end
|
729
777
|
end
|
730
778
|
|
731
779
|
# Validate that the given cookbook does not have "bad" files. Currently
|
732
780
|
# this means including spaces in filenames (such as recipes)
|
733
781
|
#
|
734
|
-
# @param [
|
782
|
+
# @param [CachedCookbook] cookbook
|
735
783
|
# the Cookbook to validate
|
736
784
|
def validate_files!(cookbook)
|
737
785
|
path = cookbook.path.to_s
|
@@ -741,7 +789,7 @@ module Berkshelf
|
|
741
789
|
f.gsub(parent, '') =~ /[[:space:]]/
|
742
790
|
end
|
743
791
|
|
744
|
-
raise
|
792
|
+
raise InvalidCookbookFiles.new(cookbook, files) unless files.empty?
|
745
793
|
end
|
746
794
|
end
|
747
795
|
end
|