berkshelf 0.4.0 → 0.5.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/berkshelf.gemspec +8 -3
- data/bin/berks +1 -1
- data/features/groups_install.feature +67 -0
- data/features/install.feature +1 -71
- data/features/json_formatter.feature +0 -17
- data/features/step_definitions/filesystem_steps.rb +1 -3
- data/features/update.feature +3 -6
- data/features/vendor_install.feature +20 -0
- data/generator_files/Vagrantfile.erb +25 -3
- data/lib/berkshelf.rb +27 -17
- data/lib/berkshelf/base_generator.rb +5 -0
- data/lib/berkshelf/berksfile.rb +82 -77
- data/lib/berkshelf/cli.rb +37 -26
- data/lib/berkshelf/cookbook_source.rb +14 -4
- data/lib/berkshelf/errors.rb +4 -1
- data/lib/berkshelf/formatters.rb +69 -5
- data/lib/berkshelf/formatters/human_readable.rb +26 -8
- data/lib/berkshelf/formatters/json.rb +51 -23
- data/lib/berkshelf/init_generator.rb +4 -4
- data/lib/berkshelf/location.rb +29 -6
- data/lib/berkshelf/locations/chef_api_location.rb +23 -5
- data/lib/berkshelf/locations/git_location.rb +13 -6
- data/lib/berkshelf/locations/path_location.rb +8 -4
- data/lib/berkshelf/locations/site_location.rb +9 -3
- data/lib/berkshelf/ui.rb +34 -0
- data/lib/berkshelf/uploader.rb +37 -103
- data/lib/berkshelf/vagrant.rb +65 -0
- data/lib/berkshelf/vagrant/action/clean.rb +24 -0
- data/lib/berkshelf/vagrant/action/install.rb +47 -0
- data/lib/berkshelf/vagrant/action/set_ui.rb +17 -0
- data/lib/berkshelf/vagrant/action/upload.rb +40 -0
- data/lib/berkshelf/vagrant/config.rb +70 -0
- data/lib/berkshelf/vagrant/middleware.rb +52 -0
- data/lib/berkshelf/version.rb +1 -1
- data/lib/thor/monkies.rb +3 -0
- data/lib/thor/monkies/hash_with_indifferent_access.rb +13 -0
- data/lib/vagrant_init.rb +2 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/chef_api.rb +6 -1
- data/spec/unit/berkshelf/berksfile_spec.rb +93 -55
- data/spec/unit/berkshelf/formatters_spec.rb +99 -1
- data/spec/unit/berkshelf/init_generator_spec.rb +1 -1
- data/spec/unit/berkshelf/location_spec.rb +44 -7
- data/spec/unit/berkshelf/lockfile_spec.rb +2 -2
- data/spec/unit/berkshelf/uploader_spec.rb +2 -20
- data/spec/unit/berkshelf_spec.rb +2 -2
- metadata +100 -14
- data/features/without.feature +0 -26
- data/lib/berkshelf/core_ext/fileutils.rb +0 -90
- data/lib/berkshelf/core_ext/kernel.rb +0 -33
- data/spec/unit/berkshelf/core_ext/fileutils_spec.rb +0 -20
data/lib/berkshelf/cli.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'thor'
|
2
|
+
require 'thor/monkies'
|
2
3
|
require 'berkshelf'
|
3
4
|
|
4
5
|
module Berkshelf
|
@@ -11,12 +12,11 @@ module Berkshelf
|
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
|
-
def initialize(*)
|
15
|
-
super
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
::Berkshelf.set_format @options[:format]
|
15
|
+
def initialize(*args)
|
16
|
+
super(*args)
|
17
|
+
self.shell = Berkshelf.ui
|
18
|
+
Berkshelf.config_path = @options[:config]
|
19
|
+
Berkshelf.set_format @options[:format]
|
20
20
|
@options = options.dup # unfreeze frozen options Hash from Thor
|
21
21
|
end
|
22
22
|
|
@@ -36,33 +36,32 @@ module Berkshelf
|
|
36
36
|
banner: "PATH"
|
37
37
|
class_option :format,
|
38
38
|
type: :string,
|
39
|
+
default: "human",
|
39
40
|
desc: "Output format to use.",
|
40
41
|
aliases: "-F",
|
41
42
|
banner: "FORMAT"
|
42
43
|
|
43
|
-
method_option :
|
44
|
-
type: :string,
|
45
|
-
default: nil,
|
46
|
-
lazy_default: File.join(Dir.pwd, "cookbooks"),
|
47
|
-
desc: "Create a directory of shims pointing to Cookbook Versions.",
|
48
|
-
banner: "PATH"
|
49
|
-
method_option :without,
|
44
|
+
method_option :except,
|
50
45
|
type: :array,
|
51
|
-
default: Array.new,
|
52
46
|
desc: "Exclude cookbooks that are in these groups.",
|
53
|
-
aliases: "-
|
47
|
+
aliases: "-e"
|
48
|
+
method_option :only,
|
49
|
+
type: :array,
|
50
|
+
desc: "Only cookbooks that are in these groups.",
|
51
|
+
aliases: "-o"
|
54
52
|
method_option :berksfile,
|
55
53
|
type: :string,
|
56
54
|
default: File.join(Dir.pwd, Berkshelf::DEFAULT_FILENAME),
|
57
55
|
desc: "Path to a Berksfile to operate off of.",
|
58
56
|
aliases: "-b",
|
59
57
|
banner: "PATH"
|
58
|
+
method_option :path,
|
59
|
+
type: :string,
|
60
|
+
desc: "Path to install cookbooks to (i.e. vendor/cookbooks).",
|
61
|
+
aliases: "-p",
|
62
|
+
banner: "PATH"
|
60
63
|
desc "install", "Install the Cookbooks specified by a Berksfile or a Berksfile.lock."
|
61
64
|
def install
|
62
|
-
unless options[:shims].nil?
|
63
|
-
options[:shims] = File.expand_path(options[:shims])
|
64
|
-
end
|
65
|
-
|
66
65
|
berksfile = ::Berkshelf::Berksfile.from_file(options[:berksfile])
|
67
66
|
berksfile.install(options)
|
68
67
|
end
|
@@ -73,11 +72,14 @@ module Berkshelf
|
|
73
72
|
desc: "Path to a Berksfile to operate off of.",
|
74
73
|
aliases: "-b",
|
75
74
|
banner: "PATH"
|
76
|
-
method_option :
|
75
|
+
method_option :except,
|
77
76
|
type: :array,
|
78
|
-
default: Array.new,
|
79
77
|
desc: "Exclude cookbooks that are in these groups.",
|
80
|
-
aliases: "-
|
78
|
+
aliases: "-e"
|
79
|
+
method_option :only,
|
80
|
+
type: :array,
|
81
|
+
desc: "Only cookbooks that are in these groups.",
|
82
|
+
aliases: "-o"
|
81
83
|
desc "update", "Update all Cookbooks and their dependencies specified by a Berksfile to their latest versions."
|
82
84
|
def update
|
83
85
|
Lockfile.remove!
|
@@ -90,11 +92,14 @@ module Berkshelf
|
|
90
92
|
desc: "Path to a Berksfile to operate off of.",
|
91
93
|
aliases: "-b",
|
92
94
|
banner: "PATH"
|
93
|
-
method_option :
|
95
|
+
method_option :except,
|
94
96
|
type: :array,
|
95
|
-
default: Array.new,
|
96
97
|
desc: "Exclude cookbooks that are in these groups.",
|
97
|
-
aliases: "-
|
98
|
+
aliases: "-e"
|
99
|
+
method_option :only,
|
100
|
+
type: :array,
|
101
|
+
desc: "Only cookbooks that are in these groups.",
|
102
|
+
aliases: "-o"
|
98
103
|
method_option :freeze,
|
99
104
|
type: :boolean,
|
100
105
|
default: false,
|
@@ -107,7 +112,13 @@ module Berkshelf
|
|
107
112
|
def upload
|
108
113
|
Berkshelf.load_config
|
109
114
|
berksfile = ::Berkshelf::Berksfile.from_file(options[:berksfile])
|
110
|
-
|
115
|
+
|
116
|
+
berksfile.upload(
|
117
|
+
server_url: Chef::Config[:chef_server_url],
|
118
|
+
client_name: Chef::Config[:node_name],
|
119
|
+
client_key: Chef::Config[:client_key],
|
120
|
+
organization: ChefAPILocation.extract_organization(Chef::Config[:chef_server_url])
|
121
|
+
)
|
111
122
|
end
|
112
123
|
|
113
124
|
desc "init [PATH]", "Prepare a local path to have its Cookbook dependencies managed by Berkshelf."
|
@@ -69,6 +69,8 @@ module Berkshelf
|
|
69
69
|
attr_reader :location
|
70
70
|
attr_accessor :cached_cookbook
|
71
71
|
|
72
|
+
def_delegator :cached_cookbook, :version, :locked_version
|
73
|
+
|
72
74
|
# @param [String] name
|
73
75
|
# @param [Hash] options
|
74
76
|
#
|
@@ -132,14 +134,22 @@ module Berkshelf
|
|
132
134
|
groups.include?(group.to_sym)
|
133
135
|
end
|
134
136
|
|
135
|
-
def locked_version
|
136
|
-
@locked_version || cached_cookbook.version
|
137
|
-
end
|
138
|
-
|
139
137
|
def to_s
|
140
138
|
msg = "#{self.name} (#{self.version_constraint}) groups: #{self.groups}"
|
141
139
|
msg << " location: #{self.location}" if self.location
|
142
140
|
msg
|
143
141
|
end
|
142
|
+
|
143
|
+
def to_hash
|
144
|
+
{}.tap do |h|
|
145
|
+
h[:name] = self.name
|
146
|
+
h[:locked_version] = self.locked_version
|
147
|
+
h[:location] = self.location.to_hash if self.location
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def to_json
|
152
|
+
MultiJson.dump(self.to_hash, pretty: true)
|
153
|
+
end
|
144
154
|
end
|
145
155
|
end
|
data/lib/berkshelf/errors.rb
CHANGED
@@ -12,6 +12,7 @@ module Berkshelf
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class InternalError < BerkshelfError; status_code(99); end
|
15
|
+
class ArgumentError < InternalError; end
|
15
16
|
class AbstractFunction < InternalError
|
16
17
|
def to_s
|
17
18
|
"Function must be implemented on includer"
|
@@ -74,7 +75,9 @@ module Berkshelf
|
|
74
75
|
status_code(113)
|
75
76
|
|
76
77
|
def status_code
|
77
|
-
@original_error ? @original_error.status_code : 113
|
78
|
+
@original_error.respond_to?(:status_code) ? @original_error.status_code : 113
|
78
79
|
end
|
79
80
|
end
|
81
|
+
|
82
|
+
class AmbiguousCookbookName < BerkshelfError; status_code(114); end
|
80
83
|
end
|
data/lib/berkshelf/formatters.rb
CHANGED
@@ -1,10 +1,74 @@
|
|
1
1
|
module Berkshelf
|
2
|
+
# @author Michael Ivey <ivey@gweezlebur.com>
|
3
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
2
4
|
module Formatters
|
5
|
+
class << self
|
6
|
+
@@formatters = Hash.new
|
7
|
+
|
8
|
+
# Access the formatters map that links string symbols to Formatter
|
9
|
+
# implementations
|
10
|
+
#
|
11
|
+
# @return [Hash]
|
12
|
+
def formatters
|
13
|
+
@@formatters
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [#to_sym] id
|
17
|
+
# @param [Constant] klass
|
18
|
+
#
|
19
|
+
# @raise [Berkshelf::InternalError] if an ID that has already been registered is attempted
|
20
|
+
# to be registered again
|
21
|
+
#
|
22
|
+
# @return [Hash]
|
23
|
+
# a hash of registered formatters
|
24
|
+
def register(id, klass)
|
25
|
+
unless id.respond_to?(:to_sym)
|
26
|
+
raise ArgumentError, "Invalid Formatter ID: must respond to #to_sym. You gave: #{id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
id = id.to_sym
|
30
|
+
if self.formatters.has_key?(id)
|
31
|
+
raise Berkshelf::InternalError, "Formatter ID '#{id}' already registered"
|
32
|
+
end
|
33
|
+
|
34
|
+
self.formatters[id] = klass
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [#to_sym] id
|
38
|
+
#
|
39
|
+
# @return [~AbstractFormatter, nil]
|
40
|
+
def get(id)
|
41
|
+
unless id.respond_to?(:to_sym)
|
42
|
+
raise ArgumentError, "Invalid Formatter ID: must respond to #to_sym. You gave: #{id}"
|
43
|
+
end
|
44
|
+
|
45
|
+
self.formatters.fetch(id.to_sym, nil)
|
46
|
+
end
|
47
|
+
alias_method :[], :get
|
48
|
+
end
|
49
|
+
|
50
|
+
# @author Michael Ivey <ivey@gweezlebur.com>
|
51
|
+
#
|
3
52
|
# @abstract Include and override {#install} {#use} {#upload}
|
4
|
-
# {#
|
53
|
+
# {#msg} {#error} to implement.
|
5
54
|
#
|
6
55
|
# Implement {#cleanup_hook} to run any steps required to run after the task is finished
|
7
56
|
module AbstractFormatter
|
57
|
+
extend ActiveSupport::Concern
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
# @param [Symbol] id
|
61
|
+
#
|
62
|
+
# @raise [Berkshelf::InternalError] if an ID that has already been registered is attempted
|
63
|
+
# to be registered again
|
64
|
+
#
|
65
|
+
# @return [Hash]
|
66
|
+
# a hash of registered formatters
|
67
|
+
def register_formatter(id)
|
68
|
+
Formatters.register(id, self)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
8
72
|
def cleanup_hook
|
9
73
|
# run after the task is finished
|
10
74
|
end
|
@@ -21,10 +85,6 @@ module Berkshelf
|
|
21
85
|
raise AbstractFunction, "#upload must be implemented on #{self.class}"
|
22
86
|
end
|
23
87
|
|
24
|
-
def shims_written(directory)
|
25
|
-
raise AbstractFunction, "#shims_written must be implemented on #{self.class}"
|
26
|
-
end
|
27
|
-
|
28
88
|
def msg(message)
|
29
89
|
raise AbstractFunction, "#msg must be implemented on #{self.class}"
|
30
90
|
end
|
@@ -32,6 +92,10 @@ module Berkshelf
|
|
32
92
|
def error(message)
|
33
93
|
raise AbstractFunction, "#error must be implemented on #{self.class}"
|
34
94
|
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
attr_reader :args
|
35
99
|
end
|
36
100
|
end
|
37
101
|
end
|
@@ -1,30 +1,48 @@
|
|
1
1
|
module Berkshelf
|
2
2
|
module Formatters
|
3
|
+
# @author Michael Ivey <ivey@gweezlebur.com>
|
3
4
|
class HumanReadable
|
4
5
|
include AbstractFormatter
|
5
6
|
|
6
|
-
|
7
|
+
register_formatter :human
|
7
8
|
|
9
|
+
# Output a Cookbook installation message using {Berkshelf.ui}
|
10
|
+
#
|
11
|
+
# @param [String] cookbook
|
12
|
+
# @param [String] version
|
13
|
+
# @param [~Location] location
|
8
14
|
def install(cookbook, version, location)
|
9
15
|
Berkshelf.ui.info "Installing #{cookbook} (#{version}) from #{location}"
|
10
16
|
end
|
11
17
|
|
12
|
-
|
18
|
+
# Output a Cookbook use message using {Berkshelf.ui}
|
19
|
+
#
|
20
|
+
# @param [String] cookbook
|
21
|
+
# @param [String] version
|
22
|
+
# @param [String] path
|
23
|
+
def use(cookbook, version, path = nil)
|
13
24
|
Berkshelf.ui.info "Using #{cookbook} (#{version})#{' at '+path if path}"
|
14
25
|
end
|
15
26
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
27
|
+
# Output a Cookbook upload message using {Berkshelf.ui}
|
28
|
+
#
|
29
|
+
# @param [String] cookbook
|
30
|
+
# @param [String] version
|
31
|
+
# @param [String] chef_api_url
|
32
|
+
def upload(cookbook, version, chef_api_url)
|
33
|
+
Berkshelf.ui.info "Uploading #{cookbook} (#{version}) to: '#{chef_api_url}'"
|
22
34
|
end
|
23
35
|
|
36
|
+
# Output a generic message using {Berkshelf.ui}
|
37
|
+
#
|
38
|
+
# @param [String] message
|
24
39
|
def msg(message)
|
25
40
|
Berkshelf.ui.info message
|
26
41
|
end
|
27
42
|
|
43
|
+
# Output an error message using {Berkshelf.ui}
|
44
|
+
#
|
45
|
+
# @param [String] message
|
28
46
|
def error(message)
|
29
47
|
Berkshelf.ui.error message
|
30
48
|
end
|
@@ -1,53 +1,81 @@
|
|
1
1
|
module Berkshelf
|
2
2
|
module Formatters
|
3
|
+
# @author Michael Ivey <ivey@gweezlebur.com>
|
3
4
|
class JSON
|
4
5
|
include AbstractFormatter
|
5
6
|
|
6
|
-
|
7
|
+
register_formatter :json
|
7
8
|
|
8
9
|
def initialize
|
9
|
-
@output = {
|
10
|
-
|
10
|
+
@output = {
|
11
|
+
cookbooks: Array.new,
|
12
|
+
errors: Array.new,
|
13
|
+
messages: Array.new
|
14
|
+
}
|
15
|
+
@cookbooks = Hash.new
|
11
16
|
super
|
12
17
|
end
|
13
18
|
|
14
19
|
def cleanup_hook
|
15
|
-
|
20
|
+
cookbooks.each do |name, details|
|
16
21
|
details[:name] = name
|
17
|
-
|
22
|
+
output[:cookbooks] << details
|
18
23
|
end
|
19
|
-
|
24
|
+
|
25
|
+
print MultiJson.dump(output)
|
20
26
|
end
|
21
27
|
|
28
|
+
# Add a Cookbook installation entry to delayed output
|
29
|
+
#
|
30
|
+
# @param [String] cookbook
|
31
|
+
# @param [String] version
|
32
|
+
# @param [~Location] location
|
22
33
|
def install(cookbook, version, location)
|
23
|
-
|
24
|
-
|
25
|
-
|
34
|
+
cookbooks[cookbook] ||= {}
|
35
|
+
cookbooks[cookbook][:version] = version
|
36
|
+
cookbooks[cookbook][:location] = location.to_s
|
26
37
|
end
|
27
38
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
39
|
+
# Add a Cookbook use entry to delayed output
|
40
|
+
#
|
41
|
+
# @param [String] cookbook
|
42
|
+
# @param [String] version
|
43
|
+
# @param [String] path
|
44
|
+
def use(cookbook, version, path = nil)
|
45
|
+
cookbooks[cookbook] ||= {}
|
46
|
+
cookbooks[cookbook][:version] = version
|
47
|
+
cookbooks[cookbook][:location] = path if path
|
32
48
|
end
|
33
49
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
50
|
+
# Add a Cookbook upload entry to delayed output
|
51
|
+
#
|
52
|
+
# @param [String] cookbook
|
53
|
+
# @param [String] version
|
54
|
+
# @param [String] chef_api_url
|
55
|
+
def upload(cookbook, version, chef_api_url)
|
56
|
+
cookbooks[cookbook] ||= {}
|
57
|
+
cookbooks[cookbook][:version] = version
|
58
|
+
cookbooks[cookbook][:uploaded_to] = chef_api_url
|
42
59
|
end
|
43
60
|
|
61
|
+
# Add a generic message entry to delayed output
|
62
|
+
#
|
63
|
+
# @param [String] message
|
44
64
|
def msg(message)
|
45
|
-
|
65
|
+
output[:messages] << message
|
46
66
|
end
|
47
67
|
|
68
|
+
# Add an error message entry to delayed output
|
69
|
+
#
|
70
|
+
# @param [String] message
|
48
71
|
def error(message)
|
49
|
-
|
72
|
+
output[:errors] << message
|
50
73
|
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
attr_reader :output
|
78
|
+
attr_reader :cookbooks
|
51
79
|
end
|
52
80
|
end
|
53
81
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Berkshelf
|
2
2
|
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
3
|
class InitGenerator < BaseGenerator
|
4
|
-
def initialize(*)
|
5
|
-
super
|
4
|
+
def initialize(*args)
|
5
|
+
super(*args)
|
6
6
|
if @options[:cookbook_name]
|
7
7
|
@cookbook_name = @options[:cookbook_name]
|
8
8
|
end
|
@@ -54,7 +54,7 @@ module Berkshelf
|
|
54
54
|
template "gitignore.erb", target.join(".gitignore")
|
55
55
|
unless File.exists?(target.join(".git"))
|
56
56
|
inside target do
|
57
|
-
run "git init"
|
57
|
+
run "git init", capture: true
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -73,7 +73,7 @@ module Berkshelf
|
|
73
73
|
|
74
74
|
if options[:vagrant]
|
75
75
|
template "Vagrantfile.erb", target.join("Vagrantfile")
|
76
|
-
::Berkshelf::Cli.new([], berksfile: target.join("Berksfile")
|
76
|
+
::Berkshelf::Cli.new([], berksfile: target.join("Berksfile")).invoke(:install)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|