core: BoxCollection can find with version constraints

This commit is contained in:
Mitchell Hashimoto 2014-01-22 15:16:12 -08:00
parent 77b5fa94b7
commit 4c1fa7359d
2 changed files with 53 additions and 47 deletions

View File

@ -229,42 +229,40 @@ module Vagrant
#
# @param [String] name Name of the box (logical name).
# @param [Array] providers Providers that the box implements.
# @param [String] version Version constraints to adhere to. Example:
# "~> 1.0" or "= 1.0, ~> 1.1"
# @return [Box] The box found, or `nil` if not found.
def find(name, providers)
providers = [providers].flatten
def find(name, providers, version)
providers = Array(providers)
# Build up the requirements we have
requirements = version.split(",").map do |v|
Gem::Requirement.new(v.strip)
end
with_collection_lock do
providers.each do |provider|
# First look directly for the box we're asking for.
box_directory = @directory.join(name, provider.to_s, "metadata.json")
@logger.info("Searching for box: #{name} (#{provider}) in #{box_directory}")
if box_directory.file?
@logger.info("Box found: #{name} (#{provider})")
return Box.new(name, provider, box_directory.dirname)
end
# If we're looking for a VirtualBox box, then we check if there is
# a V1 box.
if provider.to_sym == :virtualbox
# Check if a V1 version of this box exists, and if so, raise an
# exception notifying the caller that the box exists but needs
# to be upgraded. We don't do the upgrade here because it can be
# a fairly intensive activity and don't want to immediately degrade
# user performance on a find.
#
# To determine if it is a V1 box we just do a simple heuristic
# based approach.
@logger.info("Searching for V1 box: #{name}")
if v1_box?(@directory.join(name))
@logger.warn("V1 box found: #{name}")
raise Errors::BoxUpgradeRequired, :name => name
end
end
end
end
# Didn't find it, return nil
box_directory = @directory.join(name)
if !box_directory.directory?
@logger.info("Box not found: #{name} (#{providers.join(", ")})")
return nil
end
box_directory.children(true).each do |versiondir|
version = versiondir.basename.to_s
if !requirements.all? { |r| r.satisfied_by?(Gem::Version.new(version)) }
# Unsatisfied version requirements
next
end
providers.each do |provider|
provider_dir = versiondir.join(provider.to_s)
next if !provider_dir.directory?
@logger.info("Box found: #{name} (#{provider})")
return Box.new(name, provider, provider_dir)
end
end
end
nil
end

View File

@ -41,37 +41,45 @@ describe Vagrant::BoxCollection do
end
end
describe "finding" do
it "should return nil if the box does not exist" do
instance.find("foo", :i_dont_exist).should be_nil
describe "#find" do
it "returns nil if the box does not exist" do
expect(subject.find("foo", :i_dont_exist, ">= 0")).to be_nil
end
it "should return a box if the box does exist" do
it "returns a box if the box does exist" do
# Create the "box"
environment.box2("foo", :virtualbox)
environment.box3("foo", "0", :virtualbox)
# Actual test
result = instance.find("foo", :virtualbox)
result.should_not be_nil
result.should be_kind_of(box_class)
result.name.should == "foo"
result = subject.find("foo", :virtualbox, ">= 0")
expect(result).to_not be_nil
expect(result).to be_kind_of(box_class)
expect(result.name).to eq("foo")
end
it "should throw an exception if it is a v1 box" do
# Create a V1 box
environment.box1("foo")
it "can satisfy complex constraints" do
# Create the "box"
environment.box3("foo", "0.1", :virtualbox)
environment.box3("foo", "1.0", :virtualbox)
environment.box3("foo", "2.1", :virtualbox)
# Test!
expect { instance.find("foo", :virtualbox) }.
to raise_error(Vagrant::Errors::BoxUpgradeRequired)
# Actual test
result = subject.find("foo", :virtualbox, ">= 0.9, < 1.5")
expect(result).to_not be_nil
expect(result).to be_kind_of(box_class)
expect(result.name).to eq("foo")
# TODO: test version
end
it "should return nil if there is a V1 box but we're looking for another provider" do
# Create a V1 box
environment.box1("foo")
it "returns nil if a box's constraints can't be satisfied" do
# Create the "box"
environment.box3("foo", "0.1", :virtualbox)
environment.box3("foo", "1.0", :virtualbox)
environment.box3("foo", "2.1", :virtualbox)
# Test
instance.find("foo", :another_provider).should be_nil
# Actual test
result = subject.find("foo", :virtualbox, "> 1.0, < 1.5")
expect(result).to be_nil
end
end