Class: Gem::Server
- Inherits:
-
Object
- Object
- Gem::Server
- Defined in:
- lib/rubygems/server.rb
Overview
Gem::Server and allows 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.
Constant Summary collapse
- DOC_TEMPLATE =
<<-WEBPAGE <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>RubyGems Documentation Index</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <link rel="stylesheet" href="rdoc-style.css" type="text/css" media="screen" /> </head> <body> <div id="fileHeader"> <h1>RubyGems Documentation Index</h1> </div> <!-- banner header --> <div id="bodyContent"> <div id="contextContent"> <div id="description"> <h1>Summary</h1> <p>There are %gem_count% gems installed:</p> <p> START:specs IFNOT:is_last <a href="#%name%">%name%</a>, ENDIF:is_last IF:is_last <a href="#%name%">%name%</a>. ENDIF:is_last END:specs <h1>Gems</h1> <dl> START:specs <dt> IF:first_name_entry <a name="%name%"></a> ENDIF:first_name_entry <b>%name% %version%</b> IF:rdoc_installed <a href="%doc_path%">[rdoc]</a> ENDIF:rdoc_installed IFNOT:rdoc_installed <span title="rdoc not installed">[rdoc]</span> ENDIF:rdoc_installed IF:homepage <a href="%homepage%" target="_blank" title="%homepage%">[www]</a> ENDIF:homepage IFNOT:homepage <span title="no homepage available">[www]</span> ENDIF:homepage IF:has_deps - depends on START:dependencies IFNOT:is_last <a href="#%name%" title="%version%">%name%</a>, ENDIF:is_last IF:is_last <a href="#%name%" title="%version%">%name%</a>. ENDIF:is_last END:dependencies ENDIF:has_deps </dt> <dd> %summary% IF:executables <br/> IF:only_one_executable Executable is ENDIF:only_one_executable IFNOT:only_one_executable Executables are ENDIF:only_one_executable START:executables IFNOT:is_last <span class="context-item-name">%executable%</span>, ENDIF:is_last IF:is_last <span class="context-item-name">%executable%</span>. ENDIF:is_last END:executables ENDIF:executables <br/> <br/> </dd> END:specs </dl> </div> </div> </div> <div id="validator-badges"> <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> </div> </body> </html> WEBPAGE
- RDOC_CSS =
CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
<<-RDOCCSS body { font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 90%; margin: 0; margin-left: 40px; padding: 0; background: white; } h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } h1 { font-size: 150%; } h2,h3,h4 { margin-top: 1em; } a { background: #eef; color: #039; text-decoration: none; } a:hover { background: #039; color: #eef; } /* Override the base stylesheets Anchor inside a table cell */ td > a { background: transparent; color: #039; text-decoration: none; } /* and inside a section title */ .section-title > a { background: transparent; color: #eee; text-decoration: none; } /* === Structural elements =================================== */ div#index { margin: 0; margin-left: -40px; padding: 0; font-size: 90%; } div#index a { margin-left: 0.7em; } div#index .section-bar { margin-left: 0px; padding-left: 0.7em; background: #ccc; font-size: small; } div#classHeader, div#fileHeader { width: auto; color: white; padding: 0.5em 1.5em 0.5em 1.5em; margin: 0; margin-left: -40px; border-bottom: 3px solid #006; } div#classHeader a, div#fileHeader a { background: inherit; color: white; } div#classHeader td, div#fileHeader td { background: inherit; color: white; } div#fileHeader { background: #057; } div#classHeader { background: #048; } .class-name-in-header { font-size: 180%; font-weight: bold; } div#bodyContent { padding: 0 1.5em 0 1.5em; } div#description { padding: 0.5em 1.5em; background: #efefef; border: 1px dotted #999; } div#description h1,h2,h3,h4,h5,h6 { color: #125;; background: transparent; } div#validator-badges { text-align: center; } div#validator-badges img { border: 0; } div#copyright { color: #333; background: #efefef; font: 0.75em sans-serif; margin-top: 5em; margin-bottom: 0; padding: 0.5em 2em; } /* === Classes =================================== */ table.header-table { color: white; font-size: small; } .type-note { font-size: small; color: #DEDEDE; } .xxsection-bar { background: #eee; color: #333; padding: 3px; } .section-bar { color: #333; border-bottom: 1px solid #999; margin-left: -20px; } .section-title { background: #79a; color: #eee; padding: 3px; margin-top: 2em; margin-left: -30px; border: 1px solid #999; } .top-aligned-row { vertical-align: top } .bottom-aligned-row { vertical-align: bottom } /* --- Context section classes ----------------------- */ .context-row { } .context-item-name { font-family: monospace; font-weight: bold; color: black; } .context-item-value { font-size: small; color: #448; } .context-item-desc { color: #333; padding-left: 2em; } /* --- Method classes -------------------------- */ .method-detail { background: #efefef; padding: 0; margin-top: 0.5em; margin-bottom: 1em; border: 1px dotted #ccc; } .method-heading { color: black; background: #ccc; border-bottom: 1px solid #666; padding: 0.2em 0.5em 0 0.5em; } .method-signature { color: black; background: inherit; } .method-name { font-weight: bold; } .method-args { font-style: italic; } .method-description { padding: 0 0.5em 0 0.5em; } /* --- Source code sections -------------------- */ a.source-toggle { font-size: 90%; } div.method-source-code { background: #262626; color: #ffdead; margin: 1em; padding: 0.5em; border: 1px dashed #999; overflow: hidden; } div.method-source-code pre { color: #ffdead; overflow: hidden; } /* --- Ruby keyword styles --------------------- */ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; } .ruby-constant { color: #7fffd4; background: transparent; } .ruby-keyword { color: #00ffff; background: transparent; } .ruby-ivar { color: #eedd82; background: transparent; } .ruby-operator { color: #00ffee; background: transparent; } .ruby-identifier { color: #ffdead; background: transparent; } .ruby-node { color: #ffa07a; background: transparent; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; } RDOCCSS
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(gemdir, port, daemon) ⇒ Server
constructor
A new instance of Server.
- #run ⇒ Object
Constructor Details
#initialize(gemdir, port, daemon) ⇒ Server
Returns a new instance of Server.
377 378 379 380 381 382 383 |
# File 'lib/rubygems/server.rb', line 377 def initialize(gemdir, port, daemon) Socket.do_not_reverse_lookup=true @gemdir = gemdir @port = port @daemon = daemon end |
Class Method Details
.process_args(args) ⇒ Object
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/rubygems/server.rb', line 340 def self.process_args(args) = {} [:port] = 8808 [:gemdir] = Gem.dir [:daemon] = false opts = OptionParser.new do |opts| opts.on_tail("--help", "show this message") do puts opts exit end opts.on('-p', '--port=PORT', "Specify the port to listen on") do |port| [:port] = port end opts.on('-d', '--dir=GEMDIR', "Specify the directory from which to serve Gems") do |gemdir| [:gemdir] = gemdir end opts.on( '--daemon', "Run as a daemon") do |daemon| [:daemon] = daemon end end opts.parse! args end |
.run(args = ARGV) ⇒ Object
372 373 374 375 |
# File 'lib/rubygems/server.rb', line 372 def self.run(args = ARGV) = process_args args new([:gemdir], [:port], [:daemon]).run end |
Instance Method Details
#run ⇒ Object
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
# File 'lib/rubygems/server.rb', line 385 def run WEBrick::Daemon.start if @daemon spec_dir = File.join @gemdir, "specifications" s = WEBrick::HTTPServer.new :Port => @port s.mount_proc("/yaml") do |req, res| res['content-type'] = 'text/plain' res['date'] = File.stat(spec_dir).mtime res.body << Gem::SourceIndex.from_gems_in(spec_dir).to_yaml end s.mount_proc("/rdoc-style.css") do |req, res| res['content-type'] = 'text/css' res['date'] = File.stat(spec_dir).mtime res.body << RDOC_CSS end s.mount_proc("/") do |req, res| specs = [] total_file_count = 0 Gem::SourceIndex.from_gems_in(spec_dir).each do |path, spec| total_file_count += spec.files.size deps = spec.dependencies.collect { |dep| { "name" => dep.name, "version" => dep.version_requirements.to_s, } } deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] } deps.last["is_last"] = true unless deps.empty? # executables executables = spec.executables.sort.collect { |exec| {"executable" => exec} } executables = nil if executables.empty? executables.last["is_last"] = true if executables specs << { "authors" => spec..sort.join(", "), "date" => spec.date.to_s, "dependencies" => deps, "doc_path" => ('/doc_root/' + spec.full_name + '/rdoc/index.html'), "executables" => executables, "only_one_executable" => (executables && executables.size==1), "full_name" => spec.full_name, "has_deps" => !deps.empty?, "homepage" => spec.homepage, "name" => spec.name, "rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?, "summary" => spec.summary, "version" => spec.version.to_s, } end specs << { "authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others", "dependencies" => [], "doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html", "executables" => [{"executable" => 'gem', "is_last" => true}], "only_one_executable" => true, "full_name" => "rubygems-#{Gem::RubyGemsVersion}", "has_deps" => false, "homepage" => "http://rubygems.org/", "name" => 'rubygems', "rdoc_installed" => true, "summary" => "RubyGems itself", "version" => Gem::RubyGemsVersion, } specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] } specs.last["is_last"] = true # tag all specs with first_name_entry last_spec = nil specs.each do |spec| is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase) spec["first_name_entry"] = is_first last_spec = spec end # create page from template template = TemplatePage.new(DOC_TEMPLATE) res['content-type'] = 'text/html' template.write_html_on res.body, "gem_count" => specs.size.to_s, "specs" => specs, "total_file_count" => total_file_count.to_s end paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" } paths.each do |mount_point, mount_dir| s.mount(mount_point, WEBrick::HTTPServlet::FileHandler, File.join(@gemdir, mount_dir), true) end trap("INT") { s.shutdown; exit! } trap("TERM") { s.shutdown; exit! } s.start end |