berkshelf 1.2.0.rc1 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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