From f6a53ddff065d651509fcc1d437deac13ebf2e74 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 7 Jul 2010 23:16:56 -0700 Subject: [PATCH] Box adding middleware, box add uses it now --- lib/vagrant/action/box/unpackage.rb | 58 ++++++++++++ lib/vagrant/action/builtin.rb | 8 ++ lib/vagrant/box.rb | 2 +- test/vagrant/action/box/unpackage_test.rb | 103 +++++++++++++++++++++ test/vagrant/actions/box/unpackage_test.rb | 2 +- test/vagrant/box_test.rb | 2 +- vagrant.gemspec | 6 ++ 7 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 lib/vagrant/action/box/unpackage.rb create mode 100644 test/vagrant/action/box/unpackage_test.rb diff --git a/lib/vagrant/action/box/unpackage.rb b/lib/vagrant/action/box/unpackage.rb new file mode 100644 index 000000000..79f832ab5 --- /dev/null +++ b/lib/vagrant/action/box/unpackage.rb @@ -0,0 +1,58 @@ +module Vagrant + class Action + module Box + # Unpackages a downloaded box to a given directory with a given + # name. + # + # # Required Variables + # + # * `download.temp_path` - A location for the downloaded box. This is + # set by the {Download} action. + # * `box` - A {Vagrant::Box} object. + # + class Unpackage + attr_reader :box_directory + + def initialize(app, env) + @app = app + @env = env + end + + def call(env) + @env = env + + return if !setup_box_directory + decompress + + @app.call(@env) + + cleanup if @env.error? + end + + def cleanup + if File.directory?(box_directory) + FileUtils.rm_rf(box_directory) + end + end + + def setup_box_directory + if File.directory?(@env["box"].directory) + @env.error!(:box_already_exists, :box_name => @env["box"].name) + return false + end + + FileUtils.mkdir_p(@env["box"].directory) + @box_directory = @env["box"].directory + true + end + + def decompress + Dir.chdir(@env["box"].directory) do + @env.logger.info "Extracting box to #{@env["box"].directory}..." + Archive::Tar::Minitar.unpack(@env["download.temp_path"], @env["box"].directory) + end + end + end + end + end +end diff --git a/lib/vagrant/action/builtin.rb b/lib/vagrant/action/builtin.rb index 2103cc973..bf8a21e83 100644 --- a/lib/vagrant/action/builtin.rb +++ b/lib/vagrant/action/builtin.rb @@ -83,6 +83,14 @@ module Vagrant end register :package, package + + # box_add - Download and add a box. + box_add = Builder.new do + use Box::Download + use Box::Unpackage + end + + register :box_add, box_add end end end diff --git a/lib/vagrant/box.rb b/lib/vagrant/box.rb index 723fa2c74..3e29a84f5 100644 --- a/lib/vagrant/box.rb +++ b/lib/vagrant/box.rb @@ -133,7 +133,7 @@ module Vagrant # method requires that `name` and `uri` be set. The logic of this method # is kicked out to the {Actions::Box::Add add box} action. def add - execute!(Actions::Box::Add) + env.actions.run(:box_add, { "box" => self }) end # Beings the process of destroying this box. diff --git a/test/vagrant/action/box/unpackage_test.rb b/test/vagrant/action/box/unpackage_test.rb new file mode 100644 index 000000000..685b67059 --- /dev/null +++ b/test/vagrant/action/box/unpackage_test.rb @@ -0,0 +1,103 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') + +class UnpackageBoxActionTest < Test::Unit::TestCase + setup do + @klass = Vagrant::Action::Box::Unpackage + @app, @env = mock_action_data + + @vm = mock("vm") + @env["vm"] = @vm + @env["box"] = Vagrant::Box.new(mock_environment, "foo") + + @internal_vm = mock("internal") + @vm.stubs(:vm).returns(@internal_vm) + + @instance = @klass.new(@app, @env) + end + + context "calling" do + should "call the proper chain" do + seq = sequence("sequence") + @instance.expects(:setup_box_directory).in_sequence(seq).returns(true) + @instance.expects(:decompress).in_sequence(seq) + @app.expects(:call).with(@env) + @instance.expects(:cleanup).never + @instance.call(@env) + end + + should "halt the chain if setting up the box directory fails" do + @instance.expects(:setup_box_directory).returns(false) + @instance.expects(:decompress).never + @app.expects(:call).never + @instance.expects(:cleanup).never + @instance.call(@env) + end + + should "cleanup if there was an error" do + @env.error!(:foo) + + seq = sequence("sequence") + @instance.expects(:setup_box_directory).in_sequence(seq).returns(true) + @instance.expects(:decompress).in_sequence(seq) + @app.expects(:call).with(@env) + @instance.expects(:cleanup).once + @instance.call(@env) + end + end + + context "cleaning up" do + setup do + @instance.stubs(:box_directory).returns("foo") + File.stubs(:directory?).returns(false) + FileUtils.stubs(:rm_rf) + end + + should "do nothing if not a directory" do + FileUtils.expects(:rm_rf).never + @instance.cleanup + end + + should "remove the directory if exists" do + File.expects(:directory?).with(@instance.box_directory).once.returns(true) + FileUtils.expects(:rm_rf).with(@instance.box_directory).once + @instance.cleanup + end + end + + context "setting up the box directory" do + setup do + File.stubs(:directory?).returns(false) + FileUtils.stubs(:mkdir_p) + end + + should "error the environment if the box already exists" do + File.expects(:directory?).returns(true) + assert !@instance.setup_box_directory + assert @env.error? + assert_equal :box_already_exists, @env.error.first + end + + should "create the directory" do + FileUtils.expects(:mkdir_p).with(@env["box"].directory).once + @instance.setup_box_directory + end + end + + context "decompressing" do + setup do + @env["download.temp_path"] = "bar" + + Dir.stubs(:chdir).yields + end + + should "change to the box directory" do + Dir.expects(:chdir).with(@env["box"].directory) + @instance.decompress + end + + should "open the tar file within the new directory, and extract it all" do + Archive::Tar::Minitar.expects(:unpack).with(@env["download.temp_path"], @env["box"].directory).once + @instance.decompress + end + end +end diff --git a/test/vagrant/actions/box/unpackage_test.rb b/test/vagrant/actions/box/unpackage_test.rb index 276ec927b..9e552da15 100644 --- a/test/vagrant/actions/box/unpackage_test.rb +++ b/test/vagrant/actions/box/unpackage_test.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') -class UnpackageBoxActionTest < Test::Unit::TestCase +class UnpackageBoxActionsTest < Test::Unit::TestCase setup do @runner, @vm, @action = mock_action(Vagrant::Actions::Box::Unpackage) @runner.stubs(:name).returns("foo") diff --git a/test/vagrant/box_test.rb b/test/vagrant/box_test.rb index 4c5efa894..09294483b 100644 --- a/test/vagrant/box_test.rb +++ b/test/vagrant/box_test.rb @@ -116,7 +116,7 @@ class BoxTest < Test::Unit::TestCase end should "execute the Add action when add is called" do - @box.expects(:execute!).with(Vagrant::Actions::Box::Add).once + @box.env.actions.expects(:run).with(:box_add, { "box" => @box }) @box.add end diff --git a/vagrant.gemspec b/vagrant.gemspec index 81c8c5bbc..542d49128 100644 --- a/vagrant.gemspec +++ b/vagrant.gemspec @@ -34,6 +34,8 @@ Gem::Specification.new do |s| "keys/vagrant.pub", "lib/vagrant.rb", "lib/vagrant/action.rb", + "lib/vagrant/action/box/download.rb", + "lib/vagrant/action/box/unpackage.rb", "lib/vagrant/action/builder.rb", "lib/vagrant/action/builtin.rb", "lib/vagrant/action/environment.rb", @@ -135,6 +137,8 @@ Gem::Specification.new do |s| "templates/unison/crontab_entry.erb", "templates/unison/script.erb", "test/test_helper.rb", + "test/vagrant/action/box/download_test.rb", + "test/vagrant/action/box/unpackage_test.rb", "test/vagrant/action/builder_test.rb", "test/vagrant/action/environment_test.rb", "test/vagrant/action/error_halt_test.rb", @@ -233,6 +237,8 @@ Gem::Specification.new do |s| s.summary = %q{Vagrant is a tool for building and distributing virtualized development environments.} s.test_files = [ "test/test_helper.rb", + "test/vagrant/action/box/download_test.rb", + "test/vagrant/action/box/unpackage_test.rb", "test/vagrant/action/builder_test.rb", "test/vagrant/action/environment_test.rb", "test/vagrant/action/error_halt_test.rb",