core: BoxMetadata can read the JSON description
This commit is contained in:
parent
e8197c4e87
commit
8abcc6e5f2
|
@ -0,0 +1,124 @@
|
|||
require "json"
|
||||
|
||||
module Vagrant
|
||||
# BoxMetadata represents metadata about a box, including the name
|
||||
# it should have, a description of it, the versions it has, and
|
||||
# more.
|
||||
class BoxMetadata
|
||||
# The name that the box should be if it is added.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :name
|
||||
|
||||
# The long-form human-readable description of a box.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :description
|
||||
|
||||
# Loads the metadata associated with the box from the given
|
||||
# IO.
|
||||
#
|
||||
# @param [IO] io An IO object to read the metadata from.
|
||||
def initialize(io)
|
||||
begin
|
||||
@raw = JSON.load(io)
|
||||
rescue JSON::ParserError => e
|
||||
raise Errors::BoxMetadataMalformed,
|
||||
error: e.to_s
|
||||
end
|
||||
|
||||
@name = @raw["name"]
|
||||
@description = @raw["description"]
|
||||
@version_map = @raw["versions"].map do |v|
|
||||
[Gem::Version.new(v["version"]), v]
|
||||
end
|
||||
@version_map = Hash[@version_map]
|
||||
|
||||
# TODO: check for corruption:
|
||||
# - malformed version
|
||||
end
|
||||
|
||||
# Returns data about a single version that is included in this
|
||||
# metadata.
|
||||
#
|
||||
# @param [String] version The version to return, this can also
|
||||
# be a constraint.
|
||||
# @return [Version] The matching version or nil if a matching
|
||||
# version was not found.
|
||||
def version(version)
|
||||
requirements = version.split(",").map do |v|
|
||||
Gem::Requirement.new(v.strip)
|
||||
end
|
||||
|
||||
@version_map.keys.sort.reverse.each do |v|
|
||||
if requirements.all? { |r| r.satisfied_by?(v) }
|
||||
return Version.new(@version_map[v])
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Returns all the versions supported by this metadata. These
|
||||
# versions are sorted so the last element of the list is the
|
||||
# latest version.
|
||||
#
|
||||
# @return[Array<String>]
|
||||
def versions
|
||||
@version_map.keys.sort.map(&:to_s)
|
||||
end
|
||||
|
||||
# Represents a single version within the metadata.
|
||||
class Version
|
||||
# The version that this Version object represents.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :version
|
||||
|
||||
def initialize(raw=nil)
|
||||
return if !raw
|
||||
|
||||
@version = raw["version"]
|
||||
@provider_map = (raw["providers"] || []).map do |p|
|
||||
[p["name"], p]
|
||||
end
|
||||
@provider_map = Hash[@provider_map]
|
||||
end
|
||||
|
||||
# Returns a [Provider] for the given name, or nil if it isn't
|
||||
# supported by this version.
|
||||
def provider(name)
|
||||
p = @provider_map[name]
|
||||
return nil if !p
|
||||
Provider.new(p)
|
||||
end
|
||||
|
||||
# Returns the providers that are available for this version
|
||||
# of the box.
|
||||
#
|
||||
# @return [Provider]
|
||||
def providers
|
||||
@provider_map.keys
|
||||
end
|
||||
end
|
||||
|
||||
# Provider represents a single provider-specific box available
|
||||
# for a version for a box.
|
||||
class Provider
|
||||
# The name of the provider.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :name
|
||||
|
||||
# The URL of the box.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :url
|
||||
|
||||
def initialize(raw)
|
||||
@name = raw["name"]
|
||||
@url = raw["url"]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -144,6 +144,10 @@ module Vagrant
|
|||
error_key(:box_metadata_file_not_found)
|
||||
end
|
||||
|
||||
class BoxMetadataMalformed < VagrantError
|
||||
error_key(:box_metadata_malformed)
|
||||
end
|
||||
|
||||
class BoxNotFound < VagrantError
|
||||
error_key(:box_not_found)
|
||||
end
|
||||
|
|
|
@ -266,6 +266,12 @@ en:
|
|||
box file format can be found at the URL below:
|
||||
|
||||
http://docs.vagrantup.com/v2/boxes/format.html
|
||||
box_metadata_malformed: |-
|
||||
The metadata for the box was malformed. The exact error
|
||||
is shown below. Please contact the maintainer of the box so
|
||||
that this issue can be fixed.
|
||||
|
||||
%{error}
|
||||
box_not_found: Box '%{name}' with '%{provider}' provider could not be found.
|
||||
box_provider_doesnt_match: |-
|
||||
The box you attempted to add doesn't match the provider you specified.
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
require File.expand_path("../../base", __FILE__)
|
||||
|
||||
require "vagrant/box_metadata"
|
||||
|
||||
describe Vagrant::BoxMetadata do
|
||||
include_context "unit"
|
||||
|
||||
let(:raw) do
|
||||
<<-RAW
|
||||
{
|
||||
"name": "foo",
|
||||
"description": "bar",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"version": "1.1.5"
|
||||
},
|
||||
{
|
||||
"version": "1.1.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
RAW
|
||||
end
|
||||
|
||||
subject { described_class.new(raw) }
|
||||
|
||||
its(:name) { should eq("foo") }
|
||||
its(:description) { should eq("bar") }
|
||||
|
||||
context "with poorly formatted JSON" do
|
||||
let(:raw) {
|
||||
<<-RAW
|
||||
{ "name": "foo", }
|
||||
RAW
|
||||
}
|
||||
|
||||
it "raises an exception" do
|
||||
expect { subject }.
|
||||
to raise_error(Vagrant::Errors::BoxMetadataMalformed)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#version" do
|
||||
it "matches an exact version" do
|
||||
result = subject.version("1.0.0")
|
||||
expect(result).to_not be_nil
|
||||
expect(result).to be_kind_of(Vagrant::BoxMetadata::Version)
|
||||
expect(result.version).to eq("1.0.0")
|
||||
end
|
||||
|
||||
it "matches a constraint with latest matching version" do
|
||||
result = subject.version(">= 1.0")
|
||||
expect(result).to_not be_nil
|
||||
expect(result).to be_kind_of(Vagrant::BoxMetadata::Version)
|
||||
expect(result.version).to eq("1.1.5")
|
||||
end
|
||||
|
||||
it "matches complex constraints" do
|
||||
result = subject.version(">= 0.9, ~> 1.0.0")
|
||||
expect(result).to_not be_nil
|
||||
expect(result).to be_kind_of(Vagrant::BoxMetadata::Version)
|
||||
expect(result.version).to eq("1.0.0")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#versions" do
|
||||
it "returns the versions it contained" do
|
||||
expect(subject.versions).to eq(
|
||||
["1.0.0", "1.1.0", "1.1.5"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Vagrant::BoxMetadata::Version do
|
||||
let(:raw) { {} }
|
||||
|
||||
subject { described_class.new(raw) }
|
||||
|
||||
before do
|
||||
raw["providers"] = [
|
||||
{
|
||||
"name" => "virtualbox",
|
||||
},
|
||||
{
|
||||
"name" => "vmware",
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
describe "#version" do
|
||||
it "is the version in the raw data" do
|
||||
v = "1.0"
|
||||
raw["version"] = v
|
||||
expect(subject.version).to eq(v)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#provider" do
|
||||
it "returns nil if a provider isn't supported" do
|
||||
expect(subject.provider("foo")).to be_nil
|
||||
end
|
||||
|
||||
it "returns the provider specified" do
|
||||
result = subject.provider("virtualbox")
|
||||
expect(result).to_not be_nil
|
||||
expect(result).to be_kind_of(Vagrant::BoxMetadata::Provider)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#providers" do
|
||||
it "returns the providers available" do
|
||||
expect(subject.providers.sort).to eq(
|
||||
["virtualbox", "vmware"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Vagrant::BoxMetadata::Provider do
|
||||
let(:raw) { {} }
|
||||
|
||||
subject { described_class.new(raw) }
|
||||
|
||||
describe "#name" do
|
||||
it "is the name specified" do
|
||||
raw["name"] = "foo"
|
||||
expect(subject.name).to eq("foo")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#url" do
|
||||
it "is the URL specified" do
|
||||
raw["url"] = "bar"
|
||||
expect(subject.url).to eq("bar")
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue