doozer 0.2.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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +57 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/bin/doozer +6 -0
- data/doozer.gemspec +156 -0
- data/lib/doozer.rb +35 -0
- data/lib/doozer/active_support/array.rb +14 -0
- data/lib/doozer/active_support/class.rb +221 -0
- data/lib/doozer/active_support/date_time.rb +23 -0
- data/lib/doozer/active_support/object.rb +43 -0
- data/lib/doozer/active_support/time.rb +32 -0
- data/lib/doozer/app.rb +294 -0
- data/lib/doozer/configs.rb +146 -0
- data/lib/doozer/controller.rb +340 -0
- data/lib/doozer/exceptions.rb +12 -0
- data/lib/doozer/extend.rb +10 -0
- data/lib/doozer/initializer.rb +104 -0
- data/lib/doozer/lib.rb +32 -0
- data/lib/doozer/logger.rb +12 -0
- data/lib/doozer/orm/active_record.rb +28 -0
- data/lib/doozer/orm/data_mapper.rb +22 -0
- data/lib/doozer/orm/sequel.rb +21 -0
- data/lib/doozer/partial.rb +99 -0
- data/lib/doozer/plugins/paginate/init.rb +2 -0
- data/lib/doozer/plugins/paginate/lib/paginate.rb +32 -0
- data/lib/doozer/plugins/paginate/lib/paginate/collection.rb +60 -0
- data/lib/doozer/plugins/paginate/lib/paginate/finder.rb +116 -0
- data/lib/doozer/plugins/paginate/lib/paginate/view_helpers.rb +37 -0
- data/lib/doozer/rackup/server.ru +35 -0
- data/lib/doozer/rackup/test.rb +20 -0
- data/lib/doozer/redirect.rb +12 -0
- data/lib/doozer/route.rb +292 -0
- data/lib/doozer/scripts/cluster.rb +126 -0
- data/lib/doozer/scripts/console.rb +2 -0
- data/lib/doozer/scripts/migrate.rb +108 -0
- data/lib/doozer/scripts/task.rb +60 -0
- data/lib/doozer/scripts/test.rb +23 -0
- data/lib/doozer/version.rb +8 -0
- data/lib/doozer/view_helpers.rb +251 -0
- data/lib/doozer/watcher.rb +369 -0
- data/lib/generator/generator.rb +548 -0
- data/templates/skeleton/Rakefile +3 -0
- data/templates/skeleton/app/controllers/application_controller.rb +2 -0
- data/templates/skeleton/app/controllers/index_controller.rb +7 -0
- data/templates/skeleton/app/helpers/application_helper.rb +17 -0
- data/templates/skeleton/app/views/global/_header.html.erb +7 -0
- data/templates/skeleton/app/views/global/_navigation.html.erb +6 -0
- data/templates/skeleton/app/views/index/index.html.erb +108 -0
- data/templates/skeleton/app/views/layouts/default.html.erb +23 -0
- data/templates/skeleton/config/app.yml +31 -0
- data/templates/skeleton/config/boot.rb +17 -0
- data/templates/skeleton/config/database.yml +25 -0
- data/templates/skeleton/config/environment.rb +11 -0
- data/templates/skeleton/config/rack.rb +30 -0
- data/templates/skeleton/config/routes.rb +69 -0
- data/templates/skeleton/script/cluster +4 -0
- data/templates/skeleton/script/console +15 -0
- data/templates/skeleton/script/migrate +4 -0
- data/templates/skeleton/script/task +4 -0
- data/templates/skeleton/script/test +4 -0
- data/templates/skeleton/static/404.html +16 -0
- data/templates/skeleton/static/500.html +16 -0
- data/templates/skeleton/static/css/style.css +32 -0
- data/templates/skeleton/static/favicon.ico +0 -0
- data/templates/skeleton/static/js/application.js +1 -0
- data/templates/skeleton/static/js/jquery-1.3.min.js +19 -0
- data/templates/skeleton/static/robots.txt +5 -0
- data/templates/skeleton/test/fixtures/setup.rb +6 -0
- data/templates/skeleton/test/setup.rb +33 -0
- data/test/doozer_test.rb +7 -0
- data/test/project/Rakefile +3 -0
- data/test/project/app/controllers/application_controller.rb +2 -0
- data/test/project/app/controllers/index_controller.rb +7 -0
- data/test/project/app/helpers/application_helper.rb +17 -0
- data/test/project/app/views/global/_header.html.erb +7 -0
- data/test/project/app/views/global/_navigation.html.erb +6 -0
- data/test/project/app/views/index/index.html.erb +108 -0
- data/test/project/app/views/layouts/default.html.erb +23 -0
- data/test/project/config/app.yml +31 -0
- data/test/project/config/boot.rb +17 -0
- data/test/project/config/database.yml +25 -0
- data/test/project/config/environment.rb +11 -0
- data/test/project/config/rack.rb +30 -0
- data/test/project/config/routes.rb +72 -0
- data/test/project/script/cluster +4 -0
- data/test/project/script/console +15 -0
- data/test/project/script/migrate +4 -0
- data/test/project/script/task +4 -0
- data/test/project/script/test +4 -0
- data/test/project/static/404.html +16 -0
- data/test/project/static/500.html +16 -0
- data/test/project/static/css/style.css +32 -0
- data/test/project/static/favicon.ico +0 -0
- data/test/project/static/js/application.js +1 -0
- data/test/project/static/js/jquery-1.3.min.js +19 -0
- data/test/project/static/robots.txt +5 -0
- data/test/project/test/fixtures/setup.rb +6 -0
- data/test/project/test/setup.rb +33 -0
- data/test/routing_test.rb +66 -0
- data/test/test_helper.rb +26 -0
- metadata +169 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
APP_PATH = Dir.pwd
|
|
4
|
+
require File.join(APP_PATH, 'config/boot')
|
|
5
|
+
|
|
6
|
+
#--boot it up
|
|
7
|
+
Doozer::Initializer.boot(env)
|
|
8
|
+
|
|
9
|
+
#--hookup the logger for production only since the base rackup builder doesn't load it. this avoids double logging in development
|
|
10
|
+
use Rack::CommonLogger, Doozer::Configs.logger if Doozer::Configs.rack_env == :deployment
|
|
11
|
+
|
|
12
|
+
#--map root to doozer
|
|
13
|
+
map "/" do
|
|
14
|
+
# use Rack::ShowExceptions
|
|
15
|
+
if Doozer::Configs.rack_env != :deployment
|
|
16
|
+
use Rack::Reloader, secs=1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
use Rack::Static, {:urls => Doozer::Configs.app["static_urls"], :root => "#{APP_PATH}/#{Doozer::Configs.app["static_root"]}"} if Doozer::Configs.app
|
|
20
|
+
|
|
21
|
+
use Rack::Session::Cookie, :key => 'rack.session',
|
|
22
|
+
:domain => '',
|
|
23
|
+
:path => '/',
|
|
24
|
+
:expire_after => 2592000
|
|
25
|
+
|
|
26
|
+
run Doozer::App.new(args=options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#--stack additional rack apps
|
|
30
|
+
begin
|
|
31
|
+
require "#{APP_PATH}/config/rack"
|
|
32
|
+
stack()
|
|
33
|
+
rescue => e
|
|
34
|
+
Doozer::Configs.logger.error(e)
|
|
35
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
script to bootstrap the doozer/rackup/server.ru in test mode
|
|
3
|
+
since rackup doesn't call Rackup::Builder in test (in rackup this is 'none') mode
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
config = File.expand_path(File.join(File.dirname(__FILE__), 'server.ru'))
|
|
8
|
+
env = :test
|
|
9
|
+
cfgfile = File.read(config)
|
|
10
|
+
if cfgfile[/^#\\(.*)/]
|
|
11
|
+
opts.parse! $1.split(/\s+/)
|
|
12
|
+
end
|
|
13
|
+
ru=[]
|
|
14
|
+
ru.push("options = {:Port => 5000, :Host => '127.0.0.1', :AccessLog => []}")
|
|
15
|
+
ru.push("app = Rack::Builder.new do")
|
|
16
|
+
ru.push("use Rack::CommonLogger")
|
|
17
|
+
ru.push(cfgfile)
|
|
18
|
+
ru.push("end.to_app")
|
|
19
|
+
ru.push("Rack::Handler::Mongrel.run app, :Port => 5000")
|
|
20
|
+
app = eval "Rack::Builder.new {( " + ru.join("\n") + "\n )}.to_app", nil, config
|
data/lib/doozer/route.rb
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
require 'doozer/app'
|
|
2
|
+
|
|
3
|
+
module Doozer
|
|
4
|
+
module Routing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Route manager for drawing and adding routes.
|
|
8
|
+
class Routes
|
|
9
|
+
@@parts=[] # stored as [route.name, route.path]
|
|
10
|
+
@@dict={} # route hash
|
|
11
|
+
@@cache={} # lookup for matches
|
|
12
|
+
@@magics=[] # hold raw magic routes before processing
|
|
13
|
+
@@inner_apps={} # holds the app dedicated to processing this path
|
|
14
|
+
|
|
15
|
+
def self.draw(&block)
|
|
16
|
+
# p "draw routes"
|
|
17
|
+
instance_eval(&block) if block_given?
|
|
18
|
+
|
|
19
|
+
# init magic routes :conrtoller/:action or just /:action with predefined :controller
|
|
20
|
+
# Routes.init_magic_routes
|
|
21
|
+
|
|
22
|
+
# sort routes here
|
|
23
|
+
@@parts.sort! do |a, b| a[1].length <=> b[1].length end
|
|
24
|
+
@@parts.reverse!
|
|
25
|
+
printf "Routes drawn and sorted...\n"
|
|
26
|
+
# @@parts.each { | i | p i[1] }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# An empty path defaults to a path of '/'
|
|
31
|
+
def self.add(name=nil, path=nil, args=nil)
|
|
32
|
+
# p name
|
|
33
|
+
# p path
|
|
34
|
+
# p args.inspect
|
|
35
|
+
if not name.nil? and not path.nil? and not args.nil?
|
|
36
|
+
args = Routes::init_formats(args)
|
|
37
|
+
formats = args[:formats]
|
|
38
|
+
# p formats.inspect
|
|
39
|
+
for format in formats
|
|
40
|
+
args.delete(:formats)
|
|
41
|
+
if name != :magic
|
|
42
|
+
path = '/' if path == ''
|
|
43
|
+
|
|
44
|
+
raise Doozer::Exceptions::Route.new("Route name must be a symbol. #{name} given.") if not name.kind_of? Symbol
|
|
45
|
+
raise Doozer::Exceptions::Route.new("Route already exists with the name of #{name}.") if @@dict[name]
|
|
46
|
+
@@parts.each { |p| raise Doozer::Exceptions::Route.new("Route already defined with a path of '#{path}'") if p[1] == path }
|
|
47
|
+
parts = [name, path, args]
|
|
48
|
+
# p parts.inspect
|
|
49
|
+
args[:format] = format
|
|
50
|
+
route = Doozer::Routing::Route.new(parts)
|
|
51
|
+
# p route.inspect
|
|
52
|
+
@@parts.push([route.name, route.path])
|
|
53
|
+
@@dict[route.name] = route
|
|
54
|
+
else
|
|
55
|
+
p "magic routes init turned off"
|
|
56
|
+
# Routes.magic(parts)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# sets up default formats to initialize a mapped route
|
|
63
|
+
def self.init_formats(args)
|
|
64
|
+
formats = args[:formats]
|
|
65
|
+
formats = [] if formats.nil?
|
|
66
|
+
formats.push(:html) if not formats.include?(:html)
|
|
67
|
+
args[:formats] = formats
|
|
68
|
+
return args
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# return a route by name
|
|
72
|
+
def self.get_by_name(name)
|
|
73
|
+
# p @@dict.inspect
|
|
74
|
+
return @@dict[name]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# return the route which matches the request path
|
|
78
|
+
def self.match(path)
|
|
79
|
+
# p path
|
|
80
|
+
# p @@cache.inspect
|
|
81
|
+
# return @@dict[@@cache[path]] if @@cache[path]
|
|
82
|
+
for part in @@parts
|
|
83
|
+
route = @@dict[part[0]]
|
|
84
|
+
# p route.inspect
|
|
85
|
+
if route.match(path)
|
|
86
|
+
# Routes.cache_request_path(route, path)
|
|
87
|
+
return route
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
return nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# caches the request path and with the route.name
|
|
94
|
+
def self.cache_request_path(route,path)
|
|
95
|
+
# p "route cache request path"
|
|
96
|
+
@@cache[path] = route.name
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.magic(route)
|
|
100
|
+
@@magics.push(route)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.init_magic_routes
|
|
104
|
+
@@controllers={}
|
|
105
|
+
controller_files = Dir.glob(File.join(File.dirname(__FILE__),'../app/controllers/*_controller.rb'))
|
|
106
|
+
|
|
107
|
+
if controller_files.length > 0
|
|
108
|
+
i=0
|
|
109
|
+
for f in controller_files
|
|
110
|
+
break if i==0 and f.index('application_controller.rb')
|
|
111
|
+
if f.index('application_controller.rb')
|
|
112
|
+
controller_files.insert(0, controller_files.delete(f))
|
|
113
|
+
break
|
|
114
|
+
end
|
|
115
|
+
i+=1
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
controller_files.each {|f|
|
|
120
|
+
require f
|
|
121
|
+
key = f.split("controllers/")[1].split("_controller.rb")[0]
|
|
122
|
+
if key.index("_")
|
|
123
|
+
value = key.split('_').each{ | k | k.capitalize! }.join('')
|
|
124
|
+
else
|
|
125
|
+
value = key.capitalize
|
|
126
|
+
end
|
|
127
|
+
@@controllers[key.to_sym] = "#{value}Controller"
|
|
128
|
+
# p "cache controller: #{key.to_sym}"
|
|
129
|
+
}
|
|
130
|
+
# p @@controllers.inspect
|
|
131
|
+
# grab all controllers
|
|
132
|
+
routes = []
|
|
133
|
+
dup_lu = {}
|
|
134
|
+
obj = Doozer::Controller
|
|
135
|
+
obj.public_instance_methods.each { | name | dup_lu[name]=''}
|
|
136
|
+
# p dup_lu.inspect
|
|
137
|
+
|
|
138
|
+
@@magics.each { | route |
|
|
139
|
+
path = route[1]
|
|
140
|
+
if path.index(':controller') and path.index(':action')
|
|
141
|
+
## loop all controller and then loop all #methods
|
|
142
|
+
@@controllers.each{ |key,value |
|
|
143
|
+
klass = Object.const_get(value)
|
|
144
|
+
methods = klass.public_instance_methods()
|
|
145
|
+
methods.push('index')
|
|
146
|
+
methods.uniq! # filter duplicate indexes
|
|
147
|
+
methods.each { | val |
|
|
148
|
+
if dup_lu[val].nil?
|
|
149
|
+
controller= route[2][:controller] || key.to_s
|
|
150
|
+
action = route[2][:action] || val
|
|
151
|
+
# p "#{controller}##{action}"
|
|
152
|
+
name = "#{controller}_#{action}".to_sym
|
|
153
|
+
new_path = path.gsub(/:controller/, controller).gsub(/:action/,action)
|
|
154
|
+
new_path = new_path.gsub(/\/index/) if new_path.endswith('/index')
|
|
155
|
+
new_path = "/#{new_path}" if not new_path =~ /^\//
|
|
156
|
+
add([name, new_path, {:controller=>controller, :action=>action, :status=>200, :formats=>route[2][:formats]}])
|
|
157
|
+
end
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
elsif path.index(':action') and not route[2][:controller].nil?
|
|
161
|
+
## loop all methods on this controller
|
|
162
|
+
#p "load route controller:" + @@controllers[route[2][:controller].to_sym].inspect
|
|
163
|
+
controller= route[2][:controller]
|
|
164
|
+
|
|
165
|
+
klass = Object.const_get(@@controllers[controller.to_sym])
|
|
166
|
+
methods = klass.public_instance_methods()
|
|
167
|
+
methods.push('index')
|
|
168
|
+
methods.uniq! # filter duplicate indexes
|
|
169
|
+
methods.each { | val |
|
|
170
|
+
if dup_lu[val].nil?
|
|
171
|
+
action = val
|
|
172
|
+
# p "#{controller}##{action}"
|
|
173
|
+
name = "#{controller}_#{action}".to_sym
|
|
174
|
+
new_path = path.gsub(/:action/,action)
|
|
175
|
+
new_path = new_path.gsub(/\/index/,'') if new_path =~ /\/index/
|
|
176
|
+
new_path = "/#{new_path}" if not new_path =~ /^\//
|
|
177
|
+
|
|
178
|
+
# p [name, new_path, {:controller=>controller, :action=>action, :status=>200}].inspect
|
|
179
|
+
add([name, new_path, {:controller=>controller, :action=>action, :status=>200, :formats=>route[2][:formats]}])
|
|
180
|
+
end
|
|
181
|
+
}
|
|
182
|
+
end
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
## make sure to route index to '/'
|
|
186
|
+
## loop route/methods pairs
|
|
187
|
+
# save new path for action controller
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
class Route
|
|
192
|
+
attr_accessor :name, :path, :controller, :action,
|
|
193
|
+
:layout, :status, :content_type, :tokens,
|
|
194
|
+
:grouping, :app, :format, :view, :view_path
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# Initializes a route with the following parameters
|
|
198
|
+
# route - [:name, 'path', {args}]
|
|
199
|
+
def initialize(route)
|
|
200
|
+
#p "Doozer::Route#new: #{route}"
|
|
201
|
+
args = route[2]
|
|
202
|
+
@controller = args[:controller]
|
|
203
|
+
@action = args[:action]
|
|
204
|
+
@layout = (args[:layout]) ? args[:layout] : 'default'
|
|
205
|
+
@status = (args[:status]) ? args[:status] : 200
|
|
206
|
+
@app=args[:app]
|
|
207
|
+
@format = (args[:format]) ? args[:format] : :html
|
|
208
|
+
#@content_type = (args[:content_type]) ? args[:content_type] : 'text/html'
|
|
209
|
+
case @format
|
|
210
|
+
when :js
|
|
211
|
+
content_type = 'text/javascript'
|
|
212
|
+
when :xml
|
|
213
|
+
content_type = 'text/xml'
|
|
214
|
+
when :json
|
|
215
|
+
content_type = 'application/json'
|
|
216
|
+
when :rss
|
|
217
|
+
content_type = 'application/rss+xml'
|
|
218
|
+
when :atom
|
|
219
|
+
content_type = 'application/atom+xml'
|
|
220
|
+
else
|
|
221
|
+
content_type = 'text/html'
|
|
222
|
+
end
|
|
223
|
+
@content_type = content_type
|
|
224
|
+
@tokens = []
|
|
225
|
+
path = route[1]
|
|
226
|
+
path = '/' if path == ''
|
|
227
|
+
@path = (@format == :html) ? path : "#{path}.#{format}"
|
|
228
|
+
@name = (@format == :html) ? route[0] : "#{route[0]}_#{format.to_s}".to_sym
|
|
229
|
+
@layout = "default_#{@format.to_s}".to_sym if @format != :html and @layout == 'default'
|
|
230
|
+
|
|
231
|
+
@view = "#{@action}_#{@format.to_s}"
|
|
232
|
+
@view_path = "#{@controller}/#{@action}.#{@format.to_s}.erb"
|
|
233
|
+
regify()
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Creates the Regex grouping for matching and parsing route tokens
|
|
237
|
+
def regify
|
|
238
|
+
if (@path.index('/'))
|
|
239
|
+
grouping = []
|
|
240
|
+
url = @path.split('/')
|
|
241
|
+
for part in url
|
|
242
|
+
if /^:/.match(part)
|
|
243
|
+
token = part.gsub(/:/,'')
|
|
244
|
+
# part = '(?P<'+token+'>.)'
|
|
245
|
+
# part = '(\.*)'
|
|
246
|
+
# part = '(\w*)'
|
|
247
|
+
part = '([a-zA-Z0-9,-.%_~;]*)' # this picks up all allowable route tokens (a-zA-Z0-9,-.%)
|
|
248
|
+
@tokens.push(token)
|
|
249
|
+
end
|
|
250
|
+
grouping.push(part)
|
|
251
|
+
end
|
|
252
|
+
out = "^#{grouping.join('/')}"
|
|
253
|
+
out += ".#{@format.to_s}" if @format != :html # we need to include the
|
|
254
|
+
@grouping = Regexp.compile(out)
|
|
255
|
+
else
|
|
256
|
+
#handle default index route
|
|
257
|
+
@grouping = Regexp.compile("/")
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Matches a request path against a route.path if a direct match or route.grouping
|
|
262
|
+
def match(path)
|
|
263
|
+
# p "#{path} vs #{@path}"
|
|
264
|
+
# p path =~ @grouping
|
|
265
|
+
# short-circut for root
|
|
266
|
+
return false if path == '/' and @path != '/' #handles root condition
|
|
267
|
+
# short-circut for exact match with no tokens
|
|
268
|
+
return true if path == @path
|
|
269
|
+
# test for tokens
|
|
270
|
+
pass=(path =~ @grouping) == 0 ? true : false
|
|
271
|
+
# p @tokens.inspect if pass
|
|
272
|
+
if @tokens.empty?; pass=false if @path != path; end #handles root condition '/'
|
|
273
|
+
pass=false if path.split('/').length != @path.split('/').length #handles the root condition /:token
|
|
274
|
+
return pass
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Parses route tokens and creates a hash of extra params
|
|
278
|
+
def extra_params(path)
|
|
279
|
+
hashish = {}
|
|
280
|
+
params = @grouping.match(path)
|
|
281
|
+
# make sure to remove the format from the last token
|
|
282
|
+
@tokens.last.gsub!(Regexp.compile("\.#{@format.to_s}$"), '') if @format != :html if not @tokens.empty?
|
|
283
|
+
i = 1
|
|
284
|
+
for token in @tokens
|
|
285
|
+
hashish[token.to_sym] = params[i]
|
|
286
|
+
i += 1
|
|
287
|
+
end
|
|
288
|
+
return hashish
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#= start/stop/restart webserver(s)
|
|
2
|
+
# This file is required in script/cluster.
|
|
3
|
+
#
|
|
4
|
+
# Navigate to your app root and run it with the following commands.
|
|
5
|
+
#
|
|
6
|
+
# script/cluster
|
|
7
|
+
# -C command (start || stop || restart || test)
|
|
8
|
+
# -E environment (default: development || deployment)
|
|
9
|
+
# -D (daemonize) - This is automatically initialized in deployment mode. There should be no need to pass this unless you want to test it out in development mode.
|
|
10
|
+
# -h Hellllpppp!!!
|
|
11
|
+
require 'optparse'
|
|
12
|
+
|
|
13
|
+
APP_PATH = Dir.pwd if APP_PATH.nil?
|
|
14
|
+
config = Doozer::Configs.symbolize_keys( YAML.load(File.read(File.join(APP_PATH,'config/app.yml'))) )
|
|
15
|
+
clusters = Doozer::Configs.symbolize_keys(config[:clusters])
|
|
16
|
+
|
|
17
|
+
@command = nil
|
|
18
|
+
@env = :development
|
|
19
|
+
@daemonize = ''
|
|
20
|
+
@server = clusters[:server]
|
|
21
|
+
@config = DOOZER_PATH + '/doozer/rackup/server.ru'
|
|
22
|
+
@test_config = DOOZER_PATH + '/doozer/rackup/test.rb'
|
|
23
|
+
@apps = []
|
|
24
|
+
|
|
25
|
+
for app in clusters[:apps]
|
|
26
|
+
ip = app.split(':')[0]
|
|
27
|
+
port = app.split(':')[1]
|
|
28
|
+
@apps.push({:ip=>ip, :port=>port})
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Automatically starts a test instance of your appserver on http://localhost:5000. (No -E flag is required for this command).
|
|
32
|
+
def test
|
|
33
|
+
cmd = "rackup #{@test_config}"
|
|
34
|
+
printf "Command: #{cmd} -p 5000 -E test -o 127.0.0.1\n"
|
|
35
|
+
system(cmd)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# <b>development</b>: Only starts the first configured (if more then one) address:port
|
|
39
|
+
#
|
|
40
|
+
# <b>deployment</b>: Automatically starts a new instance of your appserver for each defined cluster address:port
|
|
41
|
+
def start
|
|
42
|
+
printf "Starting clusters...\n"
|
|
43
|
+
for app in @apps
|
|
44
|
+
if @env == :deployment
|
|
45
|
+
#need to check if application has a pid file so we don't start
|
|
46
|
+
pid_file = "#{APP_PATH}/log/doozer.#{app[:port]}.pid"
|
|
47
|
+
raise "pid file already exists for #{pid_file}" if File.exist?(pid_file)
|
|
48
|
+
cmd = "rackup #{@config} -p #{app[:port]} -E #{@env.to_s} -s #{@server} -o #{app[:ip]} #{@daemonize} -P #{pid_file}"
|
|
49
|
+
printf "Command: #{cmd}\n"
|
|
50
|
+
system(cmd)
|
|
51
|
+
else
|
|
52
|
+
cmd = "rackup #{@config} -p #{app[:port]} -E #{@env.to_s} -s #{@server} -o #{app[:ip]}"
|
|
53
|
+
printf "Command: #{cmd}\n"
|
|
54
|
+
system(cmd)
|
|
55
|
+
break
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
printf "Did they start?\n"
|
|
59
|
+
system("ps -aux | grep rackup")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Calls stop() and then start()
|
|
63
|
+
def restart
|
|
64
|
+
stop
|
|
65
|
+
start
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# <b>development</b>: Only stops the first configured (if more then one) address:port
|
|
69
|
+
#
|
|
70
|
+
# <b>deployment</b>: Automatically stops all instances of your appserver for each defined cluster address:port
|
|
71
|
+
def stop
|
|
72
|
+
system("ps -aux | grep rackup")
|
|
73
|
+
printf "Stoping clusters...\n"
|
|
74
|
+
for app in @apps
|
|
75
|
+
if @env == :deployment
|
|
76
|
+
pid_file = "#{APP_PATH}/log/doozer.#{app[:port]}.pid"
|
|
77
|
+
printf "Reading pid from #{pid_file}\n"
|
|
78
|
+
if File.exist?(pid_file)
|
|
79
|
+
File.open(pid_file, 'r'){ | f |
|
|
80
|
+
pid = f.gets.to_i
|
|
81
|
+
printf "Shutting down process #{pid}\n"
|
|
82
|
+
system("kill -9 #{pid}")
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
File.delete(pid_file)
|
|
86
|
+
else
|
|
87
|
+
printf "pid file doesn't exist\n"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
system("ps | grep rackup")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
opts = OptionParser.new("", 24, ' ') { |opts|
|
|
95
|
+
opts.banner = "Usage: script/cluster -C [command] -E [environment] -h"
|
|
96
|
+
opts.separator ""
|
|
97
|
+
opts.separator "Command options:"
|
|
98
|
+
opts.on("-C", "--command COMMAND", "start, stop, restart, or test") { | c |
|
|
99
|
+
@command = c.downcase.to_sym
|
|
100
|
+
}
|
|
101
|
+
opts.on("-E", "--env ENVIRONMENT", "default: development || deployment") { | e |
|
|
102
|
+
@env = e.downcase.to_sym
|
|
103
|
+
}
|
|
104
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
|
105
|
+
puts opts
|
|
106
|
+
exit
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
opts.parse! ARGV
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@daemonize = '-D' if @env == :deployment
|
|
113
|
+
|
|
114
|
+
case @command
|
|
115
|
+
when :start
|
|
116
|
+
start()
|
|
117
|
+
when :restart
|
|
118
|
+
restart()
|
|
119
|
+
when :stop
|
|
120
|
+
stop()
|
|
121
|
+
when :test
|
|
122
|
+
test()
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|