V2 loader now properly upgrades V1 configuration.
This is done by calling the `upgrade` method on the _old_ configuration classes. The old configuration classes are given the complete new configuration and can set whatever settings they need to on it.
This commit is contained in:
parent
3e6fe7406b
commit
53860f90ab
|
@ -81,29 +81,32 @@ module Vagrant
|
|||
V2::Root.new(config_map, keys)
|
||||
end
|
||||
|
||||
# Upgrade a V1 configuration to a V2 configuration.
|
||||
# Upgrade a V1 configuration to a V2 configuration. We do this by
|
||||
# creating a V2 configuration, and calling "upgrade" on each of the
|
||||
# V1 configurations, expecting them to set the right settings on the
|
||||
# new root.
|
||||
#
|
||||
# @param [V1::Root] old
|
||||
# @return [Array] A 3-tuple result.
|
||||
def self.upgrade(old)
|
||||
# TODO: Actually do an upgrade. For now we just return V1.
|
||||
[old, [], []]
|
||||
# Get a new root
|
||||
root = new_root_object
|
||||
|
||||
# Go through the old keys and upgrade them if they can be
|
||||
old.__internal_state["keys"].each do |_, old_value|
|
||||
if old_value.respond_to?(:upgrade)
|
||||
old_value.upgrade(root)
|
||||
end
|
||||
end
|
||||
|
||||
[root, [], []]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.new_root_object
|
||||
# Get all the registered configuration objects and use them. If
|
||||
# we're currently on version 1, then we load all the config objects,
|
||||
# otherwise we load only the upgrade safe ones, since we're
|
||||
# obviously being loaded for an upgrade.
|
||||
config_map = nil
|
||||
plugin_manager = Vagrant.plugin("2").manager
|
||||
if Config::CURRENT_VERSION == "2"
|
||||
config_map = plugin_manager.config
|
||||
else
|
||||
config_map = plugin_manager.config_upgrade_safe
|
||||
end
|
||||
# Get all the registered plugins for V2
|
||||
config_map = Vagrant.plugin("2").manager.config
|
||||
|
||||
# Create the configuration root object
|
||||
V2::Root.new(config_map)
|
||||
|
|
|
@ -78,6 +78,17 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# This is called to upgrade this V1 config to V2. The parameter given
|
||||
# is the full V2 configuration object, so you can do anything to it
|
||||
# that you want.
|
||||
#
|
||||
# No return value is expected, modifications should be made directly
|
||||
# to the new V2 object.
|
||||
#
|
||||
# @param [V2::Root] new
|
||||
def upgrade(new)
|
||||
end
|
||||
|
||||
# Called after the configuration is finalized and loaded to validate
|
||||
# this object.
|
||||
#
|
||||
|
|
|
@ -2,7 +2,7 @@ module Vagrant
|
|||
module Plugin
|
||||
module V2
|
||||
# This is the base class for a configuration key defined for
|
||||
# V1. Any configuration key plugins for V1 should inherit from this
|
||||
# V2. Any configuration key plugins for V2 should inherit from this
|
||||
# class.
|
||||
class Config
|
||||
# This is called as a last-minute hook that allows the configuration
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
require "ostruct"
|
||||
|
||||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
describe Vagrant::Config::V2::Loader do
|
||||
include_context "unit"
|
||||
|
||||
before(:each) do
|
||||
# Force the V2 loader to believe that we are in V2
|
||||
stub_const("Vagrant::Config::CURRENT_VERSION", "2")
|
||||
end
|
||||
|
||||
describe "empty" do
|
||||
it "returns an empty configuration object" do
|
||||
result = described_class.init
|
||||
result.should be_kind_of(Vagrant::Config::V2::Root)
|
||||
end
|
||||
end
|
||||
|
||||
describe "finalizing" do
|
||||
it "should call `#finalize` on the configuration object" do
|
||||
# Register a plugin for our test
|
||||
register_plugin("2") do |plugin|
|
||||
plugin.config "foo" do
|
||||
Class.new do
|
||||
attr_accessor :bar
|
||||
|
||||
def finalize!
|
||||
@bar = "finalized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create the proc we're testing
|
||||
config_proc = Proc.new do |config|
|
||||
config.foo.bar = "value"
|
||||
end
|
||||
|
||||
# Test that it works properly
|
||||
config = described_class.load(config_proc)
|
||||
config.foo.bar.should == "value"
|
||||
|
||||
# Finalize it
|
||||
described_class.finalize(config)
|
||||
config.foo.bar.should == "finalized"
|
||||
end
|
||||
end
|
||||
|
||||
describe "loading" do
|
||||
it "should configure with all plugin config keys loaded" do
|
||||
# Register a plugin for our test
|
||||
register_plugin("2") do |plugin|
|
||||
plugin.config("foo") { OpenStruct }
|
||||
end
|
||||
|
||||
# Create the proc we're testing
|
||||
config_proc = Proc.new do |config|
|
||||
config.foo.bar = "value"
|
||||
end
|
||||
|
||||
# Test that it works properly
|
||||
config = described_class.load(config_proc)
|
||||
config.foo.bar.should == "value"
|
||||
end
|
||||
end
|
||||
|
||||
describe "merging" do
|
||||
it "should merge available configuration keys" do
|
||||
old = Vagrant::Config::V2::Root.new({ :foo => Object })
|
||||
new = Vagrant::Config::V2::Root.new({ :bar => Object })
|
||||
result = described_class.merge(old, new)
|
||||
result.foo.should be_kind_of(Object)
|
||||
result.bar.should be_kind_of(Object)
|
||||
end
|
||||
|
||||
it "should merge instantiated objects" do
|
||||
config_class = Class.new do
|
||||
attr_accessor :value
|
||||
end
|
||||
|
||||
old = Vagrant::Config::V2::Root.new({ :foo => config_class })
|
||||
old.foo.value = "old"
|
||||
|
||||
new = Vagrant::Config::V2::Root.new({ :bar => config_class })
|
||||
new.bar.value = "new"
|
||||
|
||||
result = described_class.merge(old, new)
|
||||
result.foo.value.should == "old"
|
||||
result.bar.value.should == "new"
|
||||
end
|
||||
|
||||
it "should merge conflicting classes by calling `merge`" do
|
||||
config_class = Class.new do
|
||||
attr_accessor :value
|
||||
|
||||
def merge(new)
|
||||
result = self.class.new
|
||||
result.value = @value + new.value
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
old = Vagrant::Config::V2::Root.new({ :foo => config_class })
|
||||
old.foo.value = 10
|
||||
|
||||
new = Vagrant::Config::V2::Root.new({ :foo => config_class })
|
||||
new.foo.value = 15
|
||||
|
||||
result = described_class.merge(old, new)
|
||||
result.foo.value.should == 25
|
||||
end
|
||||
end
|
||||
|
||||
describe "upgrading" do
|
||||
it "should continue fine if the key doesn't implement upgrade" do
|
||||
# Make an old V1 root object
|
||||
old = Vagrant::Config::V1::Root.new({ :foo => Class.new })
|
||||
|
||||
# It should work fine
|
||||
expect { result = described_class.upgrade(old) }.to_not raise_error
|
||||
end
|
||||
|
||||
it "should upgrade the config if it implements the upgrade method" do
|
||||
# Create the old V1 class that will be upgraded
|
||||
config_class = Class.new do
|
||||
attr_accessor :value
|
||||
|
||||
def upgrade(new)
|
||||
new.foo.value = value * 2
|
||||
end
|
||||
end
|
||||
|
||||
# Create the new V2 plugin it is writing to
|
||||
register_plugin("2") do |p|
|
||||
p.config("foo") { OpenStruct }
|
||||
end
|
||||
|
||||
# Test it out!
|
||||
old = Vagrant::Config::V1::Root.new({ :foo => config_class })
|
||||
old.foo.value = 5
|
||||
|
||||
data = described_class.upgrade(old)
|
||||
data[0].foo.value.should == 10
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
describe Vagrant::Config::V2::Root do
|
||||
include_context "unit"
|
||||
|
||||
it "should provide access to config objects" do
|
||||
foo_class = Class.new
|
||||
map = { :foo => foo_class }
|
||||
|
||||
instance = described_class.new(map)
|
||||
foo = instance.foo
|
||||
foo.should be_kind_of(foo_class)
|
||||
instance.foo.should eql(foo)
|
||||
end
|
||||
|
||||
it "should raise a proper NoMethodError if a config key doesn't exist" do
|
||||
instance = described_class.new({})
|
||||
expect { instance.foo }.to raise_error(NoMethodError)
|
||||
end
|
||||
|
||||
it "can be created with initial state" do
|
||||
instance = described_class.new({}, { :foo => "bar" })
|
||||
instance.foo.should == "bar"
|
||||
end
|
||||
|
||||
it "should return internal state" do
|
||||
map = { "foo" => Object, "bar" => Object }
|
||||
instance = described_class.new(map)
|
||||
instance.__internal_state.should == {
|
||||
"config_map" => map,
|
||||
"keys" => {}
|
||||
}
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue