power_stencil 0.8.13 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -15
  3. data/doc/faq.md +4 -7
  4. data/doc/git_integration.md +38 -12
  5. data/etc/meta_templates/plugin_seed/.gitignore +12 -0
  6. data/etc/meta_templates/plugin_seed/.gitlab-ci.yml +11 -0
  7. data/etc/meta_templates/plugin_seed/README.md +20 -5
  8. data/etc/meta_templates/plugin_seed/etc/plugin_capabilities.yaml +3 -0
  9. data/etc/meta_templates/plugin_seed/psplugin_{entity}.gemspec +2 -0
  10. data/etc/meta_templates/plugin_seed/spec/project_helper.rb +50 -0
  11. data/etc/meta_templates/plugin_seed/spec/spec_helper.rb +2 -1
  12. data/etc/meta_templates/plugin_seed/spec/{entity}_spec.rb +21 -1
  13. data/etc/power_stencil.yaml +6 -1
  14. data/etc/templates/plugin_definition/.gitignore +2 -1
  15. data/etc/templates/plugin_definition/.gitlab-ci.yml +11 -0
  16. data/etc/templates/plugin_definition/README.md +20 -5
  17. data/etc/templates/plugin_definition/etc/plugin_capabilities.yaml +3 -0
  18. data/etc/templates/plugin_definition/psplugin_{entity}.gemspec +2 -0
  19. data/etc/templates/plugin_definition/spec/project_helper.rb +50 -0
  20. data/etc/templates/plugin_definition/spec/spec_helper.rb +2 -1
  21. data/etc/templates/plugin_definition/spec/{entity}_spec.rb +21 -1
  22. data/etc/templates/project/.ps_project/versioned-config.yaml +1 -0
  23. data/etc/templates/zsh_command_line_completion/_power_stencil.sh.erb +18 -8
  24. data/lib/power_stencil.rb +4 -0
  25. data/lib/power_stencil/command_processors/adm.rb +29 -1
  26. data/lib/power_stencil/command_processors/create.rb +14 -4
  27. data/lib/power_stencil/dsl/completion.rb +37 -0
  28. data/lib/power_stencil/engine/base.rb +2 -0
  29. data/lib/power_stencil/engine/directory_processor.rb +20 -1
  30. data/lib/power_stencil/engine/project_engine.rb +1 -1
  31. data/lib/power_stencil/engine/renderers/haml.rb +21 -0
  32. data/lib/power_stencil/initializer.rb +6 -1
  33. data/lib/power_stencil/plugins/base.rb +0 -1
  34. data/lib/power_stencil/plugins/capabilities.rb +4 -0
  35. data/lib/power_stencil/plugins/command_line.rb +3 -1
  36. data/lib/power_stencil/plugins/require.rb +6 -6
  37. data/lib/power_stencil/project/base.rb +2 -0
  38. data/lib/power_stencil/project/plugins.rb +35 -2
  39. data/lib/power_stencil/ultra_command_line/command_line_manager.rb +35 -0
  40. data/lib/power_stencil/ultra_command_line/option_definition.rb +5 -0
  41. data/lib/power_stencil/ultra_command_line/providers_manager.rb +21 -0
  42. data/lib/power_stencil/ultra_command_line/sub_command.rb +12 -0
  43. data/lib/power_stencil/utils/completion.rb +19 -9
  44. data/lib/power_stencil/utils/dependency_solver.rb +19 -0
  45. data/lib/power_stencil/version.rb +1 -1
  46. data/power_stencil.gemspec +2 -1
  47. metadata +35 -11
@@ -32,3 +32,6 @@
32
32
  :templates:
33
33
  - etc/templates
34
34
 
35
+ # Plugin dependencies to other plugins. Use the plugin name and NOT the plugin
36
+ # gem name (in the case of a gem plugin). Declare as well dependencies to local plugins.
37
+ :dependencies: []
@@ -11,6 +11,8 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = %q{<%= plugin_name %> is a plugin for the PowerStencil framework.}
13
13
  spec.description = %q{TODO: Write a longer description or delete this line.}
14
+ # For official plugins
15
+ # spec.homepage = "https://powerstencil.brizone.org/#plugins"
14
16
  spec.homepage = "TODO: Put your gem's website or public repo URL here."
15
17
  spec.license = 'MIT'
16
18
 
@@ -0,0 +1,50 @@
1
+ module PowerStencilTests
2
+
3
+ module Project
4
+
5
+ TEMP_DIR_PREFIX = 'PS_TESTS_'
6
+
7
+ module ClassMethods
8
+
9
+
10
+ def temporary_project(project_name, with_git_support: false, scope: :all)
11
+ self.instance_eval do
12
+ puts scope
13
+ around(scope) do |execution|
14
+ Dir.mktmpdir(TEMP_DIR_PREFIX) do |tests_root_dir|
15
+ tmp_project_path = File.join tests_root_dir, project_name
16
+ create_project_including_this_plugin tmp_project_path, with_git_support: with_git_support
17
+ execution.run
18
+ @tmp_project_path = nil
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def plugin_path
25
+ File.expand_path File.join('..', '..'), __FILE__
26
+ end
27
+
28
+ end
29
+
30
+ attr_reader :tmp_project_path
31
+
32
+ def self.included(base)
33
+ base.extend(ClassMethods)
34
+ end
35
+
36
+ def create_project_including_this_plugin(project_path, with_git_support: false)
37
+ cmd = "power_stencil init --project-path '#{project_path}'"
38
+ cmd << ' --no-git' unless with_git_support
39
+ `#{cmd}`
40
+ project_plugin_path = File.join project_path, '.ps_project', 'plugins'
41
+ `ln -s '#{self.class.plugin_path}' '#{project_plugin_path}'`
42
+ @tmp_project_path = project_path
43
+ end
44
+
45
+ def temporary_project_cmd(params)
46
+ "power_stencil #{params} --project-path '#{tmp_project_path}'"
47
+ end
48
+
49
+ end
50
+ end
@@ -1,6 +1,7 @@
1
- require "bundler/setup"
1
+ require 'bundler/setup'
2
2
  require 'power_stencil'
3
3
  require "<%= plugin_name %>"
4
+ require 'project_helper'
4
5
 
5
6
  RSpec.configure do |config|
6
7
  # Enable flags like --only-failures and --next-failure
@@ -1,10 +1,30 @@
1
1
  RSpec.describe <%= plugin_module_name %> do
2
+
3
+ include PowerStencilTests::Project
4
+ temporary_project 'test_project', scope: :all
5
+
6
+ let(:plugin_list) { 'plugin --list' }
7
+ let(:test_entity) { '<%= plugin_name %>_entity/test_<%= plugin_name %>' }
8
+ let(:create_<%= plugin_name %>) { "create #{test_entity}" }
9
+ let(:get_<%= plugin_name %>) { "get #{test_entity}" }
10
+
2
11
  it 'has a version number' do
3
12
  expect(<%= plugin_module_name %>::VERSION).not_to be nil
4
13
  end
5
14
 
6
- it 'does something useful' do
15
+ it 'should add a "<%= plugin_name %>" sub-command' do
16
+ expect(`#{temporary_project_cmd plugin_list}`).to match '- <%= plugin_name %>'
17
+ end
18
+
19
+ it 'should be possible to create a "<%= plugin_name %>_entity"' do
20
+ `#{temporary_project_cmd create_<%= plugin_name %>}`
21
+ expect($?.success?).to be_truthy
22
+ expect(`#{temporary_project_cmd get_<%= plugin_name %>}`).not_to be_empty
23
+ end
24
+
25
+ it 'should do something useful' do
7
26
  pending 'Tests implementation'
8
27
  RSpec.fail
9
28
  end
29
+
10
30
  end
@@ -7,6 +7,7 @@
7
7
 
8
8
  # Project plugins gems
9
9
  # List of plugins, provided as real Ruby gems (outside of this project), that you want to use in this project.
10
+ # Here declare the gem name, not the plugin name.
10
11
  # :project_plugins: []
11
12
 
12
13
  # Graphviz configuration
@@ -2,10 +2,10 @@
2
2
 
3
3
  # zsh shell completion script for <%= script_name %>
4
4
  # To regenerate this file: '<%= script_name %> adm --zsh-completion'
5
- # Generated on the <%= Time.now %> by <%= script_name %> v<%= PowerStencil::VERSION %>
5
+ # Generated<%= timestamp %> by <%= script_name %> v<%= PowerStencil::VERSION %>
6
6
 
7
- <% commands = PowerStencil.command_line_manager.commands -%>
8
- _<%= script_name %>() {
7
+ <% commands = context_commands -%>
8
+ _<%= script_name %>_first_level() {
9
9
  local cmd
10
10
  local <%= script_name %>_sub_commands
11
11
  <%= script_name %>_sub_commands=(<%= commands.reject { |c| c.name.empty? }.sort { |a,b| a.name <=> b.name }.map(&:name).join ' ' %>)
@@ -21,7 +21,7 @@ _<%= script_name %>() {
21
21
  (( $+functions[_<%= script_name %>_cmd_$cmd] )) && _<%= script_name %>_cmd_$cmd
22
22
  else
23
23
  _values : \
24
- <%= continued_multilines(root_command(commands).options.sort { |a,b| a.name <=> b.name }.map {|o| option_representation o}, number_spaces: 10) %>
24
+ <%= continued_multilines(context_options(root_command commands).sort { |a,b| a.name <=> b.name }.map {|o| option_representation o}, number_spaces: 10) %>
25
25
  fi
26
26
  else
27
27
  _values : \
@@ -33,7 +33,7 @@ _<%= script_name %>() {
33
33
  <% end -%>
34
34
  <%= command_representation command %> \
35
35
  <% end -%>
36
- <%= continued_multilines(root_command.options.sort { |a,b| a.name <=> b.name }.map {|o| option_representation o}, number_spaces: 8) %>
36
+ <%= continued_multilines(context_options(root_command).sort { |a,b| a.name <=> b.name }.map {|o| option_representation o}, number_spaces: 8) %>
37
37
  fi
38
38
  }
39
39
 
@@ -46,7 +46,7 @@ _<%= script_name %>_cmd_<%= command.name %>() {
46
46
  _arguments -s : \
47
47
  <%
48
48
  command_param = default_command_param_type command
49
- options_lines = command.options.sort { |a,b| a.name <=> b.name }.map {|o| option_representation o}
49
+ options_lines = context_options(command).sort { |a,b| a.name <=> b.name }.map {|o| option_representation o}
50
50
  options_lines << command_param unless command_param.empty?
51
51
  -%>
52
52
  <%= continued_multilines(options_lines) %>
@@ -124,5 +124,15 @@ _power_stencil_do_nothing() {
124
124
  return 1
125
125
  }
126
126
 
127
- # Let's rock
128
- _<%= script_name %> "$@"
127
+
128
+ _<%= script_name %>() {
129
+ if $( _within_power_stencil_project ); then
130
+ local project_root=$( _power_stencil_project_root )
131
+ if [ -f "${project_root}/.ps_project/<%= PowerStencil.config[:completion_target][:zsh][:project_completion_filename] %>" ]; then
132
+ . "${project_root}/.ps_project/<%= PowerStencil.config[:completion_target][:zsh][:project_completion_filename] %>"
133
+ fi
134
+ else
135
+ . "<%= File.expand_path(File.join PowerStencil.config[:completion_target][:zsh][:completion_dir], "_#{script_name}") %>"
136
+ fi
137
+ _<%= script_name %>_first_level "$@"
138
+ }
@@ -5,6 +5,10 @@ require 'dir_glob_ignore'
5
5
 
6
6
  $DO_NOT_AUTOSTART_CLIMATIC=true
7
7
  require 'climatic'
8
+ require 'power_stencil/ultra_command_line/command_line_manager'
9
+ require 'power_stencil/ultra_command_line/providers_manager'
10
+ require 'power_stencil/ultra_command_line/option_definition'
11
+ require 'power_stencil/ultra_command_line/sub_command'
8
12
 
9
13
  require 'power_stencil/error'
10
14
  require 'power_stencil/utils/os'
@@ -12,7 +12,35 @@ module PowerStencil
12
12
  def execute
13
13
 
14
14
  if config[:'zsh-completion']
15
- generate_zsh_completion 'power_stencil'
15
+ target_dir = File.expand_path config[:completion_target][:zsh][:completion_dir]
16
+ script_name = 'power_stencil'
17
+ user_completion_script = File.join target_dir, "_#{script_name}"
18
+ begin
19
+ current_dir = Dir.pwd
20
+ Dir.mktmpdir 'completion_generation' do |tmpdir|
21
+ Dir.chdir tmpdir
22
+ generate_zsh_completion script_name, user_completion_script, false
23
+ end
24
+ ensure
25
+ Dir.chdir current_dir
26
+ end
27
+
28
+ begin
29
+ project
30
+ shortname_project_completion_script = File.join config[:default_config_directory_name], config[:completion_target][:zsh][:project_completion_filename]
31
+ project.track_action_with_git("Adding project specific zsh completion file: '#{ shortname_project_completion_script }'.") do
32
+ project_completion_script = File.join project.project_config_root, config[:completion_target][:zsh][:project_completion_filename]
33
+ generate_zsh_completion script_name, project_completion_script, true
34
+ puts_and_logs "A specific completion has been generated for this project in '#{project_completion_script}'.", check_verbose: false
35
+ end
36
+ rescue
37
+ # Do not check errors. This is just to load project config...
38
+ logger.debug "Outside of a PowerStencil project... Not generating zsh project completion."
39
+ end
40
+ puts_and_logs "zsh global auto_completion has been installed in '#{user_completion_script}'.", check_verbose: false
41
+ puts
42
+ puts "You should ensure you have something like 'fpath=(#{target_dir} $fpath)' in your ~/.zshrc file..."
43
+ puts 'You may have to relog for changes to be applied.'
16
44
  return
17
45
  end
18
46
 
@@ -17,8 +17,17 @@ module PowerStencil
17
17
  unless config[:property].nil?
18
18
  config[:property].each do |property_def|
19
19
  if md = property_def.match(/^\s*(?<prop_name>[^:=]+)\s*[:=]\s*(?<prop_val>.*)\s*$/)
20
- logger.debug "Using extra properties from command line '#{md['prop_name']}' = '#{md['prop_val']}'"
21
- entity_as_hash[md['prop_name'].to_sym] = md['prop_val']
20
+ property_value = md['prop_val']
21
+ logger.debug "Using extra properties from command line '#{md['prop_name']}' = '#{property_value}'"
22
+ if pmd = property_value.match(/^\s*!entity\s+(?<entity_type>[^\/]+)\/(?<entity_name>.*)\s*$/)
23
+ type = pmd['entity_type'].to_sym
24
+ name = pmd['entity_name']
25
+ referenced_entity = project.engine.entity(type, name)
26
+ property_value = referenced_entity.to_reference unless referenced_entity.nil?
27
+ puts_and_logs "Could not find entity '#{type.to_s}/#{name}' !", logs_as: :error, check_verbose: false if referenced_entity.nil?
28
+ end
29
+
30
+ entity_as_hash[md['prop_name'].to_sym] = property_value
22
31
  else
23
32
  raise PowerStencil::Error, "Invalid command line property definition: '#{property_def}'"
24
33
  end
@@ -35,14 +44,16 @@ module PowerStencil
35
44
  new_entity = edit_before_save new_entity
36
45
  end
37
46
 
47
+ new_entity.resolve_fields_references!
48
+
38
49
  new_entity.valid? raise_error: true
39
50
  project.track_action_with_git("Created '#{new_entity.as_path}' (and potential dependencies).") do
40
51
  new_entity.save
41
52
  end
42
53
  puts_and_logs "Generated templates in '#{new_entity.templates_path}'.", check_verbose: false if new_entity.buildable?
43
54
  rescue => e
44
- puts_and_logs "Failed to create '#{search_criterion.as_path}' with message '#{e.message}'.", logs_as: :error, check_verbose: false
45
55
  logger.debug PowerStencil::Error.report_error(e)
56
+ raise PowerStencil::Error, "Failed to create '#{search_criterion.as_path}' with message '#{e.message}'."
46
57
  end
47
58
  end
48
59
  end
@@ -63,7 +74,6 @@ module PowerStencil
63
74
  modifications_valid? modified_path, entity
64
75
  end
65
76
  project.engine.root_universe.replace entity, modified_entity
66
- modified_entity.resolve_fields_references!
67
77
  modified_entity
68
78
  end
69
79
 
@@ -5,15 +5,52 @@ module PowerStencil
5
5
 
6
6
  class << self
7
7
  attr_accessor :script_name
8
+ attr_accessor :generating_project_completion
8
9
  end
9
10
 
10
11
  attr_reader :encountered_types
11
12
 
13
+ def timestamp
14
+ if generating_user_completion?
15
+ " on the #{Time.now}"
16
+ else
17
+ ''
18
+ end
19
+ end
20
+
12
21
  def initialize(universe)
13
22
  super
14
23
  @encountered_types = {}
15
24
  end
16
25
 
26
+ def generating_project_completion?
27
+ self.class.generating_project_completion
28
+ end
29
+
30
+ def generating_user_completion?
31
+ !self.class.generating_project_completion
32
+ end
33
+
34
+ def context_commands
35
+ if generating_user_completion?
36
+ PowerStencil.command_line_manager.commands.select do |command|
37
+ command.providers.include? PowerStencil
38
+ end
39
+ else
40
+ PowerStencil.command_line_manager.commands
41
+ end
42
+ end
43
+
44
+ def context_options(command)
45
+ if generating_user_completion?
46
+ command.options.select do |option|
47
+ option.providers.include? PowerStencil
48
+ end
49
+ else
50
+ command.options
51
+ end
52
+ end
53
+
17
54
  def script_name
18
55
  self.class.script_name
19
56
  end
@@ -2,6 +2,7 @@ require 'power_stencil/engine/entities_definitions'
2
2
  require 'power_stencil/engine/directory_processor'
3
3
 
4
4
  require 'power_stencil/engine/renderers/erb'
5
+ require 'power_stencil/engine/renderers/haml'
5
6
  require 'power_stencil/dsl/base'
6
7
  require 'power_stencil/dsl/plugin_generation'
7
8
  require 'power_stencil/dsl/completion'
@@ -18,6 +19,7 @@ module PowerStencil
18
19
  include PowerStencil::Engine::DirectoryProcessor
19
20
 
20
21
  include PowerStencil::Engine::Renderers::Erb
22
+ include PowerStencil::Engine::Renderers::Haml
21
23
 
22
24
  attr_accessor :dsl
23
25
  attr_reader :root_universe
@@ -1,5 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'erb'
3
+ require 'haml'
4
+
3
5
 
4
6
  module PowerStencil
5
7
  module Engine
@@ -30,10 +32,27 @@ module PowerStencil
30
32
  end
31
33
  end
32
34
  ensure
33
- @rendering_context = nil
35
+ @files_not_to_rename = nil
34
36
  @files_not_to_render = nil
35
37
  end
36
38
 
39
+
40
+ def render_single_template_file(source_template, destination_file, main_entry_point: nil)
41
+ compiled_universe = root_universe.compile scenario: config[:scenario]
42
+ puts_and_logs 'Entities analysis completed.'
43
+
44
+ logger.info 'Generating target file...'
45
+
46
+ process_file source_template, destination_file,
47
+ compiled_universe,
48
+ overwrite_files: true,
49
+ main_entry_point: main_entry_point
50
+ ensure
51
+ @files_not_to_rename = nil
52
+ @files_not_to_render = nil
53
+ end
54
+
55
+
37
56
  private
38
57
 
39
58
  def detemplatized_file_name(filename, replacement_text)
@@ -50,7 +50,7 @@ module PowerStencil
50
50
  private
51
51
 
52
52
  def load_plugins_entities_definition
53
- project.plugins.each do |_, plugin|
53
+ project.plugins_sorted_by_dependency.each do |plugin|
54
54
  plugin.require_plugin_entity_definitions
55
55
  end
56
56
  end
@@ -0,0 +1,21 @@
1
+ module PowerStencil
2
+ module Engine
3
+ module Renderers
4
+
5
+ module Haml
6
+
7
+ private
8
+
9
+ def render_haml_template(source, context)
10
+ logger.debug "Using HAML to render file '#{source}'"
11
+ ::Haml::Engine.new(File.read source).render(context)
12
+ rescue => e
13
+ logger.debug PowerStencil::Error.report_error(e)
14
+ raise PowerStencil::Error, "Error rendering '#{source}': '#{e.message}'"
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -55,14 +55,19 @@ module PowerStencil
55
55
  describe: PowerStencil::CommandProcessors::Describe,
56
56
  adm: PowerStencil::CommandProcessors::Adm
57
57
  }.each do |command_name, processor|
58
- command_line_manager.register_processor command_line_manager.command_by_alias(command_name),
58
+ command = command_line_manager.command_by_alias(command_name)
59
+ command_line_manager.register_processor command,
59
60
  processor.new
61
+ command.add_provider self
60
62
  end
61
63
  end
62
64
 
63
65
  def setup_climatic(cmd_line_args)
64
66
  mngr = Climatic::ConfigLayers::CommandLineLayer.build_command_line_manager base_commands_definition_file
65
67
  Climatic.bootstrap cmd_line_args: cmd_line_args, command_manager: mngr
68
+ mngr.commands.each do |command|
69
+ command.add_provider PowerStencil
70
+ end
66
71
  begin
67
72
  # Fix command line layer priority to allow a bigger number of plugins
68
73
  config.command_line_layer.priority = 999
@@ -70,7 +70,6 @@ module PowerStencil
70
70
  load_capabilities
71
71
  load_plugin_specific_config
72
72
  load_yaml_command_definition
73
- require_entry_point
74
73
  end
75
74
 
76
75
  end
@@ -13,6 +13,10 @@ module PowerStencil
13
13
  @capabilities ||= CAPABILITIES.dup.zip([false] * CAPABILITIES.size).to_h
14
14
  end
15
15
 
16
+ def dependencies
17
+ plugin_definition[:dependencies]
18
+ end
19
+
16
20
  private
17
21
 
18
22
  def load_capabilities