Commit 03a0c7e4 authored by Laurent Briais's avatar Laurent Briais

New release with plugin dependencies managed.

Whatever the plugin type (gem or local) !
parent 9e6e0508
......@@ -7,5 +7,6 @@
/spec/reports/
/tmp/
/.idea/
Gemfile.lock
# rspec failure tracking
.rspec_status
......@@ -2,7 +2,7 @@
<%= plugin_title_name %>
<%= '=' * plugin_title_name.size %>
[![Gem Version](https://badge.fury.io/rb/<%= gem_name %>.svg)](https://rubygems.org/gems/<%= gem_name %>) [![Pipeline status](https://gitlab.com/tools4devops/psplugins/<%= gem_name %>/badges/master/pipeline.svg)](https://gitlab.com/tools4devops/psplugins/<%= gem_name %>/commits/master)
[![Gem Version](https://badge.fury.io/rb/<%= gem_name %>.svg)](https://rubygems.org/gems/<%= gem_name %>) [![Pipeline status](https://gitlab.com/tools4devops/psplugins/<%= plugin_name %>/badges/master/pipeline.svg)](https://gitlab.com/tools4devops/psplugins/<%= gem_name %>/commits/master)
[PowerStencil] is the Swiss-army knife templating workflow for developers and ops.
......
......@@ -32,3 +32,6 @@
:templates:
- etc/templates
# Plugin dependencies to other plugins. Use the plugin name and NOT the plugin
# gem name (in the case of a gem plugin). Declare as well dependencies to local plugins.
:dependencies: []
\ No newline at end of file
......@@ -7,5 +7,6 @@
/spec/reports/
/tmp/
/.idea/
Gemfile.lock
# rspec failure tracking
.rspec_status
......@@ -2,7 +2,7 @@
<%= plugin_title_name %>
<%= '=' * plugin_title_name.size %>
[![Gem Version](https://badge.fury.io/rb/<%= gem_name %>.svg)](https://rubygems.org/gems/<%= gem_name %>) [![Pipeline status](https://gitlab.com/tools4devops/psplugins/<%= gem_name %>/badges/master/pipeline.svg)](https://gitlab.com/tools4devops/psplugins/<%= gem_name %>/commits/master)
[![Gem Version](https://badge.fury.io/rb/<%= gem_name %>.svg)](https://rubygems.org/gems/<%= gem_name %>) [![Pipeline status](https://gitlab.com/tools4devops/psplugins/<%= plugin_name %>/badges/master/pipeline.svg)](https://gitlab.com/tools4devops/psplugins/<%= gem_name %>/commits/master)
[PowerStencil] is the Swiss-army knife templating workflow for developers and ops.
......
......@@ -32,3 +32,6 @@
:templates:
- etc/templates
# Plugin dependencies to other plugins. Use the plugin name and NOT the plugin
# gem name (in the case of a gem plugin). Declare as well dependencies to local plugins.
:dependencies: []
......@@ -7,6 +7,7 @@
# Project plugins gems
# List of plugins, provided as real Ruby gems (outside of this project), that you want to use in this project.
# Here declare the gem name, not the plugin name.
# :project_plugins: []
# Graphviz configuration
......
......@@ -50,7 +50,7 @@ module PowerStencil
private
def load_plugins_entities_definition
project.plugins.each do |_, plugin|
project.plugins_sorted_by_dependency.each do |plugin|
plugin.require_plugin_entity_definitions
end
end
......
......@@ -70,7 +70,6 @@ module PowerStencil
load_capabilities
load_plugin_specific_config
load_yaml_command_definition
require_entry_point
end
end
......
......@@ -13,6 +13,10 @@ module PowerStencil
@capabilities ||= CAPABILITIES.dup.zip([false] * CAPABILITIES.size).to_h
end
def dependencies
plugin_definition[:dependencies]
end
private
def load_capabilities
......
......@@ -7,12 +7,6 @@ module PowerStencil
include PowerStencil::Utils::SecureRequire
private
def module_short_name
name.split(/[-_]+/).map(&:capitalize).join.to_sym
end
def require_entry_point
@entry_point_path = File.join plugin_path, 'lib', "#{name.underscore}.rb"
logger.debug "Plugin '#{name}' entry point: '#{entry_point_path}'"
......@@ -27,6 +21,12 @@ module PowerStencil
end
end
private
def module_short_name
name.split(/[-_]+/).map(&:capitalize).join.to_sym
end
def setup_version
@version = PowerStencil::Utils::SemanticVersion.new plugin_module::VERSION
capabilities[:version] = true
......
require 'power_stencil/utils/dependency_solver'
require 'power_stencil/project/paths'
require 'power_stencil/project/create'
require 'power_stencil/project/config'
......
......@@ -18,13 +18,37 @@ module PowerStencil
end
def plugins_sorted_by_dependency
solver = PowerStencil::Utils::DependencySolver.new
plugin_names = plugins.keys
plugins.each do |_, plugin|
unless plugin.dependencies.nil?
plugin.dependencies.each do |dependency_name|
raise PowerStencil::Error, "Invalid dependency '#{dependency_name}'declared for plugin '#{plugin.name}' !" unless plugin_names.include? dependency_name
end
end
solver[plugin.name] = plugin.dependencies.nil? ? [] : plugin.dependencies
end
solver.tsort.map { |plugin_name| plugins[plugin_name] }
rescue TSort::Cyclic => e
PowerStencil::Error.report_error e
raise PowerStencil::Error, 'Plugins cyclical dependency error !'
end
private
def bootstrap_plugins
@plugins = {}
initialize_gem_plugins
initialize_local_plugins
require_plugins_entry_points
command_line_manager.definition_hash_to_commands
register_plugins_processors
end
def register_plugins_processors
plugins.each do |_, plugin|
if plugin.capabilities[:processors]
plugin.register_processors
......@@ -32,6 +56,12 @@ module PowerStencil
end
end
def require_plugins_entry_points
plugins_sorted_by_dependency.each do |plugin|
plugin.require_entry_point
end
end
def initialize_gem_plugins
if config[:project_plugins].empty?
PowerStencil.logger.info 'No gem plugin found in project'
......@@ -42,7 +72,8 @@ module PowerStencil
(gem_name, gem_req) = PowerStencil::Plugins::Base.plugin_definition_to_name_and_req plugin_definition
raise PowerStencil::Error, "Plugin '#{gem_name}' already exists !" unless plugins[gem_name].nil?
plugins[gem_name] = PowerStencil::Plugins::Base.new(gem_name, self, type: :gem, gem_req: gem_req)
plugin = PowerStencil::Plugins::Base.new(gem_name, self, type: :gem, gem_req: gem_req)
plugins[plugin.name] = plugin
end
end
......@@ -55,10 +86,12 @@ module PowerStencil
Dir.entries(project_local_plugins_path)
.select { |e| File.directory? File.join(project_local_plugins_path, e) }
.reject { |d| %w(. ..).include? d }
.sort
.each do |candidate|
begin
raise PowerStencil::Error, "Plugin '#{candidate}' already exists !" unless plugins[candidate].nil?
plugins[candidate] = PowerStencil::Plugins::Base.new(candidate, self)
plugin = PowerStencil::Plugins::Base.new(candidate, self)
plugins[plugin.name] = plugin
rescue PowerStencil::Error => pse
logger.puts_and_logs pse.message, logs_as: :error
logger.puts_and_logs "Discarding invalid plugin '#{candidate}'.", logs_as: :error
......
require 'tsort'
module PowerStencil
module Utils
class DependencySolver < Hash
include TSort
alias tsort_each_node each_key
def tsort_each_child(node, &block)
fetch(node).each(&block)
end
end
end
end
module PowerStencil
VERSION = '0.9.2'.freeze
VERSION = '0.9.3'.freeze
end
require 'spec_helper'
RSpec.describe PowerStencil::Utils::DependencySolver do
let(:dependencies) do
{
'plugin1' => %w(plugin2 plugin3),
'plugin2' => %w(plugin3),
'plugin3' => [],
'plugin4' => []
}
end
let(:dependencies_solved) { %w(plugin3 plugin2 plugin1 plugin4) }
subject { described_class.new.merge dependencies }
it 'should be possible to get the list of dependencies in the right order' do
expect(subject.tsort).to eq dependencies_solved
end
context 'when dependencies are circular' do
let(:dependencies) { { 1 => [2], 2 => [3], 3 => [1] } }
it 'should fail with a cyclic exception' do
expect { subject.tsort }.to raise_error TSort::Cyclic
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment