aws-cfn-dsl 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- OTVjY2UxNTJiYmQyZjgzYmQ2M2NhYzljZDE2NGRkMWU3ZGY3YzBjZA==
5
- data.tar.gz: !binary |-
6
- NTdkNGVhNWQ5NzRhMTVmNjA3ZTA4Y2QzOGZhOWM3N2IxYTc3ODk1OA==
2
+ SHA1:
3
+ metadata.gz: b9ba230058f9ce82bf26b89f880d91fe995fe42f
4
+ data.tar.gz: f2e68182943d453d15ff62e516fe6afdc74a3f7b
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- OTYzNDdmODQ2ODNkZTUxMjMzZDExYzU0ZTM4M2UwM2VjZjQ5YzVkNGM3NDk2
10
- ZTc2ZTBhZjc4MTU3OGY3ODlkYzMzOWMzYmMwM2U1Yjc1MGZlZmVhYTVmN2Vm
11
- MTMxYTI3MWM3MDMzYWVkYjllNTRkZWEyOGQ4MjRjMGQ5MWEzYTk=
12
- data.tar.gz: !binary |-
13
- NzFjZjgyNmJlNzcxOTMwNzUwZTk4NmMyZTg3NDRiM2JiNjQ3ZmQzNDM3MmEz
14
- NGJmNWYyZWI0NDhiYjBmZGJiOGY5NDMyMTE0YTNlNmQ1MjNlODZmMTU0YTBm
15
- NWMxMDMwYTQ3MmQ5NGY0ZmViOGUwZDZjODdhMTJiMDcwMzYwYTY=
6
+ metadata.gz: 3bd00bf073fe8842760c5727baf1828660df3699ca5c4be19bdf23ca9715ab74de6cd2b3e9031bf26a08e5d9fb8b7198f3e41c1b6acf1a8136b766b0c8b79768
7
+ data.tar.gz: 0e0e5bd09a2bfdc3218a91a3e2a9929882581837b92fad3861e8f333abc336a642169aa80c614916b760ecab6598095d82c6657574f5548f9ec391dc0353640f
data/Gemfile CHANGED
@@ -12,8 +12,6 @@ gem 'aws-cfn-compiler', :path => '../aws-cfn-compiler', :group => :development
12
12
  gem 'aws-cfn-yats', :path => '../aws-cfn-yats', :group => :development
13
13
  gem 'aws-cfn-stacker', :path => '../aws-cfn-stacker', :group => :development
14
14
 
15
- gem 'slop', :group => :development
16
-
17
15
  gem 'json_pure', :group => :development
18
16
  gem 'bundler', '~> 1.5', :group => :development
19
17
  gem 'rake', :group => :development
@@ -18,9 +18,10 @@ 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'
21
+ spec.add_dependency 'awesome_print', '~> 1.2', '>= 1.2.0'
22
+ spec.add_dependency 'psych'
22
23
  spec.add_dependency 'json'
24
+ spec.add_dependency 'slop'
23
25
  spec.add_dependency 'cloudformation-ruby-dsl', '~> 0.4', '>= 0.4.3'
24
- spec.add_dependency "slop"
25
26
 
26
27
  end
@@ -7,7 +7,7 @@ module Aws
7
7
  module Dsl
8
8
  class Base
9
9
  attr_accessor :items
10
- attr_reader :output
10
+ attr_reader :template
11
11
 
12
12
  require 'dldinternet/mixlib/logging'
13
13
  include DLDInternet::Mixlib::Logging
@@ -17,30 +17,42 @@ module Aws
17
17
  @output = []
18
18
  @config ||= {}
19
19
 
20
- lcs = ::Logging::ColorScheme.new( 'compiler', :levels => {
21
- :trace => :blue,
22
- :debug => :cyan,
23
- :info => :green,
24
- :step => :green,
25
- :warn => :yellow,
26
- :error => :red,
27
- :fatal => :red,
28
- :todo => :purple,
29
- })
30
- scheme = lcs.scheme
31
- scheme['trace'] = "\e[38;5;33m"
32
- scheme['fatal'] = "\e[38;5;89m"
33
- scheme['todo'] = "\e[38;5;55m"
34
- lcs.scheme scheme
35
- @config[:log_opts] = lambda{|mlll| {
36
- :pattern => "%#{mlll}l: %m %C\n",
37
- :date_pattern => '%Y-%m-%d %H:%M:%S',
38
- :color_scheme => 'compiler'
20
+ # noinspection RubyStringKeysInHashInspection
21
+ @formats = {
22
+ 'yaml' => 'yaml',
23
+ 'yml' => 'yaml',
24
+ 'yts' => 'yaml',
25
+ 'ytf' => 'yaml',
26
+ 'ytp' => 'yaml',
27
+ 'json' => 'json',
28
+ 'jml' => 'json',
29
+ 'jts' => 'json',
30
+ 'jtf' => 'json',
31
+ 'jtp' => 'json',
32
+ 'tpl' => 'json',
33
+ 'template' => 'json',
34
+ 'ruby' => 'ruby',
35
+ 'rb' => 'ruby',
39
36
  }
40
- }
41
- @config[:log_level] = :info
42
- @logger = getLogger(@config)
43
37
 
38
+
39
+ end
40
+
41
+ def ext2format(ext)
42
+ @formats.has_key? ext ? @formats[ext] : nil
43
+ end
44
+
45
+ def format2exts(format)
46
+ exts = @formats.select{ |_,v| v == format }
47
+ if exts.size > 0
48
+ exts.keys
49
+ else
50
+ []
51
+ end
52
+ end
53
+
54
+ def formats_compatible?(format, match)
55
+ @formats[match] == @formats[format]
44
56
  end
45
57
 
46
58
  def save_dsl(path=nil,parts=@items)
@@ -50,11 +62,13 @@ module Aws
50
62
 
51
63
  def load_template(file=nil)
52
64
  if file
53
- logStep "Loading #{file}"
65
+ filn = File.join(File.dirname(file), file)
66
+ filn = File.expand_path(file) if @config[:expandedpaths]
67
+ logStep "Loading #{filn}"
54
68
  begin
55
69
  abs = File.absolute_path(File.expand_path(file))
56
- unless File.exists?(abs) or @opts[:output].nil?
57
- abs = File.absolute_path(File.expand_path(File.join(@opts[:output],file)))
70
+ unless File.exists?(abs) or @config[:directory].nil?
71
+ abs = File.absolute_path(File.expand_path(File.join(@config[:directory],file)))
58
72
  end
59
73
  rescue
60
74
  # pass
@@ -71,78 +85,13 @@ module Aws
71
85
  else
72
86
  abort! "Unable to open template: #{abs}"
73
87
  end
74
- end
75
- end
76
-
77
- protected
78
-
79
- def simplify(val,start=false)
80
- logStep "Simplify a block ..." if start
81
- if val.is_a?(Hash)
82
- val = Hash[val.map { |k,v| [k, simplify(v)] }]
83
- if val.length != 1
84
- val
85
- else
86
- k, v = val.entries[0]
87
- case @opts[:functions]
88
- when /1|on|set|enable|yes|true/ then
89
- case
90
- # CloudFormation functions
91
- when k == 'Fn::Base64'
92
- FnCall.new 'base64', [v], true
93
- when k == 'Fn::FindInMap'
94
- FnCall.new 'find_in_map', v
95
- when k == 'Fn::GetAtt'
96
- FnCall.new 'get_att', v
97
- when k == 'Fn::GetAZs'
98
- FnCall.new 'get_azs', v != '' ? [v] : []
99
- when k == 'Fn::Join'
100
- FnCall.new 'join', [v[0]] + v[1], true
101
- when k == 'Fn::Select'
102
- FnCall.new 'select', v
103
- when k == 'Ref' && v == 'AWS::Region'
104
- FnCall.new 'aws_region', []
105
- when k == 'Ref' && v == 'AWS::StackName'
106
- FnCall.new 'aws_stack_name', []
107
- # CloudFormation internal references
108
- when k == 'Ref'
109
- FnCall.new 'ref', [v]
110
- else
111
- val
112
- end
113
- else
114
- val
115
- end
116
- end
117
- elsif val.is_a?(Array)
118
- val.map { |v| simplify(v) }
88
+ @items
119
89
  else
120
- val
121
- end
122
- end
123
-
124
- def pprint(val)
125
- logStep "Pretty print ..."
126
- case detect_type(val)
127
- when :template
128
- pprint_cfn_template(val)
129
- when :parameter
130
- pprint_cfn_section 'parameter', 'TODO', val, 'Parameters'
131
- when :resource
132
- pprint_cfn_resource 'TODO', val
133
- when :parameters
134
- val.each { |k, v| pprint_cfn_section 'parameter', k, v, 'Parameters' }
135
- when :resources
136
- val.each { |k, v| pprint_cfn_resource k, v }
137
- else
138
- pprint_value(val, '')
90
+ nil
139
91
  end
140
92
  end
141
93
 
142
- def module_name(parts=-1)
143
- name = self.class.to_s.split("::")
144
- name[0..parts-1].join('::')
145
- end
94
+ protected
146
95
 
147
96
  def abort!(msg=nil,rc=1)
148
97
  @logger.error msg if msg
@@ -150,361 +99,24 @@ module Aws
150
99
  exit rc
151
100
  end
152
101
 
153
- def write(*s)
154
- if s.is_a?(Array)
155
- s = s.join('')
156
- end
157
- if @output.size > 0
158
- @output[0].write s
159
- else
160
- print s
161
- end
162
- end
163
-
164
- def writeln(s='')
165
- if @output.size > 0
166
- @output[0].puts s
167
- else
168
- puts s
169
- end
170
- end
171
-
172
- # Attempt to figure out what fragment of the template we have. This is imprecise and can't
173
- # detect Mappings and Outputs sections reliably, so it doesn't attempt to.
174
- def detect_type(val)
175
- if val.is_a?(Hash) && val['AWSTemplateFormatVersion']
176
- :template
177
- elsif val.is_a?(Hash) && /^(String|Number)$/ =~ val['Type']
178
- :parameter
179
- elsif val.is_a?(Hash) && val['Type']
180
- :resource
181
- elsif val.is_a?(Hash) && val.values.all? { |v| detect_type(v) == :parameter }
182
- :parameters
183
- elsif val.is_a?(Hash) && val.values.all? { |v| detect_type(v) == :resource }
184
- :resources
185
- end
186
- end
187
-
188
- def pprint_cfn_template(tpl)
189
- file = File.basename(@opts[:template]).gsub(%r'\.(json|yaml|js|yaml)$'i, '.rb')
190
- # noinspection RubyParenthesesAroundConditionInspection
191
- if (iam = open_output('', file.gsub(%r'\.(json|yaml|js|yml|rb)'i, '')))
192
- logStep "Saving #{file}"
193
- writeln "#!/usr/bin/env ruby"
194
- print_maintainer('')
195
- writeln
196
- if @opts[:output]
197
- writeln "$:.unshift(File.dirname(__FILE__))"
198
- # noinspection RubyExpressionInStringInspection
199
- writeln '$:.unshift File.absolute_path("#{File.dirname(__FILE__)}/../lib")'
200
- end
201
- writeln "require 'bundler/setup'"
202
- writeln "require 'aws/cfn/dsl/template'"
203
- #writeln "require 'cloudformation-ruby-dsl/spotprice'"
204
- #writeln "require 'cloudformation-ruby-dsl/table'"
205
- writeln
206
- writeln "template do"
207
- writeln
208
- tpl.each do |section, v|
209
- case section
210
- when 'Parameters'
211
- when 'Mappings'
212
- when 'Resources'
213
- when 'Outputs'
214
- else
215
- write " value #{fmt_key(section)} => "
216
- pprint_value v, ' '
217
- writeln
218
- writeln
219
- end
220
- end
221
- else
222
- @logger.warn "Not overwriting template: '#{file}'"
223
- end
224
- %w(Mappings Parameters Resources Outputs).each do |section|
225
- writeln " # #{section}" if iam
226
- v = tpl[section]
227
- case section
228
- when 'Parameters'
229
- v.each { |name, options| pprint_cfn_section 'parameter', name, options, 'Parameters', iam }
230
- when 'Mappings'
231
- v.each { |name, options| pprint_cfn_section 'mapping', name, options, 'Mappings', iam }
232
- when 'Resources'
233
- v.each { |name, options| pprint_cfn_resource name, options, iam }
234
- when 'Outputs'
235
- v.each { |name, options| pprint_cfn_section 'output', name, options, 'Outputs', iam }
236
- else
237
- abort! "Internal Error: Unexpected section '#{section}'"
238
- end
239
- writeln if iam
240
- end
241
- writeln "end.exec!" if iam
242
- end
243
-
244
- def open_output(subdir,name)
245
- if @opts[:output]
246
- file = rb_file(subdir, name)
247
- if i_am_maintainer(file)
248
- @output.unshift File.open(file, 'w')
249
- true
250
- else
251
- false
252
- end
253
- else
254
- true
255
- end
256
- end
102
+ require "aws/cfn/dsl/mixins/options"
103
+ include Aws::Cfn::Dsl::Options
257
104
 
258
- def add_brick(subdir,name)
259
- if @opts[:output]
260
- #file = rb_file(subdir, name).gsub(%r'^#{@opts[:output]}/','')
261
- #writeln " file '#{file}'"
262
- s = subdir.downcase.gsub(%r's$','')
263
- writeln " #{s} '#{name}'"
264
- end
265
- end
105
+ require "aws/cfn/dsl/mixins/maintainer"
106
+ include Aws::Cfn::Dsl::Maintainer
266
107
 
267
- def rb_file(subdir, name)
268
- path = File.join(@opts[:output], subdir)
269
- unless File.directory? path
270
- Dir.mkdir path
271
- end
272
- file = File.join(path, "#{name}.rb")
273
- end
108
+ require "aws/cfn/dsl/mixins/simplify"
109
+ include Aws::Cfn::Dsl::Simplify
274
110
 
275
- def close_output()
276
- if @opts[:output] and @output.size > 0
277
- fp = @output.shift
278
- fp.close
279
- end
280
- end
111
+ require "aws/cfn/dsl/mixins/prettyprint"
112
+ include Aws::Cfn::Dsl::PrettyPrint
281
113
 
282
- def maintainer(parts=-1)
283
- "maintainer: #{module_name parts}"
284
- end
114
+ require "aws/cfn/dsl/mixins/output"
115
+ include Aws::Cfn::Dsl::Output
285
116
 
286
- def maintainer_comment(indent=' ')
287
- "#{indent}# WARNING: This code is generated. Your changes may be overwritten!\n" +
288
- "#{indent}# Remove this message and/or set the 'maintainer: <author name>' when you need your changes to survive.\n" +
289
- "#{indent}# Abscence of the 'maintainer: ' will be considered conscent to overwrite.\n" +
290
- "#{indent}# #{maintainer 3}\n" +
291
- "#\n"
292
- end
117
+ require "aws/cfn/dsl/mixins/dsl"
118
+ include Aws::Cfn::Dsl::DSL
293
119
 
294
- def print_maintainer(indent=' ')
295
- writeln maintainer_comment(indent)
296
- end
297
-
298
- def i_am_maintainer(file)
299
- # mod = module_name 2
300
- if File.exists?(file)
301
- src = IO.read(file)
302
- mtc = src.match(%r'#{maintainer 2}')
303
- iam = (not mtc.nil? or src.match(%r'#\s*maintainer:').nil?)
304
- ovr = @config[:overwrite]
305
- iam or ovr
306
- else
307
- true
308
- end
309
- end
310
-
311
- def prelude_code(indent=' ')
312
- "scope = Aws::Cfn::Compiler.binding[File.basename(File.dirname(__FILE__))][File.basename(__FILE__, '.rb')]\n"+
313
- "template = scope[:template]\n"+
314
- "\n"+
315
- "# noinspection RubyStringKeysInHashInspection\n"+
316
- "template." +
317
- ""
318
- end
319
-
320
- def print_with_wrapper(code,indent=' ')
321
- write prelude_code(indent)+code.gsub(%r'^\s+','')
322
- end
323
-
324
- def pprint_cfn_section(section, name, options, subdir, brick=true)
325
- if open_output(subdir,name)
326
- @logger.info "Pretty print #{section} '#{name}' to '#{rb_file(subdir, name)}'"
327
- print_maintainer ''
328
- print_with_wrapper "#{section} #{fmt_string(name)}"
329
- indent = ' ' + (' ' * section.length) + ' '
330
- hang = true
331
- options.each do |k, v|
332
- if hang
333
- writeln ','
334
- hang = false
335
- end
336
- write indent, fmt_key(k), " => "
337
- pprint_value v, indent
338
- hang = true
339
- end
340
- writeln
341
- writeln
342
- close_output
343
- add_brick(subdir,name) if brick
344
- else
345
- @logger.warn "NOT overwriting existing source file '#{rb_file(subdir, name)}'"
346
- end
347
- end
348
-
349
- def pprint_cfn_resource(name, options, brick=true)
350
- subdir = 'Resources'
351
- if open_output(subdir,name)
352
- @logger.info "Pretty print resource '#{name}' to '#{rb_file(subdir, name)}'"
353
- print_maintainer ''
354
- print_with_wrapper "resource #{fmt_string(name)}"
355
- indent = ' '
356
- hang = true
357
- options.each do |k, v|
358
- if hang
359
- writeln ','
360
- hang = false
361
- end
362
-
363
- case k
364
- when /^(Metadata|Properties)$/
365
- write "#{indent}#{fmt_key(k)} => "
366
- pprint_value options[k], indent
367
- hang = true
368
- else
369
- write "#{indent}#{fmt_key(k)} => "
370
- write "#{fmt(v)}"
371
- hang = true
372
- end
373
- end
374
- writeln
375
- close_output
376
- add_brick(subdir,name) if brick
377
- else
378
- @logger.warn "NOT overwriting existing source file '#{rb_file(subdir, name)}'"
379
- end
380
- end
381
-
382
- def pprint_value(val, indent)
383
- # Prefer to write the value on a single line if it's reasonable to do so
384
- single_line = is_single_line(val) || is_single_line_hack(val)
385
- if single_line && !is_multi_line_hack(val)
386
- s = fmt(val)
387
- if s.length < 120 || is_single_line_hack(val)
388
- write s
389
- return
390
- end
391
- end
392
-
393
- # Print the value across multiple lines
394
- if val.is_a?(Hash)
395
- writeln "{"
396
- val.each do |k, v|
397
- write "#{indent} #{fmt_key(k)} => "
398
- pprint_value v, indent + ' '
399
- writeln ","
400
- end
401
- write "#{indent}}"
402
-
403
- elsif val.is_a?(Array)
404
- writeln "["
405
- val.each do |v|
406
- write "#{indent} "
407
- pprint_value v, indent + ' '
408
- writeln ","
409
- end
410
- write "#{indent}]"
411
-
412
- elsif val.is_a?(FnCall) && val.multiline && @opts[:functions] != 'raw'
413
- write val.name, "("
414
- args = val.arguments
415
- sep = ''
416
- sub_indent = indent + ' '
417
- if val.name == 'join' && args.length > 1
418
- pprint_value args[0], indent + ' '
419
- args = args[1..-1]
420
- sep = ','
421
- sub_indent = indent + ' '
422
- end
423
- unless args.empty?
424
- args.each do |v|
425
- writeln sep
426
- write sub_indent
427
- pprint_value v, sub_indent
428
- sep = ','
429
- end
430
- if val.name == 'join' && args.length > 1
431
- write ","
432
- end
433
- writeln
434
- write indent
435
- end
436
- write ")"
437
-
438
- else
439
- write fmt(val)
440
- end
441
- end
442
-
443
- def is_single_line(val)
444
- if val.is_a?(Hash)
445
- is_single_line(val.values)
446
- elsif val.is_a?(Array)
447
- val.empty? ||
448
- (val.length == 1 && is_single_line(val[0]) && !val[0].is_a?(Hash)) ||
449
- val.all? { |v| v.is_a?(String) }
450
- else
451
- true
452
- end
453
- end
454
-
455
- # Emo-specific hacks to force the desired output formatting
456
- def is_single_line_hack(val)
457
- is_array_of_strings_hack(val)
458
- end
459
-
460
- # Emo-specific hacks to force the desired output formatting
461
- def is_multi_line_hack(val)
462
- val.is_a?(Hash) && val['email']
463
- end
464
-
465
- # Emo-specific hacks to force the desired output formatting
466
- def is_array_of_strings_hack(val)
467
- val.is_a?(Array) && val.all? { |v| v.is_a?(String) } && val.grep(/\s/).empty? && (
468
- val.include?('autoscaling:EC2_INSTANCE_LAUNCH') ||
469
- val.include?('m1.small')
470
- )
471
- end
472
-
473
- def fmt(val)
474
- if val == {}
475
- '{}'
476
- elsif val == []
477
- '[]'
478
- elsif val.is_a?(Hash)
479
- '{ ' + (val.map { |k,v| fmt_key(k) + ' => ' + fmt(v) }).join(', ') + ' }'
480
- elsif val.is_a?(Array) && is_array_of_strings_hack(val)
481
- '%w(' + val.join(' ') + ')'
482
- elsif val.is_a?(Array)
483
- '[ ' + (val.map { |v| fmt(v) }).join(', ') + ' ]'
484
- elsif val.is_a?(FnCall) && val.arguments.empty?
485
- val.name
486
- elsif val.is_a?(FnCall)
487
- val.name + '(' + (val.arguments.map { |v| fmt(v) }).join(', ') + ')'
488
- elsif val.is_a?(String)
489
- fmt_string(val)
490
- elsif val == nil
491
- 'null'
492
- else
493
- val.to_s # number, boolean
494
- end
495
- end
496
-
497
- def fmt_key(s)
498
- ':' + (/^[a-zA-Z_]\w+$/ =~ s ? s : fmt_string(s)) # returns a symbol like :Foo or :'us-east-1'
499
- end
500
-
501
- def fmt_string(s)
502
- if /[^ -~]/ =~ s
503
- s.dump # contains, non-ascii or control char, return double-quoted string
504
- else
505
- '\'' + s.gsub(/([\\'])/, '\\\\\1') + '\'' # return single-quoted string, escape \ and '
506
- end
507
- end
508
120
 
509
121
  end
510
122
  end