diff --git a/CHANGELOG.md b/CHANGELOG.md index a157fb076..c52232c5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## 0.6.0 (unreleased) + - Vagrant now gives a nice error message if there is a syntax error + in any Vagrantfile. [GH-154] - The format of the ".vagrant" file which stores persisted VMs has changed. This is **backwards incompatible**. Will provide an upgrade utility prior to 0.6 launch. diff --git a/bin/vagrant b/bin/vagrant index f1a7ac228..d8b765fd4 100755 --- a/bin/vagrant +++ b/bin/vagrant @@ -9,7 +9,7 @@ begin rescue Vagrant::Errors::VagrantError => e opts = { :_translate => false, :_prefix => false } env.ui.error e.message, opts if e.message - env.ui.error e.backtrace.join("\n"), opts if ENV["VAGRANT_DEBUG"] + env.ui.error e.backtrace.join("\n"), opts if ENV["VAGRANT_DEBUG"] || e.show_stacktrace exit e.status_code if e.respond_to?(:status_code) exit 999 # An error occurred with no status code defined end diff --git a/lib/vagrant/config.rb b/lib/vagrant/config.rb index 8de981ee7..0dd87d57f 100644 --- a/lib/vagrant/config.rb +++ b/lib/vagrant/config.rb @@ -52,7 +52,12 @@ module Vagrant queue.flatten.each do |item| if item.is_a?(String) && File.exist?(item) - load item + begin + load item + rescue SyntaxError + # Report syntax errors in a nice way for Vagrantfiles + raise Errors::VagrantfileSyntaxError.new(:file => item) + end elsif item.is_a?(Proc) self.class.run(&item) end diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 8d3f84273..50a45c123 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -29,6 +29,10 @@ module Vagrant define_method(:error_namespace) { namespace } end + def self.force_stacktrace + define_method(:show_stacktrace) { true } + end + def initialize(message=nil, *args) message = { :_key => message } if message && !message.is_a?(Hash) message = { :_key => error_key, :_namespace => error_namespace }.merge(message || {}) @@ -46,6 +50,9 @@ module Vagrant # {error_key} method but can be overridden here if needed. def error_key; nil; end + # Force the stacktrace to show (false by default) + def show_stacktrace; false; end + protected def translate_error(opts) @@ -209,6 +216,12 @@ module Vagrant error_key(:interrupted) end + class VagrantfileSyntaxError < VagrantError + status_code(41) + error_key(:vagrantfile_syntax_error) + force_stacktrace + end + class VirtualBoxInvalidOSE < VagrantError status_code(9) error_key(:virtualbox_invalid_ose) diff --git a/templates/locales/en.yml b/templates/locales/en.yml index de4209592..3c41b53f6 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -56,6 +56,11 @@ en: unspecified: |- A VM system type must be specified! This is done via the `config.vm.system` configuration value. Please read the documentation online for more information. + vagrantfile_syntax_error: |- + There is a syntax error in the following Vagrantfile. The stack trace + is also printed below for convenience. + + %{file} virtualbox_invalid_ose: |- Vagrant has detected you're using an OSE ("Open Source Edition") of VirtualBox. Vagrant currently doesn't support any of the OSE editions due to slight API diff --git a/test/vagrant/config_test.rb b/test/vagrant/config_test.rb index 1de62cf2d..587d279fb 100644 --- a/test/vagrant/config_test.rb +++ b/test/vagrant/config_test.rb @@ -57,6 +57,16 @@ class ConfigTest < Test::Unit::TestCase @instance.queue << filename @instance.load! end + + should "raise an exception if there is a syntax error in a file" do + @instance.queue << "foo" + File.expects(:exist?).with("foo").returns(true) + @instance.expects(:load).with("foo").raises(SyntaxError.new) + + assert_raises(Vagrant::Errors::VagrantfileSyntaxError) { + @instance.load! + } + end end context "adding configures" do diff --git a/test/vagrant/errors_test.rb b/test/vagrant/errors_test.rb index ab885df4f..a482e7b4f 100644 --- a/test/vagrant/errors_test.rb +++ b/test/vagrant/errors_test.rb @@ -39,4 +39,13 @@ class ErrorsTest < Test::Unit::TestCase klass = Class.new(@super) { error_key(:test_key_with_interpolation) } assert_equal I18n.t("vagrant.test.errors.test_key_with_interpolation", :key => "yo"), klass.new(:key => "yo").message end + + should "not force stacktrace show by default" do + assert !@super.new.show_stacktrace + end + + should "force stacktrace to show if enabled" do + klass = Class.new(@super) { force_stacktrace } + assert klass.new.show_stacktrace + end end