Handles all the fetching with the rubygems server
# 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 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 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
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
# 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 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 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
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.