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? if !needs_install.empty?
ui.warn(I18n.t("vagrant.plugins.local.uninstalled_plugins", ui.warn(I18n.t("vagrant.plugins.local.uninstalled_plugins",
plugins: needs_install.sort.join(", "))) plugins: needs_install.sort.join(", ")))
answer = nil if !Vagrant.auto_install_local_plugins?
until ["y", "n"].include?(answer) answer = nil
answer = ui.ask(I18n.t("vagrant.plugins.local.request_plugin_install") + ": ") until ["y", "n"].include?(answer)
answer.strip.downcase! answer = ui.ask(I18n.t("vagrant.plugins.local.request_plugin_install") + ": ")
end answer.strip.downcase!
if answer == "n" end
raise Errors::PluginMissingLocalError, if answer == "n"
plugins: needs_install.sort.join(", ") raise Errors::PluginMissingLocalError,
plugins: needs_install.sort.join(", ")
end
end end
needs_install.each do |name| needs_install.each do |name|
ui.info(I18n.t("vagrant.commands.plugin.installing", name: 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 plugin_file = opts[:local] ? @local_file : @user_file
result = Vagrant::Bundler.instance.update(plugin_list.installed_plugins, specific) result = Vagrant::Bundler.instance.update(plugin_file.installed_plugins, specific)
plugin_list.installed_plugins.each do |name, info| plugin_file.installed_plugins.each do |name, info|
matching_spec = result.detect{|s| s.name == name} matching_spec = result.detect{|s| s.name == name}
info = Hash[ info = Hash[
info.map do |key, value| info.map do |key, value|
@ -280,6 +280,11 @@ module Vagrant
return return
end end
if plugins.nil?
@logger.debug("No plugins provided for loading")
return
end
begin begin
@logger.info("Loading plugins...") @logger.info("Loading plugins...")
plugins.each do |plugin_name, plugin_info| plugins.each do |plugin_name, plugin_info|

View File

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

View File

@ -130,6 +130,18 @@ module Vagrant
end end
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 # Use Ruby Resolv in place of libc
# #
# @return [boolean] enabled or not # @return [boolean] enabled or not

View File

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

View File

@ -5,21 +5,28 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
let(:home_path){ '/fake/file/path/.vagrant.d' } let(:home_path){ '/fake/file/path/.vagrant.d' }
let(:gems_path){ "#{home_path}/gems" } let(:gems_path){ "#{home_path}/gems" }
let(:force){ true } let(:force){ true }
let(:local){ false }
let(:env) {{ let(:env) {{
ui: Vagrant::UI::Silent.new, ui: Vagrant::UI::Silent.new,
home_path: home_path, home_path: home_path,
gems_path: gems_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 let(:expect_to_receive) do
lambda do lambda do
allow(File).to receive(:exist?).with(File.join(home_path, 'plugins.json')).and_return(true) 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) 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 expect(app).to receive(:call).with(env).once
end end
end end
@ -28,6 +35,7 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
before do before do
allow(Vagrant::Plugin::Manager).to receive(:instance).and_return(manager) allow(Vagrant::Plugin::Manager).to receive(:instance).and_return(manager)
allow(Vagrant::Bundler).to receive(:instance).and_return(bundler)
end end
describe "#call" do describe "#call" do
@ -36,6 +44,8 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
end end
it "should delete all plugins" do it "should delete all plugins" do
expect(user_file).to receive(:delete)
expect(plugin_gem_path).to receive(:rmtree)
subject.call(env) subject.call(env)
end end
@ -60,5 +70,44 @@ describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
end end
end 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
end end

View File

@ -18,7 +18,7 @@ describe VagrantPlugins::CommandPlugin::Action::InstallGem do
it "should install the plugin" do it "should install the plugin" do
spec = Gem::Specification.new spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with( 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 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 it "should specify the version if given" do
spec = Gem::Specification.new spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with( 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 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 it "should specify the entrypoint if given" do
spec = Gem::Specification.new spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with( 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 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 it "should specify the sources if given" do
spec = Gem::Specification.new spec = Gem::Specification.new
expect(manager).to receive(:install_plugin).with( 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 expect(app).to receive(:call).with(env).once

View File

@ -15,7 +15,7 @@ describe VagrantPlugins::CommandPlugin::Action::UninstallPlugin do
end end
it "uninstalls the specified plugin" do 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 expect(app).to receive(:call).ordered
env[:plugin_name] = "bar" env[:plugin_name] = "bar"

View File

@ -398,7 +398,13 @@ describe Vagrant::Machine do
callable = lambda { |_env| } callable = lambda { |_env| }
allow(provider).to receive(:action).with(action_name).and_return(callable) 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"}) .and_return({"vagrant-triggers"=>"stuff"})
expect(instance.instance_variable_get(:@triggers)).not_to receive(:fire_triggers) 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" specs[3].name = "foo"
expect(bundler).to receive(:install).once.with(any_args) { |plugins, local| expect(bundler).to receive(:install).once.with(any_args) { |plugins, local|
expect(plugins).to have_key("foo") expect(plugins).to have_key("foo")
expect(local).to be(false) expect(local).to be_falsey
}.and_return(specs) }.and_return(specs)
expect(bundler).to receive(:clean) 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(bundler).to receive(:install).once.with(any_args) { |plugins, local|
expect(plugins).to have_key("foo") expect(plugins).to have_key("foo")
expect(plugins["foo"]["gem_version"]).to eql(">= 0.1.0") expect(plugins["foo"]["gem_version"]).to eql(">= 0.1.0")
expect(local).to be(false) expect(local).to be_falsey
}.and_return(specs) }.and_return(specs)
expect(bundler).to receive(:clean) 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(bundler).to receive(:install).once.with(any_args) { |plugins, local|
expect(plugins).to have_key("foo") expect(plugins).to have_key("foo")
expect(plugins["foo"]["gem_version"]).to eql("0.1.0") expect(plugins["foo"]["gem_version"]).to eql("0.1.0")
expect(local).to be(false) expect(local).to be_falsey
}.and_return(specs) }.and_return(specs)
expect(bundler).to receive(:clean) expect(bundler).to receive(:clean)
@ -140,6 +140,8 @@ describe Vagrant::Plugin::Manager do
end end
it "masks bundler errors with our own error" do 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(bundler).to receive(:clean).and_raise(Gem::InstallError)
expect { subject.uninstall_plugin("foo") }. expect { subject.uninstall_plugin("foo") }.

View File

@ -32,6 +32,7 @@ describe Vagrant::Plugin::StateFile do
"require" => "", "require" => "",
"sources" => [], "sources" => [],
"installed_gem_version" => nil, "installed_gem_version" => nil,
"local" => false,
}) })
end 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 plugin installation. Enabling this value will cause Vagrant to simply log
the plugin source error and continue. 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` ## `VAGRANT_NO_PARALLEL`
If this is set, Vagrant will not perform any parallel operations (such as If this is set, Vagrant will not perform any parallel operations (such as