The `Call` built-in middleware allows for conditional MW sequences.
Read the documentation for more information.
This commit is contained in:
parent
5eed3b8417
commit
90517a0f9b
|
@ -2,7 +2,6 @@ require 'vagrant/action/builder'
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module Action
|
module Action
|
||||||
autoload :Builtin, 'vagrant/action/builtin'
|
|
||||||
autoload :Environment, 'vagrant/action/environment'
|
autoload :Environment, 'vagrant/action/environment'
|
||||||
autoload :Runner, 'vagrant/action/runner'
|
autoload :Runner, 'vagrant/action/runner'
|
||||||
autoload :Warden, 'vagrant/action/warden'
|
autoload :Warden, 'vagrant/action/warden'
|
||||||
|
@ -13,6 +12,12 @@ module Vagrant
|
||||||
autoload :Verify, 'vagrant/action/box/verify'
|
autoload :Verify, 'vagrant/action/box/verify'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Builtin contains middleware classes that are shipped with Vagrant-core
|
||||||
|
# and are thus available to all plugins as a "standard library" of sorts.
|
||||||
|
module Builtin
|
||||||
|
autoload :Call, "vagrant/action/builtin/call"
|
||||||
|
end
|
||||||
|
|
||||||
module Env
|
module Env
|
||||||
autoload :Set, 'vagrant/action/env/set'
|
autoload :Set, 'vagrant/action/env/set'
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module Builtin
|
||||||
|
# This middleware class allows a sort of "conditional" run within
|
||||||
|
# a single middlware sequence. It takes another middleware runnable,
|
||||||
|
# runs it with the same environment, then yields the result to a block,
|
||||||
|
# allowing that block to determine the next course of action in the
|
||||||
|
# middleware sequence.
|
||||||
|
#
|
||||||
|
# The first argument to this middleware sequence is anywhere middleware
|
||||||
|
# runnable, whether it be a class, lambda, or something else that
|
||||||
|
# responds to `call`. This middleware runnable is run with the same
|
||||||
|
# environment as this class. The "result" of the run is expected to be
|
||||||
|
# placed in `env[:result]`.
|
||||||
|
#
|
||||||
|
# After running, {Call} takes `env[:result]` and yields it to a block
|
||||||
|
# given to initialize the class, along with an instance of {Builder}.
|
||||||
|
# The result is used to build up a new sequence on the given builder.
|
||||||
|
# This builder is then run.
|
||||||
|
class Call
|
||||||
|
# For documentation, read the description of the {Call} class.
|
||||||
|
#
|
||||||
|
# @param [Object] callable A valid middleware runnable object. This
|
||||||
|
# can be a class, a lambda, or an object that responds to `call`.
|
||||||
|
# @yield [result, builder] This block is expected to build on `builder`
|
||||||
|
# which is the next middleware sequence that will be run.
|
||||||
|
def initialize(app, env, callable, &block)
|
||||||
|
raise ArgumentError, "A block must be given to Call" if !block
|
||||||
|
|
||||||
|
@app = app
|
||||||
|
@callable = callable
|
||||||
|
@block = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
runner = Runner.new
|
||||||
|
|
||||||
|
# Run our callable with our environment
|
||||||
|
new_env = runner.run(@callable, env)
|
||||||
|
|
||||||
|
# Build our new builder based on the result
|
||||||
|
builder = Builder.new
|
||||||
|
@block.call(new_env[:result], builder)
|
||||||
|
|
||||||
|
# Run the result with our new environment
|
||||||
|
final_env = runner.run(builder, new_env)
|
||||||
|
|
||||||
|
# Call the next step using our final environment
|
||||||
|
@app.call(final_env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -45,6 +45,10 @@ module Vagrant
|
||||||
# We place a process lock around every action that is called
|
# We place a process lock around every action that is called
|
||||||
@logger.info("Running action: #{callable_id}")
|
@logger.info("Running action: #{callable_id}")
|
||||||
Util::Busy.busy(int_callback) { callable.call(environment) }
|
Util::Busy.busy(int_callback) { callable.call(environment) }
|
||||||
|
|
||||||
|
# Return the environment in case there are things in there that
|
||||||
|
# the caller wants to use.
|
||||||
|
environment
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,14 +5,26 @@ module VagrantPlugins
|
||||||
module Action
|
module Action
|
||||||
autoload :CheckAccessible, File.expand_path("../action/check_accessible", __FILE__)
|
autoload :CheckAccessible, File.expand_path("../action/check_accessible", __FILE__)
|
||||||
autoload :CheckVirtualbox, File.expand_path("../action/check_virtualbox", __FILE__)
|
autoload :CheckVirtualbox, File.expand_path("../action/check_virtualbox", __FILE__)
|
||||||
|
autoload :Created, File.expand_path("../action/created", __FILE__)
|
||||||
|
|
||||||
|
# Include the built-in modules so that we can use them as top-level
|
||||||
|
# things.
|
||||||
|
include Vagrant::Action::Builtin
|
||||||
|
|
||||||
# This is the action that is primarily responsible for completely
|
# This is the action that is primarily responsible for completely
|
||||||
# freeing the resources of the underlying virtual machine.
|
# freeing the resources of the underlying virtual machine.
|
||||||
def self.action_destroy
|
def self.action_destroy
|
||||||
Vagrant::Action::Builder.new.tap do |b|
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
b.use CheckVirtualbox
|
b.use CheckVirtualbox
|
||||||
b.use Vagrant::Action::General::Validate
|
b.use Call, Created do |result, b2|
|
||||||
b.use CheckAccessible
|
# `result` is a boolean true/false of whether the VM is created or
|
||||||
|
# not. So if the VM _is_ created, then we continue with the
|
||||||
|
# destruction.
|
||||||
|
if result
|
||||||
|
b2.use Vagrant::Action::General::Validate
|
||||||
|
b2.use CheckAccessible
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class Created
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
# Set the result to be true if the machine is created.
|
||||||
|
env[:result] = env[:machine].state != :not_created
|
||||||
|
|
||||||
|
# Call the next if we have one (but we shouldn't, since this
|
||||||
|
# middleware is built to run with the Call-type middlewares)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,66 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
describe Vagrant::Action::Builtin::Call do
|
||||||
|
let(:app) { lambda { |env| } }
|
||||||
|
let(:env) { {} }
|
||||||
|
|
||||||
|
it "should yield the result to the block" do
|
||||||
|
received = nil
|
||||||
|
|
||||||
|
callable = lambda do |env|
|
||||||
|
env[:result] = "value"
|
||||||
|
end
|
||||||
|
|
||||||
|
described_class.new(app, env, callable) do |result, builder|
|
||||||
|
received = result
|
||||||
|
end.call({})
|
||||||
|
|
||||||
|
received.should == "value"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should give a nil result if no result is given" do
|
||||||
|
received = 42
|
||||||
|
callable = lambda { |env| }
|
||||||
|
|
||||||
|
described_class.new(app, env, callable) do |result, builder|
|
||||||
|
received = result
|
||||||
|
end.call({})
|
||||||
|
|
||||||
|
received.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call the callable with the original environment" do
|
||||||
|
received = nil
|
||||||
|
callable = lambda { |env| received = env[:foo] }
|
||||||
|
|
||||||
|
described_class.new(app, env, callable) do |result, builder|
|
||||||
|
# Nothing.
|
||||||
|
end.call({ :foo => :bar })
|
||||||
|
|
||||||
|
received.should == :bar
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call the next builder" do
|
||||||
|
received = nil
|
||||||
|
callable = lambda { |env| }
|
||||||
|
next_step = lambda { |env| received = "value" }
|
||||||
|
|
||||||
|
described_class.new(app, env, callable) do |result, builder|
|
||||||
|
builder.use next_step
|
||||||
|
end.call({})
|
||||||
|
|
||||||
|
received.should == "value"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call the next builder with the original environment" do
|
||||||
|
received = nil
|
||||||
|
callable = lambda { |env| }
|
||||||
|
next_step = lambda { |env| received = env[:foo] }
|
||||||
|
|
||||||
|
described_class.new(app, env, callable) do |result, builder|
|
||||||
|
builder.use next_step
|
||||||
|
end.call({ :foo => :bar })
|
||||||
|
|
||||||
|
received.should == :bar
|
||||||
|
end
|
||||||
|
end
|
|
@ -25,6 +25,18 @@ describe Vagrant::Action::Runner do
|
||||||
expect { instance.run(callable) }.to raise_error(Exception, "BOOM")
|
expect { instance.run(callable) }.to raise_error(Exception, "BOOM")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should return the resulting environment" do
|
||||||
|
callable = lambda do |env|
|
||||||
|
env[:data] = "value"
|
||||||
|
|
||||||
|
# Return nil so we can make sure it isn't using this return value
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
result = instance.run(callable)
|
||||||
|
result[:data].should == "value"
|
||||||
|
end
|
||||||
|
|
||||||
it "should pass options into hash given to callable" do
|
it "should pass options into hash given to callable" do
|
||||||
result = nil
|
result = nil
|
||||||
callable = lambda do |env|
|
callable = lambda do |env|
|
||||||
|
|
Loading…
Reference in New Issue