k_manager 0.0.24 → 0.0.32

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,45 +14,109 @@ module KManager
14
14
  default: '.builders',
15
15
  desc: 'The builder folder, defaults to (.builders)'
16
16
 
17
- option :boot_file,
18
- default: 'boot.rb',
19
- aliases: ['-b'],
20
- desc: 'The name of the boot file to create'
21
-
22
17
  option :force,
23
18
  default: false,
24
19
  aliases: ['-f'],
25
20
  desc: 'Force even if guard fails'
26
21
 
22
+ option :template,
23
+ default: false,
24
+ aliases: ['-t'],
25
+ desc: 'Starter template'
26
+
27
+ option :log_level,
28
+ default: nil,
29
+ desc: 'Log level, use debug for more info'
30
+
31
+ option :description,
32
+ default: nil,
33
+ aliases: ['-d'],
34
+ desc: 'Application description'
35
+
36
+ option :user_story,
37
+ default: nil,
38
+ desc: 'Main user story'
39
+
40
+ option :repo_organization,
41
+ default: nil,
42
+ desc: 'Repository organization'
43
+
27
44
  example [
28
45
  ' # Project in current directory - will create a .builders folder and boot file at ./builders/boot.rb',
29
46
  '-b ../config/boot.rb # Project in current directory - will create a .builders folder and boot file at ./config/boot.rb',
47
+ '-t ruby_gem # Use starter template `ruby_gem` to setup the files in .builders/*',
30
48
  'my_project # will watch .xmen folder'
31
49
  ]
32
50
 
33
51
  # rubocop:disable Metrics/ParameterLists
34
- def call(project_folder:, builder_folder:, boot_file:, log_level:, force:, **)
35
- project_folder = absolute_path(project_folder, Dir.pwd)
36
- name = File.basename(project_folder)
37
- builder_folder = absolute_path(builder_folder, project_folder)
38
- boot_file = absolute_path(boot_file, builder_folder)
52
+ def call(project_folder:, builder_folder:, log_level:, force:, template:, **opts)
53
+ project_folder = absolute_path(project_folder, Dir.pwd)
54
+ name = File.basename(project_folder)
55
+ builder_folder = absolute_path(builder_folder, project_folder)
56
+ template_root_folder = File.expand_path('~/dev/kgems/k_templates/definitions/starter')
39
57
 
40
- log_params(name, project_folder, builder_folder, boot_file, force) if log_level == 'debug'
58
+ log_params(name, project_folder, builder_folder, force, log_level, template_root_folder, template, **opts) if log_level == 'debug'
41
59
 
42
- create_project(project_folder, builder_folder, boot_file) if can_create?(force, builder_folder)
60
+ create_project(name, project_folder, builder_folder, template_root_folder, template, **opts) if can_create?(force, builder_folder)
43
61
  end
44
62
  # rubocop:enable Metrics/ParameterLists
45
63
 
46
64
  private
47
65
 
48
- def create_project(project_folder, builder_folder, boot_file)
66
+ # rubocop:disable Metrics/ParameterLists
67
+ def create_project(name, project_folder, builder_folder, template_root_folder, template, **opts)
49
68
  FileUtils.mkdir_p(project_folder)
50
69
  FileUtils.mkdir_p(builder_folder)
51
- File.write(boot_file, '# Boot Sequence')
52
- # Use a boot_file_template if needed
70
+
71
+ # handle_main_start_command
72
+
73
+ setup_builder_from_template(name, builder_folder, template_root_folder, 'default', **opts) unless setup_builder_from_template(name, builder_folder, template_root_folder, template, **opts)
53
74
 
54
75
  log.info 'Project created'
55
76
  end
77
+ # rubocop:enable Metrics/ParameterLists
78
+
79
+ def setup_builder_from_template(name, builder_folder, template_root_folder, template, **opts)
80
+ return false unless template
81
+
82
+ # /Users/davidcruwys/dev/kgems/k_templates/definitions/starter/ruby_gem/.starter.json
83
+ template_folder = File.join(template_root_folder, template)
84
+ starter_config = template_starter_config(template_folder)
85
+
86
+ return false unless starter_config
87
+
88
+ builder = get_builder(builder_folder, template_folder)
89
+
90
+ return false if starter_config['files'].nil? || starter_config['files'].empty?
91
+
92
+ starter_config['files']&.each do |relative_file|
93
+ builder.add_file(relative_file, template_file: relative_file, **{ name: name }.merge(opts))
94
+ end
95
+ end
96
+
97
+ def template_starter_config(template_folder)
98
+ starter_file = File.join(template_folder, '.starter.json')
99
+
100
+ return nil unless File.exist?(starter_file)
101
+
102
+ JSON.parse(File.read(starter_file))
103
+ end
104
+
105
+ # rubocop:disable Metrics/AbcSize
106
+ def get_builder(builder_folder, template_folder)
107
+ Handlebars::Helpers.configure do |config|
108
+ config.helper_config_file = File.join(Gem.loaded_specs['handlebars-helpers'].full_gem_path, '.handlebars_helpers.json')
109
+ config.string_formatter_config_file = File.join(Gem.loaded_specs['handlebars-helpers'].full_gem_path, '.handlebars_string_formatters.json')
110
+ end
111
+
112
+ KConfig.configure(:starter_template) do |config|
113
+ config.target_folders.add(:builder , builder_folder)
114
+ config.template_folders.add(:template , template_folder)
115
+ end
116
+
117
+ KBuilder::BaseBuilder.init(KConfig.configuration(:starter_template))
118
+ end
119
+ # rubocop:enable Metrics/AbcSize
56
120
 
57
121
  def can_create?(force, builder_folder)
58
122
  return true if force
@@ -63,14 +127,22 @@ module KManager
63
127
  false
64
128
  end
65
129
 
66
- def log_params(name, project_folder, builder_folder, boot_file, force)
130
+ # rubocop:disable Metrics/ParameterLists, Metrics/AbcSize
131
+ def log_params(name, project_folder, builder_folder, force, log_level, template_root_folder, template, **opts)
67
132
  log.section_heading('Create new project')
68
- log.kv 'name' , name
69
- log.kv 'project_folder' , project_folder
70
- log.kv 'builder_folder' , builder_folder
71
- log.kv 'boot_file' , boot_file
72
- log.kv 'force' , force
133
+ log.kv 'name' , name
134
+ log.kv 'project_folder' , project_folder
135
+ log.kv 'builder_folder' , builder_folder
136
+ log.kv 'force' , force
137
+ log.kv 'log_level' , log_level
138
+ log.kv 'template_root_folder' , template_root_folder
139
+ log.kv 'template' , template
140
+
141
+ opts.each do |key, value|
142
+ log.kv key, value
143
+ end
73
144
  end
145
+ # rubocop:enable Metrics/ParameterLists, Metrics/AbcSize
74
146
  end
75
147
  end
76
148
  end
@@ -27,16 +27,32 @@ module KManager
27
27
 
28
28
  log_params(builder_folder, boot_file) if log_level == 'debug'
29
29
 
30
- # puts builder_folder
31
- # puts boot_file
30
+ # If you do a System Exit (control+c) you can go into a reboot sequence based on options
31
+ # if the option is not set then system will exit gracefully
32
+ while keep_watching(builder_folder, boot_file); end
33
+ end
34
+
35
+ private
32
36
 
37
+ # rubocop:disable Metrics/AbcSize
38
+ def keep_watching(builder_folder, boot_file)
33
39
  Dir.chdir(builder_folder) do
34
40
  watcher = KManager::Watcher.new(builder_folder, boot_file)
35
41
  watcher.start
36
42
  end
37
- end
43
+ false
44
+ rescue Interrupt, SystemExit
45
+ if KManager.opts.reboot_on_kill == true || KManager.opts.reboot_on_kill == 1
46
+ puts "\nRebooting #{KManager.opts.app_name}..."
47
+ sleep KManager.opts.reboot_sleep unless KManager.opts.reboot_sleep.zero?
38
48
 
39
- private
49
+ return true
50
+ end
51
+
52
+ puts "\nExiting..."
53
+ false
54
+ end
55
+ # rubocop:enable Metrics/AbcSize
40
56
 
41
57
  def log_params(builder_folder, boot_file)
42
58
  log.section_heading('Watch project')
@@ -5,6 +5,8 @@ module KManager
5
5
  #
6
6
  # TODO: Write Tests
7
7
  class Manager
8
+ include KLog::Logging
9
+
8
10
  attr_accessor :active_uri
9
11
 
10
12
  # NOTE: rename current_resource to active_resource, focused_resource?
@@ -28,7 +30,29 @@ module KManager
28
30
  yield(@current_resource)
29
31
  end
30
32
 
31
- Options = Struct.new(:sleep, :exception_style)
33
+ # Usage
34
+ #
35
+ # KManager.opts.sleep = 10
36
+ # KManager.opts.reboot_on_kill = 0
37
+ # KManager.opts.exception_style = :short
38
+ # KManager.opts.show.time_taken = true
39
+ # KManager.opts.show.finished = true
40
+ # KManager.opts.show.finished_message = 'FINISHED :)'
41
+
42
+ Options = Struct.new(
43
+ :app_name,
44
+ :exception_style,
45
+ :reboot_on_kill,
46
+ :reboot_sleep,
47
+ :sleep,
48
+ :show
49
+ )
50
+
51
+ Show = Struct.new(
52
+ :time_taken,
53
+ :finished,
54
+ :finished_message
55
+ )
32
56
 
33
57
  # @param [Integer] sleep Seconds to sleep after running, 0 = no sleep
34
58
  # @param [Symbol] exception_style Format for exception messages caught by watcher.
@@ -36,13 +60,31 @@ module KManager
36
60
  # :short - message and short backtrace
37
61
  # :long - message and long backtrace
38
62
  def opts
39
- @opts ||= Options.new(0, :message)
63
+ @opts ||= Options.new('', :message, false, 1, 0, Show.new(true, true, 'FINISHED :)'))
40
64
  end
41
65
 
42
66
  def areas
43
67
  @areas ||= []
44
68
  end
45
69
 
70
+ # List of resources for an area.
71
+ #
72
+ # if area is nil, then return resources for the area matching the current_resource
73
+ def area_resources(area: nil)
74
+ area = resolve_area(area)
75
+
76
+ log.error 'Could not resolve area' if area.nil?
77
+
78
+ area&.resources
79
+ end
80
+
81
+ # List of documents for an area.
82
+ #
83
+ # if area is nil, for the area matching the current_resource
84
+ def area_documents(area: nil)
85
+ area_resources(area: area)&.flat_map(&:documents)
86
+ end
87
+
46
88
  def add_area(name, namespace: nil)
47
89
  area = find_area(name)
48
90
 
@@ -54,16 +96,7 @@ module KManager
54
96
  end
55
97
 
56
98
  def find_document(tag, area: nil)
57
- area = resolve_area(area)
58
-
59
- log.error 'Could not resolve area' if area.nil?
60
-
61
- log.line
62
- log.error(tag)
63
- log.line
64
-
65
- documents = area.resources.flat_map(&:documents)
66
- documents.find { |d| d.tag == tag }
99
+ area_documents(area: area)&.find { |d| d.tag == tag }
67
100
  end
68
101
 
69
102
  def fire_actions(*actions)
@@ -79,14 +112,14 @@ module KManager
79
112
 
80
113
  def resolve_area(area)
81
114
  if area.nil?
82
- return KManager.current_resource.area if KManager.current_resource
115
+ return current_resource.area if current_resource
83
116
 
84
- return KManager.areas.first
117
+ return areas.first
85
118
  end
86
119
 
87
120
  return area if area.is_a?(Area)
88
121
 
89
- find_area(name)
122
+ find_area(area)
90
123
  end
91
124
 
92
125
  # Return a list of resources for a URI.
@@ -104,7 +137,19 @@ module KManager
104
137
  @active_uri = nil
105
138
  end
106
139
 
140
+ def boot
141
+ KManager.fire_actions(:load_content, :register_document, :preload_document, :load_document)
142
+ end
143
+
144
+ def reboot
145
+ puts 'Fire reboot'
146
+ KManager.opts.reboot_on_kill = 1
147
+ raise SystemExit
148
+ end
149
+
107
150
  def debug(*sections)
151
+ log.structure(KUtil.data.to_hash(opts))
152
+
108
153
  areas.each do |area|
109
154
  area.debug(*sections)
110
155
  end
@@ -5,6 +5,10 @@ module KManager
5
5
  # Generate dashboard information on the console
6
6
  #
7
7
  # TODO: ConsoleDashboard and HtmlConsole
8
+ # dashboard = KManager::Overview::Dashboard.new(KManager.manager)
9
+ # dashboard.areas
10
+ # dashboard.resources
11
+ # dashboard.documents
8
12
  class Dashboard
9
13
  include KLog::Logging
10
14
 
@@ -45,7 +49,7 @@ module KManager
45
49
  { namespace: { display_method: ->(row) { row.namespace } } },
46
50
  { status: { display_method: ->(row) { row.status } } },
47
51
  { content_type: { display_method: ->(row) { row.content_type } } },
48
- { content: { display_method: ->(row) { row.content } } },
52
+ { content: { display_method: ->(row) { format_content(row.content, row.content_type) }, width: 50 } },
49
53
  { document_count: { display_method: ->(row) { blank_zero(row.document_count) } } },
50
54
  { valid: { display_method: ->(row) { row.valid } } },
51
55
  { error_count: { display_method: ->(row) { blank_zero(row.errors.length) } } },
@@ -83,6 +87,7 @@ module KManager
83
87
  # # { path: { display_method: -> (row) { row.resource_path } } },
84
88
  # { exist: { display_method: -> (row) { row.resource_exist } } },
85
89
  { document_id: { display_method: ->(row) { blank_zero(row.document_id) } } },
90
+ { state: { display_method: ->(row) { document_state(row.document_state) } } },
86
91
  { data: { display_method: ->(row) { row.document_data } } },
87
92
  { error_count: { display_method: ->(row) { blank_zero(row.document_errors.length) } } },
88
93
  { key: { display_method: ->(row) { row.document_key } } },
@@ -119,12 +124,35 @@ module KManager
119
124
  log.structure(data, **opts)
120
125
  end
121
126
 
127
+ def format_content(content, type)
128
+ formatted = content
129
+ case type
130
+ when :ruby
131
+ formatted = formatted&.sub(/\A# frozen_string_literal: true/, '')&.strip
132
+ end
133
+ formatted
134
+ end
135
+
122
136
  def blank_zero(value)
123
137
  return nil if value.nil? || (value.is_a?(Integer) && value.zero?)
124
138
 
125
139
  value
126
140
  end
127
141
 
142
+ # Valid states are:
143
+ # :new
144
+ # :evaluated
145
+ # :initialized
146
+ # :children_evaluated
147
+ # :actioned
148
+ def document_state(state)
149
+ return 'unknown' if state.nil?
150
+ return 'loaded (partially)' if state == :evaluated # probably has unmet dependency
151
+ return 'loaded' if state == :children_evaluated
152
+
153
+ state.to_s
154
+ end
155
+
128
156
  def lpad(size, value)
129
157
  value.to_s.rjust(size)
130
158
  end
@@ -62,9 +62,12 @@ module KManager
62
62
  attribute :resource_relative_path , Types::Strict::String.optional.default(nil)
63
63
  attribute :resource_exist? , Types::Strict::Bool
64
64
  attribute :document_id , Types::Strict::Integer
65
+ attribute :document_state , Types::Strict::String | Types::Strict::Symbol
65
66
  attribute :document_data , Types::Strict::Any.optional.default # Hash.optional.default(nil) | Types::Strict::Array.of(Types::Strict::Hash).optional.default(nil)
66
67
  attribute :document_key , Types::Strict::String | Types::Strict::Symbol
67
- attribute :document_namespace , Types::Strict::String | Types::Strict::Array.of(Types::Strict::String).optional.default(nil)
68
+ attribute :document_namespace , Types::Strict::String | Types::Strict::Symbol |
69
+ Types::Strict::Array.of(Types::Strict::String).optional.default(nil) |
70
+ Types::Strict::Array.of(Types::Strict::Symbol).optional.default(nil)
68
71
  attribute :document_tag , Types::Strict::String | Types::Strict::Symbol
69
72
  attribute :document_type , Types::Strict::String | Types::Strict::Symbol
70
73
  # TODO: Write code to populate this with the resource line number
@@ -35,6 +35,7 @@ module KManager
35
35
  **area.attribute_values('area_'),
36
36
  **resource.attribute_values('resource_'),
37
37
  document_id: document.object_id,
38
+ document_state: document.block_state,
38
39
  document_data: document.data,
39
40
  document_key: document.key,
40
41
  document_namespace: document.namespace,
@@ -25,7 +25,7 @@ module KManager
25
25
  include KLog::Logging
26
26
  include KDoc::Guarded
27
27
 
28
- ACTIONS = %i[load_content register_document load_document].freeze
28
+ ACTIONS = %i[load_content register_document preload_document load_document].freeze
29
29
 
30
30
  class << self
31
31
  def valid_action?(action)
@@ -42,6 +42,8 @@ module KManager
42
42
  # - :content_loaded
43
43
  # - :documents_registering
44
44
  # - :documents_registered
45
+ # - :documents_preloading
46
+ # - :documents_preloaded
45
47
  # - :documents_loading
46
48
  # - :documents_loaded
47
49
  attr_reader :status
@@ -102,9 +104,9 @@ module KManager
102
104
  end
103
105
 
104
106
  # TODO: Is this really needed?
105
- def document
106
- @document ||= documents&.first
107
- end
107
+ # def document
108
+ # @document ||= documents&.first
109
+ # end
108
110
 
109
111
  def activated?
110
112
  # log.section_heading("Am I activated?")
@@ -120,7 +122,8 @@ module KManager
120
122
  # @param [Symbol] action what action is to be fired
121
123
  # - :load_content for loading text content
122
124
  # - :register_document for registering 1 or more documents (name and namespace) against the resource
123
- # - :load_document for parsing the content into a document
125
+ # - :preload_document for parsing the content into a document
126
+ # - :load_document for finalizing the document load with met dependencies and action execution if applicable
124
127
  # rubocop:disable Metrics/CyclomaticComplexity
125
128
  def fire_action(action)
126
129
  # TODO: Write test for valid
@@ -131,20 +134,25 @@ module KManager
131
134
  load_content_action if alive?
132
135
  when :register_document
133
136
  register_document_action if content_loaded?
137
+ when :preload_document
138
+ preload_document_action if documents_registered?
134
139
  when :load_document
135
- load_document_action if documents_registered?
140
+ load_document_action if documents_preloaded?
136
141
  else
137
142
  log.warn "Action: '#{action}' is invalid for status: '#{status}'"
138
143
  end
139
144
  end
140
145
  # rubocop:enable Metrics/CyclomaticComplexity
141
146
 
147
+ # I don't think this is needed, it is never really used
142
148
  def fire_next_action
143
149
  if alive?
144
150
  fire_action(:load_content)
145
151
  elsif content_loaded?
146
152
  fire_action(:register_document)
147
153
  elsif documents_registered?
154
+ fire_action(:preload_document)
155
+ elsif documents_preloaded?
148
156
  fire_action(:load_document)
149
157
  end
150
158
  end
@@ -162,20 +170,30 @@ module KManager
162
170
  end
163
171
 
164
172
  def register_document
165
- # log.warn 'you need to implement register_document'
166
173
  KManager::Resources::ResourceDocumentFactory.create_documents(self)
167
174
  end
168
175
 
176
+ # rubocop:disable Lint/RescueException
177
+ def preload_document
178
+ documents.each(&:execute_block)
179
+ rescue Exception => e
180
+ guard(e.message)
181
+ debug
182
+ log.exception(e, style: KManager.opts.exception_style)
183
+ # log.exception(e, style: :short)
184
+ end
185
+ # rubocop:enable Lint/RescueException
186
+
169
187
  # rubocop:disable Lint/RescueException
170
188
  def load_document
171
- # log.warn 'you need to implement register_document'
172
189
  documents.each do |document|
173
190
  document.execute_block(run_actions: activated?)
174
191
  end
175
192
  rescue Exception => e
176
193
  guard(e.message)
177
194
  debug
178
- log.exception(e, style: :short)
195
+ log.exception(e, style: KManager.opts.exception_style)
196
+ # log.exception(e, style: :short)
179
197
  end
180
198
  # rubocop:enable Lint/RescueException
181
199
 
@@ -239,6 +257,10 @@ module KManager
239
257
  @status == :documents_registered
240
258
  end
241
259
 
260
+ def documents_preloaded?
261
+ @status == :documents_preloaded
262
+ end
263
+
242
264
  def documents_loaded?
243
265
  @status == :documents_loaded
244
266
  end
@@ -317,14 +339,18 @@ module KManager
317
339
  def register_document_action
318
340
  @status = :documents_registering
319
341
  register_document
320
- # document_factory.create_documents
321
342
  @status = :documents_registered
322
343
  end
323
344
 
345
+ def preload_document_action
346
+ @status = :documents_preloading
347
+ preload_document
348
+ @status = :documents_preloaded
349
+ end
350
+
324
351
  def load_document_action
325
352
  @status = :documents_loading
326
353
  load_document
327
- # document_factory.parse_content
328
354
  @status = :documents_loaded
329
355
  end
330
356
  end
@@ -89,6 +89,8 @@ module KManager
89
89
  # if documents.length > 0
90
90
  # resource.resource_type = KDsl::Resources::Resource::TYPE_RUBY_DSL
91
91
  # end
92
+ rescue Interrupt, SystemExit
93
+ raise
92
94
  rescue Exception => e
93
95
  # Report the error but still add the document so that you can see
94
96
  # it in the ResourceDocument list, it will be marked as Error
@@ -93,8 +93,13 @@ module KManager
93
93
  replace_resource = resource.recreate(resource)
94
94
  replace_resource.fire_action(:load_content)
95
95
  replace_resource.fire_action(:register_document)
96
+ replace_resource.fire_action(:preload_document)
96
97
  replace_resource.fire_action(:load_document)
97
98
  resource_set.replace(replace_resource)
99
+
100
+ # This is a bit of a hack, but it works for now
101
+ # TODO: I don't think is actually working.
102
+ attach_dependencies
98
103
  end
99
104
 
100
105
  def delete_resource(resource_uri)
@@ -146,6 +151,7 @@ module KManager
146
151
 
147
152
  load_content if actions.include?(:load_content)
148
153
  register_documents if actions.include?(:register_document)
154
+ preload_documents if actions.include?(:preload_document)
149
155
  load_documents if actions.include?(:load_document)
150
156
  end
151
157
 
@@ -167,18 +173,45 @@ module KManager
167
173
  end
168
174
  end
169
175
 
176
+ def preload_documents
177
+ # first pass will attempt to load every document, if a document has dependencies
178
+ # it will be loaded in a second pass after dependencies are available
179
+ resources.each do |resource|
180
+ resource.fire_action(:preload_document)
181
+ end
182
+
183
+ attach_dependencies
184
+ end
185
+
170
186
  def load_documents
187
+ # second pass will finalize any documents that were partially load due to dependencies
171
188
  resources.each do |resource|
172
189
  resource.fire_action(:load_document)
173
190
  end
174
191
  end
175
192
 
193
+ def find_document(tag)
194
+ resources.flat_map(&:documents).find { |d| d.tag == tag }
195
+ end
196
+
176
197
  def debug
177
198
  resources.each(&:debug)
199
+ nil
178
200
  end
179
201
 
180
202
  private
181
203
 
204
+ def attach_dependencies
205
+ documents_with_unmet_dependencies = resources.flat_map(&:documents).reject(&:dependencies_met?)
206
+
207
+ documents_with_unmet_dependencies.each do |document|
208
+ document.depend_on_tags.each do |tag|
209
+ dependant_document = find_document(tag)
210
+ document.resolve_dependency(dependant_document) if dependant_document
211
+ end
212
+ end
213
+ end
214
+
182
215
  def parse_uri(uri)
183
216
  return uri if uri.is_a?(URI)
184
217
  return URI.parse(uri) if uri =~ URI::ABS_URI # https://stackoverflow.com/questions/1805761/how-to-check-if-a-url-is-valid
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KManager
4
- VERSION = '0.0.24'
4
+ VERSION = '0.0.32'
5
5
  end