diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 88e61d95b..d051f87b0 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 tarruby +%w{tempfile open-uri 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/box/add.rb b/lib/vagrant/actions/box/add.rb index ae8179380..1786834e6 100644 --- a/lib/vagrant/actions/box/add.rb +++ b/lib/vagrant/actions/box/add.rb @@ -2,6 +2,15 @@ module Vagrant module Actions module Box class Add < Base + def initialize(runner, name, path, *args) + super + @name = name + @uri = path + end + + def prepare + @runner.add_action(Download, @uri) + end end end end diff --git a/lib/vagrant/actions/box/download.rb b/lib/vagrant/actions/box/download.rb index edb41a429..0fbaee608 100644 --- a/lib/vagrant/actions/box/download.rb +++ b/lib/vagrant/actions/box/download.rb @@ -4,6 +4,36 @@ module Vagrant # An action which acts on a box by downloading the box file from # the given URI into a temporary location. class Download < Base + BASENAME = "box" + BUFFERSIZE = 1048576 # 1 MB + + def initialize(runner, uri, *args) + super + @uri = uri + end + + def execute! + with_tempfile do |tempfile| + copy_uri_to(tempfile) + end + end + + def with_tempfile + logger.info "Creating tempfile for storing box file..." + Tempfile.open(BASENAME, Env.tmp_path) do |tempfile| + yield tempfile + end + end + + def copy_uri_to(f) + logger.info "Copying box to temporary location..." + open(@uri) do |remote_file| + loop do + break if remote_file.eof? + f.write(remote_file.read(BUFFERSIZE)) + end + end + end end end end diff --git a/lib/vagrant/commands.rb b/lib/vagrant/commands.rb index f43929934..4470388e2 100644 --- a/lib/vagrant/commands.rb +++ b/lib/vagrant/commands.rb @@ -139,6 +139,8 @@ error # which action to take and calls the respective action method # (see {box_add} and {box_remove}) def box(argv) + Env.load! + sub_commands = ["add", "remove"] if !sub_commands.include?(argv[0]) diff --git a/lib/vagrant/env.rb b/lib/vagrant/env.rb index 15b64107a..5c55c6e19 100644 --- a/lib/vagrant/env.rb +++ b/lib/vagrant/env.rb @@ -13,6 +13,8 @@ module Vagrant def persisted_vm; @@persisted_vm; end def root_path; @@root_path; end def dotfile_path; File.join(root_path, Vagrant.config.dotfile_name); end + def home_path; File.expand_path(Vagrant.config.vagrant.home); end + def tmp_path; File.join(home_path, "tmp"); end def load! load_root_path! diff --git a/test/test_helper.rb b/test/test_helper.rb index a1ff83d21..3b21f60d2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -66,15 +66,15 @@ class Test::Unit::TestCase end # Sets up the mocks and instantiates an action for testing - def mock_action(action_klass) + def mock_action(action_klass, *args) @vm = mock("vboxvm") @mock_vm = mock("vm") @mock_vm.stubs(:vm).returns(@vm) @mock_vm.stubs(:vm=) @mock_vm.stubs(:invoke_callback) @mock_vm.stubs(:invoke_around_callback).yields - - @action = action_klass.new(@mock_vm) + + @action = action_klass.new(@mock_vm, *args) [@mock_vm, @vm, @action] end diff --git a/test/vagrant/actions/box/add_test.rb b/test/vagrant/actions/box/add_test.rb new file mode 100644 index 000000000..36c0e4821 --- /dev/null +++ b/test/vagrant/actions/box/add_test.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') + +class AddBoxActionTest < Test::Unit::TestCase + setup do + @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::Box::Add) + mock_config + end + + # TODO: Everything, once add does anything. +end diff --git a/test/vagrant/actions/box/download_test.rb b/test/vagrant/actions/box/download_test.rb index 2fea16e29..dbc82af69 100644 --- a/test/vagrant/actions/box/download_test.rb +++ b/test/vagrant/actions/box/download_test.rb @@ -2,7 +2,60 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') class DownloadBoxActionTest < Test::Unit::TestCase setup do - @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::Box::Download) + @uri = "foo.com" + @wrapper_vm, @vm, @action = mock_action(Vagrant::Actions::Box::Download, @uri) mock_config + + Vagrant::Env.stubs(:tmp_path).returns("foo") + end + + context "executing" do + setup do + @tempfile = mock("tempfile") + end + + should "make a tempfile and copy the URI contents to it" do + @action.expects(:with_tempfile).yields(@tempfile) + @action.expects(:copy_uri_to).with(@tempfile) + @action.execute! + end + end + + context "tempfile" do + should "create a tempfile in the vagrant tmp directory" do + Tempfile.expects(:open).with(Vagrant::Actions::Box::Download::BASENAME, Vagrant::Env.tmp_path).once + @action.with_tempfile + end + + should "yield the tempfile object" do + @tempfile = mock("tempfile") + Tempfile.expects(:open).yields(@tempfile) + + @action.with_tempfile do |otherfile| + assert @tempfile.equal?(otherfile) + end + end + end + + context "copying URI file" do + setup do + @tempfile = mock("tempfile") + @tempfile.stubs(:write) + + @file = mock("file") + @file.stubs(:read) + @file.stubs(:eof?).returns(false) + @action.stubs(:open).yields(@file) + end + + should "read from the file and write to the tempfile" do + data = mock("data") + write_seq = sequence("write_seq") + @file.stubs(:eof?).returns(false).in_sequence(write_seq) + @file.expects(:read).returns(data).in_sequence(write_seq) + @tempfile.expects(:write).with(data).in_sequence(write_seq) + @file.stubs(:eof?).returns(true).in_sequence(write_seq) + @action.copy_uri_to(@tempfile) + end end end diff --git a/test/vagrant/commands_test.rb b/test/vagrant/commands_test.rb index dead34f38..b0ee47ffc 100644 --- a/test/vagrant/commands_test.rb +++ b/test/vagrant/commands_test.rb @@ -173,6 +173,11 @@ class CommandsTest < Test::Unit::TestCase Vagrant::Commands.stubs(:box_remove) end + should "load the environment" do + Vagrant::Env.expects(:load!).once + Vagrant::Commands.box(["add"]) + end + should "error and exit if the first argument is not 'add' or 'remove'" do Vagrant::Commands.expects(:error_and_exit).once Vagrant::Commands.box(["foo"]) diff --git a/test/vagrant/env_test.rb b/test/vagrant/env_test.rb index 7c4cb0410..0bac91fa4 100644 --- a/test/vagrant/env_test.rb +++ b/test/vagrant/env_test.rb @@ -180,4 +180,16 @@ class EnvTest < Test::Unit::TestCase assert_equal path, Vagrant::Env.root_path end end + + context "home directory paths" do + should "return the expanded config for `home_path`" do + assert_equal File.expand_path(Vagrant.config.vagrant.home), Vagrant::Env.home_path + end + + should "return the home_path joined with tmp for a tmp path" do + @home_path = "foo" + Vagrant::Env.stubs(:home_path).returns(@home_path) + assert_equal File.join(@home_path, "tmp"), Vagrant::Env.tmp_path + end + end end