berkshelf 1.3.1 → 1.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/CHANGELOG.md +6 -0
- data/berkshelf.gemspec +1 -1
- data/lib/berkshelf.rb +5 -12
- data/lib/berkshelf/berksfile.rb +104 -70
- data/lib/berkshelf/cached_cookbook.rb +1 -1
- data/lib/berkshelf/chef/cookbook/chefignore.rb +15 -0
- data/lib/berkshelf/cli.rb +19 -33
- data/lib/berkshelf/cookbook_source.rb +111 -27
- data/lib/berkshelf/errors.rb +3 -1
- data/lib/berkshelf/locations/git_location.rb +19 -0
- data/lib/berkshelf/locations/path_location.rb +2 -1
- data/lib/berkshelf/logger.rb +9 -0
- data/lib/berkshelf/mixin/logging.rb +18 -0
- data/lib/berkshelf/version.rb +1 -1
- data/spec/support/chef_api.rb +2 -2
- data/spec/unit/berkshelf/berksfile_spec.rb +275 -279
- data/spec/unit/berkshelf/chef/cookbook/chefignore_spec.rb +23 -0
- data/spec/unit/berkshelf/cookbook_source_spec.rb +32 -8
- data/spec/unit/berkshelf/locations/git_location_spec.rb +14 -0
- data/spec/unit/berkshelf/logger_spec.rb +29 -0
- data/spec/unit/berkshelf/mixin/logging_spec.rb +25 -0
- data/spec/unit/berkshelf_spec.rb +2 -2
- metadata +17 -12
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 1.3.1
|
2
|
+
- Support for Vagrant 1.1.x
|
3
|
+
- Move Berkshelf Vagrant plugin into it's [own repository](https://github.com/RiotGames/berkshelf-vagrant)
|
4
|
+
- Added -d flag to output debug information in berks command
|
5
|
+
- Various bug fixes in uploading cookbooks
|
6
|
+
|
1
7
|
# 1.2.0
|
2
8
|
- Remove Vagrant as a gem dependency
|
3
9
|
- Remove Chef as a gem dependency
|
data/berkshelf.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
s.add_dependency 'mixlib-shellout', '~> 1.1'
|
34
34
|
s.add_dependency 'mixlib-config', '~> 1.1'
|
35
35
|
s.add_dependency 'faraday', '>= 0.8.5'
|
36
|
-
s.add_dependency 'ridley', '
|
36
|
+
s.add_dependency 'ridley', '~> 0.9.0'
|
37
37
|
s.add_dependency 'chozo', '>= 0.6.1'
|
38
38
|
s.add_dependency 'hashie', '>= 2.0.2'
|
39
39
|
s.add_dependency 'minitar'
|
data/lib/berkshelf.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
require 'multi_json'
|
2
|
-
|
3
|
-
# Fix for Facter < 1.7.0 changing LANG to C
|
4
|
-
# https://github.com/puppetlabs/facter/commit/f77584f4
|
5
|
-
begin
|
6
|
-
old_lang = ENV['LANG']
|
7
|
-
require 'ridley'
|
8
|
-
ensure
|
9
|
-
ENV['LANG'] = old_lang
|
10
|
-
end
|
11
|
-
|
2
|
+
require 'ridley'
|
12
3
|
require 'chozo/core_ext'
|
13
4
|
require 'active_support/core_ext'
|
14
5
|
require 'archive/tar/minitar'
|
@@ -46,6 +37,7 @@ module Berkshelf
|
|
46
37
|
autoload :Git, 'berkshelf/git'
|
47
38
|
autoload :InitGenerator, 'berkshelf/init_generator'
|
48
39
|
autoload :Lockfile, 'berkshelf/lockfile'
|
40
|
+
autoload :Logger, 'berkshelf/logger'
|
49
41
|
autoload :Mixin, 'berkshelf/mixin'
|
50
42
|
autoload :Resolver, 'berkshelf/resolver'
|
51
43
|
autoload :UI, 'berkshelf/ui'
|
@@ -53,8 +45,9 @@ module Berkshelf
|
|
53
45
|
require 'berkshelf/location'
|
54
46
|
|
55
47
|
class << self
|
56
|
-
|
48
|
+
include Berkshelf::Mixin::Logging
|
57
49
|
|
50
|
+
attr_accessor :ui
|
58
51
|
attr_writer :cookbook_store
|
59
52
|
|
60
53
|
# @return [Pathname]
|
@@ -79,7 +72,7 @@ module Berkshelf
|
|
79
72
|
end
|
80
73
|
|
81
74
|
# @return [Logger]
|
82
|
-
def
|
75
|
+
def logger
|
83
76
|
Celluloid.logger
|
84
77
|
end
|
85
78
|
|
data/lib/berkshelf/berksfile.rb
CHANGED
@@ -2,6 +2,7 @@ module Berkshelf
|
|
2
2
|
# @author Jamie Winsor <reset@riotgames.com>
|
3
3
|
class Berksfile
|
4
4
|
extend Forwardable
|
5
|
+
include Berkshelf::Mixin::Logging
|
5
6
|
|
6
7
|
class << self
|
7
8
|
# @param [String] file
|
@@ -27,16 +28,16 @@ module Berkshelf
|
|
27
28
|
# @return [String]
|
28
29
|
# expanded filepath to the vendor directory
|
29
30
|
def vendor(cookbooks, path)
|
30
|
-
|
31
|
-
File.join(Dir.pwd, Berkshelf::Chef::Cookbook::Chefignore::FILENAME),
|
32
|
-
File.join(Dir.pwd, 'cookbooks', Berkshelf::Chef::Cookbook::Chefignore::FILENAME)
|
33
|
-
].find { |f| File.exists?(f) }
|
34
|
-
|
35
|
-
chefignore = chefignore_file && Berkshelf::Chef::Cookbook::Chefignore.new(chefignore_file)
|
31
|
+
chefignore = nil
|
36
32
|
path = File.expand_path(path)
|
33
|
+
scratch = Berkshelf.mktmpdir
|
34
|
+
|
37
35
|
FileUtils.mkdir_p(path)
|
38
36
|
|
39
|
-
|
37
|
+
unless (ignore_file = Berkshelf::Chef::Cookbook::Chefignore.find_relative_to(Dir.pwd)).nil?
|
38
|
+
chefignore = Berkshelf::Chef::Cookbook::Chefignore.new(ignore_file)
|
39
|
+
end
|
40
|
+
|
40
41
|
cookbooks.each do |cb|
|
41
42
|
dest = File.join(scratch, cb.cookbook_name, "/")
|
42
43
|
FileUtils.mkdir_p(dest)
|
@@ -73,10 +74,12 @@ module Berkshelf
|
|
73
74
|
def_delegator :downloader, :add_location
|
74
75
|
def_delegator :downloader, :locations
|
75
76
|
|
77
|
+
# @param [String] path
|
78
|
+
# path on disk to the file containing the contents of this Berksfile
|
76
79
|
def initialize(path)
|
77
|
-
@filepath
|
78
|
-
@sources
|
79
|
-
@downloader
|
80
|
+
@filepath = path
|
81
|
+
@sources = Hash.new
|
82
|
+
@downloader = Downloader.new(Berkshelf.cookbook_store)
|
80
83
|
@cached_cookbooks = nil
|
81
84
|
end
|
82
85
|
|
@@ -99,7 +102,8 @@ module Berkshelf
|
|
99
102
|
# cookbook 'artifact', git: 'git://github.com/RiotGames/artifact-cookbook.git'
|
100
103
|
#
|
101
104
|
# @example a cookbook source that will be retrieved from a Chef API (Chef Server)
|
102
|
-
# cookbook 'artifact', chef_api: 'https://api.opscode.com/organizations/vialstudios',
|
105
|
+
# cookbook 'artifact', chef_api: 'https://api.opscode.com/organizations/vialstudios',
|
106
|
+
# node_name: 'reset', client_key: '/Users/reset/.chef/knife.rb'
|
103
107
|
#
|
104
108
|
# @example a cookbook source that will be retrieved from a Chef API using your Berkshelf config
|
105
109
|
# cookbook 'artifact', chef_api: :config
|
@@ -225,7 +229,8 @@ module Berkshelf
|
|
225
229
|
# chef_api :config
|
226
230
|
#
|
227
231
|
# @example using a URL, node_name, and client_key to add a Chef API default location
|
228
|
-
# chef_api "https://api.opscode.com/organizations/vialstudios", node_name: "reset",
|
232
|
+
# chef_api "https://api.opscode.com/organizations/vialstudios", node_name: "reset",
|
233
|
+
# client_key: "/Users/reset/.chef/knife.rb"
|
229
234
|
#
|
230
235
|
# @param [String, Symbol] value
|
231
236
|
# @param [Hash] options
|
@@ -252,7 +257,8 @@ module Berkshelf
|
|
252
257
|
# Only raise an exception if the source is a true duplicate
|
253
258
|
groups = (options[:group].nil? || options[:group].empty?) ? [:default] : options[:group]
|
254
259
|
if !(@sources[name].groups & groups).empty?
|
255
|
-
raise DuplicateSourceDefined,
|
260
|
+
raise DuplicateSourceDefined,
|
261
|
+
"Berksfile contains multiple sources named '#{name}'. Use only one, or put them in different groups."
|
256
262
|
end
|
257
263
|
end
|
258
264
|
|
@@ -393,7 +399,9 @@ module Berkshelf
|
|
393
399
|
missing_cookbooks = (options[:cookbooks] - cookbooks.map(&:cookbook_name))
|
394
400
|
|
395
401
|
unless missing_cookbooks.empty?
|
396
|
-
|
402
|
+
msg = "Could not find cookbooks #{missing_cookbooks.collect{|cookbook| "'#{cookbook}'"}.join(', ')}"
|
403
|
+
msg << " in any of the sources. #{missing_cookbooks.size == 1 ? 'Is it' : 'Are they' } in your Berksfile?"
|
404
|
+
raise Berkshelf::CookbookNotFound, msg
|
397
405
|
end
|
398
406
|
|
399
407
|
update_lockfile(sources)
|
@@ -443,64 +451,86 @@ module Berkshelf
|
|
443
451
|
outdated
|
444
452
|
end
|
445
453
|
|
446
|
-
# @option options [
|
447
|
-
#
|
448
|
-
#
|
449
|
-
#
|
450
|
-
#
|
451
|
-
# filepath to the client's private key used to authenticate with
|
452
|
-
# the Chef API
|
453
|
-
# @option options [String] :organization
|
454
|
-
# the Organization to connect to. This is only used if you are connecting to
|
455
|
-
# private Chef or hosted Chef
|
456
|
-
# @option options [Boolean] :force Upload the Cookbook even if the version
|
457
|
-
# already exists and is frozen on the target Chef Server
|
458
|
-
# @option options [Boolean] :freeze Freeze the uploaded Cookbook on the Chef
|
459
|
-
# Server so that it cannot be overwritten
|
454
|
+
# @option options [Boolean] :force (false)
|
455
|
+
# Upload the Cookbook even if the version already exists and is frozen on the
|
456
|
+
# target Chef Server
|
457
|
+
# @option options [Boolean] :freeze (true)
|
458
|
+
# Freeze the uploaded Cookbook on the Chef Server so that it cannot be overwritten
|
460
459
|
# @option options [Symbol, Array] :except
|
461
460
|
# Group(s) to exclude which will cause any sources marked as a member of the
|
462
461
|
# group to not be installed
|
463
462
|
# @option options [Symbol, Array] :only
|
464
463
|
# Group(s) to include which will cause any sources marked as a member of the
|
465
464
|
# group to be installed and all others to be ignored
|
466
|
-
# @option
|
465
|
+
# @option options [String, Array] :cookbooks
|
467
466
|
# Names of the cookbooks to retrieve sources for
|
468
|
-
# @option options [Hash] :
|
469
|
-
#
|
470
|
-
# @option options [
|
471
|
-
#
|
472
|
-
# @option options [
|
473
|
-
#
|
474
|
-
#
|
475
|
-
# SSL options
|
476
|
-
# @option options [URI, String, Hash] :proxy
|
477
|
-
# URI, String, or Hash of HTTP proxy options
|
467
|
+
# @option options [Hash] :ssl_verify (true)
|
468
|
+
# Disable/Enable SSL verification during uploads
|
469
|
+
# @option options [Boolean] :skip_dependencies (false)
|
470
|
+
# Skip uploading dependent cookbook(s).
|
471
|
+
# @option options [Boolean] :halt_on_frozen (false)
|
472
|
+
# Raise a FrozenCookbook error if one of the cookbooks being uploaded is already located
|
473
|
+
# on the remote Chef Server and frozen.
|
478
474
|
#
|
479
475
|
# @raise [UploadFailure] if you are uploading cookbooks with an invalid or not-specified client key
|
476
|
+
# @raise [Berkshelf::FrozenCookbook]
|
477
|
+
# if an attempt to upload a cookbook which has been frozen on the target server is made
|
478
|
+
# and the :halt_on_frozen option was true
|
480
479
|
def upload(options = {})
|
481
|
-
|
482
|
-
|
480
|
+
options = options.reverse_merge(
|
481
|
+
force: false,
|
482
|
+
freeze: true,
|
483
|
+
ssl_verify: Berkshelf::Config.instance.ssl.verify,
|
484
|
+
skip_dependencies: false,
|
485
|
+
halt_on_frozen: false
|
486
|
+
)
|
487
|
+
|
488
|
+
ridley_options = options.slice(:ssl)
|
489
|
+
ridley_options[:server_url] = Berkshelf::Config.instance.chef.chef_server_url
|
490
|
+
ridley_options[:client_name] = Berkshelf::Config.instance.chef.node_name
|
491
|
+
ridley_options[:client_key] = Berkshelf::Config.instance.chef.client_key
|
492
|
+
ridley_options[:ssl] = { verify: options[:ssl_verify] }
|
493
|
+
|
494
|
+
unless ridley_options[:server_url].present?
|
495
|
+
raise UploadFailure, "Missing required attribute in your Berkshelf configuration: chef.server_url"
|
496
|
+
end
|
497
|
+
|
498
|
+
unless ridley_options[:client_name].present?
|
499
|
+
raise UploadFailure, "Missing required attribute in your Berkshelf configuration: chef.node_name"
|
500
|
+
end
|
501
|
+
|
502
|
+
unless ridley_options[:client_key].present?
|
503
|
+
raise UploadFailure, "Missing required attribute in your Berkshelf configuration: chef.client_key"
|
504
|
+
end
|
505
|
+
|
506
|
+
conn = Ridley.new(ridley_options)
|
507
|
+
solution = resolve(options)
|
508
|
+
upload_opts = options.slice(:force, :freeze)
|
483
509
|
|
484
510
|
solution.each do |cb|
|
485
|
-
|
486
|
-
upload_opts[:name] = cb.cookbook_name
|
511
|
+
Berkshelf.formatter.upload(cb.cookbook_name, cb.version, conn.server_url)
|
487
512
|
|
488
|
-
|
489
|
-
|
513
|
+
begin
|
514
|
+
conn.cookbook.upload(cb.path, upload_opts.merge(name: cb.cookbook_name))
|
515
|
+
rescue Ridley::Errors::FrozenCookbook => ex
|
516
|
+
if options[:halt_on_frozen]
|
517
|
+
raise Berkshelf::FrozenCookbook, ex
|
518
|
+
end
|
519
|
+
end
|
490
520
|
end
|
491
521
|
|
492
522
|
if options[:skip_dependencies]
|
493
523
|
missing_cookbooks = options.fetch(:cookbooks, nil) - solution.map(&:cookbook_name)
|
494
524
|
unless missing_cookbooks.empty?
|
495
525
|
msg = "Unable to upload cookbooks: #{missing_cookbooks.sort.join(', ')}\n"
|
496
|
-
msg << "Specified cookbooks must be defined within the Berkshelf file when using the
|
526
|
+
msg << "Specified cookbooks must be defined within the Berkshelf file when using the"
|
527
|
+
msg << " `--skip-dependencies` option"
|
497
528
|
raise ExplicitCookbookNotFound.new(msg)
|
498
529
|
end
|
499
530
|
end
|
500
|
-
rescue Ridley::Errors::
|
501
|
-
|
502
|
-
|
503
|
-
raise UploadFailure, msg
|
531
|
+
rescue Ridley::Errors::RidleyError => ex
|
532
|
+
log_exception(ex)
|
533
|
+
raise UploadFailure, ex
|
504
534
|
ensure
|
505
535
|
conn.terminate if conn && conn.alive?
|
506
536
|
end
|
@@ -515,32 +545,14 @@ module Berkshelf
|
|
515
545
|
# group to be installed and all others to be ignored
|
516
546
|
# @option cookbooks [String, Array] :cookbooks
|
517
547
|
# Names of the cookbooks to retrieve sources for
|
548
|
+
# @option options [Boolean] :skip_dependencies
|
549
|
+
# Skip resolving of dependencies
|
518
550
|
#
|
519
551
|
# @return [Array<Berkshelf::CachedCookbooks]
|
520
552
|
def resolve(options = {})
|
521
553
|
resolver(options).resolve
|
522
554
|
end
|
523
555
|
|
524
|
-
# Builds a Resolver instance
|
525
|
-
#
|
526
|
-
# @option options [Symbol, Array] :except
|
527
|
-
# Group(s) to exclude which will cause any sources marked as a member of the
|
528
|
-
# group to not be installed
|
529
|
-
# @option options [Symbol, Array] :only
|
530
|
-
# Group(s) to include which will cause any sources marked as a member of the
|
531
|
-
# group to be installed and all others to be ignored
|
532
|
-
# @option cookbooks [String, Array] :cookbooks
|
533
|
-
# Names of the cookbooks to retrieve sources for
|
534
|
-
#
|
535
|
-
# @return <Berkshelf::Resolver>
|
536
|
-
def resolver(options={})
|
537
|
-
Resolver.new(
|
538
|
-
self.downloader,
|
539
|
-
sources: sources(options),
|
540
|
-
skip_dependencies: options[:skip_dependencies]
|
541
|
-
)
|
542
|
-
end
|
543
|
-
|
544
556
|
# Reload this instance of Berksfile with the given content. The content
|
545
557
|
# is a string that may contain terms from the included DSL.
|
546
558
|
#
|
@@ -569,6 +581,28 @@ module Berkshelf
|
|
569
581
|
File.exist?(Berkshelf::Lockfile::DEFAULT_FILENAME)
|
570
582
|
end
|
571
583
|
|
584
|
+
# Builds a Resolver instance
|
585
|
+
#
|
586
|
+
# @option options [Symbol, Array] :except
|
587
|
+
# Group(s) to exclude which will cause any sources marked as a member of the
|
588
|
+
# group to not be installed
|
589
|
+
# @option options [Symbol, Array] :only
|
590
|
+
# Group(s) to include which will cause any sources marked as a member of the
|
591
|
+
# group to be installed and all others to be ignored
|
592
|
+
# @option options [String, Array] :cookbooks
|
593
|
+
# Names of the cookbooks to retrieve sources for
|
594
|
+
# @option options [Boolean] :skip_dependencies
|
595
|
+
# Skip resolving of dependencies
|
596
|
+
#
|
597
|
+
# @return <Berkshelf::Resolver>
|
598
|
+
def resolver(options = {})
|
599
|
+
Resolver.new(
|
600
|
+
self.downloader,
|
601
|
+
sources: sources(options),
|
602
|
+
skip_dependencies: options[:skip_dependencies]
|
603
|
+
)
|
604
|
+
end
|
605
|
+
|
572
606
|
def write_lockfile(sources)
|
573
607
|
Berkshelf::Lockfile.new(sources).write
|
574
608
|
end
|
@@ -15,6 +15,21 @@ module Berkshelf::Chef::Cookbook
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
class Chefignore
|
18
|
+
class << self
|
19
|
+
# Traverse a path in relative context to find a Chefignore file
|
20
|
+
#
|
21
|
+
# @param [String] path
|
22
|
+
# path to traverse
|
23
|
+
#
|
24
|
+
# @return [String, nil]
|
25
|
+
def find_relative_to(path)
|
26
|
+
[
|
27
|
+
File.join(path, Berkshelf::Chef::Cookbook::Chefignore::FILENAME),
|
28
|
+
File.join(path, 'cookbooks', Berkshelf::Chef::Cookbook::Chefignore::FILENAME)
|
29
|
+
].find { |f| File.exists?(f) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
18
33
|
FILENAME = "chefignore".freeze
|
19
34
|
COMMENTS_AND_WHITESPACE = /^\s*(?:#.*)?$/
|
20
35
|
|
data/lib/berkshelf/cli.rb
CHANGED
@@ -31,7 +31,7 @@ module Berkshelf
|
|
31
31
|
end
|
32
32
|
|
33
33
|
if @options[:debug]
|
34
|
-
Berkshelf.
|
34
|
+
Berkshelf.logger.level = ::Logger::DEBUG
|
35
35
|
end
|
36
36
|
|
37
37
|
if @options[:quiet]
|
@@ -199,53 +199,39 @@ module Berkshelf
|
|
199
199
|
type: :array,
|
200
200
|
desc: "Only cookbooks that are in these groups.",
|
201
201
|
aliases: "-o"
|
202
|
-
method_option :
|
202
|
+
method_option :no_freeze,
|
203
203
|
type: :boolean,
|
204
204
|
default: false,
|
205
|
-
desc: "
|
206
|
-
|
205
|
+
desc: "Do not freeze uploaded cookbook(s)."
|
206
|
+
method_option :force,
|
207
207
|
type: :boolean,
|
208
208
|
default: false,
|
209
|
-
desc: "Upload cookbook(s) even if a frozen one exists on the
|
210
|
-
|
209
|
+
desc: "Upload all cookbook(s) even if a frozen one exists on the Chef Server."
|
210
|
+
method_option :ssl_verify,
|
211
211
|
type: :boolean,
|
212
212
|
default: nil,
|
213
|
-
desc: "Disable/Enable SSL verification when uploading cookbooks"
|
214
|
-
|
213
|
+
desc: "Disable/Enable SSL verification when uploading cookbooks."
|
214
|
+
method_option :skip_syntax_check,
|
215
215
|
type: :boolean,
|
216
216
|
default: false,
|
217
|
-
desc: "Skip Ruby syntax check when uploading cookbooks",
|
217
|
+
desc: "Skip Ruby syntax check when uploading cookbooks.",
|
218
218
|
aliases: "-s"
|
219
|
-
|
219
|
+
method_option :skip_dependencies,
|
220
|
+
type: :boolean,
|
221
|
+
desc: "Skip uploading dependent cookbook(s).",
|
222
|
+
default: false,
|
223
|
+
aliases: "-D"
|
224
|
+
method_option :halt_on_frozen,
|
220
225
|
type: :boolean,
|
221
|
-
desc: 'Do not upload dependencies',
|
222
226
|
default: false,
|
223
|
-
|
227
|
+
desc: "Halt uploading and exit if the Chef Server has a frozen version of the cookbook(s)."
|
224
228
|
desc "upload [COOKBOOKS]", "Upload cookbook(s) specified by a Berksfile to the configured Chef Server."
|
225
229
|
def upload(*cookbook_names)
|
226
230
|
berksfile = ::Berkshelf::Berksfile.from_file(options[:berksfile])
|
227
231
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
raise UploadFailure, msg
|
232
|
-
end
|
233
|
-
|
234
|
-
unless Berkshelf::Config.instance.chef.node_name.present?
|
235
|
-
msg = "Could not upload cookbooks: Missing Chef node_name."
|
236
|
-
msg << " Generate or update your Berkshelf configuration that contains a valid Chef node_name."
|
237
|
-
raise UploadFailure, msg
|
238
|
-
end
|
239
|
-
|
240
|
-
upload_options = {
|
241
|
-
server_url: Berkshelf::Config.instance.chef.chef_server_url,
|
242
|
-
client_name: Berkshelf::Config.instance.chef.node_name,
|
243
|
-
client_key: Berkshelf::Config.instance.chef.client_key,
|
244
|
-
ssl: {
|
245
|
-
verify: (options[:ssl_verify].nil? ? Berkshelf::Config.instance.ssl.verify : options[:ssl_verify])
|
246
|
-
},
|
247
|
-
cookbooks: cookbook_names
|
248
|
-
}.merge(options).symbolize_keys
|
232
|
+
upload_options = Hash[options.except(:no_freeze, :berksfile)].symbolize_keys
|
233
|
+
upload_options[:cookbooks] = cookbook_names
|
234
|
+
upload_options[:freeze] = false if options[:no_freeze]
|
249
235
|
|
250
236
|
berksfile.upload(upload_options)
|
251
237
|
end
|
@@ -57,6 +57,11 @@ module Berkshelf
|
|
57
57
|
raise InternalError, "Invalid options for Cookbook Source: #{invalid_options.join(', ')}."
|
58
58
|
end
|
59
59
|
|
60
|
+
if (options.keys & [:site, :path, :git]).size > 1
|
61
|
+
invalid = (options.keys & [:site, :path, :git]).map { |opt| "'#{opt}" }
|
62
|
+
raise InternalError, "Cannot specify #{invalid.to_sentence} for a Cookbook Source!"
|
63
|
+
end
|
64
|
+
|
60
65
|
true
|
61
66
|
end
|
62
67
|
end
|
@@ -64,13 +69,10 @@ module Berkshelf
|
|
64
69
|
extend Forwardable
|
65
70
|
|
66
71
|
attr_reader :name
|
72
|
+
attr_reader :options
|
67
73
|
attr_reader :version_constraint
|
68
|
-
attr_reader :groups
|
69
|
-
attr_reader :location
|
70
74
|
attr_accessor :cached_cookbook
|
71
75
|
|
72
|
-
def_delegator :cached_cookbook, :version, :locked_version
|
73
|
-
|
74
76
|
# @param [String] name
|
75
77
|
# @param [Hash] options
|
76
78
|
#
|
@@ -92,52 +94,70 @@ module Berkshelf
|
|
92
94
|
# same as tag
|
93
95
|
# @option options [String] :locked_version
|
94
96
|
def initialize(name, options = {})
|
95
|
-
@name = name
|
96
|
-
@version_constraint = Solve::Constraint.new(options[:constraint] || ">= 0.0.0")
|
97
|
-
@groups = []
|
98
|
-
@cached_cookbook = nil
|
99
|
-
@location = nil
|
100
|
-
|
101
97
|
self.class.validate_options(options)
|
102
98
|
|
103
|
-
|
104
|
-
@location = Location.init(name, version_constraint, options)
|
105
|
-
end
|
106
|
-
|
107
|
-
if @location.is_a?(PathLocation)
|
108
|
-
begin
|
109
|
-
@cached_cookbook = CachedCookbook.from_path(location.path)
|
110
|
-
rescue IOError
|
111
|
-
raise Berkshelf::CookbookNotFound
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
99
|
+
@name = name
|
115
100
|
@locked_version = Solve::Version.new(options[:locked_version]) if options[:locked_version]
|
101
|
+
@version_constraint = Solve::Constraint.new(options[:locked_version] || options[:constraint] || ">= 0.0.0")
|
102
|
+
|
103
|
+
@cached_cookbook, @location = cached_and_location(options)
|
116
104
|
|
117
105
|
add_group(options[:group]) if options[:group]
|
118
106
|
add_group(:default) if groups.empty?
|
119
107
|
end
|
120
108
|
|
121
|
-
def add_group(*
|
122
|
-
|
123
|
-
|
109
|
+
def add_group(*local_groups)
|
110
|
+
local_groups = local_groups.first if local_groups.first.is_a?(Array)
|
111
|
+
|
112
|
+
local_groups.each do |group|
|
124
113
|
group = group.to_sym
|
125
|
-
|
114
|
+
groups << group unless groups.include?(group)
|
126
115
|
end
|
127
116
|
end
|
128
117
|
|
129
118
|
# Returns true if the cookbook source has already been downloaded. A cookbook
|
130
|
-
# source is downloaded when a cached
|
119
|
+
# source is downloaded when a cached cookbook is present.
|
131
120
|
#
|
132
121
|
# @return [Boolean]
|
133
122
|
def downloaded?
|
134
123
|
!self.cached_cookbook.nil?
|
135
124
|
end
|
136
125
|
|
126
|
+
# Returns true if this CookbookSource has the given group.
|
127
|
+
#
|
128
|
+
# @return [Boolean]
|
137
129
|
def has_group?(group)
|
138
130
|
groups.include?(group.to_sym)
|
139
131
|
end
|
140
132
|
|
133
|
+
# Get the locked version of this cookbook. First check the instance variable
|
134
|
+
# and then resort to the cached_cookbook for the version.
|
135
|
+
#
|
136
|
+
# This was formerly a delegator, but it would fail if the `@cached_cookbook`
|
137
|
+
# was nil or undefined.
|
138
|
+
#
|
139
|
+
# @return [Solve::Version, nil]
|
140
|
+
# the locked version of this cookbook
|
141
|
+
def locked_version
|
142
|
+
@locked_version ||= cached_cookbook.try(:version)
|
143
|
+
end
|
144
|
+
|
145
|
+
# The location for this CookbookSource, such as a remote Chef Server, the
|
146
|
+
# community API, :git, or a :path location. By default, this will be the
|
147
|
+
# community API.
|
148
|
+
#
|
149
|
+
# @return [Berkshelf::Location]
|
150
|
+
def location
|
151
|
+
@location
|
152
|
+
end
|
153
|
+
|
154
|
+
# The list of groups this CookbookSource belongs to.
|
155
|
+
#
|
156
|
+
# @return [Array<Symbol>]
|
157
|
+
def groups
|
158
|
+
@groups ||= []
|
159
|
+
end
|
160
|
+
|
141
161
|
def to_s
|
142
162
|
msg = "#{self.name} (#{self.version_constraint}) groups: #{self.groups}"
|
143
163
|
msg << " location: #{self.location}" if self.location
|
@@ -155,5 +175,69 @@ module Berkshelf
|
|
155
175
|
def to_json
|
156
176
|
MultiJson.dump(self.to_hash, pretty: true)
|
157
177
|
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
# Determine the CachedCookbook and Location information from the given options.
|
182
|
+
#
|
183
|
+
# @return [Array<CachedCookbook, Location>]
|
184
|
+
def cached_and_location(options = {})
|
185
|
+
from_path(options) || from_cache(options) || from_default(options)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Attempt to load a CachedCookbook from a local file system path (if the :path
|
189
|
+
# option was given). If one is found, the location and cached_cookbook is
|
190
|
+
# updated. Otherwise, this method will raise a CookbookNotFound exception.
|
191
|
+
#
|
192
|
+
# @raises [Berkshelf::CookbookNotFound]
|
193
|
+
# if no CachedCookbook exists at the given path
|
194
|
+
#
|
195
|
+
# @return [Berkshelf::CachedCookbook]
|
196
|
+
def from_path(options = {})
|
197
|
+
return nil unless options[:path]
|
198
|
+
|
199
|
+
location = PathLocation.new(name, version_constraint, path: options[:path])
|
200
|
+
cached = CachedCookbook.from_path(location.path)
|
201
|
+
|
202
|
+
[cached, location]
|
203
|
+
rescue IOError
|
204
|
+
raise Berkshelf::CookbookNotFound
|
205
|
+
end
|
206
|
+
|
207
|
+
# Attempt to load a CachedCookbook from the local CookbookStore. This will save
|
208
|
+
# the need to make an http request to download a cookbook we already have cached
|
209
|
+
# locally.
|
210
|
+
#
|
211
|
+
# @return [Berkshelf::CachedCookbook, nil]
|
212
|
+
def from_cache(options = {})
|
213
|
+
path = File.join(Berkshelf.cookbooks_dir, filename(options))
|
214
|
+
return nil unless File.exists?(path)
|
215
|
+
|
216
|
+
location = PathLocation.new(name, version_constraint, path: path)
|
217
|
+
cached = CachedCookbook.from_path(path, name: name)
|
218
|
+
|
219
|
+
[cached, location]
|
220
|
+
end
|
221
|
+
|
222
|
+
# Use the default location, and a nil CachedCookbook. If there is no location
|
223
|
+
# specified,
|
224
|
+
#
|
225
|
+
# @return [Array<nil, Location>]
|
226
|
+
def from_default(options = {})
|
227
|
+
if (options.keys & self.class.location_keys.keys).empty?
|
228
|
+
location = nil
|
229
|
+
else
|
230
|
+
location = Location.init(name, version_constraint, options)
|
231
|
+
end
|
232
|
+
|
233
|
+
[nil, location]
|
234
|
+
end
|
235
|
+
|
236
|
+
# The hypothetical location of this CachedCookbook, if it were to exist.
|
237
|
+
#
|
238
|
+
# @return [String]
|
239
|
+
def filename(options = {})
|
240
|
+
"#{name}-#{options[:locked_version]}"
|
241
|
+
end
|
158
242
|
end
|
159
243
|
end
|