ngenie 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ngenie.gemspec
4
+ gemspec
5
+
6
+
7
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jan Mendoza
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,29 @@
1
+ # Ngenie
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ngenie'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ngenie
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/ngenie ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('lib/ngenie')
4
+
5
+ Ngenie::CLI.start(ARGV)
@@ -0,0 +1,126 @@
1
+ class Mustache
2
+ class Generator
3
+ def on_routes(name, indentation)
4
+ result = on_fetch([name])
5
+
6
+ ev("ctx.route(#{result}, #{indentation.inspect})")
7
+ end
8
+ end
9
+
10
+ class Context
11
+ def route(str, indentation = '')
12
+ mustache = mustache_in_stack
13
+ part = str.to_s.gsub(/^/, indentation)
14
+
15
+ result = mustache.render(part, self)
16
+ end
17
+ end
18
+
19
+ class Parser
20
+ def scan_tags
21
+ # Scan until we hit an opening delimiter.
22
+ start_of_line = @scanner.beginning_of_line?
23
+ pre_match_position = @scanner.pos
24
+ last_index = @result.length
25
+
26
+ return unless x = @scanner.scan(/([ \t]*)?#{Regexp.escape(otag)}/)
27
+ padding = @scanner[1] || ''
28
+
29
+ # Don't touch the preceding whitespace unless we're matching the start
30
+ # of a new line.
31
+ unless start_of_line
32
+ @result << [:static, padding] unless padding.empty?
33
+ pre_match_position += padding.length
34
+ padding = ''
35
+ end
36
+
37
+ # Since {{= rewrites ctag, we store the ctag which should be used
38
+ # when parsing this specific tag.
39
+ current_ctag = self.ctag
40
+ type = @scanner.scan(/#|\^|\/|=|!|<|>|&|\{/)
41
+ @scanner.skip(/\s*/)
42
+
43
+ # ANY_CONTENT tags allow any character inside of them, while
44
+ # other tags (such as variables) are more strict.
45
+ if ANY_CONTENT.include?(type)
46
+ r = /\s*#{regexp(type)}?#{regexp(current_ctag)}/
47
+ content = scan_until_exclusive(r)
48
+ else
49
+ content = @scanner.scan(ALLOWED_CONTENT)
50
+ end
51
+
52
+ # We found {{ but we can't figure out what's going on inside.
53
+ error "Illegal content in tag" if content.empty?
54
+
55
+ fetch = [:mustache, :fetch, content.split('.')]
56
+ prev = @result
57
+
58
+ # Based on the sigil, do what needs to be done.
59
+ case type
60
+ when '#'
61
+ block = [:multi]
62
+ @result << [:mustache, :section, fetch, block]
63
+ @sections << [content, position, @result]
64
+ @result = block
65
+ when '^'
66
+ block = [:multi]
67
+ @result << [:mustache, :inverted_section, fetch, block]
68
+ @sections << [content, position, @result]
69
+ @result = block
70
+ when '/'
71
+ section, pos, result = @sections.pop
72
+ raw = @scanner.pre_match[pos[3]...pre_match_position] + padding
73
+ (@result = result).last << raw << [self.otag, self.ctag]
74
+
75
+ if section.nil?
76
+ error "Closing unopened #{content.inspect}"
77
+ elsif section != content
78
+ error "Unclosed section #{section.inspect}", pos
79
+ end
80
+ when '!'
81
+ # ignore comments
82
+ when '='
83
+ self.otag, self.ctag = content.split(' ', 2)
84
+ when '>'
85
+ @result << [:mustache, :partial, content, padding]
86
+ when '<'
87
+ @result << [:mustache, :routes, content, padding]
88
+ when '{', '&'
89
+ # The closing } in unescaped tags is just a hack for
90
+ # aesthetics.
91
+ type = "}" if type == "{"
92
+ @result << [:mustache, :utag, fetch]
93
+ else
94
+ @result << [:mustache, :etag, fetch]
95
+ end
96
+
97
+ # Skip whitespace and any balancing sigils after the content
98
+ # inside this tag.
99
+ @scanner.skip(/\s+/)
100
+ @scanner.skip(regexp(type)) if type
101
+
102
+ # Try to find the closing tag.
103
+ unless close = @scanner.scan(regexp(current_ctag))
104
+ error "Unclosed tag"
105
+ end
106
+
107
+ # If this tag was the only non-whitespace content on this line, strip
108
+ # the remaining whitespace. If not, but we've been hanging on to padding
109
+ # from the beginning of the line, re-insert the padding as static text.
110
+ if start_of_line && !@scanner.eos?
111
+ if @scanner.peek(2) =~ /\r?\n/ && SKIP_WHITESPACE.include?(type)
112
+ @scanner.skip(/\r?\n/)
113
+ else
114
+ prev.insert(last_index, [:static, padding]) unless padding.empty?
115
+ end
116
+ end
117
+
118
+ # Store off the current scanner position now that we've closed the tag
119
+ # and consumed any irrelevant whitespace.
120
+ @sections.last[1] << @scanner.pos unless @sections.empty?
121
+
122
+ return unless @result == [:multi]
123
+ end
124
+
125
+ end
126
+ end
data/lib/ngenie.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "ngenie/version"
2
+ require "mustache"
3
+ require "ext/mustache"
4
+ require "docile"
5
+ require "colored"
6
+
7
+ module Ngenie
8
+ WORK_PATH = File.join(ENV['HOME'], '.ngenie') || Dir.pwd
9
+ TEMPLATE_PATH = File.join(WORK_PATH, 'templates')
10
+ CONFD_PATH = File.join(WORK_PATH, 'conf.d')
11
+
12
+ attr_accessor :work_path
13
+
14
+ autoload :Builder, 'ngenie/builder'
15
+ autoload :CLI, 'ngenie/cli'
16
+ autoload :Generator, 'ngenie/generator'
17
+ end
@@ -0,0 +1,8 @@
1
+ module Ngenie
2
+ module Builder
3
+ autoload :BaseBuilder, 'ngenie/builder/base_builder'
4
+ autoload :DomainBuilder, 'ngenie/builder/domain_builder'
5
+ autoload :ProxyBuilder, 'ngenie/builder/proxy_builder'
6
+ autoload :RouteBuilder, 'ngenie/builder/route_builder'
7
+ end
8
+ end
@@ -0,0 +1,58 @@
1
+ module Ngenie::Builder
2
+ class BaseBuilder < Mustache
3
+ DEFAULT_BIND = '127.0.0.1'
4
+ DEFAULT_PORT = '80'
5
+
6
+ attr_accessor :name, :blueprint
7
+
8
+ def initialize(name)
9
+ @name = name
10
+ @bind = DEFAULT_BIND
11
+ @port = DEFAULT_PORT
12
+ end
13
+
14
+ def blueprint(template)
15
+ @blueprint = get_template(template)
16
+ end
17
+
18
+ def build(template='')
19
+
20
+ set_template(template)
21
+
22
+ File.open(File.join(Ngenie::CONFD_PATH, "#{name}.conf"), "w") do |f|
23
+ f.write("# GENERATED BY Ngenie. DO NOT EDIT\n#{render}\n".chomp)
24
+ f.close
25
+ end
26
+ end
27
+
28
+ def get_template(template)
29
+ File.read(File.join(Ngenie::TEMPLATE_PATH, "#{template}.#{self.template_extension}"))
30
+ end
31
+
32
+ def set_template(template)
33
+ self.template = @blueprint || get_template(template)
34
+ end
35
+
36
+ def method_missing(meth, *args, &blk)
37
+ name = meth.to_s
38
+
39
+ klass = class << self; self; end
40
+
41
+ klass.class_eval do
42
+ define_method(name) do |*args|
43
+ if !args.empty?
44
+ self.instance_variable_set(:"@#{name}", args.first)
45
+ else
46
+ self.instance_variable_get(:"@#{name}")
47
+ end
48
+ end
49
+ end
50
+
51
+ send(meth, *args, &blk)
52
+ end
53
+
54
+ def respond_to?(meth)
55
+ meth != :has_key? ? true : super(meth)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ module Ngenie::Builder
2
+ class DomainBuilder < BaseBuilder
3
+ attr_accessor :routes, :file_name
4
+
5
+ def initialize(name)
6
+ super(name)
7
+
8
+ @routes = ''
9
+ end
10
+
11
+ def route(arg='', &blk)
12
+ if arg.empty?
13
+ @routes
14
+ else
15
+ @routes += Docile.dsl_eval(RouteBuilder.new(arg), &blk).build
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Ngenie::Builder
2
+ class ProxyBuilder < BaseBuilder; end
3
+ end
@@ -0,0 +1,9 @@
1
+ module Ngenie::Builder
2
+ class RouteBuilder < BaseBuilder
3
+ def build
4
+ set_template('location')
5
+
6
+ render + "\n"
7
+ end
8
+ end
9
+ end
data/lib/ngenie/cli.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'thor'
2
+
3
+ module Ngenie
4
+ class CLI < Thor
5
+ TREE = { :work_path => WORK_PATH,
6
+ :confd_path => CONFD_PATH,
7
+ :template_path => TEMPLATE_PATH
8
+ }
9
+
10
+ desc "bootstrap", "bootstrap an ngenie deployment"
11
+
12
+ def bootstrap
13
+ bootstrap_work_path
14
+ end
15
+
16
+ desc "check", "check if node has been bootstrapped"
17
+
18
+ def check
19
+
20
+ end
21
+
22
+ desc "generate", "generate nginx config files"
23
+ def generate
24
+ Generator.new.generate
25
+ end
26
+
27
+ no_commands do
28
+ def bootstrap_work_path
29
+ TREE.each { |key, val| create_if_not_exists(key, val) }
30
+ end
31
+
32
+ def create_if_not_exists(name, file)
33
+ if File.exists?(file)
34
+ say("#{name} %s found. Skipping.", :yellow)
35
+ else
36
+ say("#{name} not found. Creating #{name}.", :green)
37
+
38
+ FileUtils.mkdir_p(file)
39
+ say("Done. Created #{name}: #{file}", :green)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ module Ngenie
2
+ class Generator
3
+ DEFAULT_DOMAIN_TEMPLATE = 'domain'
4
+ DEFAULT_PROXY_TEMPLATE = 'upstream'
5
+
6
+ def generate
7
+ load
8
+ end
9
+
10
+ def load
11
+ Dir.glob("%s/*.rb" % WORK_PATH) do |file|
12
+ eval File.read(file), binding, File.basename(file)
13
+ end
14
+ end
15
+
16
+ def proxy(arg, &blk)
17
+ Docile.dsl_eval(Builder::ProxyBuilder.new(arg), &blk).build(DEFAULT_PROXY_TEMPLATE)
18
+ end
19
+
20
+ def domain(arg, &blk)
21
+ Docile.dsl_eval(Builder::DomainBuilder.new(arg), &blk).build(DEFAULT_DOMAIN_TEMPLATE)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Ngenie
2
+ VERSION = "0.0.1"
3
+ end
data/ngenie.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ngenie/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ngenie"
8
+ spec.version = Ngenie::VERSION
9
+ spec.authors = ["Jan Mendoza"]
10
+ spec.email = ["poymode@gmail.com"]
11
+ spec.description = %q{}
12
+ spec.summary = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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_dependency "docile"
22
+ spec.add_dependency "mustache"
23
+ spec.add_dependency "thor"
24
+ spec.add_dependency "colored"
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ module Ngenie
4
+ describe Builder do
5
+ before do
6
+ CLI.start(['bootstrap'])
7
+ end
8
+
9
+
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
18
+
19
+ require File.expand_path('lib/ngenie')
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ngenie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jan Mendoza
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: docile
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mustache
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: thor
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: colored
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: bundler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.3'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.3'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rake
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: ''
127
+ email:
128
+ - poymode@gmail.com
129
+ executables:
130
+ - ngenie
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - .gitignore
135
+ - .rspec
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - bin/ngenie
141
+ - lib/ext/mustache.rb
142
+ - lib/ngenie.rb
143
+ - lib/ngenie/builder.rb
144
+ - lib/ngenie/builder/base_builder.rb
145
+ - lib/ngenie/builder/domain_builder.rb
146
+ - lib/ngenie/builder/proxy_builder.rb
147
+ - lib/ngenie/builder/route_builder.rb
148
+ - lib/ngenie/cli.rb
149
+ - lib/ngenie/generator.rb
150
+ - lib/ngenie/version.rb
151
+ - ngenie.gemspec
152
+ - spec/builder_spec.rb
153
+ - spec/spec_helper.rb
154
+ homepage: ''
155
+ licenses:
156
+ - MIT
157
+ post_install_message:
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ segments:
168
+ - 0
169
+ hash: -3093275548724926976
170
+ required_rubygems_version: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ! '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ segments:
177
+ - 0
178
+ hash: -3093275548724926976
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 1.8.25
182
+ signing_key:
183
+ specification_version: 3
184
+ summary: ''
185
+ test_files:
186
+ - spec/builder_spec.rb
187
+ - spec/spec_helper.rb