diff options
author | John Keiser <john@johnkeiser.com> | 2015-06-16 16:27:52 -0700 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-06-18 15:07:48 -0700 |
commit | db59fd9392a97328df8d7ba7f1c2b1fc03058e76 (patch) | |
tree | a5ec9072139c642ffb39d80866512ad0150dfaf5 /lib | |
parent | 59717769a12768c62aa18270a51b91c820b67010 (diff) | |
download | chef-db59fd9392a97328df8d7ba7f1c2b1fc03058e76.tar.gz |
Sort identical "provides" alphabetically (for backcompat)
- Warn when multiple providers try to provide the same thing
Diffstat (limited to 'lib')
-rw-r--r-- | lib/chef/chef_class.rb | 8 | ||||
-rw-r--r-- | lib/chef/node_map.rb | 101 | ||||
-rw-r--r-- | lib/chef/platform/priority_map.rb | 50 | ||||
-rw-r--r-- | lib/chef/platform/provider_mapping.rb | 4 | ||||
-rw-r--r-- | lib/chef/platform/provider_priority_map.rb | 24 | ||||
-rw-r--r-- | lib/chef/platform/resource_priority_map.rb | 27 | ||||
-rw-r--r-- | lib/chef/provider.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/service/debian.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/service/insserv.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/service/invokercd.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/service/redhat.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/service/upstart.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/user.rb | 2 | ||||
-rw-r--r-- | lib/chef/resource.rb | 2 | ||||
-rw-r--r-- | lib/chef/resource/macports_package.rb | 3 | ||||
-rw-r--r-- | lib/chef/resource/package.rb | 5 |
16 files changed, 131 insertions, 107 deletions
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb index f1dd797c04..a0c74f7aec 100644 --- a/lib/chef/chef_class.rb +++ b/lib/chef/chef_class.rb @@ -58,7 +58,7 @@ class Chef # @return [Array<Class>] Priority Array of Provider Classes to use for the resource_name on the node # def get_provider_priority_array(resource_name) - result = provider_priority_map.get_priority_array(node, resource_name) + result = provider_priority_map.get_priority_array(node, resource_name.to_sym) result = result.dup if result result end @@ -71,7 +71,7 @@ class Chef # @return [Array<Class>] Priority Array of Resource Classes to use for the resource_name on the node # def get_resource_priority_array(resource_name) - result = resource_priority_map.get_priority_array(node, resource_name) + result = resource_priority_map.get_priority_array(node, resource_name.to_sym) result = result.dup if result result end @@ -86,7 +86,7 @@ class Chef # @return [Array<Class>] Modified Priority Array of Provider Classes to use for the resource_name on the node # def set_provider_priority_array(resource_name, priority_array, *filter, &block) - result = provider_priority_map.set_priority_array(resource_name, priority_array, *filter, &block) + result = provider_priority_map.set_priority_array(resource_name.to_sym, priority_array, *filter, &block) result = result.dup if result result end @@ -101,7 +101,7 @@ class Chef # @return [Array<Class>] Modified Priority Array of Resource Classes to use for the resource_name on the node # def set_resource_priority_array(resource_name, priority_array, *filter, &block) - result = resource_priority_map.set_priority_array(resource_name, priority_array, *filter, &block) + result = resource_priority_map.set_priority_array(resource_name.to_sym, priority_array, *filter, &block) result = result.dup if result result end diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb index f547018a38..d5eed7c215 100644 --- a/lib/chef/node_map.rb +++ b/lib/chef/node_map.rb @@ -38,30 +38,35 @@ class Chef # # @return [NodeMap] Returns self for possible chaining # - def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, &block) + def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, override: nil, &block) Chef::Log.deprecation "The on_platform option to node_map has been deprecated" if on_platform Chef::Log.deprecation "The on_platforms option to node_map has been deprecated" if on_platforms platform ||= on_platform || on_platforms - filters = { platform: platform, platform_version: platform_version, platform_family: platform_family, os: os } - new_matcher = { filters: filters, block: block, value: value, canonical: canonical } - @map[key] ||= [] - # Decide where to insert the matcher; the new value is preferred over - # anything more specific (see `priority_of`) and is preferred over older - # values of the same specificity. (So all other things being equal, - # newest wins.) + filters = {} + filters[:platform] = platform if platform + filters[:platform_version] = platform_version if platform_version + filters[:platform_family] = platform_family if platform_family + filters[:os] = os if os + new_matcher = { value: value, filters: filters } + new_matcher[:block] = block if block + new_matcher[:canonical] = canonical if canonical + new_matcher[:override] = override if override + + # The map is sorted in order of preference already; we just need to find + # our place in it (just before the first value with the same preference level). insert_at = nil - @map[key].each_with_index do |matcher, index| - if specificity(new_matcher) >= specificity(matcher) - insert_at = index - break - end + @map[key] ||= [] + @map[key].each_with_index do |matcher,index| + cmp = compare_matchers(key, new_matcher, matcher) + insert_at ||= index if cmp && cmp <= 0 end if insert_at @map[key].insert(insert_at, new_matcher) else @map[key] << new_matcher end - self + insert_at ||= @map[key].size - 1 + @map end # @@ -116,30 +121,7 @@ class Chef remaining end - private - - # - # Gives a value for "how specific" the matcher is. - # Things which specify more specific filters get a higher number - # (platform_version > platform > platform_family > os); things - # with a block have higher specificity than similar things without - # a block. - # - def specificity(matcher) - if matcher[:filters][:platform_version] - specificity = 8 - elsif matcher[:filters][:platform] - specificity = 6 - elsif matcher[:filters][:platform_family] - specificity = 4 - elsif matcher[:filters][:os] - specificity = 2 - else - specificity = 0 - end - specificity += 1 if matcher[:block] - specificity - end + protected # # Succeeds if: @@ -197,5 +179,48 @@ class Chef return true if canonical.nil? !!canonical == !!matcher[:canonical] end + + def compare_matchers(key, new_matcher, matcher) + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:block] } + return cmp if cmp != 0 + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_version] } + return cmp if cmp != 0 + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform] } + return cmp if cmp != 0 + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_family] } + return cmp if cmp != 0 + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:os] } + return cmp if cmp != 0 + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:override] } + return cmp if cmp != 0 + # If all things are identical, return 0 + 0 + end + + def compare_matcher_properties(new_matcher, matcher) + a = yield(new_matcher) + b = yield(matcher) + + # Check for blcacklists ('!windows'). Those always come *after* positive + # whitelists. + a_negated = Array(a).any? { |f| f.is_a?(String) && f.start_with?('!') } + b_negated = Array(b).any? { |f| f.is_a?(String) && f.start_with?('!') } + if a_negated != b_negated + return 1 if a_negated + return -1 if b_negated + end + + # We treat false / true and nil / not-nil with the same comparison + a = nil if a == false + b = nil if b == false + cmp = a <=> b + # This is the case where one is non-nil, and one is nil. The one that is + # nil is "greater" (i.e. it should come last). + if cmp.nil? + return 1 if a.nil? + return -1 if b.nil? + end + cmp + end end end diff --git a/lib/chef/platform/priority_map.rb b/lib/chef/platform/priority_map.rb new file mode 100644 index 0000000000..3608975b51 --- /dev/null +++ b/lib/chef/platform/priority_map.rb @@ -0,0 +1,50 @@ +require 'chef/node_map' + +class Chef + class Platform + class PriorityMap < Chef::NodeMap + # @api private + def get_priority_array(node, key) + get(node, key) + end + + # @api private + def set_priority_array(key, priority_array, *filter, &block) + priority_array = Array(priority_array) + set(key, priority_array, *filter, &block) + priority_array + end + + # @api private + def list_handlers(node, key, **filters) + list(node, key, **filters).flatten(1).uniq + end + + # + # Priority maps have one extra precedence: priority arrays override "provides," + # and "provides" lines with identical filters sort by class name (ascending). + # + def compare_matchers(key, new_matcher, matcher) + # Priority arrays come before "provides" + if new_matcher[:value].is_a?(Array) != matcher[:value].is_a?(Array) + return new_matcher[:value].is_a?(Array) ? -1 : 1 + end + + cmp = super + if cmp == 0 + # Sort by class name (ascending) as well, if all other properties + # are exactly equal + if new_matcher[:value].is_a?(Class) && !new_matcher[:override] + cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:value].name } + if cmp < 0 + Chef::Log.warn "You are overriding #{key} on #{new_matcher[:filters].inspect} with #{new_matcher[:value].inspect}: used to be #{matcher[:value].inspect}. Use override: true if this is what you intended." + elsif cmp > 0 + Chef::Log.warn "You declared a new resource #{new_matcher[:value].inspect} for resource #{key}, but it comes alphabetically after #{matcher[:value].inspect} and has the same filters (#{new_matcher[:filters].inspect}), so it will not be used. Use override: true if you want to use it for #{key}." + end + end + end + cmp + end + end + end +end diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb index e3a894c8ac..af17d8e1b4 100644 --- a/lib/chef/platform/provider_mapping.rb +++ b/lib/chef/platform/provider_mapping.rb @@ -201,8 +201,8 @@ class Chef begin result = Chef::Provider.const_get(class_name) - Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'provides #{convert_to_snake_case(class_name).to_sym.inspect}'.") - Chef::Log.warn("This will no longer work in Chef 13: you must use 'provides' to provide DSL.") + Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'resource_name #{convert_to_snake_case(class_name).to_sym.inspect}'.") + Chef::Log.warn("This will no longer work in Chef 13: you must use 'resource_name' to provide DSL.") rescue NameError end end diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb index 9d703c9178..5599c74c2d 100644 --- a/lib/chef/platform/provider_priority_map.rb +++ b/lib/chef/platform/provider_priority_map.rb @@ -1,29 +1,11 @@ require 'singleton' +require 'chef/platform/priority_map' class Chef class Platform - class ProviderPriorityMap + # @api private + class ProviderPriorityMap < Chef::Platform::PriorityMap include Singleton - - def get_priority_array(node, resource_name) - priority_map.get(node, resource_name.to_sym) - end - - def set_priority_array(resource_name, priority_array, *filter, &block) - priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block) - end - - # @api private - def list_handlers(node, resource_name) - priority_map.list(node, resource_name.to_sym).flatten(1).uniq - end - - private - - def priority_map - require 'chef/node_map' - @priority_map ||= Chef::NodeMap.new - end end end end diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb index fb08debc53..aa57e3ddf0 100644 --- a/lib/chef/platform/resource_priority_map.rb +++ b/lib/chef/platform/resource_priority_map.rb @@ -1,34 +1,17 @@ require 'singleton' +require 'chef/platform/priority_map' class Chef class Platform - class ResourcePriorityMap + # @api private + class ResourcePriorityMap < Chef::Platform::PriorityMap include Singleton - def get_priority_array(node, resource_name, canonical: nil) - priority_map.get(node, resource_name.to_sym, canonical: canonical) - end - - def set_priority_array(resource_name, priority_array, *filter, &block) - priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block) - end - # @api private - def delete_canonical(resource_name, resource_class) - priority_map.delete_canonical(resource_name, resource_class) - end - - # @api private - def list_handlers(*args) - priority_map.list(*args).flatten(1).uniq + def get_priority_array(node, resource_name, canonical: nil) + super(node, resource_name.to_sym, canonical: canonical) end - private - - def priority_map - require 'chef/node_map' - @priority_map ||= Chef::NodeMap.new - end end end end diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb index e50e374804..131b72cd23 100644 --- a/lib/chef/provider.rb +++ b/lib/chef/provider.rb @@ -176,7 +176,7 @@ class Chef end def self.provides(short_name, opts={}, &block) - Chef.set_provider_priority_array(short_name, self, opts, &block) + Chef.provider_priority_map.set(short_name, self, opts, &block) end def self.provides?(node, resource) diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb index 01505924cb..c67f3f05da 100644 --- a/lib/chef/provider/service/debian.rb +++ b/lib/chef/provider/service/debian.rb @@ -25,8 +25,6 @@ class Chef UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i - provides :service, platform_family: "debian" - def self.provides?(node, resource) super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian) end diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb index 31965a4bc6..4534e33f32 100644 --- a/lib/chef/provider/service/insserv.rb +++ b/lib/chef/provider/service/insserv.rb @@ -24,8 +24,6 @@ class Chef class Service class Insserv < Chef::Provider::Service::Init - provides :service, os: "linux" - def self.provides?(node, resource) super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv) end diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb index 5ff24e0dbb..fdf4cbc256 100644 --- a/lib/chef/provider/service/invokercd.rb +++ b/lib/chef/provider/service/invokercd.rb @@ -23,8 +23,6 @@ class Chef class Service class Invokercd < Chef::Provider::Service::Init - provides :service, platform_family: "debian" - def self.provides?(node, resource) super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd) end diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb index 850953125e..a8deb13aec 100644 --- a/lib/chef/provider/service/redhat.rb +++ b/lib/chef/provider/service/redhat.rb @@ -26,8 +26,6 @@ class Chef CHKCONFIG_ON = /\d:on/ CHKCONFIG_MISSING = /No such/ - provides :service, platform_family: [ "rhel", "fedora", "suse" ] - def self.provides?(node, resource) super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat) end diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb index 8d4aa41035..d8ce6af649 100644 --- a/lib/chef/provider/service/upstart.rb +++ b/lib/chef/provider/service/upstart.rb @@ -27,8 +27,6 @@ class Chef class Upstart < Chef::Provider::Service::Simple UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/ - provides :service, os: "linux" - def self.provides?(node, resource) super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) end diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb index ad92a72a0a..244b11db98 100644 --- a/lib/chef/provider/user.rb +++ b/lib/chef/provider/user.rb @@ -23,8 +23,6 @@ require 'etc' class Chef class Provider class User < Chef::Provider - provides :user - include Chef::Mixin::Command attr_accessor :user_exists, :locked diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 10ad184506..418b0dc1ce 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -1143,7 +1143,7 @@ class Chef remove_canonical_dsl end - result = Chef.set_resource_priority_array(name, self, options, &block) + result = Chef.resource_priority_map.set(name, self, options, &block) Chef::DSL::Resources.add_resource_dsl(name) result end diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb index 937839b6e1..5843016897 100644 --- a/lib/chef/resource/macports_package.rb +++ b/lib/chef/resource/macports_package.rb @@ -16,10 +16,11 @@ # limitations under the License. # +require 'chef/resource/package' + class Chef class Resource class MacportsPackage < Chef::Resource::Package - provides :package, os: "darwin" end end end diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb index 1c6da75678..5be1c34b89 100644 --- a/lib/chef/resource/package.rb +++ b/lib/chef/resource/package.rb @@ -100,8 +100,3 @@ class Chef end end end - -require 'chef/chef_class' -require 'chef/resource/homebrew_package' - -Chef.set_resource_priority_array :package, Chef::Resource::HomebrewPackage, os: "darwin" |