slimgems 1.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. data/ChangeLog +5811 -0
  2. data/History.txt +887 -0
  3. data/LICENSE.txt +51 -0
  4. data/README.md +87 -0
  5. data/Rakefile +120 -0
  6. data/bin/gem +25 -0
  7. data/bin/update_slimgems +35 -0
  8. data/bootstrap/Rakefile +4 -0
  9. data/hide_lib_for_update/note.txt +5 -0
  10. data/lib/gauntlet_rubygems.rb +50 -0
  11. data/lib/rbconfig/datadir.rb +20 -0
  12. data/lib/rubygems.rb +1220 -0
  13. data/lib/rubygems/builder.rb +102 -0
  14. data/lib/rubygems/command.rb +534 -0
  15. data/lib/rubygems/command_manager.rb +182 -0
  16. data/lib/rubygems/commands/build_command.rb +53 -0
  17. data/lib/rubygems/commands/cert_command.rb +86 -0
  18. data/lib/rubygems/commands/check_command.rb +80 -0
  19. data/lib/rubygems/commands/cleanup_command.rb +106 -0
  20. data/lib/rubygems/commands/contents_command.rb +98 -0
  21. data/lib/rubygems/commands/dependency_command.rb +195 -0
  22. data/lib/rubygems/commands/environment_command.rb +132 -0
  23. data/lib/rubygems/commands/fetch_command.rb +67 -0
  24. data/lib/rubygems/commands/generate_index_command.rb +133 -0
  25. data/lib/rubygems/commands/help_command.rb +172 -0
  26. data/lib/rubygems/commands/install_command.rb +178 -0
  27. data/lib/rubygems/commands/list_command.rb +35 -0
  28. data/lib/rubygems/commands/lock_command.rb +110 -0
  29. data/lib/rubygems/commands/mirror_command.rb +111 -0
  30. data/lib/rubygems/commands/outdated_command.rb +33 -0
  31. data/lib/rubygems/commands/owner_command.rb +75 -0
  32. data/lib/rubygems/commands/pristine_command.rb +93 -0
  33. data/lib/rubygems/commands/push_command.rb +56 -0
  34. data/lib/rubygems/commands/query_command.rb +280 -0
  35. data/lib/rubygems/commands/rdoc_command.rb +91 -0
  36. data/lib/rubygems/commands/search_command.rb +31 -0
  37. data/lib/rubygems/commands/server_command.rb +86 -0
  38. data/lib/rubygems/commands/setup_command.rb +387 -0
  39. data/lib/rubygems/commands/sources_command.rb +157 -0
  40. data/lib/rubygems/commands/specification_command.rb +125 -0
  41. data/lib/rubygems/commands/stale_command.rb +27 -0
  42. data/lib/rubygems/commands/uninstall_command.rb +83 -0
  43. data/lib/rubygems/commands/unpack_command.rb +121 -0
  44. data/lib/rubygems/commands/update_command.rb +212 -0
  45. data/lib/rubygems/commands/which_command.rb +86 -0
  46. data/lib/rubygems/config_file.rb +345 -0
  47. data/lib/rubygems/custom_require.rb +44 -0
  48. data/lib/rubygems/defaults.rb +101 -0
  49. data/lib/rubygems/dependency.rb +227 -0
  50. data/lib/rubygems/dependency_installer.rb +286 -0
  51. data/lib/rubygems/dependency_list.rb +208 -0
  52. data/lib/rubygems/doc_manager.rb +242 -0
  53. data/lib/rubygems/errors.rb +35 -0
  54. data/lib/rubygems/exceptions.rb +91 -0
  55. data/lib/rubygems/ext.rb +18 -0
  56. data/lib/rubygems/ext/builder.rb +56 -0
  57. data/lib/rubygems/ext/configure_builder.rb +25 -0
  58. data/lib/rubygems/ext/ext_conf_builder.rb +24 -0
  59. data/lib/rubygems/ext/rake_builder.rb +39 -0
  60. data/lib/rubygems/format.rb +81 -0
  61. data/lib/rubygems/gem_openssl.rb +92 -0
  62. data/lib/rubygems/gem_path_searcher.rb +100 -0
  63. data/lib/rubygems/gem_runner.rb +79 -0
  64. data/lib/rubygems/gemcutter_utilities.rb +49 -0
  65. data/lib/rubygems/indexer.rb +720 -0
  66. data/lib/rubygems/install_update_options.rb +125 -0
  67. data/lib/rubygems/installer.rb +604 -0
  68. data/lib/rubygems/local_remote_options.rb +135 -0
  69. data/lib/rubygems/old_format.rb +153 -0
  70. data/lib/rubygems/package.rb +97 -0
  71. data/lib/rubygems/package/f_sync_dir.rb +23 -0
  72. data/lib/rubygems/package/tar_header.rb +266 -0
  73. data/lib/rubygems/package/tar_input.rb +222 -0
  74. data/lib/rubygems/package/tar_output.rb +144 -0
  75. data/lib/rubygems/package/tar_reader.rb +106 -0
  76. data/lib/rubygems/package/tar_reader/entry.rb +141 -0
  77. data/lib/rubygems/package/tar_writer.rb +241 -0
  78. data/lib/rubygems/package_task.rb +126 -0
  79. data/lib/rubygems/platform.rb +183 -0
  80. data/lib/rubygems/remote_fetcher.rb +414 -0
  81. data/lib/rubygems/require_paths_builder.rb +18 -0
  82. data/lib/rubygems/requirement.rb +153 -0
  83. data/lib/rubygems/security.rb +814 -0
  84. data/lib/rubygems/server.rb +872 -0
  85. data/lib/rubygems/source_index.rb +597 -0
  86. data/lib/rubygems/source_info_cache.rb +395 -0
  87. data/lib/rubygems/source_info_cache_entry.rb +56 -0
  88. data/lib/rubygems/spec_fetcher.rb +337 -0
  89. data/lib/rubygems/specification.rb +1486 -0
  90. data/lib/rubygems/test_utilities.rb +147 -0
  91. data/lib/rubygems/text.rb +65 -0
  92. data/lib/rubygems/uninstaller.rb +278 -0
  93. data/lib/rubygems/user_interaction.rb +527 -0
  94. data/lib/rubygems/validator.rb +240 -0
  95. data/lib/rubygems/version.rb +316 -0
  96. data/lib/rubygems/version_option.rb +65 -0
  97. data/lib/ubygems.rb +10 -0
  98. data/setup.rb +42 -0
  99. data/test/bogussources.rb +8 -0
  100. data/test/data/gem-private_key.pem +27 -0
  101. data/test/data/gem-public_cert.pem +20 -0
  102. data/test/fake_certlib/openssl.rb +7 -0
  103. data/test/foo/discover.rb +0 -0
  104. data/test/functional.rb +92 -0
  105. data/test/gem_installer_test_case.rb +97 -0
  106. data/test/gem_package_tar_test_case.rb +132 -0
  107. data/test/gemutilities.rb +605 -0
  108. data/test/insure_session.rb +43 -0
  109. data/test/mockgemui.rb +56 -0
  110. data/test/plugin/exception/rubygems_plugin.rb +2 -0
  111. data/test/plugin/load/rubygems_plugin.rb +1 -0
  112. data/test/plugin/standarderror/rubygems_plugin.rb +2 -0
  113. data/test/private_key.pem +27 -0
  114. data/test/public_cert.pem +20 -0
  115. data/test/rubygems_plugin.rb +21 -0
  116. data/test/simple_gem.rb +66 -0
  117. data/test/test_config.rb +12 -0
  118. data/test/test_gem.rb +766 -0
  119. data/test/test_gem_builder.rb +27 -0
  120. data/test/test_gem_command.rb +178 -0
  121. data/test/test_gem_command_manager.rb +207 -0
  122. data/test/test_gem_commands_build_command.rb +74 -0
  123. data/test/test_gem_commands_cert_command.rb +124 -0
  124. data/test/test_gem_commands_check_command.rb +18 -0
  125. data/test/test_gem_commands_contents_command.rb +156 -0
  126. data/test/test_gem_commands_dependency_command.rb +216 -0
  127. data/test/test_gem_commands_environment_command.rb +144 -0
  128. data/test/test_gem_commands_fetch_command.rb +76 -0
  129. data/test/test_gem_commands_generate_index_command.rb +135 -0
  130. data/test/test_gem_commands_install_command.rb +315 -0
  131. data/test/test_gem_commands_list_command.rb +36 -0
  132. data/test/test_gem_commands_lock_command.rb +68 -0
  133. data/test/test_gem_commands_mirror_command.rb +60 -0
  134. data/test/test_gem_commands_outdated_command.rb +40 -0
  135. data/test/test_gem_commands_owner_command.rb +105 -0
  136. data/test/test_gem_commands_pristine_command.rb +108 -0
  137. data/test/test_gem_commands_push_command.rb +81 -0
  138. data/test/test_gem_commands_query_command.rb +426 -0
  139. data/test/test_gem_commands_server_command.rb +59 -0
  140. data/test/test_gem_commands_sources_command.rb +209 -0
  141. data/test/test_gem_commands_specification_command.rb +139 -0
  142. data/test/test_gem_commands_stale_command.rb +38 -0
  143. data/test/test_gem_commands_uninstall_command.rb +83 -0
  144. data/test/test_gem_commands_unpack_command.rb +199 -0
  145. data/test/test_gem_commands_update_command.rb +353 -0
  146. data/test/test_gem_commands_which_command.rb +66 -0
  147. data/test/test_gem_config_file.rb +287 -0
  148. data/test/test_gem_dependency.rb +149 -0
  149. data/test/test_gem_dependency_installer.rb +661 -0
  150. data/test/test_gem_dependency_list.rb +230 -0
  151. data/test/test_gem_doc_manager.rb +31 -0
  152. data/test/test_gem_ext_configure_builder.rb +84 -0
  153. data/test/test_gem_ext_ext_conf_builder.rb +173 -0
  154. data/test/test_gem_ext_rake_builder.rb +81 -0
  155. data/test/test_gem_format.rb +70 -0
  156. data/test/test_gem_gem_path_searcher.rb +78 -0
  157. data/test/test_gem_gem_runner.rb +45 -0
  158. data/test/test_gem_gemcutter_utilities.rb +103 -0
  159. data/test/test_gem_indexer.rb +673 -0
  160. data/test/test_gem_install_update_options.rb +68 -0
  161. data/test/test_gem_installer.rb +857 -0
  162. data/test/test_gem_local_remote_options.rb +97 -0
  163. data/test/test_gem_package_tar_header.rb +130 -0
  164. data/test/test_gem_package_tar_input.rb +112 -0
  165. data/test/test_gem_package_tar_output.rb +97 -0
  166. data/test/test_gem_package_tar_reader.rb +46 -0
  167. data/test/test_gem_package_tar_reader_entry.rb +109 -0
  168. data/test/test_gem_package_tar_writer.rb +144 -0
  169. data/test/test_gem_package_task.rb +59 -0
  170. data/test/test_gem_platform.rb +264 -0
  171. data/test/test_gem_remote_fetcher.rb +740 -0
  172. data/test/test_gem_requirement.rb +292 -0
  173. data/test/test_gem_server.rb +356 -0
  174. data/test/test_gem_silent_ui.rb +113 -0
  175. data/test/test_gem_source_index.rb +461 -0
  176. data/test/test_gem_spec_fetcher.rb +410 -0
  177. data/test/test_gem_specification.rb +1291 -0
  178. data/test/test_gem_stream_ui.rb +218 -0
  179. data/test/test_gem_text.rb +43 -0
  180. data/test/test_gem_uninstaller.rb +146 -0
  181. data/test/test_gem_validator.rb +63 -0
  182. data/test/test_gem_version.rb +181 -0
  183. data/test/test_gem_version_option.rb +89 -0
  184. data/test/test_kernel.rb +59 -0
  185. metadata +413 -0
@@ -0,0 +1,597 @@
1
+ #--
2
+ # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+ require 'rubygems/user_interaction'
8
+ require 'rubygems/specification'
9
+
10
+ # :stopdoc:
11
+ module Gem
12
+ autoload :SpecFetcher, 'rubygems/spec_fetcher'
13
+ end
14
+ # :startdoc:
15
+
16
+ ##
17
+ # The SourceIndex object indexes all the gems available from a
18
+ # particular source (e.g. a list of gem directories, or a remote
19
+ # source). A SourceIndex maps a gem full name to a gem
20
+ # specification.
21
+ #
22
+ # NOTE:: The class used to be named Cache, but that became
23
+ # confusing when cached source fetchers where introduced. The
24
+ # constant Gem::Cache is an alias for this class to allow old
25
+ # YAMLized source index objects to load properly.
26
+
27
+ class Gem::SourceIndex
28
+
29
+ include Enumerable
30
+
31
+ include Gem::UserInteraction
32
+
33
+ attr_reader :gems # :nodoc:
34
+
35
+ ##
36
+ # Directories to use to refresh this SourceIndex when calling refresh!
37
+
38
+ attr_accessor :spec_dirs
39
+
40
+ class << self
41
+ include Gem::UserInteraction
42
+
43
+ ##
44
+ # Factory method to construct a source index instance for a given
45
+ # path.
46
+ #
47
+ # deprecated::
48
+ # If supplied, from_installed_gems will act just like
49
+ # +from_gems_in+. This argument is deprecated and is provided
50
+ # just for backwards compatibility, and should not generally
51
+ # be used.
52
+ #
53
+ # return::
54
+ # SourceIndex instance
55
+
56
+ def from_installed_gems(*deprecated)
57
+ if deprecated.empty?
58
+ from_gems_in(*installed_spec_directories)
59
+ else
60
+ from_gems_in(*deprecated) # HACK warn
61
+ end
62
+ end
63
+
64
+ ##
65
+ # Returns a list of directories from Gem.path that contain specifications.
66
+
67
+ def installed_spec_directories
68
+ Gem.path.collect { |dir| File.join(dir, "specifications") }
69
+ end
70
+
71
+ ##
72
+ # Creates a new SourceIndex from the ruby format gem specifications in
73
+ # +spec_dirs+.
74
+
75
+ def from_gems_in(*spec_dirs)
76
+ source_index = new
77
+ source_index.spec_dirs = spec_dirs
78
+ source_index.refresh!
79
+ end
80
+
81
+ ##
82
+ # Loads a ruby-format specification from +file_name+ and returns the
83
+ # loaded spec.
84
+
85
+ def load_specification(file_name)
86
+ return nil unless file_name and File.exist? file_name
87
+
88
+ spec_code = if defined? Encoding then
89
+ File.read file_name, :encoding => 'UTF-8'
90
+ else
91
+ File.read file_name
92
+ end.untaint
93
+
94
+ begin
95
+ gemspec = eval spec_code, binding, file_name
96
+
97
+ if gemspec.is_a?(Gem::Specification)
98
+ gemspec.loaded_from = file_name
99
+ return gemspec
100
+ end
101
+ alert_warning "File '#{file_name}' does not evaluate to a gem specification"
102
+ rescue SignalException, SystemExit
103
+ raise
104
+ rescue SyntaxError => e
105
+ alert_warning e
106
+ alert_warning spec_code
107
+ rescue Exception => e
108
+ alert_warning "#{e.inspect}\n#{spec_code}"
109
+ alert_warning "Invalid .gemspec format in '#{file_name}'"
110
+ end
111
+
112
+ return nil
113
+ end
114
+
115
+ end
116
+
117
+ ##
118
+ # Constructs a source index instance from the provided specifications, which
119
+ # is a Hash of gem full names and Gem::Specifications.
120
+ #--
121
+ # TODO merge @gems and @prerelease_gems and provide a separate method
122
+ # #prerelease_gems
123
+
124
+ def initialize(specifications={})
125
+ @gems = {}
126
+ specifications.each{ |full_name, spec| add_spec spec }
127
+ @spec_dirs = nil
128
+ end
129
+
130
+ # TODO: remove method
131
+ def all_gems
132
+ @gems
133
+ end
134
+
135
+ def prerelease_gems
136
+ @gems.reject{ |name, gem| !gem.version.prerelease? }
137
+ end
138
+
139
+ def released_gems
140
+ @gems.reject{ |name, gem| gem.version.prerelease? }
141
+ end
142
+
143
+ ##
144
+ # Reconstruct the source index from the specifications in +spec_dirs+.
145
+
146
+ def load_gems_in(*spec_dirs)
147
+ @gems.clear
148
+
149
+ spec_dirs.reverse_each do |spec_dir|
150
+ spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
151
+
152
+ spec_files.each do |spec_file|
153
+ gemspec = self.class.load_specification spec_file.untaint
154
+ add_spec gemspec if gemspec
155
+ end
156
+ end
157
+
158
+ self
159
+ end
160
+
161
+ ##
162
+ # Returns an Array specifications for the latest released versions
163
+ # of each gem in this index.
164
+
165
+ def latest_specs
166
+ result = Hash.new { |h,k| h[k] = [] }
167
+ latest = {}
168
+
169
+ sort.each do |_, spec|
170
+ name = spec.name
171
+ curr_ver = spec.version
172
+ prev_ver = latest.key?(name) ? latest[name].version : nil
173
+
174
+ next if curr_ver.prerelease?
175
+ next unless prev_ver.nil? or curr_ver >= prev_ver or
176
+ latest[name].platform != Gem::Platform::RUBY
177
+
178
+ if prev_ver.nil? or
179
+ (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
180
+ result[name].clear
181
+ latest[name] = spec
182
+ end
183
+
184
+ if spec.platform != Gem::Platform::RUBY then
185
+ result[name].delete_if do |result_spec|
186
+ result_spec.platform == spec.platform
187
+ end
188
+ end
189
+
190
+ result[name] << spec
191
+ end
192
+
193
+ # TODO: why is this a hash while @gems is an array? Seems like
194
+ # structural similarity would be good.
195
+ result.values.flatten
196
+ end
197
+
198
+ ##
199
+ # An array including only the prerelease gemspecs
200
+
201
+ def prerelease_specs
202
+ prerelease_gems.values
203
+ end
204
+
205
+ ##
206
+ # An array including only the released gemspecs
207
+
208
+ def released_specs
209
+ released_gems.values
210
+ end
211
+
212
+ ##
213
+ # Add a gem specification to the source index.
214
+
215
+ def add_spec(gem_spec, name = gem_spec.full_name)
216
+ # No idea why, but the Indexer wants to insert them using original_name
217
+ # instead of full_name. So we make it an optional arg.
218
+ @gems[name] = gem_spec
219
+ end
220
+
221
+ ##
222
+ # Add gem specifications to the source index.
223
+
224
+ def add_specs(*gem_specs)
225
+ gem_specs.each do |spec|
226
+ add_spec spec
227
+ end
228
+ end
229
+
230
+ ##
231
+ # Remove a gem specification named +full_name+.
232
+
233
+ def remove_spec(full_name)
234
+ @gems.delete full_name
235
+ end
236
+
237
+ ##
238
+ # Iterate over the specifications in the source index.
239
+
240
+ def each(&block) # :yields: gem.full_name, gem
241
+ @gems.each(&block)
242
+ end
243
+
244
+ ##
245
+ # The gem specification given a full gem spec name.
246
+
247
+ def specification(full_name)
248
+ @gems[full_name]
249
+ end
250
+
251
+ ##
252
+ # The signature for the source index. Changes in the signature indicate a
253
+ # change in the index.
254
+
255
+ def index_signature
256
+ require 'digest'
257
+
258
+ Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
259
+ end
260
+
261
+ ##
262
+ # The signature for the given gem specification.
263
+
264
+ def gem_signature(gem_full_name)
265
+ require 'digest'
266
+
267
+ Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
268
+ end
269
+
270
+ def size
271
+ @gems.size
272
+ end
273
+ alias length size
274
+
275
+ ##
276
+ # Find a gem by an exact match on the short name.
277
+
278
+ def find_name(gem_name, version_requirement = Gem::Requirement.default)
279
+ dep = Gem::Dependency.new gem_name, version_requirement
280
+ search dep
281
+ end
282
+
283
+ ##
284
+ # Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+
285
+ # is true, only gems matching Gem::Platform.local will be returned. An
286
+ # Array of matching Gem::Specification objects is returned.
287
+ #
288
+ # For backwards compatibility, a String or Regexp pattern may be passed as
289
+ # +gem_pattern+, and a Gem::Requirement for +platform_only+. This
290
+ # behavior is deprecated and will be removed.
291
+
292
+ def search(gem_pattern, platform_only = false)
293
+ version_requirement = nil
294
+ only_platform = false
295
+
296
+ # TODO - Remove support and warning for legacy arguments after 2008/11
297
+ unless Gem::Dependency === gem_pattern
298
+ warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name"
299
+ end
300
+
301
+ case gem_pattern
302
+ when Regexp then
303
+ version_requirement = platform_only || Gem::Requirement.default
304
+ when Gem::Dependency then
305
+ only_platform = platform_only
306
+ version_requirement = gem_pattern.requirement
307
+ gem_pattern = if Regexp === gem_pattern.name then
308
+ gem_pattern.name
309
+ elsif gem_pattern.name.empty? then
310
+ //
311
+ else
312
+ /^#{Regexp.escape gem_pattern.name}$/
313
+ end
314
+ else
315
+ version_requirement = platform_only || Gem::Requirement.default
316
+ gem_pattern = /#{gem_pattern}/i
317
+ end
318
+
319
+ unless Gem::Requirement === version_requirement then
320
+ version_requirement = Gem::Requirement.create version_requirement
321
+ end
322
+
323
+ specs = all_gems.values.select do |spec|
324
+ spec.name =~ gem_pattern and
325
+ version_requirement.satisfied_by? spec.version
326
+ end
327
+
328
+ if only_platform then
329
+ specs = specs.select do |spec|
330
+ Gem::Platform.match spec.platform
331
+ end
332
+ end
333
+
334
+ specs.sort_by { |s| s.sort_obj }
335
+ end
336
+
337
+ ##
338
+ # Replaces the gems in the source index from specifications in the
339
+ # directories this source index was created from. Raises an exception if
340
+ # this source index wasn't created from a directory (via from_gems_in or
341
+ # from_installed_gems, or having spec_dirs set).
342
+
343
+ def refresh!
344
+ raise 'source index not created from disk' if @spec_dirs.nil?
345
+ load_gems_in(*@spec_dirs)
346
+ end
347
+
348
+ ##
349
+ # Returns an Array of Gem::Specifications that are not up to date.
350
+
351
+ def outdated
352
+ outdateds = []
353
+
354
+ latest_specs.each do |local|
355
+ dependency = Gem::Dependency.new local.name, ">= #{local.version}"
356
+
357
+ begin
358
+ fetcher = Gem::SpecFetcher.fetcher
359
+ remotes = fetcher.find_matching dependency
360
+ remotes = remotes.map { |(name, version,_),_| version }
361
+ rescue Gem::RemoteFetcher::FetchError => e
362
+ raise unless fetcher.warn_legacy e do
363
+ require 'rubygems/source_info_cache'
364
+
365
+ specs = Gem::SourceInfoCache.search_with_source dependency, true
366
+
367
+ remotes = specs.map { |spec,| spec.version }
368
+ end
369
+ end
370
+
371
+ latest = remotes.sort.last
372
+
373
+ outdateds << local.name if latest and local.version < latest
374
+ end
375
+
376
+ outdateds
377
+ end
378
+
379
+ ##
380
+ # Updates this SourceIndex from +source_uri+. If +all+ is false, only the
381
+ # latest gems are fetched.
382
+
383
+ def update(source_uri, all)
384
+ source_uri = URI.parse source_uri unless URI::Generic === source_uri
385
+ source_uri.path += '/' unless source_uri.path =~ /\/$/
386
+
387
+ use_incremental = false
388
+
389
+ begin
390
+ gem_names = fetch_quick_index source_uri, all
391
+ remove_extra gem_names
392
+ missing_gems = find_missing gem_names
393
+
394
+ return false if missing_gems.size.zero?
395
+
396
+ say "Missing metadata for #{missing_gems.size} gems" if
397
+ missing_gems.size > 0 and Gem.configuration.really_verbose
398
+
399
+ use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
400
+ rescue Gem::OperationNotSupportedError => ex
401
+ alert_error "Falling back to bulk fetch: #{ex.message}" if
402
+ Gem.configuration.really_verbose
403
+ use_incremental = false
404
+ end
405
+
406
+ if use_incremental then
407
+ update_with_missing(source_uri, missing_gems)
408
+ else
409
+ new_index = fetch_bulk_index(source_uri)
410
+ @gems.replace(new_index.gems)
411
+ end
412
+
413
+ true
414
+ end
415
+
416
+ def ==(other) # :nodoc:
417
+ self.class === other and @gems == other.gems
418
+ end
419
+
420
+ def dump
421
+ Marshal.dump(self)
422
+ end
423
+
424
+ private
425
+
426
+ def fetcher
427
+ require 'rubygems/remote_fetcher'
428
+
429
+ Gem::RemoteFetcher.fetcher
430
+ end
431
+
432
+ def fetch_index_from(source_uri)
433
+ @fetch_error = nil
434
+
435
+ indexes = %W[
436
+ Marshal.#{Gem.marshal_version}.Z
437
+ Marshal.#{Gem.marshal_version}
438
+ yaml.Z
439
+ yaml
440
+ ]
441
+
442
+ indexes.each do |name|
443
+ spec_data = nil
444
+ index = source_uri + name
445
+ begin
446
+ spec_data = fetcher.fetch_path index
447
+ spec_data = unzip(spec_data) if name =~ /\.Z$/
448
+
449
+ if name =~ /Marshal/ then
450
+ return Marshal.load(spec_data)
451
+ else
452
+ return YAML.load(spec_data)
453
+ end
454
+ rescue => e
455
+ if Gem.configuration.really_verbose then
456
+ alert_error "Unable to fetch #{name}: #{e.message}"
457
+ end
458
+
459
+ @fetch_error = e
460
+ end
461
+ end
462
+
463
+ nil
464
+ end
465
+
466
+ def fetch_bulk_index(source_uri)
467
+ say "Bulk updating Gem source index for: #{source_uri}" if
468
+ Gem.configuration.verbose
469
+
470
+ index = fetch_index_from(source_uri)
471
+ if index.nil? then
472
+ raise Gem::RemoteSourceException,
473
+ "Error fetching remote gem cache: #{@fetch_error}"
474
+ end
475
+ @fetch_error = nil
476
+ index
477
+ end
478
+
479
+ ##
480
+ # Get the quick index needed for incremental updates.
481
+
482
+ def fetch_quick_index(source_uri, all)
483
+ index = all ? 'index' : 'latest_index'
484
+
485
+ zipped_index = fetcher.fetch_path source_uri + "quick/#{index}.rz"
486
+
487
+ unzip(zipped_index).split("\n")
488
+ rescue ::Exception => e
489
+ unless all then
490
+ say "Latest index not found, using quick index" if
491
+ Gem.configuration.really_verbose
492
+
493
+ fetch_quick_index source_uri, true
494
+ else
495
+ raise Gem::OperationNotSupportedError,
496
+ "No quick index found: #{e.message}"
497
+ end
498
+ end
499
+
500
+ ##
501
+ # Make a list of full names for all the missing gemspecs.
502
+
503
+ def find_missing(spec_names)
504
+ unless defined? @originals then
505
+ @originals = {}
506
+ each do |full_name, spec|
507
+ @originals[spec.original_name] = spec
508
+ end
509
+ end
510
+
511
+ spec_names.find_all { |full_name|
512
+ @originals[full_name].nil?
513
+ }
514
+ end
515
+
516
+ def remove_extra(spec_names)
517
+ dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
518
+ each do |name, spec|
519
+ remove_spec name unless dictionary.include? spec.original_name
520
+ end
521
+ end
522
+
523
+ ##
524
+ # Unzip the given string.
525
+
526
+ def unzip(string)
527
+ require 'zlib'
528
+ Gem.inflate string
529
+ end
530
+
531
+ ##
532
+ # Tries to fetch Marshal representation first, then YAML
533
+
534
+ def fetch_single_spec(source_uri, spec_name)
535
+ @fetch_error = nil
536
+
537
+ begin
538
+ marshal_uri = source_uri + "quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
539
+ zipped = fetcher.fetch_path marshal_uri
540
+ return Marshal.load(unzip(zipped))
541
+ rescue => ex
542
+ @fetch_error = ex
543
+
544
+ if Gem.configuration.really_verbose then
545
+ say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
546
+ end
547
+ end
548
+
549
+ begin
550
+ yaml_uri = source_uri + "quick/#{spec_name}.gemspec.rz"
551
+ zipped = fetcher.fetch_path yaml_uri
552
+ return YAML.load(unzip(zipped))
553
+ rescue => ex
554
+ @fetch_error = ex
555
+ if Gem.configuration.really_verbose then
556
+ say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
557
+ end
558
+ end
559
+
560
+ nil
561
+ end
562
+
563
+ ##
564
+ # Update the cached source index with the missing names.
565
+
566
+ def update_with_missing(source_uri, missing_names)
567
+ progress = ui.progress_reporter(missing_names.size,
568
+ "Updating metadata for #{missing_names.size} gems from #{source_uri}")
569
+ missing_names.each do |spec_name|
570
+ gemspec = fetch_single_spec(source_uri, spec_name)
571
+ if gemspec.nil? then
572
+ ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
573
+ "\t#{@fetch_error.message}"
574
+ else
575
+ add_spec gemspec
576
+ progress.updated spec_name
577
+ end
578
+ @fetch_error = nil
579
+ end
580
+ progress.done
581
+ progress.count
582
+ end
583
+
584
+ end
585
+
586
+ # :stopdoc:
587
+ module Gem
588
+
589
+ ##
590
+ # Cache is an alias for SourceIndex to allow older YAMLized source index
591
+ # objects to load properly.
592
+
593
+ Cache = SourceIndex
594
+
595
+ end
596
+ # :startdoc:
597
+