configulator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +74 -0
- data/Rakefile +18 -0
- data/bin/configulator +21 -0
- data/configulator.gemspec +24 -0
- data/lib/configulator.rb +20 -0
- data/lib/configulator/config_template.rb +63 -0
- data/lib/configulator/version.rb +3 -0
- data/test/configulator_test.rb +77 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0be977b2ac66bdc4eff6e156fc0b79d4f58a6f39
|
4
|
+
data.tar.gz: 666cb63c44ab7c9f7361ad415b68e751fe0fef83
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 633253c21f194e83c9e3163ac120ca75cce1ef39689693c0404e4ae64253631bb96fa29d8e60bf820b8a93b739ba86c97e522dd224a999b3f2e8a54aede2d194
|
7
|
+
data.tar.gz: 5b79fc953a1535c89bab8c616c5d968e5035c3dc8df97765eafb83cd3ef8081ff56ca367521d2c94cf0329862295ebc87452ae82f7d7c53e670fb7d1653c98a6
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Brian Muller
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Configulator : Generate Config Files
|
2
|
+
|
3
|
+
Configurator allows you to maintain a single file with configuration values that can be used to generate other config files based on templates.
|
4
|
+
|
5
|
+
For instance, if you need to generate all of the config files for a Hadoop cluster and the files vary in type (xml, json, yaml, etc) but all rely on the same few configuration values, you can use configulator to generate those files.
|
6
|
+
|
7
|
+
Configulator is a tool that takes a single master input config file and some number of template files as input and then outputs the template files with the correct configuration values substituted. Additionally, there is a way of specifying default values, and then configulator will override on the necessary ones per environment.
|
8
|
+
|
9
|
+
See [this blog post](http://findingscience.com/linux/sysadmin/ruby/2010/10/27/config-template-class.html) for the background on why this can be useful.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'configulator'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install configulator
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Configulator can accept a master config file either in json or yaml. Here's an example config file:
|
28
|
+
|
29
|
+
mysql_host: 127.0.0.1
|
30
|
+
mysql_port: 5678
|
31
|
+
db_host: <%= mysql_host %>
|
32
|
+
db_port: <%= mysql_port %>
|
33
|
+
current_time: <%= Time.now %>
|
34
|
+
|
35
|
+
It specifies a mysql host and port, as well as a general db host and port that will simply use the values for mysql. Then, given an example config file that's nasty and written in XML:
|
36
|
+
|
37
|
+
<xml><config><host><%= db_host %></host></config></xml>
|
38
|
+
|
39
|
+
We can now convert the above file into one with db_host filled in either using code or the configulator command. Here's what the code looks like (assuming our master config is master.yml and our xml is xmlisbad.xml.tmpl):
|
40
|
+
|
41
|
+
require 'configulator'
|
42
|
+
converted = Configulator.from_yaml_file('master.yml').convert_file('xmlisbad.xml')
|
43
|
+
File.write 'xmlisbad.xml', converted
|
44
|
+
|
45
|
+
You can also access specific variables in the ruby code:
|
46
|
+
|
47
|
+
puts converted.db_host # => 127.0.0.1
|
48
|
+
|
49
|
+
Using the configulator command instead looks like this:
|
50
|
+
|
51
|
+
configulator master.yml xmlisbad.xml.tmpl > xmlisbad.xml
|
52
|
+
|
53
|
+
## Environments
|
54
|
+
|
55
|
+
You have the option of setting default values in your master config file and then separate environment sections beneath that. For instance, here's a yaml config file with default values for some keys:
|
56
|
+
|
57
|
+
default:
|
58
|
+
debug: INFO
|
59
|
+
db_host: <%= mysql_host %>
|
60
|
+
db_port: <%= mysql_port %>
|
61
|
+
production:
|
62
|
+
mysql_host: 1.2.3.4
|
63
|
+
mysql_port: 5678
|
64
|
+
development:
|
65
|
+
mysql_host: 127.0.0.1
|
66
|
+
mysql_port: 5678
|
67
|
+
|
68
|
+
We can spit out the production values like this (just passing in an extra argument to from_yaml_file):
|
69
|
+
|
70
|
+
require 'configulator'
|
71
|
+
converted = Configulator.from_yaml_file('master.yml', 'production').convert_file('xmlisbad.xml')
|
72
|
+
File.write 'xmlisbad.xml', converted
|
73
|
+
|
74
|
+
When db_host is used in the xml file, configulator will look for it first in the production section and then in the default (where it is found, then repeats process for mysql_host).
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rdoc/task'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
task :default => [:test]
|
6
|
+
|
7
|
+
RDoc::Task.new("doc") { |rdoc|
|
8
|
+
rdoc.title = "Configulator - Generate config files"
|
9
|
+
rdoc.rdoc_dir = 'docs'
|
10
|
+
rdoc.rdoc_files.include('README.md')
|
11
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
+
}
|
13
|
+
|
14
|
+
desc "Run all unit tests"
|
15
|
+
Rake::TestTask.new("test") { |t|
|
16
|
+
t.libs << "lib"
|
17
|
+
t.test_files = FileList['test/*.rb']
|
18
|
+
}
|
data/bin/configulator
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'configulator'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rubygems'
|
7
|
+
require 'configulator'
|
8
|
+
end
|
9
|
+
|
10
|
+
if ARGV.length < 2
|
11
|
+
puts "Usage: configulator <master config file> <template file> [<environment>]"
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
if ARGV[0].end_with? '.yml' or ARGV[0].end_with? '.yaml'
|
16
|
+
conf = Configulator.from_yaml_file(ARGV[0], ARGV[2])
|
17
|
+
else
|
18
|
+
conf = Configulator.from_json_file(ARGV[0], ARGV[2])
|
19
|
+
end
|
20
|
+
|
21
|
+
puts conf.convert_file ARGV[1]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'configulator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "configulator"
|
8
|
+
spec.version = Configulator::VERSION
|
9
|
+
spec.authors = ["Brian Muller"]
|
10
|
+
spec.email = ["bamuller@gmail.com"]
|
11
|
+
spec.summary = %q{Generate config files from a template}
|
12
|
+
spec.description = %q{Configurator allows you to maintain a single file with configuration values that can be used to generate other config files based on templates.}
|
13
|
+
spec.homepage = "https://github.com/bmuller/configulator"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rdoc"
|
24
|
+
end
|
data/lib/configulator.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "configulator/version"
|
2
|
+
require "configulator/config_template"
|
3
|
+
|
4
|
+
module Configulator
|
5
|
+
def self.from_json(conf, environment = nil)
|
6
|
+
JSONConfigTemplate.new conf, environment
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.from_json_file(fname, environment = nil)
|
10
|
+
from_json File.read(fname), environment
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_yaml(fname, environment = nil)
|
14
|
+
YAMLConfigTemplate.new fname, environment
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_yaml_file(fname, environment = nil)
|
18
|
+
from_yaml File.read(fname), environment
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Configulator
|
6
|
+
class ConfStruct < Struct
|
7
|
+
def get_binding
|
8
|
+
binding
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ConfigTemplate
|
13
|
+
def initialize(conf, environment = nil)
|
14
|
+
if environment.nil?
|
15
|
+
@binding = make_binding conf
|
16
|
+
else
|
17
|
+
raise "No such environment: #{environment}" unless conf.has_key? environment
|
18
|
+
env = conf[environment]
|
19
|
+
env = conf['default'].merge(env) if conf.has_key? 'default'
|
20
|
+
env['environment_name'] = environment
|
21
|
+
@binding = make_binding env
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def convert_file(infile)
|
26
|
+
ERB.new(File.read(infile)).result(@binding)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(name)
|
30
|
+
eval name.to_s, @binding
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(name, *args, &block)
|
34
|
+
get name
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def make_binding(env)
|
39
|
+
klass = ConfStruct.new *env.keys.map(&:intern)
|
40
|
+
k = klass.new *env.values
|
41
|
+
# support up to 5 levels of embedding
|
42
|
+
5.times do
|
43
|
+
values = env.values.map do |v|
|
44
|
+
v.is_a?(String) ? ERB.new(v).result(k.get_binding) : v
|
45
|
+
end
|
46
|
+
k = klass.new *values
|
47
|
+
end
|
48
|
+
k.get_binding
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class JSONConfigTemplate < ConfigTemplate
|
53
|
+
def initialize(config, environment = nil)
|
54
|
+
super JSON.parse(config), environment
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class YAMLConfigTemplate < ConfigTemplate
|
59
|
+
def initialize(config, environment = nil)
|
60
|
+
super YAML.load(config), environment
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'configulator'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
class ConfigulatorTest < Test::Unit::TestCase
|
8
|
+
def test_json_load_without_env
|
9
|
+
input = {
|
10
|
+
"one" => "something",
|
11
|
+
"two" => "<%= one %> one",
|
12
|
+
"three" => "<%= two %> two"
|
13
|
+
}
|
14
|
+
c = Configulator.from_json(JSON.dump(input))
|
15
|
+
assert_equal c.one, "something"
|
16
|
+
assert_equal c.two, "something one"
|
17
|
+
assert_equal c.three, "something one two"
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_json_load_with_env
|
21
|
+
input = {
|
22
|
+
"default" => {
|
23
|
+
"one" => "something",
|
24
|
+
"two" => "<%= one %> one",
|
25
|
+
"three" => "<%= two %> two"
|
26
|
+
},
|
27
|
+
"test" => {
|
28
|
+
"three" => "<%= one %> as three",
|
29
|
+
"newone" => 3
|
30
|
+
}
|
31
|
+
}
|
32
|
+
c = Configulator.from_json(JSON.dump(input), "test")
|
33
|
+
assert_equal c.one, "something"
|
34
|
+
assert_equal c.two, "something one"
|
35
|
+
assert_equal c.three, "something as three"
|
36
|
+
assert_equal c.newone, 3
|
37
|
+
|
38
|
+
assert_raise RuntimeError do
|
39
|
+
Configulator.from_json(JSON.dump(input), "testfake")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_yaml_load_without_env
|
44
|
+
input = {
|
45
|
+
"one" => "something",
|
46
|
+
"two" => "<%= one %> one",
|
47
|
+
"three" => "<%= two %> two"
|
48
|
+
}
|
49
|
+
c = Configulator.from_yaml(YAML.dump(input))
|
50
|
+
assert_equal c.one, "something"
|
51
|
+
assert_equal c.two, "something one"
|
52
|
+
assert_equal c.three, "something one two"
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_yaml_load_with_env
|
56
|
+
input = {
|
57
|
+
"default" => {
|
58
|
+
"one" => "something",
|
59
|
+
"two" => "<%= one %> one",
|
60
|
+
"three" => "<%= two %> two"
|
61
|
+
},
|
62
|
+
"test" => {
|
63
|
+
"three" => "<%= one %> as three",
|
64
|
+
"newone" => 3
|
65
|
+
}
|
66
|
+
}
|
67
|
+
c = Configulator.from_yaml(YAML.dump(input), "test")
|
68
|
+
assert_equal c.one, "something"
|
69
|
+
assert_equal c.two, "something one"
|
70
|
+
assert_equal c.three, "something as three"
|
71
|
+
assert_equal c.newone, 3
|
72
|
+
|
73
|
+
assert_raise RuntimeError do
|
74
|
+
Configulator.from_yaml(YAML.dump(input), "testfake")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: configulator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Muller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Configurator allows you to maintain a single file with configuration
|
56
|
+
values that can be used to generate other config files based on templates.
|
57
|
+
email:
|
58
|
+
- bamuller@gmail.com
|
59
|
+
executables:
|
60
|
+
- configulator
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/configulator
|
71
|
+
- configulator.gemspec
|
72
|
+
- lib/configulator.rb
|
73
|
+
- lib/configulator/config_template.rb
|
74
|
+
- lib/configulator/version.rb
|
75
|
+
- test/configulator_test.rb
|
76
|
+
homepage: https://github.com/bmuller/configulator
|
77
|
+
licenses:
|
78
|
+
- MIT
|
79
|
+
metadata: {}
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.2.2
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: Generate config files from a template
|
100
|
+
test_files:
|
101
|
+
- test/configulator_test.rb
|