diff --git a/bin/vagrant b/bin/vagrant index 0e6738953..0763ca89f 100755 --- a/bin/vagrant +++ b/bin/vagrant @@ -29,7 +29,7 @@ argv.each_index do |i| ENV['VAGRANT_NO_PLUGINS'] = "1" end - if arg == "plugin" && argv[i+1] == "repair" + if arg == "plugin" && ["repair", "expunge"].include?(argv[i+1]) ENV['VAGRANT_DISABLE_PLUGIN_INIT'] = "1" end diff --git a/plugins/commands/plugin/action.rb b/plugins/commands/plugin/action.rb index cdc9c3943..e1ed6dbd7 100644 --- a/plugins/commands/plugin/action.rb +++ b/plugins/commands/plugin/action.rb @@ -6,6 +6,12 @@ module VagrantPlugins module CommandPlugin module Action # This middleware sequence will install a plugin. + def self.action_expunge + Vagrant::Action::Builder.new.tap do |b| + b.use ExpungePlugins + end + end + def self.action_install Vagrant::Action::Builder.new.tap do |b| b.use InstallGem @@ -51,6 +57,7 @@ module VagrantPlugins # The autoload farm action_root = Pathname.new(File.expand_path("../action", __FILE__)) + autoload :ExpungePlugins, action_root.join("expunge_plugins") autoload :InstallGem, action_root.join("install_gem") autoload :LicensePlugin, action_root.join("license_plugin") autoload :ListPlugins, action_root.join("list_plugins") diff --git a/plugins/commands/plugin/action/expunge_plugins.rb b/plugins/commands/plugin/action/expunge_plugins.rb new file mode 100644 index 000000000..4c61d9145 --- /dev/null +++ b/plugins/commands/plugin/action/expunge_plugins.rb @@ -0,0 +1,49 @@ +require 'pp' +require "vagrant/plugin/manager" + +module VagrantPlugins + module CommandPlugin + module Action + # This middleware removes user installed plugins by + # removing: + # * ~/.vagrant.d/plugins.json + # * ~/.vagrant.d/gems + # Usage should be restricted to when a repair is + # unsuccessful and the only reasonable option remaining + # is to re-install all plugins + class ExpungePlugins + def initialize(app, env) + @app = app + end + + def call(env) + if !env[:force] + result = env[:ui].ask( + I18n.t("vagrant.commands.plugin.expunge_confirm") + + " [Y/N]:" + ) + if result.to_s.downcase.strip == 'n' + exit 1 + end + end + + plugins = Vagrant::Plugin::Manager.instance.installed_plugins + plugins_json = File.join(env[:home_path], "plugins.json") + plugins_gems = env[:gems_path] + + if File.exist?(plugins_json) + FileUtils.rm(plugins_json) + end + + if File.directory?(plugins_gems) + FileUtils.rm_rf(plugins_gems) + end + + env[:ui].info(I18n.t("vagrant.commands.plugin.expunge_complete")) + + @app.call(env) + end + end + end + end +end diff --git a/plugins/commands/plugin/command/expunge.rb b/plugins/commands/plugin/command/expunge.rb new file mode 100644 index 000000000..9e5db4bd3 --- /dev/null +++ b/plugins/commands/plugin/command/expunge.rb @@ -0,0 +1,65 @@ +require 'optparse' + +require_relative "base" + +module VagrantPlugins + module CommandPlugin + module Command + class Expunge < Base + def execute + options = {} + + opts = OptionParser.new do |o| + o.banner = "Usage: vagrant plugin expunge [-h]" + + o.on("--force", "Do not prompt for confirmation") do |force| + options[:force] = force + end + + o.on("--reinstall", "Reinstall current plugins after expunge") do |reinstall| + options[:reinstall] = reinstall + end + end + + # Parse the options + argv = parse_options(opts) + return if !argv + raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if argv.length > 0 + + plugins = Vagrant::Plugin::Manager.instance.installed_plugins + + if !options[:reinstall] && !options[:force] && !plugins.empty? + result = @env.ui.ask( + I18n.t("vagrant.commands.plugin.expunge_request_reinstall") + + " [Y/N]:" + ) + options[:reinstall] = result.to_s.downcase.strip == "y" + end + + # Remove all installed user plugins + action(Action.action_expunge, options) + + if options[:reinstall] + @env.ui.info(I18n.t("vagrant.commands.plugin.expunge_reinstall")) + plugins.each do |plugin_name, plugin_info| + plugin_info = Hash[ + plugin_info.map do |key, value| + [key.to_sym, value] + end + ] + action( + Action.action_install, + plugin_info.merge( + plugin_name: plugin_name + ) + ) + end + end + + # Success, exit status 0 + 0 + end + end + end + end +end diff --git a/plugins/commands/plugin/command/root.rb b/plugins/commands/plugin/command/root.rb index 9a53f6883..6953eb495 100644 --- a/plugins/commands/plugin/command/root.rb +++ b/plugins/commands/plugin/command/root.rb @@ -14,6 +14,11 @@ module VagrantPlugins @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv) @subcommands = Vagrant::Registry.new + @subcommands.register(:expunge) do + require_relative "expunge" + Expunge + end + @subcommands.register(:install) do require_relative "install" Install diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 250d89be4..e3ce3f37a 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1576,6 +1576,21 @@ en: the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant. plugin: + expunge_confirm: |- + + This command permanently deletes all currently installed user plugins. It + should only be used when a repair command is unable to properly fix the + system. + + Continue? + expunge_request_reinstall: |- + Would you like Vagrant to attempt to reinstall current plugins? + expunge_complete: |- + + All user installed plugins have been removed from this Vagrant environment! + expunge_reinstall: |- + + Vagrant will now attempt to reinstall user plugins that were removed. installed_license: |- The license for '%{name}' was successfully installed! installing_license: |-