diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index ee0d8ea25..ab535640c 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -784,6 +784,10 @@ module Vagrant error_key(:vagrantfile_syntax_error) end + class VagrantfileTemplateNotFoundError < VagrantError + error_key(:vagrantfile_template_not_found_error) + end + class VagrantfileWriteError < VagrantError error_key(:vagrantfile_write_error) end diff --git a/plugins/commands/init/command.rb b/plugins/commands/init/command.rb index 91bd0ff8b..a86c15494 100644 --- a/plugins/commands/init/command.rb +++ b/plugins/commands/init/command.rb @@ -14,6 +14,7 @@ module VagrantPlugins force: false, minimal: false, output: "Vagrantfile", + template: nil } opts = OptionParser.new do |o| @@ -30,7 +31,7 @@ module VagrantPlugins options[:force] = f end - o.on("-m", "--minimal", "Create minimal Vagrantfile (no help comments)") do |m| + o.on("-m", "--minimal", "Use minimal Vagrantfile template (no help comments). Ignored with --template") do |m| options[:minimal] = m end @@ -38,6 +39,10 @@ module VagrantPlugins "Output path for the box. '-' for stdout") do |output| options[:output] = output end + + o.on("--template FILE", String, "Path to Vagrantfile template") do |template| + options[:template] = template + end end # Parse the options @@ -51,16 +56,32 @@ module VagrantPlugins raise Vagrant::Errors::VagrantfileExistsError if save_path.exist? end - template = "templates/commands/init/Vagrantfile" - if options[:minimal] - template = "templates/commands/init/Vagrantfile.min" + # Determine the template and template root to use + template_root = "" + if options[:template].nil? + options[:template] = "Vagrantfile" + + if options[:minimal] + options[:template] = "Vagrantfile.min" + end + + template_root = ::Vagrant.source_root.join("templates/commands/init") end - template_path = ::Vagrant.source_root.join(template) - contents = Vagrant::Util::TemplateRenderer.render(template_path, + # Strip the .erb extension off the template if the user passes it in + options[:template] = options[:template].chomp(".erb") + + # Make sure the template actually exists + full_template_path = Vagrant::Util::TemplateRenderer.new(options[:template], template_root: template_root).full_template_path + if !File.file?(full_template_path) + raise Vagrant::Errors::VagrantfileTemplateNotFoundError, path: full_template_path + end + + contents = Vagrant::Util::TemplateRenderer.render(options[:template], box_name: argv[0] || "base", box_url: argv[1], box_version: options[:box_version], + template_root: template_root ) if save_path diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 0e673586a..5608c3814 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1379,6 +1379,9 @@ en: message is reproduced below for convenience: %{file} + vagrantfile_template_not_found_error: |- + The Vagrantfile template '%{path}' does not exist. Please double check + the template path and try again. vagrantfile_write_error: |- The user that is running Vagrant doesn't have the proper permissions to write a Vagrantfile to the specified location. Please ensure that diff --git a/test/unit/plugins/commands/init/command_test.rb b/test/unit/plugins/commands/init/command_test.rb index 3bbafa8d6..e821c5a2e 100644 --- a/test/unit/plugins/commands/init/command_test.rb +++ b/test/unit/plugins/commands/init/command_test.rb @@ -37,6 +37,36 @@ describe VagrantPlugins::CommandInit::Command do expect(contents).to_not match(/provision/) end + it "creates a custom Vagrantfile using a relative template path" do + described_class.new(["--template", "test/unit/templates/commands/init/Vagrantfile"], env).execute + contents = File.read(vagrantfile_path) + expect(contents).to match(/config.vm.hostname = "vagrant.dev"/) + end + + it "creates a custom Vagrantfile using an absolute template path" do + described_class.new(["--template", ::Vagrant.source_root.join("test/unit/templates/commands/init/Vagrantfile").to_s], env).execute + contents = File.read(vagrantfile_path) + expect(contents).to match(/config.vm.hostname = "vagrant.dev"/) + end + + it "creates a custom Vagrantfile using a provided template with the extension included" do + described_class.new(["--template", ::Vagrant.source_root.join("test/unit/templates/commands/init/Vagrantfile.erb").to_s], env).execute + contents = File.read(vagrantfile_path) + expect(contents).to match(/config.vm.hostname = "vagrant.dev"/) + end + + it "ignores the -m option when using a provided template" do + described_class.new(["-m", "--template", ::Vagrant.source_root.join("test/unit/templates/commands/init/Vagrantfile").to_s], env).execute + contents = File.read(vagrantfile_path) + expect(contents).to match(/config.vm.hostname = "vagrant.dev"/) + end + + it "raises an appropriate exception when the template file can't be found" do + expect { + described_class.new(["--template", "./a/b/c/template"], env).execute + }.to raise_error(Vagrant::Errors::VagrantfileTemplateNotFoundError) + end + it "does not overwrite an existing Vagrantfile" do # Create an existing Vagrantfile File.open(File.join(env.cwd, "Vagrantfile"), "w+") { |f| f.write("") } diff --git a/test/unit/templates/commands/init/Vagrantfile.erb b/test/unit/templates/commands/init/Vagrantfile.erb new file mode 100644 index 000000000..b7f6e26a7 --- /dev/null +++ b/test/unit/templates/commands/init/Vagrantfile.erb @@ -0,0 +1,20 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure("2") do |config| + config.vm.hostname = "vagrant.dev" + config.vm.box = "<%= box_name %>" + <% if box_version -%> + config.vm.box_version = "<%= box_version %>" + <% end -%> + + <% if box_url -%> + # The url from where the 'config.vm.box' box will be fetched if it + # doesn't already exist on the user's system. + config.vm.box_url = "<%= box_url %>" + <% end -%> +end