Support non-interactive local plugin install

This commit is contained in:
Chris Roberts 2018-06-22 10:06:41 -07:00
parent 40f4e6f67e
commit 84c0aafe71
12 changed files with 109 additions and 26 deletions

View File

@ -938,14 +938,16 @@ module Vagrant
if !needs_install.empty?
ui.warn(I18n.t("vagrant.plugins.local.uninstalled_plugins",
plugins: needs_install.sort.join(", ")))
answer = nil
until ["y", "n"].include?(answer)
answer = ui.ask(I18n.t("vagrant.plugins.local.request_plugin_install") + ": ")
answer.strip.downcase!
end
if answer == "n"
raise Errors::PluginMissingLocalError,
plugins: needs_install.sort.join(", ")
if !Vagrant.auto_install_local_plugins?
answer = nil
until ["y", "n"].include?(answer)
answer = ui.ask(I18n.t("vagrant.plugins.local.request_plugin_install") + ": ")
answer.strip.downcase!
end
if answer == "n"
raise Errors::PluginMissingLocalError,
plugins: needs_install.sort.join(", ")
end
end
needs_install.each do |name|
ui.info(I18n.t("vagrant.commands.plugin.installing", name: name))

View File

@ -192,8 +192,8 @@ module Vagrant
plugin_file = opts[:local] ? @local_file : @user_file
result = Vagrant::Bundler.instance.update(plugin_list.installed_plugins, specific)
plugin_list.installed_plugins.each do |name, info|
result = Vagrant::Bundler.instance.update(plugin_file.installed_plugins, specific)
plugin_file.installed_plugins.each do |name, info|
matching_spec = result.detect{|s| s.name == name}
info = Hash[
info.map do |key, value|
@ -280,6 +280,11 @@ module Vagrant
return
end
if plugins.nil?
@logger.debug("No plugins provided for loading")
return
end
begin
@logger.info("Loading plugins...")
plugins.each do |plugin_name, plugin_info|

View File

@ -41,7 +41,7 @@ module Vagrant
"require" => opts[:require] || "",
"sources" => opts[:sources] || [],
"installed_gem_version" => opts[:installed_gem_version],
"local" => opts[:local]
"local" => !!opts[:local]
}
save!

View File

@ -130,6 +130,18 @@ module Vagrant
end
end
# Automatically install locally defined plugins instead of
# waiting for user confirmation.
#
# @return [Boolean]
def self.auto_install_local_plugins?
if ENV["VAGRANT_INSTALL_LOCAL_PLUGINS"]
true
else
false
end
end
# Use Ruby Resolv in place of libc
#
# @return [boolean] enabled or not

View File

@ -47,13 +47,13 @@ module VagrantPlugins
# Do not include global paths if local only
if !env[:local]
files << Vagrant::Plugin::Manager.instance.user_file.path
files << Vagrant::Plugin::Manager.instance.user_file
dirs << Vagrant::Bundler.instance.plugin_gem_path
end
# Add local paths if they exist
if Vagrant::Plugin::Manager.instance.local_file
files << Vagrant::Plugin::Manager.instance.local_file.path
files << Vagrant::Plugin::Manager.instance.local_file
dirs << Vagrant::Bundler.instance.env_plugin_gem_path
end

View File

@ -5,21 +5,28 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
let(:home_path){ '/fake/file/path/.vagrant.d' }
let(:gems_path){ "#{home_path}/gems" }
let(:force){ true }
let(:local){ false }
let(:env) {{
ui: Vagrant::UI::Silent.new,
home_path: home_path,
gems_path: gems_path,
force: force
force: force,
local: local
}}
let(:manager) { double("manager") }
let(:user_file) { double("user_file", exist?: true, delete: true) }
let(:local_file) { nil }
let(:bundler) { double("bundler", plugin_gem_path: plugin_gem_path,
env_plugin_gem_path: env_plugin_gem_path) }
let(:plugin_gem_path) { double("plugin_gem_path", exist?: true, rmtree: true) }
let(:env_plugin_gem_path) { nil }
let(:manager) { double("manager", user_file: user_file, local_file: local_file) }
let(:expect_to_receive) do
lambda do
allow(File).to receive(:exist?).with(File.join(home_path, 'plugins.json')).and_return(true)
allow(File).to receive(:directory?).with(gems_path).and_return(true)
expect(FileUtils).to receive(:rm).with(File.join(home_path, 'plugins.json'))
expect(FileUtils).to receive(:rm_rf).with(gems_path)
expect(app).to receive(:call).with(env).once
end
end
@ -28,6 +35,7 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
before do
allow(Vagrant::Plugin::Manager).to receive(:instance).and_return(manager)
allow(Vagrant::Bundler).to receive(:instance).and_return(bundler)
end
describe "#call" do
@ -36,6 +44,8 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
end
it "should delete all plugins" do
expect(user_file).to receive(:delete)
expect(plugin_gem_path).to receive(:rmtree)
subject.call(env)
end
@ -60,5 +70,44 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
end
end
end
context "when local option is set" do
let(:local) { true }
it "should not delete plugins" do
expect(user_file).not_to receive(:delete)
expect(plugin_gem_path).not_to receive(:rmtree)
subject.call(env)
end
end
context "when local plugins exist" do
let(:local_file) { double("local_file", exist?: true, delete: true) }
let(:env_plugin_gem_path) { double("env_plugin_gem_path", exist?: true, rmtree: true) }
it "should delete user and local plugins" do
expect(user_file).to receive(:delete)
expect(local_file).to receive(:delete)
expect(plugin_gem_path).to receive(:rmtree)
expect(env_plugin_gem_path).to receive(:rmtree)
subject.call(env)
end
context "when local option is set" do
let(:local) { true }
it "should delete local plugins" do
expect(local_file).to receive(:delete)
expect(env_plugin_gem_path).to receive(:rmtree)
subject.call(env)
end
it "should not delete user plugins" do
expect(user_file).not_to receive(:delete)
expect(plugin_gem_path).not_to receive(:rmtree)
subject.call(env)
end
end
end
end
end

View File

@ -18,7 +18,7 @@ describe VagrantPlugins::CommandPlugin::Action::InstallGem do
it "should install the plugin" do
spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with(
"foo", version: nil, require: nil, sources: nil, verbose: false).once.and_return(spec)
"foo", version: nil, require: nil, sources: nil, verbose: false, local: nil).once.and_return(spec)
expect(app).to receive(:call).with(env).once
@ -29,7 +29,7 @@ describe VagrantPlugins::CommandPlugin::Action::InstallGem do
it "should specify the version if given" do
spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with(
"foo", version: "bar", require: nil, sources: nil, verbose: false).once.and_return(spec)
"foo", version: "bar", require: nil, sources: nil, verbose: false, local: nil).once.and_return(spec)
expect(app).to receive(:call).with(env).once
@ -41,7 +41,7 @@ describe VagrantPlugins::CommandPlugin::Action::InstallGem do
it "should specify the entrypoint if given" do
spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with(
"foo", version: "bar", require: "baz", sources: nil, verbose: false).once.and_return(spec)
"foo", version: "bar", require: "baz", sources: nil, verbose: false, local: nil).once.and_return(spec)
expect(app).to receive(:call).with(env).once
@ -54,7 +54,7 @@ describe VagrantPlugins::CommandPlugin::Action::InstallGem do
it "should specify the sources if given" do
spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with(
"foo", version: nil, require: nil, sources: ["foo"], verbose: false).once.and_return(spec)
"foo", version: nil, require: nil, sources: ["foo"], verbose: false, local: nil).once.and_return(spec)
expect(app).to receive(:call).with(env).once

View File

@ -15,7 +15,7 @@ describe VagrantPlugins::CommandPlugin::Action::UninstallPlugin do
end
it "uninstalls the specified plugin" do
expect(manager).to receive(:uninstall_plugin).with("bar").ordered
expect(manager).to receive(:uninstall_plugin).with("bar", any_args).ordered
expect(app).to receive(:call).ordered
env[:plugin_name] = "bar"

View File

@ -398,7 +398,13 @@ describe Vagrant::Machine do
callable = lambda { |_env| }
allow(provider).to receive(:action).with(action_name).and_return(callable)
allow(Vagrant::Plugin::Manager.instance).to receive(:installed_plugins)
# The first call here is to allow the environment to setup with attempting
# to load a plugin that does not exist
expect(Vagrant::Plugin::Manager.instance).to receive(:installed_plugins)
.and_return({})
expect(Vagrant::Plugin::Manager.instance).to receive(:installed_plugins)
.and_return({"vagrant-triggers"=>"stuff"})
expect(instance.instance_variable_get(:@triggers)).not_to receive(:fire_triggers)

View File

@ -32,7 +32,7 @@ describe Vagrant::Plugin::Manager do
specs[3].name = "foo"
expect(bundler).to receive(:install).once.with(any_args) { |plugins, local|
expect(plugins).to have_key("foo")
expect(local).to be(false)
expect(local).to be_falsey
}.and_return(specs)
expect(bundler).to receive(:clean)
@ -95,7 +95,7 @@ describe Vagrant::Plugin::Manager do
expect(bundler).to receive(:install).once.with(any_args) { |plugins, local|
expect(plugins).to have_key("foo")
expect(plugins["foo"]["gem_version"]).to eql(">= 0.1.0")
expect(local).to be(false)
expect(local).to be_falsey
}.and_return(specs)
expect(bundler).to receive(:clean)
@ -110,7 +110,7 @@ describe Vagrant::Plugin::Manager do
expect(bundler).to receive(:install).once.with(any_args) { |plugins, local|
expect(plugins).to have_key("foo")
expect(plugins["foo"]["gem_version"]).to eql("0.1.0")
expect(local).to be(false)
expect(local).to be_falsey
}.and_return(specs)
expect(bundler).to receive(:clean)
@ -140,6 +140,8 @@ describe Vagrant::Plugin::Manager do
end
it "masks bundler errors with our own error" do
sf = Vagrant::Plugin::StateFile.new(path)
sf.add_plugin("foo")
expect(bundler).to receive(:clean).and_raise(Gem::InstallError)
expect { subject.uninstall_plugin("foo") }.

View File

@ -32,6 +32,7 @@ describe Vagrant::Plugin::StateFile do
"require" => "",
"sources" => [],
"installed_gem_version" => nil,
"local" => false,
})
end

View File

@ -161,6 +161,12 @@ may be desirable to ignore inaccessible sources and continue with the
plugin installation. Enabling this value will cause Vagrant to simply log
the plugin source error and continue.
## `VAGRANT_INSTALL_LOCAL_PLUGINS`
If this is set to any value, Vagrant will not prompt for confirmation
prior to installing local plugins which have been defined within the
local Vagrantfile.
## `VAGRANT_NO_PARALLEL`
If this is set, Vagrant will not perform any parallel operations (such as