Initial downloader implementation
This commit is contained in:
parent
06d055f443
commit
913e0e529d
|
@ -0,0 +1,102 @@
|
|||
require "log4r"
|
||||
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
module Vagrant
|
||||
module Util
|
||||
# This class downloads files using various protocols by subprocessing
|
||||
# to cURL. cURL is a much more capable and complete download tool than
|
||||
# a hand-rolled Ruby library, so we defer to it's expertise.
|
||||
class Downloader
|
||||
def initialize(source, destination, options=nil)
|
||||
@logger = Log4r::Logger.new("vagrant::util::downloader")
|
||||
@source = source
|
||||
@destination = destination
|
||||
|
||||
# Get the various optional values
|
||||
@options ||= {}
|
||||
@ui = @options[:ui]
|
||||
end
|
||||
|
||||
# This executes the actual download, downloading the source file
|
||||
# to the destination with the given opens used to initialize this
|
||||
# class.
|
||||
#
|
||||
# If this method returns without an exception, the download
|
||||
# succeeded. An exception will be raised if the download failed.
|
||||
def download!
|
||||
# Build the list of parameters to execute with cURL
|
||||
options = [
|
||||
"--fail",
|
||||
"--output", @destination,
|
||||
@source
|
||||
]
|
||||
|
||||
# This variable can contain the proc that'll be sent to
|
||||
# the subprocess execute.
|
||||
data_proc = nil
|
||||
|
||||
if @ui
|
||||
# If we're outputting progress, then setup the subprocess to
|
||||
# tell us output so we can parse it out.
|
||||
options << { :notify => :stderr }
|
||||
|
||||
# Setup the proc that'll receive the real-time data from
|
||||
# the downloader.
|
||||
data_proc = Proc.new do |type, data|
|
||||
# Type will always be "stderr" because that is the only
|
||||
# type of data we're subscribed for notifications.
|
||||
|
||||
# If the data doesn't start with a \r then it isn't a progress
|
||||
# notification, so ignore it.
|
||||
next if data[0] != "\r"
|
||||
|
||||
# Ignore the first \r and split by whitespace to grab the columns
|
||||
columns = data[1..-1].split(/\s+/)
|
||||
|
||||
# COLUMN DATA:
|
||||
#
|
||||
# 0 - blank
|
||||
# 1 - % total
|
||||
# 2 - Total size
|
||||
# 3 - % received
|
||||
# 4 - Received size
|
||||
# 5 - % transferred
|
||||
# 6 - Transferred size
|
||||
# 7 - Average download speed
|
||||
# 8 - Average upload speed
|
||||
# 9 - Total time
|
||||
# 10 - Time spent
|
||||
# 11 - Time left
|
||||
# 12 - Current speed
|
||||
|
||||
output = "Progress: #{columns[1]}% (Rate: #{columns[12]}/s, Estimated time remaining: #{columns[11]}"
|
||||
@ui.clear_line
|
||||
@ui.info(output, :new_line => false)
|
||||
end
|
||||
end
|
||||
|
||||
@logger.info("Downloader starting download: ")
|
||||
@logger.info(" -- Source: #{@source}")
|
||||
@logger.info(" -- Destination: #{@destination}")
|
||||
|
||||
# Execute!
|
||||
result = Subprocess.execute("curl", *options, &data_proc)
|
||||
|
||||
# If it didn't exit successfully, we need to parse the data and
|
||||
# show an error message.
|
||||
if result.exit_code != 0
|
||||
parts = result.stderr.split(/\ncurl:\s+\(\d+\)\s*/, 2)
|
||||
|
||||
# If the length is correct, we properly parsed an error message
|
||||
if parts.length == 2
|
||||
# TODO: Raise the error
|
||||
end
|
||||
end
|
||||
|
||||
# Everything succeeded
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue