HTTP downloader implemented. Boxes can now be added via HTTP!

This commit is contained in:
Mitchell Hashimoto 2010-02-28 22:13:37 -08:00
parent 9913c07ff2
commit 3d220ef5c8
5 changed files with 92 additions and 4 deletions

View File

@ -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{tempfile open-uri ftools json pathname logger uri virtualbox net/ssh tarruby
%w{tempfile open-uri ftools json pathname logger uri net/http virtualbox net/ssh tarruby
net/scp fileutils vagrant/util vagrant/actions/base vagrant/downloaders/base}.each do |f|
require f
end

View File

@ -12,10 +12,13 @@ module Vagrant
def prepare
# Parse the URI given and prepare a downloader
uri = URI.parse(@runner.uri)
uri_map = [[URI::HTTP, Downloaders::HTTP], [URI::Generic, Downloaders::File]]
if uri.is_a?(URI::Generic)
logger.info "Generic URI type for box download, assuming file..."
@downloader = Downloaders::File.new
uri_map.find do |uri_type, downloader_klass|
if uri.is_a?(uri_type)
logger.info "#{uri_type} for URI, downloading via #{downloader_klass}..."
@downloader = downloader_klass.new
end
end
raise ActionException.new("Unknown URI type for box download.") unless @downloader

View File

@ -0,0 +1,40 @@
module Vagrant
module Downloaders
# Downloads a file from an HTTP URL to a temporary file. This
# downloader reports its progress to stdout while downloading.
class HTTP < Base
# ANSI escape code to clear lines from cursor to end of line
CL_RESET = "\r\e[0K"
def download!(source_url, destination_file)
Net::HTTP.get_response(URI.parse(source_url)) do |response|
total = response.content_length
progress = 0
segment_count = 0
response.read_body do |segment|
# Report the progress out
progress += segment.length
segment_count += 1
# Progress reporting is limited to every 25 segments just so
# we're not constantly updating
if segment_count % 25 == 0
report_progress(progress, total)
segment_count = 0
end
# Store the segment
destination_file.write(segment)
end
end
end
def report_progress(progress, total)
percent = (progress.to_f / total.to_f) * 100
print "#{CL_RESET}Download Progress: #{percent.to_i}% (#{progress} / #{total})"
$stdout.flush
end
end
end
end

View File

@ -30,6 +30,12 @@ class DownloadBoxActionTest < Test::Unit::TestCase
@action.prepare
assert @action.downloader.is_a?(Vagrant::Downloaders::File)
end
should "set the downloader to HTTP if URI is HTTP" do
@uri.stubs(:is_a?).with(URI::HTTP).returns(true)
@action.prepare
assert @action.downloader.is_a?(Vagrant::Downloaders::HTTP)
end
end
context "executing" do

View File

@ -0,0 +1,39 @@
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
class HttpDownloaderTest < Test::Unit::TestCase
setup do
@downloader, @tempfile = mock_downloader(Vagrant::Downloaders::HTTP)
@downloader.stubs(:report_progress)
@uri = "foo.box"
end
context "downloading" do
setup do
@parsed_uri = mock("parsed")
URI.stubs(:parse).with(@uri).returns(@parsed_uri)
end
should "parse the URI and use that parsed URI for Net::HTTP" do
URI.expects(:parse).with(@uri).returns(@parsed_uri).once
Net::HTTP.expects(:get_response).with(@parsed_uri).once
@downloader.download!(@uri, @tempfile)
end
should "read the body of the response and place each segment into the file" do
response = mock("response")
response.stubs(:content_length)
segment = mock("segment")
segment.stubs(:length).returns(7)
Net::HTTP.stubs(:get_response).yields(response)
response.expects(:read_body).once.yields(segment)
@tempfile.expects(:write).with(segment).once
@downloader.download!(@uri, @tempfile)
end
end
context "reporting progress" do
# TODO: Testing for this, probably
end
end