diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb index be5774511..eaed02cea 100644 --- a/lib/vagrant/environment.rb +++ b/lib/vagrant/environment.rb @@ -100,6 +100,9 @@ module Vagrant # Load the plugins load_plugins + + # Activate the plugins + activate_plugins end #--------------------------------------------------------------- @@ -395,6 +398,10 @@ module Vagrant config_loader.set(:vm, subvm.proc_stack) end + # We activate plugins here because the files which we're loading + # configuration from may have defined new plugins as well. + activate_plugins + # Execute the configuration stack and store the result as the final # value in the config ivar. config_loader.load @@ -515,6 +522,14 @@ module Vagrant nil end + # This finds all the current plugins and activates them. This is an + # idempotent call so it is safe to call this as much as you need. + def activate_plugins + Vagrant.plugin("1").registered.each do |plugin| + plugin.activate! + end + end + # Loads the Vagrant plugins by properly setting up RubyGems so that # our private gem repository is on the path. def load_plugins diff --git a/lib/vagrant/plugin/v1.rb b/lib/vagrant/plugin/v1.rb index 30e9760df..1030d80da 100644 --- a/lib/vagrant/plugin/v1.rb +++ b/lib/vagrant/plugin/v1.rb @@ -72,6 +72,19 @@ module Vagrant hooks << block end + # The given block will be called when this plugin is activated. The + # activation block should be used to load any of the classes used by + # the plugin other than the plugin definition itself. Vagrant only + # guarantees that the plugin definition will remain backwards + # compatible, but not any other classes (such as command base classes + # or so on). Therefore, to avoid crashing future versions of Vagrant, + # these classes should be placed in separate files and loaded in the + # activation block. + def self.activated(&block) + data[:activation_block] = block if block_given? + data[:activation_block] + end + # Defines additional command line commands available by key. The key # becomes the subcommand, so if you register a command "foo" then # "vagrant foo" becomes available. @@ -185,6 +198,18 @@ module Vagrant data[:provisioners] end + # Activates the current plugin. This shouldn't be called publicly. + def self.activate! + if !data[:activated_called] + LOGGER.info("Activating plugin: #{self.name}") + data[:activated_called] = true + + # Call the activation block + block = activated + block.call if block + end + end + # Registers the plugin. This makes the plugin actually work with # Vagrant. Prior to registering, the plugin is merely a skeleton. # diff --git a/test/unit/vagrant/plugin/v1_test.rb b/test/unit/vagrant/plugin/v1_test.rb index c187b3ab5..e54757064 100644 --- a/test/unit/vagrant/plugin/v1_test.rb +++ b/test/unit/vagrant/plugin/v1_test.rb @@ -35,6 +35,34 @@ describe Vagrant::Plugin::V1 do end end + describe "activation block" do + it "should have no activation block by default" do + plugin = Class.new(described_class) + plugin.activated.should be_nil + end + + it "should be able to set and get the activation block" do + plugin = Class.new(described_class) do + activated do + 42 + end + end + + plugin.activated.call.should == 42 + end + + it "should activate when `activate!` is called" do + plugin = Class.new(described_class) do + activated do + raise NotImplementedError + end + end + + expect { plugin.activate! }.to raise_error(NotImplementedError) + expect { plugin.activate! }.to_not raise_error + end + end + describe "commands" do it "should register command classes" do plugin = Class.new(described_class) do