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.
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