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
|
||||
class VM
|
||||
include Vagrant::Util
|
||||
attr_reader :vm
|
||||
attr_accessor :vm
|
||||
attr_reader :actions
|
||||
|
||||
class << self
|
||||
# Bring up the virtual machine. Imports the base image and
|
||||
|
@ -21,6 +22,32 @@ module Vagrant
|
|||
|
||||
def initialize(vm=nil)
|
||||
@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
|
||||
|
||||
def create
|
||||
|
|
|
@ -11,6 +11,71 @@ class VMTest < Test::Unit::TestCase
|
|||
Net::SSH.stubs(:start)
|
||||
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
|
||||
should "create a Vagrant::VM instance and call create" do
|
||||
inst = mock("instance")
|
||||
|
|
Loading…
Reference in New Issue