aws-must 0.0.2
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 +7 -0
- data/README.md +235 -0
- data/bin/aws-must.rb +92 -0
- data/demo/0/conf.yaml +1 -0
- data/demo/0/root.mustache +1 -0
- data/demo/1/conf.yaml +1 -0
- data/demo/1/root.mustache +22 -0
- data/demo/2/conf.yaml +6 -0
- data/demo/2/root.mustache +54 -0
- data/demo/3/conf.yaml +3 -0
- data/demo/3/resources.mustache +26 -0
- data/demo/3/root.mustache +85 -0
- data/demo/4/conf.yaml +22 -0
- data/demo/4/resource.mustache +27 -0
- data/demo/4/resourceInstance.mustache +32 -0
- data/demo/4/resources.mustache +25 -0
- data/demo/4/root.mustache +95 -0
- data/demo/5/conf.yaml +32 -0
- data/demo/5/output.mustache +39 -0
- data/demo/5/resource.mustache +26 -0
- data/demo/5/resourceInstance.mustache +35 -0
- data/demo/5/resources.mustache +25 -0
- data/demo/5/root.mustache +100 -0
- data/demo/6/conf.yaml +31 -0
- data/demo/6/mappings.mustache +67 -0
- data/demo/6/output.mustache +40 -0
- data/demo/6/resource.mustache +29 -0
- data/demo/6/resourceInstance.mustache +35 -0
- data/demo/6/resources.mustache +35 -0
- data/demo/6/root.mustache +133 -0
- data/demo/7/conf.yaml +54 -0
- data/demo/7/mappings.mustache +67 -0
- data/demo/7/output.mustache +40 -0
- data/demo/7/parameter.mustache +38 -0
- data/demo/7/resource.mustache +38 -0
- data/demo/7/resourceInstance.mustache +45 -0
- data/demo/7/resourceSecurityGroup.mustache +37 -0
- data/demo/7/resources.mustache +35 -0
- data/demo/7/root.mustache +157 -0
- data/demo/7/tag.mustache +30 -0
- data/lib/aws-must/aws-must.rb +96 -0
- data/lib/aws-must/docu.rb +164 -0
- data/lib/aws-must/template.rb +81 -0
- data/lib/aws-must.rb +11 -0
- data/lib/tasks/demo.rake +139 -0
- data/lib/utils/hasher.rb +83 -0
- data/lib/utils/logger.rb +71 -0
- metadata +106 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module AwsMust
|
5
|
+
|
6
|
+
class AwsMust
|
7
|
+
|
8
|
+
include Utils::MyLogger # mix logger
|
9
|
+
PROGNAME = "aws-must" # logger progname
|
10
|
+
include Utils::Hasher # mix logger
|
11
|
+
|
12
|
+
# ------------------------------------------------------------------
|
13
|
+
# attributes
|
14
|
+
|
15
|
+
attr_accessor :template # mustache (or something else)
|
16
|
+
|
17
|
+
def initialize( options={} )
|
18
|
+
|
19
|
+
# init logger
|
20
|
+
@logger = getLogger( PROGNAME, options )
|
21
|
+
@logger.info( "#{__method__}" )
|
22
|
+
|
23
|
+
# create object, which knows how to generate CloudFormation template json
|
24
|
+
@template = Template.new( options )
|
25
|
+
@docu = Docu.new( @template, options )
|
26
|
+
end
|
27
|
+
|
28
|
+
# ------------------------------------------------------------------
|
29
|
+
# dump 'yaml_file' as json
|
30
|
+
|
31
|
+
def json( yaml_file )
|
32
|
+
|
33
|
+
@logger.debug( "#{__method__}, template_name '#{yaml_file}'" )
|
34
|
+
|
35
|
+
#
|
36
|
+
data = read_yaml_file( yaml_file )
|
37
|
+
|
38
|
+
puts data.to_json
|
39
|
+
|
40
|
+
|
41
|
+
end #
|
42
|
+
|
43
|
+
# ------------------------------------------------------------------
|
44
|
+
# extract documentation from 'template_name'
|
45
|
+
|
46
|
+
def doc( template_name )
|
47
|
+
|
48
|
+
@logger.debug( "#{__method__}, template_name '#{template_name}'" )
|
49
|
+
|
50
|
+
@docu.document( template_name )
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# ------------------------------------------------------------------
|
56
|
+
# generate JSON by rendering 'template_name' using configurations
|
57
|
+
# from 'yaml_file'
|
58
|
+
|
59
|
+
def generate( template_name, yaml_file, options )
|
60
|
+
|
61
|
+
@logger.debug( "#{__method__}, template_name '#{template_name}'" )
|
62
|
+
@logger.debug( "#{__method__}, yaml_file= '#{yaml_file}'" )
|
63
|
+
|
64
|
+
#
|
65
|
+
data = read_yaml_file( yaml_file )
|
66
|
+
|
67
|
+
# some 'quirks' on data
|
68
|
+
data = adjust( data )
|
69
|
+
@logger.debug( "#{__method__}, data= '#{data}'" )
|
70
|
+
|
71
|
+
puts template.to_str( template_name, data )
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# deeply iterate 'data' -hash and add comma (,) to all expect the
|
78
|
+
# last hash in arrays
|
79
|
+
def adjust( data )
|
80
|
+
return addComma( data )
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def read_yaml_file( yaml_file )
|
85
|
+
|
86
|
+
raise "YAML file #{yaml_file} does not exist" unless File.exist?( yaml_file )
|
87
|
+
data = YAML.load_file( yaml_file )
|
88
|
+
|
89
|
+
return data
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
|
2
|
+
module AwsMust
|
3
|
+
|
4
|
+
class Docu
|
5
|
+
|
6
|
+
include ::Utils::MyLogger # mix logger
|
7
|
+
PROGNAME = "docu" # progname for logger
|
8
|
+
|
9
|
+
# ------------------------------------------------------------------
|
10
|
+
# constants
|
11
|
+
|
12
|
+
DEFAULT_OPEN_TAG ="++start++"
|
13
|
+
DEFAULT_CLOSE_TAG ="++close++"
|
14
|
+
DEFAULT_INCLUDE_TAG =">"
|
15
|
+
|
16
|
+
|
17
|
+
# ------------------------------------------------------------------
|
18
|
+
# Attributes
|
19
|
+
|
20
|
+
# static
|
21
|
+
|
22
|
+
|
23
|
+
# instance
|
24
|
+
|
25
|
+
# ------------------------------------------------------------------
|
26
|
+
# Constructor
|
27
|
+
# - template: which knows how to return template files
|
28
|
+
|
29
|
+
def initialize( template, options={} )
|
30
|
+
|
31
|
+
@logger = getLogger( PROGNAME, options )
|
32
|
+
@logger.info( "#{__method__}, options=#{options}" )
|
33
|
+
|
34
|
+
@template = template
|
35
|
+
|
36
|
+
@directives = {
|
37
|
+
:open => DEFAULT_OPEN_TAG,
|
38
|
+
:close => DEFAULT_CLOSE_TAG,
|
39
|
+
:include => DEFAULT_INCLUDE_TAG,
|
40
|
+
}
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# ------------------------------------------------------------------
|
45
|
+
# docu - output documentation to stdout
|
46
|
+
|
47
|
+
def document( template_name )
|
48
|
+
|
49
|
+
@logger.debug( "#{__method__}, template_name '#{template_name}'" )
|
50
|
+
|
51
|
+
#
|
52
|
+
template_string = @template.get_template( template_name )
|
53
|
+
@logger.debug( "#{__method__}, template_string= '#{template_string}'" )
|
54
|
+
|
55
|
+
#
|
56
|
+
state_opened=false
|
57
|
+
|
58
|
+
# iterate lines
|
59
|
+
template_string && template_string.split( "\n" ).each do | line |
|
60
|
+
|
61
|
+
if !state_opened then
|
62
|
+
|
63
|
+
# waiting for +++open+++
|
64
|
+
|
65
|
+
open_found, line = directive_open( line )
|
66
|
+
if open_found then
|
67
|
+
|
68
|
+
state_opened = true
|
69
|
+
|
70
|
+
# something follows the start -tag
|
71
|
+
redo if line && ! line.empty?
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
else
|
76
|
+
|
77
|
+
# seen +++open+++, waiting for +++close+++
|
78
|
+
|
79
|
+
close_found, line_pre, line = directive_close( line )
|
80
|
+
# puts "close_found=#{close_found}, #{close_found.class}, line=#{line}"
|
81
|
+
if close_found then
|
82
|
+
output( line_pre ) if line_pre && !line_pre.empty?
|
83
|
+
state_opened = false
|
84
|
+
redo if line && ! line.empty?
|
85
|
+
elsif template_name = directive_include( line ) then
|
86
|
+
document( template_name )
|
87
|
+
else
|
88
|
+
output( line )
|
89
|
+
end
|
90
|
+
|
91
|
+
end # state_opened
|
92
|
+
end # each line
|
93
|
+
|
94
|
+
end # end - document
|
95
|
+
|
96
|
+
# ------------------------------------------------------------------
|
97
|
+
# output - document output
|
98
|
+
|
99
|
+
def output( line )
|
100
|
+
|
101
|
+
puts( line )
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# ------------------------------------------------------------------
|
106
|
+
# Check if line satisfies tag
|
107
|
+
|
108
|
+
def directive_open( line )
|
109
|
+
# return line && line.include?( get_tag(:open) )
|
110
|
+
if line && line.include?( get_tag(:open) ) then
|
111
|
+
# find index pointing _after_ :open tag
|
112
|
+
index = line.index( get_tag(:open) ) + get_tag(:open).length
|
113
|
+
# # return text after directtive
|
114
|
+
# return true, line[ index..-1]
|
115
|
+
|
116
|
+
# do not output anything for the line
|
117
|
+
return true, nil
|
118
|
+
|
119
|
+
else
|
120
|
+
return false, nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# return bool, line_pre, line
|
125
|
+
def directive_close( line )
|
126
|
+
#return line && line.include?( get_tag( :close ) )
|
127
|
+
if line && line.include?( get_tag( :close ) ) then
|
128
|
+
index = line.index( get_tag(:close) )
|
129
|
+
# return true, index == 0 ? nil : line[0..index-1], line[ index+ get_tag(:close).length..-1]
|
130
|
+
# do not output anythin on line for directive
|
131
|
+
return true, nil, nil
|
132
|
+
else
|
133
|
+
return false, nil, line
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# return include 'template' to include if it is include directive
|
139
|
+
def directive_include( line )
|
140
|
+
|
141
|
+
# not valid input
|
142
|
+
return nil unless line
|
143
|
+
|
144
|
+
# extract template_name using regexp
|
145
|
+
parse_regexp=/^#{get_tag(:include)}\s+(?<template>[\w]*)\s*/
|
146
|
+
parsed = line.match( parse_regexp )
|
147
|
+
|
148
|
+
# not found
|
149
|
+
return nil unless parsed
|
150
|
+
return parsed['template']
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# ------------------------------------------------------------------
|
155
|
+
# get tag value
|
156
|
+
def get_tag( tag )
|
157
|
+
raise "Unknown tag" unless @directives[tag]
|
158
|
+
return @directives[tag]
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
end # class
|
163
|
+
|
164
|
+
end # module
|
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
require 'mustache' # extendending implementation of
|
3
|
+
|
4
|
+
|
5
|
+
module AwsMust
|
6
|
+
|
7
|
+
class Template < Mustache
|
8
|
+
|
9
|
+
include ::Utils::MyLogger # mix logger
|
10
|
+
PROGNAME = "template" # progname for logger
|
11
|
+
|
12
|
+
# ------------------------------------------------------------------
|
13
|
+
# Attributes
|
14
|
+
|
15
|
+
# static
|
16
|
+
@@template_path = nil # directory where templates stored
|
17
|
+
@@template_extension = "mustache"# type part in filename
|
18
|
+
|
19
|
+
# instance
|
20
|
+
attr_writer :partials # f: partial-name --> template string
|
21
|
+
attr_writer :templates # f: template-name --> template string
|
22
|
+
|
23
|
+
# ------------------------------------------------------------------
|
24
|
+
# Constructor
|
25
|
+
|
26
|
+
def initialize( options={} )
|
27
|
+
@logger = getLogger( PROGNAME, options )
|
28
|
+
@logger.info( "#{__FILE__}.#{__method__} created" )
|
29
|
+
@logger.debug( "#{__FILE__}.#{__method__}, options='#{options}" )
|
30
|
+
# for mustache templates
|
31
|
+
@@template_path = options[:template_path] if options[:template_path]
|
32
|
+
end
|
33
|
+
|
34
|
+
# ------------------------------------------------------------------
|
35
|
+
# Services
|
36
|
+
|
37
|
+
def to_str( template_name, data )
|
38
|
+
@logger.debug( "#{__method__}: template_name=#{template_name}, data=#{data}" )
|
39
|
+
if template_name
|
40
|
+
template = get_template( template_name )
|
41
|
+
render( template, data )
|
42
|
+
else
|
43
|
+
render( data )
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# ------------------------------------------------------------------
|
48
|
+
# Integrate with mustache
|
49
|
+
|
50
|
+
# method used by mustache framework - delegate to 'get_partial'
|
51
|
+
def partial(name)
|
52
|
+
@logger.debug( "#{__FILE__}.#{__method__} name=#{name}" )
|
53
|
+
# File.read("#{template_path}/#{name}.#{template_extension}")
|
54
|
+
get_partial( name )
|
55
|
+
end
|
56
|
+
|
57
|
+
# cache @partials - for easier extension
|
58
|
+
def get_partial( name )
|
59
|
+
@logger.debug( "#{__FILE__}.#{__method__} name=#{name}" )
|
60
|
+
return @partials[name] if @partials && @partials[name]
|
61
|
+
|
62
|
+
partial_file = "#{@@template_path}/#{name}.#{template_extension}"
|
63
|
+
@logger.info( "#{__FILE__}.#{__method__} read partial_file=#{partial_file}" )
|
64
|
+
File.read( partial_file )
|
65
|
+
end
|
66
|
+
|
67
|
+
# hide @templates - for easier extension
|
68
|
+
def get_template( name )
|
69
|
+
|
70
|
+
@logger.debug( "#{__FILE__}.#{__method__} name=#{name}" )
|
71
|
+
return @templates[name] if @templates && @templates[name]
|
72
|
+
|
73
|
+
template_path = "#{@@template_path}/#{name}.#{@@template_extension}"
|
74
|
+
@logger.info( "#{__FILE__}.#{__method__} read template_path=#{template_path}" )
|
75
|
+
|
76
|
+
File.read( template_path )
|
77
|
+
end
|
78
|
+
|
79
|
+
end # class
|
80
|
+
|
81
|
+
end # module
|
data/lib/aws-must.rb
ADDED
data/lib/tasks/demo.rake
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
|
3
|
+
# demo.rake
|
4
|
+
|
5
|
+
# Thank You!
|
6
|
+
# http://andyatkinson.com/blog/2014/06/23/sharing-rake-tasks-in-gems
|
7
|
+
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
namespace "demo" do |ns|
|
11
|
+
|
12
|
+
# --------------------
|
13
|
+
# Demo configs
|
14
|
+
|
15
|
+
cmd = File.join File.dirname(__FILE__), "../../bin/aws-must.rb" # generator being demonstrated
|
16
|
+
demo_dir=File.join File.dirname(__FILE__), "../../demo" # directory holding demo configs
|
17
|
+
stack="demo" # stack name of the on Amazon
|
18
|
+
default_private_key_file="~/.ssh/demo-key/demo-key" # private keyfile corresponding
|
19
|
+
|
20
|
+
all_regions= ["ap-northeast-1", "ap-southeast-1", "ap-southeast-2", "cn-north-1", "eu-central-1", "eu-west-1", "sa-east-1", "us-east-1", "us-gov-west-1", "us-west-1", "us-west-2"]
|
21
|
+
|
22
|
+
[
|
23
|
+
|
24
|
+
{ :id => "1", :desc=>"Initial copy", :region=>['eu-central-1'], :ssh => false },
|
25
|
+
{ :id => "2", :desc=>"Added 'description' -property to YAML file", :region=>['eu-central-1'], :ssh => false },
|
26
|
+
{ :id => "3", :desc=>"Use resources.mustache -partial to create EC2 intance", :region=>['eu-central-1'], :ssh => false },
|
27
|
+
{ :id => "4", :desc=>"EC2 instance configuration using YAML-data", :region=>['eu-central-1'], :ssh => false },
|
28
|
+
{ :id => "5", :desc=>"Add 'Outputs' -section with reference to EC2 instance", :region=>['eu-central-1'], :ssh => false },
|
29
|
+
{ :id => "6", :desc=>"Add 'Inputs' and 'Mappings' -sections to parametirize", :region=> all_regions, :ssh => false },
|
30
|
+
{ :id => "7", :desc=>"Added support for input parameters, EC2 tags, Instance security group", :region=>all_regions, :ssh => false },
|
31
|
+
|
32
|
+
|
33
|
+
].each do |c|
|
34
|
+
|
35
|
+
desc "Output CF template using configs in '#{demo_dir}/#{c[:id]}' to demonstrate '#{c[:desc]}'"
|
36
|
+
task "template-#{c[:id]}" do
|
37
|
+
sh "#{cmd} gen -t #{demo_dir}/#{c[:id]} #{demo_dir}/#{c[:id]}/conf.yaml"
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Output configs in '#{demo_dir}/#{c[:id]}' in JSON to demonstrate '#{c[:desc]}'"
|
41
|
+
task "json-#{c[:id]}" do
|
42
|
+
sh "#{cmd} json #{demo_dir}/#{c[:id]}/conf.yaml"
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Check the difference between version '#{c[:id]}' and '#{c[:id].to_i() -1}' "
|
46
|
+
task "diff-#{c[:id]}" do
|
47
|
+
prev = c[:id].to_i() -1
|
48
|
+
# use bash temporary names pipes to diff two stdouts
|
49
|
+
# Use `jq` to create canonical pretty print json
|
50
|
+
sh "bash -c \"diff <(#{cmd} gen -t #{demo_dir}/#{c[:id]} #{demo_dir}/#{c[:id]}/conf.yaml | jq . ) <(#{cmd} gen -t #{demo_dir}/#{prev} #{demo_dir}/#{prev}/conf.yaml | jq . ) || true \""
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Create stack #{stack} for demo case #{c[:id]}, supported regions=#{c[:region]}"
|
54
|
+
task "stack-create-#{c[:id]}" do
|
55
|
+
sh "aws cloudformation create-stack --stack-name #{stack} --template-body \"$(#{cmd} gen -t #{demo_dir}/#{c[:id]} #{demo_dir}/#{c[:id]}/conf.yaml)\""
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Open html documentation in 'browser' (default 'firefox')"
|
59
|
+
task "html-#{c[:id]}", :browser do |t,args|
|
60
|
+
|
61
|
+
args.with_defaults( browser: "firefox" )
|
62
|
+
|
63
|
+
sh "#{cmd} doc -t #{demo_dir}/#{c[:id]} | markdown | #{args.browser} \"data:text/html;base64,$(base64 -w 0 <&0)\""
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
desc "Copy demo case #{c[:id]} to :templateDir and :configDir"
|
68
|
+
task "bootstrap-#{c[:id]}", :templateDir,:configDir do |t, args|
|
69
|
+
|
70
|
+
usage = "Task '#{t}' usage: #{t}[:templateDir,:configDir]"
|
71
|
+
raise usage if args.templateDir.nil?
|
72
|
+
raise usage if args.configDir.nil?
|
73
|
+
|
74
|
+
raise "Directory #{args.templateDir} does not exist" unless File.exists?( args.templateDir )
|
75
|
+
raise "Directory #{args.configDir} does not exist" unless File.exists?( args.configDir )
|
76
|
+
|
77
|
+
|
78
|
+
puts (<<-EOS) if args.templateDir == args.configDir
|
79
|
+
|
80
|
+
Warning :templateDir == :configDir == #{args.templateDir}
|
81
|
+
Suggestion to keep templates and configurations in a separate directory
|
82
|
+
|
83
|
+
EOS
|
84
|
+
|
85
|
+
demoTemplates = File.join demo_dir, c[:id], "*.mustache"
|
86
|
+
configFiles = File.join demo_dir, c[:id], "*.yaml"
|
87
|
+
|
88
|
+
Dir[demoTemplates].each { |f|
|
89
|
+
FileUtils.cp(f, args.templateDir, :verbose=>true )
|
90
|
+
}
|
91
|
+
|
92
|
+
Dir[configFiles].each { |f|
|
93
|
+
FileUtils.cp(f, args.configDir, :verbose=>true )
|
94
|
+
}
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
desc "Show status of CloudFormation stack"
|
102
|
+
task "stack-status" do
|
103
|
+
sh "aws cloudformation describe-stacks"
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "Ssh connection to ':ipName' using ':private_key' default (#{default_private_key_file})"
|
107
|
+
task 'stack-ssh', :ipName, :private_key do |t, args|
|
108
|
+
|
109
|
+
raise "Task '#{t}' usage: #{t}[ipName,private_key] - exiting" if args.ipName.nil?
|
110
|
+
|
111
|
+
stack_string = %x{ aws cloudformation describe-stacks --stack-name #{stack} }
|
112
|
+
raise "Error #{$?.exitstatus}" if $?.exitstatus != 0
|
113
|
+
|
114
|
+
args.with_defaults( private_key: default_private_key_file )
|
115
|
+
|
116
|
+
stack_json = JSON.parse( stack_string )
|
117
|
+
ip_json = stack_json["Stacks"][0]['Outputs'].select { |o| o['OutputKey'] == args.ipName }.first
|
118
|
+
raise "Could not find ip for 'ipName' '#{args.ipName}' in output section of #{stack} stack" unless ip_json
|
119
|
+
|
120
|
+
puts ip_json['OutputValue']
|
121
|
+
identity="-i #{args.private_key}"
|
122
|
+
|
123
|
+
sh "ssh ubuntu@#{ip_json['OutputValue']} #{identity}"
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
desc "Show events of CloudFormation stack '#{stack}'"
|
128
|
+
task "stack-events" do
|
129
|
+
sh "aws cloudformation describe-stack-events --stack-name #{stack}"
|
130
|
+
end
|
131
|
+
|
132
|
+
desc "Delete stack CloudFormation stack '#{stack}'"
|
133
|
+
task "stack-delete" do
|
134
|
+
sh "aws cloudformation delete-stack --stack-name #{stack}"
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
end
|
139
|
+
|
data/lib/utils/hasher.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# see http://hawkins.io/2013/08/using-the-ruby-logger/
|
2
|
+
|
3
|
+
# ------------------------------------------------------------------
|
4
|
+
# Open up class Hash to add `deep_traverse`
|
5
|
+
|
6
|
+
|
7
|
+
class Hash
|
8
|
+
def deep_traverse(&block)
|
9
|
+
self.each do |k,v|
|
10
|
+
puts k,v
|
11
|
+
yield( k,v)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
# stack = self.map{ |k,v| [ [k], v ] }
|
15
|
+
# while not stack.empty?
|
16
|
+
# key, value = stack.pop
|
17
|
+
# yield(key, value)
|
18
|
+
# if value.is_a? Hash
|
19
|
+
# value.each{ |k,v| stack.push [ key.dup << k, v ] }
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
# ------------------------------------------------------------------
|
29
|
+
# implement my own
|
30
|
+
|
31
|
+
module Utils
|
32
|
+
|
33
|
+
module Hasher
|
34
|
+
|
35
|
+
# see http://stackoverflow.com/questions/3748744/traversing-a-hash-recursively-in-ruby
|
36
|
+
|
37
|
+
def dfs(hsh, &blk)
|
38
|
+
return enum_for(:dfs, hsh) unless blk
|
39
|
+
|
40
|
+
# no change unless a hash
|
41
|
+
return hsh unless hsh.is_a? Hash
|
42
|
+
|
43
|
+
yield hsh
|
44
|
+
hsh.each do |k,v|
|
45
|
+
if v.is_a? Array
|
46
|
+
v.each do |elm|
|
47
|
+
dfs(elm, &blk)
|
48
|
+
end
|
49
|
+
elsif v.is_a? Hash
|
50
|
+
dfs(v, &blk)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
return hsh
|
54
|
+
# nil
|
55
|
+
end
|
56
|
+
|
57
|
+
# adds comma hash in arrays deeply in obj-hash
|
58
|
+
def addComma( obj )
|
59
|
+
|
60
|
+
if ( obj.is_a?(Hash) )
|
61
|
+
|
62
|
+
obj2 = dfs(obj) do |o|
|
63
|
+
o.each do |k,v|
|
64
|
+
if v.is_a? Array
|
65
|
+
# add :comma -property expect to the last element
|
66
|
+
v.slice(0,v.length-1).each do |elem|
|
67
|
+
elem["_comma"] = "," if elem.is_a? Hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end # block
|
72
|
+
|
73
|
+
obj = obj2
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
return obj
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end # module Utils
|
data/lib/utils/logger.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
# see http://hawkins.io/2013/08/using-the-ruby-logger/
|
4
|
+
|
5
|
+
|
6
|
+
module Utils
|
7
|
+
|
8
|
+
module MyLogger
|
9
|
+
|
10
|
+
# no logging done
|
11
|
+
|
12
|
+
class NullLoger < Logger
|
13
|
+
def initialize(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def add(*args, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
LOGFILE="apu.tmp"
|
21
|
+
|
22
|
+
def getLogger( progname, options={} )
|
23
|
+
|
24
|
+
level = get_level( options )
|
25
|
+
|
26
|
+
if level.nil?
|
27
|
+
|
28
|
+
return NullLoger.new
|
29
|
+
|
30
|
+
else
|
31
|
+
|
32
|
+
logger = Logger.new( LOGFILE )
|
33
|
+
logger.level=level
|
34
|
+
logger.progname = progname
|
35
|
+
return logger
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end # getLogger
|
40
|
+
|
41
|
+
# ------------------------------------------------------------------
|
42
|
+
private
|
43
|
+
|
44
|
+
def get_level( options )
|
45
|
+
|
46
|
+
# puts "#{__method__}: options=#{options}"
|
47
|
+
|
48
|
+
level_name = options && options[:log] ? options[:log] : ENV['LOG_LEVEL']
|
49
|
+
|
50
|
+
level = case level_name
|
51
|
+
when 'warn', 'WARN'
|
52
|
+
Logger::WARN
|
53
|
+
when 'info', 'INFO'
|
54
|
+
Logger::INFO
|
55
|
+
when 'debug', 'DEBUG'
|
56
|
+
Logger::DEBUG
|
57
|
+
when 'error', 'ERROR'
|
58
|
+
Logger::ERROR
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
return level
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
end
|