Class: CfnDsl::Specification

Inherits:
Object
  • Object
show all
Defined in:
lib/cfndsl/specification.rb

Overview

Module for loading and patching a spec file

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Specification

Returns a new instance of Specification.



23
24
25
26
# File 'lib/cfndsl/specification.rb', line 23

def initialize(file)
  @file = file
  @spec = JSON.parse File.read(file)
end

Instance Attribute Details

#fileObject (readonly)

Returns the value of attribute file.



21
22
23
# File 'lib/cfndsl/specification.rb', line 21

def file
  @file
end

#specObject (readonly)

Returns the value of attribute spec.



21
22
23
# File 'lib/cfndsl/specification.rb', line 21

def spec
  @spec
end

Class Method Details

.load_file(file: CfnDsl.specification_file, specs: CfnDsl.additional_specs, patches: CfnDsl.specification_patches, fail_patches: false) ⇒ Object



10
11
12
13
14
15
# File 'lib/cfndsl/specification.rb', line 10

def self.load_file(file: CfnDsl.specification_file, specs: CfnDsl.additional_specs, patches: CfnDsl.specification_patches, fail_patches: false)
  specification = new(file)
  specs&.each { |spec| specification.merge_spec(JSON.parse(File.read(spec)), spec) }
  patches&.each { |patch| specification.patch_spec(JSON.parse(File.read(patch)), patch, fail_patches) }
  specification
end

.update_required?(version:, file: CfnDsl.specification_file) ⇒ Boolean

Returns:

  • (Boolean)


17
18
19
# File 'lib/cfndsl/specification.rb', line 17

def self.update_required?(version:, file: CfnDsl.specification_file)
  version.to_s == 'latest' || !File.exist?(file) || load_file(file: file, specs: nil, patches: nil).update_required?(version)
end

Instance Method Details

#default_broken_versionObject



45
46
47
# File 'lib/cfndsl/specification.rb', line 45

def default_broken_version
  @default_broken_version ||= Gem::Version.new('0.0.0')
end

#default_fixed_versionObject



41
42
43
# File 'lib/cfndsl/specification.rb', line 41

def default_fixed_version
  @default_fixed_version ||= version.bump
end

#merge_spec(spec_parsed, _from_file) ⇒ Object



59
60
61
62
63
64
# File 'lib/cfndsl/specification.rb', line 59

def merge_spec(spec_parsed, _from_file)
  return unless patch_required?(spec_parsed)

  spec['ResourceTypes'].merge!(spec_parsed['ResourceTypes'])
  spec['PropertyTypes'].merge!(spec_parsed['PropertyTypes'])
end

#patch_required?(patch) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
57
# File 'lib/cfndsl/specification.rb', line 53

def patch_required?(patch)
  broken = patch.key?('broken') ? Gem::Version.new(patch['broken']) : default_broken_version
  fixed = patch.key?('fixed') ? Gem::Version.new(patch['fixed']) : default_fixed_version
  broken <= version && version < fixed
end

#patch_spec(parsed_patch, from_file, fail_patches) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/cfndsl/specification.rb', line 66

def patch_spec(parsed_patch, from_file, fail_patches)
  return unless patch_required?(parsed_patch)

  parsed_patch.each_pair do |top_level_type, patches|
    next unless %w[ResourceTypes PropertyTypes].include?(top_level_type)

    patches.each_pair do |property_type_name, patch_details|
      applies_to = spec[top_level_type]
      unless property_type_name == 'patch'
        # Patch applies within a specific property type
        applies_to = applies_to[property_type_name]
        patch_details = patch_details['patch']
      end

      Hana::Patch.new(patch_details['operations']).apply(applies_to) if patch_required?(patch_details)
    rescue Hana::Patch::MissingTargetException => e
      raise "Failed specification patch #{top_level_type} #{property_type_name} from #{from_file}" if fail_patches

      warn "Ignoring failed specification patch #{top_level_type} #{property_type_name} from #{from_file} - #{e.class.name}:#{e.message}"
    end
  end
end

#resourcesObject



28
29
30
# File 'lib/cfndsl/specification.rb', line 28

def resources
  spec['ResourceTypes']
end

#typesObject



32
33
34
# File 'lib/cfndsl/specification.rb', line 32

def types
  spec['PropertyTypes']
end

#update_required?(needed_version) ⇒ Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/cfndsl/specification.rb', line 49

def update_required?(needed_version)
  needed_version.to_s == 'latest' || version < Gem::Version.new(needed_version || '0.0.0')
end

#versionGem::Version

Returns semantic version of the spec file.

Returns:

  • (Gem::Version)

    semantic version of the spec file



37
38
39
# File 'lib/cfndsl/specification.rb', line 37

def version
  @version ||= Gem::Version.new(spec['ResourceSpecificationVersion'] || '0.0.0')
end