rubygems-update 3.4.19 → 3.4.20

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/bundler/CHANGELOG.md +29 -0
  4. data/bundler/lib/bundler/build_metadata.rb +2 -2
  5. data/bundler/lib/bundler/cli/info.rb +1 -1
  6. data/bundler/lib/bundler/cli/update.rb +1 -0
  7. data/bundler/lib/bundler/fetcher/base.rb +2 -2
  8. data/bundler/lib/bundler/fetcher/compact_index.rb +1 -5
  9. data/bundler/lib/bundler/fetcher/dependency.rb +1 -1
  10. data/bundler/lib/bundler/fetcher.rb +31 -30
  11. data/bundler/lib/bundler/index.rb +62 -31
  12. data/bundler/lib/bundler/installer/standalone.rb +8 -1
  13. data/bundler/lib/bundler/lockfile_parser.rb +3 -15
  14. data/bundler/lib/bundler/man/gemfile.5 +11 -0
  15. data/bundler/lib/bundler/man/gemfile.5.ronn +5 -0
  16. data/bundler/lib/bundler/plugin.rb +1 -1
  17. data/bundler/lib/bundler/resolver.rb +18 -3
  18. data/bundler/lib/bundler/retry.rb +1 -1
  19. data/bundler/lib/bundler/ruby_dsl.rb +23 -2
  20. data/bundler/lib/bundler/self_manager.rb +2 -0
  21. data/bundler/lib/bundler/settings.rb +37 -13
  22. data/bundler/lib/bundler/source/git/git_proxy.rb +14 -2
  23. data/bundler/lib/bundler/source/rubygems.rb +22 -25
  24. data/bundler/lib/bundler/templates/newgem/github/workflows/main.yml.tt +1 -1
  25. data/bundler/lib/bundler/version.rb +1 -1
  26. data/lib/rubygems/available_set.rb +1 -1
  27. data/lib/rubygems/basic_specification.rb +2 -2
  28. data/lib/rubygems/command.rb +16 -19
  29. data/lib/rubygems/commands/cert_command.rb +1 -1
  30. data/lib/rubygems/commands/dependency_command.rb +3 -4
  31. data/lib/rubygems/commands/owner_command.rb +8 -10
  32. data/lib/rubygems/commands/uninstall_command.rb +6 -7
  33. data/lib/rubygems/commands/unpack_command.rb +4 -6
  34. data/lib/rubygems/config_file.rb +1 -1
  35. data/lib/rubygems/core_ext/kernel_gem.rb +1 -1
  36. data/lib/rubygems/core_ext/kernel_warn.rb +4 -5
  37. data/lib/rubygems/dependency_installer.rb +8 -12
  38. data/lib/rubygems/deprecate.rb +2 -2
  39. data/lib/rubygems/gemcutter_utilities.rb +2 -2
  40. data/lib/rubygems/installer.rb +9 -11
  41. data/lib/rubygems/name_tuple.rb +1 -1
  42. data/lib/rubygems/package/tar_reader/entry.rb +18 -20
  43. data/lib/rubygems/package/tar_reader.rb +0 -5
  44. data/lib/rubygems/package.rb +10 -4
  45. data/lib/rubygems/query_utils.rb +1 -1
  46. data/lib/rubygems/request_set/gem_dependency_api.rb +1 -1
  47. data/lib/rubygems/resolver/activation_request.rb +2 -4
  48. data/lib/rubygems/resolver/installed_specification.rb +1 -1
  49. data/lib/rubygems/resolver/local_specification.rb +1 -1
  50. data/lib/rubygems/s3_uri_signer.rb +1 -1
  51. data/lib/rubygems/security/trust_dir.rb +4 -6
  52. data/lib/rubygems/security.rb +1 -1
  53. data/lib/rubygems/source/local.rb +34 -37
  54. data/lib/rubygems/source.rb +2 -2
  55. data/lib/rubygems/source_list.rb +2 -2
  56. data/lib/rubygems/spec_fetcher.rb +29 -33
  57. data/lib/rubygems/specification.rb +34 -26
  58. data/lib/rubygems/specification_policy.rb +33 -32
  59. data/lib/rubygems/stub_specification.rb +13 -10
  60. data/lib/rubygems/uninstaller.rb +1 -1
  61. data/lib/rubygems/user_interaction.rb +2 -2
  62. data/lib/rubygems/util/licenses.rb +115 -0
  63. data/lib/rubygems/validator.rb +5 -7
  64. data/lib/rubygems.rb +5 -7
  65. data/rubygems-update.gemspec +1 -1
  66. data/test/rubygems/helper.rb +17 -19
  67. data/test/rubygems/test_gem.rb +4 -4
  68. data/test/rubygems/test_gem_commands_build_command.rb +2 -1
  69. data/test/rubygems/test_gem_commands_stale_command.rb +1 -1
  70. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock +28 -12
  71. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml +1 -1
  72. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +16 -14
  73. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +1 -1
  74. data/test/rubygems/test_gem_indexer.rb +1 -1
  75. data/test/rubygems/test_gem_package.rb +117 -2
  76. data/test/rubygems/test_gem_package_tar_header.rb +7 -7
  77. data/test/rubygems/test_gem_package_tar_reader_entry.rb +53 -1
  78. data/test/rubygems/test_gem_package_tar_writer.rb +13 -13
  79. data/test/rubygems/test_gem_remote_fetcher.rb +21 -25
  80. data/test/rubygems/test_gem_requirement.rb +1 -1
  81. data/test/rubygems/test_gem_specification.rb +42 -6
  82. data/test/rubygems/test_gem_update_suggestion.rb +14 -20
  83. data/test/rubygems/test_require.rb +4 -6
  84. data/test/rubygems/utilities.rb +2 -2
  85. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d821097ecc787b3a4c9988ecc3caec6ed08c5b70d1f8e49e1a0d397aa9c058d
4
- data.tar.gz: fb2d20653a6a53e6d0ea35b0523f484fc6105038aa4c1255792fb3d19e902718
3
+ metadata.gz: 6d7e2796bcbea4d90f69fc8e0b49f30ff512777fd1f72bfcace6618e01505a24
4
+ data.tar.gz: 1921651535aec5214a2504f28c7b62b405e75b15f01130753543e059bbe3f4e0
5
5
  SHA512:
6
- metadata.gz: d0979e046f97714544683c39a73bd4a8c782340d96955d2b985d026e0417b0369c0e77ee60ef4622da658676fef48d0ce21a9d40286480a00be8e2fbbbbdf1d3
7
- data.tar.gz: c2e09064ca39a839a13f71885710e8102c52b4e601233c01f478c7f14ee74ec5d45695ddcf22e0e4ceaf35634698af00d029cd73c75665b4231f0aac891bd288
6
+ metadata.gz: a8897e246b67854308c5bafd93f42d03bdc3290c63a1dc1c2d706aff9694c393059de946d75fd49c29a1db4d16fe317c6e418e1c93166e000c6a30635166d47f
7
+ data.tar.gz: 479607e63ac5901ed8b904e0502fd26bb671d2700a5343a812e9120cfabfa08d199ce4098ebce337ab47df09cb4fb1e644a850b361467fd40c2d8242e2e6d566
data/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ # 3.4.20 / 2023-09-27
2
+
3
+ ## Enhancements:
4
+
5
+ * Raise `Gem::Package::FormatError` when gem encounters corrupt EOF.
6
+ Pull request [#6882](https://github.com/rubygems/rubygems/pull/6882)
7
+ by martinemde
8
+ * Allow skipping empty license `gem build` warning by setting license to
9
+ `nil`. Pull request
10
+ [#6879](https://github.com/rubygems/rubygems/pull/6879) by jhong97
11
+ * Update SPDX license list as of 2023-06-18. Pull request
12
+ [#6891](https://github.com/rubygems/rubygems/pull/6891) by
13
+ github-actions[bot]
14
+ * Update SPDX license list as of 2023-04-28. Pull request
15
+ [#6642](https://github.com/rubygems/rubygems/pull/6642) by segiddins
16
+ * Update SPDX license list as of 2023-01-26. Pull request
17
+ [#6310](https://github.com/rubygems/rubygems/pull/6310) by segiddins
18
+ * Installs bundler 2.4.20 as a default gem.
19
+
20
+ ## Bug fixes:
21
+
22
+ * Fixed false positive SymlinkError in symbolic link directory. Pull
23
+ request [#6947](https://github.com/rubygems/rubygems/pull/6947) by
24
+ negi0109
25
+ * Ensure that loading multiple gemspecs with legacy YAML class references
26
+ does not warn. Pull request
27
+ [#6889](https://github.com/rubygems/rubygems/pull/6889) by segiddins
28
+ * Fix NoMethodError when choosing a too big number from `gem uni` list.
29
+ Pull request [#6901](https://github.com/rubygems/rubygems/pull/6901) by
30
+ amatsuda
31
+
32
+ ## Performance:
33
+
34
+ * Reduce allocations for stub specifications. Pull request
35
+ [#6972](https://github.com/rubygems/rubygems/pull/6972) by segiddins
36
+
1
37
  # 3.4.19 / 2023-08-17
2
38
 
3
39
  ## Enhancements:
data/bundler/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ # 2.4.20 (September 27, 2023)
2
+
3
+ ## Enhancements:
4
+
5
+ - Bump actions/checkout to v4 in bundler gem template [#6966](https://github.com/rubygems/rubygems/pull/6966)
6
+ - Add support for the `ruby-3.2.2` format in the `ruby file:` Gemfile directive, and explicitly test the `3.2.2@gemset` format as rejected [#6954](https://github.com/rubygems/rubygems/pull/6954)
7
+ - Support `ruby file: ".tool-versions"` in Gemfile [#6898](https://github.com/rubygems/rubygems/pull/6898)
8
+ - Unify LockfileParser loading of SPECS section [#6933](https://github.com/rubygems/rubygems/pull/6933)
9
+ - Only check circular deps when dependency api is available, not on full index sources [#6919](https://github.com/rubygems/rubygems/pull/6919)
10
+
11
+ ## Bug fixes:
12
+
13
+ - Allow standalone mode to work on a Windows edge case [#6989](https://github.com/rubygems/rubygems/pull/6989)
14
+ - Fix `bundle outdated` crashing when both `ref` and `branch` specified for a git gem in Gemfile [#6959](https://github.com/rubygems/rubygems/pull/6959)
15
+ - Fix `bundle update --redownload` [#6924](https://github.com/rubygems/rubygems/pull/6924)
16
+ - Fixed malformed bundler version in lockfile making Bundler crash [#6920](https://github.com/rubygems/rubygems/pull/6920)
17
+ - Fix standalone install crashing when using legacy gemfiles with multiple global sources [#6918](https://github.com/rubygems/rubygems/pull/6918)
18
+ - Resolve ruby version file relative to bundle root [#6892](https://github.com/rubygems/rubygems/pull/6892)
19
+
20
+ ## Performance:
21
+
22
+ - Lazily construct fetcher debug messages [#6973](https://github.com/rubygems/rubygems/pull/6973)
23
+ - Avoid allocating empty hashes in Index [#6962](https://github.com/rubygems/rubygems/pull/6962)
24
+ - Stop allocating the same settings keys repeatedly [#6963](https://github.com/rubygems/rubygems/pull/6963)
25
+ - Improve `Bundler::Index` efficiency by removing unnecessary creation and dups [#6931](https://github.com/rubygems/rubygems/pull/6931)
26
+ - (Further) Improve Bundler::Settings#[] performance and memory usage [#6923](https://github.com/rubygems/rubygems/pull/6923)
27
+ - Don't use full indexes unnecessarily on legacy Gemfiles [#6916](https://github.com/rubygems/rubygems/pull/6916)
28
+ - Improve memory usage in Bundler::Settings, and thus improve boot time [#6884](https://github.com/rubygems/rubygems/pull/6884)
29
+
1
30
  # 2.4.19 (August 17, 2023)
2
31
 
3
32
  ## Enhancements:
@@ -4,8 +4,8 @@ module Bundler
4
4
  # Represents metadata from when the Bundler gem was built.
5
5
  module BuildMetadata
6
6
  # begin ivars
7
- @built_at = "2023-08-17".freeze
8
- @git_commit_sha = "86f98098e3".freeze
7
+ @built_at = "2023-09-27".freeze
8
+ @git_commit_sha = "de20c7e7b".freeze
9
9
  @release = true
10
10
  # end ivars
11
11
 
@@ -33,7 +33,7 @@ module Bundler
33
33
  def default_gem_spec(gem_name)
34
34
  return unless Gem::Specification.respond_to?(:find_all_by_name)
35
35
  gem_spec = Gem::Specification.find_all_by_name(gem_name).last
36
- return gem_spec if gem_spec&.default_gem?
36
+ gem_spec if gem_spec&.default_gem?
37
37
  end
38
38
 
39
39
  def spec_not_found(gem_name)
@@ -63,6 +63,7 @@ module Bundler
63
63
  opts = options.dup
64
64
  opts["update"] = true
65
65
  opts["local"] = options[:local]
66
+ opts["force"] = options[:redownload]
66
67
 
67
68
  Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
68
69
 
@@ -38,9 +38,9 @@ module Bundler
38
38
 
39
39
  private
40
40
 
41
- def log_specs(debug_msg)
41
+ def log_specs(&block)
42
42
  if Bundler.ui.debug?
43
- Bundler.ui.debug debug_msg
43
+ Bundler.ui.debug yield
44
44
  else
45
45
  Bundler.ui.info ".", false
46
46
  end
@@ -35,7 +35,7 @@ module Bundler
35
35
  remaining_gems = gem_names.dup
36
36
 
37
37
  until remaining_gems.empty?
38
- log_specs "Looking up gems #{remaining_gems.inspect}"
38
+ log_specs { "Looking up gems #{remaining_gems.inspect}" }
39
39
 
40
40
  deps = begin
41
41
  parallel_compact_index_client.dependencies(remaining_gems)
@@ -60,10 +60,6 @@ module Bundler
60
60
  Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API")
61
61
  return nil
62
62
  end
63
- if fetch_uri.scheme == "file"
64
- Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
65
- return false
66
- end
67
63
  # Read info file checksums out of /versions, so we can know if gems are up to date
68
64
  compact_index_client.update_and_parse_checksums!
69
65
  rescue CompactIndexClient::Updater::MisMatchedChecksumError => e
@@ -24,7 +24,7 @@ module Bundler
24
24
  def specs(gem_names, full_dependency_list = [], last_spec_list = [])
25
25
  query_list = gem_names.uniq - full_dependency_list
26
26
 
27
- log_specs "Query List: #{query_list.inspect}"
27
+ log_specs { "Query List: #{query_list.inspect}" }
28
28
 
29
29
  return last_spec_list if query_list.empty?
30
30
 
@@ -9,6 +9,7 @@ require "rubygems/request"
9
9
  module Bundler
10
10
  # Handles all the fetching with the rubygems server
11
11
  class Fetcher
12
+ autoload :Base, File.expand_path("fetcher/base", __dir__)
12
13
  autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__)
13
14
  autoload :Downloader, File.expand_path("fetcher/downloader", __dir__)
14
15
  autoload :Dependency, File.expand_path("fetcher/dependency", __dir__)
@@ -134,18 +135,7 @@ module Bundler
134
135
  def specs(gem_names, source)
135
136
  index = Bundler::Index.new
136
137
 
137
- if Bundler::Fetcher.disable_endpoint
138
- @use_api = false
139
- specs = fetchers.last.specs(gem_names)
140
- else
141
- specs = []
142
- @fetchers = fetchers.drop_while do |f|
143
- !f.available? || (f.api_fetcher? && !gem_names) || !specs = f.specs(gem_names)
144
- end
145
- @use_api = false if fetchers.none?(&:api_fetcher?)
146
- end
147
-
148
- specs.each do |name, version, platform, dependencies, metadata|
138
+ fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata|
149
139
  spec = if dependencies
150
140
  EndpointSpecification.new(name, version, platform, self, dependencies, metadata)
151
141
  else
@@ -158,22 +148,10 @@ module Bundler
158
148
 
159
149
  index
160
150
  rescue CertificateFailureError
161
- Bundler.ui.info "" if gem_names && use_api # newline after dots
151
+ Bundler.ui.info "" if gem_names && api_fetcher? # newline after dots
162
152
  raise
163
153
  end
164
154
 
165
- def use_api
166
- return @use_api if defined?(@use_api)
167
-
168
- fetchers.shift until fetchers.first.available?
169
-
170
- @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
171
- false
172
- else
173
- fetchers.first.api_fetcher?
174
- end
175
- end
176
-
177
155
  def user_agent
178
156
  @user_agent ||= begin
179
157
  ruby = Bundler::RubyVersion.system
@@ -209,10 +187,6 @@ module Bundler
209
187
  end
210
188
  end
211
189
 
212
- def fetchers
213
- @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) }
214
- end
215
-
216
190
  def http_proxy
217
191
  return unless uri = connection.proxy_uri
218
192
  uri.to_s
@@ -222,9 +196,36 @@ module Bundler
222
196
  "#<#{self.class}:0x#{object_id} uri=#{uri}>"
223
197
  end
224
198
 
199
+ def api_fetcher?
200
+ fetchers.first.api_fetcher?
201
+ end
202
+
225
203
  private
226
204
 
227
- FETCHERS = [CompactIndex, Dependency, Index].freeze
205
+ def available_fetchers
206
+ if Bundler::Fetcher.disable_endpoint
207
+ [Index]
208
+ elsif remote_uri.scheme == "file"
209
+ Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
210
+ [Index]
211
+ else
212
+ [CompactIndex, Dependency, Index]
213
+ end
214
+ end
215
+
216
+ def fetchers
217
+ @fetchers ||= available_fetchers.map {|f| f.new(downloader, @remote, uri) }.drop_while {|f| !f.available? }
218
+ end
219
+
220
+ def fetch_specs(gem_names)
221
+ fetchers.reject!(&:api_fetcher?) unless gem_names
222
+ fetchers.reject! do |f|
223
+ specs = f.specs(gem_names)
224
+ return specs if specs
225
+ true
226
+ end
227
+ []
228
+ end
228
229
 
229
230
  def cis
230
231
  env_cis = {
@@ -10,8 +10,8 @@ module Bundler
10
10
  i
11
11
  end
12
12
 
13
- attr_reader :specs, :all_specs, :sources
14
- protected :specs, :all_specs
13
+ attr_reader :specs, :duplicates, :sources
14
+ protected :specs, :duplicates
15
15
 
16
16
  RUBY = "ruby"
17
17
  NULL = "\0"
@@ -19,21 +19,21 @@ module Bundler
19
19
  def initialize
20
20
  @sources = []
21
21
  @cache = {}
22
- @specs = Hash.new {|h, k| h[k] = {} }
23
- @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
22
+ @specs = {}
23
+ @duplicates = {}
24
24
  end
25
25
 
26
26
  def initialize_copy(o)
27
27
  @sources = o.sources.dup
28
28
  @cache = {}
29
- @specs = Hash.new {|h, k| h[k] = {} }
30
- @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
29
+ @specs = {}
30
+ @duplicates = {}
31
31
 
32
32
  o.specs.each do |name, hash|
33
33
  @specs[name] = hash.dup
34
34
  end
35
- o.all_specs.each do |name, array|
36
- @all_specs[name] = array.dup
35
+ o.duplicates.each do |name, array|
36
+ @duplicates[name] = array.dup
37
37
  end
38
38
  end
39
39
 
@@ -46,12 +46,11 @@ module Bundler
46
46
  true
47
47
  end
48
48
 
49
- def search_all(name)
50
- all_matches = local_search(name) + @all_specs[name]
51
- @sources.each do |source|
52
- all_matches.concat(source.search_all(name))
53
- end
54
- all_matches
49
+ def search_all(name, &blk)
50
+ return enum_for(:search_all, name) unless blk
51
+ specs_by_name(name).each(&blk)
52
+ @duplicates[name]&.each(&blk)
53
+ @sources.each {|source| source.search_all(name, &blk) }
55
54
  end
56
55
 
57
56
  # Search this index's specs, and any source indexes that this index knows
@@ -61,11 +60,14 @@ module Bundler
61
60
  return results unless @sources.any?
62
61
 
63
62
  @sources.each do |source|
64
- results.concat(source.search(query))
63
+ results = safe_concat(results, source.search(query))
65
64
  end
66
- results.uniq(&:full_name)
65
+ results.uniq!(&:full_name) unless results.empty? # avoid modifying frozen EMPTY_SEARCH
66
+ results
67
67
  end
68
68
 
69
+ alias_method :[], :search
70
+
69
71
  def local_search(query)
70
72
  case query
71
73
  when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
@@ -76,12 +78,10 @@ module Bundler
76
78
  end
77
79
  end
78
80
 
79
- alias_method :[], :search
80
-
81
- def <<(spec)
82
- @specs[spec.name][spec.full_name] = spec
83
- spec
81
+ def add(spec)
82
+ (@specs[spec.name] ||= {}).store(spec.full_name, spec)
84
83
  end
84
+ alias_method :<<, :add
85
85
 
86
86
  def each(&blk)
87
87
  return enum_for(:each) unless blk
@@ -115,15 +115,25 @@ module Bundler
115
115
  names.uniq
116
116
  end
117
117
 
118
- def use(other, override_dupes = false)
118
+ # Combines indexes proritizing existing specs, like `Hash#reverse_merge!`
119
+ # Duplicate specs found in `other` are stored in `@duplicates`.
120
+ def use(other)
119
121
  return unless other
120
- other.each do |s|
121
- if (dupes = search_by_spec(s)) && !dupes.empty?
122
- # safe to << since it's a new array when it has contents
123
- @all_specs[s.name] = dupes << s
124
- next unless override_dupes
122
+ other.each do |spec|
123
+ exist?(spec) ? add_duplicate(spec) : add(spec)
124
+ end
125
+ self
126
+ end
127
+
128
+ # Combines indexes proritizing specs from `other`, like `Hash#merge!`
129
+ # Duplicate specs found in `self` are saved in `@duplicates`.
130
+ def merge!(other)
131
+ return unless other
132
+ other.each do |spec|
133
+ if existing = find_by_spec(spec)
134
+ add_duplicate(existing)
125
135
  end
126
- self << s
136
+ add spec
127
137
  end
128
138
  self
129
139
  end
@@ -157,19 +167,40 @@ module Bundler
157
167
 
158
168
  private
159
169
 
170
+ def safe_concat(a, b)
171
+ return a if b.empty?
172
+ return b if a.empty?
173
+ a.concat(b)
174
+ end
175
+
176
+ def add_duplicate(spec)
177
+ (@duplicates[spec.name] ||= []) << spec
178
+ end
179
+
160
180
  def specs_by_name_and_version(name, version)
161
- specs_by_name(name).select {|spec| spec.version == version }
181
+ results = @specs[name]&.values
182
+ return EMPTY_SEARCH unless results
183
+ results.select! {|spec| spec.version == version }
184
+ results
162
185
  end
163
186
 
164
187
  def specs_by_name(name)
165
- @specs[name].values
188
+ @specs[name]&.values || EMPTY_SEARCH
166
189
  end
167
190
 
168
191
  EMPTY_SEARCH = [].freeze
169
192
 
170
193
  def search_by_spec(spec)
171
- spec = @specs[spec.name][spec.full_name]
194
+ spec = find_by_spec(spec)
172
195
  spec ? [spec] : EMPTY_SEARCH
173
196
  end
197
+
198
+ def find_by_spec(spec)
199
+ @specs[spec.name]&.fetch(spec.full_name, nil)
200
+ end
201
+
202
+ def exist?(spec)
203
+ @specs[spec.name]&.key?(spec.full_name)
204
+ end
174
205
  end
175
206
  end
@@ -55,13 +55,20 @@ module Bundler
55
55
  if spec.source.instance_of?(Source::Path) && spec.source.path.absolute?
56
56
  full_path
57
57
  else
58
- Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s
58
+ relative_path_from(Bundler.root.join(bundler_path), :to => full_path) || full_path
59
59
  end
60
60
  rescue TypeError
61
61
  error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
62
62
  raise Gem::InvalidSpecificationException.new(error_message)
63
63
  end
64
64
 
65
+ def relative_path_from(source, to:)
66
+ Pathname.new(to).relative_path_from(source).to_s
67
+ rescue ArgumentError
68
+ # on Windows, if source and destination are on different drivers, there's no relative path from one to the other
69
+ nil
70
+ end
71
+
65
72
  def define_path_helpers
66
73
  <<~'END'
67
74
  unless defined?(Gem)
@@ -110,21 +110,9 @@ module Bundler
110
110
  def parse_source(line)
111
111
  case line
112
112
  when SPECS
113
- case @type
114
- when PATH
115
- @current_source = TYPES[@type].from_lock(@opts)
116
- @sources << @current_source
117
- when GIT
118
- @current_source = TYPES[@type].from_lock(@opts)
119
- @sources << @current_source
120
- when GEM
121
- @opts["remotes"] = Array(@opts.delete("remote")).reverse
122
- @current_source = TYPES[@type].from_lock(@opts)
123
- @sources << @current_source
124
- when PLUGIN
125
- @current_source = Plugin.source_from_lock(@opts)
126
- @sources << @current_source
127
- end
113
+ return unless TYPES.key?(@type)
114
+ @current_source = TYPES[@type].from_lock(@opts)
115
+ @sources << @current_source
128
116
  when OPTIONS
129
117
  value = $2
130
118
  value = true if value == "true"
@@ -98,6 +98,17 @@ ruby file: "\.ruby\-version"
98
98
  .
99
99
  .IP "" 0
100
100
  .
101
+ .P
102
+ The version file should conform to any of the following formats:
103
+ .
104
+ .IP "\(bu" 4
105
+ \fB3\.1\.2\fR (\.ruby\-version)
106
+ .
107
+ .IP "\(bu" 4
108
+ \fBruby 3\.1\.2\fR (\.tool\-versions, read: https://asdf\-vm\.com/manage/configuration\.html#tool\-versions)
109
+ .
110
+ .IP "" 0
111
+ .
101
112
  .SS "ENGINE"
102
113
  Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\.
103
114
  .
@@ -74,6 +74,11 @@ you can use the `file` option instead.
74
74
 
75
75
  ruby file: ".ruby-version"
76
76
 
77
+ The version file should conform to any of the following formats:
78
+
79
+ - `3.1.2` (.ruby-version)
80
+ - `ruby 3.1.2` (.tool-versions, read: https://asdf-vm.com/manage/configuration.html#tool-versions)
81
+
77
82
  ### ENGINE
78
83
 
79
84
  Each application _may_ specify a Ruby engine. If an engine is specified, an
@@ -197,7 +197,7 @@ module Bundler
197
197
  # @param [Hash] The options that are present in the lock file
198
198
  # @return [API::Source] the instance of the class that handles the source
199
199
  # type passed in locked_opts
200
- def source_from_lock(locked_opts)
200
+ def from_lock(locked_opts)
201
201
  src = source(locked_opts["type"])
202
202
 
203
203
  src.new(locked_opts.merge("uri" => locked_opts["remote"]))
@@ -37,9 +37,17 @@ module Bundler
37
37
  root_version = Resolver::Candidate.new(0)
38
38
 
39
39
  @all_specs = Hash.new do |specs, name|
40
- specs[name] = source_for(name).specs.search(name).reject do |s|
41
- s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } # ignore versions that depend on themselves incorrectly
42
- end.sort_by {|s| [s.version, s.platform.to_s] }
40
+ source = source_for(name)
41
+ matches = source.specs.search(name)
42
+
43
+ # Don't bother to check for circular deps when no dependency API are
44
+ # available, since it's too slow to be usable. That edge case won't work
45
+ # but resolution other than that should work fine and reasonably fast.
46
+ if source.respond_to?(:dependency_api_available?) && source.dependency_api_available?
47
+ matches = filter_invalid_self_dependencies(matches, name)
48
+ end
49
+
50
+ specs[name] = matches.sort_by {|s| [s.version, s.platform.to_s] }
43
51
  end
44
52
 
45
53
  @sorted_versions = Hash.new do |candidates, package|
@@ -318,6 +326,13 @@ module Bundler
318
326
  specs.reject {|s| s.version.prerelease? }
319
327
  end
320
328
 
329
+ # Ignore versions that depend on themselves incorrectly
330
+ def filter_invalid_self_dependencies(specs, name)
331
+ specs.reject do |s|
332
+ s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) }
333
+ end
334
+ end
335
+
321
336
  def requirement_satisfied_by?(requirement, spec)
322
337
  requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
323
338
  end
@@ -56,7 +56,7 @@ module Bundler
56
56
  def keep_trying?
57
57
  return true if current_run.zero?
58
58
  return false if last_attempt?
59
- return true if @failed
59
+ true if @failed
60
60
  end
61
61
 
62
62
  def last_attempt?
@@ -10,8 +10,8 @@ module Bundler
10
10
  raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
11
11
 
12
12
  if options[:file]
13
- raise GemfileError, "Cannot specify version when using the file option" if ruby_version.any?
14
- ruby_version << Bundler.read_file(options[:file]).strip
13
+ raise GemfileError, "Do not pass version argument when using :file option" unless ruby_version.empty?
14
+ ruby_version << normalize_ruby_file(options[:file])
15
15
  end
16
16
 
17
17
  if options[:engine] == "ruby" && options[:engine_version] &&
@@ -20,5 +20,26 @@ module Bundler
20
20
  end
21
21
  @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
22
22
  end
23
+
24
+ # Support the various file formats found in .ruby-version files.
25
+ #
26
+ # 3.2.2
27
+ # ruby-3.2.2
28
+ #
29
+ # Also supports .tool-versions files for asdf. Lines not starting with "ruby" are ignored.
30
+ #
31
+ # ruby 2.5.1 # comment is ignored
32
+ # ruby 2.5.1# close comment and extra spaces doesn't confuse
33
+ #
34
+ # Intentionally does not support `3.2.1@gemset` since rvm recommends using .ruby-gemset instead
35
+ def normalize_ruby_file(filename)
36
+ file_content = Bundler.read_file(Bundler.root.join(filename))
37
+ # match "ruby-3.2.2" or "ruby 3.2.2" capturing version string up to the first space or comment
38
+ if /^ruby(-|\s+)([^\s#]+)/.match(file_content)
39
+ $2
40
+ else
41
+ file_content.strip
42
+ end
43
+ end
23
44
  end
24
45
  end
@@ -163,6 +163,8 @@ module Bundler
163
163
 
164
164
  parsed_version = Bundler::LockfileParser.bundled_with
165
165
  @lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil
166
+ rescue ArgumentError
167
+ @lockfile_version = nil
166
168
  end
167
169
  end
168
170
  end