power_stencil 0.6.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +2 -0
  3. data/README.md +3 -7
  4. data/doc/builds.md +10 -1
  5. data/doc/entities.md +59 -50
  6. data/doc/images/power-stencil-entity-creation.svg +247 -114
  7. data/doc/plugins.md +1 -0
  8. data/doc/templates.md +23 -18
  9. data/etc/base_commands_definition.yml +14 -0
  10. data/etc/power_stencil.yaml +7 -1
  11. data/etc/templates/project/.zzzgitignore.erb +8 -3
  12. data/lib/power_stencil.rb +1 -0
  13. data/lib/power_stencil/command_processors/build.rb +15 -2
  14. data/lib/power_stencil/command_processors/check.rb +12 -0
  15. data/lib/power_stencil/command_processors/create.rb +6 -5
  16. data/lib/power_stencil/command_processors/delete.rb +23 -15
  17. data/lib/power_stencil/command_processors/edit.rb +4 -2
  18. data/lib/power_stencil/command_processors/plugin.rb +21 -6
  19. data/lib/power_stencil/command_processors/shell.rb +10 -3
  20. data/lib/power_stencil/dsl/entities.rb +0 -16
  21. data/lib/power_stencil/engine/entities_definitions.rb +16 -7
  22. data/lib/power_stencil/engine/entities_handling.rb +1 -1
  23. data/lib/power_stencil/engine/project_engine.rb +6 -10
  24. data/lib/power_stencil/initializer.rb +4 -7
  25. data/lib/power_stencil/plugins/entity_definitions.rb +15 -0
  26. data/lib/power_stencil/plugins/require.rb +1 -0
  27. data/lib/power_stencil/plugins/templates.rb +3 -3
  28. data/lib/power_stencil/project/base.rb +24 -9
  29. data/lib/power_stencil/project/create.rb +23 -2
  30. data/lib/power_stencil/project/git.rb +75 -0
  31. data/lib/power_stencil/project/info.rb +14 -1
  32. data/lib/power_stencil/project/paths.rb +22 -6
  33. data/lib/power_stencil/project/plugins.rb +1 -1
  34. data/lib/power_stencil/project/templates.rb +15 -22
  35. data/lib/power_stencil/system_entity_definitions/all.rb +2 -1
  36. data/lib/power_stencil/system_entity_definitions/buildable.rb +1 -1
  37. data/lib/power_stencil/system_entity_definitions/entity_override.rb +6 -0
  38. data/lib/power_stencil/system_entity_definitions/entity_project_common.rb +13 -5
  39. data/lib/power_stencil/system_entity_definitions/{has_associated_files.rb → entity_templates.rb} +2 -2
  40. data/lib/power_stencil/system_entity_definitions/project_config.rb +1 -1
  41. data/lib/power_stencil/system_entity_definitions/project_entity.rb +7 -0
  42. data/lib/power_stencil/system_entity_definitions/simple_exec.rb +3 -3
  43. data/lib/power_stencil/system_entity_definitions/source_provider.rb +15 -0
  44. data/lib/power_stencil/version.rb +1 -1
  45. data/power_stencil.gemspec +1 -0
  46. metadata +20 -4
@@ -7,7 +7,7 @@ module PowerStencil
7
7
 
8
8
  include PowerStencil::Utils::SecureRequire
9
9
 
10
- def require_definition_files(files_or_dirs)
10
+ def require_definition_files(files_or_dirs, source)
11
11
  required_files = []
12
12
  files_or_dirs.each do |file_or_dir|
13
13
  if File.directory? file_or_dir and File.readable? file_or_dir
@@ -21,21 +21,30 @@ module PowerStencil
21
21
  next
22
22
  end
23
23
  # This is a ruby library or there is something wrong
24
- securely_require file_or_dir
25
- # unless securely_require file_or_dir
26
- # logger.warn "While trying to load definition files, found that '#{file_or_dir}' has a problem. Ignored..."
27
- # end
24
+ securely_require_with_entity_class_detection file_or_dir, source
25
+
28
26
  end
29
- required_files.sort!.each {|file| securely_require file, fail_on_error: true}
27
+ required_files.sort!.each { |file| securely_require_with_entity_class_detection file, source }
30
28
  required_files
31
29
  end
32
30
 
33
31
  private
34
32
 
35
33
  def load_system_entities_definition
36
- require_definition_files [SYSTEM_ENTITY_DEFINITION_ENTRY_POINT]
34
+ require_definition_files [SYSTEM_ENTITY_DEFINITION_ENTRY_POINT], PowerStencil
37
35
  end
38
36
 
37
+ def securely_require_with_entity_class_detection(entity_definition_file_path, source)
38
+ before = PowerStencil::Engine::EntitiesHandling.all_types
39
+ securely_require entity_definition_file_path, fail_on_error: true
40
+ after = PowerStencil::Engine::EntitiesHandling.all_types
41
+ after.reject { |k, _| before.keys.include? k }
42
+ .each do |_, plugin_entity_class|
43
+ plugin_entity_class.instance_eval do
44
+ @entity_type_source_provider = source
45
+ end
46
+ end
47
+ end
39
48
  end
40
49
 
41
50
  end
@@ -59,7 +59,7 @@ module PowerStencil
59
59
  raise PowerStencil::Error, "Unknown entity type: '#{type}'"
60
60
  end
61
61
  fields[:name] = fields[:name].to_s
62
- res = @available_entities_hash[type.to_sym].new fields: fields, universe: work_universe
62
+ res = @available_entities_hash[type.to_sym].new fields: fields, universe: work_universe, user: user
63
63
  logger.debug "Created new '#{type}': \n#{fields.to_yaml}"
64
64
  work_universe.add res
65
65
  if work_universe == PowerStencil.project.engine.root_universe
@@ -36,7 +36,7 @@ module PowerStencil
36
36
  if Dir.exist? dir and File.readable? dir
37
37
  logger.info 'Loading project specific entity definitions.'
38
38
  $LOAD_PATH << dir
39
- require_definition_files [dir]
39
+ require_definition_files [dir], project
40
40
  end
41
41
  end
42
42
 
@@ -62,24 +62,20 @@ module PowerStencil
62
62
  end
63
63
 
64
64
  def load_project_entities
65
- logger.debug 'Loading project entities - NOT IMPLEMENTED'
66
65
  root_universe.import project.project_entities_path, stop_on_error: false do |new_entity|
67
- process_entity new_entity
66
+ logger.debug "Loaded entity: '#{new_entity.as_path}'"
68
67
  end
69
68
  end
70
69
 
71
70
  def load_user_entities
72
- logger.debug 'Loading user entities - NOT IMPLEMENTED'
73
71
  root_universe.import project.user_entities_path, stop_on_error: false do |new_entity|
74
- process_entity new_entity
72
+ logger.debug "Loaded unversioned entity: '#{new_entity.as_path}'"
73
+ new_entity.instance_eval do
74
+ @is_versioned_entity = false
75
+ end
75
76
  end
76
77
  end
77
78
 
78
- def process_entity(entity)
79
- logger.debug "New entity: '#{entity.name}' (#{entity.type})"
80
- end
81
-
82
-
83
79
  end
84
80
 
85
81
  end
@@ -8,17 +8,15 @@ module PowerStencil
8
8
 
9
9
  include Climatic::Proxy
10
10
 
11
+ def name
12
+ 'PowerStencil core'
13
+ end
14
+
11
15
  def bootstrap(cmd_line_args = ARGV.dup)
12
16
  setup_climatic cmd_line_args
13
17
  logger.debug 'Starting PowerStencil initialization...'
14
18
  setup_system_processors
15
19
  setup_universe_compiler_logger
16
- # @project = try_to_load_project fail_on_error: false
17
- begin
18
- project.setup_templates_for_entities # unless project.nil?
19
- rescue => e
20
- logger.debug PowerStencil::Error.report_error e
21
- end
22
20
  logger.debug 'PowerStencil initialization complete'
23
21
  end
24
22
 
@@ -32,7 +30,6 @@ module PowerStencil
32
30
 
33
31
  def try_to_load_project(fail_on_error: true)
34
32
  PowerStencil::Project::Base.instantiate_from_config config
35
-
36
33
  end
37
34
 
38
35
  def setup_system_processors
@@ -6,9 +6,24 @@ module PowerStencil
6
6
  def require_plugin_entity_definitions
7
7
  return unless capabilities[:entity_definitions]
8
8
  logger.info "Requiring '#{self.name}' plugin entity definitions..."
9
+ securely_require_with_entity_class_detection
10
+ end
11
+
12
+
13
+ private
14
+
15
+ def securely_require_with_entity_class_detection
16
+ before = PowerStencil::Engine::EntitiesHandling.all_types
9
17
  plugin_definition[:entity_definitions].each do |entity_definition_file_path|
10
18
  securely_require entity_definition_file_path, fail_on_error: true
11
19
  end
20
+ after = PowerStencil::Engine::EntitiesHandling.all_types
21
+ after.reject { |k, _| before.keys.include? k }.each do |_, plugin_entity_class|
22
+ plugin = self
23
+ plugin_entity_class.instance_eval do
24
+ @entity_type_source_provider = plugin
25
+ end
26
+ end
12
27
  end
13
28
 
14
29
  end
@@ -21,6 +21,7 @@ module PowerStencil
21
21
  $LOAD_PATH << plugin_root_path
22
22
  securely_require entry_point_path unless plugin_definition[:plugin_module].nil?
23
23
  rescue LoadError => e
24
+ @entry_point_path = nil
24
25
  logger.warn "As plugin '#{name}' code is invalid, removing '#{plugin_root_path}' from LOAD_PATH"
25
26
  $LOAD_PATH.delete plugin_root_path
26
27
  end
@@ -3,15 +3,15 @@ module PowerStencil
3
3
 
4
4
  module Templates
5
5
 
6
- def register_plugin_templates
6
+ def register_plugin_templates_templates
7
7
  return unless capabilities[:templates]
8
8
  logger.info "Loading '#{self.name}' plugin templates..."
9
9
  plugin_definition[:templates].each do |templates_path|
10
- plugin_templates_path = File.join self.path, templates_path
10
+ plugin_templates_path = File.join self.plugin_path, templates_path
11
11
  Dir.entries(plugin_templates_path).reject { |e| %w(. ..).include? e }.each do |entry|
12
12
  template_path = File.join(plugin_templates_path, entry)
13
13
  if Dir.exist? template_path
14
- project.register_template_path_for_type entry.to_sym, template_path
14
+ project.register_template_template_path_for_type entry.to_sym, template_path
15
15
  end
16
16
  end
17
17
  end
@@ -5,6 +5,7 @@ require 'power_stencil/project/versioning'
5
5
  require 'power_stencil/project/info'
6
6
  require 'power_stencil/project/templates'
7
7
  require 'power_stencil/project/plugins'
8
+ require 'power_stencil/project/git'
8
9
 
9
10
  require 'power_stencil/engine/project_engine'
10
11
  require 'power_stencil/engine/entity_engine'
@@ -30,40 +31,54 @@ module PowerStencil
30
31
  include PowerStencil::Project::Templates
31
32
  include PowerStencil::Project::Plugins
32
33
  include PowerStencil::Project::Info
34
+ include PowerStencil::Project::Git
33
35
  extend PowerStencil::Project::Create
34
36
 
35
37
  attr_reader :engine, :entity_engine
36
38
 
39
+ def name
40
+ File.dirname project_config_root
41
+ end
42
+
37
43
  def initialize(search_from_path: Dir.pwd)
38
44
  initialize_paths search_from_path
39
45
  load_project_specific_config
40
46
  check_project_version
41
47
  bootstrap_plugins
42
48
  build_engines
43
- register_system_templates
44
- register_project_templates
49
+ register_system_templates_templates
50
+ register_plugins_templates_templates
51
+ register_project_templates_templates
52
+ setup_git_tracking
45
53
  end
46
54
 
47
55
  private
48
56
 
49
- def register_project_templates
50
- dir = project_templates_path
57
+ def register_plugins_templates_templates
58
+ plugins.each do |_, plugin|
59
+ plugin.register_plugin_templates_templates
60
+ end
61
+ end
62
+
63
+
64
+ def register_project_templates_templates
65
+ dir = project_templates_templates_path
51
66
  if Dir.exist? dir and File.readable? dir
52
67
  logger.info 'Registering project specific templates.'
53
68
  Dir.entries(dir).each do |potential_entity_type|
54
69
  next if potential_entity_type.match /^\./
55
70
  template_dir = File.join(dir, potential_entity_type)
56
71
  next unless File.directory? template_dir
57
- register_template_path_for_type potential_entity_type.to_sym, template_dir
72
+ register_template_template_path_for_type potential_entity_type.to_sym, template_dir
58
73
  end
59
74
  end
60
75
  end
61
76
 
62
- def register_system_templates
77
+ def register_system_templates_templates
63
78
  logger.debug 'Registering system templates'
64
79
  %i(plugin_definition simple_exec).each do |template_name|
65
- template_path = template_path template_name
66
- register_template_path_for_type template_name, template_path
80
+ template_path = system_template_template_path template_name
81
+ register_template_template_path_for_type template_name, template_path
67
82
  end
68
83
  end
69
84
 
@@ -76,4 +91,4 @@ module PowerStencil
76
91
  end
77
92
 
78
93
  end
79
- end
94
+ end
@@ -5,6 +5,8 @@ module PowerStencil
5
5
 
6
6
  module Create
7
7
 
8
+ INITIAL_REPOSITORY_COMMIT_MESSAGE = 'Initial commit for project "%s".'
9
+
8
10
  include Climatic::Proxy
9
11
 
10
12
  def create_project_tree(path, config_directory_name = PowerStencil.config[:default_config_directory_name])
@@ -14,14 +16,33 @@ module PowerStencil
14
16
  raise PowerStencil::Error, "The directory '#{path}' already contains a PowerStencil project !" unless config[:force]
15
17
  end
16
18
  logger.info "Creating project in '#{path}'..."
17
- render_project_template_in(path)
19
+ render_project_template_in path
20
+ initialize_git_repository path
18
21
  end
19
22
 
20
23
  private
21
24
 
25
+ def initialize_git_repository(repo_path)
26
+ if config[:'no-git']
27
+ puts_and_logs 'Do not initialize project git repository as per config request.', logs_as: :debug
28
+ return
29
+ end
30
+ if Dir.exists? File.join(repo_path, '.git')
31
+ puts_and_logs 'Git repository already exists. Skipping.', logs_as: :debug, check_verbose: false
32
+ return
33
+ end
34
+ puts_and_logs 'Initializing git repository...', logs_as: :debug
35
+ git = ::Git.init repo_path
36
+ logger.debug 'Adding all files.'
37
+ git.add repo_path
38
+ logger.debug 'Committing initial status'
39
+ commit_msg = INITIAL_REPOSITORY_COMMIT_MESSAGE % [File.basename(repo_path)]
40
+ git.commit_all commit_msg
41
+ end
42
+
22
43
  def render_project_template_in(new_project_config_path)
23
44
  engine = PowerStencil::Engine::InitEngine.new
24
- engine.render_source PowerStencil::Project::Paths.project_system_template_path, new_project_config_path
45
+ engine.render_source PowerStencil::Project::Paths.project_system_template_template_path, new_project_config_path
25
46
  end
26
47
 
27
48
  end
@@ -0,0 +1,75 @@
1
+ module PowerStencil
2
+ module Project
3
+
4
+ module Git
5
+
6
+ include Climatic::Utils::Input
7
+
8
+ def track_action_with_git(action_message,
9
+ user_validation_required: false,
10
+ validation_message: 'Commit changes ?',
11
+ show_files_to_commit: false,
12
+ &block)
13
+ return yield if git.nil?
14
+
15
+ status_before_action = git.status
16
+ yield
17
+ status_after_action = git.status
18
+
19
+ files_introduced_by_action = status_after_action.untracked.reject { |f| status_before_action.untracked.keys.include? f}
20
+ files_deleted_by_action = status_after_action.deleted.reject { |f| status_before_action.deleted.keys.include? f}
21
+ files_modified_by_action = status_after_action.changed.reject { |f| status_before_action.changed.keys.include? f}
22
+ files_to_commit = [files_introduced_by_action, files_deleted_by_action, files_modified_by_action].map(&:keys).flatten.sort.uniq
23
+
24
+ if files_to_commit.empty?
25
+ puts_and_logs 'Nothing to commit.'
26
+ return
27
+ end
28
+
29
+ if show_files_to_commit
30
+ header = 'Following file'
31
+ header << 's' if files_to_commit.count > 1
32
+ header << ' will be committed:'
33
+ puts header
34
+ puts files_to_commit.map { |filename| " - '#{filename}'" }
35
+ end
36
+
37
+ if user_validation_required
38
+ unless get_user_confirmation(default_choice: 'Yes', prompt: validation_message)
39
+ puts_and_logs 'Commit cancelled by user.', check_verbose: false
40
+ return
41
+ end
42
+ end
43
+
44
+ files_to_commit.each { |filename| git.add filename }
45
+
46
+ # Verify files to be committed really are
47
+ files_really_to_be_committed = git.diff.stats[:files].keys.select { |filename| files_to_commit.include? filename }
48
+ return if files_really_to_be_committed.empty?
49
+ files_really_to_be_committed.each { |filename| logger.info "File '#{filename}' will be committed" }
50
+
51
+ git.commit action_message
52
+ puts_and_logs 'All changes introduced have been committed.'
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader :git
58
+
59
+ def setup_git_tracking
60
+ @git = nil
61
+ if config[:'no-git']
62
+ logger.debug "Won't track any changes with git as per config request!"
63
+ return
64
+ end
65
+ @git = ::Git.open(self.project_root, :log => PowerStencil.logger)
66
+ logger.debug 'Following project changes with git'
67
+ rescue => e
68
+ logger.debug PowerStencil::Error.report_error(e)
69
+ logger.warn 'This project is not managed by git'
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ end
@@ -60,7 +60,20 @@ module PowerStencil
60
60
  .sort{ |a,b| a.first <=> b.first }
61
61
  .each do |type, klass|
62
62
  msg = "Type '#{type}' --> #{klass}"
63
- msg << " (template-template path: '#{entity_type_templates[type]}')" unless entity_type_templates[type].nil?
63
+
64
+ source_provider = klass.entity_type_source_provider
65
+ source_provider_display = if source_provider == PowerStencil
66
+ "'#{source_provider.name}'"
67
+ elsif source_provider == self
68
+ "project '#{source_provider.name}'"
69
+ elsif source_provider.is_a? PowerStencil::Plugins::Base
70
+ "plugin '#{source_provider.name}'"
71
+ else
72
+ raise PowerStencil::Error, "Unidentified source provider for #{klass} !"
73
+ end
74
+
75
+ msg << " (provided by #{source_provider_display})"
76
+ msg << " template-template path: '#{entity_type_templates_templates[type]}'" unless entity_type_templates_templates[type].nil?
64
77
  report << msg
65
78
  end
66
79
  report
@@ -7,12 +7,12 @@ module PowerStencil
7
7
 
8
8
  attr_reader :project_config_root, :started_from
9
9
 
10
- def self.system_templates_path
10
+ def self.system_templates_templates_path
11
11
  File.expand_path File.join('..', '..', '..', '..', 'etc', 'templates'), __FILE__
12
12
  end
13
13
 
14
- def self.project_system_template_path
15
- File.join system_templates_path, 'project'
14
+ def self.project_system_template_template_path
15
+ File.join system_templates_templates_path, 'project'
16
16
  end
17
17
 
18
18
  def build_run_path(seed)
@@ -31,8 +31,8 @@ module PowerStencil
31
31
  File.join project_root, PowerStencil.config[:project_build_root_directory_name]
32
32
  end
33
33
 
34
- def template_path(entity_type)
35
- File.join PowerStencil::Project::Paths.system_templates_path, entity_type.to_s
34
+ def system_template_template_path(entity_type)
35
+ File.join PowerStencil::Project::Paths.system_templates_templates_path, entity_type.to_s
36
36
  end
37
37
 
38
38
  def project_local_plugins_path
@@ -43,10 +43,26 @@ module PowerStencil
43
43
  File.join project_local_plugins_path, plugin_name
44
44
  end
45
45
 
46
- def project_templates_path
46
+ def project_templates_templates_path
47
47
  File.join project_config_root, PowerStencil.config[:project_templates_directory_name]
48
48
  end
49
49
 
50
+ def entities_template_path
51
+ File.join project_root, PowerStencil.config[:versioned_entities_templates_directory_name]
52
+ end
53
+
54
+ def user_entities_template_path
55
+ File.join project_root, PowerStencil.config[:unversioned_user_entities_templates_directory_name]
56
+ end
57
+
58
+ def entity_template_path(entity)
59
+ if entity.is_versioned_entity?
60
+ File.join entities_template_path, entity.type.to_s, entity.name
61
+ else
62
+ File.join user_entities_template_path, entity.type.to_s, entity.name
63
+ end
64
+ end
65
+
50
66
  def project_entity_definitions_path
51
67
  File.join project_config_root, PowerStencil.config[:project_entity_definitions_directory_name]
52
68
  end