diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 6d3b38b18..e14446b13 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -8,9 +8,10 @@ module Vagrant # TODO: Move more classes over to the autoload model. We'll # start small, but slowly move everything over. - autoload :CLI, 'vagrant/cli' - autoload :Config, 'vagrant/config' - autoload :Errors, 'vagrant/errors' + autoload :CLI, 'vagrant/cli' + autoload :Config, 'vagrant/config' + autoload :DataStore, 'vagrant/data_store' + autoload :Errors, 'vagrant/errors' module Command autoload :Base, 'vagrant/command/base' diff --git a/lib/vagrant/config/base.rb b/lib/vagrant/config/base.rb index f48d36b5c..daa83a831 100644 --- a/lib/vagrant/config/base.rb +++ b/lib/vagrant/config/base.rb @@ -18,11 +18,18 @@ module Vagrant end end + # Converts the configuration to a raw hash. + def to_hash + instance_variables_hash.inject({}) do |acc, data| + k,v = data + v = v.to_hash if v.respond_to?(:to_hash) + acc[k] = v + acc + end + end + def to_json(*a) - opts = a.first if a.first.is_a?(Hash) - opts ||= {} - result = {} - result.merge!('json_class' => self.class.name) if opts[:loadable] + result = { 'json_class' => self.class.name } result.merge(instance_variables_hash).to_json(*a) end diff --git a/lib/vagrant/data_store.rb b/lib/vagrant/data_store.rb new file mode 100644 index 000000000..3b6766d71 --- /dev/null +++ b/lib/vagrant/data_store.rb @@ -0,0 +1,38 @@ +module Vagrant + # The Vagrant data store is a key-value store which is persisted + # as JSON in a local file which is specified in the initializer. + # The data store itself is accessed via typical hash accessors: `[]` + # and `[]=`. If a key is set to `nil`, then it is removed from the + # datastore. The data store is only updated on disk when {commit} + # is called on the data store itself. + class DataStore + attr_reader :file_path + + def initialize(file_path) + @file_path = file_path + + File.open(file_path, "r") do |f| + @data = JSON.parse(f.read) + end + end + + # Returns the value associated with the `key` in the data + # store. + def [](key) + @data[key] + end + + # Sets the value in the data store. + def []=(key, value) + @data[key] = value + end + + # Commits any changes to the data to disk. Even if the data + # hasn't changed, it will be reserialized and written to disk. + def commit + File.open(file_path, "w") do |f| + f.write(@data.to_json) + end + end + end +end diff --git a/lib/vagrant/provisioners/chef.rb b/lib/vagrant/provisioners/chef.rb index d6466c6e4..4a0ab4947 100644 --- a/lib/vagrant/provisioners/chef.rb +++ b/lib/vagrant/provisioners/chef.rb @@ -36,7 +36,7 @@ module Vagrant # Set up initial configuration data = { - :config => env.config, + :config => env.config.to_hash, :directory => env.config.vm.shared_folders["v-root"][:guestpath], } diff --git a/test/tmp/.gitkeep b/test/tmp/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/vagrant/config/base_test.rb b/test/vagrant/config/base_test.rb index 5cea1557d..44cc69aff 100644 --- a/test/vagrant/config/base_test.rb +++ b/test/vagrant/config/base_test.rb @@ -21,17 +21,11 @@ class ConfigBaseTest < Test::Unit::TestCase end context "converting to JSON" do - should "include magic `json_class` if loadable is set to true" do + should "include magic `json_class`" do @iv_hash = { "foo" => "bar" } @base.expects(:instance_variables_hash).returns(@iv_hash) @json = { 'json_class' => @base.class.name }.merge(@iv_hash).to_json - assert_equal @json, @base.to_json(:loadable => true) - end - - should "convert instance variable hash to json" do - @iv_hash = { "foo" => "bar" } - @base.expects(:instance_variables_hash).returns(@iv_hash) - assert_equal @iv_hash.to_json, @base.to_json + assert_equal @json, @base.to_json end should "not include env in the JSON hash" do diff --git a/test/vagrant/data_store_test.rb b/test/vagrant/data_store_test.rb new file mode 100644 index 000000000..cb927c9f2 --- /dev/null +++ b/test/vagrant/data_store_test.rb @@ -0,0 +1,33 @@ +require "test_helper" + +class DataStoreTest < Test::Unit::TestCase + setup do + @klass = Vagrant::DataStore + @initial_data = { "foo" => "bar" } + @db_file = File.expand_path("test/tmp/data_store_test", Vagrant.source_root) + File.open(@db_file, "w") { |f| f.write(@initial_data.to_json) } + + @instance = @klass.new(@db_file) + end + + teardown do + File.delete(@db_file) + end + + should "read the data" do + assert_equal @initial_data["foo"], @instance["foo"] + end + + should "write the data, but not save it right away" do + @instance["foo"] = "changed" + assert_equal "changed", @instance["foo"] + assert_equal @initial_data["foo"], @klass.new(@db_file)["foo"] + end + + should "write the data if commit is called" do + @instance["foo"] = "changed" + @instance.commit + + assert_equal "changed", @klass.new(@db_file)["foo"] + end +end diff --git a/test/vagrant/provisioners/chef_test.rb b/test/vagrant/provisioners/chef_test.rb index 468028197..6f013d7a7 100644 --- a/test/vagrant/provisioners/chef_test.rb +++ b/test/vagrant/provisioners/chef_test.rb @@ -141,7 +141,7 @@ class ChefProvisionerTest < Test::Unit::TestCase context "generating and uploading json" do def assert_json @vm.ssh.expects(:upload!).with do |json, path| - data = JSON.parse(json.read, :object_class => Hash) + data = JSON.parse(json.read) yield data true end