bundler 1.11.2 → 1.12.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +24 -0
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +17 -2
  5. data/.rubocop_todo.yml +145 -18
  6. data/.travis.yml +9 -2
  7. data/CHANGELOG.md +42 -0
  8. data/Rakefile +20 -13
  9. data/bin/rake +5 -0
  10. data/bin/rspec +5 -0
  11. data/bin/rubocop +7 -1
  12. data/bundler.gemspec +2 -1
  13. data/exe/bundle +10 -2
  14. data/exe/bundle_ruby +2 -1
  15. data/exe/bundler +3 -1
  16. data/lib/bundler.rb +54 -51
  17. data/lib/bundler/capistrano.rb +1 -0
  18. data/lib/bundler/cli.rb +26 -4
  19. data/lib/bundler/cli/binstubs.rb +1 -0
  20. data/lib/bundler/cli/cache.rb +1 -0
  21. data/lib/bundler/cli/check.rb +4 -1
  22. data/lib/bundler/cli/clean.rb +1 -0
  23. data/lib/bundler/cli/common.rb +1 -0
  24. data/lib/bundler/cli/config.rb +5 -5
  25. data/lib/bundler/cli/console.rb +1 -0
  26. data/lib/bundler/cli/exec.rb +4 -9
  27. data/lib/bundler/cli/gem.rb +12 -9
  28. data/lib/bundler/cli/init.rb +1 -0
  29. data/lib/bundler/cli/inject.rb +1 -0
  30. data/lib/bundler/cli/install.rb +8 -5
  31. data/lib/bundler/cli/lock.rb +2 -0
  32. data/lib/bundler/cli/open.rb +1 -0
  33. data/lib/bundler/cli/outdated.rb +36 -9
  34. data/lib/bundler/cli/package.rb +1 -0
  35. data/lib/bundler/cli/platform.rb +4 -1
  36. data/lib/bundler/cli/show.rb +1 -0
  37. data/lib/bundler/cli/update.rb +6 -6
  38. data/lib/bundler/cli/viz.rb +4 -6
  39. data/lib/bundler/constants.rb +1 -0
  40. data/lib/bundler/current_ruby.rb +34 -168
  41. data/lib/bundler/definition.rb +41 -15
  42. data/lib/bundler/dep_proxy.rb +1 -0
  43. data/lib/bundler/dependency.rb +10 -0
  44. data/lib/bundler/deployment.rb +1 -0
  45. data/lib/bundler/deprecate.rb +1 -0
  46. data/lib/bundler/dsl.rb +19 -9
  47. data/lib/bundler/endpoint_specification.rb +37 -8
  48. data/lib/bundler/env.rb +4 -3
  49. data/lib/bundler/environment.rb +1 -0
  50. data/lib/bundler/errors.rb +51 -32
  51. data/lib/bundler/fetcher.rb +44 -30
  52. data/lib/bundler/fetcher/base.rb +3 -2
  53. data/lib/bundler/fetcher/compact_index.rb +98 -0
  54. data/lib/bundler/fetcher/dependency.rb +36 -36
  55. data/lib/bundler/fetcher/downloader.rb +14 -8
  56. data/lib/bundler/fetcher/index.rb +28 -5
  57. data/lib/bundler/friendly_errors.rb +93 -85
  58. data/lib/bundler/gem_helper.rb +20 -21
  59. data/lib/bundler/gem_helpers.rb +9 -2
  60. data/lib/bundler/gem_remote_fetcher.rb +1 -0
  61. data/lib/bundler/gem_tasks.rb +1 -0
  62. data/lib/bundler/graph.rb +16 -17
  63. data/lib/bundler/index.rb +4 -6
  64. data/lib/bundler/injector.rb +1 -0
  65. data/lib/bundler/inline.rb +8 -2
  66. data/lib/bundler/installer.rb +4 -4
  67. data/lib/bundler/installer/gem_installer.rb +1 -0
  68. data/lib/bundler/installer/parallel_installer.rb +3 -2
  69. data/lib/bundler/installer/standalone.rb +5 -1
  70. data/lib/bundler/lazy_specification.rb +5 -2
  71. data/lib/bundler/lockfile_parser.rb +22 -15
  72. data/lib/bundler/match_platform.rb +1 -0
  73. data/lib/bundler/mirror.rb +218 -0
  74. data/lib/bundler/path_preserver.rb +12 -0
  75. data/lib/bundler/psyched_yaml.rb +1 -0
  76. data/lib/bundler/remote_specification.rb +4 -1
  77. data/lib/bundler/resolver.rb +17 -16
  78. data/lib/bundler/retry.rb +1 -0
  79. data/lib/bundler/ruby_dsl.rb +8 -2
  80. data/lib/bundler/ruby_version.rb +58 -61
  81. data/lib/bundler/rubygems_ext.rb +4 -3
  82. data/lib/bundler/rubygems_gem_installer.rb +1 -0
  83. data/lib/bundler/rubygems_integration.rb +9 -14
  84. data/lib/bundler/runtime.rb +17 -22
  85. data/lib/bundler/settings.rb +17 -21
  86. data/lib/bundler/setup.rb +1 -0
  87. data/lib/bundler/shared_helpers.rb +47 -17
  88. data/lib/bundler/similarity_detector.rb +1 -0
  89. data/lib/bundler/source.rb +2 -1
  90. data/lib/bundler/source/git.rb +2 -1
  91. data/lib/bundler/source/git/git_proxy.rb +33 -7
  92. data/lib/bundler/source/path.rb +17 -10
  93. data/lib/bundler/source/path/installer.rb +1 -0
  94. data/lib/bundler/source/rubygems.rb +4 -3
  95. data/lib/bundler/source/rubygems/remote.rb +16 -0
  96. data/lib/bundler/source_list.rb +1 -0
  97. data/lib/bundler/spec_set.rb +1 -0
  98. data/lib/bundler/ssl_certs/certificate_manager.rb +1 -0
  99. data/lib/bundler/stub_specification.rb +1 -0
  100. data/lib/bundler/templates/Executable +1 -0
  101. data/lib/bundler/templates/Gemfile +1 -0
  102. data/lib/bundler/templates/newgem/.travis.yml.tt +1 -0
  103. data/lib/bundler/templates/newgem/newgem.gemspec.tt +2 -2
  104. data/lib/bundler/ui.rb +1 -0
  105. data/lib/bundler/ui/rg_proxy.rb +1 -0
  106. data/lib/bundler/ui/shell.rb +2 -1
  107. data/lib/bundler/ui/silent.rb +1 -0
  108. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +78 -0
  109. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +97 -0
  110. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb +55 -0
  111. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/version.rb +3 -0
  112. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +4 -0
  113. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +13 -0
  114. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +5 -0
  115. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +2 -1
  116. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +2 -1
  117. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +37 -14
  118. data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +2 -1
  119. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +7 -7
  120. data/lib/bundler/vendored_molinillo.rb +1 -0
  121. data/lib/bundler/vendored_persistent.rb +1 -0
  122. data/lib/bundler/vendored_thor.rb +1 -0
  123. data/lib/bundler/version.rb +6 -1
  124. data/lib/bundler/vlad.rb +1 -0
  125. data/lib/bundler/worker.rb +12 -2
  126. data/man/bundle-config.ronn +6 -0
  127. data/man/bundle-gem.ronn +5 -5
  128. metadata +14 -6
  129. data/lib/bundler/gem_path_manipulation.rb +0 -8
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "bundler/vendored_persistent"
2
3
  require "cgi"
3
4
  require "securerandom"
@@ -6,6 +7,7 @@ require "zlib"
6
7
  module Bundler
7
8
  # Handles all the fetching with the rubygems server
8
9
  class Fetcher
10
+ autoload :CompactIndex, "bundler/fetcher/compact_index"
9
11
  autoload :Downloader, "bundler/fetcher/downloader"
10
12
  autoload :Dependency, "bundler/fetcher/dependency"
11
13
  autoload :Index, "bundler/fetcher/index"
@@ -52,10 +54,17 @@ module Bundler
52
54
 
53
55
  # Exceptions classes that should bypass retry attempts. If your password didn't work the
54
56
  # first time, it's not going to the third time.
55
- AUTH_ERRORS = [AuthenticationRequiredError, BadAuthenticationError, Net::HTTPBadGateway,
56
- Net::HTTPBadRequest, Net::HTTPForbidden, Net::HTTPMethodNotAllowed,
57
- Net::HTTPMovedPermanently, Net::HTTPNotImplemented, Net::HTTPNotFound,
58
- Net::HTTPRequestEntityTooLarge, Net::HTTPNoContent]
57
+ NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency,
58
+ :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed,
59
+ :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound,
60
+ :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge,
61
+ :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
62
+ :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
63
+ FAIL_ERRORS = begin
64
+ fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError]
65
+ fail_errors << Gem::Requirement::BadRequirementError if defined?(Gem::Requirement::BadRequirementError)
66
+ fail_errors.push(*NET_ERRORS.map {|e| SharedHelpers.const_get_safely(e, Net) }.compact)
67
+ end.freeze
59
68
 
60
69
  class << self
61
70
  attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries
@@ -87,7 +96,7 @@ module Bundler
87
96
  elsif cached_spec_path = gemspec_cached_path(spec_file_name)
88
97
  Bundler.load_gemspec(cached_spec_path)
89
98
  else
90
- Bundler.load_marshal Gem.inflate(downloader.fetch uri)
99
+ Bundler.load_marshal Gem.inflate(downloader.fetch(uri).body)
91
100
  end
92
101
  rescue MarshalError
93
102
  raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \
@@ -96,7 +105,7 @@ module Bundler
96
105
 
97
106
  # return the specs in the bundler format as an index with retries
98
107
  def specs_with_retry(gem_names, source)
99
- Bundler::Retry.new("fetcher").attempts do
108
+ Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do
100
109
  specs(gem_names, source)
101
110
  end
102
111
  end
@@ -106,20 +115,25 @@ module Bundler
106
115
  old = Bundler.rubygems.sources
107
116
  index = Bundler::Index.new
108
117
 
109
- specs = {}
110
- fetchers.dup.each do |f|
111
- break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names)
112
- fetchers.delete(f)
118
+ if Bundler::Fetcher.disable_endpoint
119
+ @use_api = false
120
+ specs = fetchers.last.specs(gem_names)
121
+ else
122
+ specs = []
123
+ fetchers.shift until fetchers.first.available? || fetchers.empty?
124
+ fetchers.dup.each do |f|
125
+ break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names)
126
+ fetchers.delete(f)
127
+ end
128
+ @use_api = false if fetchers.none?(&:api_fetcher?)
113
129
  end
114
- @use_api = false if fetchers.none?(&:api_fetcher?)
115
130
 
116
- specs[remote_uri].each do |name, version, platform, dependencies|
131
+ specs.each do |name, version, platform, dependencies|
117
132
  next if name == "bundler"
118
- spec = nil
119
- if dependencies
120
- spec = EndpointSpecification.new(name, version, platform, dependencies)
133
+ spec = if dependencies
134
+ EndpointSpecification.new(name, version, platform, dependencies)
121
135
  else
122
- spec = RemoteSpecification.new(name, version, platform, self)
136
+ RemoteSpecification.new(name, version, platform, self)
123
137
  end
124
138
  spec.source = source
125
139
  spec.remote = @remote
@@ -137,32 +151,33 @@ module Bundler
137
151
  def use_api
138
152
  return @use_api if defined?(@use_api)
139
153
 
140
- if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
141
- @use_api = false
154
+ fetchers.shift until fetchers.first.available?
155
+
156
+ @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
157
+ false
142
158
  else
143
- fetchers.reject! {|f| f.api_fetcher? && !f.api_available? }
144
- @use_api = fetchers.any?(&:api_fetcher?)
159
+ fetchers.first.api_fetcher?
145
160
  end
146
161
  end
147
162
 
148
163
  def user_agent
149
164
  @user_agent ||= begin
150
- ruby = Bundler.ruby_version
165
+ ruby = Bundler::RubyVersion.system
151
166
 
152
- agent = "bundler/#{Bundler::VERSION}"
167
+ agent = String.new("bundler/#{Bundler::VERSION}")
153
168
  agent << " rubygems/#{Gem::VERSION}"
154
- agent << " ruby/#{ruby.version}"
169
+ agent << " ruby/#{ruby.versions_string(ruby.versions)}"
155
170
  agent << " (#{ruby.host})"
156
171
  agent << " command/#{ARGV.first}"
157
172
 
158
173
  if ruby.engine != "ruby"
159
174
  # engine_version raises on unknown engines
160
175
  engine_version = begin
161
- ruby.engine_version
176
+ ruby.engine_versions
162
177
  rescue
163
178
  "???"
164
179
  end
165
- agent << " #{ruby.engine}/#{engine_version}"
180
+ agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}"
166
181
  end
167
182
 
168
183
  agent << " options/#{Bundler.settings.all.join(",")}"
@@ -185,9 +200,8 @@ module Bundler
185
200
  end
186
201
 
187
202
  def http_proxy
188
- if uri = connection.proxy_uri
189
- uri.to_s
190
- end
203
+ return unless uri = connection.proxy_uri
204
+ uri.to_s
191
205
  end
192
206
 
193
207
  def inspect
@@ -196,7 +210,7 @@ module Bundler
196
210
 
197
211
  private
198
212
 
199
- FETCHERS = [Dependency, Index]
213
+ FETCHERS = [CompactIndex, Dependency, Index].freeze
200
214
 
201
215
  def cis
202
216
  env_cis = {
@@ -256,7 +270,7 @@ module Bundler
256
270
  Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
257
271
  Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
258
272
  Net::HTTP::Persistent::Error, Zlib::BufError
259
- ]
273
+ ].freeze
260
274
 
261
275
  def bundler_cert_store
262
276
  store = OpenSSL::X509::Store.new
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bundler
2
3
  class Fetcher
3
4
  class Base
@@ -28,8 +29,8 @@ module Bundler
28
29
  end
29
30
  end
30
31
 
31
- def api_available?
32
- api_fetcher?
32
+ def available?
33
+ true
33
34
  end
34
35
 
35
36
  def api_fetcher?
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+ require "bundler/fetcher/base"
3
+ require "bundler/worker"
4
+
5
+ module Bundler
6
+ class Fetcher
7
+ class CompactIndex < Base
8
+ require "bundler/vendor/compact_index_client/lib/compact_index_client"
9
+
10
+ def self.compact_index_request(method_name)
11
+ method = instance_method(method_name)
12
+ undef_method(method_name)
13
+ define_method(method_name) do |*args, &blk|
14
+ begin
15
+ method.bind(self).call(*args, &blk)
16
+ rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e
17
+ raise HTTPError, e.message
18
+ rescue AuthenticationRequiredError
19
+ # We got a 401 from the server. Just fail.
20
+ raise
21
+ rescue HTTPError => e
22
+ Bundler.ui.trace(e)
23
+ nil
24
+ end
25
+ end
26
+ end
27
+
28
+ def specs(gem_names)
29
+ specs_for_names(gem_names)
30
+ end
31
+ compact_index_request :specs
32
+
33
+ def specs_for_names(gem_names)
34
+ gem_info = []
35
+ complete_gems = []
36
+ remaining_gems = gem_names.dup
37
+
38
+ until remaining_gems.empty?
39
+ Bundler.ui.debug "Looking up gems #{remaining_gems.inspect}"
40
+
41
+ deps = compact_index_client.dependencies(remaining_gems)
42
+ next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq
43
+ deps.each {|dep| gem_info << dep }
44
+ complete_gems.push(*deps.map(&:first)).uniq!
45
+ remaining_gems = next_gems - complete_gems
46
+ end
47
+
48
+ gem_info
49
+ end
50
+
51
+ def fetch_spec(spec)
52
+ spec -= [nil, "ruby", ""]
53
+ contents = compact_index_client.spec(*spec)
54
+ return nil if contents.nil?
55
+ contents.unshift(spec.first)
56
+ contents[3].map! {|d| Gem::Dependency.new(*d) }
57
+ EndpointSpecification.new(*contents)
58
+ end
59
+ compact_index_request :fetch_spec
60
+
61
+ def available?
62
+ # Read info file checksums out of /versions, so we can know if gems are up to date
63
+ fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums!
64
+ end
65
+ compact_index_request :available?
66
+
67
+ def api_fetcher?
68
+ true
69
+ end
70
+
71
+ private
72
+
73
+ def compact_index_client
74
+ @compact_index_client ||= begin
75
+ compact_fetcher = lambda do |path, headers|
76
+ downloader.fetch(fetch_uri + path, headers)
77
+ end
78
+
79
+ SharedHelpers.filesystem_access(cache_path) do
80
+ CompactIndexClient.new(cache_path, compact_fetcher)
81
+ end.tap do |client|
82
+ client.in_parallel = lambda do |inputs, &blk|
83
+ func = lambda {|object, _index| blk.call(object) }
84
+ worker_name = "Compact Index (#{display_uri.host})"
85
+ worker = Bundler::Worker.new(25, worker_name, func)
86
+ inputs.each {|input| worker.enq(input) }
87
+ inputs.map { worker.deq }
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def cache_path
94
+ Bundler.user_cache.join("compact_index", remote.cache_slug)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
1
2
  require "bundler/fetcher/base"
2
3
  require "cgi"
3
4
 
4
5
  module Bundler
5
6
  class Fetcher
6
7
  class Dependency < Base
7
- def api_available?
8
- downloader.fetch(dependency_api_uri)
8
+ def available?
9
+ fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri)
9
10
  rescue NetworkDownError => e
10
11
  raise HTTPError, e.message
11
12
  rescue AuthenticationRequiredError
12
13
  # We got a 401 from the server. Just fail.
13
14
  raise
14
15
  rescue HTTPError
16
+ false
15
17
  end
16
18
 
17
19
  def api_fetcher?
@@ -19,51 +21,50 @@ module Bundler
19
21
  end
20
22
 
21
23
  def specs(gem_names, full_dependency_list = [], last_spec_list = [])
22
- query_list = gem_names - full_dependency_list
24
+ query_list = gem_names.uniq - full_dependency_list
23
25
 
24
- # only display the message on the first run
25
- if Bundler.ui.debug?
26
- Bundler.ui.debug "Query List: #{query_list.inspect}"
27
- else
28
- Bundler.ui.info ".", false
29
- end
26
+ log_specs(query_list)
30
27
 
31
- return { remote_uri => last_spec_list } if query_list.empty?
28
+ return last_spec_list if query_list.empty?
32
29
 
33
- remote_specs = Bundler::Retry.new("dependency api", AUTH_ERRORS).attempts do
30
+ spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do
34
31
  dependency_specs(query_list)
35
32
  end
36
33
 
37
- spec_list, deps_list = remote_specs
38
34
  returned_gems = spec_list.map(&:first).uniq
39
35
  specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
40
36
  rescue HTTPError, MarshalError, GemspecError
41
37
  Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
42
38
  Bundler.ui.debug "could not fetch from the dependency API, trying the full index"
43
- return nil
39
+ nil
44
40
  end
45
41
 
46
42
  def dependency_specs(gem_names)
47
43
  Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}"
48
- gem_list = []
49
- deps_list = []
50
44
 
45
+ gem_list = unmarshalled_dep_gems(gem_names)
46
+ get_formatted_specs_and_deps(gem_list)
47
+ end
48
+
49
+ def unmarshalled_dep_gems(gem_names)
50
+ gem_list = []
51
51
  gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names|
52
- marshalled_deps = downloader.fetch dependency_api_uri(names)
53
- gem_list += Bundler.load_marshal(marshalled_deps)
52
+ marshalled_deps = downloader.fetch(dependency_api_uri(names)).body
53
+ gem_list.push(*Bundler.load_marshal(marshalled_deps))
54
54
  end
55
+ gem_list
56
+ end
55
57
 
56
- spec_list = gem_list.map do |s|
57
- dependencies = s[:dependencies].map do |name, requirement|
58
- dep = well_formed_dependency(name, requirement.split(", "))
59
- deps_list << dep.name
60
- dep
61
- end
58
+ def get_formatted_specs_and_deps(gem_list)
59
+ deps_list = []
60
+ spec_list = []
62
61
 
63
- [s[:name], Gem::Version.new(s[:number]), s[:platform], dependencies]
62
+ gem_list.each do |s|
63
+ deps_list.push(*s[:dependencies].map(&:first))
64
+ deps = s[:dependencies].map {|n, d| [n, d.split(", ")] }
65
+ spec_list.push([s[:name], s[:number], s[:platform], deps])
64
66
  end
65
-
66
- [spec_list, deps_list.uniq]
67
+ [spec_list, deps_list]
67
68
  end
68
69
 
69
70
  def dependency_api_uri(gem_names = [])
@@ -72,16 +73,15 @@ module Bundler
72
73
  uri
73
74
  end
74
75
 
75
- def well_formed_dependency(name, *requirements)
76
- Gem::Dependency.new(name, *requirements)
77
- rescue ArgumentError => e
78
- illformed = 'Ill-formed requirement ["#<YAML::Syck::DefaultKey'
79
- raise e unless e.message.include?(illformed)
80
- puts # we shouldn't print the error message on the "fetching info" status line
81
- raise GemspecError,
82
- "Unfortunately, the gem #{s[:name]} (#{s[:number]}) has an invalid " \
83
- "gemspec. \nPlease ask the gem author to yank the bad version to fix " \
84
- "this issue. For more information, see http://bit.ly/syck-defaultkey."
76
+ private
77
+
78
+ def log_specs(query_list)
79
+ # only display the message on the first run
80
+ if Bundler.ui.debug?
81
+ Bundler.ui.debug "Query List: #{query_list.inspect}"
82
+ else
83
+ Bundler.ui.info ".", false
84
+ end
85
85
  end
86
86
  end
87
87
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bundler
2
3
  class Fetcher
3
4
  class Downloader
@@ -9,40 +10,45 @@ module Bundler
9
10
  @redirect_limit = redirect_limit
10
11
  end
11
12
 
12
- def fetch(uri, counter = 0)
13
+ def fetch(uri, options = {}, counter = 0)
13
14
  raise HTTPError, "Too many redirects" if counter >= redirect_limit
14
15
 
15
- response = request(uri)
16
+ response = request(uri, options)
16
17
  Bundler.ui.debug("HTTP #{response.code} #{response.message}")
17
18
 
18
19
  case response
20
+ when Net::HTTPSuccess, Net::HTTPNotModified
21
+ response
19
22
  when Net::HTTPRedirection
20
23
  new_uri = URI.parse(response["location"])
21
24
  if new_uri.host == uri.host
22
25
  new_uri.user = uri.user
23
26
  new_uri.password = uri.password
24
27
  end
25
- fetch(new_uri, counter + 1)
26
- when Net::HTTPSuccess
27
- response.body
28
+ fetch(new_uri, options, counter + 1)
28
29
  when Net::HTTPRequestEntityTooLarge
29
30
  raise FallbackError, response.body
30
31
  when Net::HTTPUnauthorized
31
32
  raise AuthenticationRequiredError, uri.host
33
+ when Net::HTTPNotFound
34
+ raise FallbackError, "Net::HTTPNotFound"
32
35
  else
33
- raise HTTPError, "#{response.class}: #{response.body}"
36
+ raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}"
34
37
  end
35
38
  end
36
39
 
37
- def request(uri)
40
+ def request(uri, options)
38
41
  Bundler.ui.debug "HTTP GET #{uri}"
39
- req = Net::HTTP::Get.new uri.request_uri
42
+ req = Net::HTTP::Get.new uri.request_uri, options
40
43
  if uri.user
41
44
  user = CGI.unescape(uri.user)
42
45
  password = uri.password ? CGI.unescape(uri.password) : nil
43
46
  req.basic_auth(user, password)
44
47
  end
45
48
  connection.request(uri, req)
49
+ rescue NoMethodError => e
50
+ raise unless ["undefined method", "use_ssl="].all? {|snippet| e.message.include? snippet }
51
+ raise LoadError.new("cannot load such file -- openssl")
46
52
  rescue OpenSSL::SSL::SSLError
47
53
  raise CertificateFailureError.new(uri)
48
54
  rescue *HTTP_ERRORS => e