Class: Chef::Cookbook::Metadata

Inherits:
Object
  • Object
show all
Includes:
Mixin::FromFile, Mixin::ParamsValidate
Defined in:
lib/chef/cookbook/metadata.rb

Overview

Chef::Cookbook::Metadata

Chef::Cookbook::Metadata provides a convenient DSL for declaring metadata about Chef Cookbooks.

Direct Known Subclasses

MinimalMetadata

Constant Summary collapse

NAME =
"name".freeze
DESCRIPTION =
"description".freeze
LONG_DESCRIPTION =
"long_description".freeze
MAINTAINER =
"maintainer".freeze
MAINTAINER_EMAIL =
"maintainer_email".freeze
LICENSE =
"license".freeze
PLATFORMS =
"platforms".freeze
DEPENDENCIES =
"dependencies".freeze
PROVIDING =
"providing".freeze
RECIPES =
"recipes".freeze
VERSION =
"version".freeze
SOURCE_URL =
"source_url".freeze
ISSUES_URL =
"issues_url".freeze
PRIVACY =
"privacy".freeze
CHEF_VERSIONS =
"chef_versions".freeze
OHAI_VERSIONS =
"ohai_versions".freeze
GEMS =
"gems".freeze
COMPARISON_FIELDS =
%i{name description long_description maintainer
maintainer_email license platforms dependencies
providing recipes version source_url issues_url
privacy chef_versions ohai_versions gems}.freeze
VERSION_CONSTRAINTS =
{ depends: DEPENDENCIES,
provides: PROVIDING,
chef_version: CHEF_VERSIONS,
ohai_version: OHAI_VERSIONS }.freeze

Instance Attribute Summary collapse

Attributes included from Mixin::FromFile

#source_file

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixin::FromFile

#class_from_file, #from_file

Methods included from Mixin::ParamsValidate

#lazy, #set_or_return, #validate

Constructor Details

#initializeMetadata

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>



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/chef/cookbook/metadata.rb', line 91

def initialize
  @name = nil

  @description = ""
  @long_description = ""
  @license = "All rights reserved"

  @maintainer = ""
  @maintainer_email = ""

  @platforms = Mash.new
  @dependencies = Mash.new
  @providing = Mash.new
  @recipes = Mash.new
  @version = Version.new("0.0.0")
  @source_url = ""
  @issues_url = ""
  @privacy = false
  @chef_versions = []
  @ohai_versions = []
  @gems = []

  @errors = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



566
567
568
569
570
571
572
# File 'lib/chef/cookbook/metadata.rb', line 566

def method_missing(method, *args, &block)
  if block_given?
    super
  else
    Chef::Log.trace "ignoring method #{method} on cookbook with name #{name}, possible typo or the ghosts of metadata past or future?"
  end
end

Instance Attribute Details

#chef_versionsArray<Gem::Dependency> (readonly)

Returns Array of supported Chef versions.

Returns:

  • (Array<Gem::Dependency>)

    Array of supported Chef versions



75
76
77
# File 'lib/chef/cookbook/metadata.rb', line 75

def chef_versions
  @chef_versions
end

#dependenciesObject (readonly)

Returns the value of attribute dependencies.



70
71
72
# File 'lib/chef/cookbook/metadata.rb', line 70

def dependencies
  @dependencies
end

#gemsArray<Array> (readonly)

Returns Array of gems to install with *args as an Array.

Returns:

  • (Array<Array>)

    Array of gems to install with *args as an Array



79
80
81
# File 'lib/chef/cookbook/metadata.rb', line 79

def gems
  @gems
end

#ohai_versionsArray<Gem::Dependency> (readonly)

Returns Array of supported Ohai versions.

Returns:

  • (Array<Gem::Dependency>)

    Array of supported Ohai versions



77
78
79
# File 'lib/chef/cookbook/metadata.rb', line 77

def ohai_versions
  @ohai_versions
end

#platformsObject (readonly)

Returns the value of attribute platforms.



69
70
71
# File 'lib/chef/cookbook/metadata.rb', line 69

def platforms
  @platforms
end

#providingObject (readonly)

Returns the value of attribute providing.



71
72
73
# File 'lib/chef/cookbook/metadata.rb', line 71

def providing
  @providing
end

#recipesObject (readonly)

Returns the value of attribute recipes.



72
73
74
# File 'lib/chef/cookbook/metadata.rb', line 72

def recipes
  @recipes
end

Class Method Details

.from_hash(o) ⇒ Object



447
448
449
450
451
# File 'lib/chef/cookbook/metadata.rb', line 447

def self.from_hash(o)
  cm = new
  cm.from_hash(o)
  cm
end

.from_json(string) ⇒ Object



474
475
476
477
# File 'lib/chef/cookbook/metadata.rb', line 474

def self.from_json(string)
  o = Chef::JSONCompat.from_json(string)
  from_hash(o)
end

.validate_json(json_str) ⇒ Object



479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/chef/cookbook/metadata.rb', line 479

def self.validate_json(json_str)
  o = Chef::JSONCompat.from_json(json_str)
   = new
  VERSION_CONSTRAINTS.each do |dependency_type, hash_key|
    if dependency_group = o[hash_key]
      dependency_group.each do |cb_name, constraints|
        if .respond_to?(dependency_type)
          .public_send(dependency_type, cb_name, *Array(constraints))
        end
      end
    end
  end
  true
end

Instance Method Details

#==(other) ⇒ Object



116
117
118
119
120
# File 'lib/chef/cookbook/metadata.rb', line 116

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

#chef_version(*version_args) ⇒ Array<Gem::Dependency>

Metadata DSL to set a valid chef_version. May be declared multiple times with the result being ‘OR’d such that if any statements match, the version is considered supported. Uses Gem::Requirement for its implementation.

Parameters:

  • version_args (Array<String>)

    Version constraint in String form

Returns:

  • (Array<Gem::Dependency>)

    Current chef_versions array



320
321
322
323
# File 'lib/chef/cookbook/metadata.rb', line 320

def chef_version(*version_args)
  @chef_versions << Gem::Dependency.new("chef", *version_args) unless version_args.empty?
  @chef_versions
end

#depends(cookbook, *version_args) ⇒ Object

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



281
282
283
284
285
286
287
288
289
290
291
# File 'lib/chef/cookbook/metadata.rb', line 281

def depends(cookbook, *version_args)
  if cookbook == name
    raise "Cookbook depends on itself in cookbook #{name}, please remove the this unnecessary self-dependency"
  else
    version = new_args_format(:depends, cookbook, version_args)
    constraint = validate_version_constraint(:depends, cookbook, version)
    @dependencies[cookbook] = constraint.to_s
  end

  @dependencies[cookbook]
end

#description(arg = nil) ⇒ Object

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



200
201
202
203
204
205
206
# File 'lib/chef/cookbook/metadata.rb', line 200

def description(arg = nil)
  set_or_return(
    :description,
    arg,
    kind_of: [ String ]
  )
end

#errorsObject

A list of validation errors for this metadata object. See #valid? for comments about the validation criteria.

If there are any validation errors, one or more error strings will be returned. Otherwise an empty array is returned.

Returns

error messages<Array>

Whether this metadata object is valid



143
144
145
146
# File 'lib/chef/cookbook/metadata.rb', line 143

def errors
  run_validation
  @errors
end

#from_hash(o) ⇒ Object



453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/chef/cookbook/metadata.rb', line 453

def from_hash(o)
  @name                         = o[NAME] if o.key?(NAME)
  @description                  = o[DESCRIPTION] if o.key?(DESCRIPTION)
  @long_description             = o[LONG_DESCRIPTION] if o.key?(LONG_DESCRIPTION)
  @maintainer                   = o[MAINTAINER] if o.key?(MAINTAINER)
  @maintainer_email             = o[MAINTAINER_EMAIL] if o.key?(MAINTAINER_EMAIL)
  @license                      = o[LICENSE] if o.key?(LICENSE)
  @platforms                    = o[PLATFORMS] if o.key?(PLATFORMS)
  @dependencies                 = handle_deprecated_constraints(o[DEPENDENCIES]) if o.key?(DEPENDENCIES)
  @providing                    = o[PROVIDING] if o.key?(PROVIDING)
  @recipes                      = o[RECIPES] if o.key?(RECIPES)
  @version                      = o[VERSION] if o.key?(VERSION)
  @source_url                   = o[SOURCE_URL] if o.key?(SOURCE_URL)
  @issues_url                   = o[ISSUES_URL] if o.key?(ISSUES_URL)
  @privacy                      = o[PRIVACY] if o.key?(PRIVACY)
  @chef_versions                = gem_requirements_from_array("chef", o[CHEF_VERSIONS]) if o.key?(CHEF_VERSIONS)
  @ohai_versions                = gem_requirements_from_array("ohai", o[OHAI_VERSIONS]) if o.key?(OHAI_VERSIONS)
  @gems                         = o[GEMS] if o.key?(GEMS)
  self
end

#from_json(string) ⇒ Object



494
495
496
497
# File 'lib/chef/cookbook/metadata.rb', line 494

def from_json(string)
  o = Chef::JSONCompat.from_json(string)
  from_hash(o)
end

#gem(*args) ⇒ Array<Array>

Metadata DSL to set a gem to install from the cookbook metadata. May be declared multiple times. All the gems from all the cookbooks are combined into one Gemfile and depsolved together. Uses Bundler’s DSL for its implementation.

Parameters:

  • args (Array<String>)

    Gem name and options to pass to Bundler’s DSL

Returns:

  • (Array<Array>)

    Array of gem statements as args



342
343
344
345
# File 'lib/chef/cookbook/metadata.rb', line 342

def gem(*args)
  @gems << args unless args.empty?
  @gems
end

#gem_requirements_from_array(what, array) ⇒ Array<Gem::Dependency>

Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to a hash.

This is the inverse of #gem_requirements_to_array

Parameters:

  • what (String)

    What version constraint we are constructing (‘chef’ or ‘ohai’ presently)

  • array (Array<Array<String>])

    Simple object representation of version constraints (from json)

Returns:

  • (Array<Gem::Dependency>)

    Multiple Gem-style version constraints



413
414
415
416
417
# File 'lib/chef/cookbook/metadata.rb', line 413

def gem_requirements_from_array(what, array)
  array.map do |dep|
    Gem::Dependency.new(what, *dep)
  end
end

#gem_requirements_to_array(*deps) ⇒ Array<Array<String>]

Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to an Array.

Gem::Dependencey#to_s is not useful, and there is no #to_json defined on it or its component objets, so we have to write our own rendering method.

Gem::Dependency.new(“>= 12.5”), Gem::Dependency.new(“>= 11.18.0”, “< 12.0”)

results in:

[ “>= 12.5” ], [ “>= 11.18.0”, “< 12.0”

]

Parameters:

  • deps (Array<Gem::Dependency>)

    Multiple Gem-style version constraints

Returns:

  • (Array<Array<String>])

    Simple object representation of version constraints (for json)



398
399
400
401
402
403
404
# File 'lib/chef/cookbook/metadata.rb', line 398

def gem_requirements_to_array(*deps)
  deps.map do |dep|
    dep.requirement.requirements.map do |op, version|
      "#{op} #{version}"
    end.sort
  end
end

#issues_url(arg = nil) ⇒ Object

Sets the cookbook’s issues URL, or returns it.

Parameters

issues_url<String>

The issues URL

Returns

issues_url<String>

Returns the current issues URL.



521
522
523
524
525
526
527
# File 'lib/chef/cookbook/metadata.rb', line 521

def issues_url(arg = nil)
  set_or_return(
    :issues_url,
    arg,
    kind_of: [ String ]
  )
end

#license(arg = nil) ⇒ Object

Sets the current license, or returns it.

Parameters

license<String>

The current license.

Returns

license<String>

Returns the current license



185
186
187
188
189
190
191
# File 'lib/chef/cookbook/metadata.rb', line 185

def license(arg = nil)
  set_or_return(
    :license,
    arg,
    kind_of: [ String ]
  )
end

#long_description(arg = nil) ⇒ Object

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



215
216
217
218
219
220
221
# File 'lib/chef/cookbook/metadata.rb', line 215

def long_description(arg = nil)
  set_or_return(
    :long_description,
    arg,
    kind_of: [ String ]
  )
end

#maintainer(arg = nil) ⇒ Object

Sets the cookbooks maintainer, or returns it.

Parameters

maintainer<String>

The maintainers name

Returns

maintainer<String>

Returns the current maintainer.



155
156
157
158
159
160
161
# File 'lib/chef/cookbook/metadata.rb', line 155

def maintainer(arg = nil)
  set_or_return(
    :maintainer,
    arg,
    kind_of: [ String ]
  )
end

#maintainer_email(arg = nil) ⇒ Object

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.



170
171
172
173
174
175
176
# File 'lib/chef/cookbook/metadata.rb', line 170

def maintainer_email(arg = nil)
  set_or_return(
    :maintainer_email,
    arg,
    kind_of: [ String ]
  )
end

#name(arg = nil) ⇒ Object

Sets the name of the cookbook, or returns it.

Parameters

name<String>

The current cookbook name.

Returns

name<String>

Returns the current cookbook name.



246
247
248
249
250
251
252
# File 'lib/chef/cookbook/metadata.rb', line 246

def name(arg = nil)
  set_or_return(
    :name,
    arg,
    kind_of: [ String ]
  )
end

#ohai_version(*version_args) ⇒ Array<Gem::Dependency>

Metadata DSL to set a valid ohai_version. May be declared multiple times with the result being ‘OR’d such that if any statements match, the version is considered supported. Uses Gem::Requirement for its implementation.

Parameters:

  • version_args (Array<String>)

    Version constraint in String form

Returns:

  • (Array<Gem::Dependency>)

    Current ohai_versions array



331
332
333
334
# File 'lib/chef/cookbook/metadata.rb', line 331

def ohai_version(*version_args)
  @ohai_versions << Gem::Dependency.new("ohai", *version_args) unless version_args.empty?
  @ohai_versions
end

#privacy(arg = nil) ⇒ Object

Sets the cookbook’s privacy flag, or returns it.

Parameters

privacy<TrueClass,FalseClass>

Whether this cookbook is private or not

Returns

privacy<TrueClass,FalseClass>

Whether this cookbook is private or not



538
539
540
541
542
543
544
# File 'lib/chef/cookbook/metadata.rb', line 538

def privacy(arg = nil)
  set_or_return(
    :privacy,
    arg,
    kind_of: [ TrueClass, FalseClass ]
  )
end

#provides(cookbook, *version_args) ⇒ Object

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



307
308
309
310
311
312
# File 'lib/chef/cookbook/metadata.rb', line 307

def provides(cookbook, *version_args)
  version = new_args_format(:provides, cookbook, version_args)
  constraint = validate_version_constraint(:provides, cookbook, version)
  @providing[cookbook] = constraint.to_s
  @providing[cookbook]
end

#recipe(name, description) ⇒ Object

Adds a description for a recipe.

Parameters

recipe<String>

The recipe

description<String>

The description of the recipe

Returns

description<String>

Returns the current description



355
356
357
# File 'lib/chef/cookbook/metadata.rb', line 355

def recipe(name, description)
  @recipes[name] = description
end

#recipes_from_cookbook_version(cookbook) ⇒ Object

Sets the cookbook’s recipes to the list of recipes in the given cookbook. Any recipe that already has a description (if set by the #recipe method) will not be updated.

Parameters

cookbook<CookbookVersion>

CookbookVersion object representing the cookbook

description<String>

The description of the recipe

Returns

recipe_unqualified_names<Array>

An array of the recipe names given by the cookbook



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/chef/cookbook/metadata.rb', line 369

def recipes_from_cookbook_version(cookbook)
  cookbook.fully_qualified_recipe_names.map do |recipe_name|
    unqualified_name =
      if recipe_name =~ /::default$/
        name.to_s
      else
        recipe_name
      end

    @recipes[unqualified_name] ||= ""
    provides(unqualified_name)

    unqualified_name
  end
end

#source_url(arg = nil) ⇒ Object

Sets the cookbook’s source URL, or returns it.

Parameters

maintainer<String>

The source URL

Returns

source_url<String>

Returns the current source URL.



506
507
508
509
510
511
512
# File 'lib/chef/cookbook/metadata.rb', line 506

def source_url(arg = nil)
  set_or_return(
    :source_url,
    arg,
    kind_of: [ String ]
  )
end

#supports(platform, *version_args) ⇒ Object

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



264
265
266
267
268
269
# File 'lib/chef/cookbook/metadata.rb', line 264

def supports(platform, *version_args)
  version = new_args_format(:supports, platform, version_args)
  constraint = validate_version_constraint(:supports, platform, version)
  @platforms[platform] = constraint.to_s
  @platforms[platform]
end

#to_hObject Also known as: to_hash



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/chef/cookbook/metadata.rb', line 419

def to_h
  {
    NAME => name,
    DESCRIPTION => description,
    LONG_DESCRIPTION => long_description,
    MAINTAINER => maintainer,
    MAINTAINER_EMAIL => maintainer_email,
    LICENSE => license,
    PLATFORMS => platforms,
    DEPENDENCIES => dependencies,
    PROVIDING => providing,
    RECIPES => recipes,
    VERSION => version,
    SOURCE_URL => source_url,
    ISSUES_URL => issues_url,
    PRIVACY => privacy,
    CHEF_VERSIONS => gem_requirements_to_array(*chef_versions),
    OHAI_VERSIONS => gem_requirements_to_array(*ohai_versions),
    GEMS => gems,
  }
end

#to_json(*a) ⇒ Object



443
444
445
# File 'lib/chef/cookbook/metadata.rb', line 443

def to_json(*a)
  Chef::JSONCompat.to_json(to_h, *a)
end

#valid?Boolean

Whether this metadata is valid. In order to be valid, all required fields must be set. Chef’s validation implementation checks the content of a given field when setting (and raises an error if the content does not meet the criteria), so the content of the fields is not considered when checking validity.

Returns

valid<Boolean>

Whether this metadata object is valid

Returns:

  • (Boolean)


130
131
132
133
# File 'lib/chef/cookbook/metadata.rb', line 130

def valid?
  run_validation
  @errors.empty?
end

#validate_chef_version!Object

Validates that the Chef::VERSION of the running chef-client matches one of the configured chef_version statements in this cookbooks metadata.

Raises:



560
561
562
563
564
# File 'lib/chef/cookbook/metadata.rb', line 560

def validate_chef_version!
  unless gem_dep_matches?("chef", Gem::Version.new(Chef::VERSION), *chef_versions)
    raise Exceptions::CookbookChefVersionMismatch.new(Chef::VERSION, name, version, *chef_versions)
  end
end

#validate_ohai_version!Object

Validates that the Ohai::VERSION of the running chef-client matches one of the configured ohai_version statements in this cookbooks metadata.

Raises:



550
551
552
553
554
# File 'lib/chef/cookbook/metadata.rb', line 550

def validate_ohai_version!
  unless gem_dep_matches?("ohai", Gem::Version.new(Ohai::VERSION), *ohai_versions)
    raise Exceptions::CookbookOhaiVersionMismatch.new(Ohai::VERSION, name, version, *ohai_versions)
  end
end

#version(arg = nil) ⇒ Object

Sets the current cookbook version, or returns it. Can be two or three digits, separated by dots. ie: ‘2.1’, ‘1.5.4’ or ‘0.9’.

Parameters

version<String>

The current version, as a string

Returns

version<String>

Returns the current version



231
232
233
234
235
236
237
# File 'lib/chef/cookbook/metadata.rb', line 231

def version(arg = nil)
  if arg
    @version = Chef::Version.new(arg)
  end

  @version.to_s
end