libgems 0.0.1
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.
- data/ChangeLog +5811 -0
- data/History.txt +887 -0
- data/LICENSE.txt +51 -0
- data/README.md +87 -0
- data/Rakefile +113 -0
- data/lib/gauntlet_libgems.rb +50 -0
- data/lib/libgems.rb +1246 -0
- data/lib/libgems/builder.rb +102 -0
- data/lib/libgems/command.rb +534 -0
- data/lib/libgems/command_manager.rb +182 -0
- data/lib/libgems/commands/build_command.rb +53 -0
- data/lib/libgems/commands/cert_command.rb +86 -0
- data/lib/libgems/commands/check_command.rb +80 -0
- data/lib/libgems/commands/cleanup_command.rb +106 -0
- data/lib/libgems/commands/contents_command.rb +98 -0
- data/lib/libgems/commands/dependency_command.rb +195 -0
- data/lib/libgems/commands/environment_command.rb +133 -0
- data/lib/libgems/commands/fetch_command.rb +67 -0
- data/lib/libgems/commands/generate_index_command.rb +133 -0
- data/lib/libgems/commands/help_command.rb +172 -0
- data/lib/libgems/commands/install_command.rb +178 -0
- data/lib/libgems/commands/list_command.rb +35 -0
- data/lib/libgems/commands/lock_command.rb +110 -0
- data/lib/libgems/commands/mirror_command.rb +111 -0
- data/lib/libgems/commands/outdated_command.rb +33 -0
- data/lib/libgems/commands/owner_command.rb +75 -0
- data/lib/libgems/commands/pristine_command.rb +93 -0
- data/lib/libgems/commands/push_command.rb +56 -0
- data/lib/libgems/commands/query_command.rb +280 -0
- data/lib/libgems/commands/rdoc_command.rb +91 -0
- data/lib/libgems/commands/search_command.rb +31 -0
- data/lib/libgems/commands/server_command.rb +86 -0
- data/lib/libgems/commands/sources_command.rb +157 -0
- data/lib/libgems/commands/specification_command.rb +125 -0
- data/lib/libgems/commands/stale_command.rb +27 -0
- data/lib/libgems/commands/uninstall_command.rb +83 -0
- data/lib/libgems/commands/unpack_command.rb +121 -0
- data/lib/libgems/commands/update_command.rb +160 -0
- data/lib/libgems/commands/which_command.rb +86 -0
- data/lib/libgems/config_file.rb +345 -0
- data/lib/libgems/custom_require.rb +44 -0
- data/lib/libgems/defaults.rb +101 -0
- data/lib/libgems/dependency.rb +227 -0
- data/lib/libgems/dependency_installer.rb +286 -0
- data/lib/libgems/dependency_list.rb +208 -0
- data/lib/libgems/doc_manager.rb +242 -0
- data/lib/libgems/errors.rb +35 -0
- data/lib/libgems/exceptions.rb +91 -0
- data/lib/libgems/ext.rb +18 -0
- data/lib/libgems/ext/builder.rb +56 -0
- data/lib/libgems/ext/configure_builder.rb +25 -0
- data/lib/libgems/ext/ext_conf_builder.rb +24 -0
- data/lib/libgems/ext/rake_builder.rb +39 -0
- data/lib/libgems/format.rb +81 -0
- data/lib/libgems/gem_openssl.rb +92 -0
- data/lib/libgems/gem_path_searcher.rb +100 -0
- data/lib/libgems/gem_runner.rb +79 -0
- data/lib/libgems/gemcutter_utilities.rb +49 -0
- data/lib/libgems/indexer.rb +720 -0
- data/lib/libgems/install_update_options.rb +125 -0
- data/lib/libgems/installer.rb +604 -0
- data/lib/libgems/local_remote_options.rb +135 -0
- data/lib/libgems/old_format.rb +153 -0
- data/lib/libgems/package.rb +97 -0
- data/lib/libgems/package/f_sync_dir.rb +23 -0
- data/lib/libgems/package/tar_header.rb +266 -0
- data/lib/libgems/package/tar_input.rb +222 -0
- data/lib/libgems/package/tar_output.rb +144 -0
- data/lib/libgems/package/tar_reader.rb +106 -0
- data/lib/libgems/package/tar_reader/entry.rb +141 -0
- data/lib/libgems/package/tar_writer.rb +241 -0
- data/lib/libgems/package_task.rb +126 -0
- data/lib/libgems/platform.rb +183 -0
- data/lib/libgems/remote_fetcher.rb +414 -0
- data/lib/libgems/require_paths_builder.rb +18 -0
- data/lib/libgems/requirement.rb +153 -0
- data/lib/libgems/security.rb +814 -0
- data/lib/libgems/server.rb +872 -0
- data/lib/libgems/source_index.rb +597 -0
- data/lib/libgems/source_info_cache.rb +395 -0
- data/lib/libgems/source_info_cache_entry.rb +56 -0
- data/lib/libgems/spec_fetcher.rb +337 -0
- data/lib/libgems/specification.rb +1487 -0
- data/lib/libgems/test_utilities.rb +147 -0
- data/lib/libgems/text.rb +65 -0
- data/lib/libgems/uninstaller.rb +278 -0
- data/lib/libgems/user_interaction.rb +527 -0
- data/lib/libgems/validator.rb +240 -0
- data/lib/libgems/version.rb +316 -0
- data/lib/libgems/version_option.rb +65 -0
- data/lib/rbconfig/datadir.rb +20 -0
- data/test/bogussources.rb +8 -0
- data/test/data/gem-private_key.pem +27 -0
- data/test/data/gem-public_cert.pem +20 -0
- data/test/fake_certlib/openssl.rb +7 -0
- data/test/foo/discover.rb +0 -0
- data/test/gem_installer_test_case.rb +97 -0
- data/test/gem_package_tar_test_case.rb +132 -0
- data/test/gemutilities.rb +605 -0
- data/test/insure_session.rb +43 -0
- data/test/mockgemui.rb +56 -0
- data/test/plugin/exception/libgems_plugin.rb +2 -0
- data/test/plugin/load/libgems_plugin.rb +1 -0
- data/test/plugin/standarderror/libgems_plugin.rb +2 -0
- data/test/private_key.pem +27 -0
- data/test/public_cert.pem +20 -0
- data/test/rubygems_plugin.rb +21 -0
- data/test/simple_gem.rb +66 -0
- data/test/test_config.rb +12 -0
- data/test/test_gem.rb +780 -0
- data/test/test_gem_builder.rb +27 -0
- data/test/test_gem_command.rb +178 -0
- data/test/test_gem_command_manager.rb +207 -0
- data/test/test_gem_commands_build_command.rb +74 -0
- data/test/test_gem_commands_cert_command.rb +124 -0
- data/test/test_gem_commands_check_command.rb +18 -0
- data/test/test_gem_commands_contents_command.rb +156 -0
- data/test/test_gem_commands_dependency_command.rb +216 -0
- data/test/test_gem_commands_environment_command.rb +144 -0
- data/test/test_gem_commands_fetch_command.rb +76 -0
- data/test/test_gem_commands_generate_index_command.rb +135 -0
- data/test/test_gem_commands_install_command.rb +315 -0
- data/test/test_gem_commands_list_command.rb +36 -0
- data/test/test_gem_commands_lock_command.rb +68 -0
- data/test/test_gem_commands_mirror_command.rb +60 -0
- data/test/test_gem_commands_outdated_command.rb +40 -0
- data/test/test_gem_commands_owner_command.rb +105 -0
- data/test/test_gem_commands_pristine_command.rb +108 -0
- data/test/test_gem_commands_push_command.rb +81 -0
- data/test/test_gem_commands_query_command.rb +426 -0
- data/test/test_gem_commands_server_command.rb +59 -0
- data/test/test_gem_commands_sources_command.rb +209 -0
- data/test/test_gem_commands_specification_command.rb +139 -0
- data/test/test_gem_commands_stale_command.rb +38 -0
- data/test/test_gem_commands_uninstall_command.rb +83 -0
- data/test/test_gem_commands_unpack_command.rb +199 -0
- data/test/test_gem_commands_update_command.rb +207 -0
- data/test/test_gem_commands_which_command.rb +66 -0
- data/test/test_gem_config_file.rb +287 -0
- data/test/test_gem_dependency.rb +149 -0
- data/test/test_gem_dependency_installer.rb +661 -0
- data/test/test_gem_dependency_list.rb +230 -0
- data/test/test_gem_doc_manager.rb +31 -0
- data/test/test_gem_ext_configure_builder.rb +84 -0
- data/test/test_gem_ext_ext_conf_builder.rb +173 -0
- data/test/test_gem_ext_rake_builder.rb +81 -0
- data/test/test_gem_format.rb +70 -0
- data/test/test_gem_gem_path_searcher.rb +78 -0
- data/test/test_gem_gem_runner.rb +45 -0
- data/test/test_gem_gemcutter_utilities.rb +103 -0
- data/test/test_gem_indexer.rb +673 -0
- data/test/test_gem_install_update_options.rb +68 -0
- data/test/test_gem_installer.rb +857 -0
- data/test/test_gem_local_remote_options.rb +97 -0
- data/test/test_gem_package_tar_header.rb +130 -0
- data/test/test_gem_package_tar_input.rb +112 -0
- data/test/test_gem_package_tar_output.rb +97 -0
- data/test/test_gem_package_tar_reader.rb +46 -0
- data/test/test_gem_package_tar_reader_entry.rb +109 -0
- data/test/test_gem_package_tar_writer.rb +144 -0
- data/test/test_gem_package_task.rb +59 -0
- data/test/test_gem_platform.rb +264 -0
- data/test/test_gem_remote_fetcher.rb +740 -0
- data/test/test_gem_requirement.rb +292 -0
- data/test/test_gem_server.rb +356 -0
- data/test/test_gem_silent_ui.rb +113 -0
- data/test/test_gem_source_index.rb +461 -0
- data/test/test_gem_spec_fetcher.rb +410 -0
- data/test/test_gem_specification.rb +1334 -0
- data/test/test_gem_stream_ui.rb +218 -0
- data/test/test_gem_text.rb +43 -0
- data/test/test_gem_uninstaller.rb +146 -0
- data/test/test_gem_validator.rb +63 -0
- data/test/test_gem_version.rb +181 -0
- data/test/test_gem_version_option.rb +89 -0
- data/test/test_kernel.rb +59 -0
- metadata +402 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Available list of platforms for targeting LibGems installations.
|
|
3
|
+
|
|
4
|
+
class LibGems::Platform
|
|
5
|
+
|
|
6
|
+
@local = nil
|
|
7
|
+
|
|
8
|
+
attr_accessor :cpu
|
|
9
|
+
|
|
10
|
+
attr_accessor :os
|
|
11
|
+
|
|
12
|
+
attr_accessor :version
|
|
13
|
+
|
|
14
|
+
def self.local
|
|
15
|
+
arch = LibGems::ConfigMap[:arch]
|
|
16
|
+
arch = "#{arch}_60" if arch =~ /mswin32$/
|
|
17
|
+
@local ||= new(arch)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.match(platform)
|
|
21
|
+
LibGems.platforms.any? do |local_platform|
|
|
22
|
+
platform.nil? or local_platform == platform or
|
|
23
|
+
(local_platform != LibGems::Platform::RUBY and local_platform =~ platform)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.new(arch) # :nodoc:
|
|
28
|
+
case arch
|
|
29
|
+
when LibGems::Platform::CURRENT then
|
|
30
|
+
LibGems::Platform.local
|
|
31
|
+
when LibGems::Platform::RUBY, nil, '' then
|
|
32
|
+
LibGems::Platform::RUBY
|
|
33
|
+
else
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def initialize(arch)
|
|
39
|
+
case arch
|
|
40
|
+
when Array then
|
|
41
|
+
@cpu, @os, @version = arch
|
|
42
|
+
when String then
|
|
43
|
+
arch = arch.split '-'
|
|
44
|
+
|
|
45
|
+
if arch.length > 2 and arch.last !~ /\d/ then # reassemble x86-linux-gnu
|
|
46
|
+
extra = arch.pop
|
|
47
|
+
arch.last << "-#{extra}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
cpu = arch.shift
|
|
51
|
+
|
|
52
|
+
@cpu = case cpu
|
|
53
|
+
when /i\d86/ then 'x86'
|
|
54
|
+
else cpu
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if arch.length == 2 and arch.last =~ /^\d+(\.\d+)?$/ then # for command-line
|
|
58
|
+
@os, @version = arch
|
|
59
|
+
return
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
os, = arch
|
|
63
|
+
@cpu, os = nil, cpu if os.nil? # legacy jruby
|
|
64
|
+
|
|
65
|
+
@os, @version = case os
|
|
66
|
+
when /aix(\d+)/ then [ 'aix', $1 ]
|
|
67
|
+
when /cygwin/ then [ 'cygwin', nil ]
|
|
68
|
+
when /darwin(\d+)?/ then [ 'darwin', $1 ]
|
|
69
|
+
when /freebsd(\d+)/ then [ 'freebsd', $1 ]
|
|
70
|
+
when /hpux(\d+)/ then [ 'hpux', $1 ]
|
|
71
|
+
when /^java$/, /^jruby$/ then [ 'java', nil ]
|
|
72
|
+
when /^java([\d.]*)/ then [ 'java', $1 ]
|
|
73
|
+
when /^dotnet$/ then [ 'dotnet', nil ]
|
|
74
|
+
when /^dotnet([\d.]*)/ then [ 'dotnet', $1 ]
|
|
75
|
+
when /linux/ then [ 'linux', $1 ]
|
|
76
|
+
when /mingw32/ then [ 'mingw32', nil ]
|
|
77
|
+
when /(mswin\d+)(\_(\d+))?/ then
|
|
78
|
+
os, version = $1, $3
|
|
79
|
+
@cpu = 'x86' if @cpu.nil? and os =~ /32$/
|
|
80
|
+
[os, version]
|
|
81
|
+
when /netbsdelf/ then [ 'netbsdelf', nil ]
|
|
82
|
+
when /openbsd(\d+\.\d+)/ then [ 'openbsd', $1 ]
|
|
83
|
+
when /solaris(\d+\.\d+)/ then [ 'solaris', $1 ]
|
|
84
|
+
# test
|
|
85
|
+
when /^(\w+_platform)(\d+)/ then [ $1, $2 ]
|
|
86
|
+
else [ 'unknown', nil ]
|
|
87
|
+
end
|
|
88
|
+
when LibGems::Platform then
|
|
89
|
+
@cpu = arch.cpu
|
|
90
|
+
@os = arch.os
|
|
91
|
+
@version = arch.version
|
|
92
|
+
else
|
|
93
|
+
raise ArgumentError, "invalid argument #{arch.inspect}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def inspect
|
|
98
|
+
"#<%s:0x%x @cpu=%p, @os=%p, @version=%p>" % [self.class, object_id, *to_a]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def to_a
|
|
102
|
+
[@cpu, @os, @version]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def to_s
|
|
106
|
+
to_a.compact.join '-'
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def empty?
|
|
110
|
+
to_s.empty?
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
##
|
|
114
|
+
# Is +other+ equal to this platform? Two platforms are equal if they have
|
|
115
|
+
# the same CPU, OS and version.
|
|
116
|
+
|
|
117
|
+
def ==(other)
|
|
118
|
+
self.class === other and
|
|
119
|
+
@cpu == other.cpu and @os == other.os and @version == other.version
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
##
|
|
123
|
+
# Does +other+ match this platform? Two platforms match if they have the
|
|
124
|
+
# same CPU, or either has a CPU of 'universal', they have the same OS, and
|
|
125
|
+
# they have the same version, or either has no version.
|
|
126
|
+
|
|
127
|
+
def ===(other)
|
|
128
|
+
return nil unless LibGems::Platform === other
|
|
129
|
+
|
|
130
|
+
# cpu
|
|
131
|
+
(@cpu == 'universal' or other.cpu == 'universal' or @cpu == other.cpu) and
|
|
132
|
+
|
|
133
|
+
# os
|
|
134
|
+
@os == other.os and
|
|
135
|
+
|
|
136
|
+
# version
|
|
137
|
+
(@version.nil? or other.version.nil? or @version == other.version)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
##
|
|
141
|
+
# Does +other+ match this platform? If +other+ is a String it will be
|
|
142
|
+
# converted to a LibGems::Platform first. See #=== for matching rules.
|
|
143
|
+
|
|
144
|
+
def =~(other)
|
|
145
|
+
case other
|
|
146
|
+
when LibGems::Platform then # nop
|
|
147
|
+
when String then
|
|
148
|
+
# This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007
|
|
149
|
+
other = case other
|
|
150
|
+
when /^i686-darwin(\d)/ then ['x86', 'darwin', $1 ]
|
|
151
|
+
when /^i\d86-linux/ then ['x86', 'linux', nil ]
|
|
152
|
+
when 'java', 'jruby' then [nil, 'java', nil ]
|
|
153
|
+
when /dotnet(\-(\d+\.\d+))?/ then ['universal','dotnet', $2 ]
|
|
154
|
+
when /mswin32(\_(\d+))?/ then ['x86', 'mswin32', $2 ]
|
|
155
|
+
when 'powerpc-darwin' then ['powerpc', 'darwin', nil ]
|
|
156
|
+
when /powerpc-darwin(\d)/ then ['powerpc', 'darwin', $1 ]
|
|
157
|
+
when /sparc-solaris2.8/ then ['sparc', 'solaris', '2.8' ]
|
|
158
|
+
when /universal-darwin(\d)/ then ['universal', 'darwin', $1 ]
|
|
159
|
+
else other
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
other = LibGems::Platform.new other
|
|
163
|
+
else
|
|
164
|
+
return nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
self === other
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
##
|
|
171
|
+
# A pure-ruby gem that may use LibGems::Specification#extensions to build
|
|
172
|
+
# binary files.
|
|
173
|
+
|
|
174
|
+
RUBY = 'ruby'
|
|
175
|
+
|
|
176
|
+
##
|
|
177
|
+
# A platform-specific gem that is built for the packaging ruby's platform.
|
|
178
|
+
# This will be replaced with LibGems::Platform::local.
|
|
179
|
+
|
|
180
|
+
CURRENT = 'current'
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'time'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
6
|
+
require 'libgems'
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# RemoteFetcher handles the details of fetching gems and gem information from
|
|
10
|
+
# a remote source.
|
|
11
|
+
|
|
12
|
+
class LibGems::RemoteFetcher
|
|
13
|
+
|
|
14
|
+
include LibGems::UserInteraction
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# A FetchError exception wraps up the various possible IO and HTTP failures
|
|
18
|
+
# that could happen while downloading from the internet.
|
|
19
|
+
|
|
20
|
+
class FetchError < LibGems::Exception
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# The URI which was being accessed when the exception happened.
|
|
24
|
+
|
|
25
|
+
attr_accessor :uri
|
|
26
|
+
|
|
27
|
+
def initialize(message, uri)
|
|
28
|
+
super message
|
|
29
|
+
@uri = uri
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_s # :nodoc:
|
|
33
|
+
"#{super} (#{uri})"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@fetcher = nil
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Cached RemoteFetcher instance.
|
|
42
|
+
|
|
43
|
+
def self.fetcher
|
|
44
|
+
@fetcher ||= self.new LibGems.configuration[:http_proxy]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
# Initialize a remote fetcher using the source URI and possible proxy
|
|
49
|
+
# information.
|
|
50
|
+
#
|
|
51
|
+
# +proxy+
|
|
52
|
+
# * [String]: explicit specification of proxy; overrides any environment
|
|
53
|
+
# variable setting
|
|
54
|
+
# * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER,
|
|
55
|
+
# HTTP_PROXY_PASS)
|
|
56
|
+
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
|
|
57
|
+
|
|
58
|
+
def initialize(proxy = nil)
|
|
59
|
+
Socket.do_not_reverse_lookup = true
|
|
60
|
+
|
|
61
|
+
@connections = {}
|
|
62
|
+
@requests = Hash.new 0
|
|
63
|
+
@proxy_uri =
|
|
64
|
+
case proxy
|
|
65
|
+
when :no_proxy then nil
|
|
66
|
+
when nil then get_proxy_from_env
|
|
67
|
+
when URI::HTTP then proxy
|
|
68
|
+
else URI.parse(proxy)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
|
|
74
|
+
# already there. If the source_uri is local the gem cache dir copy is
|
|
75
|
+
# always replaced.
|
|
76
|
+
|
|
77
|
+
def download(spec, source_uri, install_dir = LibGems.dir)
|
|
78
|
+
if File.writable?(install_dir)
|
|
79
|
+
cache_dir = File.join install_dir, 'cache'
|
|
80
|
+
else
|
|
81
|
+
cache_dir = File.join(LibGems.user_dir, 'cache')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
gem_file_name = spec.file_name
|
|
85
|
+
local_gem_path = File.join cache_dir, gem_file_name
|
|
86
|
+
|
|
87
|
+
FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
|
|
88
|
+
|
|
89
|
+
# Always escape URI's to deal with potential spaces and such
|
|
90
|
+
unless URI::Generic === source_uri
|
|
91
|
+
source_uri = URI.parse(URI.const_defined?(:DEFAULT_PARSER) ?
|
|
92
|
+
URI::DEFAULT_PARSER.escape(source_uri) :
|
|
93
|
+
URI.escape(source_uri))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
scheme = source_uri.scheme
|
|
97
|
+
|
|
98
|
+
# URI.parse gets confused by MS Windows paths with forward slashes.
|
|
99
|
+
scheme = nil if scheme =~ /^[a-z]$/i
|
|
100
|
+
|
|
101
|
+
case scheme
|
|
102
|
+
when 'http', 'https' then
|
|
103
|
+
unless File.exist? local_gem_path then
|
|
104
|
+
begin
|
|
105
|
+
say "Downloading gem #{gem_file_name}" if
|
|
106
|
+
LibGems.configuration.really_verbose
|
|
107
|
+
|
|
108
|
+
remote_gem_path = source_uri + "gems/#{gem_file_name}"
|
|
109
|
+
|
|
110
|
+
gem = self.fetch_path remote_gem_path
|
|
111
|
+
rescue LibGems::RemoteFetcher::FetchError
|
|
112
|
+
raise if spec.original_platform == spec.platform
|
|
113
|
+
|
|
114
|
+
alternate_name = "#{spec.original_name}.gem"
|
|
115
|
+
|
|
116
|
+
say "Failed, downloading gem #{alternate_name}" if
|
|
117
|
+
LibGems.configuration.really_verbose
|
|
118
|
+
|
|
119
|
+
remote_gem_path = source_uri + "gems/#{alternate_name}"
|
|
120
|
+
|
|
121
|
+
gem = self.fetch_path remote_gem_path
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
File.open local_gem_path, 'wb' do |fp|
|
|
125
|
+
fp.write gem
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
when 'file' then
|
|
129
|
+
begin
|
|
130
|
+
path = source_uri.path
|
|
131
|
+
path = File.dirname(path) if File.extname(path) == '.gem'
|
|
132
|
+
|
|
133
|
+
remote_gem_path = File.join(path, 'gems', gem_file_name)
|
|
134
|
+
|
|
135
|
+
FileUtils.cp(remote_gem_path, local_gem_path)
|
|
136
|
+
rescue Errno::EACCES
|
|
137
|
+
local_gem_path = source_uri.to_s
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
say "Using local gem #{local_gem_path}" if
|
|
141
|
+
LibGems.configuration.really_verbose
|
|
142
|
+
when nil then # TODO test for local overriding cache
|
|
143
|
+
source_path = if LibGems.win_platform? && source_uri.scheme &&
|
|
144
|
+
!source_uri.path.include?(':') then
|
|
145
|
+
"#{source_uri.scheme}:#{source_uri.path}"
|
|
146
|
+
else
|
|
147
|
+
source_uri.path
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
source_path = URI.unescape source_path
|
|
151
|
+
|
|
152
|
+
begin
|
|
153
|
+
FileUtils.cp source_path, local_gem_path unless
|
|
154
|
+
File.expand_path(source_path) == File.expand_path(local_gem_path)
|
|
155
|
+
rescue Errno::EACCES
|
|
156
|
+
local_gem_path = source_uri.to_s
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
say "Using local gem #{local_gem_path}" if
|
|
160
|
+
LibGems.configuration.really_verbose
|
|
161
|
+
else
|
|
162
|
+
raise LibGems::InstallError, "unsupported URI scheme #{source_uri.scheme}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
local_gem_path
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
##
|
|
169
|
+
# Downloads +uri+ and returns it as a String.
|
|
170
|
+
|
|
171
|
+
def fetch_path(uri, mtime = nil, head = false)
|
|
172
|
+
data = open_uri_or_path uri, mtime, head
|
|
173
|
+
data = LibGems.gunzip data if data and not head and uri.to_s =~ /gz$/
|
|
174
|
+
data
|
|
175
|
+
rescue FetchError
|
|
176
|
+
raise
|
|
177
|
+
rescue Timeout::Error
|
|
178
|
+
raise FetchError.new('timed out', uri)
|
|
179
|
+
rescue IOError, SocketError, SystemCallError => e
|
|
180
|
+
raise FetchError.new("#{e.class}: #{e}", uri)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
##
|
|
184
|
+
# Returns the size of +uri+ in bytes.
|
|
185
|
+
|
|
186
|
+
def fetch_size(uri) # TODO: phase this out
|
|
187
|
+
response = fetch_path(uri, nil, true)
|
|
188
|
+
|
|
189
|
+
response['content-length'].to_i
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def escape(str)
|
|
193
|
+
return unless str
|
|
194
|
+
URI.escape(str)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def unescape(str)
|
|
198
|
+
return unless str
|
|
199
|
+
URI.unescape(str)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
##
|
|
203
|
+
# Returns an HTTP proxy URI if one is set in the environment variables.
|
|
204
|
+
|
|
205
|
+
def get_proxy_from_env
|
|
206
|
+
env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
|
|
207
|
+
|
|
208
|
+
return nil if env_proxy.nil? or env_proxy.empty?
|
|
209
|
+
|
|
210
|
+
uri = URI.parse(normalize_uri(env_proxy))
|
|
211
|
+
|
|
212
|
+
if uri and uri.user.nil? and uri.password.nil? then
|
|
213
|
+
# Probably we have http_proxy_* variables?
|
|
214
|
+
uri.user = escape(ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER'])
|
|
215
|
+
uri.password = escape(ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS'])
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
uri
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
##
|
|
222
|
+
# Normalize the URI by adding "http://" if it is missing.
|
|
223
|
+
|
|
224
|
+
def normalize_uri(uri)
|
|
225
|
+
(uri =~ /^(https?|ftp|file):/) ? uri : "http://#{uri}"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
##
|
|
229
|
+
# Creates or an HTTP connection based on +uri+, or retrieves an existing
|
|
230
|
+
# connection, using a proxy if needed.
|
|
231
|
+
|
|
232
|
+
def connection_for(uri)
|
|
233
|
+
net_http_args = [uri.host, uri.port]
|
|
234
|
+
|
|
235
|
+
if @proxy_uri then
|
|
236
|
+
net_http_args += [
|
|
237
|
+
@proxy_uri.host,
|
|
238
|
+
@proxy_uri.port,
|
|
239
|
+
@proxy_uri.user,
|
|
240
|
+
@proxy_uri.password
|
|
241
|
+
]
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
connection_id = [Thread.current.object_id, *net_http_args].join ':'
|
|
245
|
+
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
|
|
246
|
+
connection = @connections[connection_id]
|
|
247
|
+
|
|
248
|
+
if uri.scheme == 'https' and not connection.started? then
|
|
249
|
+
require 'net/https'
|
|
250
|
+
connection.use_ssl = true
|
|
251
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
connection.start unless connection.started?
|
|
255
|
+
|
|
256
|
+
connection
|
|
257
|
+
rescue Errno::EHOSTDOWN => e
|
|
258
|
+
raise FetchError.new(e.message, uri)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
##
|
|
262
|
+
# Read the data from the (source based) URI, but if it is a file:// URI,
|
|
263
|
+
# read from the filesystem instead.
|
|
264
|
+
|
|
265
|
+
def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
|
|
266
|
+
raise "block is dead" if block_given?
|
|
267
|
+
|
|
268
|
+
uri = URI.parse uri unless URI::Generic === uri
|
|
269
|
+
|
|
270
|
+
# This check is redundant unless LibGems::RemoteFetcher is likely
|
|
271
|
+
# to be used directly, since the scheme is checked elsewhere.
|
|
272
|
+
# - Daniel Berger
|
|
273
|
+
unless ['http', 'https', 'file'].include?(uri.scheme)
|
|
274
|
+
raise ArgumentError, 'uri scheme is invalid'
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
if uri.scheme == 'file'
|
|
278
|
+
path = uri.path
|
|
279
|
+
|
|
280
|
+
# Deal with leading slash on Windows paths
|
|
281
|
+
if path[0].chr == '/' && path[1].chr =~ /[a-zA-Z]/ && path[2].chr == ':'
|
|
282
|
+
path = path[1..-1]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
return LibGems.read_binary(path)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
|
|
289
|
+
response = request uri, fetch_type, last_modified
|
|
290
|
+
|
|
291
|
+
case response
|
|
292
|
+
when Net::HTTPOK, Net::HTTPNotModified then
|
|
293
|
+
head ? response : response.body
|
|
294
|
+
when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
|
|
295
|
+
Net::HTTPTemporaryRedirect then
|
|
296
|
+
raise FetchError.new('too many redirects', uri) if depth > 10
|
|
297
|
+
|
|
298
|
+
open_uri_or_path(response['Location'], last_modified, head, depth + 1)
|
|
299
|
+
else
|
|
300
|
+
raise FetchError.new("bad response #{response.message} #{response.code}", uri)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
##
|
|
305
|
+
# Performs a Net::HTTP request of type +request_class+ on +uri+ returning
|
|
306
|
+
# a Net::HTTP response object. request maintains a table of persistent
|
|
307
|
+
# connections to reduce connect overhead.
|
|
308
|
+
|
|
309
|
+
def request(uri, request_class, last_modified = nil)
|
|
310
|
+
request = request_class.new uri.request_uri
|
|
311
|
+
|
|
312
|
+
unless uri.nil? || uri.user.nil? || uri.user.empty? then
|
|
313
|
+
request.basic_auth uri.user, uri.password
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
ua = "#{LibGems::NAME}/#{LibGems::VERSION} #{LibGems::Platform.local}"
|
|
317
|
+
ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
|
|
318
|
+
ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
|
|
319
|
+
ua << ")"
|
|
320
|
+
|
|
321
|
+
request.add_field 'User-Agent', ua
|
|
322
|
+
request.add_field 'Connection', 'keep-alive'
|
|
323
|
+
request.add_field 'Keep-Alive', '30'
|
|
324
|
+
|
|
325
|
+
if last_modified then
|
|
326
|
+
last_modified = last_modified.utc
|
|
327
|
+
request.add_field 'If-Modified-Since', last_modified.rfc2822
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
yield request if block_given?
|
|
331
|
+
|
|
332
|
+
connection = connection_for uri
|
|
333
|
+
|
|
334
|
+
retried = false
|
|
335
|
+
bad_response = false
|
|
336
|
+
|
|
337
|
+
begin
|
|
338
|
+
@requests[connection.object_id] += 1
|
|
339
|
+
|
|
340
|
+
say "#{request.method} #{uri}" if
|
|
341
|
+
LibGems.configuration.really_verbose
|
|
342
|
+
|
|
343
|
+
file_name = File.basename(uri.path)
|
|
344
|
+
# perform download progress reporter only for gems
|
|
345
|
+
if request.response_body_permitted? && file_name =~ /\.gem$/
|
|
346
|
+
reporter = ui.download_reporter
|
|
347
|
+
response = connection.request(request) do |incomplete_response|
|
|
348
|
+
if Net::HTTPOK === incomplete_response
|
|
349
|
+
reporter.fetch(file_name, incomplete_response.content_length)
|
|
350
|
+
downloaded = 0
|
|
351
|
+
data = ''
|
|
352
|
+
|
|
353
|
+
incomplete_response.read_body do |segment|
|
|
354
|
+
data << segment
|
|
355
|
+
downloaded += segment.length
|
|
356
|
+
reporter.update(downloaded)
|
|
357
|
+
end
|
|
358
|
+
reporter.done
|
|
359
|
+
if incomplete_response.respond_to? :body=
|
|
360
|
+
incomplete_response.body = data
|
|
361
|
+
else
|
|
362
|
+
incomplete_response.instance_variable_set(:@body, data)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
else
|
|
367
|
+
response = connection.request request
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
say "#{response.code} #{response.message}" if
|
|
371
|
+
LibGems.configuration.really_verbose
|
|
372
|
+
|
|
373
|
+
rescue Net::HTTPBadResponse
|
|
374
|
+
say "bad response" if LibGems.configuration.really_verbose
|
|
375
|
+
|
|
376
|
+
reset connection
|
|
377
|
+
|
|
378
|
+
raise FetchError.new('too many bad responses', uri) if bad_response
|
|
379
|
+
|
|
380
|
+
bad_response = true
|
|
381
|
+
retry
|
|
382
|
+
# HACK work around EOFError bug in Net::HTTP
|
|
383
|
+
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
|
|
384
|
+
# to install gems.
|
|
385
|
+
rescue EOFError, Timeout::Error,
|
|
386
|
+
Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE
|
|
387
|
+
|
|
388
|
+
requests = @requests[connection.object_id]
|
|
389
|
+
say "connection reset after #{requests} requests, retrying" if
|
|
390
|
+
LibGems.configuration.really_verbose
|
|
391
|
+
|
|
392
|
+
raise FetchError.new('too many connection resets', uri) if retried
|
|
393
|
+
|
|
394
|
+
reset connection
|
|
395
|
+
|
|
396
|
+
retried = true
|
|
397
|
+
retry
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
response
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
##
|
|
404
|
+
# Resets HTTP connection +connection+.
|
|
405
|
+
|
|
406
|
+
def reset(connection)
|
|
407
|
+
@requests.delete connection.object_id
|
|
408
|
+
|
|
409
|
+
connection.finish
|
|
410
|
+
connection.start
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
end
|
|
414
|
+
|