rubygems-update 1.0.1 → 1.1.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.
- data.tar.gz.sig +0 -0
- data/ChangeLog +248 -0
- data/README +2 -0
- data/Rakefile +47 -23
- data/bin/gem +9 -4
- data/bin/update_rubygems +15 -1
- data/examples/application/bin/myapp +0 -0
- data/lib/rubygems.rb +506 -373
- data/lib/rubygems/builder.rb +14 -7
- data/lib/rubygems/command.rb +9 -9
- data/lib/rubygems/command_manager.rb +1 -0
- data/lib/rubygems/commands/cleanup_command.rb +67 -69
- data/lib/rubygems/commands/environment_command.rb +16 -10
- data/lib/rubygems/commands/fetch_command.rb +7 -9
- data/lib/rubygems/commands/install_command.rb +9 -3
- data/lib/rubygems/commands/list_command.rb +2 -4
- data/lib/rubygems/commands/mirror_command.rb +1 -1
- data/lib/rubygems/commands/query_command.rb +52 -5
- data/lib/rubygems/commands/sources_command.rb +19 -10
- data/lib/rubygems/commands/specification_command.rb +10 -6
- data/lib/rubygems/commands/uninstall_command.rb +23 -6
- data/lib/rubygems/commands/unpack_command.rb +15 -3
- data/lib/rubygems/commands/update_command.rb +27 -25
- data/lib/rubygems/custom_require.rb +1 -1
- data/lib/rubygems/defaults.rb +8 -1
- data/lib/rubygems/dependency_installer.rb +72 -104
- data/lib/rubygems/digest/digest_adapter.rb +0 -0
- data/lib/rubygems/digest/md5.rb +0 -0
- data/lib/rubygems/digest/sha1.rb +0 -0
- data/lib/rubygems/digest/sha2.rb +0 -0
- data/lib/rubygems/exceptions.rb +22 -1
- data/lib/rubygems/format.rb +16 -10
- data/lib/rubygems/indexer.rb +46 -33
- data/lib/rubygems/indexer/abstract_index_builder.rb +10 -2
- data/lib/rubygems/indexer/latest_index_builder.rb +35 -0
- data/lib/rubygems/indexer/master_index_builder.rb +9 -8
- data/lib/rubygems/indexer/quick_index_builder.rb +5 -3
- data/lib/rubygems/install_update_options.rb +7 -1
- data/lib/rubygems/installer.rb +8 -5
- data/lib/rubygems/package.rb +17 -774
- data/lib/rubygems/package/f_sync_dir.rb +24 -0
- data/lib/rubygems/package/tar_header.rb +245 -0
- data/lib/rubygems/package/tar_input.rb +219 -0
- data/lib/rubygems/package/tar_output.rb +143 -0
- data/lib/rubygems/package/tar_reader.rb +86 -0
- data/lib/rubygems/package/tar_reader/entry.rb +99 -0
- data/lib/rubygems/package/tar_writer.rb +180 -0
- data/lib/rubygems/remote_fetcher.rb +131 -16
- data/lib/rubygems/requirement.rb +2 -0
- data/lib/rubygems/rubygems_version.rb +1 -1
- data/lib/rubygems/security.rb +1 -0
- data/lib/rubygems/server.rb +85 -104
- data/lib/rubygems/source_index.rb +412 -329
- data/lib/rubygems/source_info_cache.rb +232 -99
- data/lib/rubygems/source_info_cache_entry.rb +14 -4
- data/lib/rubygems/specification.rb +9 -10
- data/lib/rubygems/timer.rb +0 -0
- data/lib/rubygems/uninstaller.rb +56 -32
- data/lib/rubygems/user_interaction.rb +4 -10
- data/lib/rubygems/validator.rb +0 -0
- data/scripts/gemdoc.rb +0 -0
- data/scripts/specdoc.rb +0 -0
- data/setup.rb +56 -19
- data/test/gem_installer_test_case.rb +86 -0
- data/test/gem_installer_test_case.rbc +0 -0
- data/test/gem_package_tar_test_case.rb +146 -0
- data/test/gem_package_tar_test_case.rbc +0 -0
- data/test/gemutilities.rb +123 -38
- data/test/gemutilities.rbc +0 -0
- data/test/mockgemui.rb +5 -13
- data/test/mockgemui.rbc +0 -0
- data/test/private_key.pem +27 -0
- data/test/public_cert.pem +20 -0
- data/test/simple_gem.rbc +0 -0
- data/test/test_config.rbc +0 -0
- data/test/test_gem.rb +46 -4
- data/test/test_gem.rbc +0 -0
- data/test/test_gem_builder.rbc +0 -0
- data/test/test_gem_command.rbc +0 -0
- data/test/test_gem_command_manager.rb +4 -2
- data/test/test_gem_command_manager.rbc +0 -0
- data/test/test_gem_commands_build_command.rbc +0 -0
- data/test/test_gem_commands_cert_command.rb +5 -1
- data/test/test_gem_commands_cert_command.rbc +0 -0
- data/test/test_gem_commands_check_command.rbc +0 -0
- data/test/test_gem_commands_contents_command.rbc +0 -0
- data/test/test_gem_commands_dependency_command.rbc +0 -0
- data/test/test_gem_commands_environment_command.rb +17 -1
- data/test/test_gem_commands_environment_command.rbc +0 -0
- data/test/test_gem_commands_fetch_command.rb +6 -5
- data/test/test_gem_commands_fetch_command.rbc +0 -0
- data/test/test_gem_commands_generate_index_command.rbc +0 -0
- data/test/test_gem_commands_install_command.rb +36 -28
- data/test/test_gem_commands_install_command.rbc +0 -0
- data/test/test_gem_commands_mirror_command.rbc +0 -0
- data/test/test_gem_commands_pristine_command.rbc +0 -0
- data/test/test_gem_commands_query_command.rb +143 -19
- data/test/test_gem_commands_query_command.rbc +0 -0
- data/test/test_gem_commands_server_command.rb +1 -1
- data/test/test_gem_commands_server_command.rbc +0 -0
- data/test/test_gem_commands_sources_command.rb +67 -9
- data/test/test_gem_commands_sources_command.rbc +0 -0
- data/test/test_gem_commands_specification_command.rb +3 -2
- data/test/test_gem_commands_specification_command.rbc +0 -0
- data/test/test_gem_commands_unpack_command.rb +46 -4
- data/test/test_gem_commands_unpack_command.rbc +0 -0
- data/test/test_gem_commands_update_command.rb +174 -0
- data/test/test_gem_commands_update_command.rbc +0 -0
- data/test/test_gem_config_file.rbc +0 -0
- data/test/test_gem_dependency.rbc +0 -0
- data/test/test_gem_dependency_installer.rb +172 -187
- data/test/test_gem_dependency_installer.rbc +0 -0
- data/test/test_gem_dependency_list.rbc +0 -0
- data/test/test_gem_digest.rb +0 -0
- data/test/test_gem_digest.rbc +0 -0
- data/test/test_gem_doc_manager.rbc +0 -0
- data/test/test_gem_ext_configure_builder.rb +9 -6
- data/test/test_gem_ext_configure_builder.rbc +0 -0
- data/test/test_gem_ext_ext_conf_builder.rbc +0 -0
- data/test/test_gem_ext_rake_builder.rbc +0 -0
- data/test/test_gem_format.rb +1 -1
- data/test/test_gem_format.rbc +0 -0
- data/test/test_gem_gem_path_searcher.rbc +0 -0
- data/test/test_gem_gem_runner.rbc +0 -0
- data/test/test_gem_indexer.rb +7 -2
- data/test/test_gem_indexer.rbc +0 -0
- data/test/test_gem_install_update_options.rbc +0 -0
- data/test/test_gem_installer.rb +5 -84
- data/test/test_gem_installer.rbc +0 -0
- data/test/test_gem_local_remote_options.rbc +0 -0
- data/test/test_gem_outdated_command.rbc +0 -0
- data/test/test_gem_package_tar_header.rb +137 -0
- data/test/test_gem_package_tar_header.rbc +0 -0
- data/test/test_gem_package_tar_input.rb +119 -0
- data/test/test_gem_package_tar_input.rbc +0 -0
- data/test/test_gem_package_tar_output.rb +104 -0
- data/test/test_gem_package_tar_output.rbc +0 -0
- data/test/test_gem_package_tar_reader.rb +53 -0
- data/test/test_gem_package_tar_reader.rbc +0 -0
- data/test/test_gem_package_tar_reader_entry.rb +116 -0
- data/test/test_gem_package_tar_reader_entry.rbc +0 -0
- data/test/test_gem_package_tar_writer.rb +151 -0
- data/test/test_gem_package_tar_writer.rbc +0 -0
- data/test/test_gem_platform.rbc +0 -0
- data/test/test_gem_remote_fetcher.rb +189 -17
- data/test/test_gem_remote_fetcher.rbc +0 -0
- data/test/test_gem_requirement.rbc +0 -0
- data/test/test_gem_server.rb +13 -12
- data/test/test_gem_server.rbc +0 -0
- data/test/test_gem_source_index.rb +305 -56
- data/test/test_gem_source_index.rbc +0 -0
- data/test/test_gem_source_info_cache.rb +179 -53
- data/test/test_gem_source_info_cache.rbc +0 -0
- data/test/test_gem_source_info_cache_entry.rb +41 -10
- data/test/test_gem_source_info_cache_entry.rbc +0 -0
- data/test/test_gem_specification.rb +7 -7
- data/test/test_gem_specification.rbc +0 -0
- data/test/test_gem_stream_ui.rbc +0 -0
- data/test/test_gem_uninstaller.rb +43 -0
- data/test/test_gem_uninstaller.rbc +0 -0
- data/test/test_gem_validator.rbc +0 -0
- data/test/test_gem_version.rb +1 -1
- data/test/test_gem_version.rbc +0 -0
- data/test/test_gem_version_option.rbc +0 -0
- data/test/test_kernel.rb +1 -0
- data/test/test_kernel.rbc +0 -0
- metadata +85 -8
- metadata.gz.sig +0 -0
- data/lib/rubygems/gem_open_uri.rb +0 -7
- data/lib/rubygems/open-uri.rb +0 -773
- data/test/test_open_uri.rb +0 -13
- data/test/test_package.rb +0 -608
@@ -2,7 +2,6 @@ require 'net/http'
|
|
2
2
|
require 'uri'
|
3
3
|
|
4
4
|
require 'rubygems'
|
5
|
-
require 'rubygems/gem_open_uri'
|
6
5
|
|
7
6
|
##
|
8
7
|
# RemoteFetcher handles the details of fetching gems and gem information from
|
@@ -10,6 +9,8 @@ require 'rubygems/gem_open_uri'
|
|
10
9
|
|
11
10
|
class Gem::RemoteFetcher
|
12
11
|
|
12
|
+
include Gem::UserInteraction
|
13
|
+
|
13
14
|
class FetchError < Gem::Exception; end
|
14
15
|
|
15
16
|
@fetcher = nil
|
@@ -29,6 +30,10 @@ class Gem::RemoteFetcher
|
|
29
30
|
# HTTP_PROXY_PASS)
|
30
31
|
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
|
31
32
|
def initialize(proxy)
|
33
|
+
Socket.do_not_reverse_lookup = true
|
34
|
+
|
35
|
+
@connections = {}
|
36
|
+
@requests = Hash.new 0
|
32
37
|
@proxy_uri =
|
33
38
|
case proxy
|
34
39
|
when :no_proxy then nil
|
@@ -38,6 +43,65 @@ class Gem::RemoteFetcher
|
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
46
|
+
##
|
47
|
+
# Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
|
48
|
+
# already there. If the source_uri is local the gem cache dir copy is
|
49
|
+
# always replaced.
|
50
|
+
def download(spec, source_uri, install_dir = Gem.dir)
|
51
|
+
gem_file_name = "#{spec.full_name}.gem"
|
52
|
+
local_gem_path = File.join install_dir, 'cache', gem_file_name
|
53
|
+
|
54
|
+
Gem.ensure_gem_subdirectories install_dir
|
55
|
+
|
56
|
+
source_uri = URI.parse source_uri unless URI::Generic === source_uri
|
57
|
+
scheme = source_uri.scheme
|
58
|
+
|
59
|
+
# URI.parse gets confused by MS Windows paths with forward slashes.
|
60
|
+
scheme = nil if scheme =~ /^[a-z]$/i
|
61
|
+
|
62
|
+
case scheme
|
63
|
+
when 'http' then
|
64
|
+
unless File.exist? local_gem_path then
|
65
|
+
begin
|
66
|
+
say "Downloading gem #{gem_file_name}" if
|
67
|
+
Gem.configuration.really_verbose
|
68
|
+
|
69
|
+
remote_gem_path = source_uri + "gems/#{gem_file_name}"
|
70
|
+
|
71
|
+
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
|
72
|
+
rescue Gem::RemoteFetcher::FetchError
|
73
|
+
raise if spec.original_platform == spec.platform
|
74
|
+
|
75
|
+
alternate_name = "#{spec.original_name}.gem"
|
76
|
+
|
77
|
+
say "Failed, downloading gem #{alternate_name}" if
|
78
|
+
Gem.configuration.really_verbose
|
79
|
+
|
80
|
+
remote_gem_path = source_uri + "gems/#{alternate_name}"
|
81
|
+
|
82
|
+
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
|
83
|
+
end
|
84
|
+
|
85
|
+
File.open local_gem_path, 'wb' do |fp|
|
86
|
+
fp.write gem
|
87
|
+
end
|
88
|
+
end
|
89
|
+
when nil, 'file' then # TODO test for local overriding cache
|
90
|
+
begin
|
91
|
+
FileUtils.cp source_uri.to_s, local_gem_path
|
92
|
+
rescue Errno::EACCES
|
93
|
+
local_gem_path = source_uri.to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
say "Using local gem #{local_gem_path}" if
|
97
|
+
Gem.configuration.really_verbose
|
98
|
+
else
|
99
|
+
raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
|
100
|
+
end
|
101
|
+
|
102
|
+
local_gem_path
|
103
|
+
end
|
104
|
+
|
41
105
|
# Downloads +uri+.
|
42
106
|
def fetch_path(uri)
|
43
107
|
open_uri_or_path(uri) do |input|
|
@@ -47,9 +111,8 @@ class Gem::RemoteFetcher
|
|
47
111
|
raise FetchError, "timed out fetching #{uri}"
|
48
112
|
rescue IOError, SocketError, SystemCallError => e
|
49
113
|
raise FetchError, "#{e.class}: #{e} reading #{uri}"
|
50
|
-
rescue
|
51
|
-
|
52
|
-
message = "#{e.class}: #{e} reading #{uri}\n\t#{body}"
|
114
|
+
rescue => e
|
115
|
+
message = "#{e.class}: #{e} reading #{uri}"
|
53
116
|
raise FetchError, message
|
54
117
|
end
|
55
118
|
|
@@ -83,7 +146,8 @@ class Gem::RemoteFetcher
|
|
83
146
|
end
|
84
147
|
|
85
148
|
rescue SocketError, SystemCallError, Timeout::Error => e
|
86
|
-
raise FetchError,
|
149
|
+
raise Gem::RemoteFetcher::FetchError,
|
150
|
+
"#{e.message} (#{e.class})\n\tgetting size of #{uri}"
|
87
151
|
end
|
88
152
|
|
89
153
|
private
|
@@ -131,26 +195,77 @@ class Gem::RemoteFetcher
|
|
131
195
|
|
132
196
|
# Read the data from the (source based) URI, but if it is a file:// URI,
|
133
197
|
# read from the filesystem instead.
|
134
|
-
def open_uri_or_path(uri, &block)
|
198
|
+
def open_uri_or_path(uri, depth = 0, &block)
|
135
199
|
if file_uri?(uri)
|
136
200
|
open(get_file_uri_path(uri), &block)
|
137
201
|
else
|
138
|
-
|
139
|
-
|
140
|
-
|
202
|
+
uri = URI.parse uri unless URI::Generic === uri
|
203
|
+
net_http_args = [uri.host, uri.port]
|
204
|
+
|
205
|
+
if @proxy_uri then
|
206
|
+
net_http_args += [ @proxy_uri.host,
|
207
|
+
@proxy_uri.port,
|
208
|
+
@proxy_uri.user,
|
209
|
+
@proxy_uri.password
|
210
|
+
]
|
211
|
+
end
|
212
|
+
|
213
|
+
connection_id = net_http_args.join ':'
|
214
|
+
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
|
215
|
+
connection = @connections[connection_id]
|
141
216
|
|
142
|
-
if
|
143
|
-
|
144
|
-
|
217
|
+
if uri.scheme == 'https' && ! connection.started?
|
218
|
+
http_obj.use_ssl = true
|
219
|
+
http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
145
220
|
end
|
146
221
|
|
147
|
-
|
222
|
+
connection.start unless connection.started?
|
223
|
+
|
224
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
148
225
|
unless uri.nil? || uri.user.nil? || uri.user.empty? then
|
149
|
-
|
150
|
-
[unescape(uri.user), unescape(uri.password)]
|
226
|
+
request.basic_auth(uri.user, uri.password)
|
151
227
|
end
|
152
228
|
|
153
|
-
|
229
|
+
ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
|
230
|
+
ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
|
231
|
+
ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
|
232
|
+
ua << ")"
|
233
|
+
|
234
|
+
request.add_field 'User-Agent', ua
|
235
|
+
request.add_field 'Connection', 'keep-alive'
|
236
|
+
request.add_field 'Keep-Alive', '30'
|
237
|
+
|
238
|
+
# HACK work around EOFError bug in Net::HTTP
|
239
|
+
retried = false
|
240
|
+
begin
|
241
|
+
@requests[connection_id] += 1
|
242
|
+
response = connection.request(request)
|
243
|
+
rescue EOFError
|
244
|
+
requests = @requests[connection_id]
|
245
|
+
say "connection reset after #{requests} requests, retrying" if
|
246
|
+
Gem.configuration.really_verbose
|
247
|
+
|
248
|
+
raise Gem::RemoteFetcher::FetchError, 'too many connection resets' if
|
249
|
+
retried
|
250
|
+
|
251
|
+
@requests[connection_id] = 0
|
252
|
+
|
253
|
+
connection.finish
|
254
|
+
connection.start
|
255
|
+
retried = true
|
256
|
+
retry
|
257
|
+
end
|
258
|
+
|
259
|
+
case response
|
260
|
+
when Net::HTTPOK then
|
261
|
+
block.call(StringIO.new(response.body)) if block
|
262
|
+
when Net::HTTPRedirection then
|
263
|
+
raise Gem::RemoteFetcher::FetchError, "too many redirects" if depth > 10
|
264
|
+
open_uri_or_path(response['Location'], depth + 1, &block)
|
265
|
+
else
|
266
|
+
raise Gem::RemoteFetcher::FetchError,
|
267
|
+
"bad response #{response.message} #{response.code}"
|
268
|
+
end
|
154
269
|
end
|
155
270
|
end
|
156
271
|
|
data/lib/rubygems/requirement.rb
CHANGED
data/lib/rubygems/security.rb
CHANGED
data/lib/rubygems/server.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'webrick'
|
2
|
-
require 'rdoc/template'
|
3
2
|
require 'yaml'
|
4
3
|
require 'zlib'
|
4
|
+
require 'erb'
|
5
5
|
|
6
6
|
require 'rubygems'
|
7
7
|
|
@@ -27,107 +27,87 @@ class Gem::Server
|
|
27
27
|
|
28
28
|
include Gem::UserInteraction
|
29
29
|
|
30
|
-
DOC_TEMPLATE = <<-WEBPAGE
|
31
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
32
|
-
<!DOCTYPE html
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
37
|
-
<head>
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
</head>
|
42
|
-
<body>
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
<div id="bodyContent">
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
<p>There are
|
53
|
-
<p>
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
<
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
<
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
</
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
Executables are
|
106
|
-
ENDIF:only_one_executable
|
107
|
-
|
108
|
-
START:executables
|
109
|
-
IFNOT:is_last
|
110
|
-
<span class="context-item-name">%executable%</span>,
|
111
|
-
ENDIF:is_last
|
112
|
-
IF:is_last
|
113
|
-
<span class="context-item-name">%executable%</span>.
|
114
|
-
ENDIF:is_last
|
115
|
-
END:executables
|
116
|
-
ENDIF:executables
|
117
|
-
<br/>
|
118
|
-
<br/>
|
119
|
-
</dd>
|
120
|
-
END:specs
|
121
|
-
</dl>
|
122
|
-
|
30
|
+
DOC_TEMPLATE = <<-'WEBPAGE'
|
31
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
32
|
+
<!DOCTYPE html
|
33
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
34
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
35
|
+
|
36
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
37
|
+
<head>
|
38
|
+
<title>RubyGems Documentation Index</title>
|
39
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
40
|
+
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
41
|
+
</head>
|
42
|
+
<body>
|
43
|
+
<div id="fileHeader">
|
44
|
+
<h1>RubyGems Documentation Index</h1>
|
45
|
+
</div>
|
46
|
+
<!-- banner header -->
|
47
|
+
|
48
|
+
<div id="bodyContent">
|
49
|
+
<div id="contextContent">
|
50
|
+
<div id="description">
|
51
|
+
<h1>Summary</h1>
|
52
|
+
<p>There are <%=values["gem_count"]%> gems installed:</p>
|
53
|
+
<p>
|
54
|
+
<%= values["specs"].map { |v| "<a href=\"#{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
|
55
|
+
<h1>Gems</h1>
|
56
|
+
|
57
|
+
<dl>
|
58
|
+
<% values["specs"].each do |spec| %>
|
59
|
+
<dt>
|
60
|
+
<% if spec["first_name_entry"] then %>
|
61
|
+
<a name="<%=spec["name"]%>"></a>
|
62
|
+
<% end %>
|
63
|
+
|
64
|
+
<b><%=spec["name"]%> <%=spec["version"]%></b>
|
65
|
+
|
66
|
+
<% if spec["rdoc_installed"] then %>
|
67
|
+
<a href="<%=spec["doc_path"]%>">[rdoc]</a>
|
68
|
+
<% else %>
|
69
|
+
<span title="rdoc not installed">[rdoc]</span>
|
70
|
+
<% end %>
|
71
|
+
|
72
|
+
<% if spec["homepage"] then %>
|
73
|
+
<a href="<%=spec["homepage"]%>" title="<%=spec["homepage"]%>">[www]</a>
|
74
|
+
<% else %>
|
75
|
+
<span title="no homepage available">[www]</span>
|
76
|
+
<% end %>
|
77
|
+
|
78
|
+
<% if spec["has_deps"] then %>
|
79
|
+
- depends on
|
80
|
+
<%= spec["dependencies"].map { |v| "<a href=\"#{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
|
81
|
+
<% end %>
|
82
|
+
</dt>
|
83
|
+
<dd>
|
84
|
+
<%=spec["summary"]%>
|
85
|
+
<% if spec["executables"] then %>
|
86
|
+
<br/>
|
87
|
+
|
88
|
+
<% if spec["only_one_executable"] then %>
|
89
|
+
Executable is
|
90
|
+
<% else %>
|
91
|
+
Executables are
|
92
|
+
<%end%>
|
93
|
+
|
94
|
+
<%= spec["executables"].map { |v| "<span class=\"context-item-name\">#{v["executable"]}</span>"}.join ', ' %>.
|
95
|
+
|
96
|
+
<%end%>
|
97
|
+
<br/>
|
98
|
+
<br/>
|
99
|
+
</dd>
|
100
|
+
<% end %>
|
101
|
+
</dl>
|
102
|
+
|
103
|
+
</div>
|
104
|
+
</div>
|
123
105
|
</div>
|
124
|
-
|
106
|
+
<div id="validator-badges">
|
107
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
125
108
|
</div>
|
126
|
-
|
127
|
-
|
128
|
-
</div>
|
129
|
-
</body>
|
130
|
-
</html>
|
109
|
+
</body>
|
110
|
+
</html>
|
131
111
|
WEBPAGE
|
132
112
|
|
133
113
|
# CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
|
@@ -496,11 +476,12 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|
496
476
|
end
|
497
477
|
|
498
478
|
# create page from template
|
499
|
-
template =
|
479
|
+
template = ERB.new(DOC_TEMPLATE)
|
500
480
|
res['content-type'] = 'text/html'
|
501
|
-
|
502
|
-
"
|
503
|
-
|
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
|
504
485
|
end
|
505
486
|
|
506
487
|
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
|
@@ -8,436 +8,519 @@ require 'rubygems'
|
|
8
8
|
require 'rubygems/user_interaction'
|
9
9
|
require 'rubygems/specification'
|
10
10
|
|
11
|
-
|
11
|
+
##
|
12
|
+
# The SourceIndex object indexes all the gems available from a
|
13
|
+
# particular source (e.g. a list of gem directories, or a remote
|
14
|
+
# source). A SourceIndex maps a gem full name to a gem
|
15
|
+
# specification.
|
16
|
+
#
|
17
|
+
# NOTE:: The class used to be named Cache, but that became
|
18
|
+
# confusing when cached source fetchers where introduced. The
|
19
|
+
# constant Gem::Cache is an alias for this class to allow old
|
20
|
+
# YAMLized source index objects to load properly.
|
12
21
|
|
13
|
-
|
14
|
-
# particular source (e.g. a list of gem directories, or a remote
|
15
|
-
# source). A SourceIndex maps a gem full name to a gem
|
16
|
-
# specification.
|
17
|
-
#
|
18
|
-
# NOTE:: The class used to be named Cache, but that became
|
19
|
-
# confusing when cached source fetchers where introduced. The
|
20
|
-
# constant Gem::Cache is an alias for this class to allow old
|
21
|
-
# YAMLized source index objects to load properly.
|
22
|
-
#
|
23
|
-
class SourceIndex
|
22
|
+
class Gem::SourceIndex
|
24
23
|
|
25
|
-
|
24
|
+
include Enumerable
|
26
25
|
|
26
|
+
include Gem::UserInteraction
|
27
|
+
|
28
|
+
class << self
|
27
29
|
include Gem::UserInteraction
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
from_gems_in(*installed_spec_directories)
|
48
|
-
else
|
49
|
-
from_gems_in(*deprecated)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Return a list of directories in the current gem path that
|
54
|
-
# contain specifications.
|
55
|
-
#
|
56
|
-
# return::
|
57
|
-
# List of directory paths (all ending in "../specifications").
|
58
|
-
#
|
59
|
-
def installed_spec_directories
|
60
|
-
Gem.path.collect { |dir| File.join(dir, "specifications") }
|
31
|
+
##
|
32
|
+
# Factory method to construct a source index instance for a given
|
33
|
+
# path.
|
34
|
+
#
|
35
|
+
# deprecated::
|
36
|
+
# If supplied, from_installed_gems will act just like
|
37
|
+
# +from_gems_in+. This argument is deprecated and is provided
|
38
|
+
# just for backwards compatibility, and should not generally
|
39
|
+
# be used.
|
40
|
+
#
|
41
|
+
# return::
|
42
|
+
# SourceIndex instance
|
43
|
+
|
44
|
+
def from_installed_gems(*deprecated)
|
45
|
+
if deprecated.empty?
|
46
|
+
from_gems_in(*installed_spec_directories)
|
47
|
+
else
|
48
|
+
from_gems_in(*deprecated) # HACK warn
|
61
49
|
end
|
50
|
+
end
|
62
51
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
alert_warning e
|
94
|
-
alert_warning spec_code
|
95
|
-
rescue Exception => e
|
96
|
-
alert_warning(e.inspect.to_s + "\n" + spec_code)
|
97
|
-
alert_warning "Invalid .gemspec format in '#{file_name}'"
|
52
|
+
##
|
53
|
+
# Return a list of directories in the current gem path that
|
54
|
+
# contain specifications.
|
55
|
+
#
|
56
|
+
# return::
|
57
|
+
# List of directory paths (all ending in "../specifications").
|
58
|
+
|
59
|
+
def installed_spec_directories
|
60
|
+
Gem.path.collect { |dir| File.join(dir, "specifications") }
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Creates a new SourceIndex from the ruby format gem specifications in
|
65
|
+
# +spec_dirs+.
|
66
|
+
|
67
|
+
def from_gems_in(*spec_dirs)
|
68
|
+
self.new.load_gems_in(*spec_dirs)
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Loads a ruby-format specification from +file_name+ and returns the
|
73
|
+
# loaded spec.
|
74
|
+
|
75
|
+
def load_specification(file_name)
|
76
|
+
begin
|
77
|
+
spec_code = File.read(file_name).untaint
|
78
|
+
gemspec = eval spec_code, binding, file_name
|
79
|
+
if gemspec.is_a?(Gem::Specification)
|
80
|
+
gemspec.loaded_from = file_name
|
81
|
+
return gemspec
|
98
82
|
end
|
99
|
-
|
83
|
+
alert_warning "File '#{file_name}' does not evaluate to a gem specification"
|
84
|
+
rescue SyntaxError => e
|
85
|
+
alert_warning e
|
86
|
+
alert_warning spec_code
|
87
|
+
rescue Exception => e
|
88
|
+
alert_warning(e.inspect.to_s + "\n" + spec_code)
|
89
|
+
alert_warning "Invalid .gemspec format in '#{file_name}'"
|
100
90
|
end
|
101
|
-
|
91
|
+
return nil
|
102
92
|
end
|
103
93
|
|
104
|
-
|
94
|
+
end
|
105
95
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
96
|
+
##
|
97
|
+
# Constructs a source index instance from the provided
|
98
|
+
# specifications
|
99
|
+
#
|
100
|
+
# specifications::
|
101
|
+
# [Hash] hash of [Gem name, Gem::Specification] pairs
|
102
|
+
|
103
|
+
def initialize(specifications={})
|
104
|
+
@gems = specifications
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Reconstruct the source index from the specifications in +spec_dirs+.
|
109
|
+
|
110
|
+
def load_gems_in(*spec_dirs)
|
111
|
+
@gems.clear
|
112
|
+
|
113
|
+
spec_dirs.reverse_each do |spec_dir|
|
114
|
+
spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
|
115
|
+
|
116
|
+
spec_files.each do |spec_file|
|
117
|
+
gemspec = self.class.load_specification spec_file.untaint
|
118
|
+
add_spec gemspec if gemspec
|
124
119
|
end
|
125
|
-
self
|
126
120
|
end
|
127
121
|
|
128
|
-
|
129
|
-
|
130
|
-
def latest_specs
|
131
|
-
result, latest = Hash.new { |h,k| h[k] = [] }, {}
|
122
|
+
self
|
123
|
+
end
|
132
124
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
prev_ver = latest[name]
|
125
|
+
##
|
126
|
+
# Returns a Hash of name => Specification of the latest versions of each
|
127
|
+
# gem in this index.
|
137
128
|
|
138
|
-
|
129
|
+
def latest_specs
|
130
|
+
result = Hash.new { |h,k| h[k] = [] }
|
131
|
+
latest = {}
|
139
132
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
133
|
+
sort.each do |_, spec|
|
134
|
+
name = spec.name
|
135
|
+
curr_ver = spec.version
|
136
|
+
prev_ver = latest.key?(name) ? latest[name].version : nil
|
137
|
+
|
138
|
+
next unless prev_ver.nil? or curr_ver >= prev_ver or
|
139
|
+
latest[name].platform != Gem::Platform::RUBY
|
144
140
|
|
145
|
-
|
141
|
+
if prev_ver.nil? or
|
142
|
+
(curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
|
143
|
+
result[name].clear
|
144
|
+
latest[name] = spec
|
146
145
|
end
|
147
146
|
|
148
|
-
|
149
|
-
|
147
|
+
if spec.platform != Gem::Platform::RUBY then
|
148
|
+
result[name].delete_if do |result_spec|
|
149
|
+
result_spec.platform == spec.platform
|
150
|
+
end
|
151
|
+
end
|
150
152
|
|
151
|
-
|
152
|
-
def add_spec(gem_spec)
|
153
|
-
@gems[gem_spec.full_name] = gem_spec
|
153
|
+
result[name] << spec
|
154
154
|
end
|
155
155
|
|
156
|
-
|
157
|
-
|
158
|
-
@gems.delete(full_name)
|
159
|
-
end
|
156
|
+
result.values.flatten
|
157
|
+
end
|
160
158
|
|
161
|
-
|
162
|
-
|
163
|
-
@gems.each(&block)
|
164
|
-
end
|
159
|
+
##
|
160
|
+
# Add a gem specification to the source index.
|
165
161
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
162
|
+
def add_spec(gem_spec)
|
163
|
+
@gems[gem_spec.full_name] = gem_spec
|
164
|
+
end
|
170
165
|
|
171
|
-
|
172
|
-
|
173
|
-
def index_signature
|
174
|
-
require 'rubygems/digest/sha2'
|
166
|
+
##
|
167
|
+
# Add gem specifications to the source index.
|
175
168
|
|
176
|
-
|
169
|
+
def add_specs(*gem_specs)
|
170
|
+
gem_specs.each do |spec|
|
171
|
+
add_spec spec
|
177
172
|
end
|
173
|
+
end
|
178
174
|
|
179
|
-
|
180
|
-
|
181
|
-
require 'rubygems/digest/sha2'
|
175
|
+
##
|
176
|
+
# Remove a gem specification named +full_name+.
|
182
177
|
|
183
|
-
|
184
|
-
|
178
|
+
def remove_spec(full_name)
|
179
|
+
@gems.delete(full_name)
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Iterate over the specifications in the source index.
|
184
|
+
|
185
|
+
def each(&block) # :yields: gem.full_name, gem
|
186
|
+
@gems.each(&block)
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# The gem specification given a full gem spec name.
|
191
|
+
|
192
|
+
def specification(full_name)
|
193
|
+
@gems[full_name]
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# The signature for the source index. Changes in the signature indicate a
|
198
|
+
# change in the index.
|
199
|
+
|
200
|
+
def index_signature
|
201
|
+
require 'rubygems/digest/sha2'
|
202
|
+
|
203
|
+
Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
|
204
|
+
end
|
205
|
+
|
206
|
+
##
|
207
|
+
# The signature for the given gem specification.
|
185
208
|
|
186
|
-
|
187
|
-
|
209
|
+
def gem_signature(gem_full_name)
|
210
|
+
require 'rubygems/digest/sha2'
|
211
|
+
|
212
|
+
Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
|
213
|
+
end
|
214
|
+
|
215
|
+
def size
|
216
|
+
@gems.size
|
217
|
+
end
|
218
|
+
alias length size
|
219
|
+
|
220
|
+
##
|
221
|
+
# Find a gem by an exact match on the short name.
|
222
|
+
|
223
|
+
def find_name(gem_name, version_requirement = Gem::Requirement.default)
|
224
|
+
search(/^#{gem_name}$/, version_requirement)
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+
|
229
|
+
# is true, only gems matching Gem::Platform.local will be returned. An
|
230
|
+
# Array of matching Gem::Specification objects is returned.
|
231
|
+
#
|
232
|
+
# For backwards compatibility, a String or Regexp pattern may be passed as
|
233
|
+
# +gem_pattern+, and a Gem::Requirement for +platform_only+. This
|
234
|
+
# behavior is deprecated and will be removed.
|
235
|
+
|
236
|
+
def search(gem_pattern, platform_only = false)
|
237
|
+
version_requirement = nil
|
238
|
+
only_platform = false
|
239
|
+
|
240
|
+
case gem_pattern # TODO warn after 2008/03, remove three months after
|
241
|
+
when Regexp then
|
242
|
+
version_requirement = platform_only || Gem::Requirement.default
|
243
|
+
when Gem::Dependency then
|
244
|
+
only_platform = platform_only
|
245
|
+
version_requirement = gem_pattern.version_requirements
|
246
|
+
gem_pattern = if gem_pattern.name.empty? then
|
247
|
+
//
|
248
|
+
else
|
249
|
+
/^#{Regexp.escape gem_pattern.name}$/
|
250
|
+
end
|
251
|
+
else
|
252
|
+
version_requirement = platform_only || Gem::Requirement.default
|
253
|
+
gem_pattern = /#{gem_pattern}/i
|
188
254
|
end
|
189
|
-
alias length size
|
190
255
|
|
191
|
-
|
192
|
-
|
193
|
-
search(/^#{gem_name}$/, version_requirement)
|
256
|
+
unless Gem::Requirement === version_requirement then
|
257
|
+
version_requirement = Gem::Requirement.create version_requirement
|
194
258
|
end
|
195
259
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
# For backwards compatibility, a String or Regexp pattern may be passed as
|
201
|
-
# +gem_pattern+, and a Gem::Requirement for +platform_only+. This
|
202
|
-
# behavior is deprecated and will be removed.
|
203
|
-
def search(gem_pattern, platform_only = false)
|
204
|
-
version_requirement = nil
|
205
|
-
only_platform = false
|
206
|
-
|
207
|
-
case gem_pattern # TODO warn after 2008/03, remove three months after
|
208
|
-
when Regexp then
|
209
|
-
version_requirement = platform_only || Gem::Requirement.default
|
210
|
-
when Gem::Dependency then
|
211
|
-
only_platform = platform_only
|
212
|
-
version_requirement = gem_pattern.version_requirements
|
213
|
-
gem_pattern = if gem_pattern.name.empty? then
|
214
|
-
//
|
215
|
-
else
|
216
|
-
/^#{Regexp.escape gem_pattern.name}$/
|
217
|
-
end
|
218
|
-
else
|
219
|
-
version_requirement = platform_only || Gem::Requirement.default
|
220
|
-
gem_pattern = /#{gem_pattern}/i
|
221
|
-
end
|
260
|
+
specs = @gems.values.select do |spec|
|
261
|
+
spec.name =~ gem_pattern and
|
262
|
+
version_requirement.satisfied_by? spec.version
|
263
|
+
end
|
222
264
|
|
223
|
-
|
224
|
-
|
265
|
+
if only_platform then
|
266
|
+
specs = specs.select do |spec|
|
267
|
+
Gem::Platform.match spec.platform
|
225
268
|
end
|
269
|
+
end
|
226
270
|
|
227
|
-
|
228
|
-
|
229
|
-
version_requirement.satisfied_by? spec.version
|
230
|
-
end
|
271
|
+
specs.sort_by { |s| s.sort_obj }
|
272
|
+
end
|
231
273
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
274
|
+
##
|
275
|
+
# Refresh the source index from the local file system.
|
276
|
+
#
|
277
|
+
# return:: Returns a pointer to itself.
|
237
278
|
|
238
|
-
|
239
|
-
|
279
|
+
def refresh!
|
280
|
+
load_gems_in(self.class.installed_spec_directories)
|
281
|
+
end
|
240
282
|
|
241
|
-
|
242
|
-
|
243
|
-
# return:: Returns a pointer to itself.
|
244
|
-
#
|
245
|
-
def refresh!
|
246
|
-
load_gems_in(self.class.installed_spec_directories)
|
247
|
-
end
|
283
|
+
##
|
284
|
+
# Returns an Array of Gem::Specifications that are not up to date.
|
248
285
|
|
249
|
-
|
250
|
-
|
251
|
-
def outdated
|
252
|
-
dep = Gem::Dependency.new '', Gem::Requirement.default
|
286
|
+
def outdated
|
287
|
+
dep = Gem::Dependency.new '', Gem::Requirement.default
|
253
288
|
|
254
|
-
|
289
|
+
remotes = Gem::SourceInfoCache.search dep, true
|
255
290
|
|
256
|
-
|
291
|
+
outdateds = []
|
257
292
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
outdateds << name if remote and local.version < remote.version
|
264
|
-
end
|
293
|
+
latest_specs.each do |local|
|
294
|
+
name = local.name
|
295
|
+
remote = remotes.select { |spec| spec.name == name }.
|
296
|
+
sort_by { |spec| spec.version.to_ints }.
|
297
|
+
last
|
265
298
|
|
266
|
-
outdateds
|
299
|
+
outdateds << name if remote and local.version < remote.version
|
267
300
|
end
|
268
301
|
|
269
|
-
|
270
|
-
|
302
|
+
outdateds
|
303
|
+
end
|
271
304
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
missing_gems = find_missing gem_names
|
305
|
+
##
|
306
|
+
# Updates this SourceIndex from +source_uri+. If +all+ is false, only the
|
307
|
+
# latest gems are fetched.
|
276
308
|
|
277
|
-
|
309
|
+
def update(source_uri, all)
|
310
|
+
source_uri = URI.parse source_uri unless URI::Generic === source_uri
|
311
|
+
source_uri.path += '/' unless source_uri.path =~ /\/$/
|
278
312
|
|
279
|
-
|
280
|
-
missing_gems.size > 0 and Gem.configuration.really_verbose
|
313
|
+
use_incremental = false
|
281
314
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
use_incremental = false
|
287
|
-
end
|
315
|
+
begin
|
316
|
+
gem_names = fetch_quick_index source_uri, all
|
317
|
+
remove_extra gem_names
|
318
|
+
missing_gems = find_missing gem_names
|
288
319
|
|
289
|
-
if
|
290
|
-
update_with_missing(source_uri, missing_gems)
|
291
|
-
else
|
292
|
-
new_index = fetch_bulk_index(source_uri)
|
293
|
-
@gems.replace(new_index.gems)
|
294
|
-
end
|
320
|
+
return false if missing_gems.size.zero?
|
295
321
|
|
296
|
-
|
297
|
-
|
322
|
+
say "Missing metadata for #{missing_gems.size} gems" if
|
323
|
+
missing_gems.size > 0 and Gem.configuration.really_verbose
|
298
324
|
|
299
|
-
|
300
|
-
|
325
|
+
use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
|
326
|
+
rescue Gem::OperationNotSupportedError => ex
|
327
|
+
alert_error "Falling back to bulk fetch: #{ex.message}" if
|
328
|
+
Gem.configuration.really_verbose
|
329
|
+
use_incremental = false
|
301
330
|
end
|
302
331
|
|
303
|
-
|
304
|
-
|
332
|
+
if use_incremental then
|
333
|
+
update_with_missing(source_uri, missing_gems)
|
334
|
+
else
|
335
|
+
new_index = fetch_bulk_index(source_uri)
|
336
|
+
@gems.replace(new_index.gems)
|
305
337
|
end
|
306
338
|
|
307
|
-
|
339
|
+
true
|
340
|
+
end
|
308
341
|
|
309
|
-
|
342
|
+
def ==(other) # :nodoc:
|
343
|
+
self.class === other and @gems == other.gems
|
344
|
+
end
|
310
345
|
|
311
|
-
|
346
|
+
def dump
|
347
|
+
Marshal.dump(self)
|
348
|
+
end
|
312
349
|
|
313
|
-
|
314
|
-
require 'rubygems/remote_fetcher'
|
350
|
+
protected
|
315
351
|
|
316
|
-
|
317
|
-
end
|
352
|
+
attr_reader :gems
|
318
353
|
|
319
|
-
|
320
|
-
|
354
|
+
private
|
355
|
+
|
356
|
+
def fetcher
|
357
|
+
require 'rubygems/remote_fetcher'
|
358
|
+
|
359
|
+
Gem::RemoteFetcher.fetcher
|
360
|
+
end
|
321
361
|
|
322
|
-
|
362
|
+
def fetch_index_from(source_uri)
|
363
|
+
@fetch_error = nil
|
364
|
+
|
365
|
+
indexes = %W[
|
323
366
|
Marshal.#{Gem.marshal_version}.Z
|
324
367
|
Marshal.#{Gem.marshal_version}
|
325
368
|
yaml.Z
|
326
369
|
yaml
|
327
370
|
]
|
328
371
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
if Gem.configuration.really_verbose then
|
341
|
-
alert_error "Unable to fetch #{name}: #{e.message}"
|
342
|
-
end
|
343
|
-
@fetch_error = e
|
372
|
+
indexes.each do |name|
|
373
|
+
spec_data = nil
|
374
|
+
index = source_uri + name
|
375
|
+
begin
|
376
|
+
spec_data = fetcher.fetch_path index
|
377
|
+
spec_data = unzip(spec_data) if name =~ /\.Z$/
|
378
|
+
|
379
|
+
if name =~ /Marshal/ then
|
380
|
+
return Marshal.load(spec_data)
|
381
|
+
else
|
382
|
+
return YAML.load(spec_data)
|
344
383
|
end
|
384
|
+
rescue => e
|
385
|
+
if Gem.configuration.really_verbose then
|
386
|
+
alert_error "Unable to fetch #{name}: #{e.message}"
|
387
|
+
end
|
388
|
+
|
389
|
+
@fetch_error = e
|
345
390
|
end
|
346
|
-
nil
|
347
391
|
end
|
348
392
|
|
349
|
-
|
350
|
-
|
393
|
+
nil
|
394
|
+
end
|
395
|
+
|
396
|
+
def fetch_bulk_index(source_uri)
|
397
|
+
say "Bulk updating Gem source index for: #{source_uri}"
|
351
398
|
|
352
|
-
|
353
|
-
|
354
|
-
|
399
|
+
index = fetch_index_from(source_uri)
|
400
|
+
if index.nil? then
|
401
|
+
raise Gem::RemoteSourceException,
|
355
402
|
"Error fetching remote gem cache: #{@fetch_error}"
|
356
|
-
end
|
357
|
-
@fetch_error = nil
|
358
|
-
index
|
359
403
|
end
|
404
|
+
@fetch_error = nil
|
405
|
+
index
|
406
|
+
end
|
407
|
+
|
408
|
+
##
|
409
|
+
# Get the quick index needed for incremental updates.
|
360
410
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
411
|
+
def fetch_quick_index(source_uri, all)
|
412
|
+
index = all ? 'index' : 'latest_index'
|
413
|
+
|
414
|
+
zipped_index = fetcher.fetch_path source_uri + "quick/#{index}.rz"
|
415
|
+
|
416
|
+
unzip(zipped_index).split("\n")
|
417
|
+
rescue ::Exception => e
|
418
|
+
unless all then
|
419
|
+
say "Latest index not found, using quick index" if
|
420
|
+
Gem.configuration.really_verbose
|
421
|
+
|
422
|
+
fetch_quick_index source_uri, true
|
423
|
+
else
|
366
424
|
raise Gem::OperationNotSupportedError,
|
367
|
-
"No quick index found:
|
425
|
+
"No quick index found: #{e.message}"
|
368
426
|
end
|
427
|
+
end
|
369
428
|
|
370
|
-
|
371
|
-
|
372
|
-
spec_names.find_all { |full_name|
|
373
|
-
specification(full_name).nil?
|
374
|
-
}
|
375
|
-
end
|
429
|
+
##
|
430
|
+
# Make a list of full names for all the missing gemspecs.
|
376
431
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
432
|
+
def find_missing(spec_names)
|
433
|
+
unless defined? @originals then
|
434
|
+
@originals = {}
|
435
|
+
each do |full_name, spec|
|
436
|
+
@originals[spec.original_name] = spec
|
381
437
|
end
|
382
438
|
end
|
383
439
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
440
|
+
spec_names.find_all { |full_name|
|
441
|
+
@originals[full_name].nil?
|
442
|
+
}
|
443
|
+
end
|
444
|
+
|
445
|
+
def remove_extra(spec_names)
|
446
|
+
dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
|
447
|
+
each do |name, spec|
|
448
|
+
remove_spec name unless dictionary.include? spec.original_name
|
388
449
|
end
|
450
|
+
end
|
389
451
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
452
|
+
##
|
453
|
+
# Unzip the given string.
|
454
|
+
|
455
|
+
def unzip(string)
|
456
|
+
require 'zlib'
|
457
|
+
Zlib::Inflate.inflate(string)
|
458
|
+
end
|
459
|
+
|
460
|
+
##
|
461
|
+
# Tries to fetch Marshal representation first, then YAML
|
462
|
+
|
463
|
+
def fetch_single_spec(source_uri, spec_name)
|
464
|
+
@fetch_error = nil
|
465
|
+
|
466
|
+
begin
|
467
|
+
marshal_uri = source_uri + "quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
|
468
|
+
zipped = fetcher.fetch_path marshal_uri
|
469
|
+
return Marshal.load(unzip(zipped))
|
470
|
+
rescue => ex
|
471
|
+
@fetch_error = ex
|
472
|
+
|
473
|
+
if Gem.configuration.really_verbose then
|
474
|
+
say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
|
402
475
|
end
|
476
|
+
end
|
403
477
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
end
|
478
|
+
begin
|
479
|
+
yaml_uri = source_uri + "quick/#{spec_name}.gemspec.rz"
|
480
|
+
zipped = fetcher.fetch_path yaml_uri
|
481
|
+
return YAML.load(unzip(zipped))
|
482
|
+
rescue => ex
|
483
|
+
@fetch_error = ex
|
484
|
+
if Gem.configuration.really_verbose then
|
485
|
+
say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
|
413
486
|
end
|
414
|
-
nil
|
415
487
|
end
|
416
488
|
|
417
|
-
|
418
|
-
|
419
|
-
|
489
|
+
nil
|
490
|
+
end
|
491
|
+
|
492
|
+
##
|
493
|
+
# Update the cached source index with the missing names.
|
494
|
+
|
495
|
+
def update_with_missing(source_uri, missing_names)
|
496
|
+
progress = ui.progress_reporter(missing_names.size,
|
420
497
|
"Updating metadata for #{missing_names.size} gems from #{source_uri}")
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
498
|
+
missing_names.each do |spec_name|
|
499
|
+
gemspec = fetch_single_spec(source_uri, spec_name)
|
500
|
+
if gemspec.nil? then
|
501
|
+
ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
|
425
502
|
"\t#{@fetch_error.message}"
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
end
|
430
|
-
@fetch_error = nil
|
503
|
+
else
|
504
|
+
add_spec gemspec
|
505
|
+
progress.updated spec_name
|
431
506
|
end
|
432
|
-
|
433
|
-
progress.count
|
507
|
+
@fetch_error = nil
|
434
508
|
end
|
435
|
-
|
509
|
+
progress.done
|
510
|
+
progress.count
|
436
511
|
end
|
437
512
|
|
438
|
-
|
439
|
-
|
513
|
+
end
|
514
|
+
|
515
|
+
module Gem
|
516
|
+
|
517
|
+
# :stopdoc:
|
518
|
+
|
519
|
+
# Cache is an alias for SourceIndex to allow older YAMLized source index
|
520
|
+
# objects to load properly.
|
440
521
|
Cache = SourceIndex
|
441
522
|
|
523
|
+
# :starddoc:
|
524
|
+
|
442
525
|
end
|
443
526
|
|