bundler 2.6.5 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1172 -1024
  3. data/README.md +7 -7
  4. data/bundler.gemspec +2 -2
  5. data/lib/bundler/build_metadata.rb +10 -11
  6. data/lib/bundler/checksum.rb +22 -12
  7. data/lib/bundler/cli/common.rb +1 -1
  8. data/lib/bundler/cli/config.rb +2 -2
  9. data/lib/bundler/cli/doctor/diagnose.rb +167 -0
  10. data/lib/bundler/cli/doctor/ssl.rb +249 -0
  11. data/lib/bundler/cli/doctor.rb +27 -155
  12. data/lib/bundler/cli/gem.rb +62 -30
  13. data/lib/bundler/cli/inject.rb +2 -2
  14. data/lib/bundler/cli/install.rb +5 -5
  15. data/lib/bundler/cli/issue.rb +2 -2
  16. data/lib/bundler/cli/lock.rb +2 -1
  17. data/lib/bundler/cli/outdated.rb +1 -1
  18. data/lib/bundler/cli/update.rb +3 -3
  19. data/lib/bundler/cli.rb +26 -49
  20. data/lib/bundler/compact_index_client/cache.rb +1 -1
  21. data/lib/bundler/compact_index_client/parser.rb +1 -1
  22. data/lib/bundler/compact_index_client/updater.rb +2 -1
  23. data/lib/bundler/compact_index_client.rb +1 -5
  24. data/lib/bundler/current_ruby.rb +27 -3
  25. data/lib/bundler/definition.rb +184 -151
  26. data/lib/bundler/dependency.rb +1 -1
  27. data/lib/bundler/dsl.rb +35 -26
  28. data/lib/bundler/errors.rb +18 -0
  29. data/lib/bundler/feature_flag.rb +15 -12
  30. data/lib/bundler/fetcher/dependency.rb +2 -1
  31. data/lib/bundler/fetcher/downloader.rb +33 -7
  32. data/lib/bundler/fetcher.rb +49 -19
  33. data/lib/bundler/friendly_errors.rb +3 -2
  34. data/lib/bundler/index.rb +7 -2
  35. data/lib/bundler/injector.rb +9 -9
  36. data/lib/bundler/installer.rb +6 -5
  37. data/lib/bundler/lazy_specification.rb +38 -19
  38. data/lib/bundler/lockfile_parser.rb +29 -10
  39. data/lib/bundler/man/bundle-add.1 +1 -1
  40. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  41. data/lib/bundler/man/bundle-cache.1 +1 -1
  42. data/lib/bundler/man/bundle-check.1 +1 -1
  43. data/lib/bundler/man/bundle-clean.1 +1 -1
  44. data/lib/bundler/man/bundle-config.1 +175 -129
  45. data/lib/bundler/man/bundle-config.1.ronn +93 -88
  46. data/lib/bundler/man/bundle-console.1 +1 -1
  47. data/lib/bundler/man/bundle-doctor.1 +43 -4
  48. data/lib/bundler/man/bundle-doctor.1.ronn +48 -4
  49. data/lib/bundler/man/bundle-env.1 +1 -1
  50. data/lib/bundler/man/bundle-exec.1 +3 -3
  51. data/lib/bundler/man/bundle-exec.1.ronn +2 -2
  52. data/lib/bundler/man/bundle-fund.1 +1 -1
  53. data/lib/bundler/man/bundle-gem.1 +67 -44
  54. data/lib/bundler/man/bundle-gem.1.ronn +8 -4
  55. data/lib/bundler/man/bundle-help.1 +1 -1
  56. data/lib/bundler/man/bundle-info.1 +1 -1
  57. data/lib/bundler/man/bundle-init.1 +1 -1
  58. data/lib/bundler/man/bundle-inject.1 +2 -2
  59. data/lib/bundler/man/bundle-inject.1.ronn +1 -1
  60. data/lib/bundler/man/bundle-install.1 +4 -4
  61. data/lib/bundler/man/bundle-install.1.ronn +3 -4
  62. data/lib/bundler/man/bundle-issue.1 +1 -1
  63. data/lib/bundler/man/bundle-licenses.1 +1 -1
  64. data/lib/bundler/man/bundle-list.1 +1 -1
  65. data/lib/bundler/man/bundle-lock.1 +1 -1
  66. data/lib/bundler/man/bundle-open.1 +1 -1
  67. data/lib/bundler/man/bundle-outdated.1 +1 -1
  68. data/lib/bundler/man/bundle-platform.1 +1 -1
  69. data/lib/bundler/man/bundle-plugin.1 +1 -1
  70. data/lib/bundler/man/bundle-pristine.1 +1 -1
  71. data/lib/bundler/man/bundle-remove.1 +1 -1
  72. data/lib/bundler/man/bundle-show.1 +1 -1
  73. data/lib/bundler/man/bundle-update.1 +5 -5
  74. data/lib/bundler/man/bundle-update.1.ronn +4 -4
  75. data/lib/bundler/man/bundle-version.1 +1 -1
  76. data/lib/bundler/man/bundle-viz.1 +1 -1
  77. data/lib/bundler/man/bundle.1 +1 -1
  78. data/lib/bundler/man/gemfile.5 +1 -1
  79. data/lib/bundler/match_platform.rb +31 -12
  80. data/lib/bundler/materialization.rb +2 -2
  81. data/lib/bundler/plugin/api/source.rb +1 -1
  82. data/lib/bundler/plugin/index.rb +1 -1
  83. data/lib/bundler/plugin/installer/path.rb +8 -0
  84. data/lib/bundler/plugin.rb +1 -1
  85. data/lib/bundler/resolver/candidate.rb +12 -9
  86. data/lib/bundler/resolver/package.rb +1 -1
  87. data/lib/bundler/resolver/strategy.rb +40 -0
  88. data/lib/bundler/resolver.rb +18 -27
  89. data/lib/bundler/rubygems_ext.rb +131 -120
  90. data/lib/bundler/rubygems_integration.rb +11 -6
  91. data/lib/bundler/runtime.rb +9 -6
  92. data/lib/bundler/self_manager.rb +32 -42
  93. data/lib/bundler/settings/validator.rb +0 -23
  94. data/lib/bundler/settings.rb +4 -6
  95. data/lib/bundler/shared_helpers.rb +10 -4
  96. data/lib/bundler/source/gemspec.rb +1 -4
  97. data/lib/bundler/source/git/git_proxy.rb +17 -6
  98. data/lib/bundler/source/git.rb +5 -1
  99. data/lib/bundler/source/path.rb +9 -2
  100. data/lib/bundler/source/rubygems/remote.rb +11 -3
  101. data/lib/bundler/source_list.rb +30 -16
  102. data/lib/bundler/source_map.rb +1 -1
  103. data/lib/bundler/spec_set.rb +55 -16
  104. data/lib/bundler/templates/Executable +0 -11
  105. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +2 -0
  106. data/lib/bundler/templates/newgem/newgem.gemspec.tt +6 -5
  107. data/lib/bundler/ui/shell.rb +2 -2
  108. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +53 -3
  109. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  110. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +11 -0
  111. data/lib/bundler/vendor/net-http-persistent/README.rdoc +1 -1
  112. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +2 -1
  113. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +81 -42
  114. data/lib/bundler/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +4 -24
  115. data/lib/bundler/vendor/pub_grub/lib/pub_grub/strategy.rb +42 -0
  116. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb +20 -8
  117. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb +17 -29
  118. data/lib/bundler/vendor/uri/lib/uri/common.rb +7 -3
  119. data/lib/bundler/vendor/uri/lib/uri/generic.rb +12 -11
  120. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +6 -6
  121. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  122. data/lib/bundler/version.rb +10 -2
  123. data/lib/bundler/worker.rb +1 -1
  124. data/lib/bundler.rb +14 -12
  125. metadata +9 -16
  126. data/lib/bundler/compact_index_client/gem_parser.rb +0 -32
  127. data/lib/bundler/gem_helpers.rb +0 -144
  128. data/lib/bundler/templates/Executable.bundler +0 -109
  129. data/lib/bundler/vendor/connection_pool/.document +0 -1
  130. data/lib/bundler/vendor/fileutils/.document +0 -1
  131. data/lib/bundler/vendor/net-http-persistent/.document +0 -1
  132. data/lib/bundler/vendor/pub_grub/.document +0 -1
  133. data/lib/bundler/vendor/securerandom/.document +0 -1
  134. data/lib/bundler/vendor/thor/.document +0 -1
  135. data/lib/bundler/vendor/tsort/.document +0 -1
  136. data/lib/bundler/vendor/uri/.document +0 -1
data/lib/bundler/dsl.rb CHANGED
@@ -73,11 +73,11 @@ module Bundler
73
73
  case specs_by_name_and_version.size
74
74
  when 1
75
75
  specs = specs_by_name_and_version.values.first
76
- spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first
76
+ spec = specs.find {|s| s.installable_on_platform?(Bundler.local_platform) } || specs.first
77
77
 
78
78
  @gemspecs << spec
79
79
 
80
- path path, "glob" => glob, "name" => spec.name do
80
+ path path, "glob" => glob, "name" => spec.name, "gemspec" => spec do
81
81
  add_dependency spec.name
82
82
  end
83
83
 
@@ -141,8 +141,7 @@ module Bundler
141
141
  def path(path, options = {}, &blk)
142
142
  source_options = normalize_hash(options).merge(
143
143
  "path" => Pathname.new(path),
144
- "root_path" => gemfile_root,
145
- "gemspec" => gemspecs.find {|g| g.name == options["name"] }
144
+ "root_path" => gemfile_root
146
145
  )
147
146
 
148
147
  source_options["global"] = true unless block_given?
@@ -241,28 +240,27 @@ module Bundler
241
240
  dep = Dependency.new(name, version, options)
242
241
 
243
242
  # if there's already a dependency with this name we try to prefer one
244
- if current = @dependencies.find {|d| d.name == dep.name }
243
+ if current = @dependencies.find {|d| d.name == name }
245
244
  if current.requirement != dep.requirement
246
245
  current_requirement_open = current.requirements_list.include?(">= 0")
247
246
 
248
247
  gemspec_dep = [dep, current].find(&:gemspec_dev_dep?)
249
248
  if gemspec_dep
250
- gemfile_dep = [dep, current].find(&:gemfile_dep?)
251
-
252
- if gemfile_dep && !current_requirement_open
253
- Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \
254
- "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n"
255
- elsif gemfile_dep.nil?
256
- require_relative "vendor/pub_grub/lib/pub_grub/version_range"
257
- require_relative "vendor/pub_grub/lib/pub_grub/version_constraint"
258
- require_relative "vendor/pub_grub/lib/pub_grub/version_union"
259
- require_relative "vendor/pub_grub/lib/pub_grub/rubygems"
260
-
261
- current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement)
262
- next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement)
263
-
264
- if current_gemspec_range.intersects?(next_gemspec_range)
265
- dep = Dependency.new(name, current.requirement.as_list + dep.requirement.as_list, options)
249
+ require_relative "vendor/pub_grub/lib/pub_grub/version_range"
250
+ require_relative "vendor/pub_grub/lib/pub_grub/version_constraint"
251
+ require_relative "vendor/pub_grub/lib/pub_grub/version_union"
252
+ require_relative "vendor/pub_grub/lib/pub_grub/rubygems"
253
+
254
+ current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement)
255
+ next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement)
256
+
257
+ if current_gemspec_range.intersects?(next_gemspec_range)
258
+ dep = Dependency.new(name, current.requirement.as_list + dep.requirement.as_list, options)
259
+ else
260
+ gemfile_dep = [dep, current].find(&:gemfile_dep?)
261
+
262
+ if gemfile_dep
263
+ raise GemfileError, "The #{name} dependency has conflicting requirements in Gemfile (#{gemfile_dep.requirement}) and gemspec (#{gemspec_dep.requirement})"
266
264
  else
267
265
  raise GemfileError, "Two gemspec development dependencies have conflicting requirements on the same gem: #{dep} and #{current}"
268
266
  end
@@ -274,14 +272,14 @@ module Bundler
274
272
  if dep.requirements_list.include?(">= 0") && !current_requirement_open
275
273
  update_prompt = ". Gem already added"
276
274
  else
277
- update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`"
275
+ update_prompt = ". If you want to update the gem version, run `bundle update #{name}`"
278
276
 
279
277
  update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current_requirement_open
280
278
  end
281
279
  end
282
280
 
283
281
  raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
284
- "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
282
+ "You specified: #{name} (#{current.requirement}) and #{name} (#{dep.requirement})" \
285
283
  "#{update_prompt}"
286
284
  end
287
285
  end
@@ -294,10 +292,10 @@ module Bundler
294
292
  return
295
293
  elsif current.source != dep.source
296
294
  raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
297
- "You specified that #{dep.name} (#{dep.requirement}) should come from " \
295
+ "You specified that #{name} (#{dep.requirement}) should come from " \
298
296
  "#{current.source || "an unspecified source"} and #{dep.source}\n"
299
297
  else
300
- Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
298
+ Bundler.ui.warn "Your Gemfile lists the gem #{name} (#{current.requirement}) more than once.\n" \
301
299
  "You should probably keep only one of them.\n" \
302
300
  "Remove any duplicate entries and specify the gem only once.\n" \
303
301
  "While it's not a problem now, it could cause errors if you change the version of one of them later."
@@ -413,6 +411,7 @@ module Bundler
413
411
  next if VALID_PLATFORMS.include?(p)
414
412
  raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
415
413
  end
414
+ deprecate_legacy_windows_platforms(platforms)
416
415
 
417
416
  # Save sources passed in a key
418
417
  if opts.key?("source")
@@ -493,6 +492,16 @@ module Bundler
493
492
  end
494
493
  end
495
494
 
495
+ def deprecate_legacy_windows_platforms(platforms)
496
+ windows_platforms = platforms.select {|pl| pl.to_s.match?(/mingw|mswin/) }
497
+ return if windows_platforms.empty?
498
+
499
+ windows_platforms = windows_platforms.map! {|pl| ":#{pl}" }.join(", ")
500
+ message = "Platform #{windows_platforms} is deprecated. Please use platform :windows instead."
501
+ removed_message = "Platform #{windows_platforms} has been removed. Please use platform :windows instead."
502
+ Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
503
+ end
504
+
496
505
  def check_path_source_safety
497
506
  return if @sources.global_path_source.nil?
498
507
 
@@ -512,7 +521,7 @@ module Bundler
512
521
  end
513
522
 
514
523
  def multiple_global_source_warning
515
- if Bundler.feature_flag.bundler_3_mode?
524
+ if Bundler.feature_flag.bundler_4_mode?
516
525
  msg = "This Gemfile contains multiple global sources. " \
517
526
  "Each source after the first must include a block to indicate which gems " \
518
527
  "should come from that source"
@@ -193,6 +193,24 @@ module Bundler
193
193
  status_code(31)
194
194
  end
195
195
 
196
+ class ReadOnlyFileSystemError < PermissionError
197
+ def message
198
+ "There was an error while trying to #{action} `#{@path}`. " \
199
+ "File system is read-only."
200
+ end
201
+
202
+ status_code(42)
203
+ end
204
+
205
+ class OperationNotPermittedError < PermissionError
206
+ def message
207
+ "There was an error while trying to #{action} `#{@path}`. " \
208
+ "Underlying OS system call raised an EPERM error."
209
+ end
210
+
211
+ status_code(43)
212
+ end
213
+
196
214
  class GenericSystemCallError < BundlerError
197
215
  attr_reader :underlying_error
198
216
 
@@ -27,20 +27,23 @@ module Bundler
27
27
 
28
28
  (1..10).each {|v| define_method("bundler_#{v}_mode?") { @major_version >= v } }
29
29
 
30
- settings_flag(:allow_offline_install) { bundler_3_mode? }
31
- settings_flag(:auto_clean_without_path) { bundler_3_mode? }
32
- settings_flag(:cache_all) { bundler_3_mode? }
33
- settings_flag(:default_install_uses_path) { bundler_3_mode? }
34
- settings_flag(:forget_cli_options) { bundler_3_mode? }
35
- settings_flag(:global_gem_cache) { bundler_3_mode? }
36
- settings_flag(:lockfile_checksums) { bundler_3_mode? }
37
- settings_flag(:path_relative_to_cwd) { bundler_3_mode? }
30
+ settings_flag(:allow_offline_install) { bundler_4_mode? }
31
+ settings_flag(:cache_all) { bundler_4_mode? }
32
+ settings_flag(:forget_cli_options) { bundler_4_mode? }
33
+ settings_flag(:global_gem_cache) { bundler_4_mode? }
34
+ settings_flag(:lockfile_checksums) { bundler_4_mode? }
38
35
  settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") }
39
- settings_flag(:print_only_version_number) { bundler_3_mode? }
40
- settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? }
41
- settings_flag(:update_requires_all_flag) { bundler_4_mode? }
36
+ settings_flag(:update_requires_all_flag) { bundler_5_mode? }
42
37
 
43
- settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install }
38
+ settings_option(:default_cli_command) { bundler_4_mode? ? :cli_help : :install }
39
+
40
+ def removed_major?(target_major_version)
41
+ @major_version > target_major_version
42
+ end
43
+
44
+ def deprecated_major?(target_major_version)
45
+ @major_version >= target_major_version
46
+ end
44
47
 
45
48
  def initialize(bundler_version)
46
49
  @bundler_version = Gem::Version.create(bundler_version)
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "base"
4
- require "cgi"
4
+ require "cgi/escape"
5
+ require "cgi/util" unless defined?(CGI::EscapeExt)
5
6
 
6
7
  module Bundler
7
8
  class Fetcher
@@ -3,6 +3,28 @@
3
3
  module Bundler
4
4
  class Fetcher
5
5
  class Downloader
6
+ HTTP_NON_RETRYABLE_ERRORS = [
7
+ SocketError,
8
+ Errno::EADDRNOTAVAIL,
9
+ Errno::ENETDOWN,
10
+ Errno::ENETUNREACH,
11
+ Gem::Net::HTTP::Persistent::Error,
12
+ Errno::EHOSTUNREACH,
13
+ ].freeze
14
+
15
+ HTTP_RETRYABLE_ERRORS = [
16
+ Gem::Timeout::Error,
17
+ EOFError,
18
+ Errno::EINVAL,
19
+ Errno::ECONNRESET,
20
+ Errno::ETIMEDOUT,
21
+ Errno::EAGAIN,
22
+ Gem::Net::HTTPBadResponse,
23
+ Gem::Net::HTTPHeaderSyntaxError,
24
+ Gem::Net::ProtocolError,
25
+ Zlib::BufError,
26
+ ].freeze
27
+
6
28
  attr_reader :connection
7
29
  attr_reader :redirect_limit
8
30
 
@@ -67,15 +89,19 @@ module Bundler
67
89
  connection.request(uri, req)
68
90
  rescue OpenSSL::SSL::SSLError
69
91
  raise CertificateFailureError.new(uri)
70
- rescue *HTTP_ERRORS => e
92
+ rescue *HTTP_NON_RETRYABLE_ERRORS => e
71
93
  Bundler.ui.trace e
72
- if e.is_a?(SocketError) || e.message.to_s.include?("host down:")
73
- raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \
74
- "connection and try again."
75
- else
76
- raise HTTPError, "Network error while fetching #{filtered_uri}" \
94
+
95
+ host = uri.host
96
+ host_port = "#{host}:#{uri.port}"
97
+ host = host_port if filtered_uri.to_s.include?(host_port)
98
+ raise NetworkDownError, "Could not reach host #{host}. Check your network " \
99
+ "connection and try again."
100
+ rescue *HTTP_RETRYABLE_ERRORS => e
101
+ Bundler.ui.trace e
102
+
103
+ raise HTTPError, "Network error while fetching #{filtered_uri}" \
77
104
  " (#{e})"
78
- end
79
105
  end
80
106
 
81
107
  private
@@ -2,7 +2,6 @@
2
2
 
3
3
  require_relative "vendored_persistent"
4
4
  require_relative "vendored_timeout"
5
- require "cgi"
6
5
  require_relative "vendored_securerandom"
7
6
  require "zlib"
8
7
 
@@ -73,19 +72,57 @@ module Bundler
73
72
  end
74
73
  end
75
74
 
75
+ HTTP_ERRORS = (Downloader::HTTP_RETRYABLE_ERRORS + Downloader::HTTP_NON_RETRYABLE_ERRORS).freeze
76
+ deprecate_constant :HTTP_ERRORS
77
+
78
+ NET_ERRORS = [
79
+ :HTTPBadGateway,
80
+ :HTTPBadRequest,
81
+ :HTTPFailedDependency,
82
+ :HTTPForbidden,
83
+ :HTTPInsufficientStorage,
84
+ :HTTPMethodNotAllowed,
85
+ :HTTPMovedPermanently,
86
+ :HTTPNoContent,
87
+ :HTTPNotFound,
88
+ :HTTPNotImplemented,
89
+ :HTTPPreconditionFailed,
90
+ :HTTPRequestEntityTooLarge,
91
+ :HTTPRequestURITooLong,
92
+ :HTTPUnauthorized,
93
+ :HTTPUnprocessableEntity,
94
+ :HTTPUnsupportedMediaType,
95
+ :HTTPVersionNotSupported,
96
+ ].freeze
97
+ deprecate_constant :NET_ERRORS
98
+
76
99
  # Exceptions classes that should bypass retry attempts. If your password didn't work the
77
100
  # first time, it's not going to the third time.
78
- NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency,
79
- :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed,
80
- :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound,
81
- :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge,
82
- :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
83
- :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
84
- FAIL_ERRORS = begin
85
- fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError]
86
- fail_errors << Gem::Requirement::BadRequirementError
87
- fail_errors.concat(NET_ERRORS.map {|e| Gem::Net.const_get(e) })
88
- end.freeze
101
+ FAIL_ERRORS = [
102
+ AuthenticationRequiredError,
103
+ BadAuthenticationError,
104
+ AuthenticationForbiddenError,
105
+ FallbackError,
106
+ SecurityError,
107
+ Gem::Requirement::BadRequirementError,
108
+ Gem::Net::HTTPBadGateway,
109
+ Gem::Net::HTTPBadRequest,
110
+ Gem::Net::HTTPFailedDependency,
111
+ Gem::Net::HTTPForbidden,
112
+ Gem::Net::HTTPInsufficientStorage,
113
+ Gem::Net::HTTPMethodNotAllowed,
114
+ Gem::Net::HTTPMovedPermanently,
115
+ Gem::Net::HTTPNoContent,
116
+ Gem::Net::HTTPNotFound,
117
+ Gem::Net::HTTPNotImplemented,
118
+ Gem::Net::HTTPPreconditionFailed,
119
+ Gem::Net::HTTPRequestEntityTooLarge,
120
+ Gem::Net::HTTPRequestURITooLong,
121
+ Gem::Net::HTTPUnauthorized,
122
+ Gem::Net::HTTPUnprocessableEntity,
123
+ Gem::Net::HTTPUnsupportedMediaType,
124
+ Gem::Net::HTTPVersionNotSupported,
125
+ ].freeze
89
126
 
90
127
  class << self
91
128
  attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries
@@ -294,13 +331,6 @@ module Bundler
294
331
  paths.find {|path| File.file? path }
295
332
  end
296
333
 
297
- HTTP_ERRORS = [
298
- Gem::Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
299
- Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
300
- Gem::Net::HTTPBadResponse, Gem::Net::HTTPHeaderSyntaxError, Gem::Net::ProtocolError,
301
- Gem::Net::HTTP::Persistent::Error, Zlib::BufError, Errno::EHOSTUNREACH
302
- ].freeze
303
-
304
334
  def bundler_cert_store
305
335
  store = OpenSSL::X509::Store.new
306
336
  ssl_ca_cert = Bundler.settings[:ssl_ca_cert] ||
@@ -80,7 +80,7 @@ module Bundler
80
80
  First, try this link to see if there are any existing issue reports for this error:
81
81
  #{issues_url(e)}
82
82
 
83
- If there aren't any reports for this error yet, please fill in the new issue form located at #{new_issue_url}, and copy and paste the report template above in there.
83
+ If there aren't any reports for this error yet, please fill in the new issue form located at #{new_issue_url}. Make sure to copy and paste the full output of this command under the "What happened instead?" section.
84
84
  EOS
85
85
  end
86
86
 
@@ -102,7 +102,8 @@ module Bundler
102
102
  def issues_url(exception)
103
103
  message = exception.message.lines.first.tr(":", " ").chomp
104
104
  message = message.split("-").first if exception.is_a?(Errno)
105
- require "cgi"
105
+ require "cgi/escape"
106
+ require "cgi/util" unless defined?(CGI::EscapeExt)
106
107
  "https://github.com/rubygems/rubygems/search?q=" \
107
108
  "#{CGI.escape(message)}&type=Issues"
108
109
  end
data/lib/bundler/index.rb CHANGED
@@ -131,6 +131,11 @@ module Bundler
131
131
  return unless other
132
132
  other.each do |spec|
133
133
  if existing = find_by_spec(spec)
134
+ unless dependencies_eql?(existing, spec)
135
+ Bundler.ui.warn "Local specification for #{spec.full_name} has different dependencies than the remote gem, ignoring it"
136
+ next
137
+ end
138
+
134
139
  add_duplicate(existing)
135
140
  end
136
141
  add spec
@@ -153,8 +158,8 @@ module Bundler
153
158
  end
154
159
 
155
160
  def dependencies_eql?(spec, other_spec)
156
- deps = spec.dependencies.select {|d| d.type != :development }
157
- other_deps = other_spec.dependencies.select {|d| d.type != :development }
161
+ deps = spec.runtime_dependencies
162
+ other_deps = other_spec.runtime_dependencies
158
163
  deps.sort == other_deps.sort
159
164
  end
160
165
 
@@ -108,17 +108,17 @@ module Bundler
108
108
  end
109
109
 
110
110
  if d.groups != Array(:default)
111
- group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}"
111
+ group = d.groups.size == 1 ? ", group: #{d.groups.first.inspect}" : ", groups: #{d.groups.inspect}"
112
112
  end
113
113
 
114
- source = ", :source => \"#{d.source}\"" unless d.source.nil?
115
- path = ", :path => \"#{d.path}\"" unless d.path.nil?
116
- git = ", :git => \"#{d.git}\"" unless d.git.nil?
117
- github = ", :github => \"#{d.github}\"" unless d.github.nil?
118
- branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil?
119
- ref = ", :ref => \"#{d.ref}\"" unless d.ref.nil?
120
- glob = ", :glob => \"#{d.glob}\"" unless d.glob.nil?
121
- require_path = ", :require => #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil?
114
+ source = ", source: \"#{d.source}\"" unless d.source.nil?
115
+ path = ", path: \"#{d.path}\"" unless d.path.nil?
116
+ git = ", git: \"#{d.git}\"" unless d.git.nil?
117
+ github = ", github: \"#{d.github}\"" unless d.github.nil?
118
+ branch = ", branch: \"#{d.branch}\"" unless d.branch.nil?
119
+ ref = ", ref: \"#{d.ref}\"" unless d.ref.nil?
120
+ glob = ", glob: \"#{d.glob}\"" unless d.glob.nil?
121
+ require_path = ", require: #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil?
122
122
 
123
123
  %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{glob}#{require_path})
124
124
  end.join("\n")
@@ -91,6 +91,11 @@ module Bundler
91
91
  end
92
92
 
93
93
  def generate_bundler_executable_stubs(spec, options = {})
94
+ if spec.name == "bundler"
95
+ Bundler.ui.warn "Bundler itself does not use binstubs because its version is selected by RubyGems"
96
+ return
97
+ end
98
+
94
99
  if options[:binstubs_cmd] && spec.executables.empty?
95
100
  options = {}
96
101
  spec.runtime_dependencies.each do |dep|
@@ -115,10 +120,6 @@ module Bundler
115
120
  ruby_command = Thor::Util.ruby_command
116
121
  ruby_command = ruby_command
117
122
  template_path = File.expand_path("templates/Executable", __dir__)
118
- if spec.name == "bundler"
119
- template_path += ".bundler"
120
- spec.executables = %(bundle)
121
- end
122
123
  template = File.read(template_path)
123
124
 
124
125
  exists = []
@@ -212,7 +213,7 @@ module Bundler
212
213
  def load_plugins
213
214
  Gem.load_plugins
214
215
 
215
- requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
216
+ requested_path_gems = @definition.specs.select {|s| s.source.is_a?(Source::Path) }
216
217
  path_plugin_files = requested_path_gems.flat_map do |spec|
217
218
  spec.matches_for_glob("rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
218
219
  rescue TypeError
@@ -33,7 +33,7 @@ module Bundler
33
33
  lazy_spec
34
34
  end
35
35
 
36
- def initialize(name, version, platform, source = nil)
36
+ def initialize(name, version, platform, source = nil, **materialization_options)
37
37
  @name = name
38
38
  @version = version
39
39
  @dependencies = []
@@ -43,6 +43,7 @@ module Bundler
43
43
 
44
44
  @original_source = source
45
45
  @source = source
46
+ @materialization_options = materialization_options
46
47
 
47
48
  @force_ruby_platform = default_force_ruby_platform
48
49
  @most_specific_locked_platform = nil
@@ -142,15 +143,15 @@ module Bundler
142
143
  end
143
144
  else
144
145
  materialize([name, version]) do |matching_specs|
145
- target_platform = source.is_a?(Source::Path) ? platform : local_platform
146
+ target_platform = source.is_a?(Source::Path) ? platform : Bundler.local_platform
146
147
 
147
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
148
+ installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, target_platform)
148
149
 
149
150
  specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
150
151
  return specification unless specification.nil?
151
152
 
152
153
  if target_platform != platform
153
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, platform)
154
+ installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, platform)
154
155
  end
155
156
 
156
157
  choose_compatible(installable_candidates)
@@ -175,6 +176,14 @@ module Bundler
175
176
  @force_ruby_platform = true
176
177
  end
177
178
 
179
+ def replace_source_with!(gemfile_source)
180
+ return unless gemfile_source.can_lock?(self)
181
+
182
+ @source = gemfile_source
183
+
184
+ true
185
+ end
186
+
178
187
  private
179
188
 
180
189
  def use_exact_resolved_specifications?
@@ -182,7 +191,7 @@ module Bundler
182
191
  end
183
192
 
184
193
  def ruby_platform_materializes_to_ruby_platform?
185
- generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
194
+ generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
186
195
 
187
196
  (most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform]
188
197
  end
@@ -196,7 +205,7 @@ module Bundler
196
205
 
197
206
  # If in frozen mode, we fallback to a non-installable candidate because by
198
207
  # doing this we avoid re-resolving and potentially end up changing the
199
- # lock file, which is not allowed. In that case, we will give a proper error
208
+ # lockfile, which is not allowed. In that case, we will give a proper error
200
209
  # about the mismatch higher up the stack, right before trying to install the
201
210
  # bad gem.
202
211
  def choose_compatible(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
@@ -205,22 +214,32 @@ module Bundler
205
214
  end
206
215
  if search.nil? && fallback_to_non_installable
207
216
  search = candidates.last
208
- elsif search && search.full_name == full_name
209
- # We don't validate locally installed dependencies but accept what's in
210
- # the lockfile instead for performance, since loading locally installed
211
- # dependencies would mean evaluating all gemspecs, which would affect
212
- # `bundler/setup` performance
213
- if search.is_a?(StubSpecification)
214
- search.dependencies = dependencies
215
- else
216
- if !source.is_a?(Source::Path) && search.runtime_dependencies.sort != dependencies.sort
217
- raise IncorrectLockfileDependencies.new(self)
218
- end
217
+ end
219
218
 
220
- search.locked_platform = platform if search.instance_of?(RemoteSpecification) || search.instance_of?(EndpointSpecification)
221
- end
219
+ if search
220
+ validate_dependencies(search) if search.platform == platform
221
+
222
+ search.locked_platform = platform if search.instance_of?(RemoteSpecification) || search.instance_of?(EndpointSpecification)
222
223
  end
223
224
  search
224
225
  end
226
+
227
+ # Validate dependencies of this locked spec are consistent with dependencies
228
+ # of the actual spec that was materialized.
229
+ #
230
+ # Note that unless we are in strict mode (which we set during installation)
231
+ # we don't validate dependencies of locally installed gems but
232
+ # accept what's in the lockfile instead for performance, since loading
233
+ # dependencies of locally installed gems would mean evaluating all gemspecs,
234
+ # which would affect `bundler/setup` performance.
235
+ def validate_dependencies(spec)
236
+ if !@materialization_options[:strict] && spec.is_a?(StubSpecification)
237
+ spec.dependencies = dependencies
238
+ else
239
+ if !source.is_a?(Source::Path) && spec.runtime_dependencies.sort != dependencies.sort
240
+ raise IncorrectLockfileDependencies.new(self)
241
+ end
242
+ end
243
+ end
225
244
  end
226
245
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "shared_helpers"
4
+
3
5
  module Bundler
4
6
  class LockfileParser
5
- include GemHelpers
6
-
7
7
  class Position
8
8
  attr_reader :line, :column
9
9
  def initialize(line, column)
@@ -94,7 +94,7 @@ module Bundler
94
94
  lockfile_contents.split(BUNDLED).last.strip
95
95
  end
96
96
 
97
- def initialize(lockfile)
97
+ def initialize(lockfile, strict: false)
98
98
  @platforms = []
99
99
  @sources = []
100
100
  @dependencies = {}
@@ -106,6 +106,7 @@ module Bundler
106
106
  "Gemfile.lock"
107
107
  end
108
108
  @pos = Position.new(1, 1)
109
+ @strict = strict
109
110
 
110
111
  if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
111
112
  raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
@@ -139,8 +140,23 @@ module Bundler
139
140
  end
140
141
  @pos.advance!(line)
141
142
  end
143
+
144
+ if !Bundler.frozen_bundle? && @platforms.include?(Gem::Platform::X64_MINGW_LEGACY)
145
+ if @platforms.include?(Gem::Platform::X64_MINGW)
146
+ @platforms.delete(Gem::Platform::X64_MINGW_LEGACY)
147
+ SharedHelpers.major_deprecation(2,
148
+ "Found x64-mingw32 in lockfile, which is deprecated. Removing it. Support for x64-mingw32 will be removed in Bundler 4.0.",
149
+ removed_message: "Found x64-mingw32 in lockfile, which is no longer supported as of Bundler 4.0.")
150
+ else
151
+ @platforms[@platforms.index(Gem::Platform::X64_MINGW_LEGACY)] = Gem::Platform::X64_MINGW
152
+ SharedHelpers.major_deprecation(2,
153
+ "Found x64-mingw32 in lockfile, which is deprecated. Using x64-mingw-ucrt, the replacement for x64-mingw32 in modern rubies, instead. Support for x64-mingw32 will be removed in Bundler 4.0.",
154
+ removed_message: "Found x64-mingw32 in lockfile, which is no longer supported as of Bundler 4.0.")
155
+ end
156
+ end
157
+
142
158
  @most_specific_locked_platform = @platforms.min_by do |bundle_platform|
143
- platform_specificity_match(bundle_platform, local_platform)
159
+ Gem::Platform.platform_specificity_match(bundle_platform, Bundler.local_platform)
144
160
  end
145
161
  @specs = @specs.values.sort_by!(&:full_name).each do |spec|
146
162
  spec.most_specific_locked_platform = @most_specific_locked_platform
@@ -239,7 +255,6 @@ module Bundler
239
255
  spaces = $1
240
256
  return unless spaces.size == 2
241
257
  checksums = $6
242
- return unless checksums
243
258
  name = $2
244
259
  version = $3
245
260
  platform = $4
@@ -249,10 +264,14 @@ module Bundler
249
264
  full_name = Gem::NameTuple.new(name, version, platform).full_name
250
265
  return unless spec = @specs[full_name]
251
266
 
252
- checksums.split(",") do |lock_checksum|
253
- column = line.index(lock_checksum) + 1
254
- checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
255
- spec.source.checksum_store.register(spec, checksum)
267
+ if checksums
268
+ checksums.split(",") do |lock_checksum|
269
+ column = line.index(lock_checksum) + 1
270
+ checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
271
+ spec.source.checksum_store.register(spec, checksum)
272
+ end
273
+ else
274
+ spec.source.checksum_store.register(spec, nil)
256
275
  end
257
276
  end
258
277
 
@@ -268,7 +287,7 @@ module Bundler
268
287
 
269
288
  version = Gem::Version.new(version)
270
289
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
271
- @current_spec = LazySpecification.new(name, version, platform, @current_source)
290
+ @current_spec = LazySpecification.new(name, version, platform, @current_source, strict: @strict)
272
291
  @current_source.add_dependency_names(name)
273
292
 
274
293
  @specs[@current_spec.full_name] = @current_spec