class Chef::Cookbook::Metadata
Chef::Cookbook::Metadata¶ ↑
Chef::Cookbook::Metadata provides a convenient DSL for declaring metadata about Chef Cookbooks.
Constants
- ATTRIBUTES
- COMPARISON_FIELDS
- CONFLICTING
- DEPENDENCIES
- DESCRIPTION
- GROUPINGS
- LICENSE
- LONG_DESCRIPTION
- MAINTAINER
- MAINTAINER_EMAIL
- NAME
- PLATFORMS
- PROVIDING
- RECIPES
- RECOMMENDATIONS
- REPLACING
- SUGGESTIONS
- VERSION
- VERSION_CONSTRAINTS
Attributes
Public Class Methods
# File lib/chef/cookbook/metadata.rb, line 447 def self.from_hash(o) cm = self.new() cm.from_hash(o) cm end
# File lib/chef/cookbook/metadata.rb, line 474 def self.from_json(string) o = Chef::JSONCompat.from_json(string) self.from_hash(o) end
Builds a new Chef::Cookbook::Metadata object.
Parameters¶ ↑
- cookbook<String>
-
An optional cookbook object
- maintainer<String>
-
An optional maintainer
- #maintainer_email<String>
-
An optional maintainer email
license<String>::An optional license. Default is Apache v2.0
Returns¶ ↑
metadata<Chef::Cookbook::Metadata>
# File lib/chef/cookbook/metadata.rb, line 92 def initialize(cookbook=nil, maintainer='YOUR_COMPANY_NAME', maintainer_email='YOUR_EMAIL', license='none') @cookbook = cookbook @name = cookbook ? cookbook.name : "" @long_description = "" self.maintainer(maintainer) self.maintainer_email(maintainer_email) self.license(license) self.description('A fabulous new cookbook') @platforms = Mash.new @dependencies = Mash.new @recommendations = Mash.new @suggestions = Mash.new @conflicting = Mash.new @providing = Mash.new @replacing = Mash.new @attributes = Mash.new @groupings = Mash.new @recipes = Mash.new @version = Version.new "0.0.0" if cookbook @recipes = cookbook.fully_qualified_recipe_names.inject({}) do |r, e| e = self.name.to_s if e =~ /::default$/ r[e] ||= "" self.provides e r end end end
# File lib/chef/cookbook/metadata.rb, line 479 def self.validate_json(json_str) o = Chef::JSONCompat.from_json(json_str) metadata = new() VERSION_CONSTRAINTS.each do |method_name, hash_key| if constraints = o[hash_key] constraints.each do |cb_name, constraints| metadata.send(method_name, cb_name, *Array(constraints)) end end end true end
Public Instance Methods
# File lib/chef/cookbook/metadata.rb, line 121 def ==(other) COMPARISON_FIELDS.inject(true) do |equal_so_far, field| equal_so_far && other.respond_to?(field) && (other.send(field) == send(field)) end end
Adds an attribute )hat a user needs to configure for this cookbook. Takes a name (with the / notation for a nested attribute), followed by any of these options
display_name<String>:: What a UI should show for this attribute description<String>:: A hint as to what this attr is for choice<Array>:: An array of choices to present to the user. calculated<Boolean>:: If true, the default value is calculated by the recipe and cannot be displayed. type<String>:: "string" or "array" - default is "string" ("hash" is supported for backwards compatibility) required<String>:: Whether this attr is 'required', 'recommended' or 'optional' - default 'optional' (true/false values also supported for backwards compatibility) recipes<Array>:: An array of recipes which need this attr set. default<String>,<Array>,<Hash>:: The default value
Parameters¶ ↑
- name<String>
-
The name of the attribute ('foo', or 'apache2/log_dir')
- options<Hash>
-
The description of the options
Returns¶ ↑
- options<Hash>
-
Returns the current options hash
# File lib/chef/cookbook/metadata.rb, line 386 def attribute(name, options) validate( options, { :display_name => { :kind_of => String }, :description => { :kind_of => String }, :choice => { :kind_of => [ Array ], :default => [] }, :calculated => { :equal_to => [ true, false ], :default => false }, :type => { :equal_to => [ "string", "array", "hash", "symbol", "boolean", "numeric" ], :default => "string" }, :required => { :equal_to => [ "required", "recommended", "optional", true, false ], :default => "optional" }, :recipes => { :kind_of => [ Array ], :default => [] }, :default => { :kind_of => [ String, Array, Hash, Symbol, Numeric, TrueClass, FalseClass ] } } ) options[:required] = remap_required_attribute(options[:required]) unless options[:required].nil? validate_choice_array(options) validate_calculated_default_rule(options) validate_choice_default_rule(options) @attributes[name] = options @attributes[name] end
Adds a conflict for another cookbook, with version checking strings.
Parameters¶ ↑
- cookbook<String>
-
The cookbook
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 311 def conflicts(cookbook, *version_args) version = new_args_format(:conflicts, cookbook, version_args) normalized_version = normalize_version_constraint(:conflicts, cookbook, version) @conflicting[cookbook] = normalized_version @conflicting[cookbook] end
Adds a dependency on another cookbook, with version checking strings.
Parameters¶ ↑
- cookbook<String>
-
The cookbook
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 260 def depends(cookbook, *version_args) version = new_args_format(:depends, cookbook, version_args) normalized_version = normalize_version_constraint(:depends, cookbook, version) @dependencies[cookbook] = normalized_version @dependencies[cookbook] end
Sets the current description, or returns it. Should be short - one line only!
Parameters¶ ↑
- description<String>
-
The new description
Returns¶ ↑
- description<String>
-
Returns the description
# File lib/chef/cookbook/metadata.rb, line 179 def description(arg=nil) set_or_return( :description, arg, :kind_of => [ String ] ) end
# File lib/chef/cookbook/metadata.rb, line 453 def from_hash(o) @name = o[NAME] if o.has_key?(NAME) @description = o[DESCRIPTION] if o.has_key?(DESCRIPTION) @long_description = o[LONG_DESCRIPTION] if o.has_key?(LONG_DESCRIPTION) @maintainer = o[MAINTAINER] if o.has_key?(MAINTAINER) @maintainer_email = o[MAINTAINER_EMAIL] if o.has_key?(MAINTAINER_EMAIL) @license = o[LICENSE] if o.has_key?(LICENSE) @platforms = o[PLATFORMS] if o.has_key?(PLATFORMS) @dependencies = handle_deprecated_constraints(o[DEPENDENCIES]) if o.has_key?(DEPENDENCIES) @recommendations = handle_deprecated_constraints(o[RECOMMENDATIONS]) if o.has_key?(RECOMMENDATIONS) @suggestions = handle_deprecated_constraints(o[SUGGESTIONS]) if o.has_key?(SUGGESTIONS) @conflicting = handle_deprecated_constraints(o[CONFLICTING]) if o.has_key?(CONFLICTING) @providing = o[PROVIDING] if o.has_key?(PROVIDING) @replacing = handle_deprecated_constraints(o[REPLACING]) if o.has_key?(REPLACING) @attributes = o[ATTRIBUTES] if o.has_key?(ATTRIBUTES) @groupings = o[GROUPINGS] if o.has_key?(GROUPINGS) @recipes = o[RECIPES] if o.has_key?(RECIPES) @version = o[VERSION] if o.has_key?(VERSION) self end
# File lib/chef/cookbook/metadata.rb, line 492 def from_json(string) o = Chef::JSONCompat.from_json(string) from_hash(o) end
# File lib/chef/cookbook/metadata.rb, line 409 def grouping(name, options) validate( options, { :title => { :kind_of => String }, :description => { :kind_of => String } } ) @groupings[name] = options @groupings[name] end
Sets the current long description, or returns it. Might come from a README, say.
Parameters¶ ↑
- #long_description<String>
-
The new long description
Returns¶ ↑
- #long_description<String>
-
Returns the long description
# File lib/chef/cookbook/metadata.rb, line 194 def long_description(arg=nil) set_or_return( :long_description, arg, :kind_of => [ String ] ) end
Sets the maintainers email address, or returns it.
Parameters¶ ↑
- #maintainer_email<String>
-
The maintainers email address
Returns¶ ↑
- #maintainer_email<String>
-
Returns the current maintainer email.
# File lib/chef/cookbook/metadata.rb, line 149 def maintainer_email(arg=nil) set_or_return( :maintainer_email, arg, :kind_of => [ String ] ) end
Adds a recipe, definition, or resource provided by this cookbook.
Recipes are specified as normal Definitions are followed by (), and can include :params for prototyping Resources are the stringified version (service)
Parameters¶ ↑
- recipe, definition, resource<String>
-
The thing we provide
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 332 def provides(cookbook, *version_args) version = new_args_format(:provides, cookbook, version_args) normalized_version = normalize_version_constraint(:provides, cookbook, version) @providing[cookbook] = normalized_version @providing[cookbook] end
Adds a recommendation for another cookbook, with version checking strings.
Parameters¶ ↑
- cookbook<String>
-
The cookbook
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 277 def recommends(cookbook, *version_args) version = new_args_format(:recommends, cookbook, version_args) normalized_version = normalize_version_constraint(:recommends, cookbook, version) @recommendations[cookbook] = normalized_version @recommendations[cookbook] end
Adds a cookbook that is replaced by this one, with version checking strings.
Parameters¶ ↑
- cookbook<String>
-
The cookbook we replace
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 348 def replaces(cookbook, *version_args) version = new_args_format(:replaces, cookbook, version_args) normalized_version = normalize_version_constraint(:replaces, cookbook, version) @replacing[cookbook] = normalized_version @replacing[cookbook] end
Adds a suggestion for another cookbook, with version checking strings.
Parameters¶ ↑
- cookbook<String>
-
The cookbook
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the formx.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 294 def suggests(cookbook, *version_args) version = new_args_format(:suggests, cookbook, version_args) normalized_version = normalize_version_constraint(:suggests, cookbook, version) @suggestions[cookbook] = normalized_version @suggestions[cookbook] end
Adds a supported platform, with version checking strings.
Parameters¶ ↑
- platform<String>,<Symbol>
-
The platform (like :ubuntu or :mac_os_x)
- version<String>
-
A version constraint of the form “OP VERSION”,
where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y.
Returns¶ ↑
- versions<Array>
-
Returns the list of versions for the platform
# File lib/chef/cookbook/metadata.rb, line 243 def supports(platform, *version_args) version = new_args_format(:supports, platform, version_args) normalized_version = normalize_version_constraint(:supports, platform, version) @platforms[platform] = normalized_version @platforms[platform] end
# File lib/chef/cookbook/metadata.rb, line 421 def to_hash { NAME => self.name, DESCRIPTION => self.description, LONG_DESCRIPTION => self.long_description, MAINTAINER => self.maintainer, MAINTAINER_EMAIL => self.maintainer_email, LICENSE => self.license, PLATFORMS => self.platforms, DEPENDENCIES => self.dependencies, RECOMMENDATIONS => self.recommendations, SUGGESTIONS => self.suggestions, CONFLICTING => self.conflicting, PROVIDING => self.providing, REPLACING => self.replacing, ATTRIBUTES => self.attributes, GROUPINGS => self.groupings, RECIPES => self.recipes, VERSION => self.version } end
# File lib/chef/cookbook/metadata.rb, line 443 def to_json(*a) self.to_hash.to_json(*a) end
Private Instance Methods
This method translates version constraint strings from cookbooks with the old format.
Before we began respecting version constraints, we allowed multiple constraints to be placed on cookbooks, as well as the << and >> operators, which are now just < and >. For specifications with more than one constraint, we return an empty array (otherwise, we're silently abiding only part of the contract they have specified to us). If there is only one constraint, we are replacing the old << and >> with the new < and >.
# File lib/chef/cookbook/metadata.rb, line 634 def handle_deprecated_constraints(specification) specification.inject(Mash.new) do |acc, (cb, constraints)| constraints = Array(constraints) acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, '>').gsub(/<</, '<') acc end end
# File lib/chef/cookbook/metadata.rb, line 499 def new_args_format(caller_name, dep_name, version_constraints) if version_constraints.empty? ">= 0.0.0" elsif version_constraints.size == 1 version_constraints.first else msg=<<-OBSOLETED The dependency specification syntax you are using is no longer valid. You may not specify more than one version constraint for a particular cookbook. Consult http://wiki.opscode.com/display/chef/Metadata for the updated syntax. Called by: #{caller_name} '#{dep_name}', #{version_constraints.map {|vc| vc.inspect}.join(", ")} Called from: #{caller[0...5].map {|line| " " + line}.join("\n")} OBSOLETED raise Exceptions::ObsoleteDependencySyntax, msg end end
# File lib/chef/cookbook/metadata.rb, line 536 def normalize_version_constraint(caller_name, dep_name, constraint_str) version_constraint = validate_version_constraint(caller_name, dep_name, constraint_str) "#{version_constraint.op} #{version_constraint.raw_version}" end
For backwards compatibility, remap Boolean values to String
true is mapped to "required" false is mapped to "optional"
Parameters¶ ↑
- required_attr<String><Boolean>
-
The value of options
Returns¶ ↑
- required_attr<String>
-
“required”, “recommended”, or “optional”
# File lib/chef/cookbook/metadata.rb, line 592 def remap_required_attribute(value) case value when true value = "required" when false value = "optional" end value end
# File lib/chef/cookbook/metadata.rb, line 602 def validate_calculated_default_rule(options) calculated_conflict = ((options[:default].is_a?(Array) && !options[:default].empty?) || (options[:default].is_a?(String) && !options[:default] != "")) && options[:calculated] == true raise ArgumentError, "Default cannot be specified if calculated is true!" if calculated_conflict end
Validate the choice of the options hash
Raise an exception if the members of the array do not match the defaults
Parameters¶ ↑
- opts<Hash>
-
The options hash
# File lib/chef/cookbook/metadata.rb, line 560 def validate_choice_array(opts) if opts[:choice].kind_of?(Array) case opts[:type] when "string" validator = [ String ] when "array" validator = [ Array ] when "hash" validator = [ Hash ] when "symbol" validator = [ Symbol ] when "boolean" validator = [ TrueClass, FalseClass ] when "numeric" validator = [ Numeric ] end opts[:choice].each do |choice| validate( {:choice => choice}, {:choice => {:kind_of => validator}} ) end end end
# File lib/chef/cookbook/metadata.rb, line 609 def validate_choice_default_rule(options) return if !options[:choice].is_a?(Array) || options[:choice].empty? if options[:default].is_a?(String) && options[:default] != "" raise ArgumentError, "Default must be one of your choice values!" if options[:choice].index(options[:default]) == nil end if options[:default].is_a?(Array) && !options[:default].empty? options[:default].each do |val| raise ArgumentError, "Default values must be a subset of your choice values!" if options[:choice].index(val) == nil end end end
Verify that the given array is an array of strings
Raise an exception if the members of the array are not Strings
Parameters¶ ↑
- arry<Array>
-
An array to be validated
# File lib/chef/cookbook/metadata.rb, line 547 def validate_string_array(arry) if arry.kind_of?(Array) arry.each do |choice| validate( {:choice => choice}, {:choice => {:kind_of => String}} ) end end end
# File lib/chef/cookbook/metadata.rb, line 518 def validate_version_constraint(caller_name, dep_name, constraint_str) Chef::VersionConstraint.new(constraint_str) rescue Chef::Exceptions::InvalidVersionConstraint => e Log.debug(e) msg=<<-INVALID The version constraint syntax you are using is not valid. If you recently upgraded to Chef 0.10.0, be aware that you no may longer use "<<" and ">>" for 'less than' and 'greater than'; use '<' and '>' instead. Consult http://wiki.opscode.com/display/chef/Metadata for more information. Called by: #{caller_name} '#{dep_name}', '#{constraint_str}' Called from: #{caller[0...5].map {|line| " " + line}.join("\n")} INVALID raise Exceptions::InvalidVersionConstraint, msg end