core: BoxAdd now works with HTTP URLs
This commit is contained in:
parent
03b22ab9a1
commit
09e8666296
|
@ -57,12 +57,14 @@ module Vagrant
|
|||
version = env[:box_version]
|
||||
|
||||
metadata = nil
|
||||
if File.file?(url)
|
||||
# TODO: What if file isn't valid JSON
|
||||
# TODO: What if URL is in the "file:" format
|
||||
File.open(url) do |f|
|
||||
begin
|
||||
metadata_path = download(url, env)
|
||||
|
||||
File.open(metadata_path) do |f|
|
||||
metadata = BoxMetadata.new(f)
|
||||
end
|
||||
ensure
|
||||
metadata_path.delete if metadata_path.file?
|
||||
end
|
||||
|
||||
metadata_version = metadata.version(
|
||||
|
@ -316,7 +318,10 @@ module Vagrant
|
|||
end
|
||||
|
||||
# TODO: do the HEAD request
|
||||
true
|
||||
output = d.head
|
||||
match = output.scan(/^Content-Type: (.+?)$/).last
|
||||
return false if !match
|
||||
match.last.chomp == "application/json"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,30 +38,8 @@ module Vagrant
|
|||
# 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",
|
||||
"--location",
|
||||
"--max-redirs", "10",
|
||||
"--user-agent", USER_AGENT,
|
||||
"--output", @destination,
|
||||
]
|
||||
|
||||
options += ["--cacert", @ca_cert] if @ca_cert
|
||||
options += ["--continue-at", "-"] if @continue
|
||||
options << "--insecure" if @insecure
|
||||
options << "--cert" << @client_cert if @client_cert
|
||||
options << @source
|
||||
|
||||
# Specify some options for the subprocess
|
||||
subprocess_options = {}
|
||||
|
||||
# If we're in Vagrant, then we use the packaged CA bundle
|
||||
if Vagrant.in_installer?
|
||||
subprocess_options[:env] ||= {}
|
||||
subprocess_options[:env]["CURL_CA_BUNDLE"] =
|
||||
File.expand_path("cacert.pem", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"])
|
||||
end
|
||||
options, subprocess_options = self.options
|
||||
options += ["--output", @destination]
|
||||
|
||||
# This variable can contain the proc that'll be sent to
|
||||
# the subprocess execute.
|
||||
|
@ -118,7 +96,42 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# Add the subprocess options onto the options we'll execute with
|
||||
@logger.info("Downloader starting download: ")
|
||||
@logger.info(" -- Source: #{@source}")
|
||||
@logger.info(" -- Destination: #{@destination}")
|
||||
|
||||
begin
|
||||
execute_curl(options, subprocess_options, &data_proc)
|
||||
ensure
|
||||
# If we're outputting to the UI, clear the output to
|
||||
# avoid lingering progress meters.
|
||||
if @ui
|
||||
@ui.clear_line
|
||||
|
||||
# Windows doesn't clear properly for some reason, so we just
|
||||
# output one more newline.
|
||||
@ui.info("") if Platform.windows?
|
||||
end
|
||||
end
|
||||
|
||||
# Everything succeeded
|
||||
true
|
||||
end
|
||||
|
||||
# Does a HEAD request of the URL and returns the output.
|
||||
def head
|
||||
options, subprocess_options = self.options
|
||||
options.unshift("-I")
|
||||
|
||||
@logger.info("HEAD: #{@source}")
|
||||
result = execute_curl(options, subprocess_options)
|
||||
result.stdout
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def execute_curl(options, subprocess_options, &data_proc)
|
||||
options = options.dup
|
||||
options << subprocess_options
|
||||
|
||||
# Create the callback that is called if we are interrupted
|
||||
|
@ -128,10 +141,6 @@ module Vagrant
|
|||
interrupted = true
|
||||
end
|
||||
|
||||
@logger.info("Downloader starting download: ")
|
||||
@logger.info(" -- Source: #{@source}")
|
||||
@logger.info(" -- Destination: #{@destination}")
|
||||
|
||||
# Execute!
|
||||
result = Busy.busy(int_callback) do
|
||||
Subprocess.execute("curl", *options, &data_proc)
|
||||
|
@ -140,16 +149,6 @@ module Vagrant
|
|||
# If the download was interrupted, then raise a specific error
|
||||
raise Errors::DownloaderInterrupted if interrupted
|
||||
|
||||
# If we're outputting to the UI, clear the output to
|
||||
# avoid lingering progress meters.
|
||||
if @ui
|
||||
@ui.clear_line
|
||||
|
||||
# Windows doesn't clear properly for some reason, so we just
|
||||
# output one more newline.
|
||||
@ui.info("") if Platform.windows?
|
||||
end
|
||||
|
||||
# If it didn't exit successfully, we need to parse the data and
|
||||
# show an error message.
|
||||
if result.exit_code != 0
|
||||
|
@ -159,8 +158,38 @@ module Vagrant
|
|||
raise Errors::DownloaderError, :message => parts[1].chomp
|
||||
end
|
||||
|
||||
# Everything succeeded
|
||||
true
|
||||
result
|
||||
end
|
||||
|
||||
# Returns the varoius cURL and subprocess options.
|
||||
#
|
||||
# @return [Array<Array, Hash>]
|
||||
def options
|
||||
# Build the list of parameters to execute with cURL
|
||||
options = [
|
||||
"--fail",
|
||||
"--location",
|
||||
"--max-redirs", "10",
|
||||
"--user-agent", USER_AGENT,
|
||||
]
|
||||
|
||||
options += ["--cacert", @ca_cert] if @ca_cert
|
||||
options += ["--continue-at", "-"] if @continue
|
||||
options << "--insecure" if @insecure
|
||||
options << "--cert" << @client_cert if @client_cert
|
||||
options << @source
|
||||
|
||||
# Specify some options for the subprocess
|
||||
subprocess_options = {}
|
||||
|
||||
# If we're in Vagrant, then we use the packaged CA bundle
|
||||
if Vagrant.in_installer?
|
||||
subprocess_options[:env] ||= {}
|
||||
subprocess_options[:env]["CURL_CA_BUNDLE"] =
|
||||
File.expand_path("cacert.pem", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"])
|
||||
end
|
||||
|
||||
return [options, subprocess_options]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ require "digest/sha1"
|
|||
require "pathname"
|
||||
require "tempfile"
|
||||
require "tmpdir"
|
||||
require "webrick"
|
||||
|
||||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
|
@ -32,6 +33,27 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
|||
FileChecksum.new(path, Digest::SHA1).checksum
|
||||
end
|
||||
|
||||
def with_web_server(path)
|
||||
tf = Tempfile.new("vagrant")
|
||||
tf.close
|
||||
|
||||
mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
|
||||
mime_types.store "json", "application/json"
|
||||
|
||||
port = 3838
|
||||
server = WEBrick::HTTPServer.new(
|
||||
AccessLog: [],
|
||||
Logger: WEBrick::Log.new(tf.path, 7),
|
||||
Port: port,
|
||||
DocumentRoot: path.dirname.to_s,
|
||||
MimeTypes: mime_types)
|
||||
thr = Thread.new { server.start }
|
||||
yield port
|
||||
ensure
|
||||
server.shutdown rescue nil
|
||||
thr.join rescue nil
|
||||
end
|
||||
|
||||
before do
|
||||
box_collection.stub(find: nil)
|
||||
end
|
||||
|
@ -55,6 +77,25 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
|||
subject.call(env)
|
||||
end
|
||||
|
||||
it "adds from HTTP URL" do
|
||||
box_path = iso_env.box2_file(:virtualbox)
|
||||
with_web_server(box_path) do |port|
|
||||
env[:box_name] = "foo"
|
||||
env[:box_url] = "http://127.0.0.1:#{port}/#{box_path.basename}"
|
||||
|
||||
box_collection.should_receive(:add).with do |path, name, version|
|
||||
expect(checksum(path)).to eq(checksum(box_path))
|
||||
expect(name).to eq("foo")
|
||||
expect(version).to eq("0")
|
||||
true
|
||||
end.and_return(box)
|
||||
|
||||
app.should_receive(:call).with(env)
|
||||
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an error if the box already exists" do
|
||||
box_path = iso_env.box2_file(:virtualbox)
|
||||
|
||||
|
@ -93,6 +134,49 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
|||
end
|
||||
|
||||
context "with box metadata" do
|
||||
it "adds from HTTP URL" do
|
||||
box_path = iso_env.box2_file(:virtualbox)
|
||||
tf = Tempfile.new(["vagrant", ".json"]).tap do |f|
|
||||
f.write(<<-RAW)
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"versions": [
|
||||
{
|
||||
"version": "0.5"
|
||||
},
|
||||
{
|
||||
"version": "0.7",
|
||||
"providers": [
|
||||
{
|
||||
"name": "virtualbox",
|
||||
"url": "#{box_path}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
RAW
|
||||
f.close
|
||||
end
|
||||
|
||||
|
||||
md_path = Pathname.new(tf.path)
|
||||
with_web_server(md_path) do |port|
|
||||
env[:box_url] = "http://127.0.0.1:#{port}/#{md_path.basename}"
|
||||
|
||||
box_collection.should_receive(:add).with do |path, name, version|
|
||||
expect(name).to eq("foo/bar")
|
||||
expect(version).to eq("0.7")
|
||||
expect(checksum(path)).to eq(checksum(box_path))
|
||||
true
|
||||
end.and_return(box)
|
||||
|
||||
app.should_receive(:call).with(env)
|
||||
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
it "adds the latest version of a box with only one provider" do
|
||||
box_path = iso_env.box2_file(:virtualbox)
|
||||
tf = Tempfile.new("vagrant").tap do |f|
|
||||
|
|
Loading…
Reference in New Issue