diff options
20 files changed, 475 insertions, 50 deletions
diff --git a/bin/mongrel_rails b/bin/mongrel_rails index eb04b86..0b48b1f 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -72,7 +72,7 @@ class Start < GemPlugin::Plugin "/commands" def configure_rails # need this later for safe reloading - @orig_dollar_quote = $".clone + $orig_dollar_quote = $".clone ENV['RAILS_ENV'] = @environment require 'config/environment' @@ -97,6 +97,7 @@ class Start < GemPlugin::Plugin "/commands" # graceful shutdown trap("TERM") { server.stop + File.unlink @pid_file if File.exist?(@pid_file) } # rails reload @@ -109,6 +110,7 @@ class Start < GemPlugin::Plugin "/commands" # restart trap("USR2") { server.stop + File.unlink @pid_file if File.exist?(@pid_file) @restart = true } end @@ -179,8 +181,6 @@ class Stop < GemPlugin::Plugin "/commands" else send_signal("TERM", @pid_file) end - - File.unlink(@pid_file) end end @@ -214,8 +214,6 @@ class Restart < GemPlugin::Plugin "/commands" else send_signal("USR2", @pid_file) end - - File.unlink(@pid_file) end end diff --git a/doc/site/src/default.template b/doc/site/src/default.template index 37fbbce..9ce3f06 100644 --- a/doc/site/src/default.template +++ b/doc/site/src/default.template @@ -46,6 +46,20 @@ <h4>NEWS</h4> <dl> + <dt>Mar-12-2006</dt> + <dd> + <h5><a href="{relocatable: news.html}">Mongrel 0.3.10 -- Big Release Day</a></h5> + + <p>I normally do lots of little releases rather than large big ones, but this + release involved lots of little touches all over the entire code base. It + now has a ton of features and should have the best Rails support yet. It's + even got <b>GemPlugins</b> to a leve that anyone can use it. Read the + news for the full scoop. + </p> + <a href="http://rubyforge.org/frs/?group_id=1306" title="Downloads">Download</a> + <a href="{relocatable: news.html}"><img src="{relocatable: images/li4.gif}" alt="more" /><br /></a></p> + </dd> + <dt>Mar-06-2006</dt> <dd> <h5><a href="{relocatable: news.html}">Mongrel 0.3.9 -- Gem Based Plugins</a></h5> diff --git a/doc/site/src/docs/gem_plugin.page b/doc/site/src/docs/gem_plugin.page index 346f7b7..40586bf 100644 --- a/doc/site/src/docs/gem_plugin.page +++ b/doc/site/src/docs/gem_plugin.page @@ -17,6 +17,57 @@ new commands. such as "mongrel_rails dostuff". Handlers and Filters are on their way. +h2. Why Plugins for Mongrel? + +If you've ever used other systems that have plugins you'll find there are +several painful parts to writing your own plugin: + +* You don't have their developer tools so it takes forever to get started. +* You don't know how to structure the project or even where to start. +* Once you get it built you have to figure out how to register and install it. +* When you want to update it you have to somehow get the update out to users. +* You have to manage dependencies between your plugin and other plugins. +* Including and using your own resources (images, html files, etc.) or config files + is really painful. Not sure why this is but it's really annoying. + +Most people solve many of the problems by the "sourdough method". They +take a plugin that currently works, copy it, and base their plugin +on the prototype. This works great until you want to do something +original or until you find out the original author did something wrong. + +GemPlugin solves this problem by relying on the regular RubyGems +package management system to give you: + +* A simple way to package, distribute, manage, and update your Mongrel plugins. +* Dynamic loading based on the gem dependencies and not on specific configurations. +* Segregated extensions for Mongrel in case you want a different license than LGPL. +* All the capabilities of RubyGems. GemPlugin doesn't mess with them at all. +* A little generator that starts your project off right similar to how Rails generators work. +* The ability to package resources (images, configs, etc.) with your gem and then load them + dynamically no matter where the gem eventually gets installed. + +In the end GemPlugins are just RubyGems that get loaded a special way +so they are activated right away. The only extra thing is a bit of +"magic" that puts plugins into a nice little namespace outside of +the usual Ruby module and class hierarchy. + +The advantage for Mongrel is that people can write their own +plugins and distribute them easily without anything more complex +than what all Ruby developers already have: RubyGems. + +h2. How They Work + +Mongrel plugins (a.k.a. GemPlugins) are really very simple. Basically +when you use the GemPlugin API you tell it what kind of dependencies +will trigger a gem to be loaded. GemPlugin then goes through all of +the installed gems and loads any that meet the dependency description. +Then your plugin just registers itself in the right "plugin category" +and everything starts working. The user of your plugin won't have to +do too much unless you want to give them additional configuration. + +The best way to understand this is to actually build a plugin +and watch it work. + h2. Your First Plugin diff --git a/doc/site/src/faq.page b/doc/site/src/faq.page index 1c55d50..9bcab42 100644 --- a/doc/site/src/faq.page +++ b/doc/site/src/faq.page @@ -83,7 +83,7 @@ h3. Q: How did you make this site? The site was actually incredibly easy to create. I simply went to "OSWD":http://openwebdesign.org/ and found a design that fit what I wanted for the site. I then went to "Flickr":http://flickr.com/ and found pictures of various animals that were licensed under the -"Creative Commons":http://openwebdesign.org/ license. Once I chopped the images up, worked them +"Creative Commons":http://creativecommons.org/ license. Once I chopped the images up, worked them into the design structure, and wrote an initial set of content I was done. The tool I use to generate the site is called "webgen":http://webgen.rubyforge.org/ which diff --git a/doc/site/src/images/config_tool_snap.png b/doc/site/src/images/config_tool_snap.png Binary files differnew file mode 100644 index 0000000..05e1b14 --- /dev/null +++ b/doc/site/src/images/config_tool_snap.png diff --git a/doc/site/src/news.page b/doc/site/src/news.page index a95a426..caee7ac 100644 --- a/doc/site/src/news.page +++ b/doc/site/src/news.page @@ -7,6 +7,57 @@ ordering: 2 h1. Latest News +h2. Mar-12: Mongrel 0.3.10 -- Big Release Day + +This release is a bigger release than those in the +past but it was necessary as it touched many little +parts of the code base and includes a more complete +GemPlugin functionality. This release features the +following changes: + +* GemPlugin now supports including and easily finding resources and config files + you package with your gems. +* GemPlugin loading doesn't use any deprecated RubyGems APIs. +* GemPlugin comes with a generator called *gpgen* that will make it easy to start off + a plugin project. +* A complete document on "Writing A Mongrel Plugin":/docs/gem_plugin.html that + also explains how they work. +* The "Mongrel Config Tool":/images/config_tool_snap.png that demonstrates + building a useful command for controlling a Mongrel server. +** It uses a "Camping":http://camping.rubyforge.org/ to present an interface. +** Demonstrates combining Camping handlers with Mongrel handlers. +** Shows how to use the new GemPlugin resources API to include ERB templates, images, + and CSS stylesheets which are loaded out of the gem (no external install needed). +* Restructuring of the project source a bit to support testing all the + default plugins and to make building much easier. +* Properly loads any gems that depend on Rails (including GemPlugins) until the + very last minute after Rails is loaded and configured. +* A slight hack courtesy of Sean Treadway which jacks up the default server + listen queue from 5 to 1024. This should work on all platforms where + available and should improve concurrency for everyone. +* A more complete and useful Camping postamble that makes it the same size + as the WEBrick one. Also makes sure that Camping handlers and Mongrel + handlers can live in peace together. + +There's also a bunch of bug fixes: + +* Should work well with edge rails now and tries to be very nice. +* It holds of Rails configuration until the absolute latest time to + avoid having the daemonize call from closing log files Rails opens. +* Tweaks to the API docs in various places and cleaned out dead code. +* Lots of fixes to the build. If you get the source and are on Unix + you can just do "rake install" to install the whole thing via gems. + +This release has been tested on Linux, OSX, and FreeBSD with only +light testing on Win32. I'll be making the 0.3.11 release Win32 +specific so that the config tool can be useful for those folks too. + +Otherwise this is a large release so please grab it and test like +mad. + +"Download 0.3.10":http://rubyforge.org/frs/?group_id=1306 + + h2. Mar-06: Mongrel 0.3.9 -- Gem Based Plugins This release features the beginning of a plugin system based diff --git a/lib/mongrel/rails.rb b/lib/mongrel/rails.rb index 3b99194..fb4e172 100644 --- a/lib/mongrel/rails.rb +++ b/lib/mongrel/rails.rb @@ -28,7 +28,7 @@ class RailsHandler < Mongrel::HttpHandler def initialize(dir, mime_map = {}) @files = Mongrel::DirHandler.new(dir,false) @guard = Mutex.new - + # register the requested mime types mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) } end @@ -76,7 +76,7 @@ class RailsHandler < Mongrel::HttpHandler def reload! @guard.synchronize do - $".replace @orig_dollar_quote + $".replace $orig_dollar_quote GC.start Dispatcher.reset_application! ActionController::Routing::Routes.reload diff --git a/projects/gem_plugin/lib/gem_plugin.rb b/projects/gem_plugin/lib/gem_plugin.rb index bd066c3..9b501f7 100644 --- a/projects/gem_plugin/lib/gem_plugin.rb +++ b/projects/gem_plugin/lib/gem_plugin.rb @@ -189,7 +189,6 @@ module GemPlugin file = File.join(@gems[gem_name], "resources", path) - puts "Looking for: #{file}" if File.exist? file return file else diff --git a/projects/mongrel_config/Rakefile b/projects/mongrel_config/Rakefile index 7337d22..0e46b2e 100644 --- a/projects/mongrel_config/Rakefile +++ b/projects/mongrel_config/Rakefile @@ -15,7 +15,7 @@ setup_rdoc ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] desc "Does a full compile, test run" task :default => [:test, :package] -version="0.1" +version="0.2" name="mongrel_config" setup_gem(name, version) do |spec| diff --git a/projects/mongrel_config/lib/mongrel_config/init.rb b/projects/mongrel_config/lib/mongrel_config/init.rb index 554cc62..47caf19 100644 --- a/projects/mongrel_config/lib/mongrel_config/init.rb +++ b/projects/mongrel_config/lib/mongrel_config/init.rb @@ -1,7 +1,7 @@ require 'mongrel' require 'gem_plugin' require 'camping' - +require 'erb' Camping.goes :Configure @@ -16,75 +16,149 @@ module Configure::Controllers end class Start < R '/start' - def get - `mongrel_rails start -d -p 4000` - redirect Index + def get + render :start + end + + def post + @results = `mongrel_rails start -d -p #{input.port} -e #{input.env} -n #{input.num_procs} -a #{input.address}` + render :start_done end end + class Kill < R '/kill/(\w+)' + + def get(signal) + if _running? + @signal = signal.upcase + pid = open($PID_FILE) {|f| f.read } + begin + Process.kill(@signal, pid.to_i) + @results = "Mongrel sent PID #{pid} signal #{@signal}." + rescue + puts "ERROR: #$!" + @results = "Failed to signal the Mongrel process. Maybe it is not running?<p>#$!</p>" + end + else + @results = "Mongrel does not seem to be running. Maybe delete the pid file #{$PID_FILE} or start again." + end + + render :kill + end + end + + class Stop < R '/stop' def get - `mongrel_rails stop` - redirect Index + render :stop end end - class Shutdown < R '/shutdown' + class Logs < R '/logs' def get - Thread.new do - STDERR.puts "Shutdown requested..." - sleep 2 - $server.stop - STDERR.puts "Bye." - end - render :shutdown + @log_files = Dir.glob("log/**/*") + render :logs end end + end module Configure::Views def layout - html do - head do - title 'Mongrel Configure Tool' - end - body do - h1 "Mongrel Configure Tool" - - p do - a 'start', :href => R(Start) - a 'stop', :href => R(Stop) - a 'shutdown', :href => R(Shutdown) - a 'logs', :href => "../logs" - end - - div.content do - self << yield - end - end + body_content = yield + currently_running = _running? + pid = _pid + open(GemPlugin::Manager.instance.resource("mongrel_config", "/index.html")) do |f| + template = ERB.new(f.read) + self << template.result(binding) end end def show - body do + div do + h2 { "Status" } if _running? - p { "Running..." } + p { "Currently running with PID #{_pid}." } else - p { "Not running..." } + p { "Mongrel is not running." } end end end - def shutdown - body do - p { "Shutdown shortly..." } + def start + div do + form :action => "/start", :method => "POST" do + p { span { "Port:" }; input :name => "port", :value => "4000" } + p { span { "Environment:" }; input :name => "env", :value => "development" } + p { span { "Address:" }; input :name => "address", :value => "0.0.0.0" } + p { span { "Number Processors:" }; input :name => "num_procs", :value => "20" } + input :type => "submit", :value => "START" + end end end + def start_done + div do + p { @results } + end + end + + def kill + div do + p { @results } + + case @signal + when "HUP": + p { "A reload (HUP) does not stop the process, but may not be complete." } + when "TERM": + p { "Stopped with TERM signal. The process should exit shortly, but only after processing pending requests." } + when "USR2": + p { "Complete restart (USR2) may take a little while. Check status in a few seconds or read logs." } + when "KILL": + p { "Process was violently stopped (KILL) so pending requests will be lost." } + end + end + end + + def stop + if _running? + ul do + li { a "Stop (TERM)", :href => "/kill/term" } + li { a "Reload (HUP)", :href => "/kill/hup" } + li { a "Restart (USR2)", :href => "/kill/usr2" } + li { a "Kill (KILL)", :href => "/kill/kill" } + end + else + p { "Mongrel does not appear to be running (no PID file at #$PID_FILE)." } + end + end + + def logs + div do + h2 { "Logs" } + table do + tr do + th { "File"}; th { "Bytes" }; th { "Last Modified" } + end + @log_files.each do |file| + tr do + td { a file, :href => "../#{file}" } + td { File.size file } + td { File.mtime file } + end + end + end + end + end + def _running? File.exist? $PID_FILE end + + def _pid + open($PID_FILE) {|f| f.read } if _running? + end end def Configure.create @@ -139,7 +213,9 @@ class ConfigTool < GemPlugin::Plugin "/commands" end # add our log directory - $server.register("/logs", Mongrel::DirHandler.new("log")) + $server.register("/log", Mongrel::DirHandler.new("log")) + resources = GemPlugin::Manager.instance.resource "mongrel_config", "/" + $server.register("/config/resources", Mongrel::DirHandler.new(resources)) $server.acceptor.join end diff --git a/projects/mongrel_config/resources/images/0170_bubble.png b/projects/mongrel_config/resources/images/0170_bubble.png Binary files differnew file mode 100644 index 0000000..57a289e --- /dev/null +++ b/projects/mongrel_config/resources/images/0170_bubble.png diff --git a/projects/mongrel_config/resources/images/0171_new_page.png b/projects/mongrel_config/resources/images/0171_new_page.png Binary files differnew file mode 100644 index 0000000..929d499 --- /dev/null +++ b/projects/mongrel_config/resources/images/0171_new_page.png diff --git a/projects/mongrel_config/resources/images/bottom.gif b/projects/mongrel_config/resources/images/bottom.gif Binary files differnew file mode 100644 index 0000000..8d65a26 --- /dev/null +++ b/projects/mongrel_config/resources/images/bottom.gif diff --git a/projects/mongrel_config/resources/images/bottom_orig.gif b/projects/mongrel_config/resources/images/bottom_orig.gif Binary files differnew file mode 100644 index 0000000..a2cfcfc --- /dev/null +++ b/projects/mongrel_config/resources/images/bottom_orig.gif diff --git a/projects/mongrel_config/resources/images/middle.jpg b/projects/mongrel_config/resources/images/middle.jpg Binary files differnew file mode 100644 index 0000000..447b1a2 --- /dev/null +++ b/projects/mongrel_config/resources/images/middle.jpg diff --git a/projects/mongrel_config/resources/images/top.jpg b/projects/mongrel_config/resources/images/top.jpg Binary files differnew file mode 100644 index 0000000..ee2327d --- /dev/null +++ b/projects/mongrel_config/resources/images/top.jpg diff --git a/projects/mongrel_config/resources/images/topbar.jpg b/projects/mongrel_config/resources/images/topbar.jpg Binary files differnew file mode 100644 index 0000000..83269b0 --- /dev/null +++ b/projects/mongrel_config/resources/images/topbar.jpg diff --git a/projects/mongrel_config/resources/index.html b/projects/mongrel_config/resources/index.html new file mode 100644 index 0000000..a0700f8 --- /dev/null +++ b/projects/mongrel_config/resources/index.html @@ -0,0 +1,71 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+<title>Mongrel Config Tool</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<link href="/config/resources/style.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<div id="container">
+ <div id="top">
+ <div id="title">Mongrel Config Tool</div>
+ </div>
+ <div id="middle">
+ <div id="nav">
+ <ul>
+ <li><a href="/config">Status</a></li>
+ <li><a href="/config/start">Start</a></li>
+ <li><a href="/config/stop">Stop</a></li>
+ <li><a href="/config/logs">Logs</a></li>
+ </ul>
+ </div>
+ <div id="content">
+ <div id="side">
+ <% if currently_running %>
+ <strong>Status</strong> <br />
+ <br />
+ Mongrel is running with PID <%= pid %>.
+ <% else %>
+ <strong>Status</strong> <br />
+ <br />
+ Mongrel is not running.
+ <% end %>
+ <br /><br />
+ <br />
+ <strong>Documentation</strong><br />
+ <br />
+ <a href="http://mongrel.rubyforge.org">Mongrel Home</a> <br />
+ <br />
+
+ <a href="http://mongrel.rubyforge.org/news.html">News</a><br />
+ <br />
+
+ <a href="http://mongrel.rubyforge.org/docs/started.html">Getting Started</a> <br />
+ <br />
+
+ <a href="http://mongrel.rubyforge.org/docs/win32.html">Win32 Guide</a><br />
+ <br />
+
+ <a href="http://mongrel.rubyforge.org/docs/lighttpd.html">Lighttpd Guide</a><br />
+ <br />
+
+ <a href="http://mongrel.rubyforge.org/rdoc/index.html">Mongrel API</a><br />
+ <br />
+
+ <a href="http://api.rubyonrails.org/">Ruby On Rails API</a><br />
+ <br />
+
+ <br /><br />
+ </div>
+
+ <%= body_content %>
+
+ </div>
+ </div>
+ </div>
+
+ <div id="bottom"> </div>
+
+<div id="footertext">Copyright 2006 © Zed A. Shaw | Design by Kenneth Barbour.</div>
+</body>
+</html>
diff --git a/projects/mongrel_config/resources/style.css b/projects/mongrel_config/resources/style.css new file mode 100644 index 0000000..4c546f9 --- /dev/null +++ b/projects/mongrel_config/resources/style.css @@ -0,0 +1,165 @@ +/* CSS Document */
+body {
+ margin: 25px auto 0px auto;
+ background-image: url(/config/resources/images/top.jpg);
+ background-repeat: repeat-x;
+ background-position: top;
+ font-family: "Lucida Grande", Verdana, Halvetica, sans-serif;
+ text-align: center;
+
+}
+a:hover {
+ color: #990000;
+ text-decoration: underline;
+}
+a {
+ color: #990000;
+ text-decoration: none;
+}
+#container {
+ font-weight: normal;
+ margin: 0px auto 0px auto;
+ width: 686px;
+ text-align: center;
+
+}
+#main {
+ padding-top: 50px;
+ padding-bottom: 50px;
+ border: 1px solid #CC0000;
+ height: auto;
+}
+#title {
+ font-family: Georgia, "Times New Roman", Times, serif;
+ font-size: 36px;
+ color: #FFF;
+ font-weight: normal;
+ font-size:36px;
+ text-align: center;
+ color: #FFFFFF;
+ padding-top: 28px;
+}
+#top {
+ margin: 0px auto;
+ width: 686px;
+ height: 96px;
+ background: url(/config/resources/images/topbar.jpg) no-repeat
+}
+#middle {
+ background: url(/config/resources/images/middle.jpg) no-repeat;
+ background-repeat: repeat-y;
+ margin: -2px auto 0px auto;
+}
+#bottom {
+ margin: -100px auto 0px;
+ width: 686px;
+ height: 106px;
+ background: url(/config/resources/images/bottom.gif) no-repeat;
+ clear: center;
+
+}
+#nav {
+ width: 455px;
+ padding: 20px 30px 10px;
+ margin: 0px auto;
+ color: #999;
+ font-weight: normal;
+ font-size: 11px;
+ text-align: center;
+
+}
+#nav li {
+ list-style: none;
+ display: inline;
+ margin-right: 20px;
+}
+#nav a {
+ font-size: 10px;
+ font-weight: bold;
+ color: #999;
+ text-decoration: none;
+}
+#nav a:hover {
+ color: #990000;
+ text-decoration: underline;
+}
+#content {
+ padding: 0px 68px 1px 68px;
+ margin: 0px auto 0px auto;
+ text-align: left;
+ height: 370px;
+}
+#side {
+ margin: 30px auto 0px auto;
+ width: 110px;
+ border-left: 1px dotted #C4D0D7;
+ padding: 0px 10px 0px 20px;
+ color: #999;
+ float: right;
+ font-size: 70%;
+}
+#content h2 {
+ color: #990000;
+ font-weight: bolder;
+ font-size: 14px;
+ padding: 0px 135px 0px 10px;
+}
+#content h2 a:hover{
+ color: #990000;
+ text-decoration: underline;
+}
+#content h2 a{
+ text-decoration: none;
+}
+#content h3 {
+ color: #000000;
+ font-size: 10px;
+ letter-spacing: .3em;
+ padding: 0px 135px 0px 10px;
+ text-decoration: underline;
+
+}
+#content p {
+ padding: 0px 170px 0px 10px;
+ font-size: 70%;
+ line-height: 1.7em;
+ margin: 0px 0px 1.7em 0px;
+ vertical-align: top;
+ color: #666666;
+
+}
+#footertext {
+ font-size: 10px;
+ font-weight: bold;
+ margin: 20px auto 0px;
+ height: 20px;
+ width: 686px;
+ height: 31px;
+ text-align: center;
+ color: #888;
+}
+#footertext a {
+ font-size: 10px;
+ font-weight: bold;
+ color: #999;
+ text-decoration: none;
+}
+#footertext a:hover {
+ text-decoration: underline;
+}
+
+table {
+ border-collapse: collapsed;
+}
+
+td {
+ font-size: 11px;
+ padding: 5px;
+}
+
+th {
+ border: 1px #990000 solid;
+ font-size: 12px;
+ background-color: #955;
+ color: #eeeeee;
+}
\ No newline at end of file diff --git a/projects/mongrel_status/Rakefile b/projects/mongrel_status/Rakefile index cacfa84..8f48d2c 100644 --- a/projects/mongrel_status/Rakefile +++ b/projects/mongrel_status/Rakefile @@ -15,7 +15,7 @@ setup_rdoc ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] desc "Does a full compile, test run" task :default => [:test, :package] -version="0.1" +version="0.2" name="mongrel_status" setup_gem(name, version) do |spec| |