aws-cfn-dsl 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZDJlMWZlNmRjMmZjNmRiMjk3MzU5Zjk5MTYxZTVhNzk1NmE0YjU0Nw==
5
- data.tar.gz: !binary |-
6
- ZWFiMGM1NzE2NTExNDliMDVkZDA3NzliNmY2ZmY3NzBkYzkwMWRhYQ==
2
+ SHA1:
3
+ metadata.gz: c40097a8abb684000122cdd14227aec38bcc416b
4
+ data.tar.gz: eaf401cf08d69d21f74d40de25f97474aa73d696
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MzY1NzA5OTM3ZGFhOWM3NDM1NzEwMjIyMDA4MzNkNDAwODYwZjFkYjQ4MWIx
10
- MzcyOGFlOGFhNTEzZjU3YTdmMDg0N2Q0NjYxODUwYTI4ZGI5OGNkOGExM2Yw
11
- YzA5YjY3YjgxYzZjMTNkNjIyYmNiNTRhMjZlNmI1MmY5ODQ2ZjU=
12
- data.tar.gz: !binary |-
13
- ZDIzMTkxNzkzMzFmNTljMjJhNjA1MGI2Yzk2NTFkZmZhYjI2ZGMwZjNhZGRm
14
- YzY0NmU2YWU1MWE4NThjMjRhZDFhZTI5MDU4NWE5NjI3NmFmMWU0ZGRiNjVi
15
- Y2RmZjgxZDNkNjIyZDMwNDk1NDEyZmU1ZjhlZDE4MGZhZDQ5OWU=
6
+ metadata.gz: d80906483c8db621505162efbe96531e6c73b73b158b76e1e59a09687b8039a02dd45696006a8887502c07eee5404dc426ba6a96f2d2d90b377484b927219615
7
+ data.tar.gz: a413157cbdad632905f84e0f034bef262ebbaafd8cc00a128a4b8897ed65e4b648544c2e40a5006feebe6ef4ba99247ba5891de4f617347f4491f1bef3e1b664
data/Gemfile CHANGED
@@ -2,3 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in aws-cfn-dsl.gemspec
4
4
  gemspec
5
+
6
+ gem 'cloudformation-ruby-dsl', :path => '../cloudformation-ruby-dsl', :group => :development
7
+ gem 'slop', :group => :development
8
+
9
+ gem 'json_pure', :group => :development
10
+ gem 'bundler', '~> 1.5', :group => :development
11
+ gem 'rake', :group => :development
data/aws-cfn-dsl.gemspec CHANGED
@@ -18,11 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "awesome_print"
22
- spec.add_dependency "json"
23
- spec.add_dependency 'cloudformation-ruby-dsl', "~> 0.4", ">= 0.4.2"
21
+ spec.add_dependency 'awesome_print'
22
+ spec.add_dependency 'json'
23
+ spec.add_dependency 'cloudformation-ruby-dsl', '~> 0.4', '>= 0.4.3'
24
+ spec.add_dependency "slop"
24
25
 
25
- spec.add_development_dependency "json_pure"
26
- spec.add_development_dependency 'bundler', "~> 1.5"
27
- spec.add_development_dependency 'rake'
28
26
  end
data/aws-cfn-dsl.iml CHANGED
@@ -3,24 +3,18 @@
3
3
  <component name="CompassSettings">
4
4
  <option name="compassSupportEnabled" value="true" />
5
5
  </component>
6
- <component name="FacetManager">
7
- <facet type="gem" name="Ruby Gem">
8
- <configuration>
9
- <option name="GEM_APP_ROOT_PATH" value="$MODULE_DIR$" />
10
- <option name="GEM_APP_TEST_PATH" value="$MODULE_DIR$/test" />
11
- <option name="GEM_APP_LIB_PATH" value="$MODULE_DIR$/lib" />
12
- </configuration>
13
- </facet>
14
- </component>
15
6
  <component name="NewModuleRootManager" inherit-compiler-output="true">
16
7
  <exclude-output />
17
- <content url="file://$MODULE_DIR$">
18
- <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
19
- </content>
20
- <orderEntry type="jdk" jdkName="RVM: ruby-1.9.3-p545 [aws-cfn-dsl]" jdkType="RUBY_SDK" />
8
+ <content url="file://$MODULE_DIR$" />
9
+ <orderEntry type="inheritedJdk" />
21
10
  <orderEntry type="sourceFolder" forTests="false" />
22
- <orderEntry type="library" scope="PROVIDED" name="bundler (v1.6.1, RVM: ruby-1.9.3-p545 [aws-cfn-dsl]) [gem]" level="application" />
23
- <orderEntry type="library" scope="PROVIDED" name="rake (v0.9.2.2, RVM: ruby-1.9.3-p545 [aws-cfn-dsl]) [gem]" level="application" />
11
+ <orderEntry type="module" module-name="cloudformation-ruby-dsl" />
12
+ <orderEntry type="library" scope="PROVIDED" name="awesome_print (v1.2.0, RVM: ruby-1.9.3-p547 [aws-cfn-compile]) [gem]" level="application" />
13
+ <orderEntry type="library" scope="PROVIDED" name="detabulator (v0.1.0, RVM: ruby-1.9.3-p547 [aws-cfn-compile]) [gem]" level="application" />
14
+ <orderEntry type="library" scope="PROVIDED" name="json (v1.8.1, RVM: ruby-1.9.3-p547 [aws-cfn-compile]) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="json_pure (v1.8.1, RVM: ruby-1.9.3-p547 [aws-cfn-compile]) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="rake (v10.3.2, RVM: ruby-1.9.3-p547 [aws-cfn-compile]) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="slop (v3.5.0, RVM: ruby-1.9.3-p547 [aws-cfn-compile]) [gem]" level="application" />
24
18
  </component>
25
19
  </module>
26
20
 
data/bin/cfn-dsl ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ path = File.dirname(__FILE__)
6
+ if File.exists?("#{path}/../.gitignore")
7
+ %w(aws-cfn-decompiler aws-cfn-compiler cloudformation-ruby-dsl).each do |mod|
8
+ add_path = File.expand_path(File.join(path, "../../#{mod}", "lib"))
9
+ $:.unshift(add_path)
10
+ end
11
+ else
12
+ # Borrowing from "whiches" gem ...
13
+ cmd = File.basename(__FILE__, '.rb')
14
+ exes = []
15
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
16
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
17
+ exts.each { |ext|
18
+ exe = File.join(path, "#{cmd}#{ext}")
19
+ exes << exe if File.executable? exe
20
+ }
21
+ end
22
+ if exes.size > 0
23
+ path = File.dirname(exes[0])
24
+ end
25
+
26
+ end
27
+ add_path = File.expand_path(File.join(path, "..", "lib"))
28
+ $:.unshift(add_path)
29
+
30
+ require 'aws/cfn/dsl'
31
+ Aws::Cfn::Dsl::Main.new.run
data/lib/aws/cfn/dsl.rb CHANGED
@@ -1,9 +1,7 @@
1
- require "aws/cfn/dsl/version"
1
+ require 'json'
2
+ require 'ap'
3
+ require 'yaml'
2
4
 
3
- module Aws
4
- module Cfn
5
- module Dsl
6
- # Your code goes here...
7
- end
8
- end
9
- end
5
+ require "aws/cfn/dsl/version"
6
+ require "aws/cfn/dsl/base"
7
+ require "aws/cfn/dsl/main"
@@ -0,0 +1,355 @@
1
+ require "aws/cfn/decompiler"
2
+ require "aws/cfn/dsl/fncall"
3
+
4
+ module Aws
5
+ module Cfn
6
+ module Dsl
7
+ class Base < Aws::Cfn::DeCompiler::Base
8
+
9
+ def initialize
10
+ @output = []
11
+ end
12
+
13
+ def simplify(val)
14
+ if val.is_a?(Hash)
15
+ val = Hash[val.map { |k,v| [k, simplify(v)] }]
16
+ if val.length != 1
17
+ val
18
+ else
19
+ k, v = val.entries[0]
20
+ case
21
+ # CloudFormation functions
22
+ # when k == 'Fn::Base64'
23
+ # FnCall.new 'base64', [v], true
24
+ # when k == 'Fn::FindInMap'
25
+ # FnCall.new 'find_in_map', v
26
+ # when k == 'Fn::GetAtt'
27
+ # FnCall.new 'get_att', v
28
+ # when k == 'Fn::GetAZs'
29
+ # FnCall.new 'get_azs', v != '' ? [v] : []
30
+ # when k == 'Fn::Join'
31
+ # FnCall.new 'join', [v[0]] + v[1], true
32
+ # when k == 'Fn::Select'
33
+ # FnCall.new 'select', v
34
+ # when k == 'Ref' && v == 'AWS::Region'
35
+ # FnCall.new 'aws_region', []
36
+ # when k == 'Ref' && v == 'AWS::StackName'
37
+ # FnCall.new 'aws_stack_name', []
38
+ # CloudFormation internal references
39
+ # when k == 'Ref'
40
+ # FnCall.new 'ref', [v]
41
+ # Aws::Cfn::DSL functions
42
+ when k.match(%r'^Aws::Cfn::DSL')
43
+ FnCall.new k, [v]
44
+ else
45
+ val
46
+ end
47
+ end
48
+ elsif val.is_a?(Array)
49
+ val.map { |v| simplify(v) }
50
+ else
51
+ val
52
+ end
53
+ end
54
+
55
+ def pprint(val)
56
+ case detect_type(val)
57
+ when :template
58
+ pprint_cfn_template(val)
59
+ when :parameter
60
+ pprint_cfn_section 'parameter', 'TODO', val, 'Parameters'
61
+ when :resource
62
+ pprint_cfn_resource 'TODO', val
63
+ when :parameters
64
+ val.each { |k, v| pprint_cfn_section 'parameter', k, v, 'Parameters' }
65
+ when :resources
66
+ val.each { |k, v| pprint_cfn_resource k, v }
67
+ else
68
+ pprint_value(val, '')
69
+ end
70
+ end
71
+
72
+ protected
73
+
74
+ def write(*s)
75
+ if s.is_a?(Array)
76
+ s = s.join('')
77
+ end
78
+ if @output.size > 0
79
+ @output[0].write s
80
+ else
81
+ print s
82
+ end
83
+ end
84
+
85
+ def writeln(s='')
86
+ if @output.size > 0
87
+ @output[0].puts s
88
+ else
89
+ puts s
90
+ end
91
+ end
92
+
93
+ # Attempt to figure out what fragment of the template we have. This is imprecise and can't
94
+ # detect Mappings and Outputs sections reliably, so it doesn't attempt to.
95
+ def detect_type(val)
96
+ if val.is_a?(Hash) && val['AWSTemplateFormatVersion']
97
+ :template
98
+ elsif val.is_a?(Hash) && /^(String|Number)$/ =~ val['Type']
99
+ :parameter
100
+ elsif val.is_a?(Hash) && val['Type']
101
+ :resource
102
+ elsif val.is_a?(Hash) && val.values.all? { |v| detect_type(v) == :parameter }
103
+ :parameters
104
+ elsif val.is_a?(Hash) && val.values.all? { |v| detect_type(v) == :resource }
105
+ :resources
106
+ end
107
+ end
108
+
109
+ def pprint_cfn_template(tpl)
110
+ open_output('',File.basename(@opts[:template].gsub(%r'\.(json|yaml|rb)'i,'')))
111
+ writeln "#!/usr/bin/env ruby"
112
+ writeln
113
+ if @opts[:output]
114
+ writeln "$:.unshift(File.dirname(__FILE__))"
115
+ # noinspection RubyExpressionInStringInspection
116
+ writeln '$:.unshift File.absolute_path("#{File.dirname(__FILE__)}/../lib")'
117
+ end
118
+ writeln "require 'bundler/setup'"
119
+ writeln "require 'aws/cfn/dsl/template'"
120
+ #writeln "require 'cloudformation-ruby-dsl/spotprice'"
121
+ # writeln "require 'cloudformation-ruby-dsl/table'"
122
+ writeln
123
+ writeln "template do"
124
+ writeln
125
+ tpl.each do |section, v|
126
+ case section
127
+ when 'Parameters'
128
+ when 'Mappings'
129
+ when 'Resources'
130
+ when 'Outputs'
131
+ else
132
+ write " value #{fmt_key(section)} => "
133
+ pprint_value v, ' '
134
+ writeln
135
+ writeln
136
+ end
137
+ end
138
+ %w(Mappings Parameters Resources Outputs).each do |section|
139
+ writeln " # #{section}"
140
+ v = tpl[section]
141
+ case section
142
+ when 'Parameters'
143
+ v.each { |name, options| pprint_cfn_section 'parameter', name, options, 'Parameters' }
144
+ when 'Mappings'
145
+ v.each { |name, options| pprint_cfn_section 'mapping', name, options, 'Mappings' }
146
+ when 'Resources'
147
+ v.each { |name, options| pprint_cfn_resource name, options }
148
+ when 'Outputs'
149
+ v.each { |name, options| pprint_cfn_section 'output', name, options, 'Outputs' }
150
+ else
151
+ raise "Internal Error: Unexpected section '#{section}'"
152
+ end
153
+ writeln
154
+ end
155
+ writeln "end.exec!"
156
+ end
157
+
158
+ def open_output(subdir,name)
159
+ if @opts[:output]
160
+ file = rb_file(subdir, name)
161
+
162
+ @output.unshift File.open(file, 'w')
163
+ end
164
+ end
165
+
166
+ def add_brick(subdir,name)
167
+ if @opts[:output]
168
+ #file = rb_file(subdir, name).gsub(%r'^#{@opts[:output]}/','')
169
+ #writeln " file '#{file}'"
170
+ s = subdir.downcase.gsub(%r's$','')
171
+ writeln " #{s} '#{name}'"
172
+ end
173
+ end
174
+
175
+ def rb_file(subdir, name)
176
+ path = File.join(@opts[:output], subdir)
177
+ unless File.directory? path
178
+ Dir.mkdir path
179
+ end
180
+ file = File.join(path, "#{name}.rb")
181
+ end
182
+
183
+ def close_output()
184
+ if @opts[:output] and @output.size > 0
185
+ fp = @output.shift
186
+ fp.close
187
+ end
188
+ end
189
+
190
+ def pprint_cfn_section(section, name, options, subdir)
191
+ open_output(subdir,name)
192
+ write " #{section} #{fmt_string(name)}"
193
+ indent = ' ' + (' ' * section.length) + ' '
194
+ options.each do |k, v|
195
+ writeln ","
196
+ write indent, fmt_key(k), " => "
197
+ pprint_value v, indent
198
+ end
199
+ writeln
200
+ writeln
201
+ close_output
202
+ add_brick(subdir,name)
203
+ end
204
+
205
+ def pprint_cfn_resource(name, options)
206
+ subdir = 'Resources'
207
+ open_output(subdir,name)
208
+ write " resource #{fmt_string(name)}"
209
+ indent = ' '
210
+ options.each do |k, v|
211
+ unless k == 'Properties'
212
+ write ", #{fmt_key(k)} => #{fmt(v)}"
213
+ end
214
+ end
215
+ if options.key?('Properties')
216
+ write ", #{fmt_key('Properties')} => "
217
+ pprint_value options['Properties'], indent
218
+ end
219
+ writeln
220
+ writeln
221
+ close_output
222
+ add_brick(subdir,name)
223
+ end
224
+
225
+ def pprint_value(val, indent)
226
+ # Prefer to write the value on a single line if it's reasonable to do so
227
+ single_line = is_single_line(val) || is_single_line_hack(val)
228
+ if single_line && !is_multi_line_hack(val)
229
+ s = fmt(val)
230
+ if s.length < 120 || is_single_line_hack(val)
231
+ write s
232
+ return
233
+ end
234
+ end
235
+
236
+ # Print the value across multiple lines
237
+ if val.is_a?(Hash)
238
+ writeln "{"
239
+ val.each do |k, v|
240
+ write "#{indent} #{fmt_key(k)} => "
241
+ pprint_value v, indent + ' '
242
+ writeln ","
243
+ end
244
+ write "#{indent}}"
245
+
246
+ elsif val.is_a?(Array)
247
+ writeln "["
248
+ val.each do |v|
249
+ write "#{indent} "
250
+ pprint_value v, indent + ' '
251
+ writeln ","
252
+ end
253
+ write "#{indent}]"
254
+
255
+ elsif val.is_a?(FnCall) && val.multiline
256
+ write val.name, "("
257
+ args = val.arguments
258
+ sep = ''
259
+ sub_indent = indent + ' '
260
+ if val.name == 'join' && args.length > 1
261
+ pprint_value args[0], indent + ' '
262
+ args = args[1..-1]
263
+ sep = ','
264
+ sub_indent = indent + ' '
265
+ end
266
+ unless args.empty?
267
+ args.each do |v|
268
+ writeln sep
269
+ write sub_indent
270
+ pprint_value v, sub_indent
271
+ sep = ','
272
+ end
273
+ if val.name == 'join' && args.length > 1
274
+ write ","
275
+ end
276
+ writeln
277
+ write indent
278
+ end
279
+ write ")"
280
+
281
+ else
282
+ write fmt(val)
283
+ end
284
+ end
285
+
286
+ def is_single_line(val)
287
+ if val.is_a?(Hash)
288
+ is_single_line(val.values)
289
+ elsif val.is_a?(Array)
290
+ val.empty? ||
291
+ (val.length == 1 && is_single_line(val[0]) && !val[0].is_a?(Hash)) ||
292
+ val.all? { |v| v.is_a?(String) }
293
+ else
294
+ true
295
+ end
296
+ end
297
+
298
+ # Emo-specific hacks to force the desired output formatting
299
+ def is_single_line_hack(val)
300
+ is_array_of_strings_hack(val)
301
+ end
302
+
303
+ # Emo-specific hacks to force the desired output formatting
304
+ def is_multi_line_hack(val)
305
+ val.is_a?(Hash) && val['email']
306
+ end
307
+
308
+ # Emo-specific hacks to force the desired output formatting
309
+ def is_array_of_strings_hack(val)
310
+ val.is_a?(Array) && val.all? { |v| v.is_a?(String) } && val.grep(/\s/).empty? && (
311
+ val.include?('autoscaling:EC2_INSTANCE_LAUNCH') ||
312
+ val.include?('m1.small')
313
+ )
314
+ end
315
+
316
+ def fmt(val)
317
+ if val == {}
318
+ '{}'
319
+ elsif val == []
320
+ '[]'
321
+ elsif val.is_a?(Hash)
322
+ '{ ' + (val.map { |k,v| fmt_key(k) + ' => ' + fmt(v) }).join(', ') + ' }'
323
+ elsif val.is_a?(Array) && is_array_of_strings_hack(val)
324
+ '%w(' + val.join(' ') + ')'
325
+ elsif val.is_a?(Array)
326
+ '[ ' + (val.map { |v| fmt(v) }).join(', ') + ' ]'
327
+ elsif val.is_a?(FnCall) && val.arguments.empty?
328
+ val.name
329
+ elsif val.is_a?(FnCall)
330
+ val.name + '(' + (val.arguments.map { |v| fmt(v) }).join(', ') + ')'
331
+ elsif val.is_a?(String)
332
+ fmt_string(val)
333
+ elsif val == nil
334
+ 'null'
335
+ else
336
+ val.to_s # number, boolean
337
+ end
338
+ end
339
+
340
+ def fmt_key(s)
341
+ ':' + (/^[a-zA-Z_]\w+$/ =~ s ? s : fmt_string(s)) # returns a symbol like :Foo or :'us-east-1'
342
+ end
343
+
344
+ def fmt_string(s)
345
+ if /[^ -~]/ =~ s
346
+ s.dump # contains, non-ascii or control char, return double-quoted string
347
+ else
348
+ '\'' + s.gsub(/([\\'])/, '\\\\\1') + '\'' # return single-quoted string, escape \ and '
349
+ end
350
+ end
351
+
352
+ end
353
+ end
354
+ end
355
+ end