chef 13.7.16 → 13.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/VERSION +1 -1
 - data/distro/common/man/man8/chef-solo.8 +1 -1
 - data/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb +1 -1
 - data/lib/chef/knife/bootstrap.rb +1 -1
 - data/lib/chef/knife/search.rb +3 -1
 - data/lib/chef/knife/ssh.rb +5 -7
 - data/lib/chef/node/attribute.rb +70 -46
 - data/lib/chef/node/attribute_collections.rb +5 -5
 - data/lib/chef/node/common_api.rb +1 -1
 - data/lib/chef/node/immutable_collections.rb +23 -180
 - data/lib/chef/node/mixin/state_tracking.rb +6 -6
 - data/lib/chef/node_map.rb +26 -0
 - data/lib/chef/provider/remote_file/http.rb +8 -3
 - data/lib/chef/resource/log.rb +1 -1
 - data/lib/chef/resource/windows_task.rb +4 -4
 - data/lib/chef/version.rb +1 -1
 - data/spec/functional/mixin/powershell_out_spec.rb +5 -21
 - data/spec/spec_helper.rb +19 -1
 - data/spec/unit/daemon_spec.rb +21 -12
 - data/spec/unit/mixin/powershell_type_coercions_spec.rb +6 -7
 - data/spec/unit/node/attribute_spec.rb +24 -55
 - data/spec/unit/node/immutable_collections_spec.rb +16 -30
 - data/spec/unit/node/vivid_mash_spec.rb +10 -27
 - data/spec/unit/node_map_spec.rb +29 -4
 - data/spec/unit/provider/remote_file/http_spec.rb +6 -8
 - data/spec/unit/resource/windows_task_spec.rb +9 -1
 - metadata +4 -4
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 4cf91005817c8edd084d2eef52e54b9a320c79e8
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: d64f227f12314884d0f77a6a16fac2465251cd1c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 6593a7a47e0e16c9bae832c21f7fe19eab191fb005160f8094b88303a42bb8c0709e806c9d35a18ae15155782b1936454c58ec426089c995ceafe8fd95442da6
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 802c38b93e6acf6e95961f854aa14ae65eed72f8d4b64b4dd80ba7835812b87ae3239ee657cb2f501ff40987ae872908cb2106c7451e98b06f8dca1aaeed7f74
         
     | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            13. 
     | 
| 
      
 1 
     | 
    
         
            +
            13.8.0
         
     | 
| 
         @@ -79,7 +79,7 @@ The configuration file to use. 
     | 
|
| 
       79 
79 
     | 
    
         
             
            .B \fB\-d\fP, \fB\-\-daemonize\fP
         
     | 
| 
       80 
80 
     | 
    
         
             
            Use to run the executable as a daemon.  This option may not be used in the same command with the \fB\-\-[no\-]fork\fP option.
         
     | 
| 
       81 
81 
     | 
    
         
             
            .sp
         
     | 
| 
       82 
     | 
    
         
            -
            This option is only available on machines that run in UNIX or Linux environments. For machines that are running Microsoft Windows that require similar functionality, use the \fBchef\-client::service\fP recipe in the \fBchef\-client\fP cookbook: \fI\%http://community.opscode.com/cookbooks/chef\-client\fP\&. 
     | 
| 
      
 82 
     | 
    
         
            +
            This option is only available on machines that run in UNIX or Linux environments. For machines that are running Microsoft Windows that require similar functionality, use the \fBchef\-client::service\fP recipe in the \fBchef\-client\fP cookbook: \fI\%http://community.opscode.com/cookbooks/chef\-client\fP\&.  This will install a chef\-client service under Microsoft Windows using the Windows Service Wrapper\&.
         
     | 
| 
       83 
83 
     | 
    
         
             
            .TP
         
     | 
| 
       84 
84 
     | 
    
         
             
            .B \fB\-E ENVIRONMENT_NAME\fP, \fB\-\-environment ENVIRONMENT_NAME\fP
         
     | 
| 
       85 
85 
     | 
    
         
             
            The name of the environment.
         
     | 
| 
         @@ -5,7 +5,7 @@ class Chef 
     | 
|
| 
       5 
5 
     | 
    
         
             
                module DataHandler
         
     | 
| 
       6 
6 
     | 
    
         
             
                  class OrganizationInvitesDataHandler < DataHandlerBase
         
     | 
| 
       7 
7 
     | 
    
         
             
                    def normalize(invites, entry)
         
     | 
| 
       8 
     | 
    
         
            -
                      invites.map { |invite| invite.is_a?(Hash) ? invite["username"] : invite }.sort.uniq
         
     | 
| 
      
 8 
     | 
    
         
            +
                      invites.map { |invite| invite.is_a?(Hash) ? invite["username"] : invite }.compact.sort.uniq
         
     | 
| 
       9 
9 
     | 
    
         
             
                    end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                    def minimize(invites, entry)
         
     | 
    
        data/lib/chef/knife/bootstrap.rb
    CHANGED
    
    | 
         @@ -448,7 +448,7 @@ class Chef 
     | 
|
| 
       448 
448 
     | 
    
         
             
                    ssh.config[:ssh_identity_file] = config[:ssh_identity_file] || config[:identity_file]
         
     | 
| 
       449 
449 
     | 
    
         
             
                    ssh.config[:manual] = true
         
     | 
| 
       450 
450 
     | 
    
         
             
                    ssh.config[:host_key_verify] = config[:host_key_verify]
         
     | 
| 
       451 
     | 
    
         
            -
                    ssh.config[:on_error] =  
     | 
| 
      
 451 
     | 
    
         
            +
                    ssh.config[:on_error] = true
         
     | 
| 
       452 
452 
     | 
    
         
             
                    ssh
         
     | 
| 
       453 
453 
     | 
    
         
             
                  end
         
     | 
| 
       454 
454 
     | 
    
         | 
    
        data/lib/chef/knife/search.rb
    CHANGED
    
    | 
         @@ -98,7 +98,9 @@ class Chef 
     | 
|
| 
       98 
98 
     | 
    
         
             
                    begin
         
     | 
| 
       99 
99 
     | 
    
         
             
                      q.search(@type, @query, search_args) do |item|
         
     | 
| 
       100 
100 
     | 
    
         
             
                        formatted_item = Hash.new
         
     | 
| 
       101 
     | 
    
         
            -
                        if  
     | 
| 
      
 101 
     | 
    
         
            +
                        if config[:id_only]
         
     | 
| 
      
 102 
     | 
    
         
            +
                          formatted_item = format_for_display({ "id" => item["__display_name"] })
         
     | 
| 
      
 103 
     | 
    
         
            +
                        elsif item.is_a?(Hash)
         
     | 
| 
       102 
104 
     | 
    
         
             
                          # doing a little magic here to set the correct name
         
     | 
| 
       103 
105 
     | 
    
         
             
                          formatted_item[item["__display_name"]] = item.reject { |k| k == "__display_name" }
         
     | 
| 
       104 
106 
     | 
    
         
             
                        else
         
     | 
    
        data/lib/chef/knife/ssh.rb
    CHANGED
    
    | 
         @@ -125,7 +125,7 @@ class Chef 
     | 
|
| 
       125 
125 
     | 
    
         
             
                    :long => "--exit-on-error",
         
     | 
| 
       126 
126 
     | 
    
         
             
                    :description => "Immediately exit if an error is encountered",
         
     | 
| 
       127 
127 
     | 
    
         
             
                    :boolean => true,
         
     | 
| 
       128 
     | 
    
         
            -
                    : 
     | 
| 
      
 128 
     | 
    
         
            +
                    :default => false
         
     | 
| 
       129 
129 
     | 
    
         | 
| 
       130 
130 
     | 
    
         
             
                  option :tmux_split,
         
     | 
| 
       131 
131 
     | 
    
         
             
                    :long => "--tmux-split",
         
     | 
| 
         @@ -134,15 +134,13 @@ class Chef 
     | 
|
| 
       134 
134 
     | 
    
         
             
                    :default => false
         
     | 
| 
       135 
135 
     | 
    
         | 
| 
       136 
136 
     | 
    
         
             
                  def session
         
     | 
| 
       137 
     | 
    
         
            -
                    config[:on_error] ||= :skip
         
     | 
| 
       138 
137 
     | 
    
         
             
                    ssh_error_handler = Proc.new do |server|
         
     | 
| 
       139 
     | 
    
         
            -
                       
     | 
| 
       140 
     | 
    
         
            -
                      when :skip
         
     | 
| 
       141 
     | 
    
         
            -
                        ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
         
     | 
| 
       142 
     | 
    
         
            -
                        $!.backtrace.each { |l| Chef::Log.debug(l) }
         
     | 
| 
       143 
     | 
    
         
            -
                      when :raise
         
     | 
| 
      
 138 
     | 
    
         
            +
                      if config[:on_error]
         
     | 
| 
       144 
139 
     | 
    
         
             
                        #Net::SSH::Multi magic to force exception to be re-raised.
         
     | 
| 
       145 
140 
     | 
    
         
             
                        throw :go, :raise
         
     | 
| 
      
 141 
     | 
    
         
            +
                      else
         
     | 
| 
      
 142 
     | 
    
         
            +
                        ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
         
     | 
| 
      
 143 
     | 
    
         
            +
                        $!.backtrace.each { |l| Chef::Log.debug(l) }
         
     | 
| 
       146 
144 
     | 
    
         
             
                      end
         
     | 
| 
       147 
145 
     | 
    
         
             
                    end
         
     | 
| 
       148 
146 
     | 
    
         | 
    
        data/lib/chef/node/attribute.rb
    CHANGED
    
    | 
         @@ -17,6 +17,7 @@ 
     | 
|
| 
       17 
17 
     | 
    
         
             
            # limitations under the License.
         
     | 
| 
       18 
18 
     | 
    
         
             
            #
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
      
 20 
     | 
    
         
            +
            require "chef/node/mixin/deep_merge_cache"
         
     | 
| 
       20 
21 
     | 
    
         
             
            require "chef/node/mixin/immutablize_hash"
         
     | 
| 
       21 
22 
     | 
    
         
             
            require "chef/node/mixin/state_tracking"
         
     | 
| 
       22 
23 
     | 
    
         
             
            require "chef/node/immutable_collections"
         
     | 
| 
         @@ -44,6 +45,7 @@ class Chef 
     | 
|
| 
       44 
45 
     | 
    
         
             
                  # expects.  This include should probably be deleted?
         
     | 
| 
       45 
46 
     | 
    
         
             
                  include Enumerable
         
     | 
| 
       46 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
                  include Chef::Node::Mixin::DeepMergeCache
         
     | 
| 
       47 
49 
     | 
    
         
             
                  include Chef::Node::Mixin::StateTracking
         
     | 
| 
       48 
50 
     | 
    
         
             
                  include Chef::Node::Mixin::ImmutablizeHash
         
     | 
| 
       49 
51 
     | 
    
         | 
| 
         @@ -185,9 +187,6 @@ class Chef 
     | 
|
| 
       185 
187 
     | 
    
         
             
                   # return the automatic level attribute component
         
     | 
| 
       186 
188 
     | 
    
         
             
                  attr_reader :automatic
         
     | 
| 
       187 
189 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
                  # return the immutablemash deep merge cache
         
     | 
| 
       189 
     | 
    
         
            -
                  attr_reader :deep_merge_cache
         
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
190 
     | 
    
         
             
                  def initialize(normal, default, override, automatic, node = nil)
         
     | 
| 
       192 
191 
     | 
    
         
             
                    @default        = VividMash.new(default, self, node, :default)
         
     | 
| 
       193 
192 
     | 
    
         
             
                    @env_default    = VividMash.new({}, self, node, :env_default)
         
     | 
| 
         @@ -203,8 +202,7 @@ class Chef 
     | 
|
| 
       203 
202 
     | 
    
         | 
| 
       204 
203 
     | 
    
         
             
                    @automatic      = VividMash.new(automatic, self, node, :automatic)
         
     | 
| 
       205 
204 
     | 
    
         | 
| 
       206 
     | 
    
         
            -
                     
     | 
| 
       207 
     | 
    
         
            -
                    @__node__ = node
         
     | 
| 
      
 205 
     | 
    
         
            +
                    super(nil, self, node, :merged)
         
     | 
| 
       208 
206 
     | 
    
         
             
                  end
         
     | 
| 
       209 
207 
     | 
    
         | 
| 
       210 
208 
     | 
    
         
             
                   # Debug what's going on with an attribute. +args+ is a path spec to the
         
     | 
| 
         @@ -228,22 +226,6 @@ class Chef 
     | 
|
| 
       228 
226 
     | 
    
         
             
                    end
         
     | 
| 
       229 
227 
     | 
    
         
             
                  end
         
     | 
| 
       230 
228 
     | 
    
         | 
| 
       231 
     | 
    
         
            -
                  def reset
         
     | 
| 
       232 
     | 
    
         
            -
                    @deep_merge_cache = ImmutableMash.new({}, self, @__node__, :merged)
         
     | 
| 
       233 
     | 
    
         
            -
                  end
         
     | 
| 
       234 
     | 
    
         
            -
             
     | 
| 
       235 
     | 
    
         
            -
                  def reset_cache(*path)
         
     | 
| 
       236 
     | 
    
         
            -
                    if path.empty?
         
     | 
| 
       237 
     | 
    
         
            -
                      reset
         
     | 
| 
       238 
     | 
    
         
            -
                    else
         
     | 
| 
       239 
     | 
    
         
            -
                      container = read(*path)
         
     | 
| 
       240 
     | 
    
         
            -
                      case container
         
     | 
| 
       241 
     | 
    
         
            -
                      when Hash, Array
         
     | 
| 
       242 
     | 
    
         
            -
                        container.reset
         
     | 
| 
       243 
     | 
    
         
            -
                      end
         
     | 
| 
       244 
     | 
    
         
            -
                    end
         
     | 
| 
       245 
     | 
    
         
            -
                  end
         
     | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
       247 
229 
     | 
    
         
             
                   # Set the cookbook level default attribute component to +new_data+.
         
     | 
| 
       248 
230 
     | 
    
         
             
                  def default=(new_data)
         
     | 
| 
       249 
231 
     | 
    
         
             
                    reset
         
     | 
| 
         @@ -308,7 +290,7 @@ class Chef 
     | 
|
| 
       308 
290 
     | 
    
         | 
| 
       309 
291 
     | 
    
         
             
                   # clears attributes from all precedence levels
         
     | 
| 
       310 
292 
     | 
    
         
             
                  def rm(*args)
         
     | 
| 
       311 
     | 
    
         
            -
                    with_deep_merged_return_value( 
     | 
| 
      
 293 
     | 
    
         
            +
                    with_deep_merged_return_value(self, *args) do
         
     | 
| 
       312 
294 
     | 
    
         
             
                      rm_default(*args)
         
     | 
| 
       313 
295 
     | 
    
         
             
                      rm_normal(*args)
         
     | 
| 
       314 
296 
     | 
    
         
             
                      rm_override(*args)
         
     | 
| 
         @@ -355,9 +337,6 @@ class Chef 
     | 
|
| 
       355 
337 
     | 
    
         
             
                  def with_deep_merged_return_value(obj, *path, last)
         
     | 
| 
       356 
338 
     | 
    
         
             
                    hash = obj.read(*path)
         
     | 
| 
       357 
339 
     | 
    
         
             
                    return nil unless hash.is_a?(Hash)
         
     | 
| 
       358 
     | 
    
         
            -
                    # coerce from immutablemash/vividmash to plain-old Hash
         
     | 
| 
       359 
     | 
    
         
            -
                    # also de-immutablizes and dup's the return value correctly in chef-13
         
     | 
| 
       360 
     | 
    
         
            -
                    hash = hash.to_hash
         
     | 
| 
       361 
340 
     | 
    
         
             
                    ret = hash[last]
         
     | 
| 
       362 
341 
     | 
    
         
             
                    yield
         
     | 
| 
       363 
342 
     | 
    
         
             
                    ret
         
     | 
| 
         @@ -419,16 +398,16 @@ class Chef 
     | 
|
| 
       419 
398 
     | 
    
         
             
                   # all of node['foo'] even if the user only requires node['foo']['bar']['baz'].
         
     | 
| 
       420 
399 
     | 
    
         
             
                   #
         
     | 
| 
       421 
400 
     | 
    
         | 
| 
       422 
     | 
    
         
            -
                  def  
     | 
| 
       423 
     | 
    
         
            -
                     
     | 
| 
      
 401 
     | 
    
         
            +
                  def merged_attributes(*path)
         
     | 
| 
      
 402 
     | 
    
         
            +
                    merge_all(path)
         
     | 
| 
       424 
403 
     | 
    
         
             
                  end
         
     | 
| 
       425 
404 
     | 
    
         | 
| 
       426 
     | 
    
         
            -
                  def  
     | 
| 
       427 
     | 
    
         
            -
                     
     | 
| 
      
 405 
     | 
    
         
            +
                  def combined_override(*path)
         
     | 
| 
      
 406 
     | 
    
         
            +
                    immutablize(merge_overrides(path))
         
     | 
| 
       428 
407 
     | 
    
         
             
                  end
         
     | 
| 
       429 
408 
     | 
    
         | 
| 
       430 
409 
     | 
    
         
             
                  def combined_default(*path)
         
     | 
| 
       431 
     | 
    
         
            -
                    merge_defaults(path)
         
     | 
| 
      
 410 
     | 
    
         
            +
                    immutablize(merge_defaults(path))
         
     | 
| 
       432 
411 
     | 
    
         
             
                  end
         
     | 
| 
       433 
412 
     | 
    
         | 
| 
       434 
413 
     | 
    
         
             
                  def normal_unless(*args)
         
     | 
| 
         @@ -497,14 +476,6 @@ class Chef 
     | 
|
| 
       497 
476 
     | 
    
         
             
                    merged_attributes.to_s
         
     | 
| 
       498 
477 
     | 
    
         
             
                  end
         
     | 
| 
       499 
478 
     | 
    
         | 
| 
       500 
     | 
    
         
            -
                  def [](key)
         
     | 
| 
       501 
     | 
    
         
            -
                    @deep_merge_cache[key]
         
     | 
| 
       502 
     | 
    
         
            -
                  end
         
     | 
| 
       503 
     | 
    
         
            -
             
     | 
| 
       504 
     | 
    
         
            -
                  def merged_attributes
         
     | 
| 
       505 
     | 
    
         
            -
                    @deep_merge_cache
         
     | 
| 
       506 
     | 
    
         
            -
                  end
         
     | 
| 
       507 
     | 
    
         
            -
             
     | 
| 
       508 
479 
     | 
    
         
             
                  def inspect
         
     | 
| 
       509 
480 
     | 
    
         
             
                    "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map do |iv|
         
     | 
| 
       510 
481 
     | 
    
         
             
                      "#{iv}=#{instance_variable_get(iv).inspect}"
         
     | 
| 
         @@ -513,14 +484,7 @@ class Chef 
     | 
|
| 
       513 
484 
     | 
    
         | 
| 
       514 
485 
     | 
    
         
             
                  private
         
     | 
| 
       515 
486 
     | 
    
         | 
| 
       516 
     | 
    
         
            -
             
     | 
| 
       517 
     | 
    
         
            -
                  def safe_dup(e)
         
     | 
| 
       518 
     | 
    
         
            -
                    e.dup
         
     | 
| 
       519 
     | 
    
         
            -
                  rescue TypeError
         
     | 
| 
       520 
     | 
    
         
            -
                    e
         
     | 
| 
       521 
     | 
    
         
            -
                  end
         
     | 
| 
       522 
     | 
    
         
            -
             
     | 
| 
       523 
     | 
    
         
            -
                   # Helper method for merge_defaults/merge_overrides.
         
     | 
| 
      
 487 
     | 
    
         
            +
                   # Helper method for merge_all/merge_defaults/merge_overrides.
         
     | 
| 
       524 
488 
     | 
    
         
             
                   #
         
     | 
| 
       525 
489 
     | 
    
         
             
                   # apply_path(thing, [ "foo", "bar", "baz" ]) = thing["foo"]["bar"]["baz"]
         
     | 
| 
       526 
490 
     | 
    
         
             
                   #
         
     | 
| 
         @@ -550,6 +514,34 @@ class Chef 
     | 
|
| 
       550 
514 
     | 
    
         
             
                    end
         
     | 
| 
       551 
515 
     | 
    
         
             
                  end
         
     | 
| 
       552 
516 
     | 
    
         | 
| 
      
 517 
     | 
    
         
            +
                   # For elements like Fixnums, true, nil...
         
     | 
| 
      
 518 
     | 
    
         
            +
                  def safe_dup(e)
         
     | 
| 
      
 519 
     | 
    
         
            +
                    e.dup
         
     | 
| 
      
 520 
     | 
    
         
            +
                  rescue TypeError
         
     | 
| 
      
 521 
     | 
    
         
            +
                    e
         
     | 
| 
      
 522 
     | 
    
         
            +
                  end
         
     | 
| 
      
 523 
     | 
    
         
            +
             
     | 
| 
      
 524 
     | 
    
         
            +
                   # Deep merge all attribute levels using hash-only merging between different precidence
         
     | 
| 
      
 525 
     | 
    
         
            +
                   # levels (so override arrays completely replace arrays set at any default level).
         
     | 
| 
      
 526 
     | 
    
         
            +
                   #
         
     | 
| 
      
 527 
     | 
    
         
            +
                   # The path allows for selectively deep-merging a subtree of the node object.
         
     | 
| 
      
 528 
     | 
    
         
            +
                   #
         
     | 
| 
      
 529 
     | 
    
         
            +
                   # @param path [Array] Array of args to method chain to descend into the node object
         
     | 
| 
      
 530 
     | 
    
         
            +
                   # @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
         
     | 
| 
      
 531 
     | 
    
         
            +
                  def merge_all(path)
         
     | 
| 
      
 532 
     | 
    
         
            +
                    components = [
         
     | 
| 
      
 533 
     | 
    
         
            +
                      merge_defaults(path),
         
     | 
| 
      
 534 
     | 
    
         
            +
                      apply_path(@normal, path),
         
     | 
| 
      
 535 
     | 
    
         
            +
                      merge_overrides(path),
         
     | 
| 
      
 536 
     | 
    
         
            +
                      apply_path(@automatic, path),
         
     | 
| 
      
 537 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 538 
     | 
    
         
            +
             
     | 
| 
      
 539 
     | 
    
         
            +
                    ret = components.inject(NIL) do |merged, component|
         
     | 
| 
      
 540 
     | 
    
         
            +
                      hash_only_merge!(merged, component)
         
     | 
| 
      
 541 
     | 
    
         
            +
                    end
         
     | 
| 
      
 542 
     | 
    
         
            +
                    ret == NIL ? nil : ret
         
     | 
| 
      
 543 
     | 
    
         
            +
                  end
         
     | 
| 
      
 544 
     | 
    
         
            +
             
     | 
| 
       553 
545 
     | 
    
         
             
                   # Deep merge the default attribute levels with array merging.
         
     | 
| 
       554 
546 
     | 
    
         
             
                   #
         
     | 
| 
       555 
547 
     | 
    
         
             
                   # The path allows for selectively deep-merging a subtree of the node object.
         
     | 
| 
         @@ -621,6 +613,38 @@ class Chef 
     | 
|
| 
       621 
613 
     | 
    
         
             
                    end
         
     | 
| 
       622 
614 
     | 
    
         
             
                  end
         
     | 
| 
       623 
615 
     | 
    
         | 
| 
      
 616 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 617 
     | 
    
         
            +
                  def hash_only_merge!(merge_onto, merge_with)
         
     | 
| 
      
 618 
     | 
    
         
            +
                    # If there are two Hashes, recursively merge.
         
     | 
| 
      
 619 
     | 
    
         
            +
                    if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash)
         
     | 
| 
      
 620 
     | 
    
         
            +
                      merge_with.each do |key, merge_with_value|
         
     | 
| 
      
 621 
     | 
    
         
            +
                        value =
         
     | 
| 
      
 622 
     | 
    
         
            +
                          if merge_onto.has_key?(key)
         
     | 
| 
      
 623 
     | 
    
         
            +
                            hash_only_merge!(safe_dup(merge_onto[key]), merge_with_value)
         
     | 
| 
      
 624 
     | 
    
         
            +
                          else
         
     | 
| 
      
 625 
     | 
    
         
            +
                            merge_with_value
         
     | 
| 
      
 626 
     | 
    
         
            +
                          end
         
     | 
| 
      
 627 
     | 
    
         
            +
             
     | 
| 
      
 628 
     | 
    
         
            +
                        # internal_set bypasses converting keys, does convert values and allows writing to immutable mashes
         
     | 
| 
      
 629 
     | 
    
         
            +
                        merge_onto.internal_set(key, value)
         
     | 
| 
      
 630 
     | 
    
         
            +
                      end
         
     | 
| 
      
 631 
     | 
    
         
            +
                      merge_onto
         
     | 
| 
      
 632 
     | 
    
         
            +
             
     | 
| 
      
 633 
     | 
    
         
            +
                    # If merge_with is nil, don't replace merge_onto
         
     | 
| 
      
 634 
     | 
    
         
            +
                    elsif merge_with.nil?
         
     | 
| 
      
 635 
     | 
    
         
            +
                      merge_onto
         
     | 
| 
      
 636 
     | 
    
         
            +
             
     | 
| 
      
 637 
     | 
    
         
            +
                    # In all other cases, replace merge_onto with merge_with
         
     | 
| 
      
 638 
     | 
    
         
            +
                    else
         
     | 
| 
      
 639 
     | 
    
         
            +
                      if merge_with.kind_of?(Hash)
         
     | 
| 
      
 640 
     | 
    
         
            +
                        Chef::Node::ImmutableMash.new(merge_with)
         
     | 
| 
      
 641 
     | 
    
         
            +
                      elsif merge_with.kind_of?(Array)
         
     | 
| 
      
 642 
     | 
    
         
            +
                        Chef::Node::ImmutableArray.new(merge_with)
         
     | 
| 
      
 643 
     | 
    
         
            +
                      else
         
     | 
| 
      
 644 
     | 
    
         
            +
                        merge_with
         
     | 
| 
      
 645 
     | 
    
         
            +
                      end
         
     | 
| 
      
 646 
     | 
    
         
            +
                    end
         
     | 
| 
      
 647 
     | 
    
         
            +
                  end
         
     | 
| 
       624 
648 
     | 
    
         
             
                end
         
     | 
| 
       625 
649 
     | 
    
         
             
              end
         
     | 
| 
       626 
650 
     | 
    
         
             
            end
         
     | 
| 
         @@ -63,13 +63,13 @@ class Chef 
     | 
|
| 
       63 
63 
     | 
    
         
             
                  MUTATOR_METHODS.each do |mutator|
         
     | 
| 
       64 
64 
     | 
    
         
             
                    define_method(mutator) do |*args, &block|
         
     | 
| 
       65 
65 
     | 
    
         
             
                      ret = super(*args, &block)
         
     | 
| 
       66 
     | 
    
         
            -
                      send_reset_cache 
     | 
| 
      
 66 
     | 
    
         
            +
                      send_reset_cache
         
     | 
| 
       67 
67 
     | 
    
         
             
                      ret
         
     | 
| 
       68 
68 
     | 
    
         
             
                    end
         
     | 
| 
       69 
69 
     | 
    
         
             
                  end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                  def delete(key, &block)
         
     | 
| 
       72 
     | 
    
         
            -
                    send_reset_cache(__path__)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    send_reset_cache(__path__, key)
         
     | 
| 
       73 
73 
     | 
    
         
             
                    super
         
     | 
| 
       74 
74 
     | 
    
         
             
                  end
         
     | 
| 
       75 
75 
     | 
    
         | 
| 
         @@ -147,13 +147,13 @@ class Chef 
     | 
|
| 
       147 
147 
     | 
    
         
             
                  # object.
         
     | 
| 
       148 
148 
     | 
    
         | 
| 
       149 
149 
     | 
    
         
             
                  def delete(key, &block)
         
     | 
| 
       150 
     | 
    
         
            -
                    send_reset_cache(__path__)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    send_reset_cache(__path__, key)
         
     | 
| 
       151 
151 
     | 
    
         
             
                    super
         
     | 
| 
       152 
152 
     | 
    
         
             
                  end
         
     | 
| 
       153 
153 
     | 
    
         | 
| 
       154 
154 
     | 
    
         
             
                  MUTATOR_METHODS.each do |mutator|
         
     | 
| 
       155 
155 
     | 
    
         
             
                    define_method(mutator) do |*args, &block|
         
     | 
| 
       156 
     | 
    
         
            -
                      send_reset_cache 
     | 
| 
      
 156 
     | 
    
         
            +
                      send_reset_cache
         
     | 
| 
       157 
157 
     | 
    
         
             
                      super(*args, &block)
         
     | 
| 
       158 
158 
     | 
    
         
             
                    end
         
     | 
| 
       159 
159 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -174,7 +174,7 @@ class Chef 
     | 
|
| 
       174 
174 
     | 
    
         | 
| 
       175 
175 
     | 
    
         
             
                  def []=(key, value)
         
     | 
| 
       176 
176 
     | 
    
         
             
                    ret = super
         
     | 
| 
       177 
     | 
    
         
            -
                    send_reset_cache(__path__)
         
     | 
| 
      
 177 
     | 
    
         
            +
                    send_reset_cache(__path__, key)
         
     | 
| 
       178 
178 
     | 
    
         
             
                    ret
         
     | 
| 
       179 
179 
     | 
    
         
             
                  end
         
     | 
| 
       180 
180 
     | 
    
         | 
    
        data/lib/chef/node/common_api.rb
    CHANGED
    
    
| 
         @@ -30,16 +30,22 @@ class Chef 
     | 
|
| 
       30 
30 
     | 
    
         
             
                    e
         
     | 
| 
       31 
31 
     | 
    
         
             
                  end
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                  def convert_value(value 
     | 
| 
      
 33 
     | 
    
         
            +
                  def convert_value(value)
         
     | 
| 
       34 
34 
     | 
    
         
             
                    case value
         
     | 
| 
       35 
35 
     | 
    
         
             
                    when Hash
         
     | 
| 
       36 
     | 
    
         
            -
                      ImmutableMash.new( 
     | 
| 
      
 36 
     | 
    
         
            +
                      ImmutableMash.new(value, __root__, __node__, __precedence__)
         
     | 
| 
       37 
37 
     | 
    
         
             
                    when Array
         
     | 
| 
       38 
     | 
    
         
            -
                      ImmutableArray.new( 
     | 
| 
      
 38 
     | 
    
         
            +
                      ImmutableArray.new(value, __root__, __node__, __precedence__)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    when ImmutableMash, ImmutableArray
         
     | 
| 
      
 40 
     | 
    
         
            +
                      value
         
     | 
| 
       39 
41 
     | 
    
         
             
                    else
         
     | 
| 
       40 
42 
     | 
    
         
             
                      safe_dup(value).freeze
         
     | 
| 
       41 
43 
     | 
    
         
             
                    end
         
     | 
| 
       42 
44 
     | 
    
         
             
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def immutablize(value)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    convert_value(value)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
       43 
49 
     | 
    
         
             
                end
         
     | 
| 
       44 
50 
     | 
    
         | 
| 
       45 
51 
     | 
    
         
             
                # == ImmutableArray
         
     | 
| 
         @@ -53,49 +59,15 @@ class Chef 
     | 
|
| 
       53 
59 
     | 
    
         
             
                #   Chef::Node::Attribute's values, it overrides all reader methods to
         
     | 
| 
       54 
60 
     | 
    
         
             
                #   detect staleness and raise an error if accessed when stale.
         
     | 
| 
       55 
61 
     | 
    
         
             
                class ImmutableArray < Array
         
     | 
| 
       56 
     | 
    
         
            -
                  alias_method :internal_clear, :clear
         
     | 
| 
       57 
     | 
    
         
            -
                  alias_method :internal_replace, :replace
         
     | 
| 
       58 
     | 
    
         
            -
                  alias_method :internal_push, :<<
         
     | 
| 
       59 
     | 
    
         
            -
                  alias_method :internal_to_a, :to_a
         
     | 
| 
       60 
     | 
    
         
            -
                  alias_method :internal_each, :each
         
     | 
| 
       61 
     | 
    
         
            -
                  private :internal_push, :internal_replace, :internal_clear, :internal_each
         
     | 
| 
       62 
     | 
    
         
            -
                  protected :internal_to_a
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
62 
     | 
    
         
             
                  include Immutablize
         
     | 
| 
       65 
63 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                   
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                  methods.each do |method|
         
     | 
| 
       70 
     | 
    
         
            -
                    define_method method do |*args, &block|
         
     | 
| 
       71 
     | 
    
         
            -
                      ensure_generated_cache!
         
     | 
| 
       72 
     | 
    
         
            -
                      super(*args, &block)
         
     | 
| 
       73 
     | 
    
         
            -
                    end
         
     | 
| 
       74 
     | 
    
         
            -
                  end
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
                  def each
         
     | 
| 
       77 
     | 
    
         
            -
                    ensure_generated_cache!
         
     | 
| 
       78 
     | 
    
         
            -
                    # aggressively pre generate the cache, works around ruby being too smart and fiddling with internals
         
     | 
| 
       79 
     | 
    
         
            -
                    internal_each { |i| i.ensure_generated_cache! if i.respond_to?(:ensure_generated_cache!) }
         
     | 
| 
       80 
     | 
    
         
            -
                    super
         
     | 
| 
       81 
     | 
    
         
            -
                  end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                  # because sometimes ruby gives us back Arrays or ImmutableArrays out of objects from things like #uniq or array slices
         
     | 
| 
       84 
     | 
    
         
            -
                  def return_normal_array(array)
         
     | 
| 
       85 
     | 
    
         
            -
                    if array.respond_to?(:internal_to_a, true)
         
     | 
| 
       86 
     | 
    
         
            -
                      array.internal_to_a
         
     | 
| 
       87 
     | 
    
         
            -
                    else
         
     | 
| 
       88 
     | 
    
         
            -
                      array.to_a
         
     | 
| 
       89 
     | 
    
         
            -
                    end
         
     | 
| 
       90 
     | 
    
         
            -
                  end
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                  def uniq
         
     | 
| 
       93 
     | 
    
         
            -
                    ensure_generated_cache!
         
     | 
| 
       94 
     | 
    
         
            -
                    return_normal_array(super)
         
     | 
| 
       95 
     | 
    
         
            -
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                  alias :internal_push :<<
         
     | 
| 
      
 65 
     | 
    
         
            +
                  private :internal_push
         
     | 
| 
       96 
66 
     | 
    
         | 
| 
       97 
67 
     | 
    
         
             
                  def initialize(array_data = [])
         
     | 
| 
       98 
     | 
    
         
            -
                     
     | 
| 
      
 68 
     | 
    
         
            +
                    array_data.each do |value|
         
     | 
| 
      
 69 
     | 
    
         
            +
                      internal_push(immutablize(value))
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
       99 
71 
     | 
    
         
             
                  end
         
     | 
| 
       100 
72 
     | 
    
         | 
| 
       101 
73 
     | 
    
         
             
                  # For elements like Fixnums, true, nil...
         
     | 
| 
         @@ -124,81 +96,8 @@ class Chef 
     | 
|
| 
       124 
96 
     | 
    
         | 
| 
       125 
97 
     | 
    
         
             
                  alias_method :to_array, :to_a
         
     | 
| 
       126 
98 
     | 
    
         | 
| 
       127 
     | 
    
         
            -
                  def [](*args)
         
     | 
| 
       128 
     | 
    
         
            -
                    ensure_generated_cache!
         
     | 
| 
       129 
     | 
    
         
            -
                    args.length > 1 ? return_normal_array(super) : super # correctly handle array slices
         
     | 
| 
       130 
     | 
    
         
            -
                  end
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
                  def reset
         
     | 
| 
       133 
     | 
    
         
            -
                    @generated_cache = false
         
     | 
| 
       134 
     | 
    
         
            -
                    @short_circuit_attr_level = nil
         
     | 
| 
       135 
     | 
    
         
            -
                    internal_clear # redundant?
         
     | 
| 
       136 
     | 
    
         
            -
                  end
         
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       139 
     | 
    
         
            -
                  def ensure_generated_cache!
         
     | 
| 
       140 
     | 
    
         
            -
                    generate_cache unless @generated_cache
         
     | 
| 
       141 
     | 
    
         
            -
                    @generated_cache = true
         
     | 
| 
       142 
     | 
    
         
            -
                  end
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                  # This can be set to e.g. [ :@default ] by the parent container to cause this container
         
     | 
| 
       145 
     | 
    
         
            -
                  # to only use the default level and to bypass deep merging (the common case is either
         
     | 
| 
       146 
     | 
    
         
            -
                  # default-level or automatic-level and we aren't doing any deep merging).  Right now it
         
     | 
| 
       147 
     | 
    
         
            -
                  # "optimized" for the case where we're no longer merging anything and only tracking a
         
     | 
| 
       148 
     | 
    
         
            -
                  # single level, and setting this to anything other than a size=1 array would behave
         
     | 
| 
       149 
     | 
    
         
            -
                  # in a broken fashion.  That could be fixed, but the perf boost would likely not be
         
     | 
| 
       150 
     | 
    
         
            -
                  # that large in the typical case.
         
     | 
| 
       151 
     | 
    
         
            -
                  #
         
     | 
| 
       152 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       153 
     | 
    
         
            -
                  attr_accessor :short_circuit_attr_levels
         
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
99 
     | 
    
         
             
                  private
         
     | 
| 
       156 
100 
     | 
    
         | 
| 
       157 
     | 
    
         
            -
                  # deep merging of array attribute within normal and override where they are merged together
         
     | 
| 
       158 
     | 
    
         
            -
                  def combined_components(components)
         
     | 
| 
       159 
     | 
    
         
            -
                    combined_values = nil
         
     | 
| 
       160 
     | 
    
         
            -
                    components.each do |component|
         
     | 
| 
       161 
     | 
    
         
            -
                      values = __node__.attributes.instance_variable_get(component).read(*__path__)
         
     | 
| 
       162 
     | 
    
         
            -
                      next unless values.is_a?(Array)
         
     | 
| 
       163 
     | 
    
         
            -
                      @tracked_components << component
         
     | 
| 
       164 
     | 
    
         
            -
                      combined_values ||= []
         
     | 
| 
       165 
     | 
    
         
            -
                      combined_values += values
         
     | 
| 
       166 
     | 
    
         
            -
                    end
         
     | 
| 
       167 
     | 
    
         
            -
                    combined_values
         
     | 
| 
       168 
     | 
    
         
            -
                  end
         
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
     | 
    
         
            -
                  def get_array(component)
         
     | 
| 
       171 
     | 
    
         
            -
                    array = __node__.attributes.instance_variable_get(component).read(*__path__)
         
     | 
| 
       172 
     | 
    
         
            -
                    if array.is_a?(Array)
         
     | 
| 
       173 
     | 
    
         
            -
                      @tracked_components << component
         
     | 
| 
       174 
     | 
    
         
            -
                      array
         
     | 
| 
       175 
     | 
    
         
            -
                    end # else nil
         
     | 
| 
       176 
     | 
    
         
            -
                  end
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                  def generate_cache
         
     | 
| 
       179 
     | 
    
         
            -
                    internal_clear
         
     | 
| 
       180 
     | 
    
         
            -
                    components = []
         
     | 
| 
       181 
     | 
    
         
            -
                    @tracked_components = []
         
     | 
| 
       182 
     | 
    
         
            -
                    if short_circuit_attr_levels
         
     | 
| 
       183 
     | 
    
         
            -
                      components << get_array(short_circuit_attr_levels.first)
         
     | 
| 
       184 
     | 
    
         
            -
                    else
         
     | 
| 
       185 
     | 
    
         
            -
                      components << combined_components(Attribute::DEFAULT_COMPONENTS)
         
     | 
| 
       186 
     | 
    
         
            -
                      components << get_array(:@normal)
         
     | 
| 
       187 
     | 
    
         
            -
                      components << combined_components(Attribute::OVERRIDE_COMPONENTS)
         
     | 
| 
       188 
     | 
    
         
            -
                      components << get_array(:@automatic)
         
     | 
| 
       189 
     | 
    
         
            -
                    end
         
     | 
| 
       190 
     | 
    
         
            -
                    highest = components.compact.last
         
     | 
| 
       191 
     | 
    
         
            -
                    if highest.is_a?(Array)
         
     | 
| 
       192 
     | 
    
         
            -
                      internal_replace( highest.each_with_index.map { |x, i| convert_value(x, __path__ + [ i ] ) } )
         
     | 
| 
       193 
     | 
    
         
            -
                    end
         
     | 
| 
       194 
     | 
    
         
            -
                    if @tracked_components.size == 1
         
     | 
| 
       195 
     | 
    
         
            -
                      # tracked_components is accurate enough to tell us if we're not really merging
         
     | 
| 
       196 
     | 
    
         
            -
                      internal_each do |key, value|
         
     | 
| 
       197 
     | 
    
         
            -
                        value.short_circuit_attr_levels = @tracked_components if value.respond_to?(:short_circuit_attr_levels)
         
     | 
| 
       198 
     | 
    
         
            -
                      end
         
     | 
| 
       199 
     | 
    
         
            -
                    end
         
     | 
| 
       200 
     | 
    
         
            -
                  end
         
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
101 
     | 
    
         
             
                  # needed for __path__
         
     | 
| 
       203 
102 
     | 
    
         
             
                  def convert_key(key)
         
     | 
| 
       204 
103 
     | 
    
         
             
                    key
         
     | 
| 
         @@ -221,31 +120,19 @@ class Chef 
     | 
|
| 
       221 
120 
     | 
    
         
             
                #   it is stale.
         
     | 
| 
       222 
121 
     | 
    
         
             
                # * Values can be accessed in attr_reader-like fashion via method_missing.
         
     | 
| 
       223 
122 
     | 
    
         
             
                class ImmutableMash < Mash
         
     | 
| 
       224 
     | 
    
         
            -
                  alias_method :internal_clear, :clear
         
     | 
| 
       225 
     | 
    
         
            -
                  alias_method :internal_key?, :key? # FIXME: could bypass convert_key in Mash for perf
         
     | 
| 
       226 
     | 
    
         
            -
                  alias_method :internal_each, :each
         
     | 
| 
       227 
     | 
    
         
            -
             
     | 
| 
       228 
123 
     | 
    
         
             
                  include Immutablize
         
     | 
| 
       229 
124 
     | 
    
         
             
                  include CommonAPI
         
     | 
| 
       230 
125 
     | 
    
         | 
| 
       231 
     | 
    
         
            -
                  methods = Hash.instance_methods - Object.instance_methods +
         
     | 
| 
       232 
     | 
    
         
            -
                    [ :!, :!=, :<=>, :==, :===, :eql?, :to_s, :hash, :key, :has_key?, :inspect, :pretty_print, :pretty_print_inspect, :pretty_print_cycle, :pretty_print_instance_variables ]
         
     | 
| 
       233 
     | 
    
         
            -
             
     | 
| 
       234 
     | 
    
         
            -
                  methods.each do |method|
         
     | 
| 
       235 
     | 
    
         
            -
                    define_method method do |*args, &block|
         
     | 
| 
       236 
     | 
    
         
            -
                      ensure_generated_cache!
         
     | 
| 
       237 
     | 
    
         
            -
                      super(*args, &block)
         
     | 
| 
       238 
     | 
    
         
            -
                    end
         
     | 
| 
       239 
     | 
    
         
            -
                  end
         
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
       241 
126 
     | 
    
         
             
                  # this is for deep_merge usage, chef users must never touch this API
         
     | 
| 
       242 
127 
     | 
    
         
             
                  # @api private
         
     | 
| 
       243 
128 
     | 
    
         
             
                  def internal_set(key, value)
         
     | 
| 
       244 
     | 
    
         
            -
                    regular_writer(key, convert_value(value 
     | 
| 
      
 129 
     | 
    
         
            +
                    regular_writer(key, convert_value(value))
         
     | 
| 
       245 
130 
     | 
    
         
             
                  end
         
     | 
| 
       246 
131 
     | 
    
         | 
| 
       247 
132 
     | 
    
         
             
                  def initialize(mash_data = {})
         
     | 
| 
       248 
     | 
    
         
            -
                     
     | 
| 
      
 133 
     | 
    
         
            +
                    mash_data.each do |key, value|
         
     | 
| 
      
 134 
     | 
    
         
            +
                      internal_set(key, value)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    end
         
     | 
| 
       249 
136 
     | 
    
         
             
                  end
         
     | 
| 
       250 
137 
     | 
    
         | 
| 
       251 
138 
     | 
    
         
             
                  alias :attribute? :has_key?
         
     | 
| 
         @@ -281,55 +168,11 @@ class Chef 
     | 
|
| 
       281 
168 
     | 
    
         | 
| 
       282 
169 
     | 
    
         
             
                  alias_method :to_hash, :to_h
         
     | 
| 
       283 
170 
     | 
    
         | 
| 
       284 
     | 
    
         
            -
                   
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
                     
     | 
| 
       287 
     | 
    
         
            -
                   
     | 
| 
       288 
     | 
    
         
            -
             
     | 
| 
       289 
     | 
    
         
            -
                  alias_method :to_hash, :to_h
         
     | 
| 
       290 
     | 
    
         
            -
             
     | 
| 
       291 
     | 
    
         
            -
                  def reset
         
     | 
| 
       292 
     | 
    
         
            -
                    @generated_cache = false
         
     | 
| 
       293 
     | 
    
         
            -
                    @short_circuit_attr_level = nil
         
     | 
| 
       294 
     | 
    
         
            -
                    internal_clear # redundant?
         
     | 
| 
       295 
     | 
    
         
            -
                  end
         
     | 
| 
       296 
     | 
    
         
            -
             
     | 
| 
       297 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       298 
     | 
    
         
            -
                  def ensure_generated_cache!
         
     | 
| 
       299 
     | 
    
         
            -
                    generate_cache unless @generated_cache
         
     | 
| 
       300 
     | 
    
         
            -
                    @generated_cache = true
         
     | 
| 
       301 
     | 
    
         
            -
                  end
         
     | 
| 
       302 
     | 
    
         
            -
             
     | 
| 
       303 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       304 
     | 
    
         
            -
                  attr_accessor :short_circuit_attr_levels
         
     | 
| 
       305 
     | 
    
         
            -
             
     | 
| 
       306 
     | 
    
         
            -
                  private
         
     | 
| 
       307 
     | 
    
         
            -
             
     | 
| 
       308 
     | 
    
         
            -
                  def generate_cache
         
     | 
| 
       309 
     | 
    
         
            -
                    internal_clear
         
     | 
| 
       310 
     | 
    
         
            -
                    components = short_circuit_attr_levels ? short_circuit_attr_levels : Attribute::COMPONENTS.reverse
         
     | 
| 
       311 
     | 
    
         
            -
                    # tracked_components is not entirely accurate due to the short-circuit
         
     | 
| 
       312 
     | 
    
         
            -
                    tracked_components = []
         
     | 
| 
       313 
     | 
    
         
            -
                    components.each do |component|
         
     | 
| 
       314 
     | 
    
         
            -
                      subhash = __node__.attributes.instance_variable_get(component).read(*__path__)
         
     | 
| 
       315 
     | 
    
         
            -
                      unless subhash.nil? # FIXME: nil is used for not present
         
     | 
| 
       316 
     | 
    
         
            -
                        tracked_components << component
         
     | 
| 
       317 
     | 
    
         
            -
                        if subhash.kind_of?(Hash)
         
     | 
| 
       318 
     | 
    
         
            -
                          subhash.keys.each do |key|
         
     | 
| 
       319 
     | 
    
         
            -
                            next if internal_key?(key)
         
     | 
| 
       320 
     | 
    
         
            -
                            internal_set(key, subhash[key])
         
     | 
| 
       321 
     | 
    
         
            -
                          end
         
     | 
| 
       322 
     | 
    
         
            -
                        else
         
     | 
| 
       323 
     | 
    
         
            -
                          break
         
     | 
| 
       324 
     | 
    
         
            -
                        end
         
     | 
| 
       325 
     | 
    
         
            -
                      end
         
     | 
| 
       326 
     | 
    
         
            -
                    end
         
     | 
| 
       327 
     | 
    
         
            -
                    if tracked_components.size == 1
         
     | 
| 
       328 
     | 
    
         
            -
                      # tracked_components is accurate enough to tell us if we're not really merging
         
     | 
| 
       329 
     | 
    
         
            -
                      internal_each do |key, value|
         
     | 
| 
       330 
     | 
    
         
            -
                        value.short_circuit_attr_levels = tracked_components if value.respond_to?(:short_circuit_attr_levels)
         
     | 
| 
       331 
     | 
    
         
            -
                      end
         
     | 
| 
       332 
     | 
    
         
            -
                    end
         
     | 
| 
      
 171 
     | 
    
         
            +
                  # For elements like Fixnums, true, nil...
         
     | 
| 
      
 172 
     | 
    
         
            +
                  def safe_dup(e)
         
     | 
| 
      
 173 
     | 
    
         
            +
                    e.dup
         
     | 
| 
      
 174 
     | 
    
         
            +
                  rescue TypeError
         
     | 
| 
      
 175 
     | 
    
         
            +
                    e
         
     | 
| 
       333 
176 
     | 
    
         
             
                  end
         
     | 
| 
       334 
177 
     | 
    
         | 
| 
       335 
178 
     | 
    
         
             
                  prepend Chef::Node::Mixin::StateTracking
         
     |