nitro 0.23.0 → 0.24.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.
Files changed (76) hide show
  1. data/CHANGELOG +350 -0
  2. data/INSTALL +2 -2
  3. data/ProjectInfo +61 -0
  4. data/README +5 -4
  5. data/Rakefile +5 -4
  6. data/bin/nitrogen +3 -1
  7. data/doc/AUTHORS +27 -3
  8. data/doc/RELEASES +193 -0
  9. data/doc/lhttpd.txt +4 -0
  10. data/lib/nitro.rb +1 -1
  11. data/lib/nitro/adapter/cgi.rb +6 -321
  12. data/lib/nitro/adapter/fastcgi.rb +2 -14
  13. data/lib/nitro/adapter/scgi.rb +237 -71
  14. data/lib/nitro/adapter/webrick.rb +25 -7
  15. data/lib/nitro/caching.rb +1 -0
  16. data/lib/nitro/cgi.rb +296 -0
  17. data/lib/nitro/{cookie.rb → cgi/cookie.rb} +0 -0
  18. data/lib/nitro/cgi/http.rb +62 -0
  19. data/lib/nitro/{request.rb → cgi/request.rb} +4 -1
  20. data/lib/nitro/{response.rb → cgi/response.rb} +0 -0
  21. data/lib/nitro/cgi/stream.rb +43 -0
  22. data/lib/nitro/cgi/utils.rb +38 -0
  23. data/lib/nitro/compiler.rb +23 -11
  24. data/lib/nitro/compiler/css.rb +8 -0
  25. data/lib/nitro/compiler/morphing.rb +66 -0
  26. data/lib/nitro/context.rb +21 -30
  27. data/lib/nitro/controller.rb +23 -100
  28. data/lib/nitro/dispatcher.rb +18 -8
  29. data/lib/nitro/element.rb +6 -2
  30. data/lib/nitro/flash.rb +2 -2
  31. data/lib/nitro/mixin/buffer.rb +2 -2
  32. data/lib/nitro/mixin/form.rb +204 -93
  33. data/lib/nitro/mixin/javascript.rb +170 -11
  34. data/lib/nitro/mixin/markup.rb +1 -0
  35. data/lib/nitro/mixin/pager.rb +7 -4
  36. data/lib/nitro/mixin/rss.rb +2 -0
  37. data/lib/nitro/mixin/table.rb +23 -6
  38. data/lib/nitro/mixin/xhtml.rb +2 -2
  39. data/lib/nitro/render.rb +19 -5
  40. data/lib/nitro/scaffold.rb +12 -6
  41. data/lib/nitro/server.rb +4 -6
  42. data/lib/nitro/server/runner.rb +2 -2
  43. data/lib/nitro/session.rb +8 -1
  44. data/lib/nitro/session/file.rb +40 -0
  45. data/lib/part/admin.rb +2 -0
  46. data/lib/part/admin/controller.rb +7 -3
  47. data/lib/part/admin/skin.rb +8 -1
  48. data/lib/part/admin/template/index.xhtml +39 -1
  49. data/proto/public/error.xhtml +5 -3
  50. data/proto/public/js/behaviour.js +254 -254
  51. data/proto/public/js/controls.js +427 -165
  52. data/proto/public/js/dragdrop.js +255 -276
  53. data/proto/public/js/effects.js +476 -277
  54. data/proto/public/js/prototype.js +561 -127
  55. data/proto/public/js/scaffold.js +74 -0
  56. data/proto/public/js/scriptaculous.js +44 -0
  57. data/proto/public/js/util.js +548 -0
  58. data/proto/public/scaffold/list.xhtml +4 -1
  59. data/proto/scgi.rb +333 -0
  60. data/script/scgi_ctl +221 -0
  61. data/script/scgi_service +120 -0
  62. data/test/nitro/adapter/raw_post1.bin +0 -0
  63. data/test/nitro/{tc_cookie.rb → cgi/tc_cookie.rb} +1 -1
  64. data/test/nitro/{tc_request.rb → cgi/tc_request.rb} +1 -1
  65. data/test/nitro/mixin/tc_xhtml.rb +1 -1
  66. data/test/nitro/{adapter/tc_cgi.rb → tc_cgi.rb} +12 -12
  67. data/test/nitro/tc_controller.rb +9 -5
  68. metadata +159 -169
  69. data/benchmark/bench.rb +0 -5
  70. data/benchmark/simple-webrick-n-200.txt +0 -44
  71. data/benchmark/static-webrick-n-200.txt +0 -43
  72. data/benchmark/tiny-lhttpd-n-200-c-5.txt +0 -43
  73. data/benchmark/tiny-webrick-n-200-c-5.txt +0 -44
  74. data/benchmark/tiny-webrick-n-200.txt +0 -44
  75. data/benchmark/tiny2-webrick-n-200.txt +0 -44
  76. data/examples/README +0 -7
@@ -1,9 +1,12 @@
1
1
  <SystemPage name="List of %list_name%">
2
2
  <h2><a href="#@base/new_%name%">New %name%</a></h2>
3
+ <form action="search">
4
+ Search %list_name%: <input type="text" name="q" />&nbsp;<input type="submit" value="Search" /> (not implemented yet)
5
+ </form>
3
6
  <table>
4
7
  <?r for obj in @%list_name% ?>
5
8
  <tr>
6
- <td width="100%">#{obj.to_s}</td>
9
+ <td width="100%"><a href="#@base/edit_%name%/#{obj.oid}">#{obj.to_s}</a></td>
7
10
  <?r if obj.respond_to?(:update_time) ?>
8
11
  <td nowrap="1">#{obj.update_time.stamp(:db)}</td>
9
12
  <?r end ?>
data/proto/scgi.rb ADDED
@@ -0,0 +1,333 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stringio'
4
+ require 'yaml'
5
+ require 'digest/sha1'
6
+ require 'logger'
7
+ require 'fileutils'
8
+ require 'socket'
9
+ require 'cgi'
10
+ require 'rubygems'
11
+ require 'cmdparse'
12
+ require 'monitor'
13
+
14
+ def log(msg)
15
+ $stderr.print msg,"\n"
16
+ end
17
+
18
+ def error(msg, exc=nil)
19
+ if exc
20
+ $stderr.print "ERROR: #{msg}: #{exc}\n"
21
+ $stderr.puts exc.backtrace
22
+ else
23
+ $stderr.print "ERROR: #{msg}\n"
24
+ end
25
+ end
26
+
27
+
28
+ # Modifies CGI so that we can use it.
29
+ class SCGIFixed < ::CGI
30
+ public :env_table
31
+
32
+ def initialize(params, data, out, *args)
33
+ @env_table = params
34
+ @args = *args
35
+ @input = StringIO.new(data)
36
+ @out = out
37
+ super(*args)
38
+ end
39
+ def args
40
+ @args
41
+ end
42
+ def env_table
43
+ @env_table
44
+ end
45
+ def stdinput
46
+ @input
47
+ end
48
+ def stdoutput
49
+ @out
50
+ end
51
+ end
52
+
53
+
54
+ class SCGIProcessor < Monitor
55
+
56
+ def initialize(settings)
57
+ @env = settings[:env] || "development"
58
+ @debug = settings[:debug] || false
59
+ @host = settings[:host] || "127.0.0.1"
60
+ @port = settings[:port] || "9999"
61
+ @children = settings[:children] || 1
62
+ @pid_file = settings[:pid_file] || "children.yaml"
63
+ @status_dir = settings[:status_dir] || "/tmp"
64
+ @log_file = settings[:logfile] || "log/scgi.log"
65
+ @maxconns = settings[:maxconns]
66
+ @busy_msg = settings[:busy_msg] || "BUSY"
67
+ @settings = settings
68
+ @started = Time.now
69
+ @conns = 0
70
+ @total_conns = 0
71
+ @errors = 0
72
+
73
+ if @maxconns
74
+ @maxconns = @maxconns.to_i
75
+ else
76
+ @maxconns = 2**30-1
77
+ end
78
+
79
+ if settings[:conns_second]
80
+ @throttle_sleep = 1.0/settings[:conns_second].to_i
81
+ end
82
+
83
+ super()
84
+ end
85
+
86
+ def run
87
+ ENV['NITRO_ENV'] = @env
88
+
89
+ require 'nitro'
90
+ server = TCPServer.new(@host, @port)
91
+
92
+ if @debug
93
+ log("Listening for connections on #@host:#@port")
94
+ listen(server)
95
+ else
96
+ childpids = []
97
+ @children.to_i.times do
98
+ # fork each child listening to the same port. very simple yet effective way to spread the load
99
+ # to multiple processes without using threads and still using high performance libevent
100
+ begin
101
+ pid = fork do
102
+ $stderr = open(@log_file,"w")
103
+ $stderr.sync = false
104
+ listen(server)
105
+ end
106
+ childpids << pid
107
+ Process.detach(pid)
108
+ rescue Object
109
+ error("Could not fork child processes. Your system might not support fork. Use -D instead.", $!)
110
+ end
111
+ end
112
+
113
+ # tell the user what the sha1 is so they can check for modification later
114
+ log("#@pid_file will have SHA1 #{Digest::SHA1.hexdigest(YAML.dump(childpids))}")
115
+ log("Record this somewhere so you know if it was modified later by someone else.")
116
+ # all children forked and the pids are now ready to write to the pid file
117
+ open(@pid_file,"w") { |f| f.write(YAML.dump(childpids)) }
118
+ end
119
+ end
120
+
121
+
122
+ def listen(socket)
123
+ thread = Thread.new do
124
+ while true
125
+ handle_client(socket.accept)
126
+ sleep @throttle_sleep if @throttle_sleep
127
+
128
+ @total_conns += 1
129
+ end
130
+ end
131
+
132
+ begin
133
+ thread.join
134
+ rescue Interrupt
135
+ log("Shutting down from SIGINT.")
136
+ rescue Object
137
+ error("while listening for connections on #@host:#@port", $!)
138
+ end
139
+ end
140
+
141
+
142
+ def handle_client(socket)
143
+ Thread.new do
144
+ begin
145
+ synchronize { @conns += 1}
146
+
147
+ len = ""
148
+ # we only read 10 bytes of the length. any request longer than this is invalid
149
+ while len.length <= 10
150
+ c = socket.read(1)
151
+ if c == ':'
152
+ # found the terminal, len now has a length in it so read the payload
153
+ break
154
+ else
155
+ len << c
156
+ end
157
+ end
158
+
159
+ # we should now either have a payload length to get
160
+ payload = socket.read(len.to_i)
161
+ if (c = socket.read(1)) != ','
162
+ error("Malformed request, does not end with ','")
163
+ else
164
+ read_header(socket, payload, @conns)
165
+ end
166
+ rescue IOError
167
+ error("received IOError #$! when handling client. Your web server doesn't like me.")
168
+ rescue Object
169
+ @errors += 1
170
+ error("after accepting client #@host:#@port -- #{$!.class}", $!)
171
+ ensure
172
+ synchronize { @conns -= 1}
173
+ socket.close if not socket.closed?
174
+ end
175
+ end
176
+
177
+ end
178
+
179
+
180
+ def read_header(socket, payload, conns)
181
+ return if socket.closed?
182
+ request = split_body(payload)
183
+ if request and request["CONTENT_LENGTH"]
184
+ length = request["CONTENT_LENGTH"].to_i
185
+ if length > 0
186
+ body = socket.read(length)
187
+ else
188
+ body = ""
189
+ end
190
+
191
+ if @conns > @maxconns
192
+ socket.write("Content-type: text/plain\r\n\r\n")
193
+ socket.write(@busy_msg)
194
+ else
195
+ process_request(request, body, socket)
196
+ end
197
+ end
198
+ end
199
+
200
+
201
+ def process_request(request, body, socket)
202
+ return if socket.closed?
203
+ cgi = SCGIFixed.new(request, body, socket)
204
+ begin
205
+ synchronize do
206
+ # unfortuneatly, the dependencies.rb file is not thread safe and will throw exceptions
207
+ # claiming that Dispatcher is not defined, or that other classes are missing. We have
208
+ # to sync the dispatch call to get around this.
209
+ Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, cgi.stdoutput)
210
+ end
211
+ rescue IOError
212
+ error("received IOError #$! when handling client. Your web server doesn't like me.")
213
+ rescue Object => nitro_error
214
+ error("calling Dispatcher.dispatch", nitro_error)
215
+ end
216
+ end
217
+
218
+
219
+ def split_body(data)
220
+ result = {}
221
+ el = data.split("\0")
222
+ i = 0
223
+ len = el.length
224
+ while i < len
225
+ result[el[i]] = el[i+1]
226
+ i += 1
227
+ end
228
+
229
+ return result
230
+ end
231
+
232
+ def status
233
+ pid = Process.pid
234
+ open("#@status_dir/scgi_nitro_status.#{pid}","w") do |f|
235
+ status = {
236
+ 'time' => Time.now, 'pid' => pid, 'settings' => @settings,
237
+ 'env' => @env, 'status_dir' => @status_dir, 'started' => @started,
238
+ 'max_conns' => @maxconns, 'total_conns' => @total_conns,
239
+ 'conns' => @conns, 'errors' => @errors, 'systimes' => Process.times
240
+ }
241
+ f.write(YAML.dump(status))
242
+ end
243
+ end
244
+ end
245
+
246
+
247
+ def signal_children(pidfile, signal)
248
+ if not File.exists? pidfile
249
+ log("No #{pidfile} as specified. Probably nothing running or wrong path.")
250
+ exit 1
251
+ end
252
+
253
+ childpids = YAML.load_file(pidfile)
254
+ childpids.each do |pid|
255
+ begin
256
+ log("Signaling pid #{pid}")
257
+ Process.kill(signal, pid)
258
+ rescue Object
259
+ log("Couldn't send #{signal} signal to #{pid} pid.")
260
+ end
261
+ end
262
+ end
263
+
264
+
265
+ def make_command(parent, name, desc, options)
266
+ cmd = CmdParse::Command.new(name, false )
267
+ cmd.short_desc = desc
268
+ settings = {}
269
+ cmd.options = CmdParse::OptionParserWrapper.new do |opt|
270
+ options.each do |short, long, info, symbol|
271
+ opt.on(short, long, info) {|val| settings[symbol] = val}
272
+ end
273
+ end
274
+ cmd.set_execution_block do |args|
275
+ yield(settings, args)
276
+ end
277
+ parent.add_command(cmd)
278
+ end
279
+
280
+
281
+ cmd = CmdParse::CommandParser.new( true )
282
+ cmd.program_name = 'scgi'
283
+ cmd.program_version = [0, 2, 1]
284
+ cmd.options = CmdParse::OptionParserWrapper.new do |opt|
285
+ opt.separator "Global options:"
286
+ opt.on("--verbose", "Be verbose when outputting info") {|t| $verbose = true }
287
+ end
288
+
289
+ cmd.add_command( CmdParse::HelpCommand.new )
290
+ cmd.add_command( CmdParse::VersionCommand.new )
291
+
292
+ make_command(cmd, 'start', "Start Nitro Application",
293
+ [['-e','--env STRING','Nitro environment', :env],
294
+ ['-D','--[no-]debug', 'Do not fork children, stay in foreground.', :debug],
295
+ ['-h','--host STRING', 'IP address to bind as server', :host],
296
+ ['-p','--port NUMBER', 'Port to bind to', :port],
297
+ ['-c','--children NUMBER', 'Number of children to start (not win32)', :children],
298
+ ['-f','--pid-file PATH', 'Where to read the list of running children', :pid_file],
299
+ ['-l','--log-file PATH', 'Use a different log from from log/scgi.log', :logfile],
300
+ ['-t','--throttle NUMBER', 'Max conn/second to allow.', :conns_second],
301
+ ['-m','--max-conns NUMBER', 'Max simultaneous connections before the busy message', :maxconns],
302
+ ['-b','--busy-msg', 'Busy message given to clients over the max connections ("busy")', :busy_msg],
303
+ ['-s','--status-dir PATH', 'Where to put the status files', :status_dir]]) do |settings, args|
304
+ scgi = SCGIProcessor.new(settings)
305
+ begin
306
+ trap("HUP") { scgi.status }
307
+ rescue Object
308
+ error("Could not setup a SIGHUP handler. You won't be able to get status.")
309
+ end
310
+
311
+ scgi.run
312
+ end
313
+
314
+
315
+ make_command(cmd, 'status', "Get status from all running children",
316
+ [['-s','--status-dir PATH', 'Where to put the status files', :status_dir],
317
+ ['-f','--pid-file PATH', 'Where to read the list of running children', :pid_file]]) do |settings, args|
318
+ signal_children(settings[:pid_file] || 'children.yaml', "HUP")
319
+ log("Status files for each child should show up in the configured status directory (/tmp by default).")
320
+ end
321
+
322
+ make_command(cmd, 'stop', "Stop all running children",
323
+ [['-s','--sig SIGNAL', 'Where to put the status files', :signal],
324
+ ['-n','--[no-]delete', 'Keep the children.yaml file rather than delete', :nodelete],
325
+ ['-f','--pid-file PATH', 'Where to read the list of running children', :pid_file]]) do |settings, args|
326
+ pid_file = settings[:pid_file] || "children.yaml"
327
+ signal_children(pid_file, settings[:signal] || "INT")
328
+ if not settings[:nodelete] and File.exist?(pid_file)
329
+ File.unlink(pid_file)
330
+ end
331
+ end
332
+
333
+ cmd.parse
data/script/scgi_ctl ADDED
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env ruby
2
+ require 'drb'
3
+ require 'rubygems'
4
+ require 'cmdparse'
5
+ require 'yaml'
6
+ require 'highline'
7
+
8
+ UI = HighLine.new
9
+ DEFAULT_CONFIG = "conf/scgi.yaml"
10
+
11
+ def safe(error)
12
+ begin
13
+ yield
14
+ rescue Object
15
+ STDERR.puts("ERROR: #{error}: #$!")
16
+ exit 1
17
+ end
18
+ end
19
+
20
+ def load_config(file)
21
+ safe("Could not load config") do
22
+ return YAML.load_file(file)
23
+ end
24
+ end
25
+
26
+ def connect(url)
27
+ conn = nil
28
+ safe("Can't connect to #{url}") do
29
+ conn = DRbObject.new(nil, url)
30
+ end
31
+
32
+ safe("Failed communicating with #{url}") do
33
+ yield conn
34
+ end
35
+ end
36
+
37
+ def deduce_url(settings)
38
+ settings[:control_url] || load_config(settings[:config] || DEFAULT_CONFIG)[:control_url]
39
+ end
40
+
41
+ def defaults(settings)
42
+ defaults = nil
43
+ if settings[:merge]
44
+ UI.say("Merging with previous settings.")
45
+ defaults = load_config(settings[:config] || DEFAULT_CONFIG)
46
+ else
47
+ defaults = {
48
+ :env => "production",
49
+ :host => "127.0.0.1",
50
+ :port => 9999,
51
+ :logfile => "log/scgi.log",
52
+ :config => DEFAULT_CONFIG }
53
+ end
54
+
55
+ settings = defaults.merge(settings)
56
+ # fix up the stuff that's not quite right yet
57
+ settings[:control_url] = "druby://127.0.0.1:#{settings[:port]-1000}"
58
+ settings[:port] = settings[:port].to_i
59
+ settings[:throttle] = settings[:throttle].to_i if settings[:throttle]
60
+ settings[:maxconns] = settings[:maxconns].to_i if settings[:maxconns]
61
+
62
+ return settings
63
+ end
64
+
65
+
66
+ def configure(settings)
67
+ settings = defaults(settings)
68
+
69
+ pass = settings[:password] || UI.ask("What password do you want? ")
70
+ salting = ('a' .. 'z').to_a + ('A' .. 'Z').to_a + ('0' .. '9').to_a
71
+ settings[:password] = pass.crypt(salting[rand(salting.length)] + salting[rand(salting.length)])
72
+
73
+ # great, they are not idiots. Well, they can read --help at least.
74
+ safe("Could not write config") do
75
+ open(settings[:config],"w") {|f| f.write(YAML.dump(settings)) }
76
+ UI.say("Configuration settings written to #{settings[:config]}")
77
+ end
78
+ end
79
+
80
+ def password
81
+ if not $password
82
+ $password = UI.ask("Password: ")
83
+ end
84
+ $password
85
+ end
86
+
87
+ def start(cmd, config)
88
+ fork do
89
+ exec cmd, config
90
+ end
91
+ end
92
+
93
+ def status(url)
94
+ connect(url) do |conn|
95
+ s = conn.status(password)
96
+ times = s[:systimes]
97
+
98
+ puts <<-END
99
+ #{UI.color("Status as of #{s[:time]}:",:green,:bold)}
100
+ PID: #{s[:pid]}\tStarted: #{s[:started]}\tEnvironment: #{s[:env]}
101
+ Connected Requests: #{s[:conns]}
102
+ Conns/Second: #{s[:conns_second] || "Not Set"}
103
+ Max Simultaneous Conns: #{s[:max_conns]}
104
+ Shutdown Started: #{s[:shutdown]}
105
+ Processing Time: #{times.utime} #{times.stime} #{times.cutime} #{times.cstime}
106
+ Current Settings:
107
+ #{s[:settings].to_yaml.gsub(/:([a-z])/, ' \1')}
108
+ END
109
+ end
110
+ end
111
+
112
+ def reconfigure(url)
113
+ connect(url) do |conn|
114
+ conn.reconfigure(password)
115
+ end
116
+ end
117
+
118
+ def stop(url, force)
119
+ connect(url) do |conn|
120
+ conn.shutdown(password, force)
121
+ end
122
+ end
123
+
124
+ def restart(url, force)
125
+ connect(url) do |conn|
126
+ conn.restart(password, force)
127
+ end
128
+ end
129
+
130
+ def monitor(url)
131
+ connect(url) do |conn|
132
+ while true
133
+ sleep 3
134
+ puts "\e[2J"
135
+ status(url)
136
+ end
137
+ end
138
+ end
139
+
140
+
141
+ def make_command(parent, name, desc, options)
142
+ cmd = CmdParse::Command.new(name, false )
143
+ cmd.short_desc = desc
144
+ settings = {}
145
+ cmd.options = CmdParse::OptionParserWrapper.new do |opt|
146
+ options.each do |short, long, info, symbol|
147
+ opt.on(short, long, info) {|val| settings[symbol] = val}
148
+ end
149
+ end
150
+ cmd.set_execution_block do |args|
151
+ yield(settings, args)
152
+ end
153
+ parent.add_command(cmd)
154
+ end
155
+
156
+
157
+ cmd = CmdParse::CommandParser.new( true )
158
+ cmd.program_name = "scgi_nitro"
159
+ cmd.program_version = [0, 4, 0]
160
+ cmd.options = CmdParse::OptionParserWrapper.new do |opt|
161
+ opt.separator "Global options:"
162
+ opt.on("--verbose", "Be verbose when outputting info") {|t| $verbose = true }
163
+ end
164
+
165
+ cmd.add_command( CmdParse::HelpCommand.new )
166
+ cmd.add_command( CmdParse::VersionCommand.new )
167
+
168
+ make_command(cmd, 'config', "Configure the SCGI servers",
169
+ [['-e','--env STRING','Nitro environment', :env],
170
+ ['-h','--host STRING', 'IP address to bind as server', :host],
171
+ ['-p','--port NUMBER', 'Port to bind to (starts at 9999)', :port],
172
+ ['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
173
+ ['-l','--log-file PATH', 'Use a different log from from log/scgi.log', :logfile],
174
+ ['-t','--throttle NUMBER', 'Max conn/second to allow.', :conns_second],
175
+ ['-m','--max-conns NUMBER', 'Max simultaneous connections before the busy message', :maxconns],
176
+ ['-P','--moron-mode PASSWORD', 'You are an idiot and you want your password on the command line', :password],
177
+ ['-M','--merge', 'Merge new settings with previous rather than defaults', :merge],
178
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config]]) do |settings, args|
179
+ configure(settings)
180
+ end
181
+
182
+ make_command(cmd, 'start', "Start the application",
183
+ [['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
184
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config]]) do |settings, args|
185
+ cmd = File.dirname(__FILE__) + "/scgi_service"
186
+ start(cmd, settings[:config] || DEFAULT_CONFIG)
187
+ end
188
+
189
+ make_command(cmd, 'reconfig', "Reconfigure the SCGI servers with a new config",
190
+ [['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
191
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config]]) do |settings, args|
192
+ reconfigure(deduce_url(settings))
193
+ end
194
+
195
+ make_command(cmd, 'status', "Get status",
196
+ [['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
197
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config]]) do |settings, args|
198
+ status(deduce_url(settings))
199
+ end
200
+
201
+ make_command(cmd, 'stop', "Stop the application",
202
+ [['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
203
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config],
204
+ ['-f','--force', 'Forced shutdown rather than graceful (default graceful)', :force]]) do |settings, args|
205
+ stop(deduce_url(settings), settings[:force] || false)
206
+ end
207
+
208
+ make_command(cmd, 'restart', "Restart the application",
209
+ [['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
210
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config],
211
+ ['-f','--force', 'Forced shutdown rather than graceful (default graceful)', :force]]) do |settings, args|
212
+ restart(deduce_url(settings), settings[:force] || false)
213
+ end
214
+
215
+ make_command(cmd, 'monitor', "Monitor the application",
216
+ [['-u','--control-url URL', 'DRuby URL to run control on (same as SCGI -1000)', :control_url],
217
+ ['-c','--config PATH', 'Config file to use (#{DEFAULT_CONFIG})', :config]]) do |settings, args|
218
+ monitor(deduce_url(settings))
219
+ end
220
+
221
+ cmd.parse