rubygems-update 3.4.19 → 3.4.20

Sign up to get free protection for your applications and to get access to all the features.
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