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]
|
version = env[:box_version]
|
||||||
|
|
||||||
metadata = nil
|
metadata = nil
|
||||||
if File.file?(url)
|
begin
|
||||||
# TODO: What if file isn't valid JSON
|
metadata_path = download(url, env)
|
||||||
# TODO: What if URL is in the "file:" format
|
|
||||||
File.open(url) do |f|
|
File.open(metadata_path) do |f|
|
||||||
metadata = BoxMetadata.new(f)
|
metadata = BoxMetadata.new(f)
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
metadata_path.delete if metadata_path.file?
|
||||||
end
|
end
|
||||||
|
|
||||||
metadata_version = metadata.version(
|
metadata_version = metadata.version(
|
||||||
|
@ -316,7 +318,10 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: do the HEAD request
|
# 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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,30 +38,8 @@ module Vagrant
|
||||||
# If this method returns without an exception, the download
|
# If this method returns without an exception, the download
|
||||||
# succeeded. An exception will be raised if the download failed.
|
# succeeded. An exception will be raised if the download failed.
|
||||||
def download!
|
def download!
|
||||||
# Build the list of parameters to execute with cURL
|
options, subprocess_options = self.options
|
||||||
options = [
|
options += ["--output", @destination]
|
||||||
"--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
|
|
||||||
|
|
||||||
# This variable can contain the proc that'll be sent to
|
# This variable can contain the proc that'll be sent to
|
||||||
# the subprocess execute.
|
# the subprocess execute.
|
||||||
|
@ -118,7 +96,42 @@ module Vagrant
|
||||||
end
|
end
|
||||||
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
|
options << subprocess_options
|
||||||
|
|
||||||
# Create the callback that is called if we are interrupted
|
# Create the callback that is called if we are interrupted
|
||||||
|
@ -128,10 +141,6 @@ module Vagrant
|
||||||
interrupted = true
|
interrupted = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@logger.info("Downloader starting download: ")
|
|
||||||
@logger.info(" -- Source: #{@source}")
|
|
||||||
@logger.info(" -- Destination: #{@destination}")
|
|
||||||
|
|
||||||
# Execute!
|
# Execute!
|
||||||
result = Busy.busy(int_callback) do
|
result = Busy.busy(int_callback) do
|
||||||
Subprocess.execute("curl", *options, &data_proc)
|
Subprocess.execute("curl", *options, &data_proc)
|
||||||
|
@ -140,16 +149,6 @@ module Vagrant
|
||||||
# If the download was interrupted, then raise a specific error
|
# If the download was interrupted, then raise a specific error
|
||||||
raise Errors::DownloaderInterrupted if interrupted
|
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
|
# If it didn't exit successfully, we need to parse the data and
|
||||||
# show an error message.
|
# show an error message.
|
||||||
if result.exit_code != 0
|
if result.exit_code != 0
|
||||||
|
@ -159,8 +158,38 @@ module Vagrant
|
||||||
raise Errors::DownloaderError, :message => parts[1].chomp
|
raise Errors::DownloaderError, :message => parts[1].chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
# Everything succeeded
|
result
|
||||||
true
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@ require "digest/sha1"
|
||||||
require "pathname"
|
require "pathname"
|
||||||
require "tempfile"
|
require "tempfile"
|
||||||
require "tmpdir"
|
require "tmpdir"
|
||||||
|
require "webrick"
|
||||||
|
|
||||||
require File.expand_path("../../../../base", __FILE__)
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
@ -32,6 +33,27 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
||||||
FileChecksum.new(path, Digest::SHA1).checksum
|
FileChecksum.new(path, Digest::SHA1).checksum
|
||||||
end
|
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
|
before do
|
||||||
box_collection.stub(find: nil)
|
box_collection.stub(find: nil)
|
||||||
end
|
end
|
||||||
|
@ -55,6 +77,25 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
||||||
subject.call(env)
|
subject.call(env)
|
||||||
end
|
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
|
it "raises an error if the box already exists" do
|
||||||
box_path = iso_env.box2_file(:virtualbox)
|
box_path = iso_env.box2_file(:virtualbox)
|
||||||
|
|
||||||
|
@ -93,6 +134,49 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with box metadata" do
|
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
|
it "adds the latest version of a box with only one provider" do
|
||||||
box_path = iso_env.box2_file(:virtualbox)
|
box_path = iso_env.box2_file(:virtualbox)
|
||||||
tf = Tempfile.new("vagrant").tap do |f|
|
tf = Tempfile.new("vagrant").tap do |f|
|
||||||
|
|
Loading…
Reference in New Issue