diff options
author | John Keiser <john@johnkeiser.com> | 2015-05-06 18:06:43 -0700 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-06-02 09:53:40 -0700 |
commit | c298a6f52a11fcbe022a75b259cf40ca9168394c (patch) | |
tree | 54134a058317b6c59bb3cfa0e997e2db7fa39871 /lib | |
parent | 71c89b652687021c89a630a00224deccdc5e05a5 (diff) | |
download | chef-c298a6f52a11fcbe022a75b259cf40ca9168394c.tar.gz |
Add specificity matching
Diffstat (limited to 'lib')
-rw-r--r-- | lib/chef/node_map.rb | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb index a7a0389a2a..a0af3b9169 100644 --- a/lib/chef/node_map.rb +++ b/lib/chef/node_map.rb @@ -50,11 +50,20 @@ class Chef def set(key, value, filters = {}, &block) validate_filter!(filters) deprecate_filter!(filters) + new_matcher = { filters: filters, block: block, value: value } @map[key] ||= [] - # we match on the first value we find, so we want to unshift so that the - # last setter wins - # FIXME: need a test for this behavior - @map[key].unshift({ filters: filters, block: block, value: value }) + # 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.) + insert_at = 0 + @map[key].each_with_index do |matcher, index| + if specificity(new_matcher) >= specificity(matcher) + insert_at = index + break + end + end + @map[key].insert(insert_at, new_matcher) self end @@ -89,6 +98,29 @@ class Chef 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].has_key?(:platform_version) + specificity = 8 + elsif matcher[:filters].has_key?(:platform) + specificity = 6 + elsif matcher[:filters].has_key?(:platform_family) + specificity = 4 + elsif matcher[:filters].has_key?(:os) + specificity = 2 + else + specificity = 0 + end + specificity += 1 if matcher[:block] + specificity + end + # only allow valid filter options def validate_filter!(filters) filters.each_key do |key| |