sparkle_formation 3.0.34 → 3.0.36

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,6 +14,8 @@ class SparkleFormation
14
14
  "registry",
15
15
  ]
16
16
 
17
+ # @return [String] path to root of this library
18
+ SPARKLEFORMATION_ROOT_LIBRARY = File.dirname(File.dirname(File.dirname(__FILE__)))
17
19
  # @return [String] default stack resource name
18
20
  DEFAULT_STACK_RESOURCE = "AWS::CloudFormation::Stack"
19
21
  # @return [Array<String>] collection of valid stack resource types
@@ -199,6 +201,26 @@ class SparkleFormation
199
201
 
200
202
  alias_method :dynamic_information, :dynamic_info
201
203
 
204
+ # Extract the origin of the caller outside this library
205
+ #
206
+ # @param cinfo [Array<String>] caller info
207
+ # @return [Array<String, Integer>] caller path and line number
208
+ def extract_caller(cinfo)
209
+ res = cinfo.detect { |c|
210
+ !c.include?(SPARKLEFORMATION_ROOT_LIBRARY)
211
+ }.to_s.split(":")[0, 2]
212
+ if res.size != 2
213
+ line = res.last
214
+ if line.to_i.to_s != line
215
+ res << 0
216
+ end
217
+ if res != 2
218
+ res.unshift(:unknown)
219
+ end
220
+ end
221
+ res
222
+ end
223
+
202
224
  # Insert a dynamic into a context
203
225
  #
204
226
  # @param dynamic_name [String, Symbol] dynamic name
@@ -209,7 +231,15 @@ class SparkleFormation
209
231
  __t_stringish(registry_name)
210
232
  opts = args.detect { |item| item.is_a?(Hash) } || {}
211
233
  reg = struct._self.sparkle.get(:registry, registry_name, opts[:provider])
212
- struct.instance_exec(*args, &reg[:block])
234
+ record = struct._self.audit_log.push(
235
+ type: :registry,
236
+ name: registry_name,
237
+ location: reg[:block].source_location,
238
+ caller: extract_caller(caller),
239
+ )
240
+ struct._self.wrapped_audit(record) do
241
+ struct.instance_exec(*args, &reg[:block])
242
+ end
213
243
  end
214
244
 
215
245
  # Insert a dynamic into a context
@@ -226,22 +256,39 @@ class SparkleFormation
226
256
  dyn = struct._self.sparkle.get(:dynamic, dynamic_name, opts[:provider])
227
257
  opts = nil
228
258
  raise dyn if dyn.is_a?(Exception)
259
+ result = nil
229
260
  dyn.monochrome.each do |dynamic_item|
230
- if result
231
- opts = args.detect { |i| i.is_a?(Hash) }
232
- if opts
233
- opts[:previous_layer_result] = result
234
- else
235
- args.push(:previous_layer_result => result)
261
+ record = struct._self.audit_log.push(
262
+ type: :dynamic,
263
+ name: dynamic_name,
264
+ caller: extract_caller(caller),
265
+ location: dynamic_item[:block].source_location,
266
+ )
267
+ struct._self.wrapped_audit(record) do
268
+ if result
269
+ opts = args.detect { |i| i.is_a?(Hash) }
270
+ if opts
271
+ opts[:previous_layer_result] = result
272
+ else
273
+ args.push(:previous_layer_result => result)
274
+ end
236
275
  end
276
+ result = struct.instance_exec(*args, &dynamic_item[:block])
237
277
  end
238
- result = struct.instance_exec(*args, &dynamic_item[:block])
239
278
  end
240
279
  if block_given?
241
280
  result.instance_exec(&block)
242
281
  end
243
282
  rescue Error::NotFound::Dynamic
244
- result = builtin_insert(dynamic_name, struct, *args, &block)
283
+ record = struct._self.audit_log.push(
284
+ type: :dynamic,
285
+ name: dynamic_name,
286
+ location: [:builtin, 0],
287
+ caller: extract_caller(caller),
288
+ )
289
+ result = struct._self.wrapped_audit(record) do
290
+ builtin_insert(dynamic_name, struct, *args, &block)
291
+ end
245
292
  unless result
246
293
  message = "Failed to locate requested dynamic block for insertion: #{dynamic_name} " \
247
294
  "(valid: #{struct._self.sparkle.dynamics.fetch(struct._self.sparkle.provider, {}).keys.sort.join(", ")})"
@@ -286,24 +333,37 @@ class SparkleFormation
286
333
  args.map { |a| Bogo::Utility.snake(a) }.join("_"),
287
334
  ].flatten.compact.join("_").to_sym
288
335
  end
289
- resource_name = struct._process_key(resource_name.to_sym)
290
- nested_template = compile(to_nest[:path], :sparkle)
291
- nested_template.parent = struct._self
292
- nested_template.name = resource_name
293
- if options[:parameters]
294
- nested_template.compile_state = options[:parameters]
295
- end
296
- unless struct._self.sparkle.empty?
297
- nested_template.sparkle.apply(struct._self.sparkle)
298
- end
299
- nested_resource = struct.dynamic!(
300
- struct._self.stack_resource_type,
301
- resource_name,
302
- {:resource_name_suffix => nil},
303
- &block
336
+ record = struct._self.audit_log.push(
337
+ type: :template,
338
+ caller: extract_caller(caller),
339
+ name: resource_name,
340
+ location: to_nest[:path],
304
341
  )
305
- nested_resource.properties.stack nested_template
306
- nested_resource
342
+ struct._self.wrapped_audit(record) do
343
+ resource_name = struct._process_key(resource_name.to_sym)
344
+ nested_template = compile(to_nest[:path], :sparkle)
345
+ nested_template.parent = struct._self
346
+ nested_template.audit_log = record.audit_log
347
+ nested_template.name = resource_name
348
+ if options[:parameters]
349
+ nested_template.compile_state = options[:parameters]
350
+ end
351
+ unless struct._self.sparkle.empty?
352
+ nested_template.sparkle.apply(struct._self.sparkle)
353
+ end
354
+ nested_resource = struct.dynamic!(
355
+ struct._self.stack_resource_type,
356
+ resource_name,
357
+ {:resource_name_suffix => nil},
358
+ &block
359
+ )
360
+ # Ignore the stack resource that we generated in the
361
+ # audit log since the wrapping template record will
362
+ # provide the context with actual information
363
+ record.audit_log.list.pop
364
+ nested_resource.properties.stack nested_template
365
+ nested_resource
366
+ end
307
367
  end
308
368
 
309
369
  # Insert a builtin dynamic into a context
@@ -364,6 +424,8 @@ class SparkleFormation
364
424
 
365
425
  include Bogo::Memoization
366
426
 
427
+ # @return [AuditLog] records of template composition
428
+ attr_accessor :audit_log
367
429
  # @return [Symbol] name of formation
368
430
  attr_accessor :name
369
431
  # @return [Sparkle] parts store
@@ -379,7 +441,7 @@ class SparkleFormation
379
441
  # @return [Hash] parameters for stack generation
380
442
  attr_reader :parameters
381
443
  # @return [SparkleFormation] parent stack
382
- attr_accessor :parent
444
+ attr_reader :parent
383
445
  # @return [Array<String>] valid stack resource types
384
446
  attr_reader :stack_resource_types
385
447
  # @return [Hash] state hash for compile time parameters
@@ -456,9 +518,35 @@ class SparkleFormation
456
518
  if base_block
457
519
  load_block(base_block)
458
520
  end
521
+ @audit_log = AuditLog.new
459
522
  @compiled = nil
460
523
  end
461
524
 
525
+ # Set the parent template
526
+ #
527
+ # @param p [SparkleFormation] parent template
528
+ # @return [self]
529
+ def parent=(p)
530
+ unless p.is_a?(SparkleFormation)
531
+ raise TypeError, "Expected `SparkleFormation` but received `#{p.class.name}`"
532
+ end
533
+ @parent = p
534
+ @audit_log = p.audit_log
535
+ self
536
+ end
537
+
538
+ # Wrap given block within audit log of given record
539
+ #
540
+ # @param record [AuditLog::Record]
541
+ # @return [Object] result of yield
542
+ def wrapped_audit(record)
543
+ start_log = audit_log
544
+ @audit_log = record ? record.audit_log : start_log
545
+ yield
546
+ ensure
547
+ @audit_log = start_log
548
+ end
549
+
462
550
  # Update underlying data structures based on inherit
463
551
  # or layering behavior if defined for this template
464
552
  #
@@ -728,17 +816,50 @@ class SparkleFormation
728
816
  case item
729
817
  when Composition::Component
730
818
  if item.block
731
- self.class.build(compiled, &item.block)
819
+ if item.key == "__base__"
820
+ record = audit_log.push(
821
+ type: :template,
822
+ name: name,
823
+ location: item.block.source_location.first,
824
+ caller: [:template, 0],
825
+ ) if parent.nil?
826
+ else
827
+ record = audit_log.push(
828
+ type: :component,
829
+ name: item.key,
830
+ location: item.block.source_location.first,
831
+ caller: [:template, 0],
832
+ )
833
+ end
834
+ wrapped_audit(record) do
835
+ self.class.build(compiled, &item.block)
836
+ end
732
837
  else
733
838
  sparkle.get(:component, item.key).monochrome.each do |component_block|
734
- self.class.build(compiled, &component_block[:block])
839
+ record = audit_log.push(
840
+ type: :component,
841
+ name: item.key,
842
+ location: component_block[:block].source_location.first,
843
+ caller: [:template, 0],
844
+ )
845
+ wrapped_audit(record) do
846
+ self.class.build(compiled, &component_block[:block])
847
+ end
735
848
  end
736
849
  end
737
850
  when Composition::Override
851
+ record = audit_log.push(
852
+ type: :component,
853
+ name: :override,
854
+ location: item.block.source_location.first,
855
+ caller: [:template, 0],
856
+ )
738
857
  if item.args && !item.args.empty?
739
858
  compiled._set_state(item.args)
740
859
  end
741
- self.class.build(compiled, &item.block)
860
+ wrapped_audit(record) do
861
+ self.class.build(compiled, &item.block)
862
+ end
742
863
  end
743
864
  end
744
865
  if compile_state && !compile_state.empty?
@@ -1,5 +1,5 @@
1
1
  # Unicorns and rainbows
2
2
  class SparkleFormation
3
3
  # Current library version
4
- VERSION = Gem::Version.new("3.0.34")
4
+ VERSION = Gem::Version.new("3.0.36")
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sparkle_formation
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.34
4
+ version: 3.0.36
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-30 00:00:00.000000000 Z
11
+ date: 2019-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: attribute_struct
@@ -188,6 +188,7 @@ files:
188
188
  - docs/v/jquery-2.1.3.min.js
189
189
  - docs/v/loader.js
190
190
  - lib/sparkle_formation.rb
191
+ - lib/sparkle_formation/audit_log.rb
191
192
  - lib/sparkle_formation/aws.rb
192
193
  - lib/sparkle_formation/composition.rb
193
194
  - lib/sparkle_formation/error.rb