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.
Files changed (114) hide show
  1. data/CHANGELOG +619 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +195 -0
  4. data/Rakefile +413 -0
  5. data/bin/benchmarker +19 -0
  6. data/bin/breakpointer +3 -0
  7. data/bin/breakpointer_for_gem +4 -0
  8. data/bin/console +23 -0
  9. data/bin/console_sandbox +0 -0
  10. data/bin/destroy +7 -0
  11. data/bin/generate +7 -0
  12. data/bin/listener +86 -0
  13. data/bin/process/reaper +123 -0
  14. data/bin/process/spawner +54 -0
  15. data/bin/process/spinner +60 -0
  16. data/bin/profiler +34 -0
  17. data/bin/rails +17 -0
  18. data/bin/rails_product +17 -0
  19. data/bin/runner +28 -0
  20. data/bin/server +125 -0
  21. data/bin/tracker +69 -0
  22. data/bin/update +5 -0
  23. data/configs/apache/vhost.example.conf +42 -0
  24. data/configs/apache.conf +40 -0
  25. data/configs/database.yml +23 -0
  26. data/configs/empty.log +0 -0
  27. data/configs/routes.rb +19 -0
  28. data/dispatches/dispatch.fcgi +24 -0
  29. data/dispatches/dispatch.rb +10 -0
  30. data/dispatches/gateway.cgi +97 -0
  31. data/doc/README_FOR_APP +2 -0
  32. data/environments/development.rb +14 -0
  33. data/environments/environment.rb +101 -0
  34. data/environments/production.rb +8 -0
  35. data/environments/test.rb +17 -0
  36. data/fresh_rakefile +223 -0
  37. data/helpers/application.rb +4 -0
  38. data/helpers/application_helper.rb +3 -0
  39. data/helpers/test_helper.rb +26 -0
  40. data/html/404.html +8 -0
  41. data/html/500.html +8 -0
  42. data/html/favicon.ico +0 -0
  43. data/html/index.html +78 -0
  44. data/html/javascripts/controls.js +446 -0
  45. data/html/javascripts/dragdrop.js +537 -0
  46. data/html/javascripts/effects.js +612 -0
  47. data/html/javascripts/prototype.js +1038 -0
  48. data/html/robots.txt +1 -0
  49. data/lib/binding_of_caller.rb +83 -0
  50. data/lib/breakpoint.rb +523 -0
  51. data/lib/breakpoint_client.rb +196 -0
  52. data/lib/code_statistics.rb +104 -0
  53. data/lib/console_sandbox.rb +6 -0
  54. data/lib/dispatcher.rb +59 -0
  55. data/lib/fcgi_handler.rb +156 -0
  56. data/lib/productize.rb +116 -0
  57. data/lib/rails_generator/base.rb +203 -0
  58. data/lib/rails_generator/commands.rb +409 -0
  59. data/lib/rails_generator/generators/applications/app/USAGE +16 -0
  60. data/lib/rails_generator/generators/applications/app/app_generator.rb +126 -0
  61. data/lib/rails_generator/generators/applications/productized_app/USAGE +16 -0
  62. data/lib/rails_generator/generators/applications/productized_app/productized_app_generator.rb +133 -0
  63. data/lib/rails_generator/generators/components/controller/USAGE +30 -0
  64. data/lib/rails_generator/generators/components/controller/controller_generator.rb +38 -0
  65. data/lib/rails_generator/generators/components/controller/templates/controller.rb +10 -0
  66. data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +18 -0
  67. data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
  68. data/lib/rails_generator/generators/components/controller/templates/view.rhtml +2 -0
  69. data/lib/rails_generator/generators/components/mailer/USAGE +19 -0
  70. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +32 -0
  71. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +3 -0
  72. data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +13 -0
  73. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +37 -0
  74. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +3 -0
  75. data/lib/rails_generator/generators/components/migration/USAGE +14 -0
  76. data/lib/rails_generator/generators/components/migration/migration_generator.rb +9 -0
  77. data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -0
  78. data/lib/rails_generator/generators/components/model/USAGE +17 -0
  79. data/lib/rails_generator/generators/components/model/model_generator.rb +18 -0
  80. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +5 -0
  81. data/lib/rails_generator/generators/components/model/templates/model.rb +2 -0
  82. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +14 -0
  83. data/lib/rails_generator/generators/components/scaffold/USAGE +32 -0
  84. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +178 -0
  85. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +54 -0
  86. data/lib/rails_generator/generators/components/scaffold/templates/form.rhtml +3 -0
  87. data/lib/rails_generator/generators/components/scaffold/templates/form_scaffolding.rhtml +1 -0
  88. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +98 -0
  89. data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
  90. data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +13 -0
  91. data/lib/rails_generator/generators/components/scaffold/templates/style.css +74 -0
  92. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +9 -0
  93. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +27 -0
  94. data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +8 -0
  95. data/lib/rails_generator/generators/components/scaffold/templates/view_show.rhtml +8 -0
  96. data/lib/rails_generator/generators/components/web_service/USAGE +28 -0
  97. data/lib/rails_generator/generators/components/web_service/templates/api_definition.rb +5 -0
  98. data/lib/rails_generator/generators/components/web_service/templates/controller.rb +8 -0
  99. data/lib/rails_generator/generators/components/web_service/templates/functional_test.rb +19 -0
  100. data/lib/rails_generator/generators/components/web_service/web_service_generator.rb +29 -0
  101. data/lib/rails_generator/lookup.rb +206 -0
  102. data/lib/rails_generator/manifest.rb +53 -0
  103. data/lib/rails_generator/options.rb +134 -0
  104. data/lib/rails_generator/scripts/destroy.rb +7 -0
  105. data/lib/rails_generator/scripts/generate.rb +7 -0
  106. data/lib/rails_generator/scripts/update.rb +12 -0
  107. data/lib/rails_generator/scripts.rb +83 -0
  108. data/lib/rails_generator/simple_logger.rb +46 -0
  109. data/lib/rails_generator/spec.rb +44 -0
  110. data/lib/rails_generator.rb +43 -0
  111. data/lib/rubyprof_ext.rb +35 -0
  112. data/lib/webrick_server.rb +148 -0
  113. data/sites/fresh_rakefile +176 -0
  114. 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)
@@ -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]
@@ -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) }
@@ -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,5 @@
1
+ #!/usr/local/bin/ruby
2
+ require File.dirname(__FILE__) + '/../config/environment'
3
+ require 'rails_generator'
4
+ require 'rails_generator/scripts/update'
5
+ Rails::Generator::Scripts::Update.new.run(ARGV)
@@ -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>