bundler 2.6.9 → 2.7.2

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1136 -1033
  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 +6 -0
  7. data/lib/bundler/cli/cache.rb +0 -1
  8. data/lib/bundler/cli/common.rb +1 -1
  9. data/lib/bundler/cli/config.rb +2 -2
  10. data/lib/bundler/cli/gem.rb +62 -30
  11. data/lib/bundler/cli/install.rb +5 -7
  12. data/lib/bundler/cli/lock.rb +5 -5
  13. data/lib/bundler/cli/outdated.rb +1 -1
  14. data/lib/bundler/cli/show.rb +2 -6
  15. data/lib/bundler/cli/update.rb +3 -3
  16. data/lib/bundler/cli.rb +45 -49
  17. data/lib/bundler/compact_index_client.rb +1 -5
  18. data/lib/bundler/current_ruby.rb +27 -3
  19. data/lib/bundler/definition.rb +97 -81
  20. data/lib/bundler/dependency.rb +1 -1
  21. data/lib/bundler/dsl.rb +34 -24
  22. data/lib/bundler/feature_flag.rb +15 -12
  23. data/lib/bundler/fetcher/dependency.rb +2 -1
  24. data/lib/bundler/fetcher/downloader.rb +33 -7
  25. data/lib/bundler/fetcher.rb +49 -19
  26. data/lib/bundler/friendly_errors.rb +2 -1
  27. data/lib/bundler/index.rb +7 -2
  28. data/lib/bundler/installer.rb +5 -4
  29. data/lib/bundler/lazy_specification.rb +9 -7
  30. data/lib/bundler/lockfile_parser.rb +21 -5
  31. data/lib/bundler/man/bundle-add.1 +1 -1
  32. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  33. data/lib/bundler/man/bundle-cache.1 +1 -1
  34. data/lib/bundler/man/bundle-check.1 +1 -1
  35. data/lib/bundler/man/bundle-clean.1 +1 -1
  36. data/lib/bundler/man/bundle-config.1 +200 -137
  37. data/lib/bundler/man/bundle-config.1.ronn +138 -109
  38. data/lib/bundler/man/bundle-console.1 +1 -1
  39. data/lib/bundler/man/bundle-doctor.1 +43 -4
  40. data/lib/bundler/man/bundle-doctor.1.ronn +48 -4
  41. data/lib/bundler/man/bundle-env.1 +1 -1
  42. data/lib/bundler/man/bundle-exec.1 +1 -1
  43. data/lib/bundler/man/bundle-fund.1 +1 -1
  44. data/lib/bundler/man/bundle-gem.1 +67 -44
  45. data/lib/bundler/man/bundle-gem.1.ronn +8 -4
  46. data/lib/bundler/man/bundle-help.1 +1 -1
  47. data/lib/bundler/man/bundle-info.1 +1 -1
  48. data/lib/bundler/man/bundle-init.1 +1 -1
  49. data/lib/bundler/man/bundle-inject.1 +2 -2
  50. data/lib/bundler/man/bundle-inject.1.ronn +1 -1
  51. data/lib/bundler/man/bundle-install.1 +4 -4
  52. data/lib/bundler/man/bundle-install.1.ronn +3 -4
  53. data/lib/bundler/man/bundle-issue.1 +1 -1
  54. data/lib/bundler/man/bundle-licenses.1 +1 -1
  55. data/lib/bundler/man/bundle-list.1 +1 -1
  56. data/lib/bundler/man/bundle-lock.1 +1 -1
  57. data/lib/bundler/man/bundle-open.1 +1 -1
  58. data/lib/bundler/man/bundle-outdated.1 +1 -1
  59. data/lib/bundler/man/bundle-platform.1 +1 -1
  60. data/lib/bundler/man/bundle-plugin.1 +40 -15
  61. data/lib/bundler/man/bundle-plugin.1.ronn +44 -15
  62. data/lib/bundler/man/bundle-pristine.1 +1 -1
  63. data/lib/bundler/man/bundle-remove.1 +1 -1
  64. data/lib/bundler/man/bundle-show.1 +1 -1
  65. data/lib/bundler/man/bundle-update.1 +5 -5
  66. data/lib/bundler/man/bundle-update.1.ronn +4 -4
  67. data/lib/bundler/man/bundle-version.1 +1 -1
  68. data/lib/bundler/man/bundle-viz.1 +1 -1
  69. data/lib/bundler/man/bundle.1 +1 -1
  70. data/lib/bundler/man/gemfile.5 +1 -1
  71. data/lib/bundler/match_platform.rb +31 -12
  72. data/lib/bundler/materialization.rb +2 -2
  73. data/lib/bundler/resolver/package.rb +2 -1
  74. data/lib/bundler/resolver.rb +1 -3
  75. data/lib/bundler/rubygems_ext.rb +116 -120
  76. data/lib/bundler/rubygems_integration.rb +11 -6
  77. data/lib/bundler/runtime.rb +1 -1
  78. data/lib/bundler/self_manager.rb +32 -42
  79. data/lib/bundler/settings/validator.rb +0 -23
  80. data/lib/bundler/settings.rb +4 -6
  81. data/lib/bundler/shared_helpers.rb +6 -4
  82. data/lib/bundler/source/gemspec.rb +4 -0
  83. data/lib/bundler/source/git/git_proxy.rb +3 -3
  84. data/lib/bundler/source/path.rb +9 -0
  85. data/lib/bundler/source_list.rb +1 -5
  86. data/lib/bundler/source_map.rb +1 -1
  87. data/lib/bundler/spec_set.rb +7 -3
  88. data/lib/bundler/templates/Executable +0 -11
  89. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +2 -0
  90. data/lib/bundler/templates/newgem/newgem.gemspec.tt +6 -5
  91. data/lib/bundler/ui/shell.rb +2 -2
  92. data/lib/bundler/vendor/net-http-persistent/README.rdoc +1 -1
  93. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +2 -1
  94. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +81 -42
  95. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +42 -6
  96. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +1 -1
  97. data/lib/bundler/vendor/thor/lib/thor/runner.rb +1 -1
  98. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +3 -7
  99. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  100. data/lib/bundler/version.rb +10 -2
  101. data/lib/bundler/worker.rb +1 -1
  102. data/lib/bundler.rb +14 -12
  103. metadata +4 -14
  104. data/lib/bundler/gem_helpers.rb +0 -144
  105. data/lib/bundler/templates/Executable.bundler +0 -109
  106. data/lib/bundler/vendor/connection_pool/.document +0 -1
  107. data/lib/bundler/vendor/fileutils/.document +0 -1
  108. data/lib/bundler/vendor/net-http-persistent/.document +0 -1
  109. data/lib/bundler/vendor/pub_grub/.document +0 -1
  110. data/lib/bundler/vendor/securerandom/.document +0 -1
  111. data/lib/bundler/vendor/thor/.document +0 -1
  112. data/lib/bundler/vendor/tsort/.document +0 -1
  113. data/lib/bundler/vendor/uri/.document +0 -1
data/lib/bundler/dsl.rb CHANGED
@@ -73,7 +73,7 @@ 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
 
@@ -240,28 +240,27 @@ module Bundler
240
240
  dep = Dependency.new(name, version, options)
241
241
 
242
242
  # if there's already a dependency with this name we try to prefer one
243
- if current = @dependencies.find {|d| d.name == dep.name }
243
+ if current = @dependencies.find {|d| d.name == name }
244
244
  if current.requirement != dep.requirement
245
245
  current_requirement_open = current.requirements_list.include?(">= 0")
246
246
 
247
247
  gemspec_dep = [dep, current].find(&:gemspec_dev_dep?)
248
248
  if gemspec_dep
249
- gemfile_dep = [dep, current].find(&:gemfile_dep?)
250
-
251
- if gemfile_dep && !current_requirement_open
252
- 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" \
253
- "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n"
254
- elsif gemfile_dep.nil?
255
- require_relative "vendor/pub_grub/lib/pub_grub/version_range"
256
- require_relative "vendor/pub_grub/lib/pub_grub/version_constraint"
257
- require_relative "vendor/pub_grub/lib/pub_grub/version_union"
258
- require_relative "vendor/pub_grub/lib/pub_grub/rubygems"
259
-
260
- current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement)
261
- next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement)
262
-
263
- if current_gemspec_range.intersects?(next_gemspec_range)
264
- 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})"
265
264
  else
266
265
  raise GemfileError, "Two gemspec development dependencies have conflicting requirements on the same gem: #{dep} and #{current}"
267
266
  end
@@ -273,14 +272,14 @@ module Bundler
273
272
  if dep.requirements_list.include?(">= 0") && !current_requirement_open
274
273
  update_prompt = ". Gem already added"
275
274
  else
276
- 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}`"
277
276
 
278
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
279
278
  end
280
279
  end
281
280
 
282
281
  raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
283
- "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
282
+ "You specified: #{name} (#{current.requirement}) and #{name} (#{dep.requirement})" \
284
283
  "#{update_prompt}"
285
284
  end
286
285
  end
@@ -291,12 +290,12 @@ module Bundler
291
290
  @dependencies.delete(current)
292
291
  elsif dep.gemspec_dev_dep?
293
292
  return
294
- elsif current.source != dep.source
293
+ elsif current.source.to_s != dep.source.to_s
295
294
  raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
296
- "You specified that #{dep.name} (#{dep.requirement}) should come from " \
295
+ "You specified that #{name} (#{dep.requirement}) should come from " \
297
296
  "#{current.source || "an unspecified source"} and #{dep.source}\n"
298
297
  else
299
- 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" \
300
299
  "You should probably keep only one of them.\n" \
301
300
  "Remove any duplicate entries and specify the gem only once.\n" \
302
301
  "While it's not a problem now, it could cause errors if you change the version of one of them later."
@@ -412,6 +411,7 @@ module Bundler
412
411
  next if VALID_PLATFORMS.include?(p)
413
412
  raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
414
413
  end
414
+ deprecate_legacy_windows_platforms(platforms)
415
415
 
416
416
  # Save sources passed in a key
417
417
  if opts.key?("source")
@@ -492,6 +492,16 @@ module Bundler
492
492
  end
493
493
  end
494
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
+
495
505
  def check_path_source_safety
496
506
  return if @sources.global_path_source.nil?
497
507
 
@@ -511,7 +521,7 @@ module Bundler
511
521
  end
512
522
 
513
523
  def multiple_global_source_warning
514
- if Bundler.feature_flag.bundler_3_mode?
524
+ if Bundler.feature_flag.bundler_4_mode?
515
525
  msg = "This Gemfile contains multiple global sources. " \
516
526
  "Each source after the first must include a block to indicate which gems " \
517
527
  "should come from that source"
@@ -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_5_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] ||
@@ -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
 
@@ -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 = []
@@ -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)
@@ -190,7 +191,7 @@ module Bundler
190
191
  end
191
192
 
192
193
  def ruby_platform_materializes_to_ruby_platform?
193
- 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
194
195
 
195
196
  (most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform]
196
197
  end
@@ -226,12 +227,13 @@ module Bundler
226
227
  # Validate dependencies of this locked spec are consistent with dependencies
227
228
  # of the actual spec that was materialized.
228
229
  #
229
- # Note that we don't validate dependencies of locally installed gems but
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
230
232
  # accept what's in the lockfile instead for performance, since loading
231
233
  # dependencies of locally installed gems would mean evaluating all gemspecs,
232
234
  # which would affect `bundler/setup` performance.
233
235
  def validate_dependencies(spec)
234
- if spec.is_a?(StubSpecification)
236
+ if !@materialization_options[:strict] && spec.is_a?(StubSpecification)
235
237
  spec.dependencies = dependencies
236
238
  else
237
239
  if !source.is_a?(Source::Path) && spec.runtime_dependencies.sort != dependencies.sort
@@ -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
@@ -271,7 +287,7 @@ module Bundler
271
287
 
272
288
  version = Gem::Version.new(version)
273
289
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
274
- @current_spec = LazySpecification.new(name, version, platform, @current_source)
290
+ @current_spec = LazySpecification.new(name, version, platform, @current_source, strict: @strict)
275
291
  @current_source.add_dependency_names(name)
276
292
 
277
293
  @specs[@current_spec.full_name] = @current_spec
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-ADD" "1" "March 2025" ""
3
+ .TH "BUNDLE\-ADD" "1" "August 2025" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-BINSTUBS" "1" "March 2025" ""
3
+ .TH "BUNDLE\-BINSTUBS" "1" "August 2025" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-CACHE" "1" "March 2025" ""
3
+ .TH "BUNDLE\-CACHE" "1" "August 2025" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-CHECK" "1" "March 2025" ""
3
+ .TH "BUNDLE\-CHECK" "1" "August 2025" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-CLEAN" "1" "March 2025" ""
3
+ .TH "BUNDLE\-CLEAN" "1" "August 2025" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
6
6
  .SH "SYNOPSIS"