rails_product 0.5
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/CHANGELOG +619 -0
- data/MIT-LICENSE +21 -0
- data/README +195 -0
- data/Rakefile +413 -0
- data/bin/benchmarker +19 -0
- data/bin/breakpointer +3 -0
- data/bin/breakpointer_for_gem +4 -0
- data/bin/console +23 -0
- data/bin/console_sandbox +0 -0
- data/bin/destroy +7 -0
- data/bin/generate +7 -0
- data/bin/listener +86 -0
- data/bin/process/reaper +123 -0
- data/bin/process/spawner +54 -0
- data/bin/process/spinner +60 -0
- data/bin/profiler +34 -0
- data/bin/rails +17 -0
- data/bin/rails_product +17 -0
- data/bin/runner +28 -0
- data/bin/server +125 -0
- data/bin/tracker +69 -0
- data/bin/update +5 -0
- data/configs/apache/vhost.example.conf +42 -0
- data/configs/apache.conf +40 -0
- data/configs/database.yml +23 -0
- data/configs/empty.log +0 -0
- data/configs/routes.rb +19 -0
- data/dispatches/dispatch.fcgi +24 -0
- data/dispatches/dispatch.rb +10 -0
- data/dispatches/gateway.cgi +97 -0
- data/doc/README_FOR_APP +2 -0
- data/environments/development.rb +14 -0
- data/environments/environment.rb +101 -0
- data/environments/production.rb +8 -0
- data/environments/test.rb +17 -0
- data/fresh_rakefile +223 -0
- data/helpers/application.rb +4 -0
- data/helpers/application_helper.rb +3 -0
- data/helpers/test_helper.rb +26 -0
- data/html/404.html +8 -0
- data/html/500.html +8 -0
- data/html/favicon.ico +0 -0
- data/html/index.html +78 -0
- data/html/javascripts/controls.js +446 -0
- data/html/javascripts/dragdrop.js +537 -0
- data/html/javascripts/effects.js +612 -0
- data/html/javascripts/prototype.js +1038 -0
- data/html/robots.txt +1 -0
- data/lib/binding_of_caller.rb +83 -0
- data/lib/breakpoint.rb +523 -0
- data/lib/breakpoint_client.rb +196 -0
- data/lib/code_statistics.rb +104 -0
- data/lib/console_sandbox.rb +6 -0
- data/lib/dispatcher.rb +59 -0
- data/lib/fcgi_handler.rb +156 -0
- data/lib/productize.rb +116 -0
- data/lib/rails_generator/base.rb +203 -0
- data/lib/rails_generator/commands.rb +409 -0
- data/lib/rails_generator/generators/applications/app/USAGE +16 -0
- data/lib/rails_generator/generators/applications/app/app_generator.rb +126 -0
- data/lib/rails_generator/generators/applications/productized_app/USAGE +16 -0
- data/lib/rails_generator/generators/applications/productized_app/productized_app_generator.rb +133 -0
- data/lib/rails_generator/generators/components/controller/USAGE +30 -0
- data/lib/rails_generator/generators/components/controller/controller_generator.rb +38 -0
- data/lib/rails_generator/generators/components/controller/templates/controller.rb +10 -0
- data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +18 -0
- data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/controller/templates/view.rhtml +2 -0
- data/lib/rails_generator/generators/components/mailer/USAGE +19 -0
- data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +32 -0
- data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +13 -0
- data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +37 -0
- data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +3 -0
- data/lib/rails_generator/generators/components/migration/USAGE +14 -0
- data/lib/rails_generator/generators/components/migration/migration_generator.rb +9 -0
- data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -0
- data/lib/rails_generator/generators/components/model/USAGE +17 -0
- data/lib/rails_generator/generators/components/model/model_generator.rb +18 -0
- data/lib/rails_generator/generators/components/model/templates/fixtures.yml +5 -0
- data/lib/rails_generator/generators/components/model/templates/model.rb +2 -0
- data/lib/rails_generator/generators/components/model/templates/unit_test.rb +14 -0
- data/lib/rails_generator/generators/components/scaffold/USAGE +32 -0
- data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +178 -0
- data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +54 -0
- data/lib/rails_generator/generators/components/scaffold/templates/form.rhtml +3 -0
- data/lib/rails_generator/generators/components/scaffold/templates/form_scaffolding.rhtml +1 -0
- data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +98 -0
- data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +13 -0
- data/lib/rails_generator/generators/components/scaffold/templates/style.css +74 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +9 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +27 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +8 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_show.rhtml +8 -0
- data/lib/rails_generator/generators/components/web_service/USAGE +28 -0
- data/lib/rails_generator/generators/components/web_service/templates/api_definition.rb +5 -0
- data/lib/rails_generator/generators/components/web_service/templates/controller.rb +8 -0
- data/lib/rails_generator/generators/components/web_service/templates/functional_test.rb +19 -0
- data/lib/rails_generator/generators/components/web_service/web_service_generator.rb +29 -0
- data/lib/rails_generator/lookup.rb +206 -0
- data/lib/rails_generator/manifest.rb +53 -0
- data/lib/rails_generator/options.rb +134 -0
- data/lib/rails_generator/scripts/destroy.rb +7 -0
- data/lib/rails_generator/scripts/generate.rb +7 -0
- data/lib/rails_generator/scripts/update.rb +12 -0
- data/lib/rails_generator/scripts.rb +83 -0
- data/lib/rails_generator/simple_logger.rb +46 -0
- data/lib/rails_generator/spec.rb +44 -0
- data/lib/rails_generator.rb +43 -0
- data/lib/rubyprof_ext.rb +35 -0
- data/lib/webrick_server.rb +148 -0
- data/sites/fresh_rakefile +176 -0
- metadata +250 -0
data/bin/listener
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'stringio'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'fcgi_handler'
|
|
6
|
+
|
|
7
|
+
def message(s)
|
|
8
|
+
$stderr.puts "listener: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class RemoteCGI < CGI
|
|
12
|
+
attr_accessor :stdinput, :stdoutput, :env_table
|
|
13
|
+
def initialize(env_table, input = nil, output = nil)
|
|
14
|
+
self.env_table = env_table
|
|
15
|
+
self.stdinput = input || StringIO.new
|
|
16
|
+
self.stdoutput = output || StringIO.new
|
|
17
|
+
super()
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def out(stream) # Ignore the requested output stream
|
|
21
|
+
super(stdoutput)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Listener
|
|
26
|
+
include DRbUndumped
|
|
27
|
+
|
|
28
|
+
def initialize(timeout, socket_path)
|
|
29
|
+
@socket = File.expand_path(socket_path)
|
|
30
|
+
@mutex = Mutex.new
|
|
31
|
+
@active = false
|
|
32
|
+
@timeout = timeout
|
|
33
|
+
|
|
34
|
+
@handler = RailsFCGIHandler.new
|
|
35
|
+
@handler.extend DRbUndumped
|
|
36
|
+
|
|
37
|
+
message 'opening socket'
|
|
38
|
+
DRb.start_service("drbunix:#{@socket}", self)
|
|
39
|
+
|
|
40
|
+
message 'entering process loop'
|
|
41
|
+
@handler.process! self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def each_cgi(&cgi_block)
|
|
45
|
+
@cgi_block = cgi_block
|
|
46
|
+
message 'entering idle loop'
|
|
47
|
+
loop do
|
|
48
|
+
sleep @timeout rescue nil
|
|
49
|
+
die! unless @active
|
|
50
|
+
@active = false
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def process(env, input)
|
|
55
|
+
message 'received request'
|
|
56
|
+
@mutex.synchronize do
|
|
57
|
+
@active = true
|
|
58
|
+
|
|
59
|
+
message 'creating input stream'
|
|
60
|
+
input_stream = StringIO.new(input)
|
|
61
|
+
message 'building CGI instance'
|
|
62
|
+
cgi = RemoteCGI.new(eval(env), input_stream)
|
|
63
|
+
|
|
64
|
+
message 'yielding to fcgi handler'
|
|
65
|
+
@cgi_block.call cgi
|
|
66
|
+
message 'yield finished -- sending output'
|
|
67
|
+
|
|
68
|
+
cgi.stdoutput.seek(0)
|
|
69
|
+
output = cgi.stdoutput.read
|
|
70
|
+
|
|
71
|
+
return output
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def die!
|
|
76
|
+
message 'shutting down'
|
|
77
|
+
DRb.stop_service
|
|
78
|
+
FileUtils.rm_f @socket
|
|
79
|
+
Kernel.exit 0
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
socket_path = ARGV.shift
|
|
84
|
+
timeout = (ARGV.shift || 90).to_i
|
|
85
|
+
|
|
86
|
+
Listener.new(timeout, socket_path)
|
data/bin/process/reaper
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'net/http'
|
|
5
|
+
require 'uri'
|
|
6
|
+
|
|
7
|
+
def nudge(url, iterations)
|
|
8
|
+
print "Nudging #{url}: "
|
|
9
|
+
iterations.times { Net::HTTP.get_response(URI.parse(url)); print "."; STDOUT.flush }
|
|
10
|
+
puts
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
if RUBY_PLATFORM =~ /mswin32/ then abort("Reaper is only for Unix") end
|
|
14
|
+
|
|
15
|
+
class ProgramProcess
|
|
16
|
+
class << self
|
|
17
|
+
def process_keywords(action, *keywords)
|
|
18
|
+
processes = keywords.collect { |keyword| find_by_keyword(keyword) }.flatten
|
|
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
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def find_by_keyword(keyword)
|
|
31
|
+
process_lines_with_keyword(keyword).split("\n").collect { |line|
|
|
32
|
+
next if line.include?("inq") || line.include?("ps -ax") || line.include?("grep")
|
|
33
|
+
pid, *command = line.split
|
|
34
|
+
new(pid, command.join(" "))
|
|
35
|
+
}.compact
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
def process_lines_with_keyword(keyword)
|
|
40
|
+
`ps -ax -o 'pid command' | grep #{keyword}`
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(pid, command)
|
|
45
|
+
@pid, @command = pid, command
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def find
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def reload
|
|
52
|
+
`kill -s HUP #{@pid}`
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def graceful
|
|
56
|
+
`kill -s TERM #{@pid}`
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def kill
|
|
60
|
+
`kill -9 #{@pid}`
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def to_s
|
|
64
|
+
"[#{@pid}] #{@command}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
OPTIONS = {
|
|
69
|
+
:action => "graceful",
|
|
70
|
+
:dispatcher => File.expand_path(File.dirname(__FILE__) + '/../../public/dispatch.fcgi'),
|
|
71
|
+
:iterations => 10,
|
|
72
|
+
:nudge => false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ARGV.options do |opts|
|
|
76
|
+
opts.banner = "Usage: reaper [options]"
|
|
77
|
+
|
|
78
|
+
opts.separator ""
|
|
79
|
+
|
|
80
|
+
opts.on <<-EOF
|
|
81
|
+
Description:
|
|
82
|
+
The reaper is used to reload, gracefully exit, and forcefully exit FCGI processes
|
|
83
|
+
running a Rails Dispatcher. This is commonly done when a new version of the application
|
|
84
|
+
is available, so the existing processes can be updated to use the latest code.
|
|
85
|
+
|
|
86
|
+
The reaper actions are:
|
|
87
|
+
|
|
88
|
+
* reload : Only reloads the application, but not the framework (like the development environment)
|
|
89
|
+
* graceful: Marks all of the processes for exit after the next request
|
|
90
|
+
* kill : Forcefully exists all processes regardless of whether they're currently serving a request
|
|
91
|
+
|
|
92
|
+
Graceful exist is the most common and default action. But since the processes won't exist until after
|
|
93
|
+
their next request, it's often necessary to ensure that such a request occurs right after they've been
|
|
94
|
+
marked. That's what nudging is for.
|
|
95
|
+
|
|
96
|
+
A nudge is simply a request to a URL where the dispatcher is serving. You should perform one nudge per
|
|
97
|
+
FCGI process you have running if they're setup in a round-robin. Be sure to do one nudge per FCGI process
|
|
98
|
+
across all your servers. So three servers with 10 processes each should nudge 30 times to be sure all processes
|
|
99
|
+
are restarted.
|
|
100
|
+
|
|
101
|
+
NOTE: You're responsible for restarting the processes after they exit. This can be automated by using
|
|
102
|
+
the spinner.
|
|
103
|
+
Examples:
|
|
104
|
+
reaper -a reload
|
|
105
|
+
reaper -n http://www.example.com -i 10 # gracefully exit, nudge 10 times
|
|
106
|
+
EOF
|
|
107
|
+
|
|
108
|
+
opts.on(" Options:")
|
|
109
|
+
|
|
110
|
+
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |OPTIONS[:action]| }
|
|
111
|
+
opts.on("-d", "--dispatcher=path", "default: #{OPTIONS[:dispatcher]}", String) { |OPTIONS[:dispatcher]| }
|
|
112
|
+
opts.on("-n", "--nudge=url", "Should point to URL that's handled by the FCGI process", String) { |OPTIONS[:nudge]| }
|
|
113
|
+
opts.on("-i", "--iterations=number", "One nudge per FCGI process running (default: #{OPTIONS[:iterations]})", Integer) { |OPTIONS[:iterations]| }
|
|
114
|
+
|
|
115
|
+
opts.separator ""
|
|
116
|
+
|
|
117
|
+
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
|
118
|
+
|
|
119
|
+
opts.parse!
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
ProgramProcess.process_keywords(OPTIONS[:action], OPTIONS[:dispatcher])
|
|
123
|
+
nudge(OPTIONS[:nudge], OPTIONS[:iterations]) if OPTIONS[:nudge]
|
data/bin/process/spawner
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
def spawn(port)
|
|
6
|
+
print "Starting FCGI on port: #{port}\n "
|
|
7
|
+
system("#{OPTIONS[:spawner]} -f #{OPTIONS[:dispatcher]} -p #{port}")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
OPTIONS = {
|
|
11
|
+
:environment => "production",
|
|
12
|
+
:spawner => '/usr/bin/env spawn-fcgi',
|
|
13
|
+
:dispatcher => File.expand_path(File.dirname(__FILE__) + '/../../public/dispatch.fcgi'),
|
|
14
|
+
:port => 8000,
|
|
15
|
+
:instances => 3
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ARGV.options do |opts|
|
|
19
|
+
opts.banner = "Usage: spawner [options]"
|
|
20
|
+
|
|
21
|
+
opts.separator ""
|
|
22
|
+
|
|
23
|
+
opts.on <<-EOF
|
|
24
|
+
Description:
|
|
25
|
+
The spawner is a wrapper for spawn-fcgi that makes it easier to start multiple FCGI
|
|
26
|
+
processes running the Rails dispatcher. The spawn-fcgi command is included with the lighttpd
|
|
27
|
+
web server, but can be used with both Apache and lighttpd (and any other web server supporting
|
|
28
|
+
externally managed FCGI processes).
|
|
29
|
+
|
|
30
|
+
You decide a starting port (default is 8000) and the number of FCGI process instances you'd
|
|
31
|
+
like to run. So if you pick 9100 and 3 instances, you'll start processes on 9100, 9101, and 9102.
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
spawner # starts instances on 8000, 8001, and 8002
|
|
35
|
+
spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109
|
|
36
|
+
EOF
|
|
37
|
+
|
|
38
|
+
opts.on(" Options:")
|
|
39
|
+
|
|
40
|
+
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |OPTIONS[:port]| }
|
|
41
|
+
opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |OPTIONS[:instances]| }
|
|
42
|
+
opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |OPTIONS[:environment]| }
|
|
43
|
+
opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |OPTIONS[:spawner]| }
|
|
44
|
+
opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
|
|
45
|
+
|
|
46
|
+
opts.separator ""
|
|
47
|
+
|
|
48
|
+
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
|
49
|
+
|
|
50
|
+
opts.parse!
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
ENV["RAILS_ENV"] = OPTIONS[:environment]
|
|
54
|
+
OPTIONS[:instances].times { |i| spawn(OPTIONS[:port] + i) }
|
data/bin/process/spinner
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
def daemonize
|
|
6
|
+
exit if fork # Parent exits, child continues.
|
|
7
|
+
Process.setsid # Become session leader.
|
|
8
|
+
exit if fork # Zap session leader. See [1].
|
|
9
|
+
Dir.chdir "/" # Release old working directory.
|
|
10
|
+
File.umask 0000 # Ensure sensible umask. Adjust as needed.
|
|
11
|
+
STDIN.reopen "/dev/null" # Free file descriptors and
|
|
12
|
+
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
|
|
13
|
+
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
OPTIONS = {
|
|
17
|
+
:interval => 1.0,
|
|
18
|
+
:command => File.expand_path(File.dirname(__FILE__) + '/spawner'),
|
|
19
|
+
:daemon => false
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
ARGV.options do |opts|
|
|
23
|
+
opts.banner = "Usage: spinner [options]"
|
|
24
|
+
|
|
25
|
+
opts.separator ""
|
|
26
|
+
|
|
27
|
+
opts.on <<-EOF
|
|
28
|
+
Description:
|
|
29
|
+
The spinner is a protection loop for the spawner, which will attempt to restart any FCGI processes
|
|
30
|
+
that might have been restarted or outright crashed. It's a brute-force attempt that'll just try
|
|
31
|
+
to run the spawner every X number of seconds, so it does pose a load on the server (~1% on our test
|
|
32
|
+
server).
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
spinner # attempts to run the spawner with default settings every second with output on the terminal
|
|
36
|
+
spinner -i 3 -d # only run the spawner every 3 seconds and detach from the terminal to become a daemon
|
|
37
|
+
spinner -c '/path/to/app/script/process/spawner -p 9000 -i 10' -d # using custom spawner
|
|
38
|
+
EOF
|
|
39
|
+
|
|
40
|
+
opts.on(" Options:")
|
|
41
|
+
|
|
42
|
+
opts.on("-c", "--command=path", String) { |OPTIONS[:command]| }
|
|
43
|
+
opts.on("-i", "--interval=seconds", Float) { |OPTIONS[:interval]| }
|
|
44
|
+
opts.on("-d", "--daemon") { |OPTIONS[:daemon]| }
|
|
45
|
+
|
|
46
|
+
opts.separator ""
|
|
47
|
+
|
|
48
|
+
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
|
49
|
+
|
|
50
|
+
opts.parse!
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
daemonize if OPTIONS[:daemon]
|
|
54
|
+
|
|
55
|
+
loop do
|
|
56
|
+
system(OPTIONS[:command])
|
|
57
|
+
sleep(OPTIONS[:interval])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
trap(OPTIONS[:daemon] ? "TERM" : "INT") { exit }
|
data/bin/profiler
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby
|
|
2
|
+
if ARGV.empty?
|
|
3
|
+
$stderr.puts "Usage: profiler 'Person.expensive_method(10)' [times]"
|
|
4
|
+
exit(1)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Keep the expensive require out of the profile.
|
|
8
|
+
$stderr.puts 'Loading Rails...'
|
|
9
|
+
require File.dirname(__FILE__) + '/../config/environment'
|
|
10
|
+
|
|
11
|
+
# Define a method to profile.
|
|
12
|
+
if ARGV[1] and ARGV[1].to_i > 1
|
|
13
|
+
eval "def profile_me() #{ARGV[1]}.times { #{ARGV[0]} } end"
|
|
14
|
+
else
|
|
15
|
+
eval "def profile_me() #{ARGV[0]} end"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Use the ruby-prof extension if available. Fall back to stdlib profiler.
|
|
19
|
+
begin
|
|
20
|
+
require 'prof'
|
|
21
|
+
$stderr.puts 'Using the ruby-prof extension.'
|
|
22
|
+
Prof.clock_mode = Prof::GETTIMEOFDAY
|
|
23
|
+
Prof.start
|
|
24
|
+
profile_me
|
|
25
|
+
results = Prof.stop
|
|
26
|
+
require 'rubyprof_ext'
|
|
27
|
+
Prof.print_profile(results, $stderr)
|
|
28
|
+
rescue LoadError
|
|
29
|
+
$stderr.puts 'Using the standard Ruby profiler.'
|
|
30
|
+
Profiler__.start_profile
|
|
31
|
+
profile_me
|
|
32
|
+
Profiler__.stop_profile
|
|
33
|
+
Profiler__.print_profile($stderr)
|
|
34
|
+
end
|
data/bin/rails
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
min_release = "1.8.2 (2004-12-25)"
|
|
2
|
+
ruby_release = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
|
|
3
|
+
if ruby_release < min_release
|
|
4
|
+
abort <<-end_message
|
|
5
|
+
|
|
6
|
+
Rails requires Ruby version #{min_release} or later.
|
|
7
|
+
You're running #{ruby_release}; please upgrade to continue.
|
|
8
|
+
|
|
9
|
+
end_message
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Signal.trap("INT") { puts; exit }
|
|
13
|
+
|
|
14
|
+
require File.dirname(__FILE__) + '/../lib/rails_generator'
|
|
15
|
+
require 'rails_generator/scripts/generate'
|
|
16
|
+
Rails::Generator::Base.use_application_sources!
|
|
17
|
+
Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'app')
|
data/bin/rails_product
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
min_release = "1.8.2 (2004-12-25)"
|
|
2
|
+
ruby_release = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
|
|
3
|
+
if ruby_release < min_release
|
|
4
|
+
abort <<-end_message
|
|
5
|
+
|
|
6
|
+
Rails requires Ruby version #{min_release} or later.
|
|
7
|
+
You're running #{ruby_release}; please upgrade to continue.
|
|
8
|
+
|
|
9
|
+
end_message
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Signal.trap("INT") { puts; exit }
|
|
13
|
+
|
|
14
|
+
require File.dirname(__FILE__) + '/../lib/rails_generator'
|
|
15
|
+
require 'rails_generator/scripts/generate'
|
|
16
|
+
Rails::Generator::Base.use_application_sources!
|
|
17
|
+
Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'productized_app')
|
data/bin/runner
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
|
|
3
|
+
options = { :environment => "development" }
|
|
4
|
+
|
|
5
|
+
ARGV.options do |opts|
|
|
6
|
+
script_name = File.basename($0)
|
|
7
|
+
opts.banner = "Usage: runner 'puts Person.find(1).name' [options]"
|
|
8
|
+
|
|
9
|
+
opts.separator ""
|
|
10
|
+
|
|
11
|
+
opts.on("-e", "--environment=name", String,
|
|
12
|
+
"Specifies the environment for the runner to operate under (test/development/production).",
|
|
13
|
+
"Default: development") { |options[:environment]| }
|
|
14
|
+
|
|
15
|
+
opts.separator ""
|
|
16
|
+
|
|
17
|
+
opts.on("-h", "--help",
|
|
18
|
+
"Show this help message.") { puts opts; exit }
|
|
19
|
+
|
|
20
|
+
opts.parse!
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
ENV["RAILS_ENV"] = options[:environment]
|
|
24
|
+
|
|
25
|
+
#!/usr/local/bin/ruby
|
|
26
|
+
|
|
27
|
+
require File.dirname(__FILE__) + '/../config/environment'
|
|
28
|
+
eval(ARGV.first)
|
data/bin/server
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/opt/local/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'webrick'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
|
|
6
|
+
OPTIONS = {
|
|
7
|
+
:port => 3000,
|
|
8
|
+
:ip => "0.0.0.0",
|
|
9
|
+
:environment => "development",
|
|
10
|
+
:server_root => File.expand_path(File.dirname(__FILE__) + "/../public/"),
|
|
11
|
+
:server_type => WEBrick::SimpleServer,
|
|
12
|
+
:site => nil
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ARGV.options do |opts|
|
|
16
|
+
script_name = File.basename($0)
|
|
17
|
+
opts.banner = "Usage: ruby #{script_name} [options]"
|
|
18
|
+
|
|
19
|
+
opts.separator ""
|
|
20
|
+
|
|
21
|
+
opts.on("-s", "--site=name", String,
|
|
22
|
+
"Specifies the site that this server will run.",
|
|
23
|
+
"Default: none (required)") { |OPTIONS[:site]| }
|
|
24
|
+
opts.on("-p", "--port=port", Integer,
|
|
25
|
+
"Runs Rails on the specified port.",
|
|
26
|
+
"Default: 3000") { |OPTIONS[:port]| }
|
|
27
|
+
opts.on("-b", "--binding=ip", String,
|
|
28
|
+
"Binds Rails to the specified ip.",
|
|
29
|
+
"Default: 0.0.0.0") { |OPTIONS[:ip]| }
|
|
30
|
+
opts.on("-e", "--environment=name", String,
|
|
31
|
+
"Specifies the environment to run this server under (test/development/production).",
|
|
32
|
+
"Default: development") { |OPTIONS[:environment]| }
|
|
33
|
+
opts.on("-d", "--daemon",
|
|
34
|
+
"Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)."
|
|
35
|
+
) { OPTIONS[:server_type] = WEBrick::Daemon }
|
|
36
|
+
|
|
37
|
+
opts.separator ""
|
|
38
|
+
|
|
39
|
+
opts.on("-h", "--help",
|
|
40
|
+
"Show this help message.") { puts opts; exit }
|
|
41
|
+
|
|
42
|
+
opts.parse!
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
ENV["SITE"] = OPTIONS[:site] if OPTIONS[:site]
|
|
46
|
+
ENV["RAILS_ENV"] = OPTIONS[:environment]
|
|
47
|
+
require File.dirname(__FILE__) + "/../config/environment"
|
|
48
|
+
if not defined? SITE or SITE.nil? or SITE.empty?
|
|
49
|
+
puts "=> The SITE environment variable was not set."
|
|
50
|
+
site_dir = Dir.new(File.join(RAILS_ROOT, 'sites'))
|
|
51
|
+
sites = []
|
|
52
|
+
site_dir.each do |d|
|
|
53
|
+
sites << d if File.directory?(File.join(RAILS_ROOT, 'sites', d)) and d != "." and d != ".."
|
|
54
|
+
end
|
|
55
|
+
if sites.size > 0
|
|
56
|
+
puts " According to your sites/ folder, you can set SITE to one of the following:"
|
|
57
|
+
sites.each { |d| puts " - #{d}" }
|
|
58
|
+
puts " So, for example you could start the server with:"
|
|
59
|
+
puts " './script/server -s #{sites.first}'"
|
|
60
|
+
else
|
|
61
|
+
puts " It appears that you do not yet have any sites to choose from. You will need"
|
|
62
|
+
puts " at least one site in your sites/ folder. The best way to start is to use the"
|
|
63
|
+
puts " site generator (http://wiki.rubyonrails.com/rails/show/AvailableGenerators)."
|
|
64
|
+
puts
|
|
65
|
+
puts " e.g."
|
|
66
|
+
puts " ./script/generate site super_value_cart"
|
|
67
|
+
puts
|
|
68
|
+
puts " Then start the server with something like"
|
|
69
|
+
puts " './script/server -s super_value_cart'"
|
|
70
|
+
end
|
|
71
|
+
puts "=> Shutting down."
|
|
72
|
+
exit
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
require 'webrick_server'
|
|
76
|
+
|
|
77
|
+
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
78
|
+
def handle_file(req, res)
|
|
79
|
+
begin
|
|
80
|
+
req = req.dup
|
|
81
|
+
path = req.path.dup
|
|
82
|
+
|
|
83
|
+
# Add .html if the last path piece has no . in it
|
|
84
|
+
path << '.html' if path != '/' && (%r{(^|/)[^./]+$} =~ path)
|
|
85
|
+
path.gsub!('+', ' ') # Unescape + since FileHandler doesn't do so.
|
|
86
|
+
|
|
87
|
+
req.instance_variable_set(:@path_info, path) # Set the modified path...
|
|
88
|
+
|
|
89
|
+
# Dynamically switch the Servlet's root (public) folder on a per-request
|
|
90
|
+
# basis depending on whether or not the requested file exists in the
|
|
91
|
+
# site's public folder or the base public folder.
|
|
92
|
+
base_public = File.join(ABSOLUTE_RAILS_ROOT, 'public')
|
|
93
|
+
site_public = File.expand_path(File.join(ABSOLUTE_RAILS_ROOT, SITE_ROOT, 'public'))
|
|
94
|
+
if File.exist? File.join(site_public, path)
|
|
95
|
+
# The file was found to exist in the site-specific folder, so go there:
|
|
96
|
+
root = site_public
|
|
97
|
+
else
|
|
98
|
+
# Revert to the application base whether or not the file exists here.
|
|
99
|
+
# A "file not found" (or 404) message will occur if the file is also not
|
|
100
|
+
# found in the RAILS_ROOT/public folder.
|
|
101
|
+
root = base_public
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
@file_handler.instance_variable_set(:@root, root) # Set the modified root...
|
|
105
|
+
|
|
106
|
+
@file_handler.send(:service, req, res)
|
|
107
|
+
return true
|
|
108
|
+
rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err
|
|
109
|
+
res.set_error(err)
|
|
110
|
+
return true
|
|
111
|
+
rescue => err
|
|
112
|
+
return false
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
OPTIONS['working_directory'] = File.expand_path(RAILS_ROOT)
|
|
118
|
+
|
|
119
|
+
puts "=> Productized Rails Application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
|
|
120
|
+
puts " Please visit http://inquirylabs.com/productize/ for help related to the"
|
|
121
|
+
puts " productized version of rails. [Author: duane.johnson@gmail.com]"
|
|
122
|
+
puts
|
|
123
|
+
puts "=> Operating for the following site: '#{SITE}'"
|
|
124
|
+
puts "=> Ctrl-C to shutdown server; call with --help for options" if OPTIONS[:server_type] == WEBrick::SimpleServer
|
|
125
|
+
DispatchServlet.dispatch(OPTIONS)
|
data/bin/tracker
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'drb'
|
|
4
|
+
require 'thread'
|
|
5
|
+
|
|
6
|
+
def message(s)
|
|
7
|
+
$stderr.puts "tracker: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Tracker
|
|
11
|
+
include DRbUndumped
|
|
12
|
+
|
|
13
|
+
def initialize(instances, socket_path)
|
|
14
|
+
@instances = instances
|
|
15
|
+
@socket = File.expand_path(socket_path)
|
|
16
|
+
@active = false
|
|
17
|
+
|
|
18
|
+
@listeners = []
|
|
19
|
+
@instances.times { @listeners << Mutex.new }
|
|
20
|
+
|
|
21
|
+
message "using #{@listeners.length} listeners"
|
|
22
|
+
message "opening socket at #{@socket}"
|
|
23
|
+
|
|
24
|
+
@service = DRb.start_service("drbunix://#{@socket}", self)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def with_listener
|
|
28
|
+
message "listener requested"
|
|
29
|
+
|
|
30
|
+
mutex = has_lock = index = nil
|
|
31
|
+
3.times do
|
|
32
|
+
@listeners.each_with_index do |mutex, index|
|
|
33
|
+
has_lock = mutex.try_lock
|
|
34
|
+
break if has_lock
|
|
35
|
+
end
|
|
36
|
+
break if has_lock
|
|
37
|
+
sleep 0.05
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if has_lock
|
|
41
|
+
message "obtained listener #{index}"
|
|
42
|
+
@active = true
|
|
43
|
+
begin yield index
|
|
44
|
+
ensure
|
|
45
|
+
mutex.unlock
|
|
46
|
+
message "released listener #{index}"
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
message "dropping request because no listeners are available!"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def background(check_interval = nil)
|
|
54
|
+
if check_interval
|
|
55
|
+
loop do
|
|
56
|
+
sleep check_interval
|
|
57
|
+
message "Idle for #{check_interval}, shutting down" unless @active
|
|
58
|
+
@active = false
|
|
59
|
+
Kernel.exit 0
|
|
60
|
+
end
|
|
61
|
+
else DRb.thread.join
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
socket_path = ARGV.shift
|
|
67
|
+
instances = ARGV.shift.to_i
|
|
68
|
+
t = Tracker.new(instances, socket_path)
|
|
69
|
+
t.background(ARGV.first ? ARGV.shift.to_i : 90)
|
data/bin/update
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Apache VirtualHost Sample Configuration File
|
|
2
|
+
#
|
|
3
|
+
# == General Apache Setup ==
|
|
4
|
+
#
|
|
5
|
+
# Duplicate this file for each specific site within your productized
|
|
6
|
+
# application. In your Apache global configuration (e.g. httpd.conf) file,
|
|
7
|
+
# add a line to include all of these conf files
|
|
8
|
+
# (e.g. 'Include /Products/generic_cart/config/apache/*')
|
|
9
|
+
#
|
|
10
|
+
# == What You Need to do to This File ==
|
|
11
|
+
#
|
|
12
|
+
# 1. Replace all occurrences of '/Products/generic_cart' with the absolute
|
|
13
|
+
# path to your generic application's root.
|
|
14
|
+
#
|
|
15
|
+
# 2. Replace all occurrences of 'client_co' with the instance of the specific
|
|
16
|
+
# site you want to create. Note that the site name you choose should
|
|
17
|
+
# correspond with the database prefix. For example, if you choose
|
|
18
|
+
# "cup_of_tea_cart" then there should be the following databases set up:
|
|
19
|
+
# * cup_of_tea_test (Test database)
|
|
20
|
+
# * cup_of_tea_dev (Development database)
|
|
21
|
+
# * cup_of_tea (Production database)
|
|
22
|
+
#
|
|
23
|
+
# 3. Replace 'www.example.com' with the actual name of your VirtualHost
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
FastCgiServer /Products/generic_cart/sites/client_co/public/dispatch.fcgi -processes 1 -initial-env SITE=client_co
|
|
27
|
+
|
|
28
|
+
<Directory "/Products/generic_cart/sites/client_co/public/">
|
|
29
|
+
AllowOverride All
|
|
30
|
+
</Directory>
|
|
31
|
+
|
|
32
|
+
# Remember to make sure "NameVirtualHost *:80" is set in Apache's main config file
|
|
33
|
+
# (e.g. httpd.conf) so we can use VirtualHosts.
|
|
34
|
+
<VirtualHost *:80>
|
|
35
|
+
ServerName www.example.com
|
|
36
|
+
DocumentRoot /Products/generic_cart/sites/client_co/public/
|
|
37
|
+
|
|
38
|
+
# The following alias is important since it will allow this particular site to
|
|
39
|
+
# seemlessly use the generic app's resources, e.g. images, javascripts etc. without
|
|
40
|
+
# having to copy all files to the site-specific public/ folder:
|
|
41
|
+
Alias /generic /Products/generic_cart/public/
|
|
42
|
+
</VirtualHost>
|