diff options
Diffstat (limited to 'chef/lib/chef/cookbook_version_selector.rb')
-rw-r--r-- | chef/lib/chef/cookbook_version_selector.rb | 168 |
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 |