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.rb265
1 files changed, 71 insertions, 194 deletions
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 505b403e65..b8f32a61bb 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -23,9 +23,8 @@ require 'chef/log'
require 'chef/cookbook/file_vendor'
require 'chef/cookbook/metadata'
require 'chef/version_class'
-require 'pathname'
-require 'chef/monkey_patches/pathname'
require 'chef/digester'
+require 'chef/cookbook_manifest'
class Chef
@@ -34,10 +33,8 @@ class Chef
# cookbook. Chef supports maintaining multiple versions of a cookbook on a
# single server; each version is represented by a distinct instance of this
# class.
- #--
- # TODO: timh/cw: 5-24-2010: mutators for files (e.g., recipe_filenames=,
- # recipe_filenames.insert) should dirty the manifest so it gets regenerated.
class CookbookVersion
+
include Comparable
COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
@@ -52,7 +49,16 @@ class Chef
attr_accessor :root_filenames
attr_accessor :name
attr_accessor :metadata_filenames
- attr_accessor :status
+
+ def status=(new_status)
+ Chef::Log.deprecation("Deprecated method `status' called from #{caller(1).first}. This method will be removed")
+ @status = new_status
+ end
+
+ def status
+ Chef::Log.deprecation("Deprecated method `status' called from #{caller(1).first}. 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
@@ -70,6 +76,8 @@ class Chef
attr_reader :recipe_filenames_by_name
attr_reader :attribute_filenames_by_short_filename
+ attr_accessor :chef_server_rest
+
# The first root path is the primary cookbook dir, from which metadata is loaded
def root_dir
root_paths[0]
@@ -92,10 +100,11 @@ class Chef
#
# === Returns
# object<Chef::CookbookVersion>:: Duh. :)
- def initialize(name, *root_paths)
+ def initialize(name, *root_paths, chef_server_rest: nil)
@name = name
@root_paths = root_paths
@frozen = false
+
@attribute_filenames = Array.new
@definition_filenames = Array.new
@template_filenames = Array.new
@@ -107,10 +116,12 @@ class Chef
@provider_filenames = Array.new
@metadata_filenames = Array.new
@root_filenames = Array.new
+
+ # deprecated
@status = :ready
- @manifest = nil
@file_vendor = nil
@metadata = Chef::Cookbook::Metadata.new
+ @chef_server_rest = chef_server_rest
end
def version
@@ -129,66 +140,10 @@ class Chef
end
def version=(new_version)
- manifest["version"] = new_version
+ cookbook_manifest.reset!
metadata.version(new_version)
end
- # A manifest is a Mash that maps segment names to arrays of manifest
- # records (see #preferred_manifest_record for format of manifest records),
- # as well as describing cookbook metadata. The manifest follows a form
- # like the following:
- #
- # {
- # :cookbook_name = "apache2",
- # :version = "1.0",
- # :name = "Apache 2"
- # :metadata = ???TODO: timh/cw: 5-24-2010: describe this format,
- #
- # :files => [
- # {
- # :name => "afile.rb",
- # :path => "files/ubuntu-9.10/afile.rb",
- # :checksum => "2222",
- # :specificity => "ubuntu-9.10"
- # },
- # ],
- # :templates => [ manifest_record1, ... ],
- # ...
- # }
- def manifest
- unless @manifest
- generate_manifest
- end
- @manifest
- end
-
- def manifest=(new_manifest)
- @manifest = Mash.new new_manifest
- @checksums = extract_checksums_from_manifest(@manifest)
- @manifest_records_by_path = extract_manifest_records_by_path(@manifest)
-
- COOKBOOK_SEGMENTS.each do |segment|
- next unless @manifest.has_key?(segment)
- filenames = @manifest[segment].map{|manifest_record| manifest_record['name']}
-
- replace_segment_filenames(segment, filenames)
- end
- end
-
- # Returns a hash of checksums to either nil or the on disk path (which is
- # done by generate_manifest).
- def checksums
- unless @checksums
- generate_manifest
- end
- @checksums
- end
-
- def manifest_records_by_path
- @manifest_records_by_path || generate_manifest
- @manifest_records_by_path
- end
-
def full_name
"#{name}-#{version}"
end
@@ -209,6 +164,24 @@ class Chef
alias :attribute_files :attribute_filenames
alias :attribute_files= :attribute_filenames=
+ def manifest
+ cookbook_manifest.manifest
+ end
+
+ # Returns a hash of checksums to either nil or the on disk path (which is
+ # done by generate_manifest).
+ def checksums
+ cookbook_manifest.checksums
+ end
+
+ def manifest_records_by_path
+ 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
@@ -311,7 +284,7 @@ class Chef
def preferred_manifest_record(node, segment, filename)
found_pref = find_preferred_manifest_record(node, segment, filename)
if found_pref
- @manifest_records_by_path[found_pref]
+ manifest_records_by_path[found_pref]
else
if segment == :files || segment == :templates
error_message = "Cookbook '#{name}' (#{version}) does not contain a file at any of these locations:\n"
@@ -472,19 +445,6 @@ class Chef
end
private :preferences_for_path
- def to_hash
- result = manifest.dup
- result['frozen?'] = frozen_version?
- result['chef_type'] = 'cookbook_version'
- result.to_hash
- end
-
- def to_json(*a)
- result = to_hash
- result['json_class'] = self.class.name
- Chef::JSONCompat.to_json(result, *a)
- end
-
def self.json_create(o)
cookbook_version = new(o["cookbook_name"])
# We want the Chef::Cookbook::Metadata object to always be inflated
@@ -498,7 +458,11 @@ class Chef
cookbook_version
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(&url_generator)
+ Chef::Log.deprecation("Deprecated method #generate_manifest_with_urls called from #{caller(1).first}")
+
rendered_manifest = manifest.dup
COOKBOOK_SEGMENTS.each do |segment|
if rendered_manifest.has_key?(segment)
@@ -511,6 +475,18 @@ class Chef
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
@@ -528,26 +504,23 @@ class Chef
##
# REST API
##
- def self.chef_server_rest
- Chef::REST.new(Chef::Config[:chef_server_url])
+
+ def save_url
+ # TODO: this should become deprecated when the API for CookbookManifest becomes stable
+ cookbook_manifest.save_url
end
- def chef_server_rest
- self.class.chef_server_rest
+ def force_save_url
+ # TODO: this should become deprecated when the API for CookbookManifest becomes stable
+ cookbook_manifest.force_save_url
end
- # Return the URL to save (PUT) this object to the server via the
- # REST api. If there is an existing document on the server and it
- # is marked frozen, a PUT will result in a 409 Conflict.
- def save_url
- "cookbooks/#{name}/#{version}"
+ def chef_server_rest
+ @chef_server_rest ||= self.chef_server_rest
end
- # Adds the `force=true` parameter to the upload URL. This allows
- # the user to overwrite a frozen cookbook (a PUT against the
- # normal #save_url raises a 409 Conflict in this case).
- def force_save_url
- "cookbooks/#{name}/#{version}?force=true"
+ def self.chef_server_rest
+ Chef::REST.new(Chef::Config[:chef_server_url])
end
def destroy
@@ -603,15 +576,15 @@ class Chef
private
+ def cookbook_manifest
+ @cookbook_manifest ||= CookbookManifest.new(self)
+ end
+
def find_preferred_manifest_record(node, segment, filename)
preferences = preferences_for_path(node, segment, filename)
- # ensure that we generate the manifest, which will also generate
- # @manifest_records_by_path
- manifest
-
# in order of prefernce, look for the filename in the manifest
- preferences.find {|preferred_filename| @manifest_records_by_path[preferred_filename] }
+ preferences.find {|preferred_filename| manifest_records_by_path[preferred_filename] }
end
# For each filename, produce a mapping of base filename (i.e. recipe name
@@ -620,80 +593,6 @@ class Chef
filenames.select{|filename| filename =~ /\.rb$/}.inject({}){|memo, filename| memo[File.basename(filename, '.rb')] = filename ; memo }
end
- # See #manifest for a description of the manifest return value.
- # See #preferred_manifest_record for a description an individual manifest record.
- def generate_manifest
- manifest = Mash.new({
- :recipes => Array.new,
- :definitions => Array.new,
- :libraries => Array.new,
- :attributes => Array.new,
- :files => Array.new,
- :templates => Array.new,
- :resources => Array.new,
- :providers => Array.new,
- :root_files => Array.new
- })
- checksums_to_on_disk_paths = {}
-
- if !root_paths || root_paths.size == 0
- Chef::Log.error("Cookbook #{name} does not have root_paths! Cannot generate manifest.")
- raise "Cookbook #{name} does not have root_paths! Cannot generate manifest."
- end
-
- COOKBOOK_SEGMENTS.each do |segment|
- segment_filenames(segment).each do |segment_file|
- next if File.directory?(segment_file)
-
- path, specificity = parse_segment_file_from_root_paths(segment, segment_file)
- file_name = File.basename(path)
-
- csum = self.class.checksum_cookbook_file(segment_file)
- checksums_to_on_disk_paths[csum] = segment_file
- rs = Mash.new({
- :name => file_name,
- :path => path,
- :checksum => csum,
- :specificity => specificity
- })
-
- manifest[segment] << rs
- end
- end
-
- manifest[:cookbook_name] = name.to_s
- manifest[:metadata] = metadata
- manifest[:version] = metadata.version
- manifest[:name] = full_name
-
- @checksums = checksums_to_on_disk_paths
- @manifest = manifest
- @manifest_records_by_path = extract_manifest_records_by_path(manifest)
- end
-
- def parse_segment_file_from_root_paths(segment, segment_file)
- root_paths.each do |root_path|
- pathname = Chef::Util::PathHelper.relative_path_from(root_path, segment_file)
-
- parts = pathname.each_filename.take(2)
- # Check if path is actually under root_path
- next if parts[0] == '..'
- if segment == :templates || segment == :files
- # Check if pathname looks like files/foo or templates/foo (unscoped)
- if pathname.each_filename.to_a.length == 2
- # Use root_default in case the same path exists at root_default and default
- return [ pathname.to_s, 'root_default' ]
- else
- return [ pathname.to_s, parts[1] ]
- end
- else
- return [ pathname.to_s, 'default' ]
- end
- end
- Chef::Log.error("Cookbook file #{segment_file} not under cookbook root paths #{root_paths.inspect}.")
- raise "Cookbook file #{segment_file} not under cookbook root paths #{root_paths.inspect}."
- end
-
def file_vendor
unless @file_vendor
@file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
@@ -701,27 +600,5 @@ class Chef
@file_vendor
end
- def extract_checksums_from_manifest(manifest)
- checksums = {}
- COOKBOOK_SEGMENTS.each do |segment|
- next unless manifest.has_key?(segment)
- manifest[segment].each do |manifest_record|
- checksums[manifest_record[:checksum]] = nil
- end
- end
- checksums
- end
-
- def extract_manifest_records_by_path(manifest)
- manifest_records_by_path = {}
- COOKBOOK_SEGMENTS.each do |segment|
- next unless manifest.has_key?(segment)
- manifest[segment].each do |manifest_record|
- manifest_records_by_path[manifest_record[:path]] = manifest_record
- end
- end
- manifest_records_by_path
- end
-
end
end