diff --git a/lib/inspec/control_eval_context.rb b/lib/inspec/control_eval_context.rb index 51a0ecbbc..dc2b994fc 100644 --- a/lib/inspec/control_eval_context.rb +++ b/lib/inspec/control_eval_context.rb @@ -40,7 +40,8 @@ module Inspec if hook # OK, load the hook if it hasn't been already. We'll then know a module, # which we can then inject into the context - registry.activate(:control_dsl, method_name) unless hook.activated? + hook.activate + # Inject the module's methods into the context. # implementation_class is the field name, but this is actually a module. self.class.include(hook.implementation_class) diff --git a/lib/inspec/dsl.rb b/lib/inspec/dsl.rb index 6a07c6f9e..4c59054d0 100644 --- a/lib/inspec/dsl.rb +++ b/lib/inspec/dsl.rb @@ -38,7 +38,7 @@ module Inspec::DSL if hook # OK, load the hook if it hasn't been already. We'll then know a module, # which we can then inject into the context - registry.activate(:outer_profile_dsl, method_name) unless hook.activated? + hook.activate # Inject the module's methods into the context # implementation_class is the field name, but this is actually a module. self.class.include(hook.implementation_class) diff --git a/lib/inspec/plugin/v1/plugin_types/resource.rb b/lib/inspec/plugin/v1/plugin_types/resource.rb index f2520a96e..24002443e 100644 --- a/lib/inspec/plugin/v1/plugin_types/resource.rb +++ b/lib/inspec/plugin/v1/plugin_types/resource.rb @@ -52,7 +52,7 @@ module Inspec if hook # OK, load the hook if it hasn't been already. We'll then know a module, # which we can then inject into the resource - registry.activate(:resource_dsl, method_name) unless hook.activated? + hook.activate # Inject the module's methods into the resource as class methods. # implementation_class is the field name, but this is actually a module. extend(hook.implementation_class) diff --git a/lib/inspec/plugin/v2/activator.rb b/lib/inspec/plugin/v2/activator.rb index cdc380dc2..129fda716 100644 --- a/lib/inspec/plugin/v2/activator.rb +++ b/lib/inspec/plugin/v2/activator.rb @@ -3,7 +3,7 @@ module Inspec::Plugin::V2 :plugin_name, :plugin_type, :activator_name, - :'activated?', + :activated?, :exception, :activation_proc, :implementation_class, @@ -14,8 +14,29 @@ module Inspec::Plugin::V2 end def activated?(new_value = nil) - return self[:'activated?'] if new_value.nil? - self[:'activated?'] = new_value + return self[:activated?] if new_value.nil? + self[:activated?] = new_value + end + + # Load a plugin, but if an error is encountered, store it and continue + def activate + return if activated? + # rubocop: disable Lint/RescueException + begin + impl_class = self[:activation_proc].call + self[:activated?] = true + self[:implementation_class] = impl_class + rescue Exception => ex + self[:exception] = ex + Inspec::Log.error "Could not activate #{self[:plugin_type]} hook named '#{self[:activator_name]}' for plugin #{self[:plugin_name]}" + end + # rubocop: enable Lint/RescueException + end + + # Load a plugin, but if an error is encountered, re-throw it + def activate! + activate + raise exception if exception end end end diff --git a/lib/inspec/plugin/v2/loader.rb b/lib/inspec/plugin/v2/loader.rb index 334727c7b..4008e4ddf 100644 --- a/lib/inspec/plugin/v2/loader.rb +++ b/lib/inspec/plugin/v2/loader.rb @@ -102,7 +102,7 @@ module Inspec::Plugin::V2 # OK, activate. if activate_me - registry.activate(:cli_command, act.activator_name) + act.activate act.implementation_class.register_with_thor end end diff --git a/lib/inspec/plugin/v2/registry.rb b/lib/inspec/plugin/v2/registry.rb index f9fd30a60..a52097eba 100644 --- a/lib/inspec/plugin/v2/registry.rb +++ b/lib/inspec/plugin/v2/registry.rb @@ -67,19 +67,15 @@ module Inspec::Plugin::V2 end end - def activate(plugin_type, hook_name) - activator = find_activators(plugin_type: plugin_type, activator_name: hook_name).first - # We want to capture literally any possible exception here, since we are storing them. - # rubocop: disable Lint/RescueException - begin - impl_class = activator.activation_proc.call - activator.activated?(true) - activator.implementation_class = impl_class - rescue Exception => ex - activator.exception = ex - Inspec::Log.error "Could not activate #{activator.plugin_type} hook named '#{activator.activator_name}' for plugin #{plugin_name}" + # Convenience method for when you expect exactly one + def find_activator(filters = {}) + matched_plugins = find_activators(filters) + if matched_plugins.count > 1 + raise Inspec::Plugin::V2::LoadError, "Plugin hooks search returned multiple results for filter #{filters.inspect} - use more filters, or use find_activators (plural)" + elsif matched_plugins.empty? + raise Inspec::Plugin::V2::LoadError, "Plugin hooks search returned zero results for filter #{filters.inspect}" end - # rubocop: enable Lint/RescueException + matched_plugins.first end def register(name, status) diff --git a/lib/inspec/rspec_extensions.rb b/lib/inspec/rspec_extensions.rb index 2f66ebc56..7977280f9 100644 --- a/lib/inspec/rspec_extensions.rb +++ b/lib/inspec/rspec_extensions.rb @@ -17,7 +17,7 @@ module Inspec if hook # OK, load the hook if it hasn't been already. We'll then know a module, # which we can then inject into the context - registry.activate(:describe_dsl, method_name) unless hook.activated? + hook.activate # Inject the module's methods into the example group contexts. # implementation_class is the field name, but this is actually a module. @@ -46,7 +46,7 @@ module Inspec if hook # OK, load the hook if it hasn't been already. We'll then know a module, # which we can then inject into the context - registry.activate(:test_dsl, method_name) unless hook.activated? + hook.activate # Inject the module's methods into the example group contexts. # implementation_class is the field name, but this is actually a module. diff --git a/test/unit/plugin/v2/loader_test.rb b/test/unit/plugin/v2/loader_test.rb index 84a30757d..17ae1fece 100644 --- a/test/unit/plugin/v2/loader_test.rb +++ b/test/unit/plugin/v2/loader_test.rb @@ -187,7 +187,6 @@ class PluginLoaderTests < MiniTest::Test # Management methods for activation assert_respond_to status, :activators, 'A plugin status should respond to `activators`' assert_respond_to registry, :find_activators, 'Registry should respond to `find_activators`' - assert_respond_to registry, :activate, 'Registry should respond to `activate`' # Finding an Activator assert_kind_of Array, status.activators, 'status should have an array for activators' @@ -205,7 +204,7 @@ class PluginLoaderTests < MiniTest::Test assert_nil activator.implementation_class, 'Test activator should not know implementation class prior to activation' refute InspecPlugins::MeaningOfLife.const_defined?(:MockPlugin), 'impl_class should not be defined prior to activation' - registry.activate(:mock_plugin_type, :'meaning-of-life-the-universe-and-everything') + activator.activate # Activation postconditions assert activator.activated?, 'Test activator should be activated after activate'