dupervisor 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ env:
3
+ - CODECLIMATE_REPO_TOKEN=49ca8c0e2d56ab70e7eabc237692e21cc8fe43ef13ed5d411fa20bf1e8997a44
4
+ rvm:
5
+ - 2.2.3
6
+ - 2.3.0
7
+ script: "bundle exec rspec --format documentation"
8
+ notifications:
9
+ slack:
10
+ rooms:
11
+ email:
12
+ recipients:
13
+ - kigster@gmail.com
14
+ on_success: change
15
+ on_failure: always
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dupervisor.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Konstantin Gredeskoul
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,162 @@
1
+ [![Gem Version](https://badge.fury.io/rb/dupervisor.svg)](https://badge.fury.io/rb/dupervisor)
2
+ [![Build Status](https://travis-ci.org/kigster/dupervisor.svg?branch=master)](https://travis-ci.org/kigster/dupervisor)
3
+ [![Code Climate](https://codeclimate.com/github/kigster/dupervisor/badges/gpa.svg)](https://codeclimate.com/github/kigster/dupervisor)
4
+ [![Test Coverage](https://codeclimate.com/github/kigster/dupervisor/badges/coverage.svg)](https://codeclimate.com/github/kigster/dupervisor/coverage)
5
+ [![Issue Count](https://codeclimate.com/github/kigster/dupervisor/badges/issue_count.svg)](https://codeclimate.com/github/kigster/dupervisor)
6
+
7
+ # DuperVisorâ„¢ Pro
8
+
9
+ The super-duper awesome library is your best friend if you want an easy way to convert configuration between any one of the supported formats, which at this time are: JSON, YAML, and Windows INI format.
10
+
11
+ This tool was originally created to allow storing configs of another great tool called [__supervisord__](http://supervisord.org), which is still highly applicable today, but unfortunately uses a rather [archaic configuration file format](http://supervisord.org/configuration.html) of the decades old Windows INI format.
12
+
13
+ Whatever your preferences are, the truth is that some of the modern DevOps tools (such as Ansible and SaltStack) are using YAML format extensively to configure the environments. Ability to "embed" YAML configuration for a tool like supervisord means that you don't have to go to multiple places to see what is being run everywhere.
14
+
15
+ If you enjoy using this converted, please star the repo and we very much welcome all pull requests and contributions.
16
+
17
+ ## YAML/JSON vs INI
18
+
19
+ Consider the following example taken from the [_supervisord_ configuration documentation](http://supervisord.org/configuration.html]):
20
+
21
+ ```ini
22
+ [supervisord]
23
+ nodaemon = false
24
+ minfds = 1024
25
+ minprocs = 200
26
+ umask = 022
27
+ user = chrism
28
+ identifier = supervisor
29
+ directory = /tmp
30
+ nocleanup = true
31
+ childlogdir = /tmp
32
+ strip_ansi = false
33
+ environment = PATH="/usr/bin:/usr/local/bin:/bin:/sbin",ENVIRONMENT="development"
34
+
35
+ [program:cat]
36
+ command=/bin/cat
37
+ process_name=%(program_name)s
38
+ numprocs=1
39
+ directory=/tmp
40
+ umask=022
41
+ priority=999
42
+ autostart=true
43
+ autorestart=unexpected
44
+
45
+ ```
46
+
47
+ We think that it is much easier to read this:
48
+
49
+ ```yaml
50
+ supervisord:
51
+ nodaemon: false
52
+ minfds: 1024
53
+ minprocs: 200
54
+ umask: 022
55
+ user: chrism
56
+ identifier: supervisor
57
+ directory: /tmp
58
+ nocleanup: true
59
+ childlogdir: /tmp
60
+ strip_ansi: false
61
+ environment: PATH="/usr/bin:/usr/local/bin:/bin:/sbin",ENVIRONMENT="development"
62
+
63
+ program:
64
+ cat:
65
+ command: /bin/cat
66
+ process_name: %(program_name)s
67
+ numprocs: 1
68
+ directory: /tmp
69
+ umask: 022
70
+ priority: 999
71
+ autostart: true
72
+ autorestart: unexpected
73
+ ```
74
+
75
+ Not only that, but with this structure you can leverage existing tools for merging information from the default environment to your production, and so on.
76
+
77
+ ## Installation
78
+
79
+ Install the gem:
80
+
81
+ ```
82
+ gem install dupervisor
83
+ ```
84
+
85
+ or, if you are using Bundler, you can add it to your gem file like so:
86
+
87
+ ```ruby
88
+ gem 'dupervisor'
89
+ ```
90
+
91
+ ## Usage
92
+
93
+ To perform translations in code, you would use `DuperVisor::Parser` class to parse an existing format, and `DuperVisor::Renderer` class to convert the intermediary hash into the destination format:
94
+
95
+ ```ruby
96
+ # This helper extracts format from a file extension
97
+ Detector.new('myfile.json').detect # => :json
98
+
99
+ # This is how you can parse content by specifying the format
100
+ content = Parser.new(File.read('myfile.json')).parse(:json)
101
+
102
+ # But the gem can also guess the source format from either
103
+ # the filename (if available) or the source content
104
+ content = Parser.new(File.read('myfile.json')).parse()
105
+ content.format # => :json
106
+ content.parse_result # => { ... } Hash
107
+
108
+ # Finally, here we are using Renderer to convert a hash stored
109
+ # in content.parse_result into a YAML formatted string.
110
+ Renderer.new(content.parse_result).render(:yaml) # => YAML string
111
+ ```
112
+
113
+ You can use the provided executable `dupervisor` to convert from a JSON or YAML file into an INI
114
+
115
+ ### `dv [source-file] [options]`
116
+
117
+ Summary: convert between several hierarchical configuration file formats, such as ini, yaml, json
118
+ Automatically guesses the source format based either on the file extension, or by attempting to parse it for STDIN.
119
+
120
+ #### Specific Options
121
+
122
+ ```
123
+ --ini Generate an INI file
124
+ --yaml Generate a YAML file
125
+ --json Generate a JSON file
126
+ -o, --output [FILE] File to write, if not supplied write to STDOUT
127
+ -v, --verbose Print extra debugging info
128
+ -h, --help Show this message
129
+ --version Show version
130
+ ```
131
+
132
+ #### Examples
133
+
134
+ __Guess input format, convert YAML format to an INI file:__
135
+
136
+ ```
137
+ $ cat config.yml | dv --ini > config.ini
138
+ ```
139
+
140
+ __Guess input format, convert INI format to a JSON file:__
141
+
142
+ ```
143
+ $ dv config.ini --json -o config.json
144
+ ```
145
+
146
+
147
+ ## Contributing
148
+
149
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/dupervisor.
150
+
151
+ ## Author
152
+
153
+ <p>&copy; 2016 Konstantin Gredeskoul, all rights reserved.</p>
154
+
155
+ #### Acknowledgements
156
+
157
+ * [Shippo, Inc.](https://goshippo.com/) for sponsoring this work financially, and their commitment to open source.
158
+ * [Wissam Jarjoul](https://github.com/bosswissam) for many great ideas and a good eye for bugs.
159
+
160
+ ## License
161
+
162
+ This project is distributed under the [MIT License](https://raw.githubusercontent.com/kigster/dupervisor/master/LICENSE).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dupervisor"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dupervisor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'dupervisor'
8
+ spec.version = DuperVisor::VERSION
9
+ spec.authors = ['Konstantin Gredeskoul']
10
+ spec.email = ['kigster@gmail.com']
11
+
12
+ spec.summary = %q{Convert between YAML/JSON format and Windows INI format. }
13
+ spec.description = %q{This gem's purpose in life is to freely convert various configurations between supported formats, which are currently YAML, JSON and Windows INI file format. The gem is named after a popular package supervisord, which uses INI file format for it's configuration. This gem will allow you to move supervisord configuration into a YAML file, and integrate with other DevOps tools, while generating INI file on the fly. When installed, library exposes 'dv' executable, which is a an easy-to-use converter between these three formats.}
14
+ spec.homepage = 'https://github.com/kigster/dupervisor'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = 'exe'
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'require_dir'
22
+ spec.add_dependency 'awesome_print'
23
+ spec.add_dependency 'colored2'
24
+ spec.add_dependency 'inifile'
25
+
26
+ spec.add_development_dependency 'codeclimate-test-reporter'
27
+ spec.add_development_dependency 'bundler', '~> 1.12'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rspec', '~> 3.0'
30
+ end
data/exe/dv ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby -W0
2
+ lib_path = File.dirname(__FILE__) + '/../lib'
3
+ if Dir.exist?(lib_path)
4
+ $LOAD_PATH << lib_path
5
+ end
6
+ require 'colored2'
7
+ require 'dupervisor'
8
+ require 'awesome_print'
9
+
10
+ begin
11
+ DuperVisor::Main.new(DuperVisor::CLI.new(ARGV).parse).run
12
+ rescue DuperVisor::CLIError => e
13
+ STDERR.puts 'Usage error: ' + e.message.bold.red
14
+ puts
15
+ DuperVisor::CLI.new(['--help']).parse
16
+ end
@@ -0,0 +1,8 @@
1
+ require 'dupervisor/version'
2
+ require 'require_dir'
3
+ module DuperVisor
4
+ extend RequireDir
5
+ init_from_source __FILE__
6
+ end
7
+
8
+ DuperVisor.dir_r 'dupervisor'
@@ -0,0 +1,84 @@
1
+ require 'optparse'
2
+ require 'optparse/time'
3
+ require 'ostruct'
4
+ require 'pp'
5
+ require_relative 'config'
6
+
7
+ module DuperVisor
8
+ class CLI
9
+ attr_accessor :args, :config, :parser
10
+
11
+ def initialize(args)
12
+ self.args = args
13
+ self.config = Config.new
14
+ end
15
+
16
+ def parse
17
+ self.parser = OptionParser.new do |opts|
18
+ usage_banner(opts)
19
+
20
+ opts.on('--ini', 'Generate an INI file') do
21
+ config.to = :ini
22
+ end
23
+ opts.on('--yaml', 'Generate a YAML file') do
24
+ config.to = :yaml
25
+ end
26
+ opts.on('--json', 'Generate a JSON file') do
27
+ config.to = :json
28
+ end
29
+
30
+ opts.on('-o', '--output [FILE]',
31
+ 'File to write, if not supplied write to STDOUT') do |file|
32
+ config.output = file
33
+ end
34
+
35
+ opts.on('-v', '--verbose',
36
+ 'Print extra debugging info') do
37
+ config.verbose = true
38
+ end
39
+ example_banner(opts)
40
+
41
+ # No argument, shows at tail. This will print an options summary.
42
+ # Try it and see!
43
+ opts.on_tail('-h', '--help', 'Show this message') do
44
+ puts opts
45
+ exit
46
+ end
47
+
48
+ # Another typical switch to print the version.
49
+ opts.on_tail('--version', 'Show version') do
50
+ puts DuperVisor::VERSION
51
+ exit
52
+ end
53
+ end
54
+ parser.parse!(args)
55
+ config
56
+ end
57
+
58
+ def example_banner(opts)
59
+ opts.separator ''
60
+ opts.separator 'Examples:'.bold.blue
61
+ opts.separator ''
62
+ opts.separator ' # guess input format, convert YAML format to an INI file'
63
+ opts.separator ' cat config.yml | dv --ini > config.ini'.green
64
+ opts.separator ''
65
+ opts.separator ' # guess input format, convert INI format to a JSON file '
66
+ opts.separator ' dv config.ini --json -o config.json'.green
67
+
68
+ opts.separator ''
69
+ opts.separator 'Common options:'.bold.blue
70
+ end
71
+
72
+ def usage_banner(opts)
73
+ opts.banner = 'Usage: '.bold.blue + 'dv [source-file] [options] '.bold.green
74
+ opts.separator ''
75
+ opts.separator ' Convert between several hierarchical configuration'
76
+ opts.separator ' file formats, such as ' + 'ini, yaml, json'.bold.green
77
+ opts.separator ''
78
+ opts.separator ' Automatically guesses the source format based either on'
79
+ opts.separator ' the file extension, or by attempting to parse it for STDIN'
80
+ opts.separator ''
81
+ opts.separator 'Specific options:'.bold.blue
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'content'
2
+ require_relative 'renderer'
3
+ require_relative 'detector'
4
+
5
+ module DuperVisor
6
+ class CLIError < ArgumentError
7
+ end
8
+
9
+ class Config
10
+ attr_accessor :to, :output, :verbose
11
+
12
+ def initialize(to: nil, output: nil, verbose: false)
13
+ self.to = to
14
+ self.verbose = verbose
15
+ self.output = output
16
+ end
17
+
18
+ def validate!
19
+ raise CLIError.new('Either the output format or filename is required!') unless to
20
+
21
+ self.output = if output.is_a?(String) && output != ''
22
+ File.open(output, 'w')
23
+ elsif output.respond_to?(:puts)
24
+ output
25
+ else
26
+ STDOUT
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'inifile'
4
+
5
+ module DuperVisor
6
+ #
7
+ # This class is responsible for taking the input and converting it into a
8
+ # Hash. It can also be initialized with the Hash, in which no conversion is performed.
9
+ #
10
+ # The +result+
11
+ class Content
12
+ attr_accessor :body, :format, :parse_result
13
+
14
+ def initialize(body: nil, format: nil)
15
+ self.body = body
16
+ self.format = format
17
+ self.parse_result = {}
18
+ end
19
+
20
+ def self.to_format_from(hash, format)
21
+ format_class = ::DuperVisor::Formats::Base.formats[format]
22
+ raise ArgumentError.new("No format #{format} found") unless format_class
23
+ Content.new(body: format_class.to.call(hash), format: format_class.format)
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,23 @@
1
+ module DuperVisor
2
+ class Detector
3
+ attr_accessor :filename
4
+ def initialize(filename)
5
+ self.filename = filename
6
+ end
7
+
8
+ def detect
9
+ format_from_extension(filename) if filename.is_a?(String)
10
+ end
11
+
12
+ private
13
+
14
+ def format_from_extension(filename)
15
+ extension = filename.gsub(/.*\.([\w]+)/, '\1')
16
+ format = if extension =~ /(json|ya?ml|ini)/i
17
+ f = extension.downcase.to_sym
18
+ f == :yml ? :yaml : f
19
+ end
20
+ format
21
+ end
22
+ end
23
+ end