rails 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rails might be problematic. Click here for more details.
- data/CHANGELOG +1020 -10
- data/MIT-LICENSE +1 -1
- data/README +110 -60
- data/Rakefile +74 -139
- data/bin/about +1 -1
- data/bin/console +1 -1
- data/bin/destroy +1 -1
- data/bin/generate +1 -1
- data/bin/performance/request +3 -0
- data/bin/plugin +1 -1
- data/bin/process/{spinner → inspector} +1 -1
- data/bin/rails +10 -12
- data/bin/runner +1 -1
- data/bin/server +1 -1
- data/{lib/rails_info.rb → builtin/rails_info/rails/info.rb} +33 -14
- data/builtin/rails_info/rails/info_controller.rb +9 -0
- data/builtin/rails_info/rails/info_helper.rb +2 -0
- data/builtin/rails_info/rails_info_controller.rb +2 -0
- data/configs/apache.conf +1 -1
- data/configs/databases/frontbase.yml +28 -0
- data/configs/databases/mysql.yml +54 -0
- data/configs/databases/oracle.yml +39 -0
- data/configs/databases/postgresql.yml +48 -0
- data/configs/databases/sqlite2.yml +16 -0
- data/configs/databases/sqlite3.yml +19 -0
- data/configs/initializers/inflections.rb +10 -0
- data/configs/initializers/mime_types.rb +5 -0
- data/configs/lighttpd.conf +29 -15
- data/configs/routes.rb +27 -11
- data/doc/README_FOR_APP +1 -1
- data/environments/boot.rb +103 -14
- data/environments/development.rb +5 -6
- data/environments/environment.rb +36 -30
- data/environments/production.rb +2 -3
- data/environments/test.rb +5 -2
- data/fresh_rakefile +2 -2
- data/helpers/application.rb +8 -2
- data/helpers/test_helper.rb +10 -0
- data/html/404.html +27 -5
- data/html/422.html +30 -0
- data/html/500.html +27 -5
- data/html/index.html +6 -6
- data/html/javascripts/application.js +2 -0
- data/html/javascripts/controls.js +532 -319
- data/html/javascripts/dragdrop.js +521 -133
- data/html/javascripts/effects.js +708 -442
- data/html/javascripts/prototype.js +3393 -953
- data/html/robots.txt +5 -1
- data/lib/code_statistics.rb +2 -2
- data/lib/commands/console.rb +18 -9
- data/lib/commands/performance/profiler.rb +25 -9
- data/lib/commands/performance/request.rb +6 -0
- data/lib/commands/plugin.rb +196 -96
- data/lib/commands/process/inspector.rb +68 -0
- data/lib/commands/process/reaper.rb +90 -71
- data/lib/commands/process/spawner.rb +188 -21
- data/lib/commands/process/spinner.rb +3 -3
- data/lib/commands/runner.rb +28 -7
- data/lib/commands/server.rb +20 -9
- data/lib/commands/servers/base.rb +31 -0
- data/lib/commands/servers/lighttpd.rb +60 -26
- data/lib/commands/servers/mongrel.rb +69 -0
- data/lib/commands/servers/webrick.rb +18 -11
- data/lib/console_app.rb +30 -0
- data/lib/console_sandbox.rb +2 -2
- data/lib/console_with_helpers.rb +26 -0
- data/lib/dispatcher.rb +3 -78
- data/lib/fcgi_handler.rb +98 -64
- data/lib/initializer.rb +323 -194
- data/lib/rails/plugin/loader.rb +150 -0
- data/lib/rails/plugin/locator.rb +78 -0
- data/lib/rails/plugin.rb +84 -0
- data/lib/{rails_version.rb → rails/version.rb} +1 -1
- data/lib/rails_generator/base.rb +85 -25
- data/lib/rails_generator/commands.rb +122 -40
- data/lib/rails_generator/generated_attribute.rb +42 -0
- data/lib/rails_generator/generators/applications/app/USAGE +0 -7
- data/lib/rails_generator/generators/applications/app/app_generator.rb +67 -28
- data/lib/rails_generator/generators/components/controller/USAGE +11 -12
- data/lib/rails_generator/generators/components/controller/controller_generator.rb +2 -3
- data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +1 -11
- data/lib/rails_generator/generators/components/controller/templates/{view.rhtml → view.html.erb} +0 -0
- data/lib/rails_generator/generators/components/integration_test/USAGE +8 -0
- data/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb +16 -0
- data/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +10 -0
- data/lib/rails_generator/generators/components/mailer/USAGE +9 -11
- data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +10 -8
- data/lib/rails_generator/generators/components/mailer/templates/fixture.erb +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +0 -3
- data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +9 -25
- data/lib/rails_generator/generators/components/mailer/templates/view.erb +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +0 -3
- data/lib/rails_generator/generators/components/migration/USAGE +23 -8
- data/lib/rails_generator/generators/components/migration/migration_generator.rb +15 -2
- data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -3
- data/lib/rails_generator/generators/components/model/USAGE +21 -11
- data/lib/rails_generator/generators/components/model/model_generator.rb +28 -1
- data/lib/rails_generator/generators/components/model/templates/fixtures.yml +18 -4
- data/lib/rails_generator/generators/components/model/templates/migration.rb +16 -0
- data/lib/rails_generator/generators/components/model/templates/unit_test.rb +2 -4
- data/lib/rails_generator/generators/components/observer/USAGE +13 -0
- data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
- data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
- data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +8 -0
- data/lib/rails_generator/generators/components/plugin/USAGE +10 -18
- data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +6 -0
- data/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE +20 -0
- data/lib/rails_generator/generators/components/plugin/templates/README +10 -1
- data/lib/rails_generator/generators/components/plugin/templates/Rakefile +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/USAGE +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/install.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
- data/lib/rails_generator/generators/components/resource/USAGE +23 -0
- data/lib/rails_generator/generators/components/resource/resource_generator.rb +74 -0
- data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
- data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +8 -0
- data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/scaffold/USAGE +24 -31
- data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +45 -137
- data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +65 -34
- data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +23 -76
- data/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb +17 -0
- data/lib/rails_generator/generators/components/scaffold/templates/style.css +5 -5
- data/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb +19 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb +24 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb +18 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb +10 -0
- data/lib/rails_generator/generators/components/session_migration/USAGE +6 -11
- data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +7 -1
- data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +8 -7
- data/lib/rails_generator/lookup.rb +46 -12
- data/lib/rails_generator/options.rb +11 -8
- data/lib/rails_generator/scripts/destroy.rb +23 -0
- data/lib/rails_generator/scripts.rb +7 -4
- data/lib/rails_generator/secret_key_generator.rb +160 -0
- data/lib/rails_generator/spec.rb +1 -1
- data/lib/rails_generator.rb +1 -1
- data/lib/railties_path.rb +1 -1
- data/lib/ruby_version_check.rb +17 -0
- data/lib/source_annotation_extractor.rb +62 -0
- data/lib/tasks/annotations.rake +23 -0
- data/lib/tasks/databases.rake +328 -133
- data/lib/tasks/documentation.rake +72 -68
- data/lib/tasks/framework.rake +99 -58
- data/lib/tasks/log.rake +9 -0
- data/lib/tasks/misc.rake +2 -17
- data/lib/tasks/rails.rb +2 -2
- data/lib/tasks/routes.rake +17 -0
- data/lib/tasks/statistics.rake +10 -8
- data/lib/tasks/testing.rake +99 -31
- data/lib/tasks/tmp.rake +37 -0
- data/lib/test_help.rb +8 -5
- data/lib/webrick_server.rb +11 -16
- metadata +312 -272
- data/bin/breakpointer +0 -3
- data/builtin/controllers/rails_info_controller.rb +0 -11
- data/configs/database.yml +0 -85
- data/lib/binding_of_caller.rb +0 -85
- data/lib/breakpoint.rb +0 -523
- data/lib/breakpoint_client.rb +0 -196
- data/lib/commands/breakpointer.rb +0 -1
- data/lib/rails_generator/generators/components/scaffold/templates/form.rhtml +0 -3
- data/lib/rails_generator/generators/components/scaffold/templates/form_scaffolding.rhtml +0 -1
- data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +0 -13
- data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +0 -9
- data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +0 -27
- data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +0 -8
- data/lib/rails_generator/generators/components/scaffold/templates/view_show.rhtml +0 -8
- data/lib/rails_generator/generators/components/web_service/USAGE +0 -28
- data/lib/rails_generator/generators/components/web_service/templates/api_definition.rb +0 -5
- data/lib/rails_generator/generators/components/web_service/templates/controller.rb +0 -8
- data/lib/rails_generator/generators/components/web_service/templates/functional_test.rb +0 -19
- data/lib/rails_generator/generators/components/web_service/web_service_generator.rb +0 -29
- data/lib/tasks/javascripts.rake +0 -6
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Inspector is only for Unix") end
|
4
|
+
|
5
|
+
OPTIONS = {
|
6
|
+
:pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
|
7
|
+
:pattern => "dispatch.*.pid",
|
8
|
+
:ps => "ps -o pid,state,user,start,time,pcpu,vsz,majflt,command -p %s"
|
9
|
+
}
|
10
|
+
|
11
|
+
class Inspector
|
12
|
+
def self.inspect(pid_path, pattern)
|
13
|
+
new(pid_path, pattern).inspect
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(pid_path, pattern)
|
17
|
+
@pid_path, @pattern = pid_path, pattern
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
header = `#{OPTIONS[:ps] % 1}`.split("\n")[0] + "\n"
|
22
|
+
lines = pids.collect { |pid| `#{OPTIONS[:ps] % pid}`.split("\n")[1] }
|
23
|
+
|
24
|
+
puts(header + lines.join("\n"))
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def pids
|
29
|
+
pid_files.collect do |pid_file|
|
30
|
+
File.read(pid_file).to_i
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def pid_files
|
35
|
+
Dir.glob(@pid_path + "/" + @pattern)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
ARGV.options do |opts|
|
41
|
+
opts.banner = "Usage: inspector [options]"
|
42
|
+
|
43
|
+
opts.separator ""
|
44
|
+
|
45
|
+
opts.on <<-EOF
|
46
|
+
Description:
|
47
|
+
Displays system information about Rails dispatchers (or other processes that use pid files) through
|
48
|
+
the ps command.
|
49
|
+
|
50
|
+
Examples:
|
51
|
+
inspector # default ps on all tmp/pids/dispatch.*.pid files
|
52
|
+
inspector -s 'ps -o user,start,majflt,pcpu,vsz -p %s' # custom ps, %s is where the pid is interleaved
|
53
|
+
EOF
|
54
|
+
|
55
|
+
opts.on(" Options:")
|
56
|
+
|
57
|
+
opts.on("-s", "--ps=command", "default: #{OPTIONS[:ps]}", String) { |v| OPTIONS[:ps] = v }
|
58
|
+
opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
|
59
|
+
opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
|
60
|
+
|
61
|
+
opts.separator ""
|
62
|
+
|
63
|
+
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
64
|
+
|
65
|
+
opts.parse!
|
66
|
+
end
|
67
|
+
|
68
|
+
Inspector.inspect(OPTIONS[:pid_path], OPTIONS[:pattern])
|
@@ -2,91 +2,104 @@ require 'optparse'
|
|
2
2
|
require 'net/http'
|
3
3
|
require 'uri'
|
4
4
|
|
5
|
-
if RUBY_PLATFORM =~ /
|
5
|
+
if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Reaper is only for Unix") end
|
6
6
|
|
7
|
-
|
8
|
-
# be queried by "keyword" to find those that meet a specific set of criteria.
|
9
|
-
class ProgramProcess
|
7
|
+
class Killer
|
10
8
|
class << self
|
11
|
-
|
12
9
|
# Searches for all processes matching the given keywords, and then invokes
|
13
10
|
# a specific action on each of them. This is useful for (e.g.) reloading a
|
14
11
|
# set of processes:
|
15
12
|
#
|
16
|
-
#
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
if processes.empty?
|
21
|
-
puts "Couldn't find any process matching: #{keywords.join(" or ")}"
|
22
|
-
else
|
23
|
-
processes.each do |process|
|
24
|
-
puts "#{action.capitalize}ing #{process}"
|
25
|
-
process.send(action)
|
26
|
-
end
|
27
|
-
end
|
13
|
+
# Killer.process(:reload, "/tmp/pids", "dispatcher.*.pid")
|
14
|
+
def process(action, pid_path, pattern, keyword)
|
15
|
+
new(pid_path, pattern, keyword).process(action)
|
28
16
|
end
|
29
17
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
process_lines_with_keyword(keyword).split("\n").collect { |line|
|
35
|
-
next if line =~ /inq|ps axww|grep|spawn-fcgi|spawner|reaper/
|
36
|
-
pid, *command = line.split
|
37
|
-
new(pid, command.join(" "))
|
38
|
-
}.compact
|
18
|
+
# Forces the (rails) application to reload by sending a +HUP+ signal to the
|
19
|
+
# process.
|
20
|
+
def reload(pid)
|
21
|
+
`kill -s HUP #{pid}`
|
39
22
|
end
|
40
23
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
24
|
+
# Force the (rails) application to restart by sending a +USR2+ signal to the
|
25
|
+
# process.
|
26
|
+
def restart(pid)
|
27
|
+
`kill -s USR2 #{pid}`
|
28
|
+
end
|
46
29
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
30
|
+
# Forces the (rails) application to gracefully terminate by sending a
|
31
|
+
# +TERM+ signal to the process.
|
32
|
+
def graceful(pid)
|
33
|
+
`kill -s TERM #{pid}`
|
34
|
+
end
|
52
35
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
36
|
+
# Forces the (rails) application to terminate immediately by sending a -9
|
37
|
+
# signal to the process.
|
38
|
+
def kill(pid)
|
39
|
+
`kill -9 #{pid}`
|
40
|
+
end
|
58
41
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
42
|
+
# Send a +USR1+ signal to the process.
|
43
|
+
def usr1(pid)
|
44
|
+
`kill -s USR1 #{pid}`
|
45
|
+
end
|
63
46
|
end
|
64
47
|
|
65
|
-
|
66
|
-
|
67
|
-
def kill
|
68
|
-
`kill -9 #{@pid}`
|
48
|
+
def initialize(pid_path, pattern, keyword=nil)
|
49
|
+
@pid_path, @pattern, @keyword = pid_path, pattern, keyword
|
69
50
|
end
|
70
51
|
|
71
|
-
|
72
|
-
|
73
|
-
`kill -s USR1 #{@pid}`
|
74
|
-
end
|
52
|
+
def process(action)
|
53
|
+
pids = find_processes
|
75
54
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
55
|
+
if pids.empty?
|
56
|
+
warn "Couldn't find any pid file in '#{@pid_path}' matching '#{@pattern}'"
|
57
|
+
warn "(also looked for processes matching #{@keyword.inspect})" if @keyword
|
58
|
+
else
|
59
|
+
pids.each do |pid|
|
60
|
+
puts "#{action.capitalize}ing #{pid}"
|
61
|
+
self.class.send(action, pid)
|
62
|
+
end
|
63
|
+
|
64
|
+
delete_pid_files if terminating?(action)
|
65
|
+
end
|
80
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def terminating?(action)
|
70
|
+
[ "kill", "graceful" ].include?(action)
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_processes
|
74
|
+
files = pid_files
|
75
|
+
if files.empty?
|
76
|
+
find_processes_via_grep
|
77
|
+
else
|
78
|
+
files.collect { |pid_file| File.read(pid_file).to_i }
|
79
|
+
end
|
80
|
+
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
def find_processes_via_grep
|
83
|
+
lines = `ps axww -o 'pid command' | grep #{@keyword}`.split(/\n/).
|
84
|
+
reject { |line| line =~ /inq|ps axww|grep|spawn-fcgi|spawner|reaper/ }
|
85
|
+
lines.map { |line| line[/^\s*(\d+)/, 1].to_i }
|
86
|
+
end
|
87
|
+
|
88
|
+
def delete_pid_files
|
89
|
+
pid_files.each { |pid_file| File.delete(pid_file) }
|
90
|
+
end
|
91
|
+
|
92
|
+
def pid_files
|
93
|
+
Dir.glob(@pid_path + "/" + @pattern)
|
94
|
+
end
|
85
95
|
end
|
86
96
|
|
97
|
+
|
87
98
|
OPTIONS = {
|
88
|
-
:action
|
89
|
-
:
|
99
|
+
:action => "restart",
|
100
|
+
:pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
|
101
|
+
:pattern => "dispatch.[0-9]*.pid",
|
102
|
+
:dispatcher => File.expand_path("#{RAILS_ROOT}/public/dispatch.fcgi")
|
90
103
|
}
|
91
104
|
|
92
105
|
ARGV.options do |opts|
|
@@ -96,9 +109,13 @@ ARGV.options do |opts|
|
|
96
109
|
|
97
110
|
opts.on <<-EOF
|
98
111
|
Description:
|
99
|
-
The reaper is used to restart, reload, gracefully exit, and forcefully exit
|
100
|
-
running a Rails Dispatcher
|
101
|
-
is
|
112
|
+
The reaper is used to restart, reload, gracefully exit, and forcefully exit processes
|
113
|
+
running a Rails Dispatcher (or any other process responding to the same signals). This
|
114
|
+
is commonly done when a new version of the application is available, so the existing
|
115
|
+
processes can be updated to use the latest code.
|
116
|
+
|
117
|
+
It uses pid files to work on the processes and by default assume them to be located
|
118
|
+
in RAILS_ROOT/tmp/pids.
|
102
119
|
|
103
120
|
The reaper actions are:
|
104
121
|
|
@@ -110,15 +127,17 @@ ARGV.options do |opts|
|
|
110
127
|
Restart is the most common and default action.
|
111
128
|
|
112
129
|
Examples:
|
113
|
-
reaper
|
114
|
-
reaper -a reload
|
115
|
-
reaper -a
|
130
|
+
reaper # restarts the default dispatchers
|
131
|
+
reaper -a reload # reload the default dispatchers
|
132
|
+
reaper -a kill -r *.pid # kill all processes that keep pids in tmp/pids
|
116
133
|
EOF
|
117
134
|
|
118
135
|
opts.on(" Options:")
|
119
136
|
|
120
|
-
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |OPTIONS[:action]
|
121
|
-
opts.on("-
|
137
|
+
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |v| OPTIONS[:action] = v }
|
138
|
+
opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
|
139
|
+
opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
|
140
|
+
opts.on("-d", "--dispatcher=path", "DEPRECATED. default: #{OPTIONS[:dispatcher]}", String) { |v| OPTIONS[:dispatcher] = v }
|
122
141
|
|
123
142
|
opts.separator ""
|
124
143
|
|
@@ -127,4 +146,4 @@ ARGV.options do |opts|
|
|
127
146
|
opts.parse!
|
128
147
|
end
|
129
148
|
|
130
|
-
|
149
|
+
Killer.process(OPTIONS[:action], OPTIONS[:pid_path], OPTIONS[:pattern], OPTIONS[:dispatcher])
|
@@ -1,45 +1,200 @@
|
|
1
|
+
require 'active_support'
|
1
2
|
require 'optparse'
|
3
|
+
require 'socket'
|
4
|
+
require 'fileutils'
|
2
5
|
|
3
|
-
def
|
4
|
-
|
5
|
-
|
6
|
+
def daemonize #:nodoc:
|
7
|
+
exit if fork # Parent exits, child continues.
|
8
|
+
Process.setsid # Become session leader.
|
9
|
+
exit if fork # Zap session leader. See [1].
|
10
|
+
Dir.chdir "/" # Release old working directory.
|
11
|
+
File.umask 0000 # Ensure sensible umask. Adjust as needed.
|
12
|
+
STDIN.reopen "/dev/null" # Free file descriptors and
|
13
|
+
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
|
14
|
+
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
|
6
15
|
end
|
7
16
|
|
17
|
+
class Spawner
|
18
|
+
def self.record_pid(name = "#{OPTIONS[:process]}.spawner", id = Process.pid)
|
19
|
+
FileUtils.mkdir_p(OPTIONS[:pids])
|
20
|
+
File.open(File.expand_path(OPTIONS[:pids] + "/#{name}.pid"), "w+") { |f| f.write(id) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.spawn_all
|
24
|
+
OPTIONS[:instances].times do |i|
|
25
|
+
port = OPTIONS[:port] + i
|
26
|
+
print "Checking if something is already running on #{OPTIONS[:address]}:#{port}..."
|
27
|
+
|
28
|
+
begin
|
29
|
+
srv = TCPServer.new(OPTIONS[:address], port)
|
30
|
+
srv.close
|
31
|
+
srv = nil
|
32
|
+
|
33
|
+
puts "NO"
|
34
|
+
puts "Starting dispatcher on port: #{OPTIONS[:address]}:#{port}"
|
35
|
+
|
36
|
+
FileUtils.mkdir_p(OPTIONS[:pids])
|
37
|
+
spawn(port)
|
38
|
+
rescue
|
39
|
+
puts "YES"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class FcgiSpawner < Spawner
|
46
|
+
def self.spawn(port)
|
47
|
+
cmd = "#{OPTIONS[:spawner]} -f #{OPTIONS[:dispatcher]} -p #{port} -P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid"
|
48
|
+
cmd << " -a #{OPTIONS[:address]}" if can_bind_to_custom_address?
|
49
|
+
system(cmd)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.can_bind_to_custom_address?
|
53
|
+
@@can_bind_to_custom_address ||= /^\s-a\s/.match `#{OPTIONS[:spawner]} -h`
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class MongrelSpawner < Spawner
|
58
|
+
def self.spawn(port)
|
59
|
+
cmd =
|
60
|
+
"mongrel_rails start -d " +
|
61
|
+
"-a #{OPTIONS[:address]} " +
|
62
|
+
"-p #{port} " +
|
63
|
+
"-P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid " +
|
64
|
+
"-e #{OPTIONS[:environment]} " +
|
65
|
+
"-c #{OPTIONS[:rails_root]} " +
|
66
|
+
"-l #{OPTIONS[:rails_root]}/log/mongrel.log"
|
67
|
+
|
68
|
+
# Add prefix functionality to spawner's call to mongrel_rails
|
69
|
+
# Digging through monrel's project subversion server, the earliest
|
70
|
+
# Tag that has prefix implemented in the bin/mongrel_rails file
|
71
|
+
# is 0.3.15 which also happens to be the earilest tag listed.
|
72
|
+
# References: http://mongrel.rubyforge.org/svn/tags
|
73
|
+
if Mongrel::Const::MONGREL_VERSION.to_f >=0.3 && !OPTIONS[:prefix].nil?
|
74
|
+
cmd = cmd + " --prefix #{OPTIONS[:prefix]}"
|
75
|
+
end
|
76
|
+
system(cmd)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.can_bind_to_custom_address?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
begin
|
86
|
+
require_library_or_gem 'fcgi'
|
87
|
+
rescue Exception
|
88
|
+
# FCGI not available
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
require_library_or_gem 'mongrel'
|
93
|
+
rescue Exception
|
94
|
+
# Mongrel not available
|
95
|
+
end
|
96
|
+
|
97
|
+
server = case ARGV.first
|
98
|
+
when "fcgi", "mongrel"
|
99
|
+
ARGV.shift
|
100
|
+
else
|
101
|
+
if defined?(Mongrel)
|
102
|
+
"mongrel"
|
103
|
+
elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `spawn-fcgi -version` }.blank? && defined?(FCGI)
|
104
|
+
"fcgi"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
case server
|
109
|
+
when "fcgi"
|
110
|
+
puts "=> Starting FCGI dispatchers"
|
111
|
+
spawner_class = FcgiSpawner
|
112
|
+
when "mongrel"
|
113
|
+
puts "=> Starting mongrel dispatchers"
|
114
|
+
spawner_class = MongrelSpawner
|
115
|
+
else
|
116
|
+
puts "Neither FCGI (spawn-fcgi) nor Mongrel was installed and available!"
|
117
|
+
exit(0)
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
|
8
122
|
OPTIONS = {
|
9
123
|
:environment => "production",
|
10
124
|
:spawner => '/usr/bin/env spawn-fcgi',
|
11
|
-
:dispatcher => File.expand_path(
|
125
|
+
:dispatcher => File.expand_path(RELATIVE_RAILS_ROOT + '/public/dispatch.fcgi'),
|
126
|
+
:pids => File.expand_path(RELATIVE_RAILS_ROOT + "/tmp/pids"),
|
127
|
+
:rails_root => File.expand_path(RELATIVE_RAILS_ROOT),
|
128
|
+
:process => "dispatch",
|
12
129
|
:port => 8000,
|
13
|
-
:
|
130
|
+
:address => '0.0.0.0',
|
131
|
+
:instances => 3,
|
132
|
+
:repeat => nil,
|
133
|
+
:prefix => nil
|
14
134
|
}
|
15
135
|
|
16
136
|
ARGV.options do |opts|
|
17
|
-
opts.banner = "Usage: spawner [options]"
|
137
|
+
opts.banner = "Usage: spawner [platform] [options]"
|
18
138
|
|
19
139
|
opts.separator ""
|
20
140
|
|
21
141
|
opts.on <<-EOF
|
22
142
|
Description:
|
23
|
-
The spawner is a wrapper for spawn-fcgi that makes it
|
24
|
-
processes running the Rails dispatcher. The
|
25
|
-
|
26
|
-
|
143
|
+
The spawner is a wrapper for spawn-fcgi and mongrel that makes it
|
144
|
+
easier to start multiple processes running the Rails dispatcher. The
|
145
|
+
spawn-fcgi command is included with the lighttpd web server, but can
|
146
|
+
be used with both Apache and lighttpd (and any other web server
|
147
|
+
supporting externally managed FCGI processes). Mongrel automatically
|
148
|
+
ships with with mongrel_rails for starting dispatchers.
|
149
|
+
|
150
|
+
The first choice you need to make is whether to spawn the Rails
|
151
|
+
dispatchers as FCGI or Mongrel. By default, this spawner will prefer
|
152
|
+
Mongrel, so if that's installed, and no platform choice is made,
|
153
|
+
Mongrel is used.
|
27
154
|
|
28
|
-
|
29
|
-
like to run. So if you pick 9100 and 3
|
155
|
+
Then decide a starting port (default is 8000) and the number of FCGI
|
156
|
+
process instances you'd like to run. So if you pick 9100 and 3
|
157
|
+
instances, you'll start processes on 9100, 9101, and 9102.
|
30
158
|
|
31
|
-
|
32
|
-
|
33
|
-
|
159
|
+
By setting the repeat option, you get a protection loop, which will
|
160
|
+
attempt to restart any FCGI processes that might have been exited or
|
161
|
+
outright crashed.
|
162
|
+
|
163
|
+
You can select bind address for started processes. By default these
|
164
|
+
listen on every interface. For single machine installations you would
|
165
|
+
probably want to use 127.0.0.1, hiding them form the outside world.
|
166
|
+
|
167
|
+
Examples:
|
168
|
+
spawner # starts instances on 8000, 8001, and 8002
|
169
|
+
# using Mongrel if available.
|
170
|
+
spawner fcgi # starts instances on 8000, 8001, and 8002
|
171
|
+
# using FCGI.
|
172
|
+
spawner mongrel -i 5 # starts instances on 8000, 8001, 8002,
|
173
|
+
# 8003, and 8004 using Mongrel.
|
174
|
+
spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to
|
175
|
+
# 9109 using Mongrel if available.
|
176
|
+
spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to
|
177
|
+
# 9102 and attempts start them every 5
|
178
|
+
# seconds.
|
179
|
+
spawner -a 127.0.0.1 # starts 3 instances binding to localhost
|
34
180
|
EOF
|
35
181
|
|
36
182
|
opts.on(" Options:")
|
37
183
|
|
38
|
-
opts.on("-p", "--port=number",
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
184
|
+
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |OPTIONS[:port]| }
|
185
|
+
|
186
|
+
if spawner_class.can_bind_to_custom_address?
|
187
|
+
opts.on("-a", "--address=ip", String, "Bind to IP address (default: #{OPTIONS[:address]})") { |OPTIONS[:address]| }
|
188
|
+
end
|
189
|
+
|
190
|
+
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
|
191
|
+
opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |v| OPTIONS[:instances] = v }
|
192
|
+
opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |v| OPTIONS[:repeat] = v }
|
193
|
+
opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |v| OPTIONS[:environment] = v }
|
194
|
+
opts.on("-P", "--prefix=path", String, "URL prefix for Rails app. [Used only with Mongrel > v0.3.15]: (default: #{OPTIONS[:prefix]})") { |v| OPTIONS[:prefix] = v }
|
195
|
+
opts.on("-n", "--process=name", String, "default: #{OPTIONS[:process]}") { |v| OPTIONS[:process] = v }
|
196
|
+
opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |v| OPTIONS[:spawner] = v }
|
197
|
+
opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
|
43
198
|
|
44
199
|
opts.separator ""
|
45
200
|
|
@@ -49,4 +204,16 @@ ARGV.options do |opts|
|
|
49
204
|
end
|
50
205
|
|
51
206
|
ENV["RAILS_ENV"] = OPTIONS[:environment]
|
52
|
-
|
207
|
+
|
208
|
+
if OPTIONS[:repeat]
|
209
|
+
daemonize
|
210
|
+
trap("TERM") { exit }
|
211
|
+
spawner_class.record_pid
|
212
|
+
|
213
|
+
loop do
|
214
|
+
spawner_class.spawn_all
|
215
|
+
sleep(OPTIONS[:repeat])
|
216
|
+
end
|
217
|
+
else
|
218
|
+
spawner_class.spawn_all
|
219
|
+
end
|
@@ -36,9 +36,9 @@ ARGV.options do |opts|
|
|
36
36
|
|
37
37
|
opts.on(" Options:")
|
38
38
|
|
39
|
-
opts.on("-c", "--command=path", String) { |OPTIONS[:command]
|
40
|
-
opts.on("-i", "--interval=seconds", Float) { |OPTIONS[:interval]
|
41
|
-
opts.on("-d", "--daemon") { |OPTIONS[:daemon]
|
39
|
+
opts.on("-c", "--command=path", String) { |v| OPTIONS[:command] = v }
|
40
|
+
opts.on("-i", "--interval=seconds", Float) { |v| OPTIONS[:interval] = v }
|
41
|
+
opts.on("-d", "--daemon") { |v| OPTIONS[:daemon] = v }
|
42
42
|
|
43
43
|
opts.separator ""
|
44
44
|
|
data/lib/commands/runner.rb
CHANGED
@@ -1,27 +1,48 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
|
3
3
|
options = { :environment => (ENV['RAILS_ENV'] || "development").dup }
|
4
|
+
code_or_file = nil
|
4
5
|
|
5
|
-
ARGV.options do |opts|
|
6
|
+
ARGV.clone.options do |opts|
|
6
7
|
script_name = File.basename($0)
|
7
|
-
opts.banner = "Usage:
|
8
|
+
opts.banner = "Usage: #{$0} [options] ('Some.ruby(code)' or a filename)"
|
8
9
|
|
9
10
|
opts.separator ""
|
10
11
|
|
11
12
|
opts.on("-e", "--environment=name", String,
|
12
13
|
"Specifies the environment for the runner to operate under (test/development/production).",
|
13
|
-
"Default: development") { |options[:environment]
|
14
|
+
"Default: development") { |v| options[:environment] = v }
|
14
15
|
|
15
16
|
opts.separator ""
|
16
17
|
|
17
18
|
opts.on("-h", "--help",
|
18
|
-
"Show this help message.") { puts opts; exit }
|
19
|
-
|
20
|
-
|
19
|
+
"Show this help message.") { $stderr.puts opts; exit }
|
20
|
+
|
21
|
+
if RUBY_PLATFORM !~ /mswin/
|
22
|
+
opts.separator ""
|
23
|
+
opts.separator "You can also use runner as a shebang line for your scripts like this:"
|
24
|
+
opts.separator "-------------------------------------------------------------"
|
25
|
+
opts.separator "#!/usr/bin/env #{File.expand_path($0)}"
|
26
|
+
opts.separator ""
|
27
|
+
opts.separator "Product.find(:all).each { |p| p.price *= 2 ; p.save! }"
|
28
|
+
opts.separator "-------------------------------------------------------------"
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.order! { |o| code_or_file ||= o } rescue retry
|
21
32
|
end
|
22
33
|
|
34
|
+
ARGV.delete(code_or_file)
|
35
|
+
|
23
36
|
ENV["RAILS_ENV"] = options[:environment]
|
24
37
|
RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
|
25
38
|
|
26
39
|
require RAILS_ROOT + '/config/environment'
|
27
|
-
|
40
|
+
|
41
|
+
if code_or_file.nil?
|
42
|
+
$stderr.puts "Run '#{$0} -h' for help."
|
43
|
+
exit 1
|
44
|
+
elsif File.exists?(code_or_file)
|
45
|
+
eval(File.read(code_or_file))
|
46
|
+
else
|
47
|
+
eval(code_or_file)
|
48
|
+
end
|
data/lib/commands/server.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_support'
|
2
|
+
require 'fileutils'
|
2
3
|
|
3
4
|
begin
|
4
5
|
require_library_or_gem 'fcgi'
|
@@ -6,23 +7,33 @@ rescue Exception
|
|
6
7
|
# FCGI not available
|
7
8
|
end
|
8
9
|
|
10
|
+
begin
|
11
|
+
require_library_or_gem 'mongrel'
|
12
|
+
rescue Exception
|
13
|
+
# Mongrel not available
|
14
|
+
end
|
15
|
+
|
9
16
|
server = case ARGV.first
|
10
|
-
when "lighttpd"
|
11
|
-
ARGV.shift
|
12
|
-
when "webrick"
|
17
|
+
when "lighttpd", "mongrel", "webrick"
|
13
18
|
ARGV.shift
|
14
19
|
else
|
15
|
-
if
|
20
|
+
if defined?(Mongrel)
|
21
|
+
"mongrel"
|
22
|
+
elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `lighttpd -version` }.blank? && defined?(FCGI)
|
16
23
|
"lighttpd"
|
17
24
|
else
|
18
25
|
"webrick"
|
19
26
|
end
|
20
27
|
end
|
21
28
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
case server
|
30
|
+
when "webrick"
|
31
|
+
puts "=> Booting WEBrick..."
|
32
|
+
when "lighttpd"
|
33
|
+
puts "=> Booting lighttpd (use 'script/server webrick' to force WEBrick)"
|
34
|
+
when "mongrel"
|
35
|
+
puts "=> Booting Mongrel (use 'script/server webrick' to force WEBrick)"
|
26
36
|
end
|
27
37
|
|
28
|
-
|
38
|
+
%w(cache pids sessions sockets).each { |dir_to_make| FileUtils.mkdir_p(File.join(RAILS_ROOT, 'tmp', dir_to_make)) }
|
39
|
+
require "commands/servers/#{server}"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
def tail(log_file)
|
2
|
+
cursor = File.size(log_file)
|
3
|
+
last_checked = Time.now
|
4
|
+
tail_thread = Thread.new do
|
5
|
+
File.open(log_file, 'r') do |f|
|
6
|
+
loop do
|
7
|
+
f.seek cursor
|
8
|
+
if f.mtime > last_checked
|
9
|
+
last_checked = f.mtime
|
10
|
+
contents = f.read
|
11
|
+
cursor += contents.length
|
12
|
+
print contents
|
13
|
+
end
|
14
|
+
sleep 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
tail_thread
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_debugger
|
22
|
+
begin
|
23
|
+
require_library_or_gem 'ruby-debug'
|
24
|
+
Debugger.start
|
25
|
+
Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
|
26
|
+
puts "=> Debugger enabled"
|
27
|
+
rescue Exception
|
28
|
+
puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
end
|