Parent

Class Index [+]

Quicksearch

Bundler::Fetcher

Handles all the fetching with the rubygems server

Constants

REDIRECT_LIMIT

Attributes

has_api[R]
disable_endpoint[RW]

Public Class Methods

download_gem_from_uri(spec, uri) click to toggle source
    # File lib/bundler/fetcher.rb, line 25
25:       def download_gem_from_uri(spec, uri)
26:         spec.fetch_platform
27: 
28:         download_path = Bundler.requires_sudo? ? Bundler.tmp : Bundler.rubygems.gem_dir
29:         gem_path = "#{Bundler.rubygems.gem_dir}/cache/#{spec.full_name}.gem"
30: 
31:         FileUtils.mkdir_p("#{download_path}/cache")
32:         Bundler.rubygems.download_gem(spec, uri, download_path)
33: 
34:         if Bundler.requires_sudo?
35:           Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/cache"
36:           Bundler.sudo "mv #{Bundler.tmp}/cache/#{spec.full_name}.gem #{gem_path}"
37:         end
38: 
39:         gem_path
40:       end
fetch(spec) click to toggle source
    # File lib/bundler/fetcher.rb, line 16
16:       def fetch(spec)
17:         spec, uri = @@spec_fetch_map[spec.full_name]
18:         if spec
19:           path = download_gem_from_uri(spec, uri)
20:           s = Bundler.rubygems.spec_from_gem(path)
21:           spec.__swap__(s)
22:         end
23:       end
new(remote_uri) click to toggle source
    # File lib/bundler/fetcher.rb, line 43
43:     def initialize(remote_uri)
44:       @remote_uri = remote_uri
45:       @has_api    = true # will be set to false if the rubygems index is ever fetched
46:       @@connection ||= Net::HTTP::Persistent.new nil, :ENV
47:     end

Public Instance Methods

fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = []) click to toggle source

fetch index

     # File lib/bundler/fetcher.rb, line 120
120:     def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = [])
121:       query_list = gem_names - full_dependency_list
122: 
123:       # only display the message on the first run
124:       if Bundler.ui.debug?
125:         Bundler.ui.debug "Query List: #{query_list.inspect}"
126:       else
127:         Bundler.ui.info ".", false
128:       end
129: 
130:       return {@remote_uri => last_spec_list} if query_list.empty?
131: 
132:       spec_list, deps_list = fetch_dependency_remote_specs(query_list)
133:       returned_gems = spec_list.map {|spec| spec.first }.uniq
134: 
135:       fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
136:     end
fetch_spec(spec) click to toggle source

fetch a gem specification

    # File lib/bundler/fetcher.rb, line 50
50:     def fetch_spec(spec)
51:       spec = spec - [nil, 'ruby', '']
52:       spec_file_name = "#{spec.join '-'}.gemspec.rz"
53: 
54:       uri = URI.parse("#{@remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}")
55: 
56:       spec_rz = (uri.scheme == "file") ? Gem.read_binary(uri.path) : fetch(uri)
57:       Marshal.load Gem.inflate(spec_rz)
58:     end
specs(gem_names, source) click to toggle source

return the specs in the bundler format as an index

     # File lib/bundler/fetcher.rb, line 61
 61:     def specs(gem_names, source)
 62:       index = Index.new
 63: 
 64:       if !gem_names || @remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
 65:         Bundler.ui.info "Fetching source index from #{strip_user_pass_from_uri(@remote_uri)}"
 66:         specs = fetch_all_remote_specs
 67:       else
 68:         Bundler.ui.info "Fetching gem metadata from #{strip_user_pass_from_uri(@remote_uri)}", Bundler.ui.debug?
 69:         begin
 70:           specs = fetch_remote_specs(gem_names)
 71:         # fall back to the legacy index in the following cases
 72:         # 1. Gemcutter Endpoint doesn't return a 200
 73:         # 2. Marshal blob doesn't load properly
 74:         # 3. One of the YAML gemspecs has the Syck::DefaultKey problem
 75:         rescue HTTPError, TypeError => e
 76:           # new line now that the dots are over
 77:           Bundler.ui.info "" unless Bundler.ui.debug?
 78: 
 79:           if @remote_uri.to_s.include?("rubygems.org")
 80:             Bundler.ui.info "Error #{e.class} during request to dependency API"
 81:           end
 82:           Bundler.ui.debug e.message
 83:           Bundler.ui.debug e.backtrace
 84: 
 85:           Bundler.ui.info "Fetching full source index from #{strip_user_pass_from_uri(@remote_uri)}"
 86:           specs = fetch_all_remote_specs
 87:         else
 88:           # new line now that the dots are over
 89:           Bundler.ui.info "" unless Bundler.ui.debug?
 90:         end
 91:       end
 92: 
 93:       specs[@remote_uri].each do |name, version, platform, dependencies|
 94:         next if name == 'bundler'
 95:         spec = nil
 96:         if dependencies
 97:           spec = EndpointSpecification.new(name, version, platform, dependencies)
 98:         else
 99:           spec = RemoteSpecification.new(name, version, platform, self)
100:         end
101:         spec.source = source
102:         @@spec_fetch_map[spec.full_name] = [spec, @remote_uri]
103:         index << spec
104:       end
105: 
106:       index
107:     rescue LoadError => e
108:       if e.message.include?("cannot load such file -- openssl")
109:         raise InstallError,
110:           "\nCould not load OpenSSL."            "\nYou must recompile Ruby with OpenSSL support or change the sources in your"            "\nGemfile from 'https' to 'http'. Instructions for compiling with OpenSSL"            "\nusing RVM are available at rvm.io/packages/openssl."
111:       else
112:         raise e
113:       end
114:     end

Private Instance Methods

fetch(uri, counter = 0) click to toggle source
     # File lib/bundler/fetcher.rb, line 140
140:     def fetch(uri, counter = 0)
141:       raise HTTPError, "Too many redirects" if counter >= REDIRECT_LIMIT
142: 
143:       begin
144:         Bundler.ui.debug "Fetching from: #{uri}"
145:         response = @@connection.request(uri)
146:       rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
147:              SocketError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
148:              Net::HTTP::Persistent::Error, Net::ProtocolError => e
149:         raise HTTPError, "Network error while fetching #{uri}"
150:       end
151: 
152:       case response
153:       when Net::HTTPRedirection
154:         Bundler.ui.debug("HTTP Redirection")
155:         new_uri = URI.parse(response["location"])
156:         new_uri.user = uri.user
157:         new_uri.password = uri.password
158:         fetch(new_uri, counter + 1)
159:       when Net::HTTPSuccess
160:         Bundler.ui.debug("HTTP Success")
161:         response.body
162:       else
163:         Bundler.ui.debug("HTTP Error")
164:         raise HTTPError
165:       end
166:     end
fetch_all_remote_specs() click to toggle source

fetch from modern index: specs.4.8.gz

     # File lib/bundler/fetcher.rb, line 206
206:     def fetch_all_remote_specs
207:       @has_api = false
208:       Gem.sources = ["#{@remote_uri}"]
209:       spec_list = Hash.new { |h,k| h[k] = [] }
210:       begin
211:         # Fetch all specs, minus prerelease specs
212:         spec_list = Gem::SpecFetcher.new.list(true, false)
213:         # Then fetch the prerelease specs
214:         begin
215:           Gem::SpecFetcher.new.list(false, true).each {|k, v| spec_list[k] += v }
216:         rescue Gem::RemoteFetcher::FetchError
217:           Bundler.ui.debug "Could not fetch prerelease specs from #{strip_user_pass_from_uri(@remote_uri)}"
218:         end
219:       rescue Gem::RemoteFetcher::FetchError
220:         raise HTTPError, "Could not reach #{strip_user_pass_from_uri(@remote_uri)}"
221:       end
222: 
223:       return spec_list
224:     end
fetch_dependency_remote_specs(gem_names) click to toggle source

fetch from Gemcutter Dependency Endpoint API

     # File lib/bundler/fetcher.rb, line 169
169:     def fetch_dependency_remote_specs(gem_names)
170:       Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(' ')}"
171:       encoded_gem_names = URI.encode(gem_names.join(","))
172:       uri = URI.parse("#{@remote_uri}api/v1/dependencies?gems=#{encoded_gem_names}")
173:       marshalled_deps = fetch(uri)
174:       gem_list = Marshal.load(marshalled_deps)
175:       deps_list = []
176: 
177:       spec_list = gem_list.map do |s|
178:         dependencies = s[:dependencies].map do |d|
179:           begin
180:             name, requirement = d
181:             dep = Gem::Dependency.new(name, requirement.split(", "))
182:           rescue ArgumentError => e
183:             if e.message.include?('Illformed requirement ["#<YAML::Syck::DefaultKey')
184:               puts # we shouldn't print the error message on the "fetching info" status line
185:               raise GemspecError, %{Unfortunately, the gem #{s[:name]} (#{s[:number]}) } +
186:                 %{has an invalid gemspec. As a result, Bundler cannot install this Gemfile. } +
187:                 %{Please ask the gem author to yank the bad version to fix this issue. For } +
188:                 %{more information, see http://bit.ly/syck-defaultkey.}
189:             else
190:               raise e
191:             end
192:           end
193: 
194:           deps_list << dep.name
195: 
196:           dep
197:         end
198: 
199:         [s[:name], Gem::Version.new(s[:number]), s[:platform], dependencies]
200:       end
201: 
202:       [spec_list, deps_list.uniq]
203:     end
strip_user_pass_from_uri(uri) click to toggle source
     # File lib/bundler/fetcher.rb, line 226
226:     def strip_user_pass_from_uri(uri)
227:       uri_dup = uri.dup
228:       uri_dup.user = "****" if uri_dup.user
229:       uri_dup.password = "****" if uri_dup.password
230: 
231:       uri_dup
232:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.