summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2015-06-16 16:27:52 -0700
committerJohn Keiser <john@johnkeiser.com>2015-06-18 15:07:48 -0700
commitdb59fd9392a97328df8d7ba7f1c2b1fc03058e76 (patch)
treea5ec9072139c642ffb39d80866512ad0150dfaf5 /lib
parent59717769a12768c62aa18270a51b91c820b67010 (diff)
downloadchef-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.rb8
-rw-r--r--lib/chef/node_map.rb101
-rw-r--r--lib/chef/platform/priority_map.rb50
-rw-r--r--lib/chef/platform/provider_mapping.rb4
-rw-r--r--lib/chef/platform/provider_priority_map.rb24
-rw-r--r--lib/chef/platform/resource_priority_map.rb27
-rw-r--r--lib/chef/provider.rb2
-rw-r--r--lib/chef/provider/service/debian.rb2
-rw-r--r--lib/chef/provider/service/insserv.rb2
-rw-r--r--lib/chef/provider/service/invokercd.rb2
-rw-r--r--lib/chef/provider/service/redhat.rb2
-rw-r--r--lib/chef/provider/service/upstart.rb2
-rw-r--r--lib/chef/provider/user.rb2
-rw-r--r--lib/chef/resource.rb2
-rw-r--r--lib/chef/resource/macports_package.rb3
-rw-r--r--lib/chef/resource/package.rb5
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"