diff --git a/lib/vagrant/config/base.rb b/lib/vagrant/config/base.rb index 2cc31d82b..dda537983 100644 --- a/lib/vagrant/config/base.rb +++ b/lib/vagrant/config/base.rb @@ -25,6 +25,20 @@ module Vagrant end end + # Merge another configuration object into this one. + # + # @param [Object] other The other configuration object to merge from, + # this must be the same type of object as this one. + # @return [Object] The merged object. + def merge(other) + result = self.class.new + instance_variables_hash.merge(other.instance_variables_hash).each do |key, value| + result.instance_variable_set("@#{key}".to_sym, value) + end + + result + end + # Called by {Top} after the configuration is loaded to validate # the configuaration objects. Subclasses should implement this # method and add any errors to the `errors` object given. @@ -54,7 +68,7 @@ module Vagrant # Returns the instance variables as a hash of key-value pairs. def instance_variables_hash instance_variables.inject({}) do |acc, iv| - acc[iv.to_s[1..-1]] = instance_variable_get(iv) unless iv.to_sym == :@top + acc[iv.to_s[1..-1]] = instance_variable_get(iv) acc end end diff --git a/lib/vagrant/config/loader.rb b/lib/vagrant/config/loader.rb index fe92dc61b..fc588df1e 100644 --- a/lib/vagrant/config/loader.rb +++ b/lib/vagrant/config/loader.rb @@ -20,6 +20,7 @@ module Vagrant @logger = Log4r::Logger.new("vagrant::config::loader") @sources = {} @proc_cache = {} + @config_cache = {} end # Set the configuration data for the given name. @@ -70,21 +71,26 @@ module Vagrant end # Create the top-level configuration which will hold all the config. - top = Top.new + result = Top.new @load_order.each do |key| next if !@sources.has_key?(key) @sources[key].each do |proc| - @logger.debug("Loading from: #{key}") + if !@config_cache.has_key?(proc) + @logger.debug("Loading from: #{key} (evaluating)") + current = Top.new + proc.call(current) + @config_cache[proc] = current + end - # Call each proc with the top-level configuration. - proc.call(top) + # Merge in the results of this proc's configuration + result = result.merge(@config_cache[proc]) end end @logger.debug("Configuration loaded successfully") - top + result end protected diff --git a/test/unit/vagrant/config/loader_test.rb b/test/unit/vagrant/config/loader_test.rb index 86ea2b5a1..4d5d2e20f 100644 --- a/test/unit/vagrant/config/loader_test.rb +++ b/test/unit/vagrant/config/loader_test.rb @@ -22,6 +22,27 @@ describe Vagrant::Config::Loader do config.vagrant.dotfile_name.should == "foo" end + it "should only run the same proc once" do + count = 0 + proc = Proc.new do |config| + config.vagrant.dotfile_name = "foo" + count += 1 + end + + instance.load_order = [:proc] + instance.set(:proc, proc) + + 5.times do + result = instance.load + + # Verify the config result + result.vagrant.dotfile_name.should == "foo" + + # Verify the count is only one + count.should == 1 + end + end + it "should only load configuration files once" do $_config_data = 0 @@ -35,19 +56,6 @@ describe Vagrant::Config::Loader do $_config_data.should == 1 end - it "should clear cache on setting to a new value" do - $_config_data = 0 - - instance.load_order = [:proc] - instance.set(:proc, temporary_file("$_config_data += 1")) - 5.times { instance.load } - - instance.set(:proc, temporary_file("$_config_data += 1")) - 5.times { instance.load } - - $_config_data.should == 2 - end - it "should not clear the cache if setting to the same value multiple times" do $_config_data = 0