Merge branch 'plugin-command'
This introduces a new `vagrant plugin` command and removes the old `vagrant gem` command. Technically, `vagrant plugin` is still just using RubyGems underneath to manage plugins, but it masks the entire RubyGem experience away from the end user. This merge introduces three commands; `list`, `install`, and `uninstall`. They do what they sound like they do. Future enhancements will add more information such as what components a plugin installs and activation/deactivation of plugins that you want to keep installed but don't want to run.
This commit is contained in:
commit
c8260162d4
|
@ -15,7 +15,6 @@ module Vagrant
|
|||
class Environment
|
||||
DEFAULT_HOME = "~/.vagrant.d"
|
||||
DEFAULT_LOCAL_DATA = ".vagrant"
|
||||
DEFAULT_RC = "~/.vagrantrc"
|
||||
|
||||
# The `cwd` that this environment represents
|
||||
attr_reader :cwd
|
||||
|
@ -411,6 +410,7 @@ module Vagrant
|
|||
:box_collection => boxes,
|
||||
:global_config => config_global,
|
||||
:host => host,
|
||||
:gems_path => gems_path,
|
||||
:root_path => root_path,
|
||||
:tmp_path => tmp_path,
|
||||
:ui => @ui
|
||||
|
@ -591,18 +591,27 @@ module Vagrant
|
|||
# Loads the Vagrant plugins by properly setting up RubyGems so that
|
||||
# our private gem repository is on the path.
|
||||
def load_plugins
|
||||
if ENV["VAGRANT_NO_PLUGINS"]
|
||||
# If this key exists, then we don't load any plugins. It is a "safe
|
||||
# mode" of sorts.
|
||||
@logger.warn("VAGRANT_NO_PLUGINS is set. Not loading 3rd party plugins.")
|
||||
return
|
||||
end
|
||||
|
||||
# Add our private gem path to the gem path and reset the paths
|
||||
# that Rubygems knows about.
|
||||
ENV["GEM_PATH"] = "#{@gems_path}#{::File::PATH_SEPARATOR}#{ENV["GEM_PATH"]}"
|
||||
::Gem.clear_paths
|
||||
|
||||
# Load the plugins
|
||||
rc_path = File.expand_path(ENV["VAGRANT_RC"] || DEFAULT_RC)
|
||||
if File.file?(rc_path) && @@loaded_rc.add?(rc_path)
|
||||
@logger.debug("Loading RC file: #{rc_path}")
|
||||
load rc_path
|
||||
else
|
||||
@logger.debug("RC file not found. Not loading: #{rc_path}")
|
||||
plugins_json_file = @home_path.join("plugins.json")
|
||||
@logger.debug("Loading plugins from: #{plugins_json_file}")
|
||||
if plugins_json_file.file?
|
||||
data = JSON.parse(plugins_json_file.read)
|
||||
data["installed"].each do |plugin|
|
||||
@logger.info("Loading plugin from JSON: #{plugin}")
|
||||
Vagrant.require_plugin(plugin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -336,6 +336,10 @@ module Vagrant
|
|||
error_key(:provider_not_found)
|
||||
end
|
||||
|
||||
class PluginGemError < VagrantError
|
||||
error_key(:plugin_gem_error)
|
||||
end
|
||||
|
||||
class PluginLoadError < VagrantError
|
||||
status_code(81)
|
||||
error_key(:plugin_load_error)
|
||||
|
|
|
@ -15,7 +15,7 @@ module VagrantPlugins
|
|||
if defined?(Bundler)
|
||||
require 'bundler/shared_helpers'
|
||||
if Bundler::SharedHelpers.in_bundle?
|
||||
raise Errors::GemCommandInBundler
|
||||
raise Vagrant::Errors::GemCommandInBundler
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
require "pathname"
|
||||
|
||||
require "vagrant/action/builder"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This middleware sequence will install a plugin.
|
||||
def self.action_install
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use BundlerCheck
|
||||
b.use InstallGem
|
||||
b.use PruneGems
|
||||
end
|
||||
end
|
||||
|
||||
# This middleware sequence will list all installed plugins.
|
||||
def self.action_list
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use BundlerCheck
|
||||
b.use ListPlugins
|
||||
end
|
||||
end
|
||||
|
||||
# This middleware sequence will uninstall a plugin.
|
||||
def self.action_uninstall
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use BundlerCheck
|
||||
b.use UninstallPlugin
|
||||
b.use PruneGems
|
||||
end
|
||||
end
|
||||
|
||||
# The autoload farm
|
||||
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
||||
autoload :BundlerCheck, action_root.join("bundler_check")
|
||||
autoload :InstallGem, action_root.join("install_gem")
|
||||
autoload :ListPlugins, action_root.join("list_plugins")
|
||||
autoload :PruneGems, action_root.join("prune_gems")
|
||||
autoload :UninstallPlugin, action_root.join("uninstall_plugin")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
class BundlerCheck
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# Bundler sets up its own custom gem load paths such that our
|
||||
# own gems are never loaded. Therefore, give an error if a user
|
||||
# tries to install gems while within a Bundler-managed environment.
|
||||
if defined?(Bundler)
|
||||
require 'bundler/shared_helpers'
|
||||
if Bundler::SharedHelpers.in_bundle?
|
||||
raise Vagrant::Errors::GemCommandInBundler
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
require "rubygems"
|
||||
require "rubygems/gem_runner"
|
||||
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This action takes the `:plugin_name` variable in the environment
|
||||
# and installs it using the RubyGems API.
|
||||
class InstallGem
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::plugins::plugincommand::installgem")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
plugin_name = env[:plugin_name]
|
||||
|
||||
# Install the gem
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.installing",
|
||||
:name => plugin_name))
|
||||
env[:gem_helper].cli(["install", plugin_name, "--no-ri", "--no-rdoc"])
|
||||
|
||||
# Mark that we installed the gem
|
||||
env[:plugin_state_file].add_plugin(plugin_name)
|
||||
|
||||
# Continue
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
require "rubygems"
|
||||
require "set"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This middleware lists all the installed plugins.
|
||||
#
|
||||
# This is a bit more complicated than simply listing installed
|
||||
# gems or what is in the state file as installed. Instead, this
|
||||
# actually compares installed gems with what the state file claims
|
||||
# is installed, and outputs the appropriate truly installed
|
||||
# plugins.
|
||||
class ListPlugins
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# Get the list of installed plugins according to the state file
|
||||
installed = Set.new(env[:plugin_state_file].installed_plugins)
|
||||
|
||||
# Get the actual specifications of installed gems
|
||||
specs = env[:gem_helper].with_environment do
|
||||
Gem::Specification.find_all
|
||||
end
|
||||
|
||||
# Get the latest version of the installed plugins
|
||||
installed_map = {}
|
||||
specs.each do |spec|
|
||||
# Ignore specs that aren't in our installed list
|
||||
next if !installed.include?(spec.name)
|
||||
|
||||
# If we already have a newer version in our list of installed,
|
||||
# then ignore it
|
||||
next if installed_map.has_key?(spec.name) &&
|
||||
installed_map[spec.name].version >= spec.version
|
||||
|
||||
installed_map[spec.name] = spec
|
||||
end
|
||||
|
||||
# Output!
|
||||
if installed_map.empty?
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.no_plugins"))
|
||||
else
|
||||
installed_map.values.each do |spec|
|
||||
env[:ui].info "#{spec.name} (#{spec.version})"
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,156 @@
|
|||
require "rubygems"
|
||||
require "rubygems/user_interaction"
|
||||
require "rubygems/uninstaller"
|
||||
require "set"
|
||||
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This class prunes any unnecessary gems from the Vagrant-managed
|
||||
# gem folder. This keeps the gem folder to the absolute minimum set
|
||||
# of required gems and doesn't let it blow up out of control.
|
||||
#
|
||||
# A high-level description of how this works:
|
||||
#
|
||||
# 1. Get the list of installed plugins. Vagrant maintains this
|
||||
# list on its own.
|
||||
# 2. Get the list of installed RubyGems.
|
||||
# 3. Find the latest version of each RubyGem that matches an installed
|
||||
# plugin. These are our root RubyGems that must be installed.
|
||||
# 4. Go through each root and mark all dependencies recursively as
|
||||
# necessary.
|
||||
# 5. Set subtraction between all gems and necessary gems yields a
|
||||
# list of gems that aren't needed. Uninstall them.
|
||||
#
|
||||
class PruneGems
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::plugins::plugincommand::prune")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@logger.info("Pruning gems...")
|
||||
|
||||
# Get the list of installed plugins according to the state file
|
||||
installed = Set.new(env[:plugin_state_file].installed_plugins)
|
||||
|
||||
# Get the actual specifications of installed gems
|
||||
all_specs = env[:gem_helper].with_environment do
|
||||
result = []
|
||||
Gem::Specification.find_all { |s| result << s }
|
||||
result
|
||||
end
|
||||
|
||||
# The list of specs to prune initially starts out as all of them
|
||||
all_specs = Set.new(all_specs)
|
||||
|
||||
# Go through each spec and find the latest version of the installed
|
||||
# gems, since we want to keep those.
|
||||
installed_specs = {}
|
||||
|
||||
@logger.debug("Collecting installed plugin gems...")
|
||||
all_specs.each do |spec|
|
||||
# If this isn't a spec that we claim is installed, skip it
|
||||
next if !installed.include?(spec.name)
|
||||
|
||||
# If it is already in the specs, then we need to make sure we
|
||||
# have the latest version.
|
||||
if installed_specs.has_key?(spec.name)
|
||||
if installed_specs[spec.name].version > spec.version
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
@logger.debug(" -- #{spec.name} (#{spec.version})")
|
||||
installed_specs[spec.name] = spec
|
||||
end
|
||||
|
||||
# Recursive dependency checker to keep all dependencies and remove
|
||||
# all non-crucial gems from the prune list.
|
||||
good_specs = Set.new
|
||||
to_check = installed_specs.values
|
||||
|
||||
while true
|
||||
# If we're out of gems to check then we break out
|
||||
break if to_check.empty?
|
||||
|
||||
# Get a random (first) element to check
|
||||
spec = to_check.shift
|
||||
|
||||
# If we already checked this, then do the next one
|
||||
next if good_specs.include?(spec)
|
||||
|
||||
# Find all the dependencies and add the latest compliant gem
|
||||
# to the `to_check` list.
|
||||
if spec.dependencies.length > 0
|
||||
@logger.debug("Finding dependencies for '#{spec.name}' to mark as good...")
|
||||
spec.dependencies.each do |dep|
|
||||
# Ignore non-runtime dependencies
|
||||
next if dep.type != :runtime
|
||||
@logger.debug("Searching for: '#{dep.name}'")
|
||||
|
||||
latest_matching = nil
|
||||
|
||||
all_specs.each do |prune_spec|
|
||||
if dep =~ prune_spec
|
||||
# If we have a matching one already and this one isn't newer
|
||||
# then we ditch it.
|
||||
next if latest_matching &&
|
||||
prune_spec.version <= latest_matching.version
|
||||
|
||||
latest_matching = prune_spec
|
||||
end
|
||||
end
|
||||
|
||||
if latest_matching.nil?
|
||||
@logger.error("Missing dependency for '#{spec.name}': #{dep.name}")
|
||||
next
|
||||
end
|
||||
|
||||
@logger.debug("Latest matching dep: '#{latest_matching.name}' (#{latest_matching.version})")
|
||||
to_check << latest_matching
|
||||
end
|
||||
end
|
||||
|
||||
# Add ito the list of checked things so we don't accidentally
|
||||
# re-check it
|
||||
good_specs.add(spec)
|
||||
end
|
||||
|
||||
# Figure out the gems we need to prune
|
||||
prune_specs = all_specs - good_specs
|
||||
@logger.debug("Gems to prune: #{prune_specs.inspect}")
|
||||
@logger.info("Pruning #{prune_specs.length} gems.")
|
||||
|
||||
if prune_specs.length > 0
|
||||
env[:gem_helper].with_environment do
|
||||
prune_specs.each do |prune_spec|
|
||||
uninstaller = Gem::Uninstaller.new(prune_spec.name, {
|
||||
:executables => true,
|
||||
:force => true,
|
||||
:version => prune_spec.version.version
|
||||
})
|
||||
|
||||
# This is sad, but there is no way to force this to be true
|
||||
# so I just monkey-patch here. Vagrant has a pretty strict
|
||||
# version check on the RubyGems version so this should be okay.
|
||||
# In the future, let's try to get a pull request into RubyGems
|
||||
# to fix this.
|
||||
def uninstaller.ask_if_ok(spec)
|
||||
true
|
||||
end
|
||||
|
||||
@logger.info("Uninstalling: #{prune_spec.name} (#{prune_spec.version})")
|
||||
uninstaller.uninstall
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This middleware uninstalls a plugin by simply removing it from
|
||||
# the state file. Running a {PruneGems} after should properly remove
|
||||
# it from the gem index.
|
||||
class UninstallPlugin
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# Remove it!
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.uninstalling",
|
||||
:name => env[:plugin_name]))
|
||||
env[:plugin_state_file].remove_plugin(env[:plugin_name])
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class Base < Vagrant.plugin("2", :command)
|
||||
# This is a helper for executing an action sequence with the proper
|
||||
# environment hash setup so that the plugin specific helpers are
|
||||
# in.
|
||||
#
|
||||
# @param [Object] callable the Middleware callable
|
||||
# @param [Hash] env Extra environment hash that is merged in.
|
||||
def action(callable, env=nil)
|
||||
env = {
|
||||
:gem_helper => GemHelper.new(@env.gems_path),
|
||||
:plugin_state_file => StateFile.new(@env.home_path.join("plugins.json"))
|
||||
}.merge(env || {})
|
||||
|
||||
@env.action_runner.run(callable, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'optparse'
|
||||
|
||||
require_relative "base"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class Install < Base
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin install <name> [-h]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if argv.length < 1
|
||||
|
||||
# Install the gem
|
||||
action(Action.action_install, :plugin_name => argv[0])
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'optparse'
|
||||
|
||||
require_relative "base"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class List < Base
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin list [-h]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if argv.length > 0
|
||||
|
||||
# List the installed plugins
|
||||
action(Action.action_list)
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,70 @@
|
|||
require 'optparse'
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class Root < Vagrant.plugin("2", :command)
|
||||
def initialize(argv, env)
|
||||
super
|
||||
|
||||
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||
|
||||
@subcommands = Vagrant::Registry.new
|
||||
@subcommands.register(:install) do
|
||||
require_relative "install"
|
||||
Install
|
||||
end
|
||||
|
||||
@subcommands.register(:list) do
|
||||
require_relative "list"
|
||||
List
|
||||
end
|
||||
|
||||
@subcommands.register(:uninstall) do
|
||||
require_relative "uninstall"
|
||||
Uninstall
|
||||
end
|
||||
end
|
||||
|
||||
def execute
|
||||
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||
# Print the help for all the sub-commands.
|
||||
return help
|
||||
end
|
||||
|
||||
# If we reached this far then we must have a subcommand. If not,
|
||||
# then we also just print the help and exit.
|
||||
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||
return help if !command_class || !@sub_command
|
||||
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||
|
||||
# Initialize and execute the command class
|
||||
command_class.new(@sub_args, @env).execute
|
||||
end
|
||||
|
||||
# Prints the help out for this command
|
||||
def help
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin <command> [<args>]"
|
||||
o.separator ""
|
||||
o.separator "Available subcommands:"
|
||||
|
||||
# Add the available subcommands as separators in order to print them
|
||||
# out as well.
|
||||
keys = []
|
||||
@subcommands.each { |key, value| keys << key.to_s }
|
||||
|
||||
keys.sort.each do |key|
|
||||
o.separator " #{key}"
|
||||
end
|
||||
|
||||
o.separator ""
|
||||
o.separator "For help on any individual command run `vagrant plugin COMMAND -h`"
|
||||
end
|
||||
|
||||
@env.ui.info(opts.help, :prefix => false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'optparse'
|
||||
|
||||
require_relative "base"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class Uninstall < Base
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin uninstall <name> [-h]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if argv.length < 1
|
||||
|
||||
# Uninstall the gem
|
||||
action(Action.action_uninstall, :plugin_name => argv[0])
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,74 @@
|
|||
require "rubygems"
|
||||
require "rubygems/gem_runner"
|
||||
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
# This class provides methods to help with calling out to the
|
||||
# `gem` command but using the RubyGems API.
|
||||
class GemHelper
|
||||
def initialize(gem_home)
|
||||
@gem_home = gem_home.to_s
|
||||
@logger = Log4r::Logger.new("vagrant::plugins::plugincommand::gemhelper")
|
||||
end
|
||||
|
||||
# This executes the `gem` command with the given arguments. Under
|
||||
# the covers this is actually using the RubyGems API directly,
|
||||
# instead of shelling out, which allows for more fine-grained control.
|
||||
#
|
||||
# @param [Array<String>] argv The arguments to send to the `gem` command.
|
||||
def cli(argv)
|
||||
# Initialize the UI to use for RubyGems. This allows us to capture
|
||||
# the stdout/stderr without actually going to the real STDOUT/STDERR.
|
||||
# The final "false" here tells RubyGems we're not a TTY, so don't
|
||||
# ask us things.
|
||||
gem_ui = Gem::StreamUI.new(StringIO.new, StringIO.new, StringIO.new, false)
|
||||
|
||||
# Set the GEM_HOME so that it is installed into our local gems path
|
||||
with_environment do
|
||||
@logger.info("Calling gem with argv: #{argv.inspect}")
|
||||
Gem::DefaultUserInteraction.use_ui(gem_ui) do
|
||||
Gem::GemRunner.new.run(argv)
|
||||
end
|
||||
end
|
||||
rescue Gem::SystemExitException => e
|
||||
# This means that something forced an exit within RubyGems.
|
||||
# We capture this to check whether it succeeded or not by
|
||||
# checking the "exit_code"
|
||||
raise Vagrant::Errors::PluginGemError,
|
||||
:output => gem_ui.errs.string.chomp if e.exit_code != 0
|
||||
ensure
|
||||
# Log the output properly
|
||||
@logger.debug("Gem STDOUT: #{gem_ui.outs.string}")
|
||||
@logger.debug("Gem STDERR: #{gem_ui.errs.string}")
|
||||
end
|
||||
|
||||
# This will yield the given block with the proper ENV setup so
|
||||
# that RubyGems only sees the gems in the Vagrant-managed gem
|
||||
# path.
|
||||
def with_environment
|
||||
old_gem_home = ENV["GEM_HOME"]
|
||||
old_gem_path = ENV["GEM_PATH"]
|
||||
ENV["GEM_HOME"] = @gem_home
|
||||
ENV["GEM_PATH"] = @gem_home
|
||||
@logger.debug("Set GEM_* to: #{ENV["GEM_HOME"]}")
|
||||
|
||||
# Clear paths so that it reads the new GEM_HOME setting
|
||||
Gem.paths = ENV
|
||||
|
||||
# Use a silent UI so that we have no output
|
||||
Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do
|
||||
return yield
|
||||
end
|
||||
ensure
|
||||
# Restore the old GEM_* settings
|
||||
ENV["GEM_HOME"] = old_gem_home
|
||||
ENV["GEM_PATH"] = old_gem_path
|
||||
|
||||
# Reset everything
|
||||
Gem.paths = ENV
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "plugin command"
|
||||
description <<-DESC
|
||||
This command helps manage and install plugins within the
|
||||
Vagrant environment.
|
||||
DESC
|
||||
|
||||
command("plugin") do
|
||||
require File.expand_path("../command/root", __FILE__)
|
||||
Command::Root
|
||||
end
|
||||
end
|
||||
|
||||
autoload :Action, File.expand_path("../action", __FILE__)
|
||||
autoload :GemHelper, File.expand_path("../gem_helper", __FILE__)
|
||||
autoload :StateFile, File.expand_path("../state_file", __FILE__)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
require "json"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
# This is a helper to deal with the plugin state file that Vagrant
|
||||
# uses to track what plugins are installed and activated and such.
|
||||
class StateFile
|
||||
def initialize(path)
|
||||
@path = path
|
||||
|
||||
@data = {}
|
||||
@data = JSON.parse(@path.read) if @path.exist?
|
||||
@data["installed"] ||= []
|
||||
end
|
||||
|
||||
# Add a plugin that is installed to the state file.
|
||||
#
|
||||
# @param [String] name The name of the plugin
|
||||
def add_plugin(name)
|
||||
if !@data["installed"].include?(name)
|
||||
@data["installed"] << name
|
||||
end
|
||||
|
||||
save!
|
||||
end
|
||||
|
||||
# This returns a list of installed plugins according to the state
|
||||
# file. Note that this may _not_ directly match over to actually
|
||||
# installed gems.
|
||||
#
|
||||
# @return [Array<String>]
|
||||
def installed_plugins
|
||||
@data["installed"]
|
||||
end
|
||||
|
||||
# Remove a plugin that is installed from the state file.
|
||||
#
|
||||
# @param [String] name The name of the plugin.
|
||||
def remove_plugin(name)
|
||||
@data["installed"].delete(name)
|
||||
save!
|
||||
end
|
||||
|
||||
# This saves the state back into the state file.
|
||||
def save!
|
||||
# Scrub some fields
|
||||
@data["installed"].sort!
|
||||
@data["installed"].uniq!
|
||||
|
||||
# Save
|
||||
@path.open("w+") do |f|
|
||||
f.write(JSON.dump(@data))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -114,11 +114,11 @@ en:
|
|||
occurring. Please wait for the other instance of Vagrant to end and then
|
||||
try again.
|
||||
gem_command_in_bundler: |-
|
||||
You cannot run the `vagrant gem` command while in a bundler environment.
|
||||
Bundler messes around quite a bit with the RubyGem load paths and gems
|
||||
installed via `vagrant gem` are excluded by Bundler.
|
||||
|
||||
Instead, please include your Vagrant plugins in your Gemfile itself.
|
||||
You cannot run the `vagrant plugin` command while in a bundler environment.
|
||||
This should generally never happen unless Vagrant is installed outside
|
||||
of the official installers or another gem is wrongly attempting to
|
||||
use Vagrant internals directly. Please properly install Vagrant to
|
||||
fix this. If this error persists, please contact support.
|
||||
guest:
|
||||
invalid_class: |-
|
||||
The specified guest class does not inherit from a proper guest
|
||||
|
@ -165,6 +165,11 @@ en:
|
|||
no_env: |-
|
||||
A Vagrant environment is required to run this command. Run `vagrant init`
|
||||
to set one up.
|
||||
plugin_gem_error: |-
|
||||
An error occurred within RubyGems, the underlying system used to
|
||||
manage Vagrant plugins. The output of the errors are shown below:
|
||||
|
||||
%{output}
|
||||
plugin_load_error: |-
|
||||
The plugin "%{plugin}" could not be found. Please make sure that it is
|
||||
properly installed via `vagrant gem`.
|
||||
|
@ -411,6 +416,13 @@ en:
|
|||
ready to `vagrant up` your first virtual environment! Please read
|
||||
the comments in the Vagrantfile as well as documentation on
|
||||
`vagrantup.com` for more information on using Vagrant.
|
||||
plugin:
|
||||
no_plugins: |-
|
||||
No plugins installed.
|
||||
installing: |-
|
||||
Installing the '%{name}' plugin. This can take a few minutes...
|
||||
uninstalling: |-
|
||||
Uninstalling the '%{name}' plugin...
|
||||
status:
|
||||
aborted: |-
|
||||
The VM is in an aborted state. This means that it was abruptly
|
||||
|
|
Loading…
Reference in New Issue