Class: Bundler::Fetcher

Inherits:
Object
  • Object
show all
Defined in:
lib/bundler/fetcher.rb,
lib/bundler/fetcher/base.rb,
lib/bundler/fetcher/index.rb,
lib/bundler/fetcher/downloader.rb,
lib/bundler/fetcher/dependency.rb

Overview

Handles all the fetching with the rubygems server

Defined Under Namespace

Classes: AuthenticationRequiredError, BadAuthenticationError, Base, CertificateFailureError, Dependency, Downloader, FallbackError, Index, NetworkDownError, SSLError

Constant Summary

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, Net::HTTPBadGateway,
Net::HTTPBadRequest, Net::HTTPForbidden, Net::HTTPMethodNotAllowed,
Net::HTTPMovedPermanently, Net::HTTPNotImplemented, Net::HTTPNotFound,
Net::HTTPRequestEntityTooLarge, Net::HTTPNoContent]

Class Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(remote) ⇒ Fetcher

Returns a new instance of Fetcher



68
69
70
71
72
73
# File 'lib/bundler/fetcher.rb', line 68

def initialize(remote)
  @remote = remote

  Socket.do_not_reverse_lookup = true
  connection # create persistent connection
end

Class Attribute Details

.api_timeoutObject

Returns the value of attribute api_timeout



61
62
63
# File 'lib/bundler/fetcher.rb', line 61

def api_timeout
  @api_timeout
end

.disable_endpointObject

Returns the value of attribute disable_endpoint



61
62
63
# File 'lib/bundler/fetcher.rb', line 61

def disable_endpoint
  @disable_endpoint
end

.max_retriesObject

Returns the value of attribute max_retries



61
62
63
# File 'lib/bundler/fetcher.rb', line 61

def max_retries
  @max_retries
end

.redirect_limitObject

Returns the value of attribute redirect_limit



61
62
63
# File 'lib/bundler/fetcher.rb', line 61

def redirect_limit
  @redirect_limit
end

Instance Method Details

#fetch_spec(spec) ⇒ Object

fetch a gem specification



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/bundler/fetcher.rb', line 80

def fetch_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(downloader.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

#fetchersObject



183
184
185
# File 'lib/bundler/fetcher.rb', line 183

def fetchers
  @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) }
end

#http_proxyObject



187
188
189
190
191
# File 'lib/bundler/fetcher.rb', line 187

def http_proxy
  if uri = connection.proxy_uri
    uri.to_s
  end
end

#inspectObject



193
194
195
# File 'lib/bundler/fetcher.rb', line 193

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



105
106
107
108
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 105

def specs(gem_names, source)
  old = Bundler.rubygems.sources
  index = Bundler::Index.new

  specs = {}
  fetchers.dup.each do |f|
    break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names)
    fetchers.delete(f)
  end
  @use_api = false if fetchers.none?(&:api_fetcher?)

  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.remote = @remote
    index << spec
  end

  index
rescue CertificateFailureError
  Bundler.ui.info "" if gem_names && use_api # newline after dots
  raise
ensure
  Bundler.rubygems.sources = old
end

#specs_with_retry(gem_names, source) ⇒ Object

return the specs in the bundler format as an index with retries



98
99
100
101
102
# File 'lib/bundler/fetcher.rb', line 98

def specs_with_retry(gem_names, source)
  Bundler::Retry.new("fetcher").attempts do
    specs(gem_names, source)
  end
end

#uriObject



75
76
77
# File 'lib/bundler/fetcher.rb', line 75

def uri
  @remote.anonymized_uri
end

#use_apiObject



137
138
139
140
141
142
143
144
145
146
# File 'lib/bundler/fetcher.rb', line 137

def use_api
  return @use_api if defined?(@use_api)

  if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
    @use_api = false
  else
    fetchers.reject! {|f| f.api_fetcher? && !f.api_available? }
    @use_api = fetchers.any?(&:api_fetcher?)
  end
end

#user_agentObject



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/bundler/fetcher.rb', line 148

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 = begin
                         ruby.engine_version
                       rescue
                         "???"
                       end
      agent << " #{ruby.engine}/#{engine_version}"
    end

    agent << " options/#{Bundler.settings.all.join(",")}"

    agent << " ci/#{cis.join(",")}" if cis.any?

    # add a random ID so we can consolidate runs server-side
    agent << " " << SecureRandom.hex(8)

    # add any user agent strings set in the config
    extra_ua = Bundler.settings[:user_agent]
    agent << " " << extra_ua if extra_ua

    agent
  end
end