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
data/lib/berkshelf/logger.rb
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
module Berkshelf
|
|
2
|
-
Logger =
|
|
2
|
+
Logger = Celluloid::Logger.dup
|
|
3
3
|
|
|
4
|
-
Logger.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def deprecate(message)
|
|
8
|
-
trace = caller.join("\n\t")
|
|
9
|
-
warn "DEPRECATION WARNING: #{message}\n\t#{trace}"
|
|
4
|
+
Logger.module_eval do
|
|
5
|
+
def self.fatal(string)
|
|
6
|
+
error(string)
|
|
10
7
|
end
|
|
11
8
|
end
|
|
12
9
|
end
|
|
@@ -6,6 +6,9 @@ module Berkshelf
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
module ClassMethods
|
|
9
|
+
# @return [String, nil]
|
|
10
|
+
attr_reader :default_location
|
|
11
|
+
|
|
9
12
|
# Load a Chef configuration from the given path.
|
|
10
13
|
#
|
|
11
14
|
# @raise [Berkshelf::ConfigNotFound]
|
|
@@ -16,10 +19,15 @@ module Berkshelf
|
|
|
16
19
|
raise Berkshelf::ConfigNotFound.new(self.class.name, filepath)
|
|
17
20
|
end
|
|
18
21
|
|
|
22
|
+
# @return [Berkshelf::Mixin::Config]
|
|
23
|
+
def instance
|
|
24
|
+
@instance ||= load
|
|
25
|
+
end
|
|
26
|
+
|
|
19
27
|
# Load the contents of the most probable Chef config. See {location}
|
|
20
28
|
# for more information on how this logic is decided.
|
|
21
29
|
def load
|
|
22
|
-
|
|
30
|
+
new(location)
|
|
23
31
|
end
|
|
24
32
|
|
|
25
33
|
# Class method for defining a default option.
|
|
@@ -47,9 +55,6 @@ module Berkshelf
|
|
|
47
55
|
@default_location = File.expand_path(path)
|
|
48
56
|
end
|
|
49
57
|
|
|
50
|
-
# @return [String, nil]
|
|
51
|
-
attr_reader :default_location
|
|
52
|
-
|
|
53
58
|
# Converts a path to a path usable for your current platform
|
|
54
59
|
#
|
|
55
60
|
# @param [String] path
|
|
@@ -64,7 +69,19 @@ module Berkshelf
|
|
|
64
69
|
path
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
# @return [Berkshelf::Mixin::Config]
|
|
73
|
+
def reload
|
|
74
|
+
@instance = nil
|
|
75
|
+
instance
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @param [Berkshelf::Mixin::Config]
|
|
79
|
+
def set_config(config)
|
|
80
|
+
@instance = config
|
|
81
|
+
end
|
|
82
|
+
|
|
67
83
|
private
|
|
84
|
+
|
|
68
85
|
# @abstract
|
|
69
86
|
# include and override {location} in your class to define the
|
|
70
87
|
# default location logic
|
data/lib/berkshelf/resolver.rb
CHANGED
|
@@ -1,189 +1,99 @@
|
|
|
1
1
|
module Berkshelf
|
|
2
2
|
class Resolver
|
|
3
|
-
require_relative '
|
|
4
|
-
require_relative 'locations/git_location'
|
|
5
|
-
require_relative 'locations/path_location'
|
|
3
|
+
require_relative 'resolver/graph'
|
|
6
4
|
|
|
7
5
|
extend Forwardable
|
|
8
6
|
|
|
9
7
|
# @return [Berkshelf::Berksfile]
|
|
10
8
|
attr_reader :berksfile
|
|
11
9
|
|
|
12
|
-
# @return [
|
|
10
|
+
# @return [Resolver::Graph]
|
|
13
11
|
attr_reader :graph
|
|
14
12
|
|
|
15
|
-
# @
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
# @option options [Array<CookbookSource>, CookbookSource] sources
|
|
19
|
-
def initialize(berksfile, options = {})
|
|
20
|
-
@berksfile = berksfile
|
|
21
|
-
@downloader = berksfile.downloader
|
|
22
|
-
@graph = Solve::Graph.new
|
|
23
|
-
@sources = Hash.new
|
|
24
|
-
|
|
25
|
-
# Dependencies need to be added AFTER the sources. If they are
|
|
26
|
-
# not, then one of the dependencies of a source that is added
|
|
27
|
-
# may take precedence over an explicitly set source that appears
|
|
28
|
-
# later in the iterator.
|
|
29
|
-
Array(options[:sources]).each do |source|
|
|
30
|
-
add_source(source, false)
|
|
31
|
-
end
|
|
13
|
+
# @return [Array<Berkshelf::Dependency>]
|
|
14
|
+
# an array of dependencies that must be satisfied
|
|
15
|
+
attr_reader :demands
|
|
32
16
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
# @param [Berkshelf::Berksfile] berksfile
|
|
18
|
+
# @param [Array<Berkshelf::Dependency>, Berkshelf::Dependency] demands
|
|
19
|
+
# a dependency, or array of dependencies, which must be satisfied
|
|
20
|
+
def initialize(berksfile, demands = [])
|
|
21
|
+
@berksfile = berksfile
|
|
22
|
+
@graph = Graph.new
|
|
23
|
+
@demands = Array.new
|
|
24
|
+
|
|
25
|
+
Array(demands).each { |demand| add_demand(demand) }
|
|
38
26
|
end
|
|
39
27
|
|
|
40
|
-
# Add the given
|
|
41
|
-
#
|
|
42
|
-
#
|
|
28
|
+
# Add the given dependency to the collection of demands
|
|
29
|
+
#
|
|
30
|
+
# @param [Berkshelf::Dependency] demand
|
|
31
|
+
# add a dependency that must be satisfied to the graph
|
|
43
32
|
#
|
|
44
|
-
# @
|
|
45
|
-
# source to add
|
|
46
|
-
# @param [Boolean] include_dependencies
|
|
47
|
-
# adds the dependencies of the given source as sources to the collection of
|
|
48
|
-
# if true. Dependencies will be ignored if false.
|
|
33
|
+
# @raise [DuplicateDemand]
|
|
49
34
|
#
|
|
50
|
-
# @return [Array<
|
|
51
|
-
def
|
|
52
|
-
if
|
|
53
|
-
raise
|
|
35
|
+
# @return [Array<Berkshelf::Dependency>]
|
|
36
|
+
def add_demand(demand)
|
|
37
|
+
if has_demand?(demand)
|
|
38
|
+
raise DuplicateDemand, "A demand named '#{demand.name}' is already present."
|
|
54
39
|
end
|
|
55
40
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
graph.artifacts(source.name, source.cached_cookbook.version)
|
|
41
|
+
demands.push(demand)
|
|
42
|
+
end
|
|
60
43
|
|
|
61
|
-
|
|
62
|
-
|
|
44
|
+
def add_explicit_dependencies(dependency)
|
|
45
|
+
unless cookbook = dependency.cached_cookbook
|
|
46
|
+
return nil
|
|
63
47
|
end
|
|
64
48
|
|
|
65
|
-
|
|
49
|
+
graph.populate_local(cookbook)
|
|
66
50
|
end
|
|
67
51
|
|
|
68
|
-
#
|
|
69
|
-
# on this instance of Resolver. Any dependencies which already have a source in the
|
|
70
|
-
# collection of sources of the same name will not be added to the collection a second
|
|
71
|
-
# time.
|
|
52
|
+
# An array of arrays containing the name and constraint of each demand
|
|
72
53
|
#
|
|
73
|
-
# @
|
|
74
|
-
# source to convert dependencies into sources
|
|
54
|
+
# @note this is the format that Solve uses to determine a solution for the graph
|
|
75
55
|
#
|
|
76
|
-
# @return [Array<
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
next if has_source?(name)
|
|
80
|
-
|
|
81
|
-
add_source(CookbookSource.new(berksfile, name, constraint: constraint))
|
|
82
|
-
end
|
|
56
|
+
# @return [Array<String, String>]
|
|
57
|
+
def demand_array
|
|
58
|
+
demands.collect { |demand| [ demand.name, demand.version_constraint ] }
|
|
83
59
|
end
|
|
84
60
|
|
|
85
|
-
#
|
|
86
|
-
# an array of CookbookSources that are currently added to this resolver
|
|
87
|
-
def sources
|
|
88
|
-
@sources.values
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Finds a solution for the currently added sources and their dependencies and
|
|
61
|
+
# Finds a solution for the currently added dependencies and their dependencies and
|
|
92
62
|
# returns an array of CachedCookbooks.
|
|
93
63
|
#
|
|
94
|
-
# @
|
|
64
|
+
# @raise [Berkshelf::NoSolutionError] when a solution could not be found for the given demands
|
|
65
|
+
#
|
|
66
|
+
# @return [Array<Array<String, String, Dependency>>]
|
|
95
67
|
def resolve
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
l_demands << [ artifact.name, artifact.version ]
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
solution = Solve.it!(graph, demands)
|
|
68
|
+
graph.populate_store
|
|
69
|
+
graph.populate(berksfile.sources)
|
|
103
70
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
end
|
|
71
|
+
Solve.it!(graph, demand_array).collect do |name, version|
|
|
72
|
+
dependency = get_demand(name) || Dependency.new(berksfile, name, locked_version: version)
|
|
73
|
+
[ name, version, dependency ]
|
|
108
74
|
end
|
|
75
|
+
rescue Solve::Errors::NoSolutionError
|
|
76
|
+
raise Berkshelf::NoSolutionError.new(demands)
|
|
109
77
|
end
|
|
110
78
|
|
|
111
|
-
#
|
|
112
|
-
# name of the source to return
|
|
79
|
+
# Retrieve the given demand from the resolver
|
|
113
80
|
#
|
|
114
|
-
# @
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
81
|
+
# @param [Berkshelf::Dependency, #to_s] demand
|
|
82
|
+
# name of the dependency to return
|
|
83
|
+
#
|
|
84
|
+
# @return [Berkshelf::Dependency]
|
|
85
|
+
def [](demand)
|
|
86
|
+
name = demand.respond_to?(:name) ? demand.name : demand.to_s
|
|
87
|
+
demands.find { |demand| demand.name == name }
|
|
120
88
|
end
|
|
121
|
-
alias_method :
|
|
89
|
+
alias_method :get_demand, :[]
|
|
122
90
|
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
|
|
126
|
-
|
|
91
|
+
# Check if the given demand has been added to the resolver
|
|
92
|
+
#
|
|
93
|
+
# @param [Berkshelf::Dependency, #to_s] demand
|
|
94
|
+
# the demand or the name of the demand to check for
|
|
95
|
+
def has_demand?(demand)
|
|
96
|
+
!get_demand(demand).nil?
|
|
127
97
|
end
|
|
128
|
-
|
|
129
|
-
private
|
|
130
|
-
|
|
131
|
-
attr_reader :downloader
|
|
132
|
-
|
|
133
|
-
# @param [Berkshelf::CookbookSource] source
|
|
134
|
-
#
|
|
135
|
-
# @return [Boolean]
|
|
136
|
-
def install_source(source)
|
|
137
|
-
cached_cookbook, location = downloader.download(source)
|
|
138
|
-
Berkshelf.formatter.install(source.name, cached_cookbook.version, location)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Use the given source to create a constraint solution if the source has been downloaded or can
|
|
142
|
-
# be satisfied by a cached cookbook that is already present in the cookbook store.
|
|
143
|
-
#
|
|
144
|
-
# @note Git location sources which have not yet been downloaded will not be satisfied by a
|
|
145
|
-
# cached cookbook from the cookbook store.
|
|
146
|
-
#
|
|
147
|
-
# @param [Berkshelf::CookbookSource] source
|
|
148
|
-
#
|
|
149
|
-
# @raise [ConstraintNotSatisfied] if the CachedCookbook does not satisfy the version constraint of
|
|
150
|
-
# this instance of Location.
|
|
151
|
-
# contain a cookbook that satisfies the given version constraint of this instance of
|
|
152
|
-
# CookbookSource.
|
|
153
|
-
#
|
|
154
|
-
# @return [Boolean]
|
|
155
|
-
def use_source(source)
|
|
156
|
-
name = source.name
|
|
157
|
-
locked = source.locked_version
|
|
158
|
-
location = source.location
|
|
159
|
-
|
|
160
|
-
# Lock the version constraint if a locked version was supplied
|
|
161
|
-
source.version_constraint = Solve::Constraint.new(locked.to_s) if locked
|
|
162
|
-
constraint = source.version_constraint
|
|
163
|
-
|
|
164
|
-
if source.downloaded?
|
|
165
|
-
cached = source.cached_cookbook
|
|
166
|
-
location.validate_cached(cached) if location
|
|
167
|
-
Berkshelf.formatter.use(name, cached.version, location)
|
|
168
|
-
true
|
|
169
|
-
elsif location.is_a?(GitLocation)
|
|
170
|
-
false
|
|
171
|
-
else
|
|
172
|
-
# If a locked version if specified, it must exist
|
|
173
|
-
if locked
|
|
174
|
-
cached = downloader.cookbook_store.cookbook(name, locked)
|
|
175
|
-
else
|
|
176
|
-
cached = downloader.cookbook_store.satisfy(name, constraint)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
if cached
|
|
180
|
-
get_source(source).cached_cookbook = cached
|
|
181
|
-
Berkshelf.formatter.use(name, cached.version)
|
|
182
|
-
true
|
|
183
|
-
else
|
|
184
|
-
false
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
98
|
end
|
|
189
99
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Berkshelf
|
|
2
|
+
class Resolver
|
|
3
|
+
class Graph < Solve::Graph
|
|
4
|
+
# @param [Berkshelf::CookbookStore] store
|
|
5
|
+
def populate_store(store = nil)
|
|
6
|
+
store ||= Berkshelf::CookbookStore.instance
|
|
7
|
+
|
|
8
|
+
store.cookbooks.each do |cookbook|
|
|
9
|
+
artifacts(cookbook.cookbook_name, cookbook.version)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def populate_local(cookbook)
|
|
14
|
+
name = cookbook.cookbook_name
|
|
15
|
+
version = cookbook.version
|
|
16
|
+
|
|
17
|
+
artifacts(name, version)
|
|
18
|
+
cookbook.dependencies.each do |dependency, constraint|
|
|
19
|
+
artifacts(name, version).depends(dependency, constraint)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param [Array<Berkshelf::Source>, Berkshelf::Source] sources
|
|
24
|
+
def populate(sources)
|
|
25
|
+
universe(sources).each do |cookbook|
|
|
26
|
+
artifacts(cookbook.name, cookbook.version)
|
|
27
|
+
|
|
28
|
+
cookbook.dependencies.each do |dependency, constraint|
|
|
29
|
+
artifacts(cookbook.name, cookbook.version).depends(dependency, constraint)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param [Array<Berkshelf::Source>, Berkshelf::Source] sources
|
|
35
|
+
#
|
|
36
|
+
# @return [Array<Berkshelf::RemoteCookbook>]
|
|
37
|
+
def universe(sources)
|
|
38
|
+
cookbooks = []
|
|
39
|
+
Array(sources).each { |source| cookbooks = cookbooks | source.universe }
|
|
40
|
+
cookbooks
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Berkshelf
|
|
2
|
+
class Source
|
|
3
|
+
include Comparable
|
|
4
|
+
|
|
5
|
+
# @return [Berkshelf::SourceURI]
|
|
6
|
+
attr_reader :uri
|
|
7
|
+
|
|
8
|
+
# @param [String, Berkshelf::SourceURI] uri
|
|
9
|
+
def initialize(uri)
|
|
10
|
+
@uri = SourceURI.parse(uri)
|
|
11
|
+
@api_client = APIClient.new(uri)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [Hash]
|
|
15
|
+
def universe
|
|
16
|
+
@universe ||= api_client.universe
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param [String] name
|
|
20
|
+
# @param [String] version
|
|
21
|
+
#
|
|
22
|
+
# @return [APIClient::RemoteCookbook]
|
|
23
|
+
def cookbook(name, version)
|
|
24
|
+
universe.find { |cookbook| cookbook.name == name && cookbook.version == version }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param [String] name
|
|
28
|
+
#
|
|
29
|
+
# @return [APIClient::RemoteCookbook]
|
|
30
|
+
def latest(name)
|
|
31
|
+
versions(name).sort.last
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param [String] name
|
|
35
|
+
#
|
|
36
|
+
# @return [Array<APIClient::RemoteCookbook>]
|
|
37
|
+
def versions(name)
|
|
38
|
+
universe.select { |cookbook| cookbook.name == name }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_s
|
|
42
|
+
uri.to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ==(other)
|
|
46
|
+
return false unless other.is_a?(self.class)
|
|
47
|
+
uri == other.uri
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# @return [Berkshelf::APIClient]
|
|
53
|
+
attr_reader :api_client
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'addressable/uri'
|
|
2
|
+
|
|
3
|
+
module Berkshelf
|
|
4
|
+
class SourceURI < Addressable::URI
|
|
5
|
+
class << self
|
|
6
|
+
# Returns a URI object based on the parsed string.
|
|
7
|
+
#
|
|
8
|
+
# @param [String, Addressable::URI, #to_str] uri
|
|
9
|
+
# The URI string to parse.
|
|
10
|
+
# No parsing is performed if the object is already an
|
|
11
|
+
# <code>Addressable::URI</code>.
|
|
12
|
+
#
|
|
13
|
+
# @raise [Berkshelf::InvalidSourceURI]
|
|
14
|
+
#
|
|
15
|
+
# @return [Berkshelf::SourceURI]
|
|
16
|
+
def parse(uri)
|
|
17
|
+
parsed_uri = super(uri)
|
|
18
|
+
parsed_uri.send(:validate)
|
|
19
|
+
parsed_uri
|
|
20
|
+
rescue TypeError, ArgumentError => ex
|
|
21
|
+
raise InvalidSourceURI.new(uri, ex)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
VALID_SCHEMES = [ "http", "https" ].freeze
|
|
26
|
+
|
|
27
|
+
# @raise [Berkshelf::InvalidSourceURI]
|
|
28
|
+
def validate
|
|
29
|
+
super
|
|
30
|
+
|
|
31
|
+
unless VALID_SCHEMES.include?(self.scheme)
|
|
32
|
+
raise InvalidSourceURI.new(self, "invalid URI scheme '#{self.scheme}'. Valid schemes: #{VALID_SCHEMES}")
|
|
33
|
+
end
|
|
34
|
+
rescue Addressable::URI::InvalidURIError => ex
|
|
35
|
+
raise InvalidSourceURI.new(self, ex)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|