diff --git a/bin/vagrant-package b/bin/vagrant-package index b55781d6c..782229d43 100755 --- a/bin/vagrant-package +++ b/bin/vagrant-package @@ -18,7 +18,7 @@ GitStyleBinary.command do banner <<-EOS Usage: #{command.full_name} #{all_options_string} -Package the current vagrant environment +Package the current vagrant environment into a box. EOS run do |command| diff --git a/lib/vagrant/actions/vm/export.rb b/lib/vagrant/actions/vm/export.rb index 1a1efaeb2..6dafbecd1 100644 --- a/lib/vagrant/actions/vm/export.rb +++ b/lib/vagrant/actions/vm/export.rb @@ -2,13 +2,28 @@ module Vagrant module Actions module VM class Export < Base - def execute!(name=Vagrant.config.package.name, to=FileUtils.pwd) - folder = FileUtils.mkpath(File.join(to, name)) + attr_reader :temp_dir - logger.info "Creating export directory: #{folder} ..." - ovf_path = File.join(folder, "#{name}.ovf") + def execute! + setup_temp_dir + export + end - logger.info "Exporting required VM files to directory: #{folder} ..." + def setup_temp_dir + @temp_dir = File.join(Env.tmp_path, Time.now.to_i.to_s) + + logger.info "Creating temporary directory for export..." + FileUtils.mkpath(temp_dir) + + @runner.invoke_callback(:set_export_temp_path, @temp_dir) + end + + def ovf_path + File.join(temp_dir, Vagrant.config.vm.box_ovf) + end + + def export + logger.info "Exporting VM to #{ovf_path} ..." @runner.export(ovf_path) end end diff --git a/lib/vagrant/actions/vm/package.rb b/lib/vagrant/actions/vm/package.rb index 5d34f3d5f..d9dc3e0e7 100644 --- a/lib/vagrant/actions/vm/package.rb +++ b/lib/vagrant/actions/vm/package.rb @@ -2,48 +2,47 @@ module Vagrant module Actions module VM class Package < Base - attr_accessor :name, :to + attr_accessor :out_path + attr_accessor :temp_path - def initialize(vm, *args) - super vm - @name = args[0] - @to = args[1] + def initialize(vm, out_path = nil, *args) + super + @out_path = out_path || "package" + @temp_path = nil end def execute! - logger.info "Packaging VM into #{tar_path} ..." compress - - logger.info "Removing working directory ..." clean - - tar_path end def clean - FileUtils.rm_r(working_dir) - end - - def working_dir - FileUtils.mkpath(File.join(@to, @name)) + logger.info "Removing temporary directory ..." + FileUtils.rm_r(temp_path) end def tar_path - "#{working_dir}#{Vagrant.config.package.extension}" + File.join(FileUtils.pwd, "#{out_path}#{Vagrant.config.package.extension}") end def compress + logger.info "Packaging VM into #{tar_path} ..." Tar.open(tar_path, File::CREAT | File::WRONLY, 0644, Tar::GNU) do |tar| begin # Append tree will append the entire directory tree unless a relative folder reference is used current_dir = FileUtils.pwd - FileUtils.cd(@to) - tar.append_tree(@name) + FileUtils.cd(temp_path) + tar.append_tree(".") ensure FileUtils.cd(current_dir) end end end + + # This is a callback by Actions::VM::Export + def set_export_temp_path(temp_path) + @temp_path = temp_path + end end end end diff --git a/lib/vagrant/commands.rb b/lib/vagrant/commands.rb index 0ed0ab215..59c41051d 100644 --- a/lib/vagrant/commands.rb +++ b/lib/vagrant/commands.rb @@ -113,17 +113,14 @@ error # Export and package the current vm # # This command requires that an instance be powered off - def package(name=nil) + def package(out_path=nil) Env.load! Env.require_persisted_vm error_and_exit(<<-error) unless Env.persisted_vm.powered_off? The vagrant virtual environment you are trying to package must be powered off error - # TODO allow directory specification - act_on_vm do |vm| - vm.add_action(Actions::VM::Export) - vm.add_action(Actions::VM::Package, name || Vagrant.config[:package][:name], FileUtils.pwd) - end + + Env.persisted_vm.package(out_path) end # Manages the `vagrant box` command, allowing the user to add diff --git a/lib/vagrant/vm.rb b/lib/vagrant/vm.rb index 00037fa4c..709cd4f0c 100644 --- a/lib/vagrant/vm.rb +++ b/lib/vagrant/vm.rb @@ -19,6 +19,12 @@ module Vagrant @vm = vm end + def package(out_path) + add_action(Actions::VM::Export) + add_action(Actions::VM::Package, out_path) + execute! + end + def destroy execute!(Actions::VM::Stop) if @vm.running? diff --git a/test/vagrant/actions/vm/export_test.rb b/test/vagrant/actions/vm/export_test.rb index b1c6692c2..2bbc12b83 100644 --- a/test/vagrant/actions/vm/export_test.rb +++ b/test/vagrant/actions/vm/export_test.rb @@ -2,20 +2,66 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') class ExportActionTest < Test::Unit::TestCase setup do - @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Export) + @runner, @vm, @action = mock_action(Vagrant::Actions::VM::Export) mock_config end - should "setup and correct working directory and export to it" do - new_dir = File.join(FileUtils.pwd, Vagrant.config.package.name) - FileUtils.expects(:mkpath).with(new_dir).returns(new_dir) - @wrapper_vm.expects(:export).with(File.join(new_dir, "#{Vagrant.config.package.name}.ovf")) - @action.execute! + context "executing" do + should "setup the temp dir then export" do + exec_seq = sequence('execute') + @action.expects(:setup_temp_dir).once.in_sequence(exec_seq) + @action.expects(:export).once.in_sequence(exec_seq) + @action.execute! + end + end + context "setting up the temporary directory" do + setup do + @time_now = Time.now.to_i.to_s + Time.stubs(:now).returns(@time_now) -#FileUtils.expects(:rm_r).with(new_dir) + @tmp_path = "foo" + Vagrant::Env.stubs(:tmp_path).returns(@tmp_path) + @temp_dir = File.join(Vagrant::Env.tmp_path, @time_now) + end - # assert_equal Vagrant::VM.new(@mock_vm).package(name, location), "#{new_dir}.box" + should "create the temporary directory using the current time" do + FileUtils.expects(:mkpath).with(@temp_dir).once + @action.setup_temp_dir + end + + should "set the temporary directory to the temp_dir variable" do + @action.setup_temp_dir + assert_equal @temp_dir, @action.temp_dir + end + + should "call the set_export_temp_path callback" do + @runner.expects(:invoke_callback).with(:set_export_temp_path, @temp_dir).once + @action.setup_temp_dir + end + end + + context "path to OVF file" do + setup do + @temp_dir = "foo" + @action.stubs(:temp_dir).returns(@temp_dir) + end + + should "be the temporary directory joined with the OVF filename" do + assert_equal File.join(@temp_dir, Vagrant.config.vm.box_ovf), @action.ovf_path + end + end + + context "exporting" do + setup do + @ovf_path = mock("ovf_path") + @action.stubs(:ovf_path).returns(@ovf_path) + end + + should "call export on the runner with the ovf path" do + @runner.expects(:export).with(@ovf_path).once + @action.export + end end end diff --git a/test/vagrant/actions/vm/package_test.rb b/test/vagrant/actions/vm/package_test.rb index a2342a034..36cbc63d9 100644 --- a/test/vagrant/actions/vm/package_test.rb +++ b/test/vagrant/actions/vm/package_test.rb @@ -2,19 +2,17 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') class PackageActionTest < Test::Unit::TestCase setup do - @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Package) - @action.to = '/foo/bar/baz' - @action.name = 'bing' + @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Package, "bing") mock_config + + @temp_path = "temp_path" + @action.temp_path = @temp_path end context "executing" do setup do - @tar_path = "foo" - @action.stubs(:compress) @action.stubs(:clean) - @action.stubs(:tar_path).returns(@tar_path) end should "compress and remove the working directory" do @@ -23,10 +21,6 @@ class PackageActionTest < Test::Unit::TestCase @action.expects(:clean).in_sequence(package_seq) @action.execute! end - - should "return the tar path" do - assert_equal @tar_path, @action.execute! - end end context "cleaning up" do @@ -36,22 +30,16 @@ class PackageActionTest < Test::Unit::TestCase end should "remove the working directory" do - FileUtils.expects(:rm_r).with(@working_dir).once + FileUtils.expects(:rm_r).with(@temp_path).once @action.clean end end - context "working directory" do - should "create the directory" do - FileUtils.expects(:mkpath).with(File.join(@action.to, @action.name)) - @action.working_dir - end - end - context "tar path" do - should "be the working directory with the extension attached" do - @action.expects(:working_dir).returns("foo") - assert_equal "foo#{Vagrant.config.package.extension}", @action.tar_path + should "be the temporary directory with the name and extension attached" do + pwd = "foo" + FileUtils.stubs(:pwd).returns(pwd) + assert_equal File.join(pwd, "#{@action.out_path}#{Vagrant.config.package.extension}"), @action.tar_path end end @@ -79,15 +67,15 @@ class PackageActionTest < Test::Unit::TestCase should "cd to the directory and append the directory" do compress_seq = sequence("compress_seq") FileUtils.expects(:pwd).once.returns(@pwd).in_sequence(compress_seq) - FileUtils.expects(:cd).with(@action.to).in_sequence(compress_seq) - @tar.expects(:append_tree).with(@action.name).in_sequence(compress_seq) + FileUtils.expects(:cd).with(@temp_path).in_sequence(compress_seq) + @tar.expects(:append_tree).with(".").in_sequence(compress_seq) FileUtils.expects(:cd).with(@pwd).in_sequence(compress_seq) @action.compress end should "pop back to the current directory even if an exception is raised" do cd_seq = sequence("cd_seq") - FileUtils.expects(:cd).with(@action.to).raises(Exception).in_sequence(cd_seq) + FileUtils.expects(:cd).with(@temp_path).raises(Exception).in_sequence(cd_seq) FileUtils.expects(:cd).with(@pwd).in_sequence(cd_seq) assert_raises(Exception) { @@ -95,4 +83,12 @@ class PackageActionTest < Test::Unit::TestCase } end end + + context "export callback to set temp path" do + should "save to the temp_path directory" do + foo = mock("foo") + @action.set_export_temp_path(foo) + assert foo.equal?(@action.temp_path) + end + end end diff --git a/test/vagrant/commands_test.rb b/test/vagrant/commands_test.rb index 9c6b981e2..1a066b39f 100644 --- a/test/vagrant/commands_test.rb +++ b/test/vagrant/commands_test.rb @@ -155,8 +155,6 @@ class CommandsTest < Test::Unit::TestCase setup do @persisted_vm.stubs(:package) @persisted_vm.stubs(:powered_off?).returns(true) - @persisted_vm.expects(:add_action).twice - @persisted_vm.expects(:execute!) end should "require a persisted vm" do @@ -170,6 +168,17 @@ class CommandsTest < Test::Unit::TestCase @persisted_vm.expects(:package).never Vagrant::Commands.package end + + should "call package on the persisted VM" do + @persisted_vm.expects(:package).once + Vagrant::Commands.package + end + + should "pass in the out path to the package method" do + out_path = mock("out_path") + @persisted_vm.expects(:package).with(out_path).once + Vagrant::Commands.package(out_path) + end end context "box" do diff --git a/test/vagrant/vm_test.rb b/test/vagrant/vm_test.rb index 477414f23..10204c448 100644 --- a/test/vagrant/vm_test.rb +++ b/test/vagrant/vm_test.rb @@ -37,6 +37,17 @@ class VMTest < Test::Unit::TestCase @vm = Vagrant::VM.new(@mock_vm) end + context "packaging" do + should "queue up the actions and execute" do + out_path = mock("out_path") + action_seq = sequence("actions") + @vm.expects(:add_action).with(Vagrant::Actions::VM::Export).once.in_sequence(action_seq) + @vm.expects(:add_action).with(Vagrant::Actions::VM::Package, out_path).once.in_sequence(action_seq) + @vm.expects(:execute!).in_sequence(action_seq) + @vm.package(out_path) + end + end + context "destroying" do setup do @mock_vm.stubs(:running?).returns(false)