diff --git a/lib/vagrant/actions/import.rb b/lib/vagrant/actions/import.rb index 9f8c5c0a8..193f005a8 100644 --- a/lib/vagrant/actions/import.rb +++ b/lib/vagrant/actions/import.rb @@ -1,11 +1,18 @@ module Vagrant module Actions class Import < Base + #First arg should be the ovf_file location for import + def initialize(vm, *args) + super vm + @ovf_file = args[0] + end + def execute! @vm.invoke_around_callback(:import) do Busy.busy do logger.info "Importing base VM (#{Vagrant.config[:vm][:base]})..." - @vm.vm = VirtualBox::VM.import(File.expand_path(Vagrant.config[:vm][:base])) + # Use the first argument passed to the action + @vm.vm = VirtualBox::VM.import(@ovf_file || File.expand_path(Vagrant.config[:vm][:base])) end end end diff --git a/lib/vagrant/actions/move_hard_drive.rb b/lib/vagrant/actions/move_hard_drive.rb index 518aa5922..72d6e649f 100644 --- a/lib/vagrant/actions/move_hard_drive.rb +++ b/lib/vagrant/actions/move_hard_drive.rb @@ -12,9 +12,17 @@ error destroy_drive_after { clone_and_attach } end - # TODO: Better way to detect main bootup drive? def hard_drive - @vm.storage_controllers.first.devices.first + @hard_drive ||= find_hard_drive + end + + # TODO won't work if the first disk is not the boot disk or even if there are multiple disks + def find_hard_drive + @vm.storage_controllers.each do |sc| + sc.devices.each do |d| + return d if d.image.is_a?(VirtualBox::HardDrive) + end + end end def clone_and_attach @@ -40,4 +48,4 @@ error end end end -end \ No newline at end of file +end diff --git a/lib/vagrant/actions/package.rb b/lib/vagrant/actions/package.rb index 54461896d..2cceda6a1 100644 --- a/lib/vagrant/actions/package.rb +++ b/lib/vagrant/actions/package.rb @@ -19,7 +19,7 @@ module Vagrant Zlib::GzipWriter.open(compressed_file_name) do |gz| files_to_compress.each do |file| # Delimit the files, and guarantee new line for next file if not the first - gz.write "#{delimiter}#{file}#{delimiter}" + gz.write "#{delimiter}#{File.basename(file)}#{delimiter}" File.open(file).each { |line| gz.write(line) } end end diff --git a/lib/vagrant/actions/unpackage.rb b/lib/vagrant/actions/unpackage.rb new file mode 100644 index 000000000..2bca0f275 --- /dev/null +++ b/lib/vagrant/actions/unpackage.rb @@ -0,0 +1,71 @@ +module Vagrant + module Actions + class Unpackage < Base + def initialize(vm, *args) + super vm + @package_file_path = args[0] + end + + def execute! + # Exit if folder of same name exists + # TODO provide a way for them to specify the directory name + error_and_exit(<<-error) if File.exists?(new_base_dir) +The directory `#{file_name_without_extension}` already exists under #{Vagrant.config[:vagrant][:home]}. Please +remove it, rename your packaged VM file, or (TODO) specifiy an +alternate directory +error + + logger.info "Creating working new base directory: #{new_base_dir} ..." + FileUtils.mkpath(new_base_dir) + + logger.info "Decompressing the packaged VM: #{package_file_path} to: #{new_base_dir}..." + decompress_to new_base_dir + + #Return the ovf file for importation + Dir["#{new_base_dir}/*.ovf"].first + end + + def new_base_dir + File.join(Vagrant.config[:vagrant][:home], file_name_without_extension) + end + + def file_name_without_extension + File.basename(package_file_path, '.*') + end + + def package_file_path + File.expand_path(@package_file_path) + end + + def decompress_to(dir, file_delimeter=Vagrant.config[:package][:delimiter_regex]) + file = nil + Zlib::GzipReader.open(package_file_path) do |gz| + begin + gz.each_line do |line| + + # If the line is a file delimiter create new file and write to it + if line =~ file_delimeter + + #Write the the part of the line belonging to the previous file + if file + file.write $1 + file.close + end + + #Open a new file with the name contained in the delimiter + file = File.open(File.join(dir, $2), 'w') + + #Write the rest of the line to the new file + file.write $3 + else + file.write line + end + end + ensure + file.close if file + end + end + end + end + end +end diff --git a/lib/vagrant/actions/up.rb b/lib/vagrant/actions/up.rb index f4910c3d9..263c6316e 100644 --- a/lib/vagrant/actions/up.rb +++ b/lib/vagrant/actions/up.rb @@ -1,12 +1,20 @@ module Vagrant module Actions class Up < Base + #First arg should be the ovf_file location for import + def initialize(vm, *args) + super vm + @ovf_file = args[0] + end + def prepare # Up is a "meta-action" so it really just queues up a bunch # of other actions in its place: - steps = [Import, ForwardPorts, SharedFolders, Start] + @vm.add_action(Import, @ovf_file) + + steps = [ForwardPorts, SharedFolders, Start] steps << Provision if Vagrant.config.chef.enabled - steps.insert(1, MoveHardDrive) if Vagrant.config.vm.hd_location + steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location steps.each do |action_klass| @vm.add_action(action_klass) diff --git a/lib/vagrant/commands.rb b/lib/vagrant/commands.rb index 325b2f20a..cc12c7f2b 100644 --- a/lib/vagrant/commands.rb +++ b/lib/vagrant/commands.rb @@ -130,12 +130,11 @@ error error_and_exit(<<-error) unless name Please specify a target package to unpack and import error - VM.up(VM.unpackage(name)) - end - + + VM.execute!(Actions::Up, VM.execute!(Actions::Unpackage, name)) + end private - def act_on_vm(&block) yield Env.persisted_vm Env.persisted_vm.execute! diff --git a/lib/vagrant/vm.rb b/lib/vagrant/vm.rb index 3836c6343..85520106e 100644 --- a/lib/vagrant/vm.rb +++ b/lib/vagrant/vm.rb @@ -14,62 +14,6 @@ module Vagrant vm.execute! end - # Unpack the specified vm package - def unpackage(package_path) - working_dir = package_path.chomp(File.extname(package_path)) - new_base_dir = File.join(Vagrant.config[:vagrant][:home], File.basename(package_path, '.*')) - - # Exit if folder of same name exists - # TODO provide a way for them to specify the directory name - error_and_exit(<<-error) if File.exists?(new_base_dir) -The directory `#{File.basename(package_path, '.*')}` already exists under #{Vagrant.config[:vagrant][:home]}. Please -remove it, rename your packaged VM file, or (TODO) specifiy an -alternate directory -error - - logger.info "Creating working dir: #{working_dir} ..." - FileUtils.mkpath(working_dir) - - logger.info "Decompressing the packaged VM: #{package_path} ..." - decompress(package_path, working_dir) - - logger.info "Moving the unpackaged VM to #{new_base_dir} ..." - FileUtils.mv(working_dir, Vagrant.config[:vagrant][:home]) - - #Return the ovf file for importation - Dir["#{new_base_dir}/*.ovf"].first - end - - def decompress(path, dir, file_delimeter=Vagrant.config[:package][:delimiter_regex]) - file = nil - Zlib::GzipReader.open(path) do |gz| - begin - gz.each_line do |line| - - # If the line is a file delimiter create new file and write to it - if line =~ file_delimeter - - #Write the the part of the line belonging to the previous file - if file - file.write $1 - file.close - end - - #Open a new file with the name contained in the delimiter - file = File.open(File.join(dir, $2), 'w') - - #Write the rest of the line to the new file - file.write $3 - else - file.write line - end - end - ensure - file.close if file - end - end - end - # Finds a virtual machine by a given UUID and either returns # a Vagrant::VM object or returns nil. def find(uuid) @@ -96,11 +40,13 @@ error # Call the prepare method on each once its # initialized, then call the execute! method + return_value = nil [:prepare, :execute!].each do |method| @actions.each do |action| - action.send(method) + return_value = action.send(method) end end + return_value end # Invokes an "around callback" which invokes before_name and @@ -141,5 +87,7 @@ error def powered_off?; @vm.powered_off? end def export(filename); @vm.export(filename, {}, true) end + + def storage_controllers; @vm.storage_controllers end end end diff --git a/test/vagrant/actions/move_hard_drive_test.rb b/test/vagrant/actions/move_hard_drive_test.rb index 2adec5bf4..7891b28e5 100644 --- a/test/vagrant/actions/move_hard_drive_test.rb +++ b/test/vagrant/actions/move_hard_drive_test.rb @@ -10,6 +10,21 @@ class MoveHardDriveActionTest < Test::Unit::TestCase end end + + should "be able to identifiy a hard drive within the storage controllers" do + hd = mock('hd') + hd_image = mock('hd_image') + hd_image.expects(:is_a?).returns(true) + hd.expects(:image).returns(hd_image) + + dvd = mock('dvd') + controller = mock('controller') + controller.expects(:devices).returns([hd, dvd]) + + @mock_vm.expects(:storage_controllers).once.returns([controller]) + assert_equal @action.find_hard_drive, hd + end + context "execution" do should "error and exit if the vm is not powered off" do @mock_vm.expects(:powered_off?).returns(false) diff --git a/test/vagrant/actions/unpackage_test.rb b/test/vagrant/actions/unpackage_test.rb new file mode 100644 index 000000000..f1574cddf --- /dev/null +++ b/test/vagrant/actions/unpackage_test.rb @@ -0,0 +1,19 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'test_helper') + +class UnpackageActionTest < Test::Unit::TestCase + setup do + @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::Unpackage) + mock_config + end + + # TODO test actual decompression + should "call decompress with the path to the file and the directory to decompress to" do + new_base_dir = File.join Vagrant.config[:vagrant][:home], 'something' + file = File.join(FileUtils.pwd, 'something.box') + FileUtils.expects(:mkpath).with(new_base_dir).once + Dir.expects(:[]).returns(File.join new_base_dir, 'something.ovf') + @action.expects(:decompress_to).with(new_base_dir).once + @action.stubs(:package_file_path).returns(file) + @action.execute! + end +end diff --git a/test/vagrant/actions/up_test.rb b/test/vagrant/actions/up_test.rb index c323124ef..47db3c0c9 100644 --- a/test/vagrant/actions/up_test.rb +++ b/test/vagrant/actions/up_test.rb @@ -8,11 +8,12 @@ class UpActionTest < Test::Unit::TestCase context "sub-actions" do setup do - @default_order = [Vagrant::Actions::Import, Vagrant::Actions::ForwardPorts, Vagrant::Actions::SharedFolders, Vagrant::Actions::Start] + @default_order = [Vagrant::Actions::ForwardPorts, Vagrant::Actions::SharedFolders, Vagrant::Actions::Start] end def setup_action_expectations default_seq = sequence("default_seq") + @mock_vm.expects(:add_action).with(Vagrant::Actions::Import, nil).once.in_sequence(default_seq) @default_order.each do |action| @mock_vm.expects(:add_action).with(action).once.in_sequence(default_seq) end @@ -39,7 +40,7 @@ class UpActionTest < Test::Unit::TestCase config.vm.hd_location = "foo" end - @default_order.insert(1, Vagrant::Actions::MoveHardDrive) + @default_order.insert(0, Vagrant::Actions::MoveHardDrive) setup_action_expectations @action.prepare end diff --git a/test/vagrant/vm_test.rb b/test/vagrant/vm_test.rb index 4b875515f..63b6ec07a 100644 --- a/test/vagrant/vm_test.rb +++ b/test/vagrant/vm_test.rb @@ -197,18 +197,4 @@ class VMTest < Test::Unit::TestCase end end end - - context "unpackaging a vm" do - - # TODO test actual decompression - should "call decompress with the path to the file and the directory to decompress to" do - working_dir = File.join FileUtils.pwd, 'something' - file = File.join(FileUtils.pwd, 'something.box') - FileUtils.expects(:mkpath).with(working_dir).once - FileUtils.expects(:mv).with(working_dir, Vagrant.config[:vagrant][:home]).once - Vagrant::VM.expects(:decompress).with(file, working_dir).once - Vagrant::VM.unpackage(file) - - end - end end