berkshelf 1.2.0.rc1 → 1.2.1

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.
Files changed (37) hide show
  1. data/CHANGELOG.md +8 -0
  2. data/Gemfile +1 -1
  3. data/README.md +2 -0
  4. data/berkshelf.gemspec +4 -3
  5. data/features/step_definitions/filesystem_steps.rb +0 -1
  6. data/generator_files/Gemfile.erb +0 -3
  7. data/generator_files/Vagrantfile.erb +13 -1
  8. data/lib/berkshelf.rb +0 -1
  9. data/lib/berkshelf/berksfile.rb +11 -4
  10. data/lib/berkshelf/cached_cookbook.rb +2 -257
  11. data/lib/berkshelf/chef.rb +0 -1
  12. data/lib/berkshelf/chef/config.rb +3 -0
  13. data/lib/berkshelf/chef/cookbook.rb +0 -2
  14. data/lib/berkshelf/community_rest.rb +31 -6
  15. data/lib/berkshelf/cookbook_source.rb +5 -1
  16. data/lib/berkshelf/errors.rb +24 -0
  17. data/lib/berkshelf/git.rb +49 -1
  18. data/lib/berkshelf/init_generator.rb +1 -1
  19. data/lib/berkshelf/locations/chef_api_location.rb +6 -3
  20. data/lib/berkshelf/locations/path_location.rb +2 -0
  21. data/lib/berkshelf/version.rb +1 -1
  22. data/spec/spec_helper.rb +9 -2
  23. data/spec/support/chef_api.rb +1 -10
  24. data/spec/unit/berkshelf/cached_cookbook_spec.rb +37 -458
  25. data/spec/unit/berkshelf/git_spec.rb +119 -9
  26. data/spec/unit/berkshelf/init_generator_spec.rb +0 -1
  27. metadata +30 -24
  28. data/lib/berkshelf/chef/cookbook/metadata.rb +0 -556
  29. data/lib/berkshelf/chef/cookbook/syntax_check.rb +0 -158
  30. data/lib/berkshelf/chef/digester.rb +0 -67
  31. data/lib/berkshelf/mixin/checksum.rb +0 -16
  32. data/lib/berkshelf/mixin/params_validate.rb +0 -218
  33. data/lib/berkshelf/mixin/shell_out.rb +0 -23
  34. data/lib/berkshelf/uploader.rb +0 -80
  35. data/spec/unit/berkshelf/uploader_spec.rb +0 -27
  36. data/spec/unit/chef/cookbook/metadata_spec.rb +0 -5
  37. data/spec/unit/chef/digester_spec.rb +0 -41
@@ -3,6 +3,7 @@ require 'spec_helper'
3
3
  describe Berkshelf::Git do
4
4
  describe "ClassMethods" do
5
5
  subject { Berkshelf::Git }
6
+ let(:git) { Berkshelf::Git }
6
7
 
7
8
  describe "::find_git" do
8
9
  it "should find git" do
@@ -33,16 +34,60 @@ describe Berkshelf::Git do
33
34
  describe "::checkout" do
34
35
  let(:repo_path) { clone_target_for('nginx') }
35
36
  let(:repo) {
36
- origin_uri = git_origin_for('nginx', tags: ['1.0.1'])
37
- subject.clone(origin_uri, repo_path)
37
+ origin_uri = git_origin_for('nginx', tags: ['1.0.1', '1.0.2'], branches: ['topic', 'next_topic'])
38
+ git.clone(origin_uri, repo_path)
38
39
  }
39
- let(:tag) { "1.0.1" }
40
40
 
41
- it "checks out the specified path of the given repository" do
42
- subject.checkout(repo, tag)
41
+ shared_examples "able to checkout git ref" do |test_ref|
42
+ it "checks out the specified ref of the given repository" do
43
+ git.checkout(repo, ref)
44
+
45
+ Dir.chdir repo_path do
46
+ test_ref ||= ref
47
+ %x[git rev-parse #{test_ref}].should == %x[git rev-parse HEAD]
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'with sha commit id' do
53
+ let(:ref) { git_sha_for_ref('nginx', '1.0.1') }
54
+
55
+ it_behaves_like 'able to checkout git ref'
56
+ end
57
+
58
+ context 'with tags' do
59
+ let(:ref) { "1.0.1" }
60
+
61
+ it_behaves_like 'able to checkout git ref'
62
+
63
+ context 'after checking out another tag' do
64
+ let(:other_tag) { '1.0.2' }
65
+ before do
66
+ git.checkout(repo, other_tag)
67
+ Dir.chdir repo_path do
68
+ run! "echo 'uncommitted change' >> content_file"
69
+ end
70
+ end
71
+
72
+ it_behaves_like 'able to checkout git ref'
73
+ end
74
+ end
75
+
76
+ context 'with branches' do
77
+ let(:ref) { 'topic' }
43
78
 
44
- Dir.chdir repo_path do
45
- %x[git rev-parse #{tag}].should == %x[git rev-parse HEAD]
79
+ it_behaves_like 'able to checkout git ref', 'origin/topic'
80
+
81
+ context 'after checking out another branch' do
82
+ let(:other_branch) { 'next_topic' }
83
+ before do
84
+ git.checkout(repo, other_branch)
85
+ Dir.chdir repo_path do
86
+ run! "echo 'uncommitted change' >> content_file"
87
+ end
88
+ end
89
+
90
+ it_behaves_like 'able to checkout git ref', 'origin/topic'
46
91
  end
47
92
  end
48
93
  end
@@ -52,11 +97,76 @@ describe Berkshelf::Git do
52
97
  before(:each) do |example|
53
98
  origin_uri = git_origin_for('nginx', tags: ['1.1.1'])
54
99
  subject.clone(origin_uri, repo_path)
55
- subject.checkout(repo_path, git_sha_for_tag('nginx', '1.1.1'))
100
+ subject.checkout(repo_path, git_sha_for_ref('nginx', '1.1.1'))
56
101
  end
57
102
 
58
103
  it "returns the ref for HEAD" do
59
- expect(subject.rev_parse(repo_path)).to eql(git_sha_for_tag('nginx', '1.1.1'))
104
+ expect(subject.rev_parse(repo_path)).to eql(git_sha_for_ref('nginx', '1.1.1'))
105
+ end
106
+ end
107
+
108
+ describe "::show_ref" do
109
+ let(:repo_path) { clone_target_for('nginx') }
110
+ let(:tags) { ['1.0.1'] }
111
+ let(:branches) { ['topic'] }
112
+ let!(:repo) {
113
+ origin_uri = git_origin_for('nginx', tags: tags, branches: branches)
114
+ git.clone(origin_uri, repo_path)
115
+ }
116
+
117
+ it 'returns the commit id for the given tag' do
118
+ git.show_ref(repo_path, '1.0.1').should == git_sha_for_ref('nginx', '1.0.1')
119
+ end
120
+
121
+ it 'returns the commit id for the given branch' do
122
+ git.show_ref(repo_path, 'topic').should == git_sha_for_ref('nginx', 'topic')
123
+ end
124
+
125
+ context 'with an ambiguous ref' do
126
+ let(:tags) { ['topic'] }
127
+ let(:branches) { ['topic'] }
128
+
129
+ it 'raises an error' do
130
+ expect {git.show_ref(repo_path, 'topic')}.to raise_error(Berkshelf::AmbiguousGitRef)
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '::revision_from_ref' do
136
+ let(:repo_path) { clone_target_for('nginx') }
137
+ let(:tags) { ['1.0.1'] }
138
+ let(:branches) { ['topic'] }
139
+ let!(:repo) {
140
+ origin_uri = git_origin_for('nginx', tags: tags, branches: branches)
141
+ git.clone(origin_uri, repo_path)
142
+ }
143
+
144
+ context 'with sha commit id' do
145
+ let(:revision) { git_sha_for_ref('nginx', '1.0.1') }
146
+ it 'returns the passed revision' do
147
+ git.revision_from_ref(repo_path, revision).should == revision
148
+ end
149
+ end
150
+
151
+ context 'with tag' do
152
+ let(:revision) { git_sha_for_ref('nginx', '1.0.1') }
153
+ it 'returns the revision' do
154
+ git.revision_from_ref(repo_path, '1.0.1').should == revision
155
+ end
156
+ end
157
+
158
+ context 'with branch' do
159
+ let(:revision) { git_sha_for_ref('nginx', 'topic') }
160
+ it 'returns the revision' do
161
+ git.revision_from_ref(repo_path, 'topic').should == revision
162
+ end
163
+ end
164
+
165
+ context 'with an invalid ref' do
166
+ let(:ref) { 'foobar' }
167
+ it 'raises an error' do
168
+ expect { git.revision_from_ref(repo_path, ref) }.to raise_error(Berkshelf::InvalidGitRef)
169
+ end
60
170
  end
61
171
  end
62
172
 
@@ -18,7 +18,6 @@ describe Berkshelf::InitGenerator do
18
18
  file "Berksfile"
19
19
  file "Gemfile" do
20
20
  contains "gem 'berkshelf'"
21
- contains "gem 'vagrant'"
22
21
  end
23
22
  file "Vagrantfile" do
24
23
  contains "require 'berkshelf/vagrant'"
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: berkshelf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0.rc1
5
- prerelease: 6
4
+ version: 1.2.1
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jamie Winsor
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-02-26 00:00:00.000000000 Z
15
+ date: 2013-03-07 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: yajl-ruby
@@ -101,7 +101,7 @@ dependencies:
101
101
  requirements:
102
102
  - - ! '>='
103
103
  - !ruby/object:Gem::Version
104
- version: 0.7.0.rc4
104
+ version: 0.8.3
105
105
  type: :runtime
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
@@ -109,7 +109,7 @@ dependencies:
109
109
  requirements:
110
110
  - - ! '>='
111
111
  - !ruby/object:Gem::Version
112
- version: 0.7.0.rc4
112
+ version: 0.8.3
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: chozo
115
115
  requirement: !ruby/object:Gem::Requirement
@@ -117,7 +117,7 @@ dependencies:
117
117
  requirements:
118
118
  - - ! '>='
119
119
  - !ruby/object:Gem::Version
120
- version: 0.5.0
120
+ version: 0.6.1
121
121
  type: :runtime
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
@@ -125,7 +125,7 @@ dependencies:
125
125
  requirements:
126
126
  - - ! '>='
127
127
  - !ruby/object:Gem::Version
128
- version: 0.5.0
128
+ version: 0.6.1
129
129
  - !ruby/object:Gem::Dependency
130
130
  name: hashie
131
131
  requirement: !ruby/object:Gem::Requirement
@@ -133,7 +133,7 @@ dependencies:
133
133
  requirements:
134
134
  - - ! '>='
135
135
  - !ruby/object:Gem::Version
136
- version: '0'
136
+ version: 2.0.2
137
137
  type: :runtime
138
138
  prerelease: false
139
139
  version_requirements: !ruby/object:Gem::Requirement
@@ -141,7 +141,7 @@ dependencies:
141
141
  requirements:
142
142
  - - ! '>='
143
143
  - !ruby/object:Gem::Version
144
- version: '0'
144
+ version: 2.0.2
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: minitar
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -222,6 +222,22 @@ dependencies:
222
222
  - - ~>
223
223
  - !ruby/object:Gem::Version
224
224
  version: 0.16.0
225
+ - !ruby/object:Gem::Dependency
226
+ name: retryable
227
+ requirement: !ruby/object:Gem::Requirement
228
+ none: false
229
+ requirements:
230
+ - - ! '>='
231
+ - !ruby/object:Gem::Version
232
+ version: '0'
233
+ type: :runtime
234
+ prerelease: false
235
+ version_requirements: !ruby/object:Gem::Requirement
236
+ none: false
237
+ requirements:
238
+ - - ! '>='
239
+ - !ruby/object:Gem::Version
240
+ version: '0'
225
241
  - !ruby/object:Gem::Dependency
226
242
  name: moneta
227
243
  requirement: !ruby/object:Gem::Requirement
@@ -487,9 +503,6 @@ files:
487
503
  - lib/berkshelf/chef/config.rb
488
504
  - lib/berkshelf/chef/cookbook.rb
489
505
  - lib/berkshelf/chef/cookbook/chefignore.rb
490
- - lib/berkshelf/chef/cookbook/metadata.rb
491
- - lib/berkshelf/chef/cookbook/syntax_check.rb
492
- - lib/berkshelf/chef/digester.rb
493
506
  - lib/berkshelf/cli.rb
494
507
  - lib/berkshelf/command.rb
495
508
  - lib/berkshelf/community_rest.rb
@@ -517,14 +530,10 @@ files:
517
530
  - lib/berkshelf/locations/site_location.rb
518
531
  - lib/berkshelf/lockfile.rb
519
532
  - lib/berkshelf/mixin.rb
520
- - lib/berkshelf/mixin/checksum.rb
521
- - lib/berkshelf/mixin/params_validate.rb
522
533
  - lib/berkshelf/mixin/path_helpers.rb
523
- - lib/berkshelf/mixin/shell_out.rb
524
534
  - lib/berkshelf/resolver.rb
525
535
  - lib/berkshelf/thor.rb
526
536
  - lib/berkshelf/ui.rb
527
- - lib/berkshelf/uploader.rb
528
537
  - lib/berkshelf/vagrant.rb
529
538
  - lib/berkshelf/vagrant/action/clean.rb
530
539
  - lib/berkshelf/vagrant/action/install.rb
@@ -592,11 +601,8 @@ files:
592
601
  - spec/unit/berkshelf/lockfile_spec.rb
593
602
  - spec/unit/berkshelf/resolver_spec.rb
594
603
  - spec/unit/berkshelf/ui_spec.rb
595
- - spec/unit/berkshelf/uploader_spec.rb
596
604
  - spec/unit/berkshelf_spec.rb
597
605
  - spec/unit/chef/config_spec.rb
598
- - spec/unit/chef/cookbook/metadata_spec.rb
599
- - spec/unit/chef/digester_spec.rb
600
606
  homepage: http://berkshelf.com
601
607
  licenses:
602
608
  - Apache 2.0
@@ -613,9 +619,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
613
619
  required_rubygems_version: !ruby/object:Gem::Requirement
614
620
  none: false
615
621
  requirements:
616
- - - ! '>'
622
+ - - ! '>='
617
623
  - !ruby/object:Gem::Version
618
- version: 1.3.1
624
+ version: '0'
625
+ segments:
626
+ - 0
627
+ hash: -3254137740807236813
619
628
  requirements: []
620
629
  rubyforge_project:
621
630
  rubygems_version: 1.8.24
@@ -702,9 +711,6 @@ test_files:
702
711
  - spec/unit/berkshelf/lockfile_spec.rb
703
712
  - spec/unit/berkshelf/resolver_spec.rb
704
713
  - spec/unit/berkshelf/ui_spec.rb
705
- - spec/unit/berkshelf/uploader_spec.rb
706
714
  - spec/unit/berkshelf_spec.rb
707
715
  - spec/unit/chef/config_spec.rb
708
- - spec/unit/chef/cookbook/metadata_spec.rb
709
- - spec/unit/chef/digester_spec.rb
710
716
  has_rdoc:
@@ -1,556 +0,0 @@
1
- module Berkshelf::Chef::Cookbook
2
- # @author Jamie Winsor <reset@riotgames.com>
3
- #
4
- # Borrowed and modified from: {https://raw.github.com/opscode/chef/11.4.0/lib/chef/cookbook/metadata.rb}
5
- #
6
- # Copyright:: Copyright 2008-2010 Opscode, Inc.
7
- #
8
- # Licensed under the Apache License, Version 2.0 (the "License");
9
- # you may not use this file except in compliance with the License.
10
- # You may obtain a copy of the License at
11
- #
12
- # http://www.apache.org/licenses/LICENSE-2.0
13
- #
14
- # Unless required by applicable law or agreed to in writing, software
15
- # distributed under the License is distributed on an "AS IS" BASIS,
16
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- # See the License for the specific language governing permissions and
18
- # limitations under the License.
19
- #
20
- # == Chef::Cookbook::Metadata
21
- # Chef::Cookbook::Metadata provides a convenient DSL for declaring metadata
22
- # about Chef Cookbooks.
23
- class Metadata
24
- class << self
25
- def from_hash(hash)
26
- new.from_hash(hash)
27
- end
28
- end
29
-
30
- NAME = 'name'.freeze
31
- DESCRIPTION = 'description'.freeze
32
- LONG_DESCRIPTION = 'long_description'.freeze
33
- MAINTAINER = 'maintainer'.freeze
34
- MAINTAINER_EMAIL = 'maintainer_email'.freeze
35
- LICENSE = 'license'.freeze
36
- PLATFORMS = 'platforms'.freeze
37
- DEPENDENCIES = 'dependencies'.freeze
38
- RECOMMENDATIONS = 'recommendations'.freeze
39
- SUGGESTIONS = 'suggestions'.freeze
40
- CONFLICTING = 'conflicting'.freeze
41
- PROVIDING = 'providing'.freeze
42
- REPLACING = 'replacing'.freeze
43
- ATTRIBUTES = 'attributes'.freeze
44
- GROUPINGS = 'groupings'.freeze
45
- RECIPES = 'recipes'.freeze
46
- VERSION = 'version'.freeze
47
-
48
- COMPARISON_FIELDS = [
49
- :name, :description, :long_description, :maintainer,
50
- :maintainer_email, :license, :platforms, :dependencies,
51
- :recommendations, :suggestions, :conflicting, :providing,
52
- :replacing, :attributes, :groupings, :recipes, :version
53
- ]
54
-
55
- include Berkshelf::Mixin::ParamsValidate
56
- include Chozo::Mixin::FromFile
57
-
58
- attr_reader :cookbook
59
- attr_reader :platforms
60
- attr_reader :dependencies
61
- attr_reader :recommendations
62
- attr_reader :suggestions
63
- attr_reader :conflicting
64
- attr_reader :providing
65
- attr_reader :replacing
66
- attr_reader :attributes
67
- attr_reader :groupings
68
- attr_reader :recipes
69
- attr_reader :version
70
-
71
- # Builds a new Chef::Cookbook::Metadata object.
72
- #
73
- # === Parameters
74
- # cookbook<String>:: An optional cookbook object
75
- # maintainer<String>:: An optional maintainer
76
- # maintainer_email<String>:: An optional maintainer email
77
- # license<String>::An optional license. Default is Apache v2.0
78
- #
79
- # === Returns
80
- # metadata<Chef::Cookbook::Metadata>
81
- def initialize(cookbook = nil, maintainer = 'YOUR_COMPANY_NAME', maintainer_email = 'YOUR_EMAIL', license = 'none')
82
- @cookbook = cookbook
83
- @name = cookbook ? cookbook.name : ""
84
- @long_description = ""
85
- self.maintainer(maintainer)
86
- self.maintainer_email(maintainer_email)
87
- self.license(license)
88
- self.description('A fabulous new cookbook')
89
- @platforms = Hashie::Mash.new
90
- @dependencies = Hashie::Mash.new
91
- @recommendations = Hashie::Mash.new
92
- @suggestions = Hashie::Mash.new
93
- @conflicting = Hashie::Mash.new
94
- @providing = Hashie::Mash.new
95
- @replacing = Hashie::Mash.new
96
- @attributes = Hashie::Mash.new
97
- @groupings = Hashie::Mash.new
98
- @recipes = Hashie::Mash.new
99
- @version = Solve::Version.new("0.0.0")
100
- if cookbook
101
- @recipes = cookbook.fully_qualified_recipe_names.inject({}) do |r, e|
102
- e = self.name if e =~ /::default$/
103
- r[e] = ""
104
- self.provides e
105
- r
106
- end
107
- end
108
- end
109
-
110
- def ==(other)
111
- COMPARISON_FIELDS.inject(true) do |equal_so_far, field|
112
- equal_so_far && other.respond_to?(field) && (other.send(field) == send(field))
113
- end
114
- end
115
-
116
- # Sets the cookbooks maintainer, or returns it.
117
- #
118
- # === Parameters
119
- # maintainer<String>:: The maintainers name
120
- #
121
- # === Returns
122
- # maintainer<String>:: Returns the current maintainer.
123
- def maintainer(arg = nil)
124
- set_or_return(
125
- :maintainer,
126
- arg,
127
- :kind_of => [ String ]
128
- )
129
- end
130
-
131
- # Sets the maintainers email address, or returns it.
132
- #
133
- # === Parameters
134
- # maintainer_email<String>:: The maintainers email address
135
- #
136
- # === Returns
137
- # maintainer_email<String>:: Returns the current maintainer email.
138
- def maintainer_email(arg = nil)
139
- set_or_return(
140
- :maintainer_email,
141
- arg,
142
- :kind_of => [ String ]
143
- )
144
- end
145
-
146
- # Sets the current license, or returns it.
147
- #
148
- # === Parameters
149
- # license<String>:: The current license.
150
- #
151
- # === Returns
152
- # license<String>:: Returns the current license
153
- def license(arg = nil)
154
- set_or_return(
155
- :license,
156
- arg,
157
- :kind_of => [ String ]
158
- )
159
- end
160
-
161
- # Sets the current description, or returns it. Should be short - one line only!
162
- #
163
- # === Parameters
164
- # description<String>:: The new description
165
- #
166
- # === Returns
167
- # description<String>:: Returns the description
168
- def description(arg = nil)
169
- set_or_return(
170
- :description,
171
- arg,
172
- :kind_of => [ String ]
173
- )
174
- end
175
-
176
- # Sets the current long description, or returns it. Might come from a README, say.
177
- #
178
- # === Parameters
179
- # long_description<String>:: The new long description
180
- #
181
- # === Returns
182
- # long_description<String>:: Returns the long description
183
- def long_description(arg = nil)
184
- set_or_return(
185
- :long_description,
186
- arg,
187
- :kind_of => [ String ]
188
- )
189
- end
190
-
191
- # Sets the current cookbook version, or returns it. Can be two or three digits, seperated
192
- # by dots. ie: '2.1', '1.5.4' or '0.9'.
193
- #
194
- # === Parameters
195
- # version<String>:: The curent version, as a string
196
- #
197
- # === Returns
198
- # version<String>:: Returns the current version
199
- def version(arg = nil)
200
- if arg
201
- @version = Solve::Version.new(arg)
202
- end
203
-
204
- @version.to_s
205
- end
206
-
207
- # Sets the name of the cookbook, or returns it.
208
- #
209
- # === Parameters
210
- # name<String>:: The curent cookbook name.
211
- #
212
- # === Returns
213
- # name<String>:: Returns the current cookbook name.
214
- def name(arg = nil)
215
- set_or_return(
216
- :name,
217
- arg,
218
- :kind_of => [ String ]
219
- )
220
- end
221
-
222
- # Adds a supported platform, with version checking strings.
223
- #
224
- # === Parameters
225
- # platform<String>,<Symbol>:: The platform (like :ubuntu or :mac_os_x)
226
- # version<String>:: A version constraint of the form "OP VERSION",
227
- # where OP is one of < <= = > >= ~> and VERSION has
228
- # the form x.y.z or x.y.
229
- #
230
- # === Returns
231
- # versions<Array>:: Returns the list of versions for the platform
232
- def supports(platform, *version_args)
233
- version = version_args.first
234
- @platforms[platform] = Solve::Constraint.new(version).to_s
235
- @platforms[platform]
236
- rescue Solve::Errors::InvalidConstraintFormat => ex
237
- raise InvalidVersionConstraint, ex.to_s
238
- end
239
-
240
- # Adds a dependency on another cookbook, with version checking strings.
241
- #
242
- # === Parameters
243
- # cookbook<String>:: The cookbook
244
- # version<String>:: A version constraint of the form "OP VERSION",
245
- # where OP is one of < <= = > >= ~> and VERSION has
246
- # the form x.y.z or x.y.
247
- #
248
- # === Returns
249
- # versions<Array>:: Returns the list of versions for the platform
250
- def depends(cookbook, *version_args)
251
- version = version_args.first
252
- @dependencies[cookbook] = Solve::Constraint.new(version).to_s
253
- @dependencies[cookbook]
254
- rescue Solve::Errors::InvalidConstraintFormat => ex
255
- raise InvalidVersionConstraint, ex.to_s
256
- end
257
-
258
- # Adds a recommendation for another cookbook, with version checking strings.
259
- #
260
- # === Parameters
261
- # cookbook<String>:: The cookbook
262
- # version<String>:: A version constraint of the form "OP VERSION",
263
- # where OP is one of < <= = > >= ~> and VERSION has
264
- # the form x.y.z or x.y.
265
- #
266
- # === Returns
267
- # versions<Array>:: Returns the list of versions for the platform
268
- def recommends(cookbook, *version_args)
269
- version = version_args.first
270
- @recommendations[cookbook] = Solve::Constraint.new(version).to_s
271
- @recommendations[cookbook]
272
- rescue Solve::Errors::InvalidConstraintFormat => ex
273
- raise InvalidVersionConstraint, ex.to_s
274
- end
275
-
276
- # Adds a suggestion for another cookbook, with version checking strings.
277
- #
278
- # === Parameters
279
- # cookbook<String>:: The cookbook
280
- # version<String>:: A version constraint of the form "OP VERSION",
281
- # where OP is one of < <= = > >= ~> and VERSION has the
282
- # formx.y.z or x.y.
283
- #
284
- # === Returns
285
- # versions<Array>:: Returns the list of versions for the platform
286
- def suggests(cookbook, *version_args)
287
- version = version_args.first
288
- @suggestions[cookbook] = Solve::Constraint.new(version).to_s
289
- @suggestions[cookbook]
290
- rescue Solve::Errors::InvalidConstraintFormat => ex
291
- raise InvalidVersionConstraint, ex.to_s
292
- end
293
-
294
- # Adds a conflict for another cookbook, with version checking strings.
295
- #
296
- # === Parameters
297
- # cookbook<String>:: The cookbook
298
- # version<String>:: A version constraint of the form "OP VERSION",
299
- # where OP is one of < <= = > >= ~> and VERSION has
300
- # the form x.y.z or x.y.
301
- #
302
- # === Returns
303
- # versions<Array>:: Returns the list of versions for the platform
304
- def conflicts(cookbook, *version_args)
305
- version = version_args.first
306
- @conflicting[cookbook] = Solve::Constraint.new(version).to_s
307
- @conflicting[cookbook]
308
- rescue Solve::Errors::InvalidConstraintFormat => ex
309
- raise InvalidVersionConstraint, ex.to_s
310
- end
311
-
312
- # Adds a recipe, definition, or resource provided by this cookbook.
313
- #
314
- # Recipes are specified as normal
315
- # Definitions are followed by (), and can include :params for prototyping
316
- # Resources are the stringified version (service[apache2])
317
- #
318
- # === Parameters
319
- # recipe, definition, resource<String>:: The thing we provide
320
- # version<String>:: A version constraint of the form "OP VERSION",
321
- # where OP is one of < <= = > >= ~> and VERSION has
322
- # the form x.y.z or x.y.
323
- #
324
- # === Returns
325
- # versions<Array>:: Returns the list of versions for the platform
326
- def provides(cookbook, *version_args)
327
- version = version_args.first
328
- @providing[cookbook] = Solve::Constraint.new(version).to_s
329
- @providing[cookbook]
330
- rescue Solve::Errors::InvalidConstraintFormat => ex
331
- raise InvalidVersionConstraint, ex.to_s
332
- end
333
-
334
- # Adds a cookbook that is replaced by this one, with version checking strings.
335
- #
336
- # === Parameters
337
- # cookbook<String>:: The cookbook we replace
338
- # version<String>:: A version constraint of the form "OP VERSION",
339
- # where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
340
- #
341
- # === Returns
342
- # versions<Array>:: Returns the list of versions for the platform
343
- def replaces(cookbook, *version_args)
344
- version = version_args.first
345
- @replacing[cookbook] = Solve::Constraint.new(version).to_s
346
- @replacing[cookbook]
347
- rescue Solve::Errors::InvalidConstraintFormat => ex
348
- raise InvalidVersionConstraint, ex.to_s
349
- end
350
-
351
- # Adds a description for a recipe.
352
- #
353
- # === Parameters
354
- # recipe<String>:: The recipe
355
- # description<String>:: The description of the recipe
356
- #
357
- # === Returns
358
- # description<String>:: Returns the current description
359
- def recipe(name, description)
360
- @recipes[name] = description
361
- end
362
-
363
- # Adds an attribute )hat a user needs to configure for this cookbook. Takes
364
- # a name (with the / notation for a nested attribute), followed by any of
365
- # these options
366
- #
367
- # display_name<String>:: What a UI should show for this attribute
368
- # description<String>:: A hint as to what this attr is for
369
- # choice<Array>:: An array of choices to present to the user.
370
- # calculated<Boolean>:: If true, the default value is calculated by the recipe and cannot be displayed.
371
- # type<String>:: "string" or "array" - default is "string" ("hash" is supported for backwards compatibility)
372
- # required<String>:: Whether this attr is 'required', 'recommended' or 'optional' - default 'optional' (true/false values also supported for backwards compatibility)
373
- # recipes<Array>:: An array of recipes which need this attr set.
374
- # default<String>,<Array>,<Hash>:: The default value
375
- #
376
- # === Parameters
377
- # name<String>:: The name of the attribute ('foo', or 'apache2/log_dir')
378
- # options<Hash>:: The description of the options
379
- #
380
- # === Returns
381
- # options<Hash>:: Returns the current options hash
382
- def attribute(name, options)
383
- validate(
384
- options,
385
- {
386
- :display_name => { :kind_of => String },
387
- :description => { :kind_of => String },
388
- :choice => { :kind_of => [ Array ], :default => [] },
389
- :calculated => { :equal_to => [ true, false ], :default => false },
390
- :type => { :equal_to => [ "string", "array", "hash", "symbol" ], :default => "string" },
391
- :required => { :equal_to => [ "required", "recommended", "optional", true, false ], :default => "optional" },
392
- :recipes => { :kind_of => [ Array ], :default => [] },
393
- :default => { :kind_of => [ String, Array, Hash ] }
394
- }
395
- )
396
- options[:required] = remap_required_attribute(options[:required]) unless options[:required].nil?
397
- validate_string_array(options[:choice])
398
- validate_calculated_default_rule(options)
399
- validate_choice_default_rule(options)
400
-
401
- @attributes[name] = options
402
- @attributes[name]
403
- end
404
-
405
- def grouping(name, options)
406
- validate(
407
- options,
408
- {
409
- :title => { :kind_of => String },
410
- :description => { :kind_of => String }
411
- }
412
- )
413
- @groupings[name] = options
414
- @groupings[name]
415
- end
416
-
417
- def to_hash
418
- {
419
- NAME => self.name,
420
- DESCRIPTION => self.description,
421
- LONG_DESCRIPTION => self.long_description,
422
- MAINTAINER => self.maintainer,
423
- MAINTAINER_EMAIL => self.maintainer_email,
424
- LICENSE => self.license,
425
- PLATFORMS => self.platforms,
426
- DEPENDENCIES => self.dependencies,
427
- RECOMMENDATIONS => self.recommendations,
428
- SUGGESTIONS => self.suggestions,
429
- CONFLICTING => self.conflicting,
430
- PROVIDING => self.providing,
431
- REPLACING => self.replacing,
432
- ATTRIBUTES => self.attributes,
433
- GROUPINGS => self.groupings,
434
- RECIPES => self.recipes,
435
- VERSION => self.version
436
- }
437
- end
438
-
439
- def from_hash(o)
440
- @name = o[NAME] if o.has_key?(NAME)
441
- @description = o[DESCRIPTION] if o.has_key?(DESCRIPTION)
442
- @long_description = o[LONG_DESCRIPTION] if o.has_key?(LONG_DESCRIPTION)
443
- @maintainer = o[MAINTAINER] if o.has_key?(MAINTAINER)
444
- @maintainer_email = o[MAINTAINER_EMAIL] if o.has_key?(MAINTAINER_EMAIL)
445
- @license = o[LICENSE] if o.has_key?(LICENSE)
446
- @platforms = o[PLATFORMS] if o.has_key?(PLATFORMS)
447
- @dependencies = handle_deprecated_constraints(o[DEPENDENCIES]) if o.has_key?(DEPENDENCIES)
448
- @recommendations = handle_deprecated_constraints(o[RECOMMENDATIONS]) if o.has_key?(RECOMMENDATIONS)
449
- @suggestions = handle_deprecated_constraints(o[SUGGESTIONS]) if o.has_key?(SUGGESTIONS)
450
- @conflicting = handle_deprecated_constraints(o[CONFLICTING]) if o.has_key?(CONFLICTING)
451
- @providing = o[PROVIDING] if o.has_key?(PROVIDING)
452
- @replacing = handle_deprecated_constraints(o[REPLACING]) if o.has_key?(REPLACING)
453
- @attributes = o[ATTRIBUTES] if o.has_key?(ATTRIBUTES)
454
- @groupings = o[GROUPINGS] if o.has_key?(GROUPINGS)
455
- @recipes = o[RECIPES] if o.has_key?(RECIPES)
456
- @version = o[VERSION] if o.has_key?(VERSION)
457
- self
458
- end
459
-
460
- def from_file(filepath)
461
- super
462
- rescue IOError => ex
463
- raise Berkshelf::CookbookNotFound, ex.to_s
464
- end
465
-
466
- private
467
-
468
- # Verify that the given array is an array of strings
469
- #
470
- # Raise an exception if the members of the array are not Strings
471
- #
472
- # === Parameters
473
- # arry<Array>:: An array to be validated
474
- def validate_string_array(arry)
475
- if arry.kind_of?(Array)
476
- arry.each do |choice|
477
- validate( {:choice => choice}, {:choice => {:kind_of => String}} )
478
- end
479
- end
480
- end
481
-
482
- # For backwards compatibility, remap Boolean values to String
483
- # true is mapped to "required"
484
- # false is mapped to "optional"
485
- #
486
- # === Parameters
487
- # required_attr<String><Boolean>:: The value of options[:required]
488
- #
489
- # === Returns
490
- # required_attr<String>:: "required", "recommended", or "optional"
491
- def remap_required_attribute(value)
492
- case value
493
- when true
494
- value = "required"
495
- when false
496
- value = "optional"
497
- end
498
- value
499
- end
500
-
501
- def validate_calculated_default_rule(options)
502
- calculated_conflict = ((options[:default].is_a?(Array) && !options[:default].empty?) ||
503
- (options[:default].is_a?(String) && !options[:default] != "")) &&
504
- options[:calculated] == true
505
- raise ArgumentError, "Default cannot be specified if calculated is true!" if calculated_conflict
506
- end
507
-
508
- def validate_choice_default_rule(options)
509
- return if !options[:choice].is_a?(Array) || options[:choice].empty?
510
-
511
- if options[:default].is_a?(String) && options[:default] != ""
512
- raise ArgumentError, "Default must be one of your choice values!" if options[:choice].index(options[:default]) == nil
513
- end
514
-
515
- if options[:default].is_a?(Array) && !options[:default].empty?
516
- options[:default].each do |val|
517
- raise ArgumentError, "Default values must be a subset of your choice values!" if options[:choice].index(val) == nil
518
- end
519
- end
520
- end
521
-
522
- # This method translates version constraint strings from
523
- # cookbooks with the old format.
524
- #
525
- # Before we began respecting version constraints, we allowed
526
- # multiple constraints to be placed on cookbooks, as well as the
527
- # << and >> operators, which are now just < and >. For
528
- # specifications with more than one constraint, we return an
529
- # empty array (otherwise, we're silently abiding only part of
530
- # the contract they have specified to us). If there is only one
531
- # constraint, we are replacing the old << and >> with the new <
532
- # and >.
533
- def handle_deprecated_constraints(specification)
534
- specification.inject(Hashie::Mash.new) do |acc, (cb, constraints)|
535
- constraints = Array(constraints)
536
- acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, '>').gsub(/<</, '<')
537
- acc
538
- end
539
- end
540
- end
541
-
542
- #== Chef::Cookbook::MinimalMetadata
543
- # MinimalMetadata is a duck type of Cookbook::Metadata, used
544
- # internally by Chef Server when determining the optimal set of
545
- # cookbooks for a node.
546
- #
547
- # MinimalMetadata objects typically contain only enough information
548
- # to solve the cookbook collection for a run list, but not enough to
549
- # generate the proper response
550
- class MinimalMetadata < Metadata
551
- def initialize(name, params)
552
- @name = name
553
- from_hash(params)
554
- end
555
- end
556
- end