Initial attempt at refactoring commands out into evented actions. Heavy documentation on the "vagrant/actions/base.rb" class. New VM action runner functionality is well tested, as well.
This commit is contained in:
parent
a4b9375abf
commit
af1fcd0ae0
|
@ -0,0 +1,50 @@
|
||||||
|
module Vagrant
|
||||||
|
module Actions
|
||||||
|
# Base class for any command actions. A command action handles
|
||||||
|
# executing a step or steps on a given Vagrant::VM object. The
|
||||||
|
# action should define any callbacks that it will call, or
|
||||||
|
# attach itself to some callbacks on the VM object.
|
||||||
|
class Base
|
||||||
|
attr_reader :vm
|
||||||
|
|
||||||
|
include Vagrant::Util
|
||||||
|
|
||||||
|
# Initialization of the actions are done all at once. The guarantee
|
||||||
|
# is that when an action is initialized, no other action has had
|
||||||
|
# its `prepare` or `execute!` method called yet, so an action can
|
||||||
|
# setup anything it needs to with this safety. An example of this
|
||||||
|
# would be instance_evaling the vm instance to include a module so
|
||||||
|
# additionally functionality could be defined on the vm which other
|
||||||
|
# action `prepare` methods may rely on.
|
||||||
|
def initialize(vm)
|
||||||
|
@vm = vm
|
||||||
|
end
|
||||||
|
|
||||||
|
# This method is called once per action, allowing the action
|
||||||
|
# to setup any callbacks, add more events, etc. Prepare is
|
||||||
|
# called in the order the actions are defined, and the action
|
||||||
|
# itself has no control over this, so no race conditions between
|
||||||
|
# action setups should be done here.
|
||||||
|
def prepare
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# Perhaps we need an additional action to go, specifically
|
||||||
|
# maybe only if a configuration is set
|
||||||
|
#
|
||||||
|
#@vm.actions << FooAction if Vagrant.config[:foo] == :bar
|
||||||
|
end
|
||||||
|
|
||||||
|
# This method is called once, after preparing, to execute the
|
||||||
|
# actual task. This method is responsible for calling any
|
||||||
|
# callbacks. Adding new actions here will have NO EFFECT, and
|
||||||
|
# adding callbacks has unpredictable effects.
|
||||||
|
def execute!
|
||||||
|
# Example code:
|
||||||
|
#
|
||||||
|
# @vm.invoke_callback(:before_oven, "cookies")
|
||||||
|
# Do lots of stuff here
|
||||||
|
# @vm.invoke_callback(:after_oven, "more", "than", "one", "option")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,8 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
class VM
|
class VM
|
||||||
include Vagrant::Util
|
include Vagrant::Util
|
||||||
attr_reader :vm
|
attr_accessor :vm
|
||||||
|
attr_reader :actions
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
# Bring up the virtual machine. Imports the base image and
|
# Bring up the virtual machine. Imports the base image and
|
||||||
|
@ -21,6 +22,32 @@ module Vagrant
|
||||||
|
|
||||||
def initialize(vm=nil)
|
def initialize(vm=nil)
|
||||||
@vm = vm
|
@vm = vm
|
||||||
|
@actions = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute!
|
||||||
|
# Initialize each action. Prepare is not done together with
|
||||||
|
# this since initialization is a time which guarantees that
|
||||||
|
# prepare has not been called for any other action yet.
|
||||||
|
@actions.collect! do |action_class|
|
||||||
|
action_class.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Call the prepare method on each once its
|
||||||
|
# initialized, then call the execute! method
|
||||||
|
[:prepare, :execute!].each do |method|
|
||||||
|
@actions.each do |action|
|
||||||
|
action.send(method)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def invoke_callback(name, *args)
|
||||||
|
# Attempt to call the method for the callback on each of the
|
||||||
|
# actions
|
||||||
|
@actions.each do |action|
|
||||||
|
action.send(name, *args) if action.respond_to?(name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
|
@ -11,6 +11,71 @@ class VMTest < Test::Unit::TestCase
|
||||||
Net::SSH.stubs(:start)
|
Net::SSH.stubs(:start)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "callbacks" do
|
||||||
|
setup do
|
||||||
|
@vm = Vagrant::VM.new(@mock_vm)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not invoke callback on actions which don't respond to it" do
|
||||||
|
action = mock("action")
|
||||||
|
action.stubs(:respond_to?).with(:foo).returns(false)
|
||||||
|
action.expects(:foo).never
|
||||||
|
|
||||||
|
assert_nothing_raised do
|
||||||
|
@vm.actions << action
|
||||||
|
@vm.invoke_callback(:foo)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "invoke callback on actions which do respond to the method" do
|
||||||
|
action = mock("action")
|
||||||
|
action.expects(:foo).once
|
||||||
|
|
||||||
|
@vm.actions << action
|
||||||
|
@vm.invoke_callback(:foo)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "actions" do
|
||||||
|
setup do
|
||||||
|
@vm = Vagrant::VM.new(@mock_vm)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be empty initially" do
|
||||||
|
assert @vm.actions.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to add actions" do
|
||||||
|
assert_nothing_raised do
|
||||||
|
@vm.actions << "Foo"
|
||||||
|
@vm.actions << "Bar"
|
||||||
|
assert_equal 2, @vm.actions.length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "run #prepare on all actions, then #execute!" do
|
||||||
|
action_seq = sequence("action_seq")
|
||||||
|
actions = []
|
||||||
|
5.times do |i|
|
||||||
|
action = mock("action#{i}")
|
||||||
|
action_class = mock("action_class#{i}")
|
||||||
|
|
||||||
|
action_class.expects(:new).once.returns(action).in_sequence(action_seq)
|
||||||
|
|
||||||
|
@vm.actions << action_class
|
||||||
|
actions << action
|
||||||
|
end
|
||||||
|
|
||||||
|
[:prepare, :execute!].each do |method|
|
||||||
|
actions.each do |action|
|
||||||
|
action.expects(method).once.in_sequence(action_seq)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@vm.execute!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "vagrant up" do
|
context "vagrant up" do
|
||||||
should "create a Vagrant::VM instance and call create" do
|
should "create a Vagrant::VM instance and call create" do
|
||||||
inst = mock("instance")
|
inst = mock("instance")
|
||||||
|
|
Loading…
Reference in New Issue