Support warnings/errors when upgrading Vagrantfiles internally

This commit is contained in:
Mitchell Hashimoto 2013-01-20 22:04:50 -05:00
parent 6965525b35
commit 2d57afbbda
9 changed files with 133 additions and 18 deletions

View File

@ -87,6 +87,11 @@ module Vagrant
# This will hold our result # This will hold our result
result = current_config_klass.init result = current_config_klass.init
# Keep track of the warnings and errors that may come from
# upgrading the Vagrantfiles
warnings = []
errors = []
order.each do |key| order.each do |key|
next if !@sources.has_key?(key) next if !@sources.has_key?(key)
@ -98,6 +103,11 @@ module Vagrant
version_loader = @versions.get(version) version_loader = @versions.get(version)
version_config = version_loader.load(proc) version_config = version_loader.load(proc)
# Store the errors/warnings associated with loading this
# configuration. We'll store these for later.
version_warnings = []
version_errors = []
# If this version is not the current version, then we need # If this version is not the current version, then we need
# to upgrade to the latest version. # to upgrade to the latest version.
if version != current_version if version != current_version
@ -114,30 +124,40 @@ module Vagrant
upgrade_result = loader.upgrade(version_config) upgrade_result = loader.upgrade(version_config)
# XXX: Do something with the warning/error messages # XXX: Do something with the warning/error messages
warnings = upgrade_result[1] this_warnings = upgrade_result[1]
errors = upgrade_result[2] this_errors = upgrade_result[2]
@logger.debug("Upgraded to version #{next_version} with " + @logger.debug("Upgraded to version #{next_version} with " +
"#{warnings.length} warnings and " + "#{this_warnings.length} warnings and " +
"#{errors.length} errors") "#{this_errors.length} errors")
# Append loading this to the version warnings and errors
version_warnings += this_warnings
version_errors += this_errors
# Store the new upgraded version # Store the new upgraded version
version_config = upgrade_result[0] version_config = upgrade_result[0]
end end
end end
# Cache the results for this proc # Cache the loaded configuration along with any warnings
@config_cache[proc] = version_config # or errors so that they can be retrieved later.
@config_cache[proc] = [version_config, version_warnings, version_errors]
else else
@logger.debug("Loading from: #{key} (cache)") @logger.debug("Loading from: #{key} (cache)")
end end
# Merge the configurations # Merge the configurations
result = current_config_klass.merge(result, @config_cache[proc]) cache_data = @config_cache[proc]
result = current_config_klass.merge(result, cache_data[0])
# Append the total warnings/errors
warnings += cache_data[1]
errors += cache_data[2]
end end
end end
@logger.debug("Configuration loaded successfully, finalizing and returning") @logger.debug("Configuration loaded successfully, finalizing and returning")
current_config_klass.finalize(result) [current_config_klass.finalize(result), warnings, errors]
end end
protected protected

View File

@ -92,14 +92,24 @@ module Vagrant
# Get a new root # Get a new root
root = new_root_object root = new_root_object
# Store the warnings/errors
warnings = []
errors = []
# Go through the old keys and upgrade them if they can be # Go through the old keys and upgrade them if they can be
old.__internal_state["keys"].each do |_, old_value| old.__internal_state["keys"].each do |_, old_value|
if old_value.respond_to?(:upgrade) if old_value.respond_to?(:upgrade)
old_value.upgrade(root) result = old_value.upgrade(root)
# Sanity check to guard against random return values
if result.is_a?(Array)
warnings += result[0]
errors += result[1]
end
end end
end end
[root, [], []] [root, warnings, errors]
end end
protected protected

View File

@ -247,7 +247,8 @@ module Vagrant
# with the box Vagrantfile (if it has one). # with the box Vagrantfile (if it has one).
vm_config_key = "vm_#{name}".to_sym vm_config_key = "vm_#{name}".to_sym
@config_loader.set(vm_config_key, sub_vm.config_procs) @config_loader.set(vm_config_key, sub_vm.config_procs)
config = @config_loader.load([:default, :home, :root, vm_config_key]) config, config_warnings, config_errors = \
@config_loader.load([:default, :home, :root, vm_config_key])
box = nil box = nil
begin begin
@ -270,7 +271,8 @@ module Vagrant
@logger.info("Box exists with Vagrantfile. Reloading machine config.") @logger.info("Box exists with Vagrantfile. Reloading machine config.")
box_config_key = "box_#{box.name}_#{box.provider}".to_sym box_config_key = "box_#{box.name}_#{box.provider}".to_sym
@config_loader.set(box_config_key, box_vagrantfile) @config_loader.set(box_config_key, box_vagrantfile)
config = @config_loader.load([:default, box_config_key, :home, :root, vm_config_key]) config, config_warnings, config_errors = \
@config_loader.load([:default, box_config_key, :home, :root, vm_config_key])
end end
end end
@ -282,6 +284,22 @@ module Vagrant
machine_data_path = @local_data_path.join("machines/#{name}/#{provider}") machine_data_path = @local_data_path.join("machines/#{name}/#{provider}")
FileUtils.mkdir_p(machine_data_path) FileUtils.mkdir_p(machine_data_path)
# If there were warnings or errors we want to output them
if !config_warnings.empty? || !config_errors.empty?
# The color of the output depends on whether we have warnings
# or errors...
level = config_errors.empty? ? :warn : :error
output = Util::TemplateRenderer.render(
"config/messages",
:warnings => config_warnings,
:errors => config_errors).chomp
@ui.send(level, I18n.t("vagrant.general.config_upgrade_messages",
:output => output))
# If we had errors, then we bail
raise Errors::ConfigUpgradeErrors if !config_errors.empty?
end
# Create the machine and cache it for future calls. This will also # Create the machine and cache it for future calls. This will also
# return the machine from this method. # return the machine from this method.
@machines[cache_key] = Machine.new(name, provider_cls, provider_config, @machines[cache_key] = Machine.new(name, provider_cls, provider_config,
@ -448,7 +466,8 @@ module Vagrant
# Make the initial call to get the "global" config. This is mostly # Make the initial call to get the "global" config. This is mostly
# only useful to get the list of machines that we are managing. # only useful to get the list of machines that we are managing.
@config_global = @config_loader.load([:default, :home, :root]) # Because of this, we ignore any warnings or errors.
@config_global, _ = @config_loader.load([:default, :home, :root])
# Old order: default, box, home, root, vm # Old order: default, box, home, root, vm
end end

View File

@ -154,6 +154,10 @@ module Vagrant
error_key(:config_invalid) error_key(:config_invalid)
end end
class ConfigUpgradeErrors < VagrantError
error_key(:config_upgrade_errors)
end
class DestroyRequiresForce < VagrantError class DestroyRequiresForce < VagrantError
status_code(74) status_code(74)
error_key(:destroy_requires_force) error_key(:destroy_requires_force)

View File

@ -131,7 +131,14 @@ module VagrantPlugins
new.vm.define(name, options, &block) new.vm.define(name, options, &block)
end end
# XXX: Warning: `vm.name` is useless now # If name is used, warn that it has no effect anymore
warnings = []
if @name
warnings << "`config.vm.name` has no effect anymore. Names are derived\n" +
"directly from any `config.vm.define` calls."
end
[warnings, []]
end end
end end
end end

View File

@ -0,0 +1,14 @@
<% if !warnings.empty? -%>
Warnings:
<% warnings.each do |warning| -%>
* <%= warning %>
<% end -%>
<% end -%>
<% if !errors.empty? -%>
Errors:
<% errors.each do |error| -%>
* <%= error %>
<% end -%>
<% end -%>

View File

@ -1,6 +1,15 @@
en: en:
vagrant: vagrant:
general: general:
config_upgrade_messages: |-
There were warnings and/or errors while loading your Vagrantfile.
Your Vagrantfile was written for an earlier version of Vagrant,
and while Vagrant does the best it can to remain backwards
compatible, there are some cases where things have changed
significantly enough to warrant a message. These messages are
shown below.
%{output}
moving_home_dir: "Moving old Vagrant home directory to new location: %{directory}" moving_home_dir: "Moving old Vagrant home directory to new location: %{directory}"
home_dir_migration_failed: |- home_dir_migration_failed: |-
Both an old and new Vagrant home directory exist. Only the new one will Both an old and new Vagrant home directory exist. Only the new one will
@ -61,6 +70,9 @@ en:
the following errors and try again: the following errors and try again:
%{errors} %{errors}
config_upgrade_errors: |-
Because there were errors upgrading your Vagrantfiles, Vagrant
can no longer continue. Please fix the errors above and try again.
destroy_requires_force: |- destroy_requires_force: |-
Destroy doesn't have a TTY to ask for confirmation. Please pass the Destroy doesn't have a TTY to ask for confirmation. Please pass the
`--force` flag to force a destroy, otherwise attach a TTY so that `--force` flag to force a destroy, otherwise attach a TTY so that

View File

@ -49,9 +49,11 @@ describe Vagrant::Config::Loader do
end end
instance.set(:proc, [[current_version, proc]]) instance.set(:proc, [[current_version, proc]])
config = instance.load([:proc]) config, warnings, errors = instance.load([:proc])
config[:foo].should == "yep" config[:foo].should == "yep"
warnings.should == []
errors.should == []
end end
end end
@ -70,7 +72,7 @@ describe Vagrant::Config::Loader do
# Run the actual configuration and assert that we get the proper result # Run the actual configuration and assert that we get the proper result
instance.set(:proc, [[current_version, proc]]) instance.set(:proc, [[current_version, proc]])
config = instance.load([:proc]) config, _ = instance.load([:proc])
config[:foo].should == "yep" config[:foo].should == "yep"
config[:finalized].should == true config[:finalized].should == true
end end
@ -93,10 +95,33 @@ describe Vagrant::Config::Loader do
# Load a version 1 proc, and verify it is upgraded to version 2 # Load a version 1 proc, and verify it is upgraded to version 2
proc = lambda { |config| config[:foo] = "yep" } proc = lambda { |config| config[:foo] = "yep" }
instance.set(:proc, [["1", proc]]) instance.set(:proc, [["1", proc]])
config = instance.load([:proc]) config, _ = instance.load([:proc])
config[:foo].should == "yep" config[:foo].should == "yep"
config[:v2].should == true config[:v2].should == true
end end
it "should keep track of warnings and errors" do
test_loader_v2 = Class.new(test_loader) do
def self.upgrade(old)
new = old.dup
new[:v2] = true
[new, ["foo!"], ["bar!"]]
end
end
versions.register("2") { test_loader_v2 }
version_order << "2"
# Load a version 1 proc, and verify it is upgraded to version 2
proc = lambda { |config| config[:foo] = "yep" }
instance.set(:proc, [["1", proc]])
config, warnings, errors = instance.load([:proc])
config[:foo].should == "yep"
config[:v2].should == true
warnings.should == ["foo!"]
errors.should == ["bar!"]
end
end end
describe "loading edge cases" do describe "loading edge cases" do
@ -110,7 +135,7 @@ describe Vagrant::Config::Loader do
instance.set(:proc, [[current_version, proc]]) instance.set(:proc, [[current_version, proc]])
5.times do 5.times do
result = instance.load([:proc]) result, _ = instance.load([:proc])
# Verify the config result # Verify the config result
result[:foo].should == "yep" result[:foo].should == "yep"

View File

@ -128,6 +128,8 @@ describe Vagrant::Config::V2::Loader do
def upgrade(new) def upgrade(new)
new.foo.value = value * 2 new.foo.value = value * 2
[["foo"], ["bar"]]
end end
end end
@ -142,6 +144,8 @@ describe Vagrant::Config::V2::Loader do
data = described_class.upgrade(old) data = described_class.upgrade(old)
data[0].foo.value.should == 10 data[0].foo.value.should == 10
data[1].should == ["foo"]
data[2].should == ["bar"]
end end
end end
end end