#!/usr/bin/env ruby
DOC_TEMPLATE = <<-WEBPAGE
RubyGems Documentation Index
RubyGems Documentation Index
Gem Name |
Description |
Documentation |
START:specs
%full_name% |
%summary% |
IF:rdoc_installed
RDoc Index
ENDIF:rdoc_installed
IFNOT:rdoc_installed
None installed
ENDIF:rdoc_installed
|
END:specs
WEBPAGE
##
# gem_server and gem_server.cgi are equivalent programs that allow
# users to serve gems for consumption by `gem --remote-install`.
#
# gem_server starts an HTTP server on the given port, and serves the folowing:
# * "/" - Browsing of gem spec files for installed gems
# * "/yaml" - Full yaml dump of metadata for installed gems
# * "/gems" - Direct access to download the installable gems
#
# Usage: gem_server [-p portnum] [-d gem_path]
# port_num:: The TCP port the HTTP server will bind to
# gem_path::
# Root gem directory containing both "cache" and "specifications"
# subdirectories.
if __FILE__ == $0
require 'rubygems'
Gem.manage_gems
require 'webrick'
require 'yaml'
require 'optparse'
require 'rdoc/template'
Socket.do_not_reverse_lookup=true
options = {}
ARGV.options do |opts|
opts.on_tail("--help",
"show this message") {puts opts; exit}
opts.on('-pPORT','--port=PORT',
"Specify the port to listen on") { |options[:port]| }
opts.on('-dGEMDIR','--dir=GEMDIR',
"Specify the directory from which to serve Gems") { |options[:gemdir]| }
opts.parse!
end
s = WEBrick::HTTPServer.new(:Port => options[:port] || 8808)
s.mount_proc("/yaml") { |req, res|
fn = File.join(options[:gemdir] || Gem.dir, "specifications")
res['content-type'] = 'text/plain'
res['date'] = File.stat(fn).mtime
res.body << Gem::SourceIndex.from_installed_gems(fn).to_yaml
}
s.mount_proc("/") { |req, res|
specs = []
specifications_dir = File.join(options[:gemdir] || Gem.dir, "specifications")
Gem::SourceIndex.from_installed_gems(specifications_dir).each do |path, spec|
specs << {
"name" => spec.name,
"version" => spec.version,
"full_name" => spec.full_name,
"summary" => spec.summary,
"rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
"doc_path" => ('/doc_root/' + spec.full_name + '/rdoc/index.html')
}
end
specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
template = TemplatePage.new(DOC_TEMPLATE)
res['content-type'] = 'text/html'
template.write_html_on(res.body, {"specs" => specs})
}
{
"/gems" => "/cache/",
"/doc_root" => "/doc/"
}.each do |mount_point, mount_dir|
s.mount(
mount_point,
WEBrick::HTTPServlet::FileHandler,
File.join(options[:gemdir] || Gem.dir, mount_dir),
true)
end
trap("INT") { s.shutdown; exit! }
s.start
end