From c644cfad1ae2c3a096f0b21787cd7e5ddf5e604c Mon Sep 17 00:00:00 2001 From: John Bender Date: Fri, 19 Feb 2010 00:54:49 -0800 Subject: [PATCH] package and unpackage moved to tar, tarruby added --- Gemfile | 3 +- config/default.rb | 2 -- lib/vagrant.rb | 2 +- lib/vagrant/actions/import.rb | 7 ++-- lib/vagrant/actions/package.rb | 39 ++++++++++++++------- lib/vagrant/actions/unpackage.rb | 47 ++++++++------------------ lib/vagrant/commands.rb | 4 +-- lib/vagrant/config.rb | 2 -- test/test_helper.rb | 2 -- test/vagrant/actions/.#package_test.rb | 1 - test/vagrant/actions/import_test.rb | 20 +++++++++++ test/vagrant/actions/package_test.rb | 12 ++++++- test/vagrant/actions/unpackage_test.rb | 28 ++++++++++++--- 13 files changed, 105 insertions(+), 64 deletions(-) delete mode 120000 test/vagrant/actions/.#package_test.rb diff --git a/Gemfile b/Gemfile index 7103a75cd..70f63f354 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,7 @@ gem "net-ssh", ">= 2.0.19" gem "net-scp", ">= 1.0.2" gem "jashmenn-git-style-binaries", ">= 0.1.10" gem "json", ">= 1.2.0" +gem "tarruby", ">= 0.1.5" # Gems required for testing only. To install run # gem bundle test @@ -14,4 +15,4 @@ group :test do gem "contest", ">= 0.1.2" gem "mocha" gem "ruby-debug", ">= 0.10.3" if RUBY_VERSION < '1.9' -end \ No newline at end of file +end diff --git a/config/default.rb b/config/default.rb index 44989c6c0..6a019f2bf 100644 --- a/config/default.rb +++ b/config/default.rb @@ -19,8 +19,6 @@ Vagrant::Config.run do |config| config.package.name = 'vagrant' config.package.extension = '.box' - config.package.delimiter = 'VAGRANT' - config.package.delimiter_regex = /(.*)#{config.package.delimiter}(.+)#{config.package.delimiter}(.*[\n\r])/ config.chef.enabled = false config.chef.cookbooks_path = "cookbooks" diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 4e55e3d9d..88e61d95b 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -3,7 +3,7 @@ $:.unshift(libdir) PROJECT_ROOT = File.join(libdir, '..') unless defined?(PROJECT_ROOT) # The libs which must be loaded prior to the rest -%w{ftools json pathname logger virtualbox net/ssh +%w{ftools json pathname logger virtualbox net/ssh tarruby net/scp fileutils vagrant/util vagrant/actions/base}.each do |f| require f end diff --git a/lib/vagrant/actions/import.rb b/lib/vagrant/actions/import.rb index 193f005a8..eb85a47f9 100644 --- a/lib/vagrant/actions/import.rb +++ b/lib/vagrant/actions/import.rb @@ -1,18 +1,19 @@ module Vagrant module Actions class Import < Base + attr_accessor :ovf_file #First arg should be the ovf_file location for import def initialize(vm, *args) super vm - @ovf_file = args[0] + @ovf_file = File.expand_path(args[0] || Vagrant.config[:vm][:base]) end def execute! @vm.invoke_around_callback(:import) do Busy.busy do - logger.info "Importing base VM (#{Vagrant.config[:vm][:base]})..." + logger.info "Importing base VM (#{@ovf_file})..." # Use the first argument passed to the action - @vm.vm = VirtualBox::VM.import(@ovf_file || File.expand_path(Vagrant.config[:vm][:base])) + @vm.vm = VirtualBox::VM.import(@ovf_file) end end end diff --git a/lib/vagrant/actions/package.rb b/lib/vagrant/actions/package.rb index 2cceda6a1..a5b89af8b 100644 --- a/lib/vagrant/actions/package.rb +++ b/lib/vagrant/actions/package.rb @@ -1,26 +1,41 @@ module Vagrant module Actions class Package < Base - def execute!(name=Vagrant.config.package.name, to=FileUtils.pwd) - folder = FileUtils.mkpath(File.join(to, name)) - tar_path = "#{folder}#{Vagrant.config.package.extension}" + attr_accessor :name, :to + def initialize(vm, *args) + super vm + @name = args[0] + @to = args[1] + end + + def execute! logger.info "Packaging VM into #{tar_path} ..." - compress(Dir["#{folder}/*.*"], tar_path) + compress logger.info "Removing working directory ..." - FileUtils.rm_r(folder) + FileUtils.rm_r(working_dir) tar_path end - def compress(files_to_compress, compressed_file_name) - delimiter = Vagrant.config.package.delimiter - 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.basename(file)}#{delimiter}" - File.open(file).each { |line| gz.write(line) } + def working_dir + FileUtils.mkpath(File.join(@to, @name)) + end + + def tar_path + "#{working_dir}#{Vagrant.config.package.extension}" + end + + def compress + 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) + ensure + FileUtils.cd(current_dir) end end end diff --git a/lib/vagrant/actions/unpackage.rb b/lib/vagrant/actions/unpackage.rb index 2bca0f275..fbb27ea64 100644 --- a/lib/vagrant/actions/unpackage.rb +++ b/lib/vagrant/actions/unpackage.rb @@ -1,6 +1,9 @@ module Vagrant module Actions class Unpackage < Base + TAR_OPTIONS = [File::RDONLY, 0644, Tar::GNU] + attr_accessor :package_file_path + def initialize(vm, *args) super vm @package_file_path = args[0] @@ -15,55 +18,35 @@ 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: #{working_dir}..." + decompress - logger.info "Decompressing the packaged VM: #{package_file_path} to: #{new_base_dir}..." - decompress_to new_base_dir + logger.info "Moving decompressed files in: #{working_dir} to: #{new_base_dir} ..." + FileUtils.mv(working_dir, 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) + File.join(Vagrant.config.vagrant.home, file_name_without_extension) end def file_name_without_extension File.basename(package_file_path, '.*') end + def working_dir + package_file_path.chomp(File.extname(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 + def decompress + Tar.open(package_file_path, *TAR_OPTIONS) do |tar| + tar.extract_all end end end diff --git a/lib/vagrant/commands.rb b/lib/vagrant/commands.rb index cc12c7f2b..941c2f3f8 100644 --- a/lib/vagrant/commands.rb +++ b/lib/vagrant/commands.rb @@ -121,7 +121,7 @@ error # TODO allow directory specification act_on_vm do |vm| vm.add_action(Actions::Export) - vm.add_action(Actions::Package)# (name || Vagrant.config[:package][:name], FileUtils.pwd) + vm.add_action(Actions::Package, name || Vagrant.config[:package][:name], FileUtils.pwd) end end @@ -130,7 +130,7 @@ error error_and_exit(<<-error) unless name Please specify a target package to unpack and import error - + VM.execute!(Actions::Up, VM.execute!(Actions::Unpackage, name)) end diff --git a/lib/vagrant/config.rb b/lib/vagrant/config.rb index c420703d3..0e99474f1 100644 --- a/lib/vagrant/config.rb +++ b/lib/vagrant/config.rb @@ -79,8 +79,6 @@ module Vagrant class PackageConfig < Base attr_accessor :name attr_accessor :extension - attr_accessor :delimiter - attr_accessor :delimiter_regex end class ChefConfig < Base diff --git a/test/test_helper.rb b/test/test_helper.rb index 9d59395c7..a1ff83d21 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -40,8 +40,6 @@ class Test::Unit::TestCase config.package.name = 'vagrant' config.package.extension = '.box' - config.package.delimiter = 'V' - config.package.delimiter_regex = /'V(.+)V'/ config.chef.cookbooks_path = "cookbooks" config.chef.provisioning_path = "/tmp/hobo-chef" diff --git a/test/vagrant/actions/.#package_test.rb b/test/vagrant/actions/.#package_test.rb deleted file mode 120000 index d9b5b59f5..000000000 --- a/test/vagrant/actions/.#package_test.rb +++ /dev/null @@ -1 +0,0 @@ -johnbender@john-benders-macbook-pro-2.local.460 \ No newline at end of file diff --git a/test/vagrant/actions/import_test.rb b/test/vagrant/actions/import_test.rb index efa253b6a..ebf47d7ba 100644 --- a/test/vagrant/actions/import_test.rb +++ b/test/vagrant/actions/import_test.rb @@ -28,4 +28,24 @@ class ImportActionTest < Test::Unit::TestCase VirtualBox::VM.expects(:import).returns(new_vm) @import.execute! end + + context "when importing with or without an ovf file as an argument" do + # NOTE for both tests File.expects(:expand_path) makes mocha recurse and vomit + + should "default the ovf_file value to the vagrant base when not passed as an init argument" do\ + File.stubs(:expand_path) + File.expand_path do |n| + assert_equal n, Vagrant.config.vm.base + end + Vagrant::Actions::Import.new(@vm) + end + + should "expand the ovf path and assign it when passed as a parameter" do + File.stubs(:expand_path) + File.expand_path do |n| + assert_equal n, 'foo' + end + Vagrant::Actions::Import.new(@vm, 'foo') + end + end end diff --git a/test/vagrant/actions/package_test.rb b/test/vagrant/actions/package_test.rb index 119142879..01c0d16ad 100644 --- a/test/vagrant/actions/package_test.rb +++ b/test/vagrant/actions/package_test.rb @@ -3,15 +3,25 @@ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper') class PackageActionTest < Test::Unit::TestCase setup do @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::Package) + @action.to = '/foo/bar/baz' + @action.name = 'bing' mock_config end should "setup and correct working directory and export to it" do - working_dir = File.join(FileUtils.pwd, Vagrant.config.package.name) + working_dir = File.join(@action.to, @action.name) FileUtils.expects(:rm_r).with(working_dir) @action.expects(:compress) assert_equal @action.execute!, "#{working_dir}.box" end + should "return the target file and the proper extension for tar_path" do + assert_equal File.join(@action.to, @action.name + Vagrant.config.package.extension), @action.tar_path + end + + should "return the target working dir" do + assert_equal File.join(@action.to, @action.name), @action.working_dir + end + # TODO test compression once its finished end diff --git a/test/vagrant/actions/unpackage_test.rb b/test/vagrant/actions/unpackage_test.rb index f1574cddf..825deb81a 100644 --- a/test/vagrant/actions/unpackage_test.rb +++ b/test/vagrant/actions/unpackage_test.rb @@ -3,17 +3,35 @@ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper') class UnpackageActionTest < Test::Unit::TestCase setup do @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::Unpackage) + @expanded_path = File.join(FileUtils.pwd, 'foo.box') + File.stubs(:expand_path).returns(@expanded_path) + @action.package_file_path = 'foo.box' 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 + new_base_dir = File.join Vagrant.config[:vagrant][:home], 'foo' + FileUtils.expects(:mv).with(@action.working_dir, 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.expects(:decompress) @action.execute! end + + should "return the full package file path without extension for the working directory" do + assert_equal @action.working_dir, @action.package_file_path.gsub(/\.box/, '') + end + + should "return base name without extension" do + assert_equal @action.file_name_without_extension, 'foo' + end + + should "call decompress with the defined options and the correct package path" do + Tar.expects(:open).with(@expanded_path, *Vagrant::Actions::Unpackage::TAR_OPTIONS) + @action.decompress + end + + should "return a new base dir under the home dir with the same name as the file without the extension" do + assert_equal @action.new_base_dir, File.join(Vagrant.config.vagrant.home, 'foo') + end end