Class: Bundler::Source::Rubygems

Inherits:
Bundler::Source show all
Defined in:
lib/bundler/source/rubygems.rb,
lib/bundler/source/rubygems/remote.rb

Direct Known Subclasses

Plugin::Installer::Rubygems

Defined Under Namespace

Classes: Remote

Constant Summary collapse

API_REQUEST_SIZE =

Ask for X gems per API request

100
REQUIRE_MUTEX =
Mutex.new

Instance Attribute Summary collapse

Attributes inherited from Bundler::Source

#checksum_store, #dependency_names

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Bundler::Source

#add_dependency_names, #extension_cache_path, #inspect, #path?, #version_message

Constructor Details

#initialize(options = {}) ⇒ Rubygems

Returns a new instance of Rubygems.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/bundler/source/rubygems.rb', line 16

def initialize(options = {})
  @options = options
  @remotes = []
  @dependency_names = []
  @allow_remote = false
  @allow_cached = false
  @allow_local = options["allow_local"] || false
  @prefer_local = false
  @checksum_store = Checksum::Store.new
  @gem_installers = {}
  @gem_installers_mutex = Mutex.new

  Array(options["remotes"]).reverse_each {|r| add_remote(r) }

  @lockfile_remotes = @remotes if options["from_lockfile"]
end

Instance Attribute Details

#remotesObject

Returns the value of attribute remotes.



14
15
16
# File 'lib/bundler/source/rubygems.rb', line 14

def remotes
  @remotes
end

Class Method Details

.from_lock(options) ⇒ Object



106
107
108
109
# File 'lib/bundler/source/rubygems.rb', line 106

def self.from_lock(options)
  options["remotes"] = Array(options.delete("remote")).reverse
  new(options.merge("from_lockfile" => true))
end

Instance Method Details

#add_remote(source) ⇒ Object



246
247
248
249
# File 'lib/bundler/source/rubygems.rb', line 246

def add_remote(source)
  uri = normalize_uri(source)
  @remotes.unshift(uri) unless @remotes.include?(uri)
end

#cache(spec, custom_path = nil) ⇒ Object



221
222
223
224
225
226
227
228
229
230
# File 'lib/bundler/source/rubygems.rb', line 221

def cache(spec, custom_path = nil)
  cached_path = Bundler.settings[:cache_all_platforms] ? fetch_gem_if_possible(spec) : cached_gem(spec)
  raise GemNotFound, "Missing gem file '#{spec.file_name}'." unless cached_path
  return if File.dirname(cached_path) == Bundler.app_cache.to_s
  Bundler.ui.info "  * #{File.basename(cached_path)}"
  FileUtils.cp(cached_path, Bundler.app_cache(custom_path))
rescue Errno::EACCES => e
  Bundler.ui.debug(e)
  raise InstallError, e.message
end

#cached!Object



66
67
68
69
70
71
72
73
# File 'lib/bundler/source/rubygems.rb', line 66

def cached!
  return unless File.exist?(cache_path)

  return if @allow_cached

  @specs = nil
  @allow_cached = true
end

#cached_built_in_gem(spec, local: false) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/bundler/source/rubygems.rb', line 232

def cached_built_in_gem(spec, local: false)
  cached_path = cached_gem(spec)
  if cached_path.nil? && !local
    remote_spec = remote_specs.search(spec).first
    if remote_spec
      cached_path = fetch_gem(remote_spec)
      spec.remote = remote_spec.remote
    else
      Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it."
    end
  end
  cached_path
end

#cachesObject



33
34
35
# File 'lib/bundler/source/rubygems.rb', line 33

def caches
  @caches ||= [cache_path, *Bundler.rubygems.gem_cache]
end

#can_lock?(spec) ⇒ Boolean

Returns:

  • (Boolean)


97
98
99
100
# File 'lib/bundler/source/rubygems.rb', line 97

def can_lock?(spec)
  return super unless multiple_remotes?
  include?(spec.source)
end

#dependency_api_available?Boolean

Returns:

  • (Boolean)


313
314
315
# File 'lib/bundler/source/rubygems.rb', line 313

def dependency_api_available?
  @allow_remote && api_fetchers.any?
end

#dependency_names_to_double_checkObject



298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/bundler/source/rubygems.rb', line 298

def dependency_names_to_double_check
  names = []
  remote_specs.each do |spec|
    case spec
    when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification
      names.concat(spec.runtime_dependencies.map(&:name))
    when RemoteSpecification # from the full index
      return nil
    else
      raise "unhandled spec type (#{spec.inspect})"
    end
  end
  names
end

#double_check_for(unmet_dependency_names) ⇒ Object



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/bundler/source/rubygems.rb', line 278

def double_check_for(unmet_dependency_names)
  return unless dependency_api_available?

  unmet_dependency_names = unmet_dependency_names.call
  unless unmet_dependency_names.nil?
    if api_fetchers.size <= 1
      # can't do this when there are multiple fetchers because then we might not fetch from _all_
      # of them
      unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten
    end
    return if unmet_dependency_names.empty?
  end

  Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}"

  fetch_names(api_fetchers, unmet_dependency_names, remote_specs)

  specs.use remote_specs
end

#download(spec, options = {}) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/bundler/source/rubygems.rb', line 168

def download(spec, options = {})
  if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
    return true
  end

  installer = rubygems_gem_installer(spec, options)

  if spec.remote
    s = begin
      installer.spec
    rescue Gem::Package::FormatError
      Bundler.rm_rf(installer.gem)
      raise
    rescue Gem::Security::Exception => e
      raise SecurityError,
       "The gem #{installer.gem} can't be installed because " \
       "the security policy didn't allow it, with the message: #{e.message}"
    end

    spec.__swap__(s)
  end

  spec
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns:

  • (Boolean)


79
80
81
# File 'lib/bundler/source/rubygems.rb', line 79

def eql?(other)
  other.is_a?(Rubygems) && other.credless_remotes == credless_remotes
end

#fetchersObject



274
275
276
# File 'lib/bundler/source/rubygems.rb', line 274

def fetchers
  @fetchers ||= remote_fetchers.values.freeze
end

#hashObject



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

def hash
  @remotes.hash
end

#identifierObject Also known as: name, to_gemfile



135
136
137
138
139
140
141
# File 'lib/bundler/source/rubygems.rb', line 135

def identifier
  if remotes.empty?
    "locally installed gems"
  else
    "rubygems repository #{remote_names}"
  end
end

#include?(o) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/bundler/source/rubygems.rb', line 85

def include?(o)
  o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty?
end

#install(spec, options = {}) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/bundler/source/rubygems.rb', line 193

def install(spec, options = {})
  if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
    print_using_message "Using #{version_message(spec, options[:previous_spec])}"
    return nil # no post-install message
  end

  return if Bundler.settings[:no_install]

  installer = rubygems_gem_installer(spec, options)
  spec.source.checksum_store.register(spec, installer.gem_checksum)

  message = "Installing #{version_message(spec, options[:previous_spec])}"
  message += " with native extensions" if spec.extensions.any?
  Bundler.ui.confirm message

  installed_spec = nil

  Gem.time("Installed #{spec.name} in", 0, true) do
    installed_spec = installer.install
  end

  spec.full_gem_path = installed_spec.full_gem_path
  spec.loaded_from = installed_spec.loaded_from
  spec.base_dir = installed_spec.base_dir

  spec.post_install_message
end

#local!Object



52
53
54
55
56
57
# File 'lib/bundler/source/rubygems.rb', line 52

def local!
  return if @allow_local

  @specs = nil
  @allow_local = true
end

#local_only!Object



41
42
43
44
45
46
# File 'lib/bundler/source/rubygems.rb', line 41

def local_only!
  @specs = nil
  @allow_local = true
  @allow_cached = false
  @allow_remote = false
end

#local_only?Boolean

Returns:

  • (Boolean)


48
49
50
# File 'lib/bundler/source/rubygems.rb', line 48

def local_only?
  @allow_local && !@allow_remote
end

#multiple_remotes?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/bundler/source/rubygems.rb', line 89

def multiple_remotes?
  @remotes.size > 1
end

#no_remotes?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/bundler/source/rubygems.rb', line 93

def no_remotes?
  @remotes.size == 0
end

#optionsObject



102
103
104
# File 'lib/bundler/source/rubygems.rb', line 102

def options
  { "remotes" => @remotes.map(&:to_s) }
end

#prefer_local!Object



37
38
39
# File 'lib/bundler/source/rubygems.rb', line 37

def prefer_local!
  @prefer_local = true
end

#remote!Object



59
60
61
62
63
64
# File 'lib/bundler/source/rubygems.rb', line 59

def remote!
  return if @allow_remote

  @specs = nil
  @allow_remote = true
end

#remote_fetchersObject



267
268
269
270
271
272
# File 'lib/bundler/source/rubygems.rb', line 267

def remote_fetchers
  @remote_fetchers ||= remotes.to_h do |uri|
    remote = Source::Rubygems::Remote.new(uri)
    [remote, Bundler::Fetcher.new(remote)]
  end.freeze
end

#spec_namesObject



251
252
253
254
255
256
257
# File 'lib/bundler/source/rubygems.rb', line 251

def spec_names
  if dependency_api_available?
    remote_specs.spec_names
  else
    []
  end
end

#specsObject



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/bundler/source/rubygems.rb', line 145

def specs
  @specs ||= begin
    # remote_specs usually generates a way larger Index than the other
    # sources, and large_idx.merge! small_idx is way faster than
    # small_idx.merge! large_idx.
    index = @allow_remote ? remote_specs.dup : Index.new
    index.merge!(cached_specs) if @allow_cached
    index.merge!(installed_specs) if @allow_local

    if @allow_local
      if @prefer_local
        index.merge!(default_specs)
      else
        # complete with default specs, only if not already available in the
        # index through remote, cached, or installed specs
        index.use(default_specs)
      end
    end

    index
  end
end

#to_lockObject



111
112
113
114
115
116
117
# File 'lib/bundler/source/rubygems.rb', line 111

def to_lock
  out = String.new("GEM\n")
  lockfile_remotes.reverse_each do |remote|
    out << "  remote: #{remote}\n"
  end
  out << "  specs:\n"
end

#to_sObject



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/bundler/source/rubygems.rb', line 119

def to_s
  if remotes.empty?
    "locally installed gems"
  elsif @allow_remote && @allow_cached && @allow_local
    "rubygems repository #{remote_names}, cached gems or installed locally"
  elsif @allow_remote && @allow_local
    "rubygems repository #{remote_names} or installed locally"
  elsif @allow_remote
    "rubygems repository #{remote_names}"
  elsif @allow_cached && @allow_local
    "cached gems or installed locally"
  else
    "locally installed gems"
  end
end

#unmet_depsObject



259
260
261
262
263
264
265
# File 'lib/bundler/source/rubygems.rb', line 259

def unmet_deps
  if dependency_api_available?
    remote_specs.unmet_dependency_names
  else
    []
  end
end