summaryrefslogtreecommitdiff
path: root/lib/chef/cookbook_version.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/cookbook_version.rb')
-rw-r--r--lib/chef/cookbook_version.rb244
1 files changed, 75 insertions, 169 deletions
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 1e903608b5..7bb3f3385f 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -4,7 +4,7 @@
# Author:: Tim Hinderliter (<tim@chef.io>)
# Author:: Seth Falcon (<seth@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# Copyright:: Copyright 2008-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,50 +37,23 @@ class Chef
class CookbookVersion
include Comparable
+ extend Forwardable
+
+ def_delegator :@cookbook_manifest, :files_for
+ def_delegator :@cookbook_manifest, :each_file
COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
- attr_accessor :all_files
+ attr_reader :all_files
attr_accessor :root_paths
- attr_accessor :definition_filenames
- attr_accessor :template_filenames
- attr_accessor :file_filenames
- attr_accessor :library_filenames
- attr_accessor :resource_filenames
- attr_accessor :provider_filenames
- attr_accessor :root_filenames
attr_accessor :name
- attr_accessor :metadata_filenames
-
- def status=(new_status)
- Chef.log_deprecation("Deprecated method `status' called. This method will be removed.")
- @status = new_status
- end
-
- def status
- Chef.log_deprecation("Deprecated method `status' called. This method will be removed.")
- @status
- end
# A Chef::Cookbook::Metadata object. It has a setter that fixes up the
# metadata to add descriptions of the recipes contained in this
# CookbookVersion.
attr_reader :metadata
- # attribute_filenames also has a setter that has non-default
- # functionality.
- attr_reader :attribute_filenames
-
- # recipe_filenames also has a setter that has non-default
- # functionality.
- attr_reader :recipe_filenames
-
- attr_reader :recipe_filenames_by_name
- attr_reader :attribute_filenames_by_short_filename
-
- attr_accessor :chef_server_rest
-
# The `identifier` field is used for cookbook_artifacts, which are
# organized on the chef server according to their content. If the
# policy_mode option to CookbookManifest is set to true it will include
@@ -96,12 +69,17 @@ class Chef
root_paths[0]
end
+ def all_files=(files)
+ @all_files = Array(files)
+ cookbook_manifest.reset!
+ end
+
# This is the one and only method that knows how cookbook files'
# checksums are generated.
def self.checksum_cookbook_file(filepath)
Chef::Digester.generate_md5_checksum_for_file(filepath)
rescue Errno::ENOENT
- Chef::Log.debug("File #{filepath} does not exist, so there is no checksum to generate")
+ Chef::Log.trace("File #{filepath} does not exist, so there is no checksum to generate")
nil
end
@@ -118,23 +96,10 @@ class Chef
@root_paths = root_paths
@frozen = false
- @attribute_filenames = Array.new
- @definition_filenames = Array.new
- @template_filenames = Array.new
- @file_filenames = Array.new
- @recipe_filenames = Array.new
- @recipe_filenames_by_name = Hash.new
- @library_filenames = Array.new
- @resource_filenames = Array.new
- @provider_filenames = Array.new
- @metadata_filenames = Array.new
- @root_filenames = Array.new
-
@all_files = Array.new
- # deprecated
- @status = :ready
@file_vendor = nil
+ @cookbook_manifest = Chef::CookbookManifest.new(self)
@metadata = Chef::Cookbook::Metadata.new
@chef_server_rest = chef_server_rest
end
@@ -163,26 +128,40 @@ class Chef
"#{name}-#{version}"
end
- def attribute_filenames=(*filenames)
- @attribute_filenames = filenames.flatten
- @attribute_filenames_by_short_filename = filenames_by_name(attribute_filenames)
- attribute_filenames
+ def attribute_filenames_by_short_filename
+ @attribute_filenames_by_short_filename ||= begin
+ name_map = filenames_by_name(files_for("attributes"))
+ root_alias = cookbook_manifest.root_files.find { |record| record[:name] == "attributes.rb" }
+ name_map["default"] = root_alias[:full_path] if root_alias
+ name_map
+ end
+ end
+
+ def recipe_filenames_by_name
+ @recipe_filenames_by_name ||= begin
+ name_map = filenames_by_name(files_for("recipes"))
+ root_alias = cookbook_manifest.root_files.find { |record| record[:name] == "recipe.rb" }
+ if root_alias
+ Chef::Log.error("Cookbook #{name} contains both recipe.rb and and recipes/default.rb, ignoring recipes/default.rb") if name_map["default"]
+ name_map["default"] = root_alias[:full_path]
+ end
+ name_map
+ end
end
def metadata=(metadata)
@metadata = metadata
@metadata.recipes_from_cookbook_version(self)
- @metadata
end
- ## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
- alias :attribute_files :attribute_filenames
- alias :attribute_files= :attribute_filenames=
-
def manifest
cookbook_manifest.manifest
end
+ def manifest=(new_manifest)
+ cookbook_manifest.update_from(new_manifest)
+ end
+
# Returns a hash of checksums to either nil or the on disk path (which is
# done by generate_manifest).
def checksums
@@ -193,36 +172,23 @@ class Chef
cookbook_manifest.manifest_records_by_path
end
- def manifest=(new_manifest)
- cookbook_manifest.update_from(new_manifest)
- end
-
# Return recipe names in the form of cookbook_name::recipe_name
def fully_qualified_recipe_names
- results = Array.new
- recipe_filenames_by_name.each_key do |rname|
- results << "#{name}::#{rname}"
+ files_for("recipes").inject([]) do |memo, recipe|
+ rname = recipe[:name].split("/")[1]
+ rname = File.basename(rname, ".rb")
+ memo << "#{name}::#{rname}"
+ memo
end
- results
- end
-
- def recipe_filenames=(*filenames)
- @recipe_filenames = filenames.flatten
- @recipe_filenames_by_name = filenames_by_name(recipe_filenames)
- recipe_filenames
end
- ## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
- alias :recipe_files :recipe_filenames
- alias :recipe_files= :recipe_filenames=
-
# called from DSL
def load_recipe(recipe_name, run_context)
unless recipe_filenames_by_name.has_key?(recipe_name)
raise Chef::Exceptions::RecipeNotFound, "could not find recipe #{recipe_name} for cookbook #{name}"
end
- Chef::Log.debug("Found recipe #{recipe_name} in cookbook #{name}")
+ Chef::Log.trace("Found recipe #{recipe_name} in cookbook #{name}")
recipe = Chef::Recipe.new(name, recipe_name, run_context)
recipe_filename = recipe_filenames_by_name[recipe_name]
@@ -235,41 +201,7 @@ class Chef
end
def segment_filenames(segment)
- unless COOKBOOK_SEGMENTS.include?(segment)
- raise ArgumentError, "invalid segment #{segment}: must be one of #{COOKBOOK_SEGMENTS.join(', ')}"
- end
-
- case segment.to_sym
- when :resources
- @resource_filenames
- when :providers
- @provider_filenames
- when :recipes
- @recipe_filenames
- when :libraries
- @library_filenames
- when :definitions
- @definition_filenames
- when :attributes
- @attribute_filenames
- when :files
- @file_filenames
- when :templates
- @template_filenames
- when :root_files
- @root_filenames
- end
- end
-
- def replace_segment_filenames(segment, filenames)
- case segment.to_sym
- when :recipes
- self.recipe_filenames = filenames
- when :attributes
- self.attribute_filenames = filenames
- else
- segment_filenames(segment).replace(filenames)
- end
+ files_for(segment).map { |f| f["full_path"] || File.join(root_dir, f["path"]) }
end
# Query whether a template file +template_filename+ is available. File
@@ -316,13 +248,13 @@ class Chef
error_message << error_locations.join("\n")
existing_files = segment_filenames(segment)
# Strip the root_dir prefix off all files for readability
- pretty_existing_files = existing_files.map { |path|
+ pretty_existing_files = existing_files.map do |path|
if root_dir
path[root_dir.length + 1..-1]
else
path
end
- }
+ end
# Show the files that the cookbook does have. If the user made a typo,
# hopefully they'll see it here.
unless pretty_existing_files.empty?
@@ -349,7 +281,7 @@ class Chef
filenames_by_pref = Hash.new
preferences.each { |pref| filenames_by_pref[pref] = Array.new }
- manifest[segment].each do |manifest_record|
+ files_for(segment).each do |manifest_record|
manifest_record_path = manifest_record[:path]
# find the NON SPECIFIC filenames, but prefer them by filespecificity.
@@ -389,7 +321,7 @@ class Chef
records_by_pref = Hash.new
preferences.each { |pref| records_by_pref[pref] = Array.new }
- manifest[segment].each do |manifest_record|
+ files_for(segment).each do |manifest_record|
manifest_record_path = manifest_record[:path]
# extract the preference part from the path.
@@ -469,12 +401,22 @@ class Chef
end
private :preferences_for_path
+ def display
+ output = Mash.new
+ output["cookbook_name"] = name
+ output["name"] = full_name
+ output["frozen?"] = frozen_version?
+ output["metadata"] = metadata.to_hash
+ output["version"] = version
+ output.merge(cookbook_manifest.by_parent_directory)
+ end
+
def self.from_hash(o)
cookbook_version = new(o["cookbook_name"] || o["name"])
# We want the Chef::Cookbook::Metadata object to always be inflated
- cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
cookbook_version.manifest = o
+ cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
cookbook_version.identifier = o["identifier"] if o.key?("identifier")
# We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>)
@@ -484,42 +426,10 @@ class Chef
cookbook_version
end
- def self.json_create(o)
- Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::CookbookVersion#from_hash")
- from_hash(o)
- end
-
def self.from_cb_artifact_data(o)
from_hash(o)
end
- # @deprecated This method was used by the Ruby Chef Server and is no longer
- # needed. There is no replacement.
- def generate_manifest_with_urls
- Chef.log_deprecation("Deprecated method #generate_manifest_with_urls.")
-
- rendered_manifest = manifest.dup
- COOKBOOK_SEGMENTS.each do |segment|
- if rendered_manifest.has_key?(segment)
- rendered_manifest[segment].each do |manifest_record|
- url_options = { :cookbook_name => name.to_s, :cookbook_version => version, :checksum => manifest_record["checksum"] }
- manifest_record["url"] = yield(url_options)
- end
- end
- end
- rendered_manifest
- end
-
- def to_hash
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.to_hash
- end
-
- def to_json(*a)
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.to_json
- end
-
def metadata_json_file
File.join(root_paths[0], "metadata.json")
end
@@ -538,22 +448,12 @@ class Chef
# REST API
##
- def save_url
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.save_url
- end
-
- def force_save_url
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.force_save_url
- end
-
def chef_server_rest
- @chef_server_rest ||= self.chef_server_rest
+ @chef_server_rest ||= chef_server_rest
end
def self.chef_server_rest
- Chef::ServerAPI.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url], { version_class: Chef::CookbookManifestVersions })
end
def destroy
@@ -599,20 +499,20 @@ class Chef
end
end
- def <=>(o)
- raise Chef::Exceptions::CookbookVersionNameMismatch if self.name != o.name
+ def <=>(other)
+ raise Chef::Exceptions::CookbookVersionNameMismatch if name != other.name
# FIXME: can we change the interface to the Metadata class such
# that metadata.version returns a Chef::Version instance instead
# of a string?
- Chef::Version.new(self.version) <=> Chef::Version.new(o.version)
+ Chef::Version.new(version) <=> Chef::Version.new(other.version)
end
- private
-
def cookbook_manifest
@cookbook_manifest ||= CookbookManifest.new(self)
end
+ private
+
def find_preferred_manifest_record(node, segment, filename)
preferences = preferences_for_path(node, segment, filename)
@@ -620,15 +520,21 @@ class Chef
preferences.find { |preferred_filename| manifest_records_by_path[preferred_filename] }
end
- # For each filename, produce a mapping of base filename (i.e. recipe name
+ # For each manifest record, produce a mapping of base filename (i.e. recipe name
+ # or attribute file) to on disk location
+ def relative_paths_by_name(records)
+ records.select { |record| record[:name] =~ /\.rb$/ }.inject({}) { |memo, record| memo[File.basename(record[:name], ".rb")] = record[:path]; memo }
+ end
+
+ # For each manifest record, produce a mapping of base filename (i.e. recipe name
# or attribute file) to on disk location
- def filenames_by_name(filenames)
- filenames.select { |filename| filename =~ /\.rb$/ }.inject({}) { |memo, filename| memo[File.basename(filename, ".rb")] = filename ; memo }
+ def filenames_by_name(records)
+ records.select { |record| record[:name] =~ /\.rb$/ }.inject({}) { |memo, record| memo[File.basename(record[:name], ".rb")] = record[:full_path]; memo }
end
def file_vendor
unless @file_vendor
- @file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
+ @file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(cookbook_manifest)
end
@file_vendor
end