class Vagrant::Action::Builtin::BoxRemove

This middleware will remove a box for a given provider.

Public Class Methods

new(app, env) click to toggle source
# File lib/vagrant/action/builtin/box_remove.rb, line 8
def initialize(app, env)
  @app    = app
  @logger = Log4r::Logger.new("vagrant::action::builtin::box_remove")
end

Public Instance Methods

call(env) click to toggle source
# File lib/vagrant/action/builtin/box_remove.rb, line 13
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