Class: Bundler::Fetcher
- Inherits:
-
Object
- Object
- Bundler::Fetcher
- Defined in:
- lib/bundler/fetcher.rb
Overview
Handles all the fetching with the rubygems server
Defined Under Namespace
Classes: AuthenticationRequiredError, BadAuthenticationError, CertificateFailureError, FallbackError, SSLError
Constant Summary collapse
- AUTH_ERRORS =
Exceptions classes that should bypass retry attempts. If your password didn’t work the first time, it’s not going to the third time.
[AuthenticationRequiredError, BadAuthenticationError]
Class Attribute Summary collapse
-
.api_timeout ⇒ Object
Returns the value of attribute api_timeout.
-
.disable_endpoint ⇒ Object
Returns the value of attribute disable_endpoint.
-
.max_retries ⇒ Object
Returns the value of attribute max_retries.
-
.redirect_limit ⇒ Object
Returns the value of attribute redirect_limit.
Class Method Summary collapse
Instance Method Summary collapse
- #connection ⇒ Object
-
#fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = []) ⇒ Object
fetch index.
-
#fetch_spec(spec) ⇒ Object
fetch a gem specification.
-
#gemspec_cached_path(spec_file_name) ⇒ Object
cached gem specification path, if one exists.
-
#initialize(remote_uri) ⇒ Fetcher
constructor
A new instance of Fetcher.
- #inspect ⇒ Object
-
#specs(gem_names, source) ⇒ Object
return the specs in the bundler format as an index.
- #uri ⇒ Object
- #use_api ⇒ Object
Constructor Details
#initialize(remote_uri) ⇒ Fetcher
Returns a new instance of Fetcher.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/bundler/fetcher.rb', line 93 def initialize(remote_uri) # How many redirects to allew in one request @redirect_limit = 5 # How long to wait for each gemcutter API call @api_timeout = 10 # How many retries for the gemcutter API call @max_retries = 3 @remote_uri = Bundler::Source.mirror_for(remote_uri) @public_uri = @remote_uri.dup @public_uri.user, @public_uri.password = nil, nil # don't print these Socket.do_not_reverse_lookup = true end |
Class Attribute Details
.api_timeout ⇒ Object
Returns the value of attribute api_timeout.
52 53 54 |
# File 'lib/bundler/fetcher.rb', line 52 def api_timeout @api_timeout end |
.disable_endpoint ⇒ Object
Returns the value of attribute disable_endpoint.
52 53 54 |
# File 'lib/bundler/fetcher.rb', line 52 def disable_endpoint @disable_endpoint end |
.max_retries ⇒ Object
Returns the value of attribute max_retries.
52 53 54 |
# File 'lib/bundler/fetcher.rb', line 52 def max_retries @max_retries end |
.redirect_limit ⇒ Object
Returns the value of attribute redirect_limit.
52 53 54 |
# File 'lib/bundler/fetcher.rb', line 52 def redirect_limit @redirect_limit end |
Class Method Details
.download_gem_from_uri(spec, uri) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/bundler/fetcher.rb', line 54 def download_gem_from_uri(spec, uri) spec.fetch_platform download_path = Bundler.requires_sudo? ? Bundler.tmp(spec.full_name) : Bundler.rubygems.gem_dir gem_path = "#{Bundler.rubygems.gem_dir}/cache/#{spec.full_name}.gem" FileUtils.mkdir_p("#{download_path}/cache") Bundler.rubygems.download_gem(spec, uri, download_path) if Bundler.requires_sudo? Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/cache" Bundler.sudo "mv #{Bundler.tmp(spec.full_name)}/cache/#{spec.full_name}.gem #{gem_path}" end gem_path end |
.user_agent ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/bundler/fetcher.rb', line 71 def user_agent @user_agent ||= begin ruby = Bundler.ruby_version agent = "bundler/#{Bundler::VERSION}" agent += " rubygems/#{Gem::VERSION}" agent += " ruby/#{ruby.version}" agent += " (#{ruby.host})" agent += " command/#{ARGV.first}" if ruby.engine != "ruby" # engine_version raises on unknown engines engine_version = ruby.engine_version rescue "???" agent += " #{ruby.engine}/#{engine_version}" end # add a random ID so we can consolidate runs server-side agent << " " << SecureRandom.hex(8) end end |
Instance Method Details
#connection ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/bundler/fetcher.rb', line 109 def connection return @connection if @connection needs_ssl = @remote_uri.scheme == "https" || Bundler.settings[:ssl_verify_mode] || Bundler.settings[:ssl_client_cert] raise SSLError if needs_ssl && !defined?(OpenSSL) @connection = Net::HTTP::Persistent.new 'bundler', :ENV if @remote_uri.scheme == "https" @connection.verify_mode = (Bundler.settings[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_PEER) @connection.cert_store = bundler_cert_store end if Bundler.settings[:ssl_client_cert] pem = File.read(Bundler.settings[:ssl_client_cert]) @connection.cert = OpenSSL::X509::Certificate.new(pem) @connection.key = OpenSSL::PKey::RSA.new(pem) end @connection.read_timeout = @api_timeout @connection.override_headers["User-Agent"] = self.class.user_agent @connection end |
#fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = []) ⇒ Object
fetch index
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/bundler/fetcher.rb', line 203 def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = []) query_list = gem_names - full_dependency_list # only display the message on the first run if Bundler.ui.debug? Bundler.ui.debug "Query List: #{query_list.inspect}" else Bundler.ui.info ".", false end return {@remote_uri => last_spec_list} if query_list.empty? remote_specs = Bundler::Retry.new("dependency api", AUTH_ERRORS).attempts do fetch_dependency_remote_specs(query_list) end spec_list, deps_list = remote_specs returned_gems = spec_list.map {|spec| spec.first }.uniq fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) rescue HTTPError, MarshalError, GemspecError Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over Bundler.ui.debug "could not fetch from the dependency API, trying the full index" @use_api = false return nil end |
#fetch_spec(spec) ⇒ Object
fetch a gem specification
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/bundler/fetcher.rb', line 142 def fetch_spec(spec) spec = spec - [nil, 'ruby', ''] spec_file_name = "#{spec.join '-'}.gemspec" uri = URI.parse("#{@remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") if uri.scheme == 'file' Bundler.load_marshal Gem.inflate(Gem.read_binary(uri.path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) Bundler.load_gemspec(cached_spec_path) else Bundler.load_marshal Gem.inflate(fetch(uri)) end rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ "Your network or your gem server is probably having issues right now." end |
#gemspec_cached_path(spec_file_name) ⇒ Object
cached gem specification path, if one exists
160 161 162 163 164 |
# File 'lib/bundler/fetcher.rb', line 160 def gemspec_cached_path spec_file_name paths = Bundler.rubygems.spec_cache_dirs.map { |dir| File.join(dir, spec_file_name) } paths = paths.select {|path| File.file? path } paths.first end |
#inspect ⇒ Object
241 242 243 |
# File 'lib/bundler/fetcher.rb', line 241 def inspect "#<#{self.class}:0x#{object_id} uri=#{uri}>" end |
#specs(gem_names, source) ⇒ Object
return the specs in the bundler format as an index
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/bundler/fetcher.rb', line 167 def specs(gem_names, source) index = Index.new if gem_names && use_api specs = fetch_remote_specs(gem_names) end if specs.nil? # API errors mean we should treat this as a non-API source @use_api = false specs = Bundler::Retry.new("source fetch", AUTH_ERRORS).attempts do fetch_all_remote_specs end end specs[@remote_uri].each do |name, version, platform, dependencies| next if name == 'bundler' spec = nil if dependencies spec = EndpointSpecification.new(name, version, platform, dependencies) else spec = RemoteSpecification.new(name, version, platform, self) end spec.source = source spec.source_uri = @remote_uri index << spec end index rescue CertificateFailureError => e Bundler.ui.info "" if gem_names && use_api # newline after dots raise e end |
#uri ⇒ Object
137 138 139 |
# File 'lib/bundler/fetcher.rb', line 137 def uri @public_uri end |
#use_api ⇒ Object
229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/bundler/fetcher.rb', line 229 def use_api return @use_api if defined?(@use_api) if @remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint @use_api = false elsif fetch(dependency_api_uri) @use_api = true end rescue HTTPError @use_api = false end |