rubygems-update 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (152) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +267 -1
  3. data/Rakefile +13 -7
  4. data/doc/release_notes/rel_1_2_0.rdoc +105 -0
  5. data/lib/rubygems.rb +82 -14
  6. data/lib/rubygems/command.rb +1 -1
  7. data/lib/rubygems/command_manager.rb +3 -2
  8. data/lib/rubygems/commands/cert_command.rb +1 -1
  9. data/lib/rubygems/commands/dependency_command.rb +57 -19
  10. data/lib/rubygems/commands/environment_command.rb +2 -0
  11. data/lib/rubygems/commands/fetch_command.rb +3 -1
  12. data/lib/rubygems/commands/install_command.rb +3 -3
  13. data/lib/rubygems/commands/list_command.rb +30 -28
  14. data/lib/rubygems/commands/lock_command.rb +1 -1
  15. data/lib/rubygems/commands/outdated_command.rb +5 -2
  16. data/lib/rubygems/commands/pristine_command.rb +3 -44
  17. data/lib/rubygems/commands/query_command.rb +80 -21
  18. data/lib/rubygems/commands/sources_command.rb +56 -28
  19. data/lib/rubygems/commands/specification_command.rb +4 -3
  20. data/lib/rubygems/commands/stale_command.rb +27 -0
  21. data/lib/rubygems/commands/update_command.rb +35 -22
  22. data/lib/rubygems/config_file.rb +29 -12
  23. data/lib/rubygems/custom_require.rb +1 -1
  24. data/lib/rubygems/defaults.rb +1 -1
  25. data/lib/rubygems/dependency.rb +63 -9
  26. data/lib/rubygems/dependency_installer.rb +60 -23
  27. data/lib/rubygems/dependency_list.rb +1 -1
  28. data/lib/rubygems/doc_manager.rb +5 -5
  29. data/lib/rubygems/gem_openssl.rb +1 -1
  30. data/lib/rubygems/indexer.rb +269 -84
  31. data/lib/rubygems/install_update_options.rb +6 -0
  32. data/lib/rubygems/installer.rb +35 -12
  33. data/lib/rubygems/local_remote_options.rb +26 -5
  34. data/lib/rubygems/platform.rb +15 -1
  35. data/lib/rubygems/remote_fetcher.rb +158 -90
  36. data/lib/rubygems/requirement.rb +16 -12
  37. data/lib/rubygems/rubygems_version.rb +1 -1
  38. data/lib/rubygems/security.rb +2 -2
  39. data/lib/rubygems/server.rb +239 -110
  40. data/lib/rubygems/source_index.rb +44 -18
  41. data/lib/rubygems/source_info_cache.rb +1 -1
  42. data/lib/rubygems/spec_fetcher.rb +251 -0
  43. data/lib/rubygems/specification.rb +120 -38
  44. data/lib/rubygems/test_utilities.rb +120 -0
  45. data/lib/rubygems/uninstaller.rb +11 -10
  46. data/lib/rubygems/user_interaction.rb +149 -74
  47. data/lib/rubygems/validator.rb +3 -3
  48. data/lib/rubygems/version.rb +23 -21
  49. data/setup.rb +105 -100
  50. data/test/gemutilities.rb +63 -86
  51. data/test/test_config.rb +0 -5
  52. data/test/test_gem.rb +22 -2
  53. data/test/test_gem_command_manager.rb +1 -1
  54. data/test/test_gem_commands_dependency_command.rb +125 -6
  55. data/test/test_gem_commands_environment_command.rb +1 -0
  56. data/test/test_gem_commands_fetch_command.rb +24 -4
  57. data/test/test_gem_commands_install_command.rb +6 -8
  58. data/test/{test_gem_outdated_command.rb → test_gem_commands_outdated_command.rb} +5 -2
  59. data/test/test_gem_commands_pristine_command.rb +13 -4
  60. data/test/test_gem_commands_query_command.rb +113 -37
  61. data/test/test_gem_commands_sources_command.rb +101 -31
  62. data/test/test_gem_commands_specification_command.rb +4 -1
  63. data/test/test_gem_commands_stale_command.rb +39 -0
  64. data/test/test_gem_commands_update_command.rb +17 -27
  65. data/test/test_gem_config_file.rb +38 -1
  66. data/test/test_gem_dependency.rb +51 -0
  67. data/test/test_gem_dependency_installer.rb +133 -25
  68. data/test/test_gem_gem_path_searcher.rb +4 -1
  69. data/test/test_gem_indexer.rb +124 -19
  70. data/test/test_gem_installer.rb +32 -2
  71. data/test/test_gem_local_remote_options.rb +6 -5
  72. data/test/test_gem_remote_fetcher.rb +14 -9
  73. data/test/test_gem_server.rb +207 -21
  74. data/test/test_gem_source_index.rb +203 -63
  75. data/test/test_gem_source_info_cache.rb +8 -6
  76. data/test/test_gem_source_info_cache_entry.rb +11 -9
  77. data/test/test_gem_spec_fetcher.rb +303 -0
  78. data/test/test_gem_specification.rb +91 -7
  79. data/test/test_gem_uninstaller.rb +21 -0
  80. data/test/test_gem_version.rb +14 -5
  81. data/test/test_kernel.rb +1 -1
  82. metadata +10 -73
  83. metadata.gz.sig +0 -0
  84. data/lib/rubygems/indexer/abstract_index_builder.rb +0 -88
  85. data/lib/rubygems/indexer/latest_index_builder.rb +0 -35
  86. data/lib/rubygems/indexer/marshal_index_builder.rb +0 -17
  87. data/lib/rubygems/indexer/master_index_builder.rb +0 -54
  88. data/lib/rubygems/indexer/quick_index_builder.rb +0 -50
  89. data/test/gem_installer_test_case.rbc +0 -0
  90. data/test/gem_package_tar_test_case.rbc +0 -0
  91. data/test/gemutilities.rbc +0 -0
  92. data/test/mockgemui.rbc +0 -0
  93. data/test/simple_gem.rbc +0 -0
  94. data/test/test_config.rbc +0 -0
  95. data/test/test_gem.rbc +0 -0
  96. data/test/test_gem_builder.rbc +0 -0
  97. data/test/test_gem_command.rbc +0 -0
  98. data/test/test_gem_command_manager.rbc +0 -0
  99. data/test/test_gem_commands_build_command.rbc +0 -0
  100. data/test/test_gem_commands_cert_command.rbc +0 -0
  101. data/test/test_gem_commands_check_command.rbc +0 -0
  102. data/test/test_gem_commands_contents_command.rbc +0 -0
  103. data/test/test_gem_commands_dependency_command.rbc +0 -0
  104. data/test/test_gem_commands_environment_command.rbc +0 -0
  105. data/test/test_gem_commands_fetch_command.rbc +0 -0
  106. data/test/test_gem_commands_generate_index_command.rbc +0 -0
  107. data/test/test_gem_commands_install_command.rbc +0 -0
  108. data/test/test_gem_commands_mirror_command.rbc +0 -0
  109. data/test/test_gem_commands_pristine_command.rbc +0 -0
  110. data/test/test_gem_commands_query_command.rbc +0 -0
  111. data/test/test_gem_commands_server_command.rbc +0 -0
  112. data/test/test_gem_commands_sources_command.rbc +0 -0
  113. data/test/test_gem_commands_specification_command.rbc +0 -0
  114. data/test/test_gem_commands_unpack_command.rbc +0 -0
  115. data/test/test_gem_commands_update_command.rbc +0 -0
  116. data/test/test_gem_config_file.rbc +0 -0
  117. data/test/test_gem_dependency.rbc +0 -0
  118. data/test/test_gem_dependency_installer.rbc +0 -0
  119. data/test/test_gem_dependency_list.rbc +0 -0
  120. data/test/test_gem_digest.rbc +0 -0
  121. data/test/test_gem_doc_manager.rbc +0 -0
  122. data/test/test_gem_ext_configure_builder.rbc +0 -0
  123. data/test/test_gem_ext_ext_conf_builder.rbc +0 -0
  124. data/test/test_gem_ext_rake_builder.rbc +0 -0
  125. data/test/test_gem_format.rbc +0 -0
  126. data/test/test_gem_gem_path_searcher.rbc +0 -0
  127. data/test/test_gem_gem_runner.rbc +0 -0
  128. data/test/test_gem_indexer.rbc +0 -0
  129. data/test/test_gem_install_update_options.rbc +0 -0
  130. data/test/test_gem_installer.rbc +0 -0
  131. data/test/test_gem_local_remote_options.rbc +0 -0
  132. data/test/test_gem_outdated_command.rbc +0 -0
  133. data/test/test_gem_package_tar_header.rbc +0 -0
  134. data/test/test_gem_package_tar_input.rbc +0 -0
  135. data/test/test_gem_package_tar_output.rbc +0 -0
  136. data/test/test_gem_package_tar_reader.rbc +0 -0
  137. data/test/test_gem_package_tar_reader_entry.rbc +0 -0
  138. data/test/test_gem_package_tar_writer.rbc +0 -0
  139. data/test/test_gem_platform.rbc +0 -0
  140. data/test/test_gem_remote_fetcher.rbc +0 -0
  141. data/test/test_gem_requirement.rbc +0 -0
  142. data/test/test_gem_server.rbc +0 -0
  143. data/test/test_gem_source_index.rbc +0 -0
  144. data/test/test_gem_source_info_cache.rbc +0 -0
  145. data/test/test_gem_source_info_cache_entry.rbc +0 -0
  146. data/test/test_gem_specification.rbc +0 -0
  147. data/test/test_gem_stream_ui.rbc +0 -0
  148. data/test/test_gem_uninstaller.rbc +0 -0
  149. data/test/test_gem_validator.rbc +0 -0
  150. data/test/test_gem_version.rbc +0 -0
  151. data/test/test_gem_version_option.rbc +0 -0
  152. data/test/test_kernel.rbc +0 -0
@@ -12,6 +12,7 @@ require 'rubygems/version'
12
12
  #
13
13
  # A Requirement object can actually contain multiple, er,
14
14
  # requirements, as in (> 1.2, < 2.0).
15
+
15
16
  class Gem::Requirement
16
17
 
17
18
  include Comparable
@@ -35,7 +36,7 @@ class Gem::Requirement
35
36
  # Version, a String, or nil. Intended to simplify client code.
36
37
  #
37
38
  # If the input is "weird", the default version requirement is returned.
38
- #
39
+
39
40
  def self.create(input)
40
41
  case input
41
42
  when Gem::Requirement then
@@ -57,6 +58,7 @@ class Gem::Requirement
57
58
  # This comment once said:
58
59
  #
59
60
  # "A default "version requirement" can surely _only_ be '> 0'."
61
+
60
62
  def self.default
61
63
  self.new ['>= 0']
62
64
  end
@@ -65,6 +67,7 @@ class Gem::Requirement
65
67
  # Constructs a Requirement from +requirements+ which can be a String, a
66
68
  # Gem::Version, or an Array of those. See parse for details on the
67
69
  # formatting of requirement strings.
70
+
68
71
  def initialize(requirements)
69
72
  @requirements = case requirements
70
73
  when Array then
@@ -77,13 +80,17 @@ class Gem::Requirement
77
80
  @version = nil # Avoid warnings.
78
81
  end
79
82
 
83
+ ##
80
84
  # Marshal raw requirements, rather than the full object
81
- def marshal_dump
85
+
86
+ def marshal_dump # :nodoc:
82
87
  [@requirements]
83
88
  end
84
89
 
90
+ ##
85
91
  # Load custom marshal format
86
- def marshal_load(array)
92
+
93
+ def marshal_load(array) # :nodoc:
87
94
  @requirements = array[0]
88
95
  @version = nil
89
96
  end
@@ -108,20 +115,16 @@ class Gem::Requirement
108
115
  end
109
116
 
110
117
  ##
111
- # Is the requirement satifised by +version+.
112
- #
113
- # version:: [Gem::Version] the version to compare against
114
- # return:: [Boolean] true if this requirement is satisfied by
115
- # the version, otherwise false
116
- #
118
+ # True if this requirement satisfied by the Gem::Version +version+.
119
+
117
120
  def satisfied_by?(version)
118
121
  normalize
119
122
  @requirements.all? { |op, rv| satisfy?(op, version, rv) }
120
123
  end
121
124
 
122
125
  ##
123
- # Is "version op required_version" satisfied?
124
- #
126
+ # Is "+version+ +op+ +required_version+" satisfied?
127
+
125
128
  def satisfy?(op, version, required_version)
126
129
  OPS[op].call(version, required_version)
127
130
  end
@@ -132,6 +135,7 @@ class Gem::Requirement
132
135
  # The requirement can be a String or a Gem::Version. A String can be an
133
136
  # operator (<, <=, =, =>, >, !=, ~>), a version number, or both, operator
134
137
  # first.
138
+
135
139
  def parse(obj)
136
140
  case obj
137
141
  when /^\s*(#{OP_RE})\s*([0-9.]+)\s*$/o then
@@ -147,7 +151,7 @@ class Gem::Requirement
147
151
  end
148
152
  end
149
153
 
150
- def <=>(other)
154
+ def <=>(other) # :nodoc:
151
155
  to_s <=> other.to_s
152
156
  end
153
157
 
@@ -2,5 +2,5 @@
2
2
  # This file is auto-generated by build scripts.
3
3
  # See: rake update_version
4
4
  module Gem
5
- RubyGemsVersion = '1.1.1'
5
+ RubyGemsVersion = '1.2.0'
6
6
  end
@@ -557,7 +557,7 @@ module Gem::Security
557
557
  #
558
558
  # Medium security policy: verify the signing certificate, verify the signing
559
559
  # certificate chain all the way to the root certificate, and only trust root
560
- # certificates that we have explicity allowed trust for.
560
+ # certificates that we have explicitly allowed trust for.
561
561
  #
562
562
  # This security policy is reasonable, but it allows unsigned packages, so a
563
563
  # malicious person could simply delete the package signature and pass the
@@ -576,7 +576,7 @@ module Gem::Security
576
576
  # High security policy: only allow signed gems to be installed, verify the
577
577
  # signing certificate, verify the signing certificate chain all the way to
578
578
  # the root certificate, and only trust root certificates that we have
579
- # explicity allowed trust for.
579
+ # explicitly allowed trust for.
580
580
  #
581
581
  # This security policy is significantly more difficult to bypass, and offers
582
582
  # a reasonable guarantee that the contents of the gem have not been altered.
@@ -4,25 +4,32 @@ require 'zlib'
4
4
  require 'erb'
5
5
 
6
6
  require 'rubygems'
7
+ require 'rubygems/doc_manager'
7
8
 
8
9
  ##
9
10
  # Gem::Server and allows users to serve gems for consumption by
10
11
  # `gem --remote-install`.
11
12
  #
12
- # gem_server starts an HTTP server on the given port and serves the folowing:
13
+ # gem_server starts an HTTP server on the given port and serves the following:
13
14
  # * "/" - Browsing of gem spec files for installed gems
14
- # * "/Marshal" - Full SourceIndex dump of metadata for installed gems
15
- # * "/yaml" - YAML dump of metadata for installed gems - deprecated
15
+ # * "/specs.#{Gem.marshal_version}.gz" - specs name/version/platform index
16
+ # * "/latest_specs.#{Gem.marshal_version}.gz" - latest specs
17
+ # name/version/platform index
18
+ # * "/quick/" - Individual gemspecs
16
19
  # * "/gems" - Direct access to download the installable gems
20
+ # * legacy indexes:
21
+ # * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata
22
+ # for installed gems
23
+ # * "/yaml" - YAML dump of metadata for installed gems - deprecated
17
24
  #
18
25
  # == Usage
19
26
  #
20
- # gem server [-p portnum] [-d gem_path]
27
+ # gem_server = Gem::Server.new Gem.dir, 8089, false
28
+ # gem_server.run
21
29
  #
22
- # port_num:: The TCP port the HTTP server will bind to
23
- # gem_path::
24
- # Root gem directory containing both "cache" and "specifications"
25
- # subdirectories.
30
+ #--
31
+ # TODO Refactor into a real WEBrick servlet to remove code duplication.
32
+
26
33
  class Gem::Server
27
34
 
28
35
  include Gem::UserInteraction
@@ -36,7 +43,6 @@ class Gem::Server
36
43
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
37
44
  <head>
38
45
  <title>RubyGems Documentation Index</title>
39
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
40
46
  <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
41
47
  </head>
42
48
  <body>
@@ -325,32 +331,99 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
325
331
  new(options[:gemdir], options[:port], options[:daemon]).run
326
332
  end
327
333
 
328
- def initialize(gemdir, port, daemon)
334
+ def initialize(gem_dir, port, daemon)
329
335
  Socket.do_not_reverse_lookup = true
330
336
 
331
- @gemdir = gemdir
337
+ @gem_dir = gem_dir
332
338
  @port = port
333
339
  @daemon = daemon
334
340
  logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
335
341
  @server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger
336
342
 
337
- @spec_dir = File.join @gemdir, "specifications"
343
+ @spec_dir = File.join @gem_dir, 'specifications'
344
+
345
+ unless File.directory? @spec_dir then
346
+ raise ArgumentError, "#{@gem_dir} does not appear to be a gem repository"
347
+ end
348
+
338
349
  @source_index = Gem::SourceIndex.from_gems_in @spec_dir
339
350
  end
340
351
 
352
+ def Marshal(req, res)
353
+ @source_index.refresh!
354
+
355
+ res['date'] = File.stat(@spec_dir).mtime
356
+
357
+ index = Marshal.dump @source_index
358
+
359
+ if req.request_method == 'HEAD' then
360
+ res['content-length'] = index.length
361
+ return
362
+ end
363
+
364
+ if req.path =~ /Z$/ then
365
+ res['content-type'] = 'application/x-deflate'
366
+ index = Gem.deflate index
367
+ else
368
+ res['content-type'] = 'application/octet-stream'
369
+ end
370
+
371
+ res.body << index
372
+ end
373
+
374
+ def latest_specs(req, res)
375
+ @source_index.refresh!
376
+
377
+ res['content-type'] = 'application/x-gzip'
378
+
379
+ res['date'] = File.stat(@spec_dir).mtime
380
+
381
+ specs = @source_index.latest_specs.sort.map do |spec|
382
+ platform = spec.original_platform
383
+ platform = Gem::Platform::RUBY if platform.nil?
384
+ [spec.name, spec.version, platform]
385
+ end
386
+
387
+ specs = Marshal.dump specs
388
+
389
+ if req.path =~ /\.gz$/ then
390
+ specs = Gem.gzip specs
391
+ res['content-type'] = 'application/x-gzip'
392
+ else
393
+ res['content-type'] = 'application/octet-stream'
394
+ end
395
+
396
+ if req.request_method == 'HEAD' then
397
+ res['content-length'] = specs.length
398
+ else
399
+ res.body << specs
400
+ end
401
+ end
402
+
341
403
  def quick(req, res)
404
+ @source_index.refresh!
405
+
342
406
  res['content-type'] = 'text/plain'
343
407
  res['date'] = File.stat(@spec_dir).mtime
344
408
 
345
- case req.request_uri.request_uri
409
+ case req.request_uri.path
346
410
  when '/quick/index' then
347
- res.body << @source_index.map { |name,_| name }.join("\n")
411
+ res.body << @source_index.map { |name,| name }.sort.join("\n")
348
412
  when '/quick/index.rz' then
349
- index = @source_index.map { |name,_| name }.join("\n")
350
- res.body << Zlib::Deflate.deflate(index)
413
+ index = @source_index.map { |name,| name }.sort.join("\n")
414
+ res['content-type'] = 'application/x-deflate'
415
+ res.body << Gem.deflate(index)
416
+ when '/quick/latest_index' then
417
+ index = @source_index.latest_specs.map { |spec| spec.full_name }
418
+ res.body << index.sort.join("\n")
419
+ when '/quick/latest_index.rz' then
420
+ index = @source_index.latest_specs.map { |spec| spec.full_name }
421
+ res['content-type'] = 'application/x-deflate'
422
+ res.body << Gem.deflate(index.sort.join("\n"))
351
423
  when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then
352
424
  dep = Gem::Dependency.new $2, $3
353
425
  specs = @source_index.search dep
426
+ marshal_format = $1
354
427
 
355
428
  selector = [$2, $3, $4].map { |s| s.inspect }.join ' '
356
429
 
@@ -368,17 +441,98 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
368
441
  elsif specs.length > 1 then
369
442
  res.status = 500
370
443
  res.body = "Multiple gems found matching #{selector}"
371
- elsif $1 then # marshal quickindex instead of YAML
372
- res.body << Zlib::Deflate.deflate(Marshal.dump(specs.first))
444
+ elsif marshal_format then
445
+ res['content-type'] = 'application/x-deflate'
446
+ res.body << Gem.deflate(Marshal.dump(specs.first))
373
447
  else # deprecated YAML format
374
- res.body << Zlib::Deflate.deflate(specs.first.to_yaml)
448
+ res['content-type'] = 'application/x-deflate'
449
+ res.body << Gem.deflate(specs.first.to_yaml)
375
450
  end
376
451
  else
377
- res.status = 404
378
- res.body = "#{req.request_uri} not found"
452
+ raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
379
453
  end
380
454
  end
381
455
 
456
+ def root(req, res)
457
+ @source_index.refresh!
458
+ res['date'] = File.stat(@spec_dir).mtime
459
+
460
+ raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless
461
+ req.path == '/'
462
+
463
+ specs = []
464
+ total_file_count = 0
465
+
466
+ @source_index.each do |path, spec|
467
+ total_file_count += spec.files.size
468
+ deps = spec.dependencies.map do |dep|
469
+ { "name" => dep.name,
470
+ "type" => dep.type,
471
+ "version" => dep.version_requirements.to_s, }
472
+ end
473
+
474
+ deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
475
+ deps.last["is_last"] = true unless deps.empty?
476
+
477
+ # executables
478
+ executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
479
+ executables = nil if executables.empty?
480
+ executables.last["is_last"] = true if executables
481
+
482
+ specs << {
483
+ "authors" => spec.authors.sort.join(", "),
484
+ "date" => spec.date.to_s,
485
+ "dependencies" => deps,
486
+ "doc_path" => "/doc_root/#{spec.full_name}/rdoc/index.html",
487
+ "executables" => executables,
488
+ "only_one_executable" => (executables && executables.size == 1),
489
+ "full_name" => spec.full_name,
490
+ "has_deps" => !deps.empty?,
491
+ "homepage" => spec.homepage,
492
+ "name" => spec.name,
493
+ "rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
494
+ "summary" => spec.summary,
495
+ "version" => spec.version.to_s,
496
+ }
497
+ end
498
+
499
+ specs << {
500
+ "authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
501
+ "dependencies" => [],
502
+ "doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html",
503
+ "executables" => [{"executable" => 'gem', "is_last" => true}],
504
+ "only_one_executable" => true,
505
+ "full_name" => "rubygems-#{Gem::RubyGemsVersion}",
506
+ "has_deps" => false,
507
+ "homepage" => "http://rubygems.org/",
508
+ "name" => 'rubygems',
509
+ "rdoc_installed" => true,
510
+ "summary" => "RubyGems itself",
511
+ "version" => Gem::RubyGemsVersion,
512
+ }
513
+
514
+ specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
515
+ specs.last["is_last"] = true
516
+
517
+ # tag all specs with first_name_entry
518
+ last_spec = nil
519
+ specs.each do |spec|
520
+ is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
521
+ spec["first_name_entry"] = is_first
522
+ last_spec = spec
523
+ end
524
+
525
+ # create page from template
526
+ template = ERB.new(DOC_TEMPLATE)
527
+ res['content-type'] = 'text/html'
528
+
529
+ values = { "gem_count" => specs.size.to_s, "specs" => specs,
530
+ "total_file_count" => total_file_count.to_s }
531
+
532
+ result = template.result binding
533
+ res.body = result
534
+ end
535
+
382
536
  def run
383
537
  @server.listen nil, @port
384
538
 
@@ -386,27 +540,21 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
386
540
 
387
541
  WEBrick::Daemon.start if @daemon
388
542
 
389
- @server.mount_proc("/yaml") do |req, res|
390
- res['content-type'] = 'text/plain'
391
- res['date'] = File.stat(@spec_dir).mtime
392
- if req.request_method == 'HEAD' then
393
- res['content-length'] = @source_index.to_yaml.length
394
- else
395
- res.body << @source_index.to_yaml
396
- end
397
- end
543
+ @server.mount_proc "/yaml", method(:yaml)
544
+ @server.mount_proc "/yaml.Z", method(:yaml)
398
545
 
399
- @server.mount_proc("/Marshal") do |req, res|
400
- res['content-type'] = 'text/plain'
401
- res['date'] = File.stat(@spec_dir).mtime
402
- if req.request_method == 'HEAD' then
403
- res['content-length'] = Marshal.dump(@source_index).length
404
- else
405
- res.body << Marshal.dump(@source_index)
406
- end
407
- end
546
+ @server.mount_proc "/Marshal.#{Gem.marshal_version}", method(:Marshal)
547
+ @server.mount_proc "/Marshal.#{Gem.marshal_version}.Z", method(:Marshal)
548
+
549
+ @server.mount_proc "/specs.#{Gem.marshal_version}", method(:specs)
550
+ @server.mount_proc "/specs.#{Gem.marshal_version}.gz", method(:specs)
551
+
552
+ @server.mount_proc "/latest_specs.#{Gem.marshal_version}",
553
+ method(:latest_specs)
554
+ @server.mount_proc "/latest_specs.#{Gem.marshal_version}.gz",
555
+ method(:latest_specs)
408
556
 
409
- @server.mount_proc("/quick/", &method(:quick))
557
+ @server.mount_proc "/quick/", method(:quick)
410
558
 
411
559
  @server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
412
560
  res['content-type'] = 'text/css'
@@ -414,80 +562,12 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
414
562
  res.body << RDOC_CSS
415
563
  end
416
564
 
417
- @server.mount_proc("/") do |req, res|
418
- specs = []
419
- total_file_count = 0
420
-
421
- @source_index.each do |path, spec|
422
- total_file_count += spec.files.size
423
- deps = spec.dependencies.collect { |dep|
424
- { "name" => dep.name,
425
- "version" => dep.version_requirements.to_s, }
426
- }
427
- deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
428
- deps.last["is_last"] = true unless deps.empty?
429
-
430
- # executables
431
- executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
432
- executables = nil if executables.empty?
433
- executables.last["is_last"] = true if executables
434
-
435
- specs << {
436
- "authors" => spec.authors.sort.join(", "),
437
- "date" => spec.date.to_s,
438
- "dependencies" => deps,
439
- "doc_path" => ('/doc_root/' + spec.full_name + '/rdoc/index.html'),
440
- "executables" => executables,
441
- "only_one_executable" => (executables && executables.size==1),
442
- "full_name" => spec.full_name,
443
- "has_deps" => !deps.empty?,
444
- "homepage" => spec.homepage,
445
- "name" => spec.name,
446
- "rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
447
- "summary" => spec.summary,
448
- "version" => spec.version.to_s,
449
- }
450
- end
451
-
452
- specs << {
453
- "authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
454
- "dependencies" => [],
455
- "doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html",
456
- "executables" => [{"executable" => 'gem', "is_last" => true}],
457
- "only_one_executable" => true,
458
- "full_name" => "rubygems-#{Gem::RubyGemsVersion}",
459
- "has_deps" => false,
460
- "homepage" => "http://rubygems.org/",
461
- "name" => 'rubygems',
462
- "rdoc_installed" => true,
463
- "summary" => "RubyGems itself",
464
- "version" => Gem::RubyGemsVersion,
465
- }
466
-
467
- specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
468
- specs.last["is_last"] = true
469
-
470
- # tag all specs with first_name_entry
471
- last_spec = nil
472
- specs.each do |spec|
473
- is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
474
- spec["first_name_entry"] = is_first
475
- last_spec = spec
476
- end
477
-
478
- # create page from template
479
- template = ERB.new(DOC_TEMPLATE)
480
- res['content-type'] = 'text/html'
481
- values = { "gem_count" => specs.size.to_s, "specs" => specs,
482
- "total_file_count" => total_file_count.to_s }
483
- result = template.result binding
484
- res.body = result
485
- end
565
+ @server.mount_proc "/", method(:root)
486
566
 
487
567
  paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
488
568
  paths.each do |mount_point, mount_dir|
489
569
  @server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
490
- File.join(@gemdir, mount_dir), true)
570
+ File.join(@gem_dir, mount_dir), true)
491
571
  end
492
572
 
493
573
  trap("INT") { @server.shutdown; exit! }
@@ -496,5 +576,54 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
496
576
  @server.start
497
577
  end
498
578
 
579
+ def specs(req, res)
580
+ @source_index.refresh!
581
+
582
+ res['date'] = File.stat(@spec_dir).mtime
583
+
584
+ specs = @source_index.sort.map do |_, spec|
585
+ platform = spec.original_platform
586
+ platform = Gem::Platform::RUBY if platform.nil?
587
+ [spec.name, spec.version, platform]
588
+ end
589
+
590
+ specs = Marshal.dump specs
591
+
592
+ if req.path =~ /\.gz$/ then
593
+ specs = Gem.gzip specs
594
+ res['content-type'] = 'application/x-gzip'
595
+ else
596
+ res['content-type'] = 'application/octet-stream'
597
+ end
598
+
599
+ if req.request_method == 'HEAD' then
600
+ res['content-length'] = specs.length
601
+ else
602
+ res.body << specs
603
+ end
604
+ end
605
+
606
+ def yaml(req, res)
607
+ @source_index.refresh!
608
+
609
+ res['date'] = File.stat(@spec_dir).mtime
610
+
611
+ index = @source_index.to_yaml
612
+
613
+ if req.path =~ /Z$/ then
614
+ res['content-type'] = 'application/x-deflate'
615
+ index = Gem.deflate index
616
+ else
617
+ res['content-type'] = 'text/plain'
618
+ end
619
+
620
+ if req.request_method == 'HEAD' then
621
+ res['content-length'] = index.length
622
+ return
623
+ end
624
+
625
+ res.body << index
626
+ end
627
+
499
628
  end
500
629