summaryrefslogtreecommitdiff
path: root/chef/lib/chef/cookbook_version_selector.rb
diff options
context:
space:
mode:
Diffstat (limited to 'chef/lib/chef/cookbook_version_selector.rb')
-rw-r--r--chef/lib/chef/cookbook_version_selector.rb168
1 files changed, 0 insertions, 168 deletions
diff --git a/chef/lib/chef/cookbook_version_selector.rb b/chef/lib/chef/cookbook_version_selector.rb
deleted file mode 100644
index 9e60f85639..0000000000
--- a/chef/lib/chef/cookbook_version_selector.rb
+++ /dev/null
@@ -1,168 +0,0 @@
-#
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-require 'dep_selector'
-
-class Chef
- module CookbookVersionSelector
- # This method replaces verbiage from DepSelector messages with
- # Chef-domain-specific verbiage, such as replacing package with
- # cookbook.
- #
- # TODO [cw, 2011/2/25]: this is a near-term hack. In the long run,
- # we'll do this better.
- def self.filter_dep_selector_message(message)
- m = message
- m.gsub!("Package", "Cookbook")
- m.gsub!("package", "cookbook")
- m.gsub!("Solution constraint", "Run list item")
- m.gsub!("solution constraint", "run list item")
- m
- end
-
- # all_cookbooks - a hash mapping cookbook names to an array of
- # available CookbookVersions.
- #
- # Creates a DependencyGraph from CookbookVersion objects
- def self.create_dependency_graph_from_cookbooks(all_cookbooks)
- dep_graph = DepSelector::DependencyGraph.new
-
- all_cookbooks.each do |cb_name, cb_versions|
- cb_versions.each do |cb_version|
- cb_version_deps = cb_version.metadata.dependencies
- # TODO [cw. 2011/2/10]: CookbookVersion#version returns a
- # String even though we're storing as a DepSelector::Version
- # object underneath. This should be changed so that we
- # return the object and handle proper serialization and
- # de-serialization. For now, I'm just going to create a
- # Version object from the String representation.
- pv = dep_graph.package(cb_name).add_version(Chef::Version.new(cb_version.version))
- cb_version_deps.each_pair do |dep_name, constraint_str|
- # if the dependency is specified as cookbook::recipe,
- # extract the cookbook component
- dep_cb_name = dep_name.split("::").first
- constraint = Chef::VersionConstraint.new(constraint_str)
- pv.dependencies << DepSelector::Dependency.new(dep_graph.package(dep_cb_name), constraint)
- end
- end
- end
-
- dep_graph
- end
-
- # Return a hash mapping cookbook names to a CookbookVersion
- # object. If there is no solution that satisfies the constraints,
- # the first run list item that caused unsatisfiability is
- # returned.
- #
- # This is the final version-resolved list of cookbooks for the
- # RunList.
- #
- # all_cookbooks - a hash mapping cookbook names to an array of
- # available CookbookVersions.
- #
- # recipe_constraints - an array of hashes describing the expanded
- # run list. Each element is a hash containing keys :name and
- # :version_constraint. The :name component is either the
- # fully-qualified recipe name (e.g. "cookbook1::non_default_recipe")
- # or just a cookbook name, indicating the default recipe is to be
- # run (e.g. "cookbook1").
- def self.constrain(all_cookbooks, recipe_constraints)
- dep_graph = create_dependency_graph_from_cookbooks(all_cookbooks)
-
- # extract cookbook names from (possibly) fully-qualified recipe names
- cookbook_constraints = recipe_constraints.map do |recipe_spec|
- cookbook_name = (recipe_spec[:name][/^(.+)::/, 1] || recipe_spec[:name])
- DepSelector::SolutionConstraint.new(dep_graph.package(cookbook_name),
- recipe_spec[:version_constraint])
- end
-
- # Pass in the list of all available cookbooks (packages) so that
- # DepSelector can distinguish between "no version available for
- # cookbook X" and "no such cookbook X" when an environment
- # filters out all versions for a given cookbook.
- all_packages = all_cookbooks.inject([]) do |acc, (cookbook_name, cookbook_versions)|
- acc << dep_graph.package(cookbook_name)
- acc
- end
-
- # find a valid assignment of CoookbookVersions. If no valid
- # assignment exists, indicate which run_list_item causes the
- # unsatisfiability and try to hint at what might be wrong.
- soln =
- begin
- DepSelector::Selector.new(dep_graph).find_solution(cookbook_constraints, all_packages)
- rescue DepSelector::Exceptions::InvalidSolutionConstraints => e
- non_existent_cookbooks = e.non_existent_packages.map {|constraint| constraint.package.name}
- cookbooks_with_no_matching_versions = e.constrained_to_no_versions.map {|constraint| constraint.package.name}
-
- # Spend a whole lot of effort for pluralizing and
- # prettifying the message.
- message = ""
- if non_existent_cookbooks.length > 0
- message += "no such " + (non_existent_cookbooks.length > 1 ? "cookbooks" : "cookbook")
- message += " #{non_existent_cookbooks.join(", ")}"
- end
-
- if cookbooks_with_no_matching_versions.length > 0
- if message.length > 0
- message += "; "
- end
-
- message += "no versions match the constraints on " + (cookbooks_with_no_matching_versions.length > 1 ? "cookbooks" : "cookbook")
- message += " #{cookbooks_with_no_matching_versions.join(", ")}"
- end
-
- message = "Run list contains invalid items: #{message}."
-
- raise Chef::Exceptions::CookbookVersionSelection::InvalidRunListItems.new(message, non_existent_cookbooks, cookbooks_with_no_matching_versions)
- rescue DepSelector::Exceptions::NoSolutionExists => e
- raise Chef::Exceptions::CookbookVersionSelection::UnsatisfiableRunListItem.new(filter_dep_selector_message(e.message), e.unsatisfiable_solution_constraint, e.disabled_non_existent_packages, e.disabled_most_constrained_packages)
- end
-
-
- # map assignment back to CookbookVersion objects
- selected_cookbooks = {}
- soln.each_pair do |cb_name, cb_version|
- # TODO [cw, 2011/2/10]: related to the TODO in
- # create_dependency_graph_from_cookbooks, cbv.version
- # currently returns a String, so we must compare to
- # cb_version.to_s, since it's a for-real Version object.
- selected_cookbooks[cb_name] = all_cookbooks[cb_name].find{|cbv| cbv.version == cb_version.to_s}
- end
- selected_cookbooks
- end
-
- # Expands the run_list, constrained to the environment's CookbookVersion
- # constraints.
- #
- # Returns:
- # Hash of: name to CookbookVersion
- def self.expand_to_cookbook_versions(run_list, environment, couchdb=nil)
- # expand any roles in this run_list.
- expanded_run_list = run_list.expand(environment, 'couchdb', :couchdb => couchdb).recipes.with_version_constraints
-
- cookbooks_for_environment = Chef::Environment.cdb_minimal_filtered_versions(environment, couchdb)
- cookbook_collection = constrain(cookbooks_for_environment, expanded_run_list)
- full_cookbooks = Chef::MinimalCookbookVersion.load_full_versions_of(cookbook_collection.values, couchdb)
- full_cookbooks.inject({}) do |cb_map, cookbook_version|
- cb_map[cookbook_version.name] = cookbook_version
- cb_map
- end
- end
- end
-end