Track application of action name hooks / triggers

When expanding stack track the origin action name and only apply
it once the stack has completed its expansion. The local env data
is marked with origin action to prevent it from being applied in
nested builders as they are expanded. The value of the stored action
name is checked and invalidated if another action is applied to the
same env in the future so hooks / triggers for that action are
applied as expected.
This commit is contained in:
Chris Roberts 2020-11-02 10:31:51 -08:00
parent cba5bca7de
commit db24f26daa
2 changed files with 16 additions and 33 deletions

View File

@ -173,16 +173,23 @@ module Vagrant
# be modified
builder = self.dup
if env[:builder_applied] != env[:action_name]
apply_action_name = true
env[:builder_applied] = env[:action_name]
end
# Apply all dynamic modifications of the stack. This
# will generate dynamic hooks for all actions within
# the stack, load any triggers for action classes, and
# apply them to the builder's stack
builder.apply_dynamic_updates(env)
# Now that the stack is fully expanded, apply any
# action hooks that may be defined so they are on
# the outermost locations of the stack
builder.apply_action_name(env)
if apply_action_name
# Now that the stack is fully expanded, apply any
# action hooks that may be defined so they are on
# the outermost locations of the stack
builder.apply_action_name(env)
end
# Wrap the middleware stack with the Warden to provide a consistent
# and predictable behavior upon exceptions.
@ -259,6 +266,7 @@ module Vagrant
# @return [Builder]
def apply_action_name(env)
return self if !env[:action_name]
hook = Hook.new
machine_name = env[:machine].name if env[:machine]
@ -306,21 +314,8 @@ module Vagrant
# we can just send ourself back
return self if hook.empty?
# These are the options to pass into hook application.
options = {}
# If we already ran through once and did append/prepends,
# then don't do it again.
if env[:action_hooks_already_ran]
options[:no_prepend_or_append] = true
end
# Specify that we already ran, so in the future we don't repeat
# the prepend/append hooks.
env[:action_hooks_already_ran] = true
# Apply all the hooks to the new builder instance
hook.apply(self, options)
hook.apply(self)
self
end

View File

@ -255,10 +255,10 @@ describe Vagrant::Action::Builder do
subject.call(data)
expect(data[:data]).to eq([1, 2])
expect(data[:action_hooks_already_ran]).to eq(true)
expect(data[:builder_applied]).to eq(:test_action)
end
it "applies without prepend/append if it has already" do
it "applies without adding action hooks/triggers if it has already" do
hook_proc = proc{ |h| h.append(appender_proc(2)) }
expect(manager).to receive(:action_hooks).with(:test_action).
and_return([hook_proc])
@ -266,7 +266,7 @@ describe Vagrant::Action::Builder do
data[:action_name] = :test_action
subject.use appender_proc(1)
subject.call(data.merge(action_hooks_already_ran: true))
subject.call(data.merge(builder_applied: :test_action))
expect(data[:data]).to eq([1])
subject.call(data)
@ -637,11 +637,6 @@ describe Vagrant::Action::Builder do
before { allow(triggers).to receive(:find).and_return([]) }
after { @subject = nil }
it "should mark action hooks applied within env" do
subject.apply_action_name(env)
expect(env[:action_hooks_already_ran]).to be_truthy
end
context "when a plugin has added an action hook" do
let(:plugin) do
@plugin ||= Class.new(Vagrant.plugin("2")) do
@ -663,13 +658,6 @@ describe Vagrant::Action::Builder do
subject.apply_action_name(env)
expect(subject.stack[0].first).to eq(Vagrant::Action::Builtin::Call)
end
it "should only add new action to the call stack once" do
subject.apply_action_name(env)
subject.apply_action_name(env)
expect(subject.stack[0].first).to eq(Vagrant::Action::Builtin::Call)
expect(subject.stack[1].first).not_to eq(Vagrant::Action::Builtin::Call)
end
end
context "when trigger has been defined for raw action" do