diff options
Diffstat (limited to 'lib/chef/node/attribute.rb')
-rw-r--r-- | lib/chef/node/attribute.rb | 120 |
1 files changed, 49 insertions, 71 deletions
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb index 1ac9c92468..3265d44d92 100644 --- a/lib/chef/node/attribute.rb +++ b/lib/chef/node/attribute.rb @@ -1,7 +1,7 @@ #-- # Author:: Adam Jacob (<adam@chef.io>) # Author:: AJ Christensen (<aj@chef.io>) -# Copyright:: Copyright 2008-2016, Chef Software, Inc. +# Copyright:: Copyright 2008-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ # limitations under the License. # -require "chef/node/mixin/deep_merge_cache" +#require "chef/node/mixin/deep_merge_cache" require "chef/node/mixin/immutablize_hash" require "chef/node/mixin/state_tracking" require "chef/node/immutable_collections" @@ -45,7 +45,7 @@ class Chef # expects. This include should probably be deleted? include Enumerable - include Chef::Node::Mixin::DeepMergeCache + #include Chef::Node::Mixin::DeepMergeCache include Chef::Node::Mixin::StateTracking include Chef::Node::Mixin::ImmutablizeHash @@ -187,6 +187,9 @@ class Chef # return the automatic level attribute component attr_reader :automatic + # return the immutablemash deep merge cache + attr_reader :deep_merge_cache + def initialize(normal, default, override, automatic, node = nil) @default = VividMash.new(default, self, node, :default) @env_default = VividMash.new({}, self, node, :env_default) @@ -202,7 +205,8 @@ class Chef @automatic = VividMash.new(automatic, self, node, :automatic) - super(nil, self, node, :merged) + @deep_merge_cache = ImmutableMash.new({}, self, node, :merged) + @__node__ = node end # Debug what's going on with an attribute. +args+ is a path spec to the @@ -230,6 +234,22 @@ class Chef end end + def reset + @deep_merge_cache = ImmutableMash.new({}, self, @__node__, :merged) + end + + def reset_cache(*path) + if path.empty? + reset + else + container = read(*path) + case container + when Hash, Array + container.reset + end + end + end + # Set the cookbook level default attribute component to +new_data+. def default=(new_data) reset @@ -294,7 +314,7 @@ class Chef # clears attributes from all precedence levels def rm(*args) - with_deep_merged_return_value(self, *args) do + with_deep_merged_return_value(combined_all, *args) do rm_default(*args) rm_normal(*args) rm_override(*args) @@ -341,6 +361,9 @@ class Chef def with_deep_merged_return_value(obj, *path, last) hash = obj.read(*path) return nil unless hash.is_a?(Hash) + # coerce from immutablemash/vividmash to plain-old Hash + # also de-immutablizes and dup's the return value correctly in chef-13 + hash = hash.to_hash ret = hash[last] yield ret @@ -402,16 +425,16 @@ class Chef # all of node['foo'] even if the user only requires node['foo']['bar']['baz']. # - def merged_attributes(*path) - merge_all(path) + def combined_override(*path) + merge_overrides(path) end - def combined_override(*path) - immutablize(merge_overrides(path)) + def combined_all(*path) + path.empty? ? self : read(*path) end def combined_default(*path) - immutablize(merge_defaults(path)) + merge_defaults(path) end def normal_unless(*args) @@ -499,6 +522,14 @@ class Chef merged_attributes.to_s end + def [](key) + @deep_merge_cache[key] + end + + def merged_attributes + @deep_merge_cache + end + def inspect "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map do |iv| "#{iv}=#{instance_variable_get(iv).inspect}" @@ -507,7 +538,14 @@ class Chef private - # Helper method for merge_all/merge_defaults/merge_overrides. + # For elements like Fixnums, true, nil... + def safe_dup(e) + e.dup + rescue TypeError + e + end + + # Helper method for merge_defaults/merge_overrides. # # apply_path(thing, [ "foo", "bar", "baz" ]) = thing["foo"]["bar"]["baz"] # @@ -537,34 +575,6 @@ class Chef end end - # For elements like Fixnums, true, nil... - def safe_dup(e) - e.dup - rescue TypeError - e - end - - # Deep merge all attribute levels using hash-only merging between different precidence - # levels (so override arrays completely replace arrays set at any default level). - # - # The path allows for selectively deep-merging a subtree of the node object. - # - # @param path [Array] Array of args to method chain to descend into the node object - # @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object - def merge_all(path) - components = [ - merge_defaults(path), - apply_path(@normal, path), - merge_overrides(path), - apply_path(@automatic, path), - ] - - ret = components.inject(NIL) do |merged, component| - hash_only_merge!(merged, component) - end - ret == NIL ? nil : ret - end - # Deep merge the default attribute levels with array merging. # # The path allows for selectively deep-merging a subtree of the node object. @@ -636,38 +646,6 @@ class Chef end end - # @api private - def hash_only_merge!(merge_onto, merge_with) - # If there are two Hashes, recursively merge. - if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash) - merge_with.each do |key, merge_with_value| - value = - if merge_onto.has_key?(key) - hash_only_merge!(safe_dup(merge_onto[key]), merge_with_value) - else - merge_with_value - end - - # internal_set bypasses converting keys, does convert values and allows writing to immutable mashes - merge_onto.internal_set(key, value) - end - merge_onto - - # If merge_with is nil, don't replace merge_onto - elsif merge_with.nil? - merge_onto - - # In all other cases, replace merge_onto with merge_with - else - if merge_with.kind_of?(Hash) - Chef::Node::ImmutableMash.new(merge_with) - elsif merge_with.kind_of?(Array) - Chef::Node::ImmutableArray.new(merge_with) - else - merge_with - end - end - end end end end |