rubygems-update 1.8.30 → 2.0.0.preview2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rubygems-update might be problematic. Click here for more details.
- checksums.yaml +6 -6
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +3 -0
- data/.autotest +6 -3
- data/History.txt +137 -63
- data/LICENSE.txt +1 -5
- data/Manifest.txt +69 -32
- data/README.rdoc +11 -9
- data/Rakefile +24 -38
- data/bin/gem +0 -9
- data/bin/update_rubygems +1 -0
- data/lib/rubygems.rb +193 -405
- data/lib/rubygems/available_set.rb +95 -0
- data/lib/rubygems/command.rb +88 -45
- data/lib/rubygems/command_manager.rb +67 -40
- data/lib/rubygems/commands/build_command.rb +5 -23
- data/lib/rubygems/commands/cert_command.rb +199 -57
- data/lib/rubygems/commands/check_command.rb +14 -39
- data/lib/rubygems/commands/cleanup_command.rb +9 -1
- data/lib/rubygems/commands/contents_command.rb +30 -12
- data/lib/rubygems/commands/dependency_command.rb +3 -8
- data/lib/rubygems/commands/environment_command.rb +13 -8
- data/lib/rubygems/commands/fetch_command.rb +3 -16
- data/lib/rubygems/commands/generate_index_command.rb +7 -47
- data/lib/rubygems/commands/help_command.rb +1 -1
- data/lib/rubygems/commands/install_command.rb +69 -36
- data/lib/rubygems/commands/list_command.rb +6 -4
- data/lib/rubygems/commands/lock_command.rb +1 -1
- data/lib/rubygems/commands/mirror_command.rb +17 -0
- data/lib/rubygems/commands/outdated_command.rb +6 -3
- data/lib/rubygems/commands/owner_command.rb +13 -5
- data/lib/rubygems/commands/pristine_command.rb +19 -4
- data/lib/rubygems/commands/push_command.rb +12 -1
- data/lib/rubygems/commands/query_command.rb +43 -27
- data/lib/rubygems/commands/rdoc_command.rb +23 -28
- data/lib/rubygems/commands/search_command.rb +4 -18
- data/lib/rubygems/commands/server_command.rb +1 -1
- data/lib/rubygems/commands/setup_command.rb +124 -38
- data/lib/rubygems/commands/sources_command.rb +16 -16
- data/lib/rubygems/commands/specification_command.rb +11 -13
- data/lib/rubygems/commands/uninstall_command.rb +24 -7
- data/lib/rubygems/commands/unpack_command.rb +7 -3
- data/lib/rubygems/commands/update_command.rb +22 -36
- data/lib/rubygems/commands/yank_command.rb +98 -0
- data/lib/rubygems/compatibility.rb +51 -0
- data/lib/rubygems/config_file.rb +82 -54
- data/lib/rubygems/core_ext/kernel_gem.rb +53 -0
- data/lib/rubygems/core_ext/kernel_require.rb +119 -0
- data/lib/rubygems/defaults.rb +10 -21
- data/lib/rubygems/dependency.rb +61 -10
- data/lib/rubygems/dependency_installer.rb +157 -69
- data/lib/rubygems/dependency_list.rb +11 -19
- data/lib/rubygems/dependency_resolver.rb +562 -0
- data/lib/rubygems/deprecate.rb +40 -40
- data/lib/rubygems/errors.rb +77 -24
- data/lib/rubygems/exceptions.rb +25 -7
- data/lib/rubygems/ext/builder.rb +20 -23
- data/lib/rubygems/ext/configure_builder.rb +2 -2
- data/lib/rubygems/ext/ext_conf_builder.rb +5 -45
- data/lib/rubygems/ext/rake_builder.rb +2 -2
- data/lib/rubygems/gem_runner.rb +3 -16
- data/lib/rubygems/gemcutter_utilities.rb +22 -7
- data/lib/rubygems/indexer.rb +6 -159
- data/lib/rubygems/install_message.rb +12 -0
- data/lib/rubygems/install_update_options.rb +56 -18
- data/lib/rubygems/installer.rb +244 -134
- data/lib/rubygems/installer_test_case.rb +71 -19
- data/lib/rubygems/mock_gem_ui.rb +17 -0
- data/lib/rubygems/name_tuple.rb +110 -0
- data/lib/rubygems/package.rb +514 -43
- data/lib/rubygems/package/digest_io.rb +64 -0
- data/lib/rubygems/package/old.rb +147 -0
- data/lib/rubygems/package/tar_header.rb +18 -55
- data/lib/rubygems/package/tar_reader.rb +20 -3
- data/lib/rubygems/package/tar_writer.rb +63 -7
- data/lib/rubygems/package_task.rb +3 -4
- data/lib/rubygems/path_support.rb +14 -7
- data/lib/rubygems/platform.rb +19 -26
- data/lib/rubygems/rdoc.rb +316 -0
- data/lib/rubygems/remote_fetcher.rb +117 -54
- data/lib/rubygems/request_set.rb +182 -0
- data/lib/rubygems/requirement.rb +63 -26
- data/lib/rubygems/security.rb +295 -555
- data/lib/rubygems/security/policies.rb +115 -0
- data/lib/rubygems/security/policy.rb +227 -0
- data/lib/rubygems/security/signer.rb +136 -0
- data/lib/rubygems/security/trust_dir.rb +104 -0
- data/lib/rubygems/server.rb +45 -55
- data/lib/rubygems/source.rb +144 -0
- data/lib/rubygems/source_list.rb +87 -0
- data/lib/rubygems/source_local.rb +92 -0
- data/lib/rubygems/source_specific_file.rb +28 -0
- data/lib/rubygems/spec_fetcher.rb +116 -184
- data/lib/rubygems/specification.rb +731 -335
- data/lib/rubygems/ssl_certs/AddTrustExternalCARoot.pem +88 -30
- data/lib/rubygems/ssl_certs/Entrust_net-Secure-Server-Certification-Authority.pem +90 -0
- data/lib/rubygems/ssl_certs/VerisignClass3PublicPrimaryCertificationAuthority-G2.pem +57 -0
- data/lib/rubygems/syck_hack.rb +2 -0
- data/lib/rubygems/test_case.rb +199 -109
- data/lib/rubygems/test_utilities.rb +25 -5
- data/lib/rubygems/uninstaller.rb +62 -20
- data/lib/rubygems/user_interaction.rb +10 -0
- data/lib/rubygems/validator.rb +33 -40
- data/lib/rubygems/version.rb +19 -8
- data/setup.rb +8 -1
- data/test/rubygems/alternate_cert.pem +9 -0
- data/test/rubygems/alternate_cert_32.pem +9 -0
- data/test/rubygems/alternate_key.pem +9 -0
- data/test/rubygems/bad_rake.rb +1 -0
- data/test/rubygems/child_cert.pem +9 -0
- data/test/rubygems/child_cert_32.pem +9 -0
- data/test/rubygems/child_key.pem +9 -0
- data/test/rubygems/data/null-type.gemspec.rz +0 -0
- data/test/rubygems/expired_cert.pem +9 -0
- data/test/rubygems/future_cert.pem +9 -0
- data/test/rubygems/future_cert_32.pem +9 -0
- data/test/rubygems/good_rake.rb +1 -0
- data/test/rubygems/grandchild_cert.pem +9 -0
- data/test/rubygems/grandchild_cert_32.pem +9 -0
- data/test/rubygems/grandchild_key.pem +9 -0
- data/test/rubygems/invalid_issuer_cert.pem +9 -0
- data/test/rubygems/invalid_issuer_cert_32.pem +9 -0
- data/test/rubygems/invalid_key.pem +9 -0
- data/test/rubygems/invalid_signer_cert.pem +9 -0
- data/test/rubygems/invalid_signer_cert_32.pem +9 -0
- data/test/rubygems/invalidchild_cert.pem +9 -0
- data/test/rubygems/invalidchild_cert_32.pem +9 -0
- data/test/rubygems/invalidchild_key.pem +9 -0
- data/test/rubygems/plugin/exception/rubygems_plugin.rb +1 -1
- data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +1 -1
- data/test/rubygems/private_key.pem +7 -25
- data/test/rubygems/public_cert.pem +8 -18
- data/test/rubygems/public_cert_32.pem +10 -0
- data/test/rubygems/public_key.pem +4 -0
- data/test/rubygems/rubygems/commands/crash_command.rb +1 -1
- data/test/rubygems/test_config.rb +4 -6
- data/test/rubygems/test_deprecate.rb +76 -0
- data/test/rubygems/test_gem.rb +318 -83
- data/test/rubygems/test_gem_available_set.rb +106 -0
- data/test/rubygems/test_gem_command.rb +10 -0
- data/test/rubygems/test_gem_command_manager.rb +55 -9
- data/test/rubygems/test_gem_commands_build_command.rb +11 -19
- data/test/rubygems/test_gem_commands_cert_command.rb +441 -42
- data/test/rubygems/test_gem_commands_cleanup_command.rb +29 -1
- data/test/rubygems/test_gem_commands_contents_command.rb +23 -0
- data/test/rubygems/test_gem_commands_dependency_command.rb +5 -0
- data/test/rubygems/test_gem_commands_fetch_command.rb +19 -20
- data/test/rubygems/test_gem_commands_generate_index_command.rb +2 -83
- data/test/rubygems/test_gem_commands_help_command.rb +2 -1
- data/test/rubygems/test_gem_commands_install_command.rb +647 -48
- data/test/rubygems/test_gem_commands_mirror.rb +32 -0
- data/test/rubygems/test_gem_commands_owner_command.rb +4 -8
- data/test/rubygems/test_gem_commands_pristine_command.rb +99 -4
- data/test/rubygems/test_gem_commands_push_command.rb +62 -8
- data/test/rubygems/test_gem_commands_query_command.rb +51 -0
- data/test/rubygems/test_gem_commands_search_command.rb +25 -0
- data/test/rubygems/test_gem_commands_setup_command.rb +45 -0
- data/test/rubygems/test_gem_commands_sources_command.rb +21 -6
- data/test/rubygems/test_gem_commands_specification_command.rb +33 -1
- data/test/rubygems/test_gem_commands_uninstall_command.rb +91 -31
- data/test/rubygems/test_gem_commands_unpack_command.rb +3 -3
- data/test/rubygems/test_gem_commands_update_command.rb +56 -38
- data/test/rubygems/test_gem_commands_which_command.rb +4 -4
- data/test/rubygems/test_gem_commands_yank_command.rb +97 -0
- data/test/rubygems/test_gem_config_file.rb +66 -21
- data/test/rubygems/test_gem_dependency.rb +46 -0
- data/test/rubygems/test_gem_dependency_installer.rb +228 -18
- data/test/rubygems/test_gem_dependency_list.rb +0 -9
- data/test/rubygems/test_gem_dependency_resolver.rb +327 -0
- data/test/rubygems/test_gem_ext_configure_builder.rb +4 -4
- data/test/rubygems/test_gem_ext_ext_conf_builder.rb +21 -49
- data/test/rubygems/test_gem_ext_rake_builder.rb +13 -13
- data/test/rubygems/test_gem_gem_runner.rb +27 -5
- data/test/rubygems/test_gem_gemcutter_utilities.rb +19 -0
- data/test/rubygems/test_gem_indexer.rb +14 -227
- data/test/rubygems/test_gem_install_update_options.rb +83 -3
- data/test/rubygems/test_gem_installer.rb +211 -236
- data/test/rubygems/test_gem_local_remote_options.rb +8 -2
- data/test/rubygems/test_gem_name_tuple.rb +15 -0
- data/test/rubygems/test_gem_package.rb +547 -0
- data/test/rubygems/test_gem_package_old.rb +37 -0
- data/test/rubygems/test_gem_package_tar_reader.rb +32 -0
- data/test/rubygems/test_gem_package_tar_writer.rb +84 -1
- data/test/rubygems/test_gem_path_support.rb +4 -30
- data/test/rubygems/test_gem_platform.rb +3 -6
- data/test/rubygems/test_gem_rdoc.rb +245 -0
- data/test/rubygems/test_gem_remote_fetcher.rb +51 -5
- data/test/rubygems/test_gem_request_set.rb +70 -0
- data/test/rubygems/test_gem_requirement.rb +53 -24
- data/test/rubygems/test_gem_security.rb +189 -43
- data/test/rubygems/test_gem_security_policy.rb +376 -0
- data/test/rubygems/test_gem_security_signer.rb +184 -0
- data/test/rubygems/test_gem_security_trust_dir.rb +94 -0
- data/test/rubygems/test_gem_server.rb +31 -36
- data/test/rubygems/test_gem_silent_ui.rb +2 -2
- data/test/rubygems/test_gem_source.rb +188 -0
- data/test/rubygems/test_gem_source_list.rb +87 -0
- data/test/rubygems/test_gem_source_local.rb +83 -0
- data/test/rubygems/test_gem_source_specific_file.rb +33 -0
- data/test/rubygems/test_gem_spec_fetcher.rb +91 -255
- data/test/rubygems/test_gem_specification.rb +293 -39
- data/test/rubygems/test_gem_uninstaller.rb +136 -13
- data/test/rubygems/test_gem_validator.rb +14 -41
- data/test/rubygems/test_gem_version.rb +15 -21
- data/test/rubygems/test_require.rb +193 -0
- data/test/rubygems/wrong_key_cert.pem +9 -0
- data/test/rubygems/wrong_key_cert_32.pem +9 -0
- metadata +171 -83
- metadata.gz.sig +1 -0
- data/CVE-2013-4287.txt +0 -36
- data/CVE-2013-4363.txt +0 -45
- data/ci_build.sh +0 -27
- data/cruise_config.rb +0 -32
- data/lib/rbconfig/datadir.rb +0 -13
- data/lib/rubygems/builder.rb +0 -99
- data/lib/rubygems/custom_require.rb +0 -69
- data/lib/rubygems/doc_manager.rb +0 -243
- data/lib/rubygems/format.rb +0 -82
- data/lib/rubygems/gem_openssl.rb +0 -90
- data/lib/rubygems/gem_path_searcher.rb +0 -172
- data/lib/rubygems/old_format.rb +0 -153
- data/lib/rubygems/package/f_sync_dir.rb +0 -23
- data/lib/rubygems/package/tar_input.rb +0 -234
- data/lib/rubygems/package/tar_output.rb +0 -146
- data/lib/rubygems/require_paths_builder.rb +0 -18
- data/lib/rubygems/source_index.rb +0 -406
- data/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem +0 -25
- data/lib/rubygems/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
- data/lib/rubygems/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +0 -23
- data/lib/rubygems/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
- data/lib/rubygems/ssl_certs/GeoTrustGlobalCA.pem +0 -20
- data/test/rubygems/test_bundled_ca.rb +0 -59
- data/test/rubygems/test_gem_builder.rb +0 -44
- data/test/rubygems/test_gem_doc_manager.rb +0 -32
- data/test/rubygems/test_gem_ext_builder.rb +0 -58
- data/test/rubygems/test_gem_format.rb +0 -88
- data/test/rubygems/test_gem_gem_path_searcher.rb +0 -94
- data/test/rubygems/test_gem_package_tar_input.rb +0 -129
- data/test/rubygems/test_gem_package_tar_output.rb +0 -101
- data/test/rubygems/test_gem_source_index.rb +0 -250
- data/util/update_bundled_ca_certificates.rb +0 -103
@@ -1,4 +1,5 @@
|
|
1
1
|
##
|
2
|
+
#
|
2
3
|
# Gem::PathSupport facilitates the GEM_HOME and GEM_PATH environment settings
|
3
4
|
# to the rest of RubyGems.
|
4
5
|
#
|
@@ -42,16 +43,18 @@ class Gem::PathSupport
|
|
42
43
|
# Set the Gem search path (as reported by Gem.path).
|
43
44
|
|
44
45
|
def path=(gpaths)
|
45
|
-
|
46
|
+
# FIX: it should be [home, *path], not [*path, home]
|
47
|
+
|
48
|
+
gem_path = []
|
46
49
|
|
47
50
|
# FIX: I can't tell wtf this is doing.
|
48
51
|
gpaths ||= (ENV['GEM_PATH'] || "").empty? ? nil : ENV["GEM_PATH"]
|
49
52
|
|
50
|
-
if gpaths
|
51
|
-
if gpaths.kind_of?(Array)
|
52
|
-
gem_path.
|
53
|
+
if gpaths
|
54
|
+
if gpaths.kind_of?(Array)
|
55
|
+
gem_path = gpaths.dup
|
53
56
|
else
|
54
|
-
gem_path
|
57
|
+
gem_path = gpaths.split(Gem.path_separator)
|
55
58
|
end
|
56
59
|
|
57
60
|
if File::ALT_SEPARATOR then
|
@@ -59,10 +62,14 @@ class Gem::PathSupport
|
|
59
62
|
this_path.gsub File::ALT_SEPARATOR, File::SEPARATOR
|
60
63
|
end
|
61
64
|
end
|
65
|
+
|
66
|
+
gem_path << @home
|
62
67
|
else
|
63
|
-
gem_path
|
68
|
+
gem_path = Gem.default_path + [@home]
|
64
69
|
|
65
|
-
|
70
|
+
if defined?(APPLE_GEM_HOME)
|
71
|
+
gem_path << APPLE_GEM_HOME
|
72
|
+
end
|
66
73
|
end
|
67
74
|
|
68
75
|
@path = gem_path.uniq
|
data/lib/rubygems/platform.rb
CHANGED
@@ -21,7 +21,8 @@ class Gem::Platform
|
|
21
21
|
|
22
22
|
def self.match(platform)
|
23
23
|
Gem.platforms.any? do |local_platform|
|
24
|
-
platform.nil? or
|
24
|
+
platform.nil? or
|
25
|
+
local_platform == platform or
|
25
26
|
(local_platform != Gem::Platform::RUBY and local_platform =~ platform)
|
26
27
|
end
|
27
28
|
end
|
@@ -65,28 +66,28 @@ class Gem::Platform
|
|
65
66
|
@cpu, os = nil, cpu if os.nil? # legacy jruby
|
66
67
|
|
67
68
|
@os, @version = case os
|
68
|
-
when /aix(\d+)
|
69
|
-
when /cygwin/ then
|
70
|
-
when /darwin(\d+)?/ then
|
71
|
-
when /^macruby$/ then
|
72
|
-
when /freebsd(\d+)
|
73
|
-
when /hpux(\d+)
|
74
|
-
when /^java$/, /^jruby$/ then
|
75
|
-
when /^java([\d.]*)/ then
|
76
|
-
when /^dotnet$/ then
|
77
|
-
when /^dotnet([\d.]*)/ then
|
78
|
-
when /linux/ then
|
79
|
-
when /mingw32/ then
|
69
|
+
when /aix(\d+)?/ then [ 'aix', $1 ]
|
70
|
+
when /cygwin/ then [ 'cygwin', nil ]
|
71
|
+
when /darwin(\d+)?/ then [ 'darwin', $1 ]
|
72
|
+
when /^macruby$/ then [ 'macruby', nil ]
|
73
|
+
when /freebsd(\d+)?/ then [ 'freebsd', $1 ]
|
74
|
+
when /hpux(\d+)?/ then [ 'hpux', $1 ]
|
75
|
+
when /^java$/, /^jruby$/ then [ 'java', nil ]
|
76
|
+
when /^java([\d.]*)/ then [ 'java', $1 ]
|
77
|
+
when /^dotnet$/ then [ 'dotnet', nil ]
|
78
|
+
when /^dotnet([\d.]*)/ then [ 'dotnet', $1 ]
|
79
|
+
when /linux/ then [ 'linux', $1 ]
|
80
|
+
when /mingw32/ then [ 'mingw32', nil ]
|
80
81
|
when /(mswin\d+)(\_(\d+))?/ then
|
81
82
|
os, version = $1, $3
|
82
83
|
@cpu = 'x86' if @cpu.nil? and os =~ /32$/
|
83
84
|
[os, version]
|
84
|
-
when /netbsdelf/ then
|
85
|
-
when /openbsd(\d+\.\d+)
|
86
|
-
when /solaris(\d+\.\d+)
|
85
|
+
when /netbsdelf/ then [ 'netbsdelf', nil ]
|
86
|
+
when /openbsd(\d+\.\d+)?/ then [ 'openbsd', $1 ]
|
87
|
+
when /solaris(\d+\.\d+)?/ then [ 'solaris', $1 ]
|
87
88
|
# test
|
88
|
-
when /^(\w+_platform)(\d+)
|
89
|
-
else
|
89
|
+
when /^(\w+_platform)(\d+)?/ then [ $1, $2 ]
|
90
|
+
else [ 'unknown', nil ]
|
90
91
|
end
|
91
92
|
when Gem::Platform then
|
92
93
|
@cpu = arch.cpu
|
@@ -109,10 +110,6 @@ class Gem::Platform
|
|
109
110
|
to_a.compact.join '-'
|
110
111
|
end
|
111
112
|
|
112
|
-
def empty?
|
113
|
-
to_s.empty?
|
114
|
-
end
|
115
|
-
|
116
113
|
##
|
117
114
|
# Is +other+ equal to this platform? Two platforms are equal if they have
|
118
115
|
# the same CPU, OS and version.
|
@@ -186,9 +183,5 @@ class Gem::Platform
|
|
186
183
|
# This will be replaced with Gem::Platform::local.
|
187
184
|
|
188
185
|
CURRENT = 'current'
|
189
|
-
|
190
|
-
extend Gem::Deprecate
|
191
|
-
|
192
|
-
deprecate :empty?, :none, 2011, 11
|
193
186
|
end
|
194
187
|
|
@@ -0,0 +1,316 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/user_interaction'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
begin
|
6
|
+
gem 'rdoc'
|
7
|
+
rescue Gem::LoadError
|
8
|
+
# swallow
|
9
|
+
else
|
10
|
+
# This will force any deps that 'rdoc' might have
|
11
|
+
# (such as json) that are ambigious to be activated, which
|
12
|
+
# is important because we end up using Specification.reset
|
13
|
+
# and we don't want the warning it pops out.
|
14
|
+
Gem.finish_resolve
|
15
|
+
end
|
16
|
+
|
17
|
+
loaded_hook = false
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'rdoc/rubygems_hook'
|
21
|
+
loaded_hook = true
|
22
|
+
module Gem
|
23
|
+
RDoc = RDoc::RubygemsHook
|
24
|
+
end
|
25
|
+
rescue LoadError
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Gem::RDoc provides methods to generate RDoc and ri data for installed gems.
|
30
|
+
# It works for RDoc 1.0.1 (in Ruby 1.8) up to RDoc 3.6.
|
31
|
+
#
|
32
|
+
# This implementation is considered obsolete. The RDoc project is the
|
33
|
+
# appropriate location to find this functionality. This file provides the
|
34
|
+
# hooks to load RDoc generation code from the "rdoc" gem and a fallback in
|
35
|
+
# case the installed version of RDoc does not have them.
|
36
|
+
|
37
|
+
class Gem::RDoc # :nodoc: all
|
38
|
+
|
39
|
+
include Gem::UserInteraction
|
40
|
+
|
41
|
+
@rdoc_version = nil
|
42
|
+
@specs = []
|
43
|
+
|
44
|
+
##
|
45
|
+
# Force installation of documentation?
|
46
|
+
|
47
|
+
attr_accessor :force
|
48
|
+
|
49
|
+
##
|
50
|
+
# Generate rdoc?
|
51
|
+
|
52
|
+
attr_accessor :generate_rdoc
|
53
|
+
|
54
|
+
##
|
55
|
+
# Generate ri data?
|
56
|
+
|
57
|
+
attr_accessor :generate_ri
|
58
|
+
|
59
|
+
class << self
|
60
|
+
|
61
|
+
##
|
62
|
+
# Loaded version of RDoc. Set by ::load_rdoc
|
63
|
+
|
64
|
+
attr_reader :rdoc_version
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Post installs hook that generates documentation for each specification in
|
70
|
+
# +specs+
|
71
|
+
|
72
|
+
def self.generation_hook installer, specs
|
73
|
+
types = installer.document
|
74
|
+
|
75
|
+
generate_rdoc = types.include? 'rdoc'
|
76
|
+
generate_ri = types.include? 'ri'
|
77
|
+
|
78
|
+
specs.each do |spec|
|
79
|
+
new(spec, generate_rdoc, generate_ri).generate
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Loads the RDoc generator
|
85
|
+
|
86
|
+
def self.load_rdoc
|
87
|
+
return if @rdoc_version
|
88
|
+
|
89
|
+
begin
|
90
|
+
require 'rdoc/rdoc'
|
91
|
+
|
92
|
+
@rdoc_version = if ::RDoc.const_defined? :VERSION then
|
93
|
+
Gem::Version.new ::RDoc::VERSION
|
94
|
+
else
|
95
|
+
Gem::Version.new '1.0.1'
|
96
|
+
end
|
97
|
+
|
98
|
+
rescue LoadError => e
|
99
|
+
raise Gem::DocumentError, "RDoc is not installed: #{e}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Creates a new documentation generator for +spec+. RDoc and ri data
|
105
|
+
# generation can be enabled or disabled through +generate_rdoc+ and
|
106
|
+
# +generate_ri+ respectively.
|
107
|
+
#
|
108
|
+
# Only +generate_ri+ is enabled by default.
|
109
|
+
|
110
|
+
def initialize spec, generate_rdoc = false, generate_ri = true
|
111
|
+
@doc_dir = spec.doc_dir
|
112
|
+
@file_info = nil
|
113
|
+
@force = false
|
114
|
+
@rdoc = nil
|
115
|
+
@spec = spec
|
116
|
+
|
117
|
+
@generate_rdoc = generate_rdoc
|
118
|
+
@generate_ri = generate_ri
|
119
|
+
|
120
|
+
@rdoc_dir = spec.doc_dir 'rdoc'
|
121
|
+
@ri_dir = spec.doc_dir 'ri'
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Removes legacy rdoc arguments from +args+
|
126
|
+
|
127
|
+
def delete_legacy_args args
|
128
|
+
args.delete '--inline-source'
|
129
|
+
args.delete '--promiscuous'
|
130
|
+
args.delete '-p'
|
131
|
+
args.delete '--one-file'
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Generates documentation using the named +generator+ ("darkfish" or "ri")
|
136
|
+
# and following the given +options+.
|
137
|
+
#
|
138
|
+
# Documentation will be generated into +destination+
|
139
|
+
|
140
|
+
def document generator, options, destination
|
141
|
+
options = options.dup
|
142
|
+
options.exclude ||= [] # TODO maybe move to RDoc::Options#finish
|
143
|
+
options.setup_generator generator
|
144
|
+
options.op_dir = destination
|
145
|
+
options.finish
|
146
|
+
|
147
|
+
@rdoc.options = options
|
148
|
+
@rdoc.generator = options.generator.new options
|
149
|
+
|
150
|
+
say "Installing #{generator} documentation for #{@spec.full_name}"
|
151
|
+
|
152
|
+
FileUtils.mkdir_p options.op_dir
|
153
|
+
|
154
|
+
Dir.chdir options.op_dir do
|
155
|
+
begin
|
156
|
+
@rdoc.class.current = @rdoc
|
157
|
+
@rdoc.generator.generate @file_info
|
158
|
+
ensure
|
159
|
+
@rdoc.class.current = nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Generates RDoc and ri data
|
166
|
+
|
167
|
+
def generate
|
168
|
+
return unless @generate_ri or @generate_rdoc
|
169
|
+
|
170
|
+
setup
|
171
|
+
|
172
|
+
if Gem::Requirement.new('< 3').satisfied_by? self.class.rdoc_version then
|
173
|
+
generate_legacy
|
174
|
+
else
|
175
|
+
::RDoc::TopLevel.reset # TODO ::RDoc::RDoc.reset
|
176
|
+
::RDoc::Parser::C.reset
|
177
|
+
|
178
|
+
options = ::RDoc::Options.new
|
179
|
+
options.default_title = "#{@spec.full_name} Documentation"
|
180
|
+
options.files = []
|
181
|
+
options.files.push(*@spec.require_paths)
|
182
|
+
options.files.push(*@spec.extra_rdoc_files)
|
183
|
+
|
184
|
+
args = @spec.rdoc_options
|
185
|
+
|
186
|
+
case config_args = Gem.configuration[:rdoc]
|
187
|
+
when String then
|
188
|
+
args = args.concat config_args.split
|
189
|
+
when Array then
|
190
|
+
args = args.concat config_args
|
191
|
+
end
|
192
|
+
|
193
|
+
delete_legacy_args args
|
194
|
+
options.parse args
|
195
|
+
options.quiet = !Gem.configuration.really_verbose
|
196
|
+
|
197
|
+
@rdoc = new_rdoc
|
198
|
+
@rdoc.options = options
|
199
|
+
|
200
|
+
Dir.chdir @spec.full_gem_path do
|
201
|
+
@file_info = @rdoc.parse_files options.files
|
202
|
+
end
|
203
|
+
|
204
|
+
document 'ri', options, @ri_dir if
|
205
|
+
@generate_ri and (@force or not File.exist? @ri_dir)
|
206
|
+
|
207
|
+
document 'darkfish', options, @rdoc_dir if
|
208
|
+
@generate_rdoc and (@force or not File.exist? @rdoc_dir)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
##
|
213
|
+
# Generates RDoc and ri data for legacy RDoc versions. This method will not
|
214
|
+
# exist in future versions.
|
215
|
+
|
216
|
+
def generate_legacy
|
217
|
+
if @generate_rdoc then
|
218
|
+
FileUtils.rm_rf @rdoc_dir
|
219
|
+
say "Installing RDoc documentation for #{@spec.full_name}"
|
220
|
+
legacy_rdoc '--op', @rdoc_dir
|
221
|
+
end
|
222
|
+
|
223
|
+
if @generate_ri then
|
224
|
+
FileUtils.rm_rf @ri_dir
|
225
|
+
say "Installing ri documentation for #{@spec.full_name}"
|
226
|
+
legacy_rdoc '--ri', '--op', @ri_dir
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Generates RDoc using a legacy version of RDoc from the ARGV-like +args+.
|
232
|
+
# This method will not exist in future versions.
|
233
|
+
|
234
|
+
def legacy_rdoc *args
|
235
|
+
args << @spec.rdoc_options
|
236
|
+
args << '--quiet'
|
237
|
+
args << @spec.require_paths.clone
|
238
|
+
args << @spec.extra_rdoc_files
|
239
|
+
args << '--title' << "#{@spec.full_name} Documentation"
|
240
|
+
args = args.flatten.map do |arg| arg.to_s end
|
241
|
+
|
242
|
+
delete_legacy_args args if
|
243
|
+
Gem::Requirement.new('>= 2.4.0') =~ self.class.rdoc_version
|
244
|
+
|
245
|
+
r = new_rdoc
|
246
|
+
say "rdoc #{args.join ' '}" if Gem.configuration.really_verbose
|
247
|
+
|
248
|
+
Dir.chdir @spec.full_gem_path do
|
249
|
+
begin
|
250
|
+
r.document args
|
251
|
+
rescue Errno::EACCES => e
|
252
|
+
dirname = File.dirname e.message.split("-")[1].strip
|
253
|
+
raise Gem::FilePermissionError, dirname
|
254
|
+
rescue Interrupt => e
|
255
|
+
raise e
|
256
|
+
rescue Exception => ex
|
257
|
+
alert_error "While generating documentation for #{@spec.full_name}"
|
258
|
+
ui.errs.puts "... MESSAGE: #{ex}"
|
259
|
+
ui.errs.puts "... RDOC args: #{args.join(' ')}"
|
260
|
+
ui.backtrace ex
|
261
|
+
ui.errs.puts "(continuing with the rest of the installation)"
|
262
|
+
ensure
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# #new_rdoc creates a new RDoc instance. This method is provided only to
|
269
|
+
# make testing easier.
|
270
|
+
|
271
|
+
def new_rdoc
|
272
|
+
::RDoc::RDoc.new
|
273
|
+
end
|
274
|
+
|
275
|
+
##
|
276
|
+
# Is rdoc documentation installed?
|
277
|
+
|
278
|
+
def rdoc_installed?
|
279
|
+
File.exist? @rdoc_dir
|
280
|
+
end
|
281
|
+
|
282
|
+
##
|
283
|
+
# Removes generated RDoc and ri data
|
284
|
+
|
285
|
+
def remove
|
286
|
+
base_dir = @spec.base_dir
|
287
|
+
|
288
|
+
raise Gem::FilePermissionError, base_dir unless File.writable? base_dir
|
289
|
+
|
290
|
+
FileUtils.rm_rf @rdoc_dir
|
291
|
+
FileUtils.rm_rf @ri_dir
|
292
|
+
end
|
293
|
+
|
294
|
+
##
|
295
|
+
# Is ri data installed?
|
296
|
+
|
297
|
+
def ri_installed?
|
298
|
+
File.exist? @ri_dir
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# Prepares the spec for documentation generation
|
303
|
+
|
304
|
+
def setup
|
305
|
+
self.class.load_rdoc
|
306
|
+
|
307
|
+
raise Gem::FilePermissionError, @doc_dir if
|
308
|
+
File.exist?(@doc_dir) and not File.writable?(@doc_dir)
|
309
|
+
|
310
|
+
FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir
|
311
|
+
end
|
312
|
+
|
313
|
+
end unless loaded_hook
|
314
|
+
|
315
|
+
Gem.done_installing(&Gem::RDoc.method(:generation_hook))
|
316
|
+
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rubygems/user_interaction'
|
3
3
|
require 'uri'
|
4
|
+
require 'resolv'
|
4
5
|
|
5
6
|
##
|
6
7
|
# RemoteFetcher handles the details of fetching gems and gem information from
|
@@ -8,8 +9,6 @@ require 'uri'
|
|
8
9
|
|
9
10
|
class Gem::RemoteFetcher
|
10
11
|
|
11
|
-
BuiltinSSLCerts = File.expand_path("./ssl_certs/*.pem", File.dirname(__FILE__))
|
12
|
-
|
13
12
|
include Gem::UserInteraction
|
14
13
|
|
15
14
|
##
|
@@ -34,6 +33,13 @@ class Gem::RemoteFetcher
|
|
34
33
|
|
35
34
|
end
|
36
35
|
|
36
|
+
##
|
37
|
+
# A FetchError that indicates that the reason for not being
|
38
|
+
# able to fetch data was that the host could not be contacted
|
39
|
+
|
40
|
+
class UnknownHostError < FetchError
|
41
|
+
end
|
42
|
+
|
37
43
|
@fetcher = nil
|
38
44
|
|
39
45
|
##
|
@@ -53,8 +59,11 @@ class Gem::RemoteFetcher
|
|
53
59
|
# * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER,
|
54
60
|
# HTTP_PROXY_PASS)
|
55
61
|
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
|
62
|
+
#
|
63
|
+
# +dns+: An object to use for DNS resolution of the API endpoint.
|
64
|
+
# By default, use Resolv::DNS.
|
56
65
|
|
57
|
-
def initialize(proxy =
|
66
|
+
def initialize(proxy=nil, dns=Resolv::DNS.new)
|
58
67
|
require 'net/http'
|
59
68
|
require 'stringio'
|
60
69
|
require 'time'
|
@@ -72,6 +81,27 @@ class Gem::RemoteFetcher
|
|
72
81
|
else URI.parse(proxy)
|
73
82
|
end
|
74
83
|
@user_agent = user_agent
|
84
|
+
@env_no_proxy = get_no_proxy_from_env
|
85
|
+
|
86
|
+
@dns = dns
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
#
|
91
|
+
# Given a source at +uri+, calculate what hostname to actually
|
92
|
+
# connect to query the data for it.
|
93
|
+
|
94
|
+
def api_endpoint(uri)
|
95
|
+
host = uri.host
|
96
|
+
|
97
|
+
begin
|
98
|
+
res = @dns.getresource "_rubygems._tcp.#{host}",
|
99
|
+
Resolv::DNS::Resource::IN::SRV
|
100
|
+
rescue Resolv::ResolvError
|
101
|
+
uri
|
102
|
+
else
|
103
|
+
URI.parse "#{res.target}#{uri.path}"
|
104
|
+
end
|
75
105
|
end
|
76
106
|
|
77
107
|
##
|
@@ -82,14 +112,13 @@ class Gem::RemoteFetcher
|
|
82
112
|
# larger, more emcompassing effort. -erikh
|
83
113
|
|
84
114
|
def download_to_cache dependency
|
85
|
-
found = Gem::SpecFetcher.fetcher.
|
86
|
-
dependency.prerelease?
|
115
|
+
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dependency
|
87
116
|
|
88
117
|
return if found.empty?
|
89
118
|
|
90
|
-
spec,
|
119
|
+
spec, source = found.sort_by { |(s,_)| s.version }.last
|
91
120
|
|
92
|
-
download spec,
|
121
|
+
download spec, source.uri.to_s
|
93
122
|
end
|
94
123
|
|
95
124
|
##
|
@@ -100,11 +129,14 @@ class Gem::RemoteFetcher
|
|
100
129
|
def download(spec, source_uri, install_dir = Gem.dir)
|
101
130
|
Gem.ensure_gem_subdirectories(install_dir) rescue nil
|
102
131
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
132
|
+
cache_dir =
|
133
|
+
if Dir.pwd == install_dir then # see fetch_command
|
134
|
+
install_dir
|
135
|
+
elsif File.writable? install_dir then
|
136
|
+
File.join install_dir, "cache"
|
137
|
+
else
|
138
|
+
File.join Gem.user_dir, "cache"
|
139
|
+
end
|
108
140
|
|
109
141
|
gem_file_name = File.basename spec.cache_file
|
110
142
|
local_gem_path = File.join cache_dir, gem_file_name
|
@@ -123,6 +155,8 @@ class Gem::RemoteFetcher
|
|
123
155
|
# URI.parse gets confused by MS Windows paths with forward slashes.
|
124
156
|
scheme = nil if scheme =~ /^[a-z]$/i
|
125
157
|
|
158
|
+
# REFACTOR: split this up and dispatch on scheme (eg download_http)
|
159
|
+
# REFACTOR: be sure to clean up fake fetcher when you do this... cleaner
|
126
160
|
case scheme
|
127
161
|
when 'http', 'https' then
|
128
162
|
unless File.exist? local_gem_path then
|
@@ -132,7 +166,7 @@ class Gem::RemoteFetcher
|
|
132
166
|
|
133
167
|
remote_gem_path = source_uri + "gems/#{gem_file_name}"
|
134
168
|
|
135
|
-
|
169
|
+
self.cache_update_path remote_gem_path, local_gem_path
|
136
170
|
rescue Gem::RemoteFetcher::FetchError
|
137
171
|
raise if spec.original_platform == spec.platform
|
138
172
|
|
@@ -143,11 +177,7 @@ class Gem::RemoteFetcher
|
|
143
177
|
|
144
178
|
remote_gem_path = source_uri + "gems/#{alternate_name}"
|
145
179
|
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
|
-
File.open local_gem_path, 'wb' do |fp|
|
150
|
-
fp.write gem
|
180
|
+
self.cache_update_path remote_gem_path, local_gem_path
|
151
181
|
end
|
152
182
|
end
|
153
183
|
when 'file' then
|
@@ -184,7 +214,7 @@ class Gem::RemoteFetcher
|
|
184
214
|
say "Using local gem #{local_gem_path}" if
|
185
215
|
Gem.configuration.really_verbose
|
186
216
|
else
|
187
|
-
raise
|
217
|
+
raise ArgumentError, "unsupported URI scheme #{source_uri.scheme}"
|
188
218
|
end
|
189
219
|
|
190
220
|
local_gem_path
|
@@ -232,18 +262,54 @@ class Gem::RemoteFetcher
|
|
232
262
|
uri = URI.parse uri unless URI::Generic === uri
|
233
263
|
|
234
264
|
raise ArgumentError, "bad uri: #{uri}" unless uri
|
235
|
-
|
236
|
-
|
265
|
+
|
266
|
+
unless uri.scheme
|
267
|
+
raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}"
|
268
|
+
end
|
237
269
|
|
238
270
|
data = send "fetch_#{uri.scheme}", uri, mtime, head
|
239
|
-
|
271
|
+
|
272
|
+
if data and !head and uri.to_s =~ /gz$/
|
273
|
+
begin
|
274
|
+
data = Gem.gunzip data
|
275
|
+
rescue Zlib::GzipFile::Error
|
276
|
+
raise FetchError.new("server did not return a valid file", uri.to_s)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
240
280
|
data
|
241
281
|
rescue FetchError
|
242
282
|
raise
|
243
283
|
rescue Timeout::Error
|
244
|
-
raise
|
284
|
+
raise UnknownHostError.new('timed out', uri.to_s)
|
245
285
|
rescue IOError, SocketError, SystemCallError => e
|
246
|
-
|
286
|
+
if e.message =~ /getaddrinfo/
|
287
|
+
raise UnknownHostError.new('no such name', uri.to_s)
|
288
|
+
else
|
289
|
+
raise FetchError.new("#{e.class}: #{e}", uri.to_s)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
##
|
294
|
+
# Downloads +uri+ to +path+ if necessary. If no path is given, it just
|
295
|
+
# passes the data.
|
296
|
+
|
297
|
+
def cache_update_path(uri, path = nil)
|
298
|
+
mtime = path && File.stat(path).mtime rescue nil
|
299
|
+
|
300
|
+
if mtime && Net::HTTPNotModified === fetch_path(uri, mtime, true)
|
301
|
+
Gem.read_binary(path)
|
302
|
+
else
|
303
|
+
data = fetch_path(uri)
|
304
|
+
|
305
|
+
if path
|
306
|
+
open(path, 'wb') do |io|
|
307
|
+
io.write data
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
data
|
312
|
+
end
|
247
313
|
end
|
248
314
|
|
249
315
|
##
|
@@ -273,6 +339,17 @@ class Gem::RemoteFetcher
|
|
273
339
|
URI
|
274
340
|
end
|
275
341
|
|
342
|
+
##
|
343
|
+
# Returns list of no_proxy entries (if any) from the environment
|
344
|
+
|
345
|
+
def get_no_proxy_from_env
|
346
|
+
env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
|
347
|
+
|
348
|
+
return [] if env_no_proxy.nil? or env_no_proxy.empty?
|
349
|
+
|
350
|
+
env_no_proxy.split(/\s*,\s*/)
|
351
|
+
end
|
352
|
+
|
276
353
|
##
|
277
354
|
# Returns an HTTP proxy URI if one is set in the environment variables.
|
278
355
|
|
@@ -296,7 +373,7 @@ class Gem::RemoteFetcher
|
|
296
373
|
# Normalize the URI by adding "http://" if it is missing.
|
297
374
|
|
298
375
|
def normalize_uri(uri)
|
299
|
-
(uri =~ /^(https?|ftp|file):/) ? uri : "http://#{uri}"
|
376
|
+
(uri =~ /^(https?|ftp|file):/i) ? uri : "http://#{uri}"
|
300
377
|
end
|
301
378
|
|
302
379
|
##
|
@@ -306,7 +383,7 @@ class Gem::RemoteFetcher
|
|
306
383
|
def connection_for(uri)
|
307
384
|
net_http_args = [uri.host, uri.port]
|
308
385
|
|
309
|
-
if @proxy_uri then
|
386
|
+
if @proxy_uri and not no_proxy?(uri.host) then
|
310
387
|
net_http_args += [
|
311
388
|
@proxy_uri.host,
|
312
389
|
@proxy_uri.port,
|
@@ -319,37 +396,23 @@ class Gem::RemoteFetcher
|
|
319
396
|
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
|
320
397
|
connection = @connections[connection_id]
|
321
398
|
|
322
|
-
if https?(uri) and
|
399
|
+
if https?(uri) and not connection.started? then
|
323
400
|
configure_connection_for_https(connection)
|
324
|
-
|
325
|
-
# Don't refactor this with the else branch. We don't want the
|
326
|
-
# http-only code path to not depend on anything in OpenSSL.
|
327
|
-
#
|
328
|
-
begin
|
329
|
-
connection.start
|
330
|
-
rescue OpenSSL::SSL::SSLError, Errno::EHOSTDOWN => e
|
331
|
-
raise FetchError.new(e.message, uri)
|
332
|
-
end
|
333
|
-
else
|
334
|
-
begin
|
335
|
-
connection.start unless connection.started?
|
336
|
-
rescue Errno::EHOSTDOWN => e
|
337
|
-
raise FetchError.new(e.message, uri)
|
338
|
-
end
|
339
401
|
end
|
340
402
|
|
403
|
+
connection.start unless connection.started?
|
404
|
+
|
341
405
|
connection
|
406
|
+
rescue OpenSSL::SSL::SSLError, Errno::EHOSTDOWN => e
|
407
|
+
raise FetchError.new(e.message, uri)
|
342
408
|
end
|
343
409
|
|
344
410
|
def configure_connection_for_https(connection)
|
345
411
|
require 'net/https'
|
346
|
-
|
347
412
|
connection.use_ssl = true
|
348
413
|
connection.verify_mode =
|
349
414
|
Gem.configuration.ssl_verify_mode || OpenSSL::SSL::VERIFY_PEER
|
350
|
-
|
351
415
|
store = OpenSSL::X509::Store.new
|
352
|
-
|
353
416
|
if Gem.configuration.ssl_ca_cert
|
354
417
|
if File.directory? Gem.configuration.ssl_ca_cert
|
355
418
|
store.add_path Gem.configuration.ssl_ca_cert
|
@@ -360,12 +423,12 @@ class Gem::RemoteFetcher
|
|
360
423
|
store.set_default_paths
|
361
424
|
add_rubygems_trusted_certs(store)
|
362
425
|
end
|
363
|
-
|
364
426
|
connection.cert_store = store
|
365
427
|
end
|
366
428
|
|
367
429
|
def add_rubygems_trusted_certs(store)
|
368
|
-
|
430
|
+
pattern = File.expand_path("./ssl_certs/*.pem", File.dirname(__FILE__))
|
431
|
+
Dir.glob(pattern).each do |ssl_cert_file|
|
369
432
|
store.add_file ssl_cert_file
|
370
433
|
end
|
371
434
|
end
|
@@ -378,13 +441,13 @@ class Gem::RemoteFetcher
|
|
378
441
|
end
|
379
442
|
end
|
380
443
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
444
|
+
def no_proxy? host
|
445
|
+
host = host.downcase
|
446
|
+
@env_no_proxy.each do |pattern|
|
447
|
+
pattern = pattern.downcase
|
448
|
+
return true if host[-pattern.length, pattern.length ] == pattern
|
449
|
+
end
|
450
|
+
return false
|
388
451
|
end
|
389
452
|
|
390
453
|
##
|