berkshelf 0.4.0.rc4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +2 -0
  2. data/Guardfile +6 -3
  3. data/features/default_locations.feature +122 -0
  4. data/features/install.feature +20 -4
  5. data/features/lockfile.feature +1 -6
  6. data/features/update.feature +2 -3
  7. data/generator_files/Berksfile.erb +2 -0
  8. data/generator_files/gitignore.erb +6 -0
  9. data/lib/berkshelf.rb +6 -10
  10. data/lib/berkshelf/berksfile.rb +203 -14
  11. data/lib/berkshelf/cached_cookbook.rb +5 -1
  12. data/lib/berkshelf/cli.rb +4 -0
  13. data/lib/berkshelf/cookbook_source.rb +49 -91
  14. data/lib/berkshelf/cookbook_store.rb +2 -0
  15. data/lib/berkshelf/downloader.rb +71 -51
  16. data/lib/berkshelf/errors.rb +7 -3
  17. data/lib/berkshelf/formatters.rb +6 -6
  18. data/lib/berkshelf/location.rb +171 -0
  19. data/lib/berkshelf/locations/chef_api_location.rb +252 -0
  20. data/lib/berkshelf/locations/git_location.rb +76 -0
  21. data/lib/berkshelf/locations/path_location.rb +38 -0
  22. data/lib/berkshelf/locations/site_location.rb +150 -0
  23. data/lib/berkshelf/lockfile.rb +2 -2
  24. data/lib/berkshelf/resolver.rb +12 -15
  25. data/lib/berkshelf/uploader.rb +2 -9
  26. data/lib/berkshelf/version.rb +1 -1
  27. data/spec/fixtures/lockfile_spec/without_lock/.gitkeep +0 -0
  28. data/spec/support/chef_api.rb +7 -1
  29. data/spec/unit/berkshelf/berksfile_spec.rb +157 -12
  30. data/spec/unit/berkshelf/cached_cookbook_spec.rb +19 -0
  31. data/spec/unit/berkshelf/cookbook_generator_spec.rb +1 -0
  32. data/spec/unit/berkshelf/cookbook_source_spec.rb +25 -35
  33. data/spec/unit/berkshelf/cookbook_store_spec.rb +3 -3
  34. data/spec/unit/berkshelf/downloader_spec.rb +171 -43
  35. data/spec/unit/berkshelf/formatters_spec.rb +13 -16
  36. data/spec/unit/berkshelf/{cookbook_source/location_spec.rb → location_spec.rb} +10 -10
  37. data/spec/unit/berkshelf/{cookbook_source → locations}/chef_api_location_spec.rb +4 -4
  38. data/spec/unit/berkshelf/{cookbook_source → locations}/git_location_spec.rb +8 -8
  39. data/spec/unit/berkshelf/{cookbook_source → locations}/path_location_spec.rb +5 -5
  40. data/spec/unit/berkshelf/{cookbook_source → locations}/site_location_spec.rb +17 -3
  41. data/spec/unit/berkshelf/lockfile_spec.rb +26 -17
  42. data/spec/unit/berkshelf/resolver_spec.rb +6 -5
  43. data/spec/unit/berkshelf/uploader_spec.rb +6 -4
  44. metadata +27 -31
  45. data/lib/berkshelf/cookbook_source/chef_api_location.rb +0 -256
  46. data/lib/berkshelf/cookbook_source/git_location.rb +0 -78
  47. data/lib/berkshelf/cookbook_source/location.rb +0 -167
  48. data/lib/berkshelf/cookbook_source/path_location.rb +0 -40
  49. data/lib/berkshelf/cookbook_source/site_location.rb +0 -149
  50. data/lib/berkshelf/dsl.rb +0 -45
  51. data/lib/berkshelf/tx_result.rb +0 -12
  52. data/lib/berkshelf/tx_result_set.rb +0 -37
  53. data/spec/fixtures/lockfile_spec/without_lock/Berksfile.lock +0 -5
  54. data/spec/unit/berkshelf/dsl_spec.rb +0 -42
  55. data/spec/unit/berkshelf/tx_result_set_spec.rb +0 -77
  56. data/spec/unit/berkshelf/tx_result_spec.rb +0 -21
data/.gitignore CHANGED
@@ -16,6 +16,8 @@ tmp
16
16
  \#*
17
17
  .DS_Store
18
18
  /spec/knife.rb
19
+ /spec/validator.pem
20
+ /spec/berkshelf.pem
19
21
  /spec/fixtures/vcr_cassettes
20
22
  /features/config.yml
21
23
  *.sw[op]
data/Guardfile CHANGED
@@ -1,22 +1,25 @@
1
+ notification :off
2
+ interactor :coolline
3
+
1
4
  guard 'spork' do
2
5
  watch('Gemfile')
3
6
  watch('spec/spec_helper.rb') { :rspec }
4
7
  watch(%r{^features/support/}) { :cucumber }
5
8
  end
6
9
 
7
- guard 'yard', :stdout => '/dev/null', :stderr => '/dev/null' do
10
+ guard 'yard', stdout: '/dev/null', stderr: '/dev/null' do
8
11
  watch(%r{app/.+\.rb})
9
12
  watch(%r{lib/.+\.rb})
10
13
  watch(%r{ext/.+\.c})
11
14
  end
12
15
 
13
- guard 'rspec', :version => 2, :cli => "--color --drb --format Fuubar", :all_on_start => false, :all_after_pass => false, :notification => false do
16
+ guard 'rspec', version: 2, cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false do
14
17
  watch(%r{^spec/unit/.+_spec\.rb$})
15
18
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
16
19
  watch('spec/spec_helper.rb') { "spec" }
17
20
  end
18
21
 
19
- guard 'cucumber', :cli => "--drb --format pretty --tags ~@no_run", :all_on_start => false, :all_after_pass => false, :notification => false do
22
+ guard 'cucumber', cli: "--drb --format pretty --tags ~@no_run --tags ~@wip", all_on_start: false, all_after_pass: false do
20
23
  watch(%r{^features/.+\.feature$})
21
24
  watch(%r{^features/support/.+$}) { 'features' }
22
25
  watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
@@ -0,0 +1,122 @@
1
+ Feature: Berksfile default locations
2
+ As a Berkshelf user
3
+ I want to be able to define default locations in my Berksfile
4
+ So I can set the precedence of where cookbook sources are downloaded from or define an alternate location for all
5
+ cookbook sources to attempt to retrieve from
6
+
7
+ Scenario: with a default chef_api(1) and site(2) location with a cookbook source that is satisfied by the chef_api(1) location
8
+ Given I write to "Berksfile" with:
9
+ """
10
+ chef_api :knife
11
+ site 'http://cookbooks.opscode.com/api/v1/cookbooks'
12
+
13
+ cookbook "artifact", "= 0.10.0"
14
+ """
15
+ And the Chef server has cookbooks:
16
+ | artifact | 0.10.0 |
17
+ When I run the install command
18
+ Then the output should contain:
19
+ """
20
+ Installing artifact (0.10.0) from chef_api:
21
+ """
22
+ And the cookbook store should have the cookbooks:
23
+ | artifact | 0.10.0 |
24
+ And the exit status should be 0
25
+
26
+ Scenario: with a default chef_api(1) and site(2) location with a cookbook source that is not satisfied by the chef_api(1) location
27
+ Given I write to "Berksfile" with:
28
+ """
29
+ chef_api :knife
30
+ site 'http://cookbooks.opscode.com/api/v1/cookbooks'
31
+
32
+ cookbook "artifact", "= 0.10.0"
33
+ """
34
+ And the Chef server does not have the cookbooks:
35
+ | artifact | 0.10.0 |
36
+ When I run the install command
37
+ Then the output should contain:
38
+ """
39
+ Installing artifact (0.10.0) from site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
40
+ """
41
+ And the cookbook store should have the cookbooks:
42
+ | artifact | 0.10.0 |
43
+ And the exit status should be 0
44
+
45
+ Scenario: with a default site(1) and chef_api(2) location with a cookbook source that is satisfied by the site(1) location
46
+ Given I write to "Berksfile" with:
47
+ """
48
+ site 'http://cookbooks.opscode.com/api/v1/cookbooks'
49
+ chef_api :knife
50
+
51
+ cookbook "artifact", "= 0.10.0"
52
+ """
53
+ And the Chef server has cookbooks:
54
+ | artifact | 0.10.0 |
55
+ When I run the install command
56
+ Then the output should contain:
57
+ """
58
+ Installing artifact (0.10.0) from site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
59
+ """
60
+ And the cookbook store should have the cookbooks:
61
+ | artifact | 0.10.0 |
62
+ And the exit status should be 0
63
+
64
+ Scenario: with a default chef_api(1) location and a cookbook source that is satisfied by the chef_api(1) location but has an explicit location set
65
+ Given I write to "Berksfile" with:
66
+ """
67
+ chef_api :knife
68
+
69
+ cookbook 'artifact', '= 0.10.0', site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
70
+ """
71
+ And the Chef server has cookbooks:
72
+ | artifact | 0.10.0 |
73
+ When I run the install command
74
+ Then the output should contain:
75
+ """
76
+ Installing artifact (0.10.0) from site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
77
+ """
78
+ And the cookbook store should have the cookbooks:
79
+ | artifact | 0.10.0 |
80
+ And the exit status should be 0
81
+
82
+ Scenario: with a defualt chef_api(1) location and a cookbook source that is not satisfied by it
83
+ Given I write to "Berksfile" with:
84
+ """
85
+ chef_api :knife
86
+
87
+ cookbook 'artifact', '= 0.10.0'
88
+ """
89
+ And the Chef server does not have the cookbooks:
90
+ | artifact | 0.10.0 |
91
+ When I run the install command
92
+ Then the output should contain:
93
+ """
94
+ Cookbook 'artifact' not found in any of the default locations
95
+ """
96
+ And the CLI should exit with the status code for error "CookbookNotFound"
97
+
98
+ Scenario: with two duplicate locations definitions
99
+ Given I write to "Berksfile" with:
100
+ """
101
+ site 'http://cookbooks.opscode.com/api/v1/cookbooks'
102
+ site 'http://cookbooks.opscode.com/api/v1/cookbooks'
103
+
104
+ cookbook 'artifact', '= 0.10.0'
105
+ """
106
+ When I run the install command
107
+ Then the output should contain:
108
+ """
109
+ A default 'site' location with the value 'http://cookbooks.opscode.com/api/v1/cookbooks' is already defined
110
+ """
111
+ And the CLI should exit with the status code for error "DuplicateLocationDefined"
112
+
113
+ Scenario: with two locations of the same type but different values
114
+ Given I write to "Berksfile" with:
115
+ """
116
+ site 'http://cookbooks.opscode.com/api/v1/cookbooks'
117
+ site 'http://cookbooks.opscode.com/api/v2/cookbooks'
118
+
119
+ cookbook 'artifact', '= 0.10.0'
120
+ """
121
+ When I run the install command
122
+ Then the exit status should be 0
@@ -65,7 +65,7 @@ Feature: install cookbooks from a Berksfile
65
65
  """
66
66
  And the exit status should be 0
67
67
 
68
- @wip
68
+ @no_run
69
69
  Scenario: installing a Berksfile that contains a path location which contains a broken symlink
70
70
  Given a Berksfile with path location sources to fixtures:
71
71
  | example_cookbook_broken_link | example_cookbook_broken_link |
@@ -142,9 +142,9 @@ Feature: install cookbooks from a Berksfile
142
142
  And I run the install command
143
143
  Then the output should contain:
144
144
  """
145
- Cookbook 'doesntexist' not found at site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
145
+ Cookbook 'doesntexist' not found in any of the default locations
146
146
  """
147
- And the CLI should exit with the status code for error "DownloadFailure"
147
+ And the CLI should exit with the status code for error "CookbookNotFound"
148
148
 
149
149
  Scenario: running install command with the --shims flag to create a directory of shims
150
150
  Given I write to "Berksfile" with:
@@ -162,6 +162,22 @@ Feature: install cookbooks from a Berksfile
162
162
  """
163
163
  And the exit status should be 0
164
164
 
165
+ Scenario: running install command with the --shims flag and a relative path
166
+ Given I write to "Berksfile" with:
167
+ """
168
+ cookbook "mysql", "1.2.4"
169
+ """
170
+ When I run the install command with flags:
171
+ | --shims relativepath |
172
+ Then the following directories should exist:
173
+ | relativepath |
174
+ | relativepath/mysql |
175
+ And the output should contain:
176
+ """
177
+ Shims written to:
178
+ """
179
+ And the exit status should be 0
180
+
165
181
  Scenario: running install with --shims when current project is a cookbook and the 'metadata' is specified
166
182
  Given a cookbook named "sparkle_motion"
167
183
  And the cookbook "sparkle_motion" has the file "Berksfile" with:
@@ -254,7 +270,7 @@ Feature: install cookbooks from a Berksfile
254
270
  cookbook "artifact", chef_api: :knife
255
271
  """
256
272
  And the Chef server has cookbooks:
257
- | artifact | 0.10.0 |
273
+ | artifact | 0.10.2 |
258
274
  When I run the install command
259
275
  Then the output should contain:
260
276
  """
@@ -7,16 +7,11 @@ Feature: Berksfile.lock
7
7
  Scenario: Writing the Berksfile.lock
8
8
  Given I write to "Berksfile" with:
9
9
  """
10
- cookbook 'ntp'
11
- cookbook 'mysql', git: 'https://github.com/opscode-cookbooks/mysql.git', :ref => '190c0c2267785b7b9b303369b8a64ed04364d5f9'
10
+ cookbook 'ntp', '1.1.8'
12
11
  """
13
12
  When I run the install command
14
13
  Then a file named "Berksfile.lock" should exist in the current directory
15
14
  And the file "Berksfile.lock" should contain in the current directory:
16
15
  """
17
16
  cookbook 'ntp', :locked_version => '1.1.8'
18
- cookbook 'mysql', :git => 'https://github.com/opscode-cookbooks/mysql.git', :ref => '190c0c2267785b7b9b303369b8a64ed04364d5f9'
19
- cookbook 'openssl', :locked_version => '1.0.0'
20
- cookbook 'windows', :locked_version => '1.3.2'
21
- cookbook 'chef_handler', :locked_version => '1.0.6'
22
17
  """
@@ -6,7 +6,7 @@ Feature: update
6
6
  Scenario: knife berkshelf update
7
7
  Given I write to "Berksfile" with:
8
8
  """
9
- cookbook "mysql"
9
+ cookbook "mysql", "1.3.0"
10
10
  """
11
11
  Given I write to "Berksfile.lock" with:
12
12
  """
@@ -18,6 +18,5 @@ Feature: update
18
18
  """
19
19
  cookbook 'mysql', :locked_version => '1.3.0'
20
20
  cookbook 'openssl', :locked_version => '1.0.0'
21
- cookbook 'windows', :locked_version => '1.3.2'
22
- cookbook 'chef_handler', :locked_version => '1.0.6'
21
+ cookbook 'build-essential', :locked_version => '1.1.0'
23
22
  """
@@ -1,3 +1,5 @@
1
+ site :opscode
1
2
  <% if options[:metadata_entry] -%>
3
+
2
4
  metadata
3
5
  <% end -%>
@@ -1,6 +1,12 @@
1
1
  .vagrant
2
2
  Berksfile.lock
3
3
  Gemfile.lock
4
+ *~
5
+ *#
6
+ .#*
7
+ \#*#
8
+ .*.sw[a-z]
9
+ *.un~
4
10
  /cookbooks
5
11
  <% if options[:scmversion] -%>
6
12
  VERSION
@@ -1,3 +1,5 @@
1
+ require 'forwardable'
2
+ require 'uri'
1
3
  require 'pathname'
2
4
  require 'zlib'
3
5
  require 'archive/tar/minitar'
@@ -20,7 +22,6 @@ module Berkshelf
20
22
  DEFAULT_FILENAME = 'Berksfile'.freeze
21
23
 
22
24
  autoload :Cli, 'berkshelf/cli'
23
- autoload :DSL, 'berkshelf/dsl'
24
25
  autoload :Git, 'berkshelf/git'
25
26
  autoload :Berksfile, 'berkshelf/berksfile'
26
27
  autoload :Lockfile, 'berkshelf/lockfile'
@@ -30,18 +31,17 @@ module Berkshelf
30
31
  autoload :CookbookSource, 'berkshelf/cookbook_source'
31
32
  autoload :CookbookStore, 'berkshelf/cookbook_store'
32
33
  autoload :CachedCookbook, 'berkshelf/cached_cookbook'
33
- autoload :TXResult, 'berkshelf/tx_result'
34
- autoload :TXResultSet, 'berkshelf/tx_result_set'
35
34
  autoload :Downloader, 'berkshelf/downloader'
36
35
  autoload :Uploader, 'berkshelf/uploader'
37
36
  autoload :Resolver, 'berkshelf/resolver'
38
37
 
38
+ require 'berkshelf/location'
39
+
39
40
  class << self
40
41
  attr_accessor :ui
41
- attr_accessor :cookbook_store
42
- attr_accessor :downloader
43
-
42
+
44
43
  attr_writer :config_path
44
+ attr_writer :cookbook_store
45
45
 
46
46
  def root
47
47
  @root ||= Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
@@ -74,10 +74,6 @@ module Berkshelf
74
74
  @cookbook_store ||= CookbookStore.new(cookbooks_dir)
75
75
  end
76
76
 
77
- def downloader
78
- @downloader ||= Downloader.new(cookbook_store)
79
- end
80
-
81
77
  def config_path
82
78
  @config_path ||= DEFAULT_CONFIG
83
79
  end
@@ -1,9 +1,13 @@
1
1
  module Berkshelf
2
2
  # @author Jamie Winsor <jamie@vialstudios.com>
3
3
  class Berksfile
4
- include DSL
4
+ extend Forwardable
5
5
 
6
6
  class << self
7
+ # @param [String] file
8
+ # a path on disk to a Berksfile to instantiate from
9
+ #
10
+ # @return [Berksfile]
7
11
  def from_file(file)
8
12
  content = File.read(file)
9
13
  object = new(file)
@@ -28,26 +32,201 @@ module Berkshelf
28
32
  end
29
33
  end
30
34
 
35
+ @@active_group = nil
36
+
37
+ # @return [String]
38
+ # The path on disk to the file representing this instance of Berksfile
31
39
  attr_reader :filepath
40
+
41
+ # @return [Berkshelf::Downloader]
42
+ attr_reader :downloader
43
+
44
+ def_delegator :downloader, :add_location
45
+ def_delegator :downloader, :locations
32
46
 
33
47
  def initialize(path)
34
48
  @filepath = path
35
49
  @sources = Hash.new
50
+ @downloader = Downloader.new(Berkshelf.cookbook_store)
36
51
  end
37
52
 
38
- # Add the given source to the sources array. A DuplicateSourceDefined
39
- # exception will be raised if a source is added whose name conflicts
40
- # with a source who has already been added.
53
+ # Add a cookbook source to the Berksfile to be retrieved and have it's dependencies recurisvely retrieved
54
+ # and resolved.
55
+ #
56
+ # @example a cookbook source that will be retrieved from one of the default locations
57
+ # cookbook 'artifact'
58
+ #
59
+ # @example a cookbook source that will be retrieved from a path on disk
60
+ # cookbook 'artifact', path: '/Users/reset/code/artifact'
61
+ #
62
+ # @example a cookbook source that will be retrieved from a remote community site
63
+ # cookbook 'artifact', site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
64
+ #
65
+ # @example a cookbook source that will be retrieved from the latest API of the Opscode Community Site
66
+ # cookbook 'artifact', site: :opscode
67
+ #
68
+ # @example a cookbook source that will be retrieved from a Git server
69
+ # cookbook 'artifact', git: 'git://github.com/RiotGames/artifact-cookbook.git'
41
70
  #
42
- # @param [Berkshelf::CookbookSource] source
43
- # the source to add
71
+ # @example a cookbook source that will be retrieved from a Chef API (Chef Server)
72
+ # cookbook 'artifact', chef_api: 'https://api.opscode.com/organizations/vialstudios', node_name: 'reset', client_key: '/Users/reset/.chef/knife.rb'
73
+ #
74
+ # @example a cookbook source that will be retrieved from a Chef API using your Knife config
75
+ # cookbook 'artifact', chef_api: :knife
76
+ #
77
+ # @overload cookbook(name, version_constraint, options = {})
78
+ # @param [#to_s] name
79
+ # @param [#to_s] version_constraint
80
+ # @param [Hash] options
81
+ #
82
+ # @option options [Symbol, Array] :group
83
+ # the group or groups that the cookbook belongs to
84
+ # @option options [String, Symbol] :chef_api
85
+ # a URL to a Chef API. Alternatively the symbol :knife can be provided
86
+ # which will instantiate this location with the values found in your
87
+ # knife configuration.
88
+ # @option options [String] :site
89
+ # a URL pointing to a community API endpoint
90
+ # @option options [String] :path
91
+ # a filepath to the cookbook on your local disk
92
+ # @option options [String] :git
93
+ # the Git URL to clone
94
+ #
95
+ # @see ChefAPILocation
96
+ # @see SiteLocation
97
+ # @see PathLocation
98
+ # @see GitLocation
99
+ # @overload cookbook(name, options = {})
100
+ # @param [#to_s] name
101
+ # @param [Hash] options
102
+ #
103
+ # @option options [Symbol, Array] :group
104
+ # the group or groups that the cookbook belongs to
105
+ # @option options [String, Symbol] :chef_api
106
+ # a URL to a Chef API. Alternatively the symbol :knife can be provided
107
+ # which will instantiate this location with the values found in your
108
+ # knife configuration.
109
+ # @option options [String] :site
110
+ # a URL pointing to a community API endpoint
111
+ # @option options [String] :path
112
+ # a filepath to the cookbook on your local disk
113
+ # @option options [String] :git
114
+ # the Git URL to clone
115
+ #
116
+ # @see ChefAPILocation
117
+ # @see SiteLocation
118
+ # @see PathLocation
119
+ # @see GitLocation
120
+ def cookbook(*args)
121
+ options = args.last.is_a?(Hash) ? args.pop : Hash.new
122
+ name, constraint = args
123
+
124
+ options[:group] = Array(options[:group])
125
+
126
+ if @@active_group
127
+ options[:group] += @@active_group
128
+ end
129
+
130
+ add_source(name, constraint, options)
131
+ end
132
+
133
+
134
+ def group(*args)
135
+ @@active_group = args
136
+ yield
137
+ @@active_group = nil
138
+ end
139
+
140
+ # Use a Cookbook metadata file to determine additional cookbook sources to retrieve. All
141
+ # sources found in the metadata will use the default locations set in the Berksfile (if any are set)
142
+ # or the default locations defined by Berkshelf.
143
+ #
144
+ # @param [Hash] options
145
+ #
146
+ # @option options [String] :path
147
+ # path to the metadata file
148
+ def metadata(options = {})
149
+ path = options[:path] || File.dirname(filepath)
150
+
151
+ metadata_file = Berkshelf.find_metadata(path)
152
+
153
+ unless metadata_file
154
+ raise CookbookNotFound, "No 'metadata.rb' found at #{path}"
155
+ end
156
+
157
+ metadata = Chef::Cookbook::Metadata.new
158
+ metadata.from_file(metadata_file.to_s)
159
+
160
+ name = if metadata.name.empty? || metadata.name.nil?
161
+ File.basename(File.dirname(metadata_file))
162
+ else
163
+ metadata.name
164
+ end
165
+
166
+ constraint = "= #{metadata.version}"
167
+
168
+ add_source(name, constraint, path: File.dirname(metadata_file))
169
+ end
170
+
171
+ # Add a 'Site' default location which will be used to resolve cookbook sources that do not
172
+ # contain an explicit location.
173
+ #
174
+ # @note
175
+ # specifying the symbol :opscode as the value of the site default location is an alias for the
176
+ # latest API of the Opscode Community Site.
177
+ #
178
+ # @example
179
+ # site :opscode
180
+ # site "http://cookbooks.opscode.com/api/v1/cookbooks"
181
+ #
182
+ # @param [String, Symbol] value
183
+ #
184
+ # @return [Hash]
185
+ def site(value)
186
+ add_location(:site, value)
187
+ end
188
+
189
+ # Add a 'Chef API' default location which will be used to resolve cookbook sources that do not
190
+ # contain an explicit location.
191
+ #
192
+ # @note
193
+ # specifying the symbol :knife as the value of the chef_api default location will attempt to use the
194
+ # contents of your user's Knife.rb to find the Chef API to interact with.
195
+ #
196
+ # @example using the symbol :knife to add a Chef API default location
197
+ # chef_api :knife
198
+ #
199
+ # @example using a URL, node_name, and client_key to add a Chef API default location
200
+ # chef_api "https://api.opscode.com/organizations/vialstudios", node_name: "reset", client_key: "/Users/reset/.chef/knife.rb"
201
+ #
202
+ # @param [String, Symbol] value
203
+ # @param [Hash] options
204
+ #
205
+ # @return [Hash]
206
+ def chef_api(value, options = {})
207
+ add_location(:chef_api, value, options)
208
+ end
209
+
210
+ # Add a source of the given name and constraint to the array of sources.
211
+ #
212
+ # @param [String] name
213
+ # the name of the source to add
214
+ # @param [String, Solve::Constraint] constraint
215
+ # the constraint to lock the source to
216
+ # @param [Hash] options
217
+ #
218
+ # @raise [DuplicateSourceDefined] if a source is added whose name conflicts
219
+ # with a source who has already been added.
44
220
  #
45
221
  # @return [Array<Berkshelf::CookbookSource]
46
- def add_source(source)
47
- if has_source?(source)
48
- raise DuplicateSourceDefined, "Berksfile contains two sources named '#{source.name}'. Remove one and try again."
222
+ def add_source(name, constraint = nil, options = {})
223
+ if has_source?(name)
224
+ raise DuplicateSourceDefined, "Berksfile contains two sources named '#{name}'. Remove one and try again."
49
225
  end
50
- @sources[source.to_s] = source
226
+
227
+ options[:constraint] = constraint
228
+
229
+ @sources[name] = CookbookSource.new(name, options)
51
230
  end
52
231
 
53
232
  # @param [#to_s] source
@@ -97,7 +276,7 @@ module Berkshelf
97
276
  # }
98
277
  def groups
99
278
  {}.tap do |groups|
100
- @sources.each_pair do |name, source|
279
+ sources.each do |source|
101
280
  source.groups.each do |group|
102
281
  groups[group] ||= []
103
282
  groups[group] << source
@@ -122,7 +301,11 @@ module Berkshelf
122
301
  # Path to a directory of shims each pointing to a Cookbook Version that is
123
302
  # part of the dependency solution. Each shim is a hard link on disk.
124
303
  def install(options = {})
125
- resolver = Resolver.new(Berkshelf.downloader, sources(exclude: options[:without]))
304
+ resolver = Resolver.new(
305
+ self.downloader,
306
+ sources: sources(exclude: options[:without])
307
+ )
308
+
126
309
  solution = resolver.resolve
127
310
  if options[:shims]
128
311
  write_shims(options[:shims], solution)
@@ -154,7 +337,7 @@ module Berkshelf
154
337
 
155
338
  solution.each do |cb|
156
339
  Berkshelf.formatter.upload cb.cookbook_name, cb.version, chef_server_url
157
- uploader.upload!(cb, options)
340
+ uploader.upload(cb, options)
158
341
  end
159
342
  end
160
343
 
@@ -166,7 +349,10 @@ module Berkshelf
166
349
  #
167
350
  # @return [Array<Berkshelf::CachedCookbooks]
168
351
  def resolve(options = {})
169
- Resolver.new(Berkshelf.downloader, sources(exclude: options[:without])).resolve
352
+ Resolver.new(
353
+ self.downloader,
354
+ sources: sources(exclude: options[:without])
355
+ ).resolve
170
356
  end
171
357
 
172
358
  # Write a collection of hard links to the given path representing the given
@@ -182,6 +368,7 @@ module Berkshelf
182
368
  # @param [Pathname, String] path
183
369
  # @param [Array<Berkshelf::CachedCookbook>] cached_cookbooks
184
370
  def write_shims(path, cached_cookbooks)
371
+ path = File.expand_path(path)
185
372
  actual_path = nil
186
373
 
187
374
  if descendant_directory?(path, Dir.pwd)
@@ -207,6 +394,8 @@ module Berkshelf
207
394
  #
208
395
  # @param [String] content
209
396
  #
397
+ # @raise [BerksfileReadError] if Berksfile contains bad content
398
+ #
210
399
  # @return [Berksfile]
211
400
  def load(content)
212
401
  begin