Prior to this commit, `vagrant box prune --force` would not prompt a user to prune Vagrant boxes, even if that box was in use. There was no way to prune boxes, ignore the prompt, but keep in-use boxes. This commit adds a new flag that can be combined with `--force`, that will keep in-use boxes but prune older boxes without prompting the user.
129 lines
4.4 KiB
Ruby
129 lines
4.4 KiB
Ruby
require "log4r"
|
|
|
|
module Vagrant
|
|
module Action
|
|
module Builtin
|
|
# This middleware will remove a box for a given provider.
|
|
class BoxRemove
|
|
def initialize(app, env)
|
|
@app = app
|
|
@logger = Log4r::Logger.new("vagrant::action::builtin::box_remove")
|
|
end
|
|
|
|
def call(env)
|
|
box_name = env[:box_name]
|
|
box_provider = env[:box_provider]
|
|
box_provider = box_provider.to_sym if box_provider
|
|
box_version = env[:box_version]
|
|
box_remove_all_versions = env[:box_remove_all_versions]
|
|
|
|
boxes = {}
|
|
env[:box_collection].all.each do |n, v, p|
|
|
boxes[n] ||= {}
|
|
boxes[n][p] ||= []
|
|
boxes[n][p] << v
|
|
end
|
|
|
|
all_box = boxes[box_name]
|
|
if !all_box
|
|
raise Errors::BoxRemoveNotFound, name: box_name
|
|
end
|
|
|
|
all_versions = nil
|
|
if !box_provider
|
|
if all_box.length == 1
|
|
# There is only one provider, just use that.
|
|
all_versions = all_box.values.first
|
|
box_provider = all_box.keys.first
|
|
else
|
|
raise Errors::BoxRemoveMultiProvider,
|
|
name: box_name,
|
|
providers: all_box.keys.map(&:to_s).sort.join(", ")
|
|
end
|
|
else
|
|
all_versions = all_box[box_provider]
|
|
if !all_versions
|
|
raise Errors::BoxRemoveProviderNotFound,
|
|
name: box_name,
|
|
provider: box_provider.to_s,
|
|
providers: all_box.keys.map(&:to_s).sort.join(", ")
|
|
end
|
|
end
|
|
|
|
if !box_version
|
|
if all_versions.length == 1
|
|
# There is only one version, just use that.
|
|
box_version = all_versions.first
|
|
elsif not box_remove_all_versions
|
|
# There are multiple versions, we can't choose.
|
|
raise Errors::BoxRemoveMultiVersion,
|
|
name: box_name,
|
|
provider: box_provider.to_s,
|
|
versions: all_versions.sort.map { |k| " * #{k}" }.join("\n")
|
|
end
|
|
elsif !all_versions.include?(box_version)
|
|
raise Errors::BoxRemoveVersionNotFound,
|
|
name: box_name,
|
|
provider: box_provider.to_s,
|
|
version: box_version,
|
|
versions: all_versions.sort.map { |k| " * #{k}" }.join("\n")
|
|
end
|
|
|
|
versions_to_remove = [box_version]
|
|
versions_to_remove = all_versions if box_remove_all_versions
|
|
|
|
versions_to_remove.sort.each do |version_to_remove|
|
|
box = env[:box_collection].find(
|
|
box_name, box_provider, box_version)
|
|
|
|
# Verify that this box is not in use by an active machine,
|
|
# otherwise warn the user.
|
|
users = box.in_use?(env[:machine_index]) || []
|
|
users = users.find_all { |u| u.valid?(env[:home_path]) }
|
|
if !users.empty?
|
|
# Build up the output to show the user.
|
|
users = users.map do |entry|
|
|
"#{entry.name} (ID: #{entry.id})"
|
|
end.join("\n")
|
|
|
|
force_key = :force_confirm_box_remove
|
|
message = I18n.t(
|
|
"vagrant.commands.box.remove_in_use_query",
|
|
name: box.name,
|
|
provider: box.provider,
|
|
version: box.version,
|
|
users: users) + " "
|
|
|
|
# Ask the user if we should do this
|
|
stack = Builder.new.tap do |b|
|
|
b.use Confirm, message, force_key
|
|
end
|
|
|
|
# Keep used boxes, even if "force" is applied
|
|
keep_used_boxes = env[:keep_used_boxes]
|
|
|
|
result = env[:action_runner].run(stack, env)
|
|
if !result[:result] || keep_used_boxes
|
|
# They said "no", so continue with the next box
|
|
next
|
|
end
|
|
end
|
|
|
|
env[:ui].info(I18n.t("vagrant.commands.box.removing",
|
|
name: box.name,
|
|
provider: box.provider,
|
|
version: box.version))
|
|
box.destroy!
|
|
env[:box_collection].clean(box.name)
|
|
|
|
# Passes on the removed box to the rest of the middleware chain
|
|
env[:box_removed] = box
|
|
end
|
|
|
|
@app.call(env)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|