From b8a4188fa3c112f34560cbb36583e7ac62a53eb5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 3 Sep 2010 11:16:38 -0700 Subject: [PATCH] Config class is now responsible for loading configuration. Cleans up environment. --- lib/vagrant/config.rb | 27 +++++++ lib/vagrant/environment.rb | 33 ++------ test/vagrant/config_test.rb | 134 ++++++++++++++++++++++--------- test/vagrant/environment_test.rb | 65 ++++----------- 4 files changed, 146 insertions(+), 113 deletions(-) diff --git a/lib/vagrant/config.rb b/lib/vagrant/config.rb index abe270351..8de981ee7 100644 --- a/lib/vagrant/config.rb +++ b/lib/vagrant/config.rb @@ -1,11 +1,15 @@ require 'vagrant/config/base' module Vagrant + # The config class is responsible for loading Vagrant configurations + # (usually through Vagrantfiles). class Config extend Util::StackedProcRunner @@config = nil + attr_reader :queue + class << self def reset!(env=nil) @@config = nil @@ -36,6 +40,29 @@ module Vagrant end end + def initialize(env) + @env = env + @queue = [] + end + + # Loads the queue of files/procs, executes them in the proper + # sequence, and returns the resulting configuration object. + def load! + self.class.reset!(@env) + + queue.flatten.each do |item| + if item.is_a?(String) && File.exist?(item) + load item + elsif item.is_a?(Proc) + self.class.run(&item) + end + end + + return self.class.execute! + end + end + + class Config class Top < Base @@configures = [] diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb index 56fe83380..3ac118230 100644 --- a/lib/vagrant/environment.rb +++ b/lib/vagrant/environment.rb @@ -215,40 +215,21 @@ module Vagrant # this environment, meaning that it will use the given root directory # to load the Vagrantfile into that context. def load_config! - # Prepare load paths for config files and append to config queue - config_queue = [File.expand_path("config/default.rb", Vagrant.source_root)] - config_queue << File.join(box.directory, ROOTFILE_NAME) if box - config_queue << File.join(home_path, ROOTFILE_NAME) if home_path - config_queue << File.join(root_path, ROOTFILE_NAME) if root_path + loader = Config.new(self) + loader.queue << File.expand_path("config/default.rb", Vagrant.source_root) + loader.queue << File.join(box.directory, ROOTFILE_NAME) if box + loader.queue << File.join(home_path, ROOTFILE_NAME) if home_path + loader.queue << File.join(root_path, ROOTFILE_NAME) if root_path # If this environment represents some VM in a multi-VM environment, # we push that VM's configuration onto the config_queue. if vm_name subvm = parent.config.vm.defined_vms[vm_name] - config_queue << subvm.proc_stack if subvm - end - - # Flatten the config queue so any nested procs are flattened - config_queue.flatten! - - # Clear out the old data - Config.reset!(self) - - # Load each of the config files in order - config_queue.each do |item| - if item.is_a?(String) && File.exist?(item) - load item - next - end - - if item.is_a?(Proc) - # Just push the proc straight onto the config runnable stack - Config.run(&item) - end + loader.queue << subvm.proc_stack if subvm end # Execute the configuration stack and store the result - @config = Config.execute! + @config = loader.load! # (re)load the logger @logger = nil diff --git a/test/vagrant/config_test.rb b/test/vagrant/config_test.rb index f8ec1b5b5..1de62cf2d 100644 --- a/test/vagrant/config_test.rb +++ b/test/vagrant/config_test.rb @@ -1,81 +1,139 @@ require "test_helper" class ConfigTest < Test::Unit::TestCase + setup do + @klass = Vagrant::Config + end + + context "with an instance" do + setup do + @env = mock_environment + @instance = @klass.new(@env) + end + + should "initially have an empty queue" do + assert @instance.queue.empty? + end + + should "reset the config class on load, then execute" do + seq = sequence("sequence") + @klass.expects(:reset!).with(@env).in_sequence(seq) + @klass.expects(:execute!).in_sequence(seq) + @instance.load! + end + + should "run the queue in the order given" do + @instance.queue << Proc.new { |config| config.vm.box = "foo" } + @instance.queue << Proc.new { |config| config.vm.box = "bar" } + result = @instance.load! + + assert_equal "bar", result.vm.box + end + + should "allow nested arrays" do + queue = [] + queue << Proc.new { |config| config.vm.box = "foo" } + queue << Proc.new { |config| config.vm.box = "bar" } + @instance.queue << queue + result = @instance.load! + + assert_equal "bar", result.vm.box + end + + should "load a file if it exists" do + filename = "foo" + File.expects(:exist?).with(filename).returns(true) + @instance.expects(:load).with(filename).once + + @instance.queue << filename + @instance.load! + end + + should "not load a file if it doesn't exist" do + filename = "foo" + File.expects(:exist?).with(filename).returns(false) + @instance.expects(:load).with(filename).never + + @instance.queue << filename + @instance.load! + end + end + context "adding configures" do should "forward the method to the Top class" do key = mock("key") klass = mock("klass") - Vagrant::Config::Top.expects(:configures).with(key, klass) - Vagrant::Config.configures(key, klass) + @klass::Top.expects(:configures).with(key, klass) + @klass.configures(key, klass) end end context "resetting" do setup do - Vagrant::Config.run { |config| } - Vagrant::Config.execute! + @klass.run { |config| } + @klass.execute! end should "return the same config object typically" do - config = Vagrant::Config.config - assert config.equal?(Vagrant::Config.config) + config = @klass.config + assert config.equal?(@klass.config) end should "create a new object if cleared" do - config = Vagrant::Config.config - Vagrant::Config.reset! - assert !config.equal?(Vagrant::Config.config) + config = @klass.config + @klass.reset! + assert !config.equal?(@klass.config) end should "empty the proc stack" do - assert !Vagrant::Config.proc_stack.empty? - Vagrant::Config.reset! - assert Vagrant::Config.proc_stack.empty? + assert !@klass.proc_stack.empty? + @klass.reset! + assert @klass.proc_stack.empty? end should "reload the config object based on the given environment" do env = mock("env") - Vagrant::Config.expects(:config).with(env).once - Vagrant::Config.reset!(env) + @klass.expects(:config).with(env).once + @klass.reset!(env) end end context "initializing" do setup do - Vagrant::Config.reset! + @klass.reset! end should "add the given block to the proc stack" do proc = Proc.new {} - Vagrant::Config.run(&proc) - assert_equal [proc], Vagrant::Config.proc_stack + @klass.run(&proc) + assert_equal [proc], @klass.proc_stack end should "run the proc stack with the config when execute is called" do - Vagrant::Config.expects(:run_procs!).with(Vagrant::Config.config).once - Vagrant::Config.execute! + @klass.expects(:run_procs!).with(@klass.config).once + @klass.execute! end should "not be loaded, initially" do - assert !Vagrant::Config.config.loaded? + assert !@klass.config.loaded? end should "be loaded after running" do - Vagrant::Config.run {} - Vagrant::Config.execute! - assert Vagrant::Config.config.loaded? + @klass.run {} + @klass.execute! + assert @klass.config.loaded? end should "return the configuration on execute!" do - Vagrant::Config.run {} - result = Vagrant::Config.execute! - assert result.is_a?(Vagrant::Config::Top) + @klass.run {} + result = @klass.execute! + assert result.is_a?(@klass::Top) end should "use given configuration object if given" do fake_env = mock("env") - config = Vagrant::Config::Top.new(fake_env) - result = Vagrant::Config.execute!(config) + config = @klass::Top.new(fake_env) + result = @klass.execute!(config) assert_equal config.env, result.env end end @@ -83,18 +141,18 @@ class ConfigTest < Test::Unit::TestCase context "top config class" do setup do @configures_list = [] - Vagrant::Config::Top.stubs(:configures_list).returns(@configures_list) + @klass::Top.stubs(:configures_list).returns(@configures_list) end context "adding configure keys" do setup do @key = "top_config_foo" - @klass = mock("klass") + @config_klass = mock("klass") end should "add key and klass to configures list" do - @configures_list.expects(:<<).with([@key, @klass]) - Vagrant::Config::Top.configures(@key, @klass) + @configures_list.expects(:<<).with([@key, @config_klass]) + @klass::Top.configures(@key, @config_klass) end end @@ -115,7 +173,7 @@ class ConfigTest < Test::Unit::TestCase @configures_list << [key, klass] end - Vagrant::Config::Top.new(env) + @klass::Top.new(env) end should "allow reading via methods" do @@ -124,16 +182,16 @@ class ConfigTest < Test::Unit::TestCase instance = mock("instance") instance.stubs(:env=) klass.expects(:new).returns(instance) - Vagrant::Config::Top.configures(key, klass) + @klass::Top.configures(key, klass) - config = Vagrant::Config::Top.new + config = @klass::Top.new assert_equal instance, config.send(key) end end context "loaded status" do setup do - @top= Vagrant::Config::Top.new + @top= @klass::Top.new end should "not be loaded by default" do @@ -152,8 +210,8 @@ class ConfigTest < Test::Unit::TestCase end setup do - Vagrant::Config::Top.configures :deep, DeepCloneConfig - @top = Vagrant::Config::Top.new + @klass::Top.configures :deep, DeepCloneConfig + @top = @klass::Top.new @top.deep.attribute = [1,2,3] end diff --git a/test/vagrant/environment_test.rb b/test/vagrant/environment_test.rb index 05c935486..69ab77860 100644 --- a/test/vagrant/environment_test.rb +++ b/test/vagrant/environment_test.rb @@ -393,47 +393,36 @@ class EnvironmentTest < Test::Unit::TestCase @env.stubs(:root_path).returns(@root_path) @env.stubs(:home_path).returns(@home_path) - @parent_env = mock_environment - - File.stubs(:exist?).returns(false) - end - - should "reset the configuration object" do - Vagrant::Config.expects(:reset!).with(@env).once - @env.load_config! + @loader = Vagrant::Config.new(@env) + Vagrant::Config.stubs(:new).returns(@loader) + @loader.stubs(:load!) end should "load from the project root" do - File.expects(:exist?).with(File.join(Vagrant.source_root, "config", "default.rb")).once @env.load_config! + assert @loader.queue.include?(File.expand_path("config/default.rb", Vagrant.source_root)) end should "load from the root path" do - File.expects(:exist?).with(File.join(@root_path, @klass::ROOTFILE_NAME)).once @env.load_config! + assert @loader.queue.include?(File.join(@root_path, @klass::ROOTFILE_NAME)) end should "not load from the root path if nil" do @env.stubs(:root_path).returns(nil) - File.expects(:exist?).with(File.join(@root_path, @klass::ROOTFILE_NAME)).never @env.load_config! + assert !@loader.queue.include?(File.join(@root_path, @klass::ROOTFILE_NAME)) end should "load from the home directory" do - File.expects(:exist?).with(File.join(@env.home_path, @klass::ROOTFILE_NAME)).once @env.load_config! + assert @loader.queue.include?(File.join(@env.home_path, @klass::ROOTFILE_NAME)) end should "not load from the home directory if the config is nil" do @env.stubs(:home_path).returns(nil) - File.expects(:exist?).twice.returns(false) - @env.load_config! - end - - should "not load from the box directory if it is nil" do - @env.expects(:box).once.returns(nil) - File.expects(:exist?).twice.returns(false) @env.load_config! + assert !@loader.queue.include?(File.join(@home_path, @klass::ROOTFILE_NAME)) end should "load from the box directory if it is not nil" do @@ -441,52 +430,30 @@ class EnvironmentTest < Test::Unit::TestCase box = mock("box") box.stubs(:directory).returns(dir) @env.expects(:box).twice.returns(box) - File.expects(:exist?).with(File.join(dir, @klass::ROOTFILE_NAME)).once @env.load_config! + assert @loader.queue.include?(File.join(dir, @klass::ROOTFILE_NAME)) end should "load a sub-VM configuration if specified" do - vm_name = :foo - sub_box = :YO - @parent_env.config.vm.box = :NO - @parent_env.config.vm.define(vm_name) do |config| - config.vm.box = sub_box - end - - # Sanity - assert_equal :NO, @parent_env.config.vm.box - + vm_name = :foobar + proc = Proc.new {} + parent_env = mock_environment + parent_env.config.vm.define(vm_name, &proc) + @env.stubs(:parent).returns(parent_env) @env.stubs(:vm_name).returns(vm_name) - @env.stubs(:parent).returns(@parent_env) @env.load_config! - - assert_equal sub_box, @env.config.vm.box - end - - should "load the files only if exist? returns true" do - File.expects(:exist?).once.returns(true) - @env.expects(:load).once - @env.load_config! - end - - should "not load the files if exist? returns false" do - @env.expects(:load).never - @env.load_config! + assert @loader.queue.flatten.include?(proc) end should "execute after loading and set result to environment config" do result = mock("result") - File.expects(:exist?).once.returns(true) - @env.expects(:load).once - Vagrant::Config.expects(:execute!).once.returns(result) + @loader.expects(:load!).once.returns(result) @env.load_config! assert_equal result, @env.config end should "reload the logger after executing" do - load_seq = sequence("load_seq") - Vagrant::Config.expects(:execute!).once.returns(nil).in_sequence(load_seq) @env.load_config! assert @env.instance_variable_get(:@logger).nil? end