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.
- data.tar.gz.sig +0 -0
- data/ChangeLog +267 -1
- data/Rakefile +13 -7
- data/doc/release_notes/rel_1_2_0.rdoc +105 -0
- data/lib/rubygems.rb +82 -14
- data/lib/rubygems/command.rb +1 -1
- data/lib/rubygems/command_manager.rb +3 -2
- data/lib/rubygems/commands/cert_command.rb +1 -1
- data/lib/rubygems/commands/dependency_command.rb +57 -19
- data/lib/rubygems/commands/environment_command.rb +2 -0
- data/lib/rubygems/commands/fetch_command.rb +3 -1
- data/lib/rubygems/commands/install_command.rb +3 -3
- data/lib/rubygems/commands/list_command.rb +30 -28
- data/lib/rubygems/commands/lock_command.rb +1 -1
- data/lib/rubygems/commands/outdated_command.rb +5 -2
- data/lib/rubygems/commands/pristine_command.rb +3 -44
- data/lib/rubygems/commands/query_command.rb +80 -21
- data/lib/rubygems/commands/sources_command.rb +56 -28
- data/lib/rubygems/commands/specification_command.rb +4 -3
- data/lib/rubygems/commands/stale_command.rb +27 -0
- data/lib/rubygems/commands/update_command.rb +35 -22
- data/lib/rubygems/config_file.rb +29 -12
- data/lib/rubygems/custom_require.rb +1 -1
- data/lib/rubygems/defaults.rb +1 -1
- data/lib/rubygems/dependency.rb +63 -9
- data/lib/rubygems/dependency_installer.rb +60 -23
- data/lib/rubygems/dependency_list.rb +1 -1
- data/lib/rubygems/doc_manager.rb +5 -5
- data/lib/rubygems/gem_openssl.rb +1 -1
- data/lib/rubygems/indexer.rb +269 -84
- data/lib/rubygems/install_update_options.rb +6 -0
- data/lib/rubygems/installer.rb +35 -12
- data/lib/rubygems/local_remote_options.rb +26 -5
- data/lib/rubygems/platform.rb +15 -1
- data/lib/rubygems/remote_fetcher.rb +158 -90
- data/lib/rubygems/requirement.rb +16 -12
- data/lib/rubygems/rubygems_version.rb +1 -1
- data/lib/rubygems/security.rb +2 -2
- data/lib/rubygems/server.rb +239 -110
- data/lib/rubygems/source_index.rb +44 -18
- data/lib/rubygems/source_info_cache.rb +1 -1
- data/lib/rubygems/spec_fetcher.rb +251 -0
- data/lib/rubygems/specification.rb +120 -38
- data/lib/rubygems/test_utilities.rb +120 -0
- data/lib/rubygems/uninstaller.rb +11 -10
- data/lib/rubygems/user_interaction.rb +149 -74
- data/lib/rubygems/validator.rb +3 -3
- data/lib/rubygems/version.rb +23 -21
- data/setup.rb +105 -100
- data/test/gemutilities.rb +63 -86
- data/test/test_config.rb +0 -5
- data/test/test_gem.rb +22 -2
- data/test/test_gem_command_manager.rb +1 -1
- data/test/test_gem_commands_dependency_command.rb +125 -6
- data/test/test_gem_commands_environment_command.rb +1 -0
- data/test/test_gem_commands_fetch_command.rb +24 -4
- data/test/test_gem_commands_install_command.rb +6 -8
- data/test/{test_gem_outdated_command.rb → test_gem_commands_outdated_command.rb} +5 -2
- data/test/test_gem_commands_pristine_command.rb +13 -4
- data/test/test_gem_commands_query_command.rb +113 -37
- data/test/test_gem_commands_sources_command.rb +101 -31
- data/test/test_gem_commands_specification_command.rb +4 -1
- data/test/test_gem_commands_stale_command.rb +39 -0
- data/test/test_gem_commands_update_command.rb +17 -27
- data/test/test_gem_config_file.rb +38 -1
- data/test/test_gem_dependency.rb +51 -0
- data/test/test_gem_dependency_installer.rb +133 -25
- data/test/test_gem_gem_path_searcher.rb +4 -1
- data/test/test_gem_indexer.rb +124 -19
- data/test/test_gem_installer.rb +32 -2
- data/test/test_gem_local_remote_options.rb +6 -5
- data/test/test_gem_remote_fetcher.rb +14 -9
- data/test/test_gem_server.rb +207 -21
- data/test/test_gem_source_index.rb +203 -63
- data/test/test_gem_source_info_cache.rb +8 -6
- data/test/test_gem_source_info_cache_entry.rb +11 -9
- data/test/test_gem_spec_fetcher.rb +303 -0
- data/test/test_gem_specification.rb +91 -7
- data/test/test_gem_uninstaller.rb +21 -0
- data/test/test_gem_version.rb +14 -5
- data/test/test_kernel.rb +1 -1
- metadata +10 -73
- metadata.gz.sig +0 -0
- data/lib/rubygems/indexer/abstract_index_builder.rb +0 -88
- data/lib/rubygems/indexer/latest_index_builder.rb +0 -35
- data/lib/rubygems/indexer/marshal_index_builder.rb +0 -17
- data/lib/rubygems/indexer/master_index_builder.rb +0 -54
- data/lib/rubygems/indexer/quick_index_builder.rb +0 -50
- data/test/gem_installer_test_case.rbc +0 -0
- data/test/gem_package_tar_test_case.rbc +0 -0
- data/test/gemutilities.rbc +0 -0
- data/test/mockgemui.rbc +0 -0
- data/test/simple_gem.rbc +0 -0
- data/test/test_config.rbc +0 -0
- 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.rbc +0 -0
- data/test/test_gem_commands_build_command.rbc +0 -0
- 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.rbc +0 -0
- 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.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.rbc +0 -0
- data/test/test_gem_commands_server_command.rbc +0 -0
- data/test/test_gem_commands_sources_command.rbc +0 -0
- data/test/test_gem_commands_specification_command.rbc +0 -0
- data/test/test_gem_commands_unpack_command.rbc +0 -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.rbc +0 -0
- data/test/test_gem_dependency_list.rbc +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.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.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.rbc +0 -0
- data/test/test_gem_install_update_options.rbc +0 -0
- 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.rbc +0 -0
- data/test/test_gem_package_tar_input.rbc +0 -0
- data/test/test_gem_package_tar_output.rbc +0 -0
- data/test/test_gem_package_tar_reader.rbc +0 -0
- data/test/test_gem_package_tar_reader_entry.rbc +0 -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.rbc +0 -0
- data/test/test_gem_requirement.rbc +0 -0
- data/test/test_gem_server.rbc +0 -0
- data/test/test_gem_source_index.rbc +0 -0
- data/test/test_gem_source_info_cache.rbc +0 -0
- data/test/test_gem_source_info_cache_entry.rbc +0 -0
- data/test/test_gem_specification.rbc +0 -0
- data/test/test_gem_stream_ui.rbc +0 -0
- data/test/test_gem_uninstaller.rbc +0 -0
- data/test/test_gem_validator.rbc +0 -0
- data/test/test_gem_version.rbc +0 -0
- data/test/test_gem_version_option.rbc +0 -0
- data/test/test_kernel.rbc +0 -0
@@ -89,6 +89,12 @@ module Gem::InstallUpdateOptions
|
|
89
89
|
'foo_exec18') do |value, options|
|
90
90
|
options[:format_executable] = value
|
91
91
|
end
|
92
|
+
|
93
|
+
add_option(:"Install/Update", "--development",
|
94
|
+
"Install any additional development",
|
95
|
+
"dependencies") do |value, options|
|
96
|
+
options[:development] = true
|
97
|
+
end
|
92
98
|
end
|
93
99
|
|
94
100
|
# Default options for the gem install command.
|
data/lib/rubygems/installer.rb
CHANGED
@@ -56,6 +56,7 @@ class Gem::Installer
|
|
56
56
|
# foo_exec18.
|
57
57
|
# :security_policy:: Use the specified security policy. See Gem::Security
|
58
58
|
# :wrappers:: Install wrappers if true, symlinks if false.
|
59
|
+
|
59
60
|
def initialize(gem, options={})
|
60
61
|
@gem = gem
|
61
62
|
|
@@ -76,6 +77,7 @@ class Gem::Installer
|
|
76
77
|
@security_policy = options[:security_policy]
|
77
78
|
@wrappers = options[:wrappers]
|
78
79
|
@bin_dir = options[:bin_dir]
|
80
|
+
@development = options[:development]
|
79
81
|
|
80
82
|
begin
|
81
83
|
@format = Gem::Format.from_file_by_path @gem, @security_policy
|
@@ -98,6 +100,7 @@ class Gem::Installer
|
|
98
100
|
# cache/<gem-version>.gem #=> a cached copy of the installed gem
|
99
101
|
# gems/<gem-version>/... #=> extracted files
|
100
102
|
# specifications/<gem-version>.gemspec #=> the Gem::Specification
|
103
|
+
|
101
104
|
def install
|
102
105
|
# If we're forcing the install then disable security unless the security
|
103
106
|
# policy says that we only install singed gems.
|
@@ -119,7 +122,10 @@ class Gem::Installer
|
|
119
122
|
end
|
120
123
|
|
121
124
|
unless @ignore_dependencies then
|
122
|
-
@spec.
|
125
|
+
deps = @spec.runtime_dependencies
|
126
|
+
deps |= @spec.development_dependencies if @development
|
127
|
+
|
128
|
+
deps.each do |dep_gem|
|
123
129
|
ensure_dependency @spec, dep_gem
|
124
130
|
end
|
125
131
|
end
|
@@ -150,6 +156,8 @@ class Gem::Installer
|
|
150
156
|
@spec.loaded_from = File.join(@gem_home, 'specifications',
|
151
157
|
"#{@spec.full_name}.gemspec")
|
152
158
|
|
159
|
+
Gem.source_index.add_spec @spec
|
160
|
+
|
153
161
|
return @spec
|
154
162
|
rescue Zlib::GzipFile::Error
|
155
163
|
raise Gem::InstallError, "gzip error installing #{@gem}"
|
@@ -161,6 +169,7 @@ class Gem::Installer
|
|
161
169
|
#
|
162
170
|
# spec :: Gem::Specification
|
163
171
|
# dependency :: Gem::Dependency
|
172
|
+
|
164
173
|
def ensure_dependency(spec, dependency)
|
165
174
|
unless installation_satisfies_dependency? dependency then
|
166
175
|
raise Gem::InstallError, "#{spec.name} requires #{dependency}"
|
@@ -170,17 +179,15 @@ class Gem::Installer
|
|
170
179
|
end
|
171
180
|
|
172
181
|
##
|
173
|
-
# True if the
|
174
|
-
|
175
|
-
# dependency :: Gem::Dependency
|
182
|
+
# True if the gems in Gem.source_index satisfy +dependency+.
|
183
|
+
|
176
184
|
def installation_satisfies_dependency?(dependency)
|
177
|
-
|
178
|
-
current_index.find_name(dependency.name, dependency.version_requirements).size > 0
|
185
|
+
Gem.source_index.find_name(dependency.name, dependency.version_requirements).size > 0
|
179
186
|
end
|
180
187
|
|
181
188
|
##
|
182
189
|
# Unpacks the gem into the given directory.
|
183
|
-
|
190
|
+
|
184
191
|
def unpack(directory)
|
185
192
|
@gem_dir = directory
|
186
193
|
@format = Gem::Format.from_file_by_path @gem, @security_policy
|
@@ -193,7 +200,7 @@ class Gem::Installer
|
|
193
200
|
#
|
194
201
|
# spec:: [Gem::Specification] The Gem specification to output
|
195
202
|
# spec_path:: [String] The location (path) to write the gemspec to
|
196
|
-
|
203
|
+
|
197
204
|
def write_spec
|
198
205
|
rubycode = @spec.to_ruby
|
199
206
|
|
@@ -208,7 +215,7 @@ class Gem::Installer
|
|
208
215
|
|
209
216
|
##
|
210
217
|
# Creates windows .bat files for easy running of commands
|
211
|
-
|
218
|
+
|
212
219
|
def generate_windows_script(bindir, filename)
|
213
220
|
if Gem.win_platform? then
|
214
221
|
script_name = filename + ".bat"
|
@@ -227,7 +234,7 @@ class Gem::Installer
|
|
227
234
|
# If the user has asked for the gem to be installed in a directory that is
|
228
235
|
# the system gem directory, then use the system bin directory, else create
|
229
236
|
# (or use) a new bin dir under the gem_home.
|
230
|
-
bindir = @bin_dir ? @bin_dir :
|
237
|
+
bindir = @bin_dir ? @bin_dir : Gem.bindir(@gem_home)
|
231
238
|
|
232
239
|
Dir.mkdir bindir unless File.exist? bindir
|
233
240
|
raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
|
@@ -252,7 +259,7 @@ class Gem::Installer
|
|
252
259
|
# The Windows script is generated in addition to the regular one due to a
|
253
260
|
# bug or misfeature in the Windows shell's pipe. See
|
254
261
|
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
|
255
|
-
|
262
|
+
|
256
263
|
def generate_bin_script(filename, bindir)
|
257
264
|
bin_script_path = File.join bindir, formatted_program_filename(filename)
|
258
265
|
|
@@ -260,6 +267,8 @@ class Gem::Installer
|
|
260
267
|
|
261
268
|
# HACK some gems don't have #! in their executables, restore 2008/06
|
262
269
|
#if File.read(exec_path, 2) == '#!' then
|
270
|
+
FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
|
271
|
+
|
263
272
|
File.open bin_script_path, 'w', 0755 do |file|
|
264
273
|
file.print app_script_text(filename)
|
265
274
|
end
|
@@ -277,7 +286,7 @@ class Gem::Installer
|
|
277
286
|
##
|
278
287
|
# Creates the symlinks to run the applications in the gem. Moves
|
279
288
|
# the symlink if the gem being installed has a newer version.
|
280
|
-
|
289
|
+
|
281
290
|
def generate_bin_symlink(filename, bindir)
|
282
291
|
if Gem.win_platform? then
|
283
292
|
alert_warning "Unable to use symlinks on Windows, installing wrapper"
|
@@ -303,6 +312,7 @@ class Gem::Installer
|
|
303
312
|
##
|
304
313
|
# Generates a #! line for +bin_file_name+'s wrapper copying arguments if
|
305
314
|
# necessary.
|
315
|
+
|
306
316
|
def shebang(bin_file_name)
|
307
317
|
if @env_shebang then
|
308
318
|
"#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
|
@@ -324,7 +334,9 @@ class Gem::Installer
|
|
324
334
|
end
|
325
335
|
end
|
326
336
|
|
337
|
+
##
|
327
338
|
# Return the text for an application file.
|
339
|
+
|
328
340
|
def app_script_text(bin_file_name)
|
329
341
|
<<-TEXT
|
330
342
|
#{shebang bin_file_name}
|
@@ -349,7 +361,9 @@ load '#{bin_file_name}'
|
|
349
361
|
TEXT
|
350
362
|
end
|
351
363
|
|
364
|
+
##
|
352
365
|
# return the stub script text used to launch the true ruby script
|
366
|
+
|
353
367
|
def windows_stub_script(bindir, bin_file_name)
|
354
368
|
<<-TEXT
|
355
369
|
@ECHO OFF
|
@@ -361,8 +375,10 @@ GOTO :EOF
|
|
361
375
|
TEXT
|
362
376
|
end
|
363
377
|
|
378
|
+
##
|
364
379
|
# Builds extensions. Valid types of extensions are extconf.rb files,
|
365
380
|
# configure scripts and rakefiles or mkrf_conf files.
|
381
|
+
|
366
382
|
def build_extensions
|
367
383
|
return if @spec.extensions.empty?
|
368
384
|
say "Building native extensions. This could take a while..."
|
@@ -418,6 +434,7 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
|
|
418
434
|
# Reads the file index and extracts each file into the gem directory.
|
419
435
|
#
|
420
436
|
# Ensures that files can't be installed outside the gem directory.
|
437
|
+
|
421
438
|
def extract_files
|
422
439
|
expand_and_validate_gem_dir
|
423
440
|
|
@@ -445,11 +462,15 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
|
|
445
462
|
out.write file_data
|
446
463
|
end
|
447
464
|
|
465
|
+
FileUtils.chmod entry['mode'], path
|
466
|
+
|
448
467
|
say path if Gem.configuration.really_verbose
|
449
468
|
end
|
450
469
|
end
|
451
470
|
|
471
|
+
##
|
452
472
|
# Prefix and suffix the program filename the same as ruby.
|
473
|
+
|
453
474
|
def formatted_program_filename(filename)
|
454
475
|
if @format_executable then
|
455
476
|
self.class.exec_format % File.basename(filename)
|
@@ -460,7 +481,9 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
|
|
460
481
|
|
461
482
|
private
|
462
483
|
|
484
|
+
##
|
463
485
|
# HACK Pathname is broken on windows.
|
486
|
+
|
464
487
|
def absolute_path? pathname
|
465
488
|
pathname.absolute? or (Gem.win_platform? and pathname.to_s =~ /\A[a-z]:/i)
|
466
489
|
end
|
@@ -4,27 +4,34 @@
|
|
4
4
|
# See LICENSE.txt for permissions.
|
5
5
|
#++
|
6
6
|
|
7
|
+
require 'uri'
|
7
8
|
require 'rubygems'
|
8
9
|
|
10
|
+
##
|
9
11
|
# Mixin methods for local and remote Gem::Command options.
|
12
|
+
|
10
13
|
module Gem::LocalRemoteOptions
|
11
14
|
|
15
|
+
##
|
12
16
|
# Allows OptionParser to handle HTTP URIs.
|
17
|
+
|
13
18
|
def accept_uri_http
|
14
19
|
OptionParser.accept URI::HTTP do |value|
|
15
20
|
begin
|
16
|
-
|
21
|
+
uri = URI.parse value
|
17
22
|
rescue URI::InvalidURIError
|
18
23
|
raise OptionParser::InvalidArgument, value
|
19
24
|
end
|
20
25
|
|
21
|
-
raise OptionParser::InvalidArgument, value unless
|
26
|
+
raise OptionParser::InvalidArgument, value unless uri.scheme == 'http'
|
22
27
|
|
23
28
|
value
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
32
|
+
##
|
27
33
|
# Add local/remote options to the command line parser.
|
34
|
+
|
28
35
|
def add_local_remote_options
|
29
36
|
add_option(:"Local/Remote", '-l', '--local',
|
30
37
|
'Restrict operations to the LOCAL domain') do |value, options|
|
@@ -47,7 +54,9 @@ module Gem::LocalRemoteOptions
|
|
47
54
|
add_update_sources_option
|
48
55
|
end
|
49
56
|
|
57
|
+
##
|
50
58
|
# Add the --bulk-threshold option
|
59
|
+
|
51
60
|
def add_bulk_threshold_option
|
52
61
|
add_option(:"Local/Remote", '-B', '--bulk-threshold COUNT',
|
53
62
|
"Threshold for switching to bulk",
|
@@ -57,7 +66,9 @@ module Gem::LocalRemoteOptions
|
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
69
|
+
##
|
60
70
|
# Add the --http-proxy option
|
71
|
+
|
61
72
|
def add_proxy_option
|
62
73
|
accept_uri_http
|
63
74
|
|
@@ -68,22 +79,28 @@ module Gem::LocalRemoteOptions
|
|
68
79
|
end
|
69
80
|
end
|
70
81
|
|
82
|
+
##
|
71
83
|
# Add the --source option
|
84
|
+
|
72
85
|
def add_source_option
|
73
86
|
accept_uri_http
|
74
87
|
|
75
88
|
add_option(:"Local/Remote", '--source URL', URI::HTTP,
|
76
|
-
'Use URL as the remote source for gems') do |
|
89
|
+
'Use URL as the remote source for gems') do |source, options|
|
90
|
+
source << '/' if source !~ /\/\z/
|
91
|
+
|
77
92
|
if options[:added_source] then
|
78
|
-
Gem.sources <<
|
93
|
+
Gem.sources << source
|
79
94
|
else
|
80
95
|
options[:added_source] = true
|
81
|
-
Gem.sources.replace [
|
96
|
+
Gem.sources.replace [source]
|
82
97
|
end
|
83
98
|
end
|
84
99
|
end
|
85
100
|
|
101
|
+
##
|
86
102
|
# Add the --source option
|
103
|
+
|
87
104
|
def add_update_sources_option
|
88
105
|
|
89
106
|
add_option(:"Local/Remote", '-u', '--[no-]update-sources',
|
@@ -92,12 +109,16 @@ module Gem::LocalRemoteOptions
|
|
92
109
|
end
|
93
110
|
end
|
94
111
|
|
112
|
+
##
|
95
113
|
# Is local fetching enabled?
|
114
|
+
|
96
115
|
def local?
|
97
116
|
options[:domain] == :local || options[:domain] == :both
|
98
117
|
end
|
99
118
|
|
119
|
+
##
|
100
120
|
# Is remote fetching enabled?
|
121
|
+
|
101
122
|
def remote?
|
102
123
|
options[:domain] == :remote || options[:domain] == :both
|
103
124
|
end
|
data/lib/rubygems/platform.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
+
##
|
3
4
|
# Available list of platforms for targeting Gem installations.
|
4
|
-
|
5
|
+
|
5
6
|
class Gem::Platform
|
6
7
|
|
7
8
|
@local = nil
|
@@ -122,11 +123,20 @@ class Gem::Platform
|
|
122
123
|
to_a.compact.join '-'
|
123
124
|
end
|
124
125
|
|
126
|
+
##
|
127
|
+
# Is +other+ equal to this platform? Two platforms are equal if they have
|
128
|
+
# the same CPU, OS and version.
|
129
|
+
|
125
130
|
def ==(other)
|
126
131
|
self.class === other and
|
127
132
|
@cpu == other.cpu and @os == other.os and @version == other.version
|
128
133
|
end
|
129
134
|
|
135
|
+
##
|
136
|
+
# Does +other+ match this platform? Two platforms match if they have the
|
137
|
+
# same CPU, or either has a CPU of 'universal', they have the same OS, and
|
138
|
+
# they have the same version, or either has no version.
|
139
|
+
|
130
140
|
def ===(other)
|
131
141
|
return nil unless Gem::Platform === other
|
132
142
|
|
@@ -140,6 +150,10 @@ class Gem::Platform
|
|
140
150
|
(@version.nil? or other.version.nil? or @version == other.version)
|
141
151
|
end
|
142
152
|
|
153
|
+
##
|
154
|
+
# Does +other+ match this platform? If +other+ is a String it will be
|
155
|
+
# converted to a Gem::Platform first. See #=== for matching rules.
|
156
|
+
|
143
157
|
def =~(other)
|
144
158
|
case other
|
145
159
|
when Gem::Platform then # nop
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'stringio'
|
2
3
|
require 'uri'
|
3
4
|
|
4
5
|
require 'rubygems'
|
@@ -11,15 +12,38 @@ class Gem::RemoteFetcher
|
|
11
12
|
|
12
13
|
include Gem::UserInteraction
|
13
14
|
|
14
|
-
|
15
|
+
##
|
16
|
+
# A FetchError exception wraps up the various possible IO and HTTP failures
|
17
|
+
# that could happen while downloading from the internet.
|
18
|
+
|
19
|
+
class FetchError < Gem::Exception
|
20
|
+
|
21
|
+
##
|
22
|
+
# The URI which was being accessed when the exception happened.
|
23
|
+
|
24
|
+
attr_accessor :uri
|
25
|
+
|
26
|
+
def initialize(message, uri)
|
27
|
+
super message
|
28
|
+
@uri = uri
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s # :nodoc:
|
32
|
+
"#{super} (#{uri})"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
15
36
|
|
16
37
|
@fetcher = nil
|
17
38
|
|
39
|
+
##
|
18
40
|
# Cached RemoteFetcher instance.
|
41
|
+
|
19
42
|
def self.fetcher
|
20
43
|
@fetcher ||= self.new Gem.configuration[:http_proxy]
|
21
44
|
end
|
22
45
|
|
46
|
+
##
|
23
47
|
# Initialize a remote fetcher using the source URI and possible proxy
|
24
48
|
# information.
|
25
49
|
#
|
@@ -29,6 +53,7 @@ class Gem::RemoteFetcher
|
|
29
53
|
# * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER,
|
30
54
|
# HTTP_PROXY_PASS)
|
31
55
|
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
|
56
|
+
|
32
57
|
def initialize(proxy)
|
33
58
|
Socket.do_not_reverse_lookup = true
|
34
59
|
|
@@ -47,11 +72,13 @@ class Gem::RemoteFetcher
|
|
47
72
|
# Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
|
48
73
|
# already there. If the source_uri is local the gem cache dir copy is
|
49
74
|
# always replaced.
|
75
|
+
|
50
76
|
def download(spec, source_uri, install_dir = Gem.dir)
|
77
|
+
cache_dir = File.join install_dir, 'cache'
|
51
78
|
gem_file_name = "#{spec.full_name}.gem"
|
52
|
-
local_gem_path = File.join
|
79
|
+
local_gem_path = File.join cache_dir, gem_file_name
|
53
80
|
|
54
|
-
|
81
|
+
FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
|
55
82
|
|
56
83
|
source_uri = URI.parse source_uri unless URI::Generic === source_uri
|
57
84
|
scheme = source_uri.scheme
|
@@ -102,21 +129,26 @@ class Gem::RemoteFetcher
|
|
102
129
|
local_gem_path
|
103
130
|
end
|
104
131
|
|
105
|
-
|
132
|
+
##
|
133
|
+
# Downloads +uri+ and returns it as a String.
|
134
|
+
|
106
135
|
def fetch_path(uri)
|
107
136
|
open_uri_or_path(uri) do |input|
|
108
137
|
input.read
|
109
138
|
end
|
139
|
+
rescue FetchError
|
140
|
+
raise
|
110
141
|
rescue Timeout::Error
|
111
|
-
raise FetchError
|
142
|
+
raise FetchError.new('timed out', uri)
|
112
143
|
rescue IOError, SocketError, SystemCallError => e
|
113
|
-
raise FetchError
|
144
|
+
raise FetchError.new("#{e.class}: #{e}", uri)
|
114
145
|
rescue => e
|
115
|
-
|
116
|
-
raise FetchError, message
|
146
|
+
raise FetchError.new("#{e.class}: #{e}", uri)
|
117
147
|
end
|
118
148
|
|
149
|
+
##
|
119
150
|
# Returns the size of +uri+ in bytes.
|
151
|
+
|
120
152
|
def fetch_size(uri)
|
121
153
|
return File.size(get_file_uri_path(uri)) if file_uri? uri
|
122
154
|
|
@@ -124,30 +156,23 @@ class Gem::RemoteFetcher
|
|
124
156
|
|
125
157
|
raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
|
126
158
|
|
127
|
-
|
128
|
-
|
129
|
-
request = Net::HTTP::Head.new uri.request_uri
|
159
|
+
response = request uri, Net::HTTP::Head
|
130
160
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
if resp.code !~ /^2/ then
|
137
|
-
raise Gem::RemoteSourceException,
|
138
|
-
"HTTP Response #{resp.code} fetching #{uri}"
|
161
|
+
case response
|
162
|
+
when Net::HTTPOK then
|
163
|
+
else
|
164
|
+
raise FetchError.new("bad response #{response.message} #{response.code}", uri)
|
139
165
|
end
|
140
166
|
|
141
|
-
if
|
142
|
-
return
|
167
|
+
if response['content-length'] then
|
168
|
+
return response['content-length'].to_i
|
143
169
|
else
|
144
|
-
|
145
|
-
return
|
170
|
+
response = http.get uri.request_uri
|
171
|
+
return response.body.size
|
146
172
|
end
|
147
173
|
|
148
174
|
rescue SocketError, SystemCallError, Timeout::Error => e
|
149
|
-
raise
|
150
|
-
"#{e.message} (#{e.class})\n\tgetting size of #{uri}"
|
175
|
+
raise FetchError.new("#{e.message} (#{e.class})\n\tfetching size", uri)
|
151
176
|
end
|
152
177
|
|
153
178
|
private
|
@@ -162,7 +187,9 @@ class Gem::RemoteFetcher
|
|
162
187
|
URI.unescape(str)
|
163
188
|
end
|
164
189
|
|
190
|
+
##
|
165
191
|
# Returns an HTTP proxy URI if one is set in the environment variables.
|
192
|
+
|
166
193
|
def get_proxy_from_env
|
167
194
|
env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
|
168
195
|
|
@@ -179,104 +206,145 @@ class Gem::RemoteFetcher
|
|
179
206
|
uri
|
180
207
|
end
|
181
208
|
|
209
|
+
##
|
182
210
|
# Normalize the URI by adding "http://" if it is missing.
|
211
|
+
|
183
212
|
def normalize_uri(uri)
|
184
213
|
(uri =~ /^(https?|ftp|file):/) ? uri : "http://#{uri}"
|
185
214
|
end
|
186
215
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
216
|
+
##
|
217
|
+
# Creates or an HTTP connection based on +uri+, or retrieves an existing
|
218
|
+
# connection, using a proxy if needed.
|
219
|
+
|
220
|
+
def connection_for(uri)
|
221
|
+
net_http_args = [uri.host, uri.port]
|
222
|
+
|
223
|
+
if @proxy_uri then
|
224
|
+
net_http_args += [
|
225
|
+
@proxy_uri.host,
|
226
|
+
@proxy_uri.port,
|
227
|
+
@proxy_uri.user,
|
228
|
+
@proxy_uri.password
|
229
|
+
]
|
193
230
|
end
|
231
|
+
|
232
|
+
connection_id = net_http_args.join ':'
|
233
|
+
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
|
234
|
+
connection = @connections[connection_id]
|
235
|
+
|
236
|
+
if uri.scheme == 'https' and not connection.started? then
|
237
|
+
http_obj.use_ssl = true
|
238
|
+
http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
239
|
+
end
|
240
|
+
|
241
|
+
connection.start unless connection.started?
|
242
|
+
|
243
|
+
connection
|
194
244
|
end
|
195
245
|
|
246
|
+
##
|
196
247
|
# Read the data from the (source based) URI, but if it is a file:// URI,
|
197
248
|
# read from the filesystem instead.
|
249
|
+
|
198
250
|
def open_uri_or_path(uri, depth = 0, &block)
|
199
251
|
if file_uri?(uri)
|
200
252
|
open(get_file_uri_path(uri), &block)
|
201
253
|
else
|
202
254
|
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
255
|
|
213
|
-
|
214
|
-
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
|
215
|
-
connection = @connections[connection_id]
|
216
|
-
|
217
|
-
if uri.scheme == 'https' && ! connection.started?
|
218
|
-
http_obj.use_ssl = true
|
219
|
-
http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
220
|
-
end
|
221
|
-
|
222
|
-
connection.start unless connection.started?
|
223
|
-
|
224
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
225
|
-
unless uri.nil? || uri.user.nil? || uri.user.empty? then
|
226
|
-
request.basic_auth(uri.user, uri.password)
|
227
|
-
end
|
228
|
-
|
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
|
-
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
|
240
|
-
# to install gems.
|
241
|
-
retried = false
|
242
|
-
begin
|
243
|
-
@requests[connection_id] += 1
|
244
|
-
response = connection.request(request)
|
245
|
-
rescue EOFError, Errno::ECONNABORTED
|
246
|
-
requests = @requests[connection_id]
|
247
|
-
say "connection reset after #{requests} requests, retrying" if
|
248
|
-
Gem.configuration.really_verbose
|
249
|
-
|
250
|
-
raise Gem::RemoteFetcher::FetchError, 'too many connection resets' if
|
251
|
-
retried
|
252
|
-
|
253
|
-
@requests[connection_id] = 0
|
254
|
-
|
255
|
-
connection.finish
|
256
|
-
connection.start
|
257
|
-
retried = true
|
258
|
-
retry
|
259
|
-
end
|
256
|
+
response = request uri
|
260
257
|
|
261
258
|
case response
|
262
259
|
when Net::HTTPOK then
|
263
260
|
block.call(StringIO.new(response.body)) if block
|
264
261
|
when Net::HTTPRedirection then
|
265
|
-
raise
|
262
|
+
raise FetchError.new('too many redirects', uri) if depth > 10
|
263
|
+
|
266
264
|
open_uri_or_path(response['Location'], depth + 1, &block)
|
267
265
|
else
|
268
|
-
raise
|
269
|
-
"bad response #{response.message} #{response.code}"
|
266
|
+
raise FetchError.new("bad response #{response.message} #{response.code}", uri)
|
270
267
|
end
|
271
268
|
end
|
272
269
|
end
|
273
270
|
|
271
|
+
##
|
272
|
+
# Performs a Net::HTTP request of type +request_class+ on +uri+ returning
|
273
|
+
# a Net::HTTP response object. request maintains a table of persistent
|
274
|
+
# connections to reduce connect overhead.
|
275
|
+
|
276
|
+
def request(uri, request_class = Net::HTTP::Get)
|
277
|
+
request = request_class.new uri.request_uri
|
278
|
+
|
279
|
+
unless uri.nil? || uri.user.nil? || uri.user.empty? then
|
280
|
+
request.basic_auth uri.user, uri.password
|
281
|
+
end
|
282
|
+
|
283
|
+
ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
|
284
|
+
ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
|
285
|
+
ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
|
286
|
+
ua << ")"
|
287
|
+
|
288
|
+
request.add_field 'User-Agent', ua
|
289
|
+
request.add_field 'Connection', 'keep-alive'
|
290
|
+
request.add_field 'Keep-Alive', '30'
|
291
|
+
|
292
|
+
connection = connection_for uri
|
293
|
+
|
294
|
+
retried = false
|
295
|
+
bad_response = false
|
296
|
+
|
297
|
+
# HACK work around EOFError bug in Net::HTTP
|
298
|
+
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
|
299
|
+
# to install gems.
|
300
|
+
begin
|
301
|
+
@requests[connection.object_id] += 1
|
302
|
+
response = connection.request request
|
303
|
+
say "#{request.method} #{response.code} #{response.message}: #{uri}" if
|
304
|
+
Gem.configuration.really_verbose
|
305
|
+
rescue Net::HTTPBadResponse
|
306
|
+
reset connection
|
307
|
+
|
308
|
+
raise FetchError.new('too many bad responses', uri) if bad_response
|
309
|
+
|
310
|
+
bad_response = true
|
311
|
+
retry
|
312
|
+
rescue EOFError, Errno::ECONNABORTED, Errno::ECONNRESET
|
313
|
+
requests = @requests[connection.object_id]
|
314
|
+
say "connection reset after #{requests} requests, retrying" if
|
315
|
+
Gem.configuration.really_verbose
|
316
|
+
|
317
|
+
raise FetchError.new('too many connection resets', uri) if retried
|
318
|
+
|
319
|
+
reset connection
|
320
|
+
|
321
|
+
retried = true
|
322
|
+
retry
|
323
|
+
end
|
324
|
+
|
325
|
+
response
|
326
|
+
end
|
327
|
+
|
328
|
+
##
|
329
|
+
# Resets HTTP connection +connection+.
|
330
|
+
|
331
|
+
def reset(connection)
|
332
|
+
@requests.delete connection.object_id
|
333
|
+
|
334
|
+
connection.finish
|
335
|
+
connection.start
|
336
|
+
end
|
337
|
+
|
338
|
+
##
|
274
339
|
# Checks if the provided string is a file:// URI.
|
340
|
+
|
275
341
|
def file_uri?(uri)
|
276
342
|
uri =~ %r{\Afile://}
|
277
343
|
end
|
278
344
|
|
345
|
+
##
|
279
346
|
# Given a file:// URI, returns its local path.
|
347
|
+
|
280
348
|
def get_file_uri_path(uri)
|
281
349
|
uri.sub(%r{\Afile://}, '')
|
282
350
|
end
|