Module: AutoStacker24::Preprocessor

Defined in:
lib/autostacker24/template_preprocessor.rb

Class Method Summary collapse

Class Method Details

.parse_json(template) ⇒ Object



20
21
22
23
24
25
26
# File 'lib/autostacker24/template_preprocessor.rb', line 20

def self.parse_json(template)
  JSON(template)
rescue JSON::ParserError => e
  require 'json/pure' # pure ruby parser has better error diagnostics

  JSON(template)
  raise e
end

.parse_ref(token) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/autostacker24/template_preprocessor.rb', line 83

def self.parse_ref(token)
  m = /\A@([^\[]*)(\[([^,]*)(\s*,\s*(.*))?\])?$/.match(token)
  m1 = m[1]
  m2 = m[3]
  m3 = m[5]
  if m2
    args = if m3
              [m1, m2, m3]
           else
             [m1 + 'Map', '@' + m1, m2]
           end
    {'Fn::FindInMap' => [args[0], preprocess_string(args[1]), preprocess_string(args[2])]}
  else
    {'Ref' => m1}
  end
end

.parse_yaml(template) ⇒ Object



28
29
30
# File 'lib/autostacker24/template_preprocessor.rb', line 28

def self.parse_yaml(template)
  YAML.load(template)
end

.preprocess(template) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/autostacker24/template_preprocessor.rb', line 10

def self.preprocess(template)
  if template =~ /\A\s*\{/
    template
  elsif template =~ /\A\s*\/{2}/
    preprocess_json(parse_json(template)).to_json
  else
    preprocess_json(parse_yaml(template)).to_json
  end
end

.preprocess_json(json) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/autostacker24/template_preprocessor.rb', line 32

def self.preprocess_json(json)
  if json.is_a?(Hash)
    json.inject({}) do |m, (k, v)|
      if k == 'UserData' && v.is_a?(String)
        m.merge(k => preprocess_user_data(v))
      else
        m.merge(k => preprocess_json(v))
      end
    end
  elsif json.is_a?(Array)
    json.map{|v| preprocess_json(v)}
  elsif json.is_a?(String)
    preprocess_string(json)
  else
    json
  end
end

.preprocess_string(s) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/autostacker24/template_preprocessor.rb', line 54

def self.preprocess_string(s)
  m = /^@file:\/\/(.*)$/.match(s)
  s = File.read(m[1]) if m
  parts = tokenize(s).map do |token|
    case token
      when '@@' then '@'
      when '@[' then '['
      when /\A@/ then parse_ref(token)
      else token
    end
  end

  # merge neighboured strings

  parts = parts.reduce([])do |m, p|
    if m.last.is_a?(String) && p.is_a?(String)
      m[-1] += p
    else
      m << p
    end
    m
  end

  if parts.length == 1
    parts.first
  else # we need a join construct

    {'Fn::Join' => ['', parts]}
  end
end

.preprocess_user_data(s) ⇒ Object



50
51
52
# File 'lib/autostacker24/template_preprocessor.rb', line 50

def self.preprocess_user_data(s)
  {'Fn::Base64' => preprocess_string(s)}
end

.tokenize(s) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/autostacker24/template_preprocessor.rb', line 100

def self.tokenize(s)
  # for recursive bracket matching see

  # http://stackoverflow.com/questions/19486686/recursive-nested-matching-pairs-of-curly-braces-in-ruby-regex

  # but for we limit ourself to one level to make things less complex

  pattern = /@@|@\[|@(\w+(::\w+)?)(\[[^\]]*\])?/
  tokens = []
  loop do
    m = pattern.match(s)
    if m
      tokens << m.pre_match unless m.pre_match.empty?
      tokens << m.to_s
      s = m.post_match
    else
      tokens << s unless s.empty? && !tokens.empty?
      break
    end
  end
  tokens
end