commands/box: update command can update a specific box now

This commit is contained in:
Mitchell Hashimoto 2014-01-25 10:03:33 -08:00
parent 386938f0b1
commit 7a6d1a3ff1
6 changed files with 238 additions and 25 deletions

View File

@ -27,6 +27,7 @@ module Vagrant
error: e.to_s
end
@raw ||= {}
@name = @raw["name"]
@description = @raw["description"]
@version_map = (@raw["versions"] || []).map do |v|

View File

@ -172,6 +172,14 @@ module Vagrant
error_key(:box_metadata_malformed)
end
class BoxNotFound < VagrantError
error_key(:box_not_found)
end
class BoxNotFoundWithProvider < VagrantError
error_key(:box_not_found_with_provider)
end
class BoxOutdatedNoBox < VagrantError
error_key(:box_outdated_no_box)
end
@ -200,6 +208,10 @@ module Vagrant
error_key(:untar_failure, "vagrant.actions.box.unpackage")
end
class BoxUpdateMultiProvider < VagrantError
error_key(:box_update_multi_provider)
end
class BoxUpdateNoMetadata < VagrantError
error_key(:box_update_no_metadata)
end

View File

@ -23,11 +23,62 @@ module VagrantPlugins
o.on("--box VALUE", String, "Update a specific box") do |b|
options[:box] = b
end
o.on("--provider VALUE", String, "Update box with specific provider.") do |p|
options[:provider] = p.to_sym
end
end
argv = parse_options(opts)
return if !argv
if options[:box]
update_specific(options[:box], options[:provider])
else
update_vms(argv)
end
0
end
def update_specific(name, provider)
boxes = {}
@env.boxes.all.each do |n, v, p|
boxes[n] ||= {}
boxes[n][p] ||= []
boxes[n][p] << v
end
if !boxes[name]
raise Vagrant::Errors::BoxNotFound, name: name.to_s
end
if !provider
if boxes[name].length > 1
raise Vagrant::Errors::BoxUpdateMultiProvider,
name: name.to_s,
providers: boxes[name].keys.map(&:to_s).sort.join(", ")
end
provider = boxes[name].keys.first
elsif !boxes[name][provider]
raise Vagrant::Errors::BoxNotFoundWithProvider,
name: name.to_s,
provider: provider.to_s,
providers: boxes[name].keys.map(&:to_s).sort.join(", ")
end
to_update = [
[name, provider, boxes[name][provider].last],
]
to_update.each do |n, p, v|
box = @env.boxes.find(n, p, v)
box_update(box, "> #{v}", @env.ui)
end
end
def update_vms(argv)
with_target_vms(argv) do |machine|
if !machine.box
machine.ui.output(I18n.t(
@ -38,33 +89,36 @@ module VagrantPlugins
box = machine.box
version = machine.config.vm.box_version
machine.ui.output(I18n.t("vagrant.box_update_checking", name: box.name))
machine.ui.detail("Version constraints: #{version}")
machine.ui.detail("Provider: #{box.provider}")
update = box.has_update?(version)
if !update
machine.ui.success(I18n.t(
"vagrant.box_up_to_date_single",
name: box.name, version: box.version))
next
end
machine.ui.output(I18n.t(
"vagrant.box_updating",
name: update[0].name,
provider: update[2].name,
old: box.version,
new: update[1].version))
@env.action_runner.run(Vagrant::Action.action_box_add, {
box_url: box.metadata_url,
box_provider: update[2].name,
box_version: update[1].version,
ui: machine.ui,
})
box_update(box, version, machine.ui)
end
end
def box_update(box, version, ui)
ui.output(I18n.t("vagrant.box_update_checking", name: box.name))
ui.detail("Version constraints: #{version}")
ui.detail("Provider: #{box.provider}")
update = box.has_update?(version)
if !update
ui.success(I18n.t(
"vagrant.box_up_to_date_single",
name: box.name, version: box.version))
return
end
ui.output(I18n.t(
"vagrant.box_updating",
name: update[0].name,
provider: update[2].name,
old: box.version,
new: update[1].version))
@env.action_runner.run(Vagrant::Action.action_box_add, {
box_url: box.metadata_url,
box_provider: update[2].name,
box_version: update[1].version,
ui: ui,
})
end
end
end
end

View File

@ -378,6 +378,16 @@ en:
that this issue can be fixed.
%{error}
box_not_found: |-
The box '%{name}' does not exist. Please double check and
try again. You can see the boxes that are installed with
`vagrant box list`.
box_not_found_with_provider: |-
The box '%{name}' isn't installed for the provider '%{provider}'.
Please double-check and try again. The installed providers for
the box are shown below:
%{providers}
box_outdated_no_box: |-
The box '%{name}' isn't downloaded or added yet, so we can't
check if it is outdated. Run a `vagrant up` or add the box
@ -409,6 +419,12 @@ en:
the provider specified. Please double-check and try again.
The providers for this are: %{providers}
box_update_multi_provider: |-
You requested to update the box '%{name}'. This box has
multiple providers. You must explicitly select a single
provider to remove with `--provider`.
Available providers: %{providers}
box_update_no_metadata: |-
The box '%{name}' is not a versioned box. The box was added
directly instead of from a box catalog. Vagrant can only

View File

@ -1,3 +1,6 @@
require "pathname"
require "tmpdir"
require File.expand_path("../../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/box/command/update")
@ -23,6 +26,126 @@ describe VagrantPlugins::CommandBox::Command::Update do
end
describe "execute" do
context "updating specific box" do
let(:argv) { ["--box", "foo"] }
let(:metadata_url) { Pathname.new(Dir.mktmpdir).join("metadata.json") }
before do
metadata_url.open("w") do |f|
f.write("")
end
test_iso_env.box3(
"foo", "1.0", :virtualbox, metadata_url: metadata_url.to_s)
end
it "doesn't update if they're up to date" do
action_runner.should_receive(:run).never
subject.execute
end
it "does update if there is an update" do
metadata_url.open("w") do |f|
f.write(<<-RAW)
{
"name": "foo",
"versions": [
{
"version": "1.0"
},
{
"version": "1.1",
"providers": [
{
"name": "virtualbox",
"url": "bar"
}
]
}
]
}
RAW
end
action_runner.should_receive(:run).with do |action, opts|
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("virtualbox")
expect(opts[:box_version]).to eq("1.1")
true
end
subject.execute
end
it "raises an error if there are multiple providers" do
test_iso_env.box3("foo", "1.0", :vmware)
action_runner.should_receive(:run).never
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxUpdateMultiProvider)
end
context "with multiple providers and specifying the provider" do
let(:argv) { ["--box", "foo", "--provider", "vmware"] }
it "updates the proper box" do
metadata_url.open("w") do |f|
f.write(<<-RAW)
{
"name": "foo",
"versions": [
{
"version": "1.0"
},
{
"version": "1.1",
"providers": [
{
"name": "vmware",
"url": "bar"
}
]
}
]
}
RAW
end
test_iso_env.box3("foo", "1.0", :vmware)
action_runner.should_receive(:run).with do |action, opts|
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("vmware")
expect(opts[:box_version]).to eq("1.1")
true
end
subject.execute
end
it "raises an error if that provider doesn't exist" do
action_runner.should_receive(:run).never
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxNotFoundWithProvider)
end
end
context "with a box that doesn't exist" do
let(:argv) { ["--box", "nope"] }
it "raises an exception" do
action_runner.should_receive(:run).never
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxNotFound)
end
end
end
context "updating environment machines" do
before do
subject.stub(:with_target_vms) { |&block| block.call machine }

View File

@ -117,6 +117,13 @@ module Unit
end
end
# Create the metadata URL
if opts[:metadata_url]
boxes_dir.join(name, "metadata_url").open("w") do |f|
f.write(opts[:metadata_url])
end
end
box_dir
end