chef 0.9.18 → 0.10.0.beta.0

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 (177) hide show
  1. data/README.rdoc +0 -3
  2. data/distro/arch/etc/rc.d/chef-server +0 -4
  3. data/distro/arch/etc/rc.d/chef-server-webui +0 -4
  4. data/distro/arch/etc/rc.d/chef-solr +0 -4
  5. data/distro/arch/etc/rc.d/chef-solr-indexer +0 -4
  6. data/lib/chef.rb +3 -3
  7. data/lib/chef/api_client.rb +1 -1
  8. data/lib/chef/application.rb +11 -1
  9. data/lib/chef/application/client.rb +18 -22
  10. data/lib/chef/application/knife.rb +28 -29
  11. data/lib/chef/application/solo.rb +14 -12
  12. data/lib/chef/client.rb +112 -54
  13. data/lib/chef/config.rb +4 -0
  14. data/lib/chef/cookbook/chefignore.rb +66 -0
  15. data/lib/chef/cookbook/cookbook_collection.rb +6 -5
  16. data/lib/chef/cookbook/cookbook_version_loader.rb +151 -0
  17. data/lib/chef/cookbook/file_system_file_vendor.rb +10 -8
  18. data/lib/chef/cookbook/metadata.rb +200 -108
  19. data/lib/chef/cookbook_loader.rb +39 -163
  20. data/lib/chef/cookbook_uploader.rb +100 -78
  21. data/lib/chef/cookbook_version.rb +92 -47
  22. data/lib/chef/cookbook_version_selector.rb +163 -0
  23. data/lib/chef/couchdb.rb +9 -1
  24. data/lib/chef/data_bag.rb +1 -1
  25. data/lib/chef/data_bag_item.rb +1 -1
  26. data/lib/chef/encrypted_data_bag_item.rb +126 -0
  27. data/lib/chef/environment.rb +386 -0
  28. data/lib/chef/exceptions.rb +82 -1
  29. data/lib/chef/index_queue/amqp_client.rb +15 -12
  30. data/lib/chef/index_queue/indexable.rb +38 -4
  31. data/lib/chef/json_compat.rb +3 -3
  32. data/lib/chef/knife.rb +97 -202
  33. data/lib/chef/knife/bootstrap.rb +27 -61
  34. data/lib/chef/knife/bootstrap/archlinux-gems.erb +4 -2
  35. data/lib/chef/knife/bootstrap/centos5-gems.erb +6 -15
  36. data/lib/chef/knife/bootstrap/fedora13-gems.erb +3 -4
  37. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
  38. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -5
  39. data/lib/chef/knife/client_bulk_delete.rb +6 -3
  40. data/lib/chef/knife/client_create.rb +13 -10
  41. data/lib/chef/knife/client_delete.rb +10 -7
  42. data/lib/chef/knife/client_edit.rb +9 -6
  43. data/lib/chef/knife/client_list.rb +8 -5
  44. data/lib/chef/knife/client_reregister.rb +9 -6
  45. data/lib/chef/knife/client_show.rb +9 -6
  46. data/lib/chef/knife/configure.rb +15 -19
  47. data/lib/chef/knife/configure_client.rb +4 -4
  48. data/lib/chef/knife/cookbook_bulk_delete.rb +11 -8
  49. data/lib/chef/knife/cookbook_create.rb +120 -55
  50. data/lib/chef/knife/cookbook_delete.rb +18 -12
  51. data/lib/chef/knife/cookbook_download.rb +10 -6
  52. data/lib/chef/knife/cookbook_list.rb +15 -6
  53. data/lib/chef/knife/cookbook_metadata.rb +41 -21
  54. data/lib/chef/knife/cookbook_metadata_from_file.rb +4 -0
  55. data/lib/chef/knife/cookbook_show.rb +16 -5
  56. data/lib/chef/knife/cookbook_site_download.rb +2 -2
  57. data/lib/chef/knife/cookbook_site_share.rb +18 -13
  58. data/lib/chef/knife/cookbook_site_unshare.rb +7 -4
  59. data/lib/chef/knife/cookbook_site_vendor.rb +21 -18
  60. data/lib/chef/knife/cookbook_test.rb +14 -14
  61. data/lib/chef/knife/cookbook_upload.rb +91 -40
  62. data/lib/chef/knife/data_bag_create.rb +41 -6
  63. data/lib/chef/knife/data_bag_delete.rb +5 -3
  64. data/lib/chef/knife/data_bag_edit.rb +55 -11
  65. data/lib/chef/knife/data_bag_from_file.rb +47 -7
  66. data/lib/chef/knife/data_bag_list.rb +4 -1
  67. data/lib/chef/knife/data_bag_show.rb +44 -4
  68. data/lib/chef/knife/environment_create.rb +53 -0
  69. data/lib/chef/knife/environment_delete.rb +45 -0
  70. data/lib/chef/knife/environment_edit.rb +45 -0
  71. data/lib/chef/knife/environment_from_file.rb +39 -0
  72. data/lib/chef/knife/environment_list.rb +42 -0
  73. data/lib/chef/knife/environment_show.rb +46 -0
  74. data/lib/chef/knife/exec.rb +1 -1
  75. data/lib/chef/knife/index_rebuild.rb +8 -9
  76. data/lib/chef/knife/node_bulk_delete.rb +9 -6
  77. data/lib/chef/knife/node_create.rb +9 -6
  78. data/lib/chef/knife/node_delete.rb +10 -7
  79. data/lib/chef/knife/node_edit.rb +129 -10
  80. data/lib/chef/knife/node_from_file.rb +10 -7
  81. data/lib/chef/knife/node_list.rb +11 -6
  82. data/lib/chef/knife/node_run_list_add.rb +10 -7
  83. data/lib/chef/knife/node_run_list_remove.rb +9 -6
  84. data/lib/chef/knife/node_show.rb +15 -7
  85. data/lib/chef/knife/recipe_list.rb +4 -3
  86. data/lib/chef/knife/role_bulk_delete.rb +9 -6
  87. data/lib/chef/knife/role_create.rb +9 -6
  88. data/lib/chef/knife/role_delete.rb +10 -7
  89. data/lib/chef/knife/role_edit.rb +11 -8
  90. data/lib/chef/knife/role_from_file.rb +10 -7
  91. data/lib/chef/knife/role_list.rb +8 -5
  92. data/lib/chef/knife/role_show.rb +11 -8
  93. data/lib/chef/knife/search.rb +33 -10
  94. data/lib/chef/knife/ssh.rb +33 -61
  95. data/lib/chef/knife/status.rb +7 -4
  96. data/lib/chef/knife/subcommand_loader.rb +101 -0
  97. data/lib/chef/knife/tag_create.rb +31 -0
  98. data/lib/chef/knife/tag_delete.rb +31 -0
  99. data/lib/chef/knife/tag_list.rb +29 -0
  100. data/lib/chef/knife/ui.rb +229 -0
  101. data/lib/chef/knife/windows_bootstrap.rb +8 -5
  102. data/lib/chef/log.rb +5 -59
  103. data/lib/chef/mash.rb +211 -0
  104. data/lib/chef/mixins.rb +1 -2
  105. data/lib/chef/nil_argument.rb +3 -0
  106. data/lib/chef/node.rb +96 -34
  107. data/lib/chef/platform.rb +27 -0
  108. data/lib/chef/provider/cookbook_file.rb +21 -20
  109. data/lib/chef/provider/deploy/revision.rb +3 -0
  110. data/lib/chef/provider/file.rb +20 -11
  111. data/lib/chef/provider/git.rb +26 -26
  112. data/lib/chef/provider/group/aix.rb +70 -0
  113. data/lib/chef/provider/group/groupadd.rb +7 -4
  114. data/lib/chef/provider/group/usermod.rb +1 -1
  115. data/lib/chef/provider/package.rb +28 -28
  116. data/lib/chef/provider/package/dpkg.rb +1 -1
  117. data/lib/chef/provider/package/portage.rb +50 -39
  118. data/lib/chef/provider/package/rubygems.rb +1 -1
  119. data/lib/chef/provider/package/zypper.rb +3 -20
  120. data/lib/chef/provider/remote_directory.rb +0 -2
  121. data/lib/chef/provider/remote_file.rb +2 -3
  122. data/lib/chef/provider/service/arch.rb +28 -35
  123. data/lib/chef/provider/service/simple.rb +1 -1
  124. data/lib/chef/provider/subversion.rb +22 -22
  125. data/lib/chef/providers.rb +1 -0
  126. data/lib/chef/recipe.rb +10 -12
  127. data/lib/chef/resource.rb +49 -42
  128. data/lib/chef/resource/gem_package.rb +7 -3
  129. data/lib/chef/resource/git.rb +5 -5
  130. data/lib/chef/resource/package.rb +7 -7
  131. data/lib/chef/resource/scm.rb +2 -1
  132. data/lib/chef/resource/solaris_package.rb +0 -1
  133. data/lib/chef/resource/yum_package.rb +0 -1
  134. data/lib/chef/rest.rb +7 -16
  135. data/lib/chef/rest/rest_request.rb +0 -16
  136. data/lib/chef/role.rb +67 -13
  137. data/lib/chef/run_context.rb +37 -21
  138. data/lib/chef/run_list.rb +30 -15
  139. data/lib/chef/run_list/run_list_expansion.rb +41 -20
  140. data/lib/chef/run_list/run_list_item.rb +20 -6
  141. data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
  142. data/lib/chef/runner.rb +7 -15
  143. data/lib/chef/search/query.rb +12 -7
  144. data/lib/chef/shef.rb +6 -7
  145. data/lib/chef/shef/shef_session.rb +40 -35
  146. data/lib/chef/shell_out.rb +22 -201
  147. data/lib/chef/shell_out/unix.rb +224 -0
  148. data/lib/chef/shell_out/windows.rb +95 -0
  149. data/lib/chef/solr_query.rb +187 -0
  150. data/lib/chef/solr_query/lucene.treetop +145 -0
  151. data/lib/chef/solr_query/lucene_nodes.rb +285 -0
  152. data/lib/chef/solr_query/query_transform.rb +65 -0
  153. data/lib/chef/solr_query/solr_http_request.rb +118 -0
  154. data/lib/chef/version.rb +4 -2
  155. data/lib/chef/version_class.rb +70 -0
  156. data/lib/chef/version_constraint.rb +116 -0
  157. metadata +68 -37
  158. data/lib/chef/cookbook/metadata/version.rb +0 -87
  159. data/lib/chef/knife/bluebox_images_list.rb +0 -54
  160. data/lib/chef/knife/bluebox_server_create.rb +0 -157
  161. data/lib/chef/knife/bluebox_server_delete.rb +0 -63
  162. data/lib/chef/knife/bluebox_server_list.rb +0 -59
  163. data/lib/chef/knife/ec2_instance_data.rb +0 -46
  164. data/lib/chef/knife/ec2_server_create.rb +0 -218
  165. data/lib/chef/knife/ec2_server_delete.rb +0 -87
  166. data/lib/chef/knife/ec2_server_list.rb +0 -89
  167. data/lib/chef/knife/rackspace_server_create.rb +0 -184
  168. data/lib/chef/knife/rackspace_server_delete.rb +0 -57
  169. data/lib/chef/knife/rackspace_server_list.rb +0 -59
  170. data/lib/chef/knife/slicehost_images_list.rb +0 -53
  171. data/lib/chef/knife/slicehost_server_create.rb +0 -103
  172. data/lib/chef/knife/slicehost_server_delete.rb +0 -61
  173. data/lib/chef/knife/slicehost_server_list.rb +0 -64
  174. data/lib/chef/knife/terremark_server_create.rb +0 -152
  175. data/lib/chef/knife/terremark_server_delete.rb +0 -87
  176. data/lib/chef/knife/terremark_server_list.rb +0 -77
  177. data/lib/chef/mixin/find_preferred_file.rb +0 -92
@@ -7,9 +7,9 @@
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
8
8
  # you may not use this file except in compliance with the License.
9
9
  # You may obtain a copy of the License at
10
- #
10
+ #
11
11
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
12
+ #
13
13
  # Unless required by applicable law or agreed to in writing, software
14
14
  # distributed under the License is distributed on an "AS IS" BASIS,
15
15
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -30,25 +30,27 @@ class Chef
30
30
  # locations, since in the chef-client case, that information is
31
31
  # non-sensical.
32
32
  class FileSystemFileVendor < FileVendor
33
-
34
- def initialize(manifest)
33
+
34
+ def initialize(manifest, *repo_paths)
35
35
  @cookbook_name = manifest[:cookbook_name]
36
+ @repo_paths = repo_paths.flatten
37
+ raise ArgumentError, "You must specify at least one repo path" if @repo_paths.empty?
36
38
  end
37
-
39
+
38
40
  # Implements abstract base's requirement. It looks in the
39
41
  # Chef::Config.cookbook_path file hierarchy for the requested
40
42
  # file.
41
43
  def get_filename(filename)
42
- location = Array(Chef::Config.cookbook_path).inject(nil) do |memo, basepath|
44
+ location = @repo_paths.inject(nil) do |memo, basepath|
43
45
  candidate_location = File.join(basepath, @cookbook_name, filename)
44
46
  memo = candidate_location if File.exist?(candidate_location)
45
47
  memo
46
48
  end
47
49
  raise "File #{filename} does not exist for cookbook #{@cookbook_name}" unless location
48
-
50
+
49
51
  location
50
52
  end
51
-
53
+
52
54
  end
53
55
  end
54
56
  end
@@ -1,15 +1,16 @@
1
1
  #
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: AJ Christensen (<aj@opscode.com>)
4
- # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # Author:: Seth Falcon (<seth@opscode.com>)
5
+ # Copyright:: Copyright 2008-2010 Opscode, Inc.
5
6
  # License:: Apache License, Version 2.0
6
7
  #
7
8
  # Licensed under the Apache License, Version 2.0 (the "License");
8
9
  # you may not use this file except in compliance with the License.
9
10
  # You may obtain a copy of the License at
10
- #
11
+ #
11
12
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
+ #
13
14
  # Unless required by applicable law or agreed to in writing, software
14
15
  # distributed under the License is distributed on an "AS IS" BASIS,
15
16
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +22,8 @@ require 'chef/mixin/from_file'
21
22
  require 'chef/mixin/params_validate'
22
23
  require 'chef/mixin/check_helper'
23
24
  require 'chef/log'
24
- require 'chef/cookbook/metadata/version'
25
+ require 'chef/version_class'
26
+ require 'chef/version_constraint'
25
27
 
26
28
  class Chef
27
29
  class Cookbook
@@ -34,12 +36,19 @@ class Chef
34
36
  :maintainer_email, :license, :platforms, :dependencies,
35
37
  :recommendations, :suggestions, :conflicting, :providing,
36
38
  :replacing, :attributes, :groupings, :recipes, :version]
37
-
39
+
40
+ VERSION_CONSTRAINTS = {:depends => "dependencies",
41
+ :recommends => "recommendations",
42
+ :suggests => "suggestions",
43
+ :conflicts => "conflicting",
44
+ :provides => "providing",
45
+ :replaces => "replacing" }
46
+
38
47
  include Chef::Mixin::CheckHelper
39
48
  include Chef::Mixin::ParamsValidate
40
49
  include Chef::Mixin::FromFile
41
50
 
42
- attr_reader :cookbook,
51
+ attr_reader :cookbook,
43
52
  :platforms,
44
53
  :dependencies,
45
54
  :recommendations,
@@ -53,7 +62,7 @@ class Chef
53
62
  :version
54
63
 
55
64
  # Builds a new Chef::Cookbook::Metadata object.
56
- #
65
+ #
57
66
  # === Parameters
58
67
  # cookbook<String>:: An optional cookbook object
59
68
  # maintainer<String>:: An optional maintainer
@@ -64,7 +73,7 @@ class Chef
64
73
  # metadata<Chef::Cookbook::Metadata>
65
74
  def initialize(cookbook=nil, maintainer='Your Name', maintainer_email='youremail@example.com', license='Apache v2.0')
66
75
  @cookbook = cookbook
67
- @name = cookbook ? cookbook.name : ""
76
+ @name = cookbook ? cookbook.name : ""
68
77
  @long_description = ""
69
78
  self.maintainer(maintainer)
70
79
  self.maintainer_email(maintainer_email)
@@ -82,8 +91,8 @@ class Chef
82
91
  @recipes = Mash.new
83
92
  @version = Version.new "0.0.0"
84
93
  if cookbook
85
- @recipes = cookbook.fully_qualified_recipe_names.inject({}) do |r, e|
86
- e = self.name if e =~ /::default$/
94
+ @recipes = cookbook.fully_qualified_recipe_names.inject({}) do |r, e|
95
+ e = self.name if e =~ /::default$/
87
96
  r[e] = ""
88
97
  self.provides e
89
98
  r
@@ -115,7 +124,7 @@ class Chef
115
124
  # Sets the maintainers email address, or returns it.
116
125
  #
117
126
  # === Parameters
118
- # maintainer_email<String>:: The maintainers email address
127
+ # maintainer_email<String>:: The maintainers email address
119
128
  #
120
129
  # === Returns
121
130
  # maintainer_email<String>:: Returns the current maintainer email.
@@ -133,7 +142,7 @@ class Chef
133
142
  # license<String>:: The current license.
134
143
  #
135
144
  # === Returns
136
- # license<String>:: Returns the current license
145
+ # license<String>:: Returns the current license
137
146
  def license(arg=nil)
138
147
  set_or_return(
139
148
  :license,
@@ -145,10 +154,10 @@ class Chef
145
154
  # Sets the current description, or returns it. Should be short - one line only!
146
155
  #
147
156
  # === Parameters
148
- # description<String>:: The new description
157
+ # description<String>:: The new description
149
158
  #
150
159
  # === Returns
151
- # description<String>:: Returns the description
160
+ # description<String>:: Returns the description
152
161
  def description(arg=nil)
153
162
  set_or_return(
154
163
  :description,
@@ -157,13 +166,13 @@ class Chef
157
166
  )
158
167
  end
159
168
 
160
- # Sets the current long description, or returns it. Might come from a README, say.
169
+ # Sets the current long description, or returns it. Might come from a README, say.
161
170
  #
162
171
  # === Parameters
163
172
  # long_description<String>:: The new long description
164
173
  #
165
174
  # === Returns
166
- # long_description<String>:: Returns the long description
175
+ # long_description<String>:: Returns the long description
167
176
  def long_description(arg=nil)
168
177
  set_or_return(
169
178
  :long_description,
@@ -179,10 +188,10 @@ class Chef
179
188
  # version<String>:: The curent version, as a string
180
189
  #
181
190
  # === Returns
182
- # version<String>:: Returns the current version
191
+ # version<String>:: Returns the current version
183
192
  def version(arg=nil)
184
193
  if arg
185
- @version = Version.new(arg)
194
+ @version = Chef::Version.new(arg)
186
195
  end
187
196
 
188
197
  @version.to_s
@@ -191,10 +200,10 @@ class Chef
191
200
  # Sets the name of the cookbook, or returns it.
192
201
  #
193
202
  # === Parameters
194
- # name<String>:: The curent cookbook name.
203
+ # name<String>:: The curent cookbook name.
195
204
  #
196
205
  # === Returns
197
- # name<String>:: Returns the current cookbook name.
206
+ # name<String>:: Returns the current cookbook name.
198
207
  def name(arg=nil)
199
208
  set_or_return(
200
209
  :name,
@@ -203,121 +212,141 @@ class Chef
203
212
  )
204
213
  end
205
214
 
206
- # Adds a supported platform, with version checking strings.
215
+ # Adds a supported platform, with version checking strings.
207
216
  #
208
217
  # === Parameters
209
218
  # platform<String>,<Symbol>:: The platform (like :ubuntu or :mac_os_x)
210
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
219
+ # version<String>:: A version constraint of the form "OP VERSION",
220
+ # where OP is one of < <= = > >= ~> and VERSION has
221
+ # the form x.y.z or x.y.
211
222
  #
212
223
  # === Returns
213
- # versions<Array>:: Returns the list of versions for the platform
214
- def supports(platform, *versions)
215
- versions.each { |v| _check_version_expression(v) }
216
- @platforms[platform] = versions
224
+ # versions<Array>:: Returns the list of versions for the platform
225
+ def supports(platform, *version_args)
226
+ version = new_args_format(:supports, platform, version_args)
227
+ validate_version_constraint(:supports, platform, version)
228
+ @platforms[platform] = version
217
229
  @platforms[platform]
218
230
  end
219
231
 
220
232
  # Adds a dependency on another cookbook, with version checking strings.
221
233
  #
222
234
  # === Parameters
223
- # cookbook<String>:: The cookbook
224
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
235
+ # cookbook<String>:: The cookbook
236
+ # version<String>:: A version constraint of the form "OP VERSION",
237
+ # where OP is one of < <= = > >= ~> and VERSION has
238
+ # the form x.y.z or x.y.
225
239
  #
226
240
  # === Returns
227
- # versions<Array>:: Returns the list of versions for the platform
228
- def depends(cookbook, *versions)
229
- versions.each { |v| _check_version_expression(v) }
230
- @dependencies[cookbook] = versions
241
+ # versions<Array>:: Returns the list of versions for the platform
242
+ def depends(cookbook, *version_args)
243
+ version = new_args_format(:depends, cookbook, version_args)
244
+ validate_version_constraint(:depends, cookbook, version)
245
+ @dependencies[cookbook] = version
231
246
  @dependencies[cookbook]
232
247
  end
233
248
 
234
249
  # Adds a recommendation for another cookbook, with version checking strings.
235
250
  #
236
251
  # === Parameters
237
- # cookbook<String>:: The cookbook
238
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
252
+ # cookbook<String>:: The cookbook
253
+ # version<String>:: A version constraint of the form "OP VERSION",
254
+ # where OP is one of < <= = > >= ~> and VERSION has
255
+ # the form x.y.z or x.y.
239
256
  #
240
257
  # === Returns
241
- # versions<Array>:: Returns the list of versions for the platform
242
- def recommends(cookbook, *versions)
243
- versions.each { |v| _check_version_expression(v) }
244
- @recommendations[cookbook] = versions
258
+ # versions<Array>:: Returns the list of versions for the platform
259
+ def recommends(cookbook, *version_args)
260
+ version = new_args_format(:recommends, cookbook, version_args)
261
+ validate_version_constraint(:recommends, cookbook, version)
262
+ @recommendations[cookbook] = version
245
263
  @recommendations[cookbook]
246
264
  end
247
265
 
248
266
  # Adds a suggestion for another cookbook, with version checking strings.
249
267
  #
250
268
  # === Parameters
251
- # cookbook<String>:: The cookbook
252
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
269
+ # cookbook<String>:: The cookbook
270
+ # version<String>:: A version constraint of the form "OP VERSION",
271
+ # where OP is one of < <= = > >= ~> and VERSION has the
272
+ # formx.y.z or x.y.
253
273
  #
254
274
  # === Returns
255
- # versions<Array>:: Returns the list of versions for the platform
256
- def suggests(cookbook, *versions)
257
- versions.each { |v| _check_version_expression(v) }
258
- @suggestions[cookbook] = versions
259
- @suggestions[cookbook]
275
+ # versions<Array>:: Returns the list of versions for the platform
276
+ def suggests(cookbook, *version_args)
277
+ version = new_args_format(:suggests, cookbook, version_args)
278
+ validate_version_constraint(:suggests, cookbook, version)
279
+ @suggestions[cookbook] = version
280
+ @suggestions[cookbook]
260
281
  end
261
282
 
262
283
  # Adds a conflict for another cookbook, with version checking strings.
263
284
  #
264
285
  # === Parameters
265
- # cookbook<String>:: The cookbook
266
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
286
+ # cookbook<String>:: The cookbook
287
+ # version<String>:: A version constraint of the form "OP VERSION",
288
+ # where OP is one of < <= = > >= ~> and VERSION has
289
+ # the form x.y.z or x.y.
267
290
  #
268
291
  # === Returns
269
- # versions<Array>:: Returns the list of versions for the platform
270
- def conflicts(cookbook, *versions)
271
- versions.each { |v| _check_version_expression(v) }
272
- @conflicting[cookbook] = versions
273
- @conflicting[cookbook]
292
+ # versions<Array>:: Returns the list of versions for the platform
293
+ def conflicts(cookbook, *version_args)
294
+ version = new_args_format(:conflicts, cookbook, version_args)
295
+ validate_version_constraint(:conflicts, cookbook, version)
296
+ @conflicting[cookbook] = version
297
+ @conflicting[cookbook]
274
298
  end
275
299
 
276
- # Adds a recipe, definition, or resource provided by this cookbook.
300
+ # Adds a recipe, definition, or resource provided by this cookbook.
277
301
  #
278
302
  # Recipes are specified as normal
279
303
  # Definitions are followed by (), and can include :params for prototyping
280
304
  # Resources are the stringified version (service[apache2])
281
305
  #
282
306
  # === Parameters
283
- # recipe, definition, resource<String>:: The thing we provide
284
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
307
+ # recipe, definition, resource<String>:: The thing we provide
308
+ # version<String>:: A version constraint of the form "OP VERSION",
309
+ # where OP is one of < <= = > >= ~> and VERSION has
310
+ # the form x.y.z or x.y.
285
311
  #
286
312
  # === Returns
287
- # versions<Array>:: Returns the list of versions for the platform
288
- def provides(cookbook, *versions)
289
- versions.each { |v| _check_version_expression(v) }
290
- @providing[cookbook] = versions
291
- @providing[cookbook]
313
+ # versions<Array>:: Returns the list of versions for the platform
314
+ def provides(cookbook, *version_args)
315
+ version = new_args_format(:provides, cookbook, version_args)
316
+ validate_version_constraint(:provides, cookbook, version)
317
+ @providing[cookbook] = version
318
+ @providing[cookbook]
292
319
  end
293
320
 
294
321
  # Adds a cookbook that is replaced by this one, with version checking strings.
295
322
  #
296
323
  # === Parameters
297
- # cookbook<String>:: The cookbook we replace
298
- # *versions<String>:: A list of versions matching << <= = >= >> followed by a version.
324
+ # cookbook<String>:: The cookbook we replace
325
+ # version<String>:: A version constraint of the form "OP VERSION",
326
+ # where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
299
327
  #
300
328
  # === Returns
301
- # versions<Array>:: Returns the list of versions for the platform
302
- def replaces(cookbook, *versions)
303
- versions.each { |v| _check_version_expression(v) }
304
- @replacing[cookbook] = versions
305
- @replacing[cookbook]
329
+ # versions<Array>:: Returns the list of versions for the platform
330
+ def replaces(cookbook, *version_args)
331
+ version = new_args_format(:replaces, cookbook, version_args)
332
+ validate_version_constraint(:replaces, cookbook, version)
333
+ @replacing[cookbook] = version
334
+ @replacing[cookbook]
306
335
  end
307
336
 
308
- # Adds a description for a recipe.
337
+ # Adds a description for a recipe.
309
338
  #
310
339
  # === Parameters
311
340
  # recipe<String>:: The recipe
312
341
  # description<String>:: The description of the recipe
313
342
  #
314
343
  # === Returns
315
- # description<String>:: Returns the current description
344
+ # description<String>:: Returns the current description
316
345
  def recipe(name, description)
317
- @recipes[name] = description
346
+ @recipes[name] = description
318
347
  end
319
348
 
320
- # Adds an attribute that a user needs to configure for this cookbook. Takes
349
+ # Adds an attribute )hat a user needs to configure for this cookbook. Takes
321
350
  # a name (with the / notation for a nested attribute), followed by any of
322
351
  # these options
323
352
  #
@@ -331,11 +360,11 @@ class Chef
331
360
  # default<String>,<Array>,<Hash>:: The default value
332
361
  #
333
362
  # === Parameters
334
- # name<String>:: The name of the attribute ('foo', or 'apache2/log_dir')
335
- # options<Hash>:: The description of the options
363
+ # name<String>:: The name of the attribute ('foo', or 'apache2/log_dir')
364
+ # options<Hash>:: The description of the options
336
365
  #
337
366
  # === Returns
338
- # options<Hash>:: Returns the current options hash
367
+ # options<Hash>:: Returns the current options hash
339
368
  def attribute(name, options)
340
369
  validate(
341
370
  options,
@@ -355,7 +384,7 @@ class Chef
355
384
  validate_calculated_default_rule(options)
356
385
  validate_choice_default_rule(options)
357
386
 
358
- @attributes[name] = options
387
+ @attributes[name] = options
359
388
  @attributes[name]
360
389
  end
361
390
 
@@ -367,43 +396,38 @@ class Chef
367
396
  :description => { :kind_of => String }
368
397
  }
369
398
  )
370
- @groupings[name] = options
399
+ @groupings[name] = options
371
400
  @groupings[name]
372
401
  end
373
402
 
374
- def _check_version_expression(version_string)
375
- if version_string =~ /^(>>|>=|=|<=|<<) (.+)$/
376
- [ $1, $2 ]
377
- else
378
- raise ArgumentError, "Version expression #{version_string} is invalid!"
379
- end
403
+ def to_hash
404
+ {
405
+ 'name' => self.name,
406
+ 'description' => self.description,
407
+ 'long_description' => self.long_description,
408
+ 'maintainer' => self.maintainer,
409
+ 'maintainer_email' => self.maintainer_email,
410
+ 'license' => self.license,
411
+ 'platforms' => self.platforms,
412
+ 'dependencies' => self.dependencies,
413
+ 'recommendations' => self.recommendations,
414
+ 'suggestions' => self.suggestions,
415
+ 'conflicting' => self.conflicting,
416
+ 'providing' => self.providing,
417
+ 'replacing' => self.replacing,
418
+ 'attributes' => self.attributes,
419
+ 'groupings' => self.groupings,
420
+ 'recipes' => self.recipes,
421
+ 'version' => self.version
422
+ }
380
423
  end
381
424
 
382
425
  def to_json(*a)
383
- result = {
384
- :name => self.name,
385
- :description => self.description,
386
- :long_description => self.long_description,
387
- :maintainer => self.maintainer,
388
- :maintainer_email => self.maintainer_email,
389
- :license => self.license,
390
- :platforms => self.platforms,
391
- :dependencies => self.dependencies,
392
- :recommendations => self.recommendations,
393
- :suggestions => self.suggestions,
394
- :conflicting => self.conflicting,
395
- :providing => self.providing,
396
- :replacing => self.replacing,
397
- :attributes => self.attributes,
398
- :groupings => self.groupings,
399
- :recipes => self.recipes,
400
- :version => self.version
401
- }
402
- result.to_json(*a)
426
+ self.to_hash.to_json(*a)
403
427
  end
404
428
 
405
429
  def self.from_hash(o)
406
- cm = self.new()
430
+ cm = self.new()
407
431
  cm.from_hash(o)
408
432
  cm
409
433
  end
@@ -416,12 +440,12 @@ class Chef
416
440
  @maintainer_email = o['maintainer_email'] if o.has_key?('maintainer_email')
417
441
  @license = o['license'] if o.has_key?('license')
418
442
  @platforms = o['platforms'] if o.has_key?('platforms')
419
- @dependencies = o['dependencies'] if o.has_key?('dependencies')
420
- @recommendations = o['recommendations'] if o.has_key?('recommendations')
421
- @suggestions = o['suggestions'] if o.has_key?('suggestions')
422
- @conflicting = o['conflicting'] if o.has_key?('conflicting')
443
+ @dependencies = handle_deprecated_constraints(o['dependencies']) if o.has_key?('dependencies')
444
+ @recommendations = handle_deprecated_constraints(o['recommendations']) if o.has_key?('recommendations')
445
+ @suggestions = handle_deprecated_constraints(o['suggestions']) if o.has_key?('suggestions')
446
+ @conflicting = handle_deprecated_constraints(o['conflicting']) if o.has_key?('conflicting')
423
447
  @providing = o['providing'] if o.has_key?('providing')
424
- @replacing = o['replacing'] if o.has_key?('replacing')
448
+ @replacing = handle_deprecated_constraints(o['replacing']) if o.has_key?('replacing')
425
449
  @attributes = o['attributes'] if o.has_key?('attributes')
426
450
  @groupings = o['groupings'] if o.has_key?('groupings')
427
451
  @recipes = o['recipes'] if o.has_key?('recipes')
@@ -434,6 +458,19 @@ class Chef
434
458
  self.from_hash(o)
435
459
  end
436
460
 
461
+ def self.validate_json(json_str)
462
+ o = Chef::JSONCompat.from_json(json_str)
463
+ metadata = new()
464
+ VERSION_CONSTRAINTS.each do |method_name, hash_key|
465
+ if constraints = o[hash_key]
466
+ constraints.each do |cb_name, constraints|
467
+ metadata.send(method_name, cb_name, *Array(constraints))
468
+ end
469
+ end
470
+ end
471
+ true
472
+ end
473
+
437
474
  def from_json(string)
438
475
  o = Chef::JSONCompat.from_json(string)
439
476
  from_hash(o)
@@ -441,6 +478,42 @@ class Chef
441
478
 
442
479
  private
443
480
 
481
+ def new_args_format(caller_name, dep_name, version_constraints)
482
+ if version_constraints.empty?
483
+ ">= 0.0.0"
484
+ elsif version_constraints.size == 1
485
+ version_constraints.first
486
+ else
487
+ msg=<<-OBSOLETED
488
+ The dependency specification syntax you are using is no longer valid. You may not
489
+ specify more than one version constraint for a particular cookbook.
490
+ Consult http://wiki.opscode.com/display/chef/Metadata for the updated syntax.
491
+
492
+ Called by: #{caller_name} '#{dep_name}', #{version_constraints.map {|vc| vc.inspect}.join(", ")}
493
+ Called from:
494
+ #{caller[0...5].map {|line| " " + line}.join("\n")}
495
+ OBSOLETED
496
+ raise Exceptions::ObsoleteDependencySyntax, msg
497
+ end
498
+ end
499
+
500
+ def validate_version_constraint(caller_name, dep_name, constraint_str)
501
+ Chef::VersionConstraint.new(constraint_str)
502
+ rescue Chef::Exceptions::InvalidVersionConstraint => e
503
+ Log.debug(e)
504
+
505
+ msg=<<-INVALID
506
+ The version constraint syntax you are using is not valid. If you recently
507
+ upgraded to Chef 0.10.0, be aware that you no may longer use "<<" and ">>" for
508
+ 'less than' and 'greater than'; use '<' and '>' instead.
509
+ Consult http://wiki.opscode.com/display/chef/Metadata for more information.
510
+
511
+ Called by: #{caller_name} '#{dep_name}', '#{constraint_str}'
512
+ Called from:
513
+ #{caller[0...5].map {|line| " " + line}.join("\n")}
514
+ INVALID
515
+ raise Exceptions::InvalidVersionConstraint, msg
516
+ end
444
517
  # Verify that the given array is an array of strings
445
518
  #
446
519
  # Raise an exception if the members of the array are not Strings
@@ -495,6 +568,25 @@ class Chef
495
568
  end
496
569
  end
497
570
 
571
+ # This method translates version constraint strings from
572
+ # cookbooks with the old format.
573
+ #
574
+ # Before we began respecting version constraints, we allowed
575
+ # multiple constraints to be placed on cookbooks, as well as the
576
+ # << and >> operators, which are now just < and >. For
577
+ # specifications with more than one constraint, we return an
578
+ # empty array (otherwise, we're silently abiding only part of
579
+ # the contract they have specified to us). If there is only one
580
+ # constraint, we are replacing the old << and >> with the new <
581
+ # and >.
582
+ def handle_deprecated_constraints(specification)
583
+ specification.inject(Mash.new) do |acc, (cb, constraints)|
584
+ constraints = Array(constraints)
585
+ acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, '>').gsub(/<</, '<')
586
+ acc
587
+ end
588
+ end
589
+
498
590
  end
499
591
  end
500
592
  end