rubygems-update 3.5.11 → 3.5.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Manifest.txt +1 -0
  4. data/bundler/CHANGELOG.md +28 -0
  5. data/bundler/lib/bundler/build_metadata.rb +2 -2
  6. data/bundler/lib/bundler/cli.rb +5 -8
  7. data/bundler/lib/bundler/compact_index_client/cache.rb +47 -81
  8. data/bundler/lib/bundler/compact_index_client/parser.rb +84 -0
  9. data/bundler/lib/bundler/compact_index_client.rb +51 -80
  10. data/bundler/lib/bundler/definition.rb +13 -3
  11. data/bundler/lib/bundler/endpoint_specification.rb +11 -0
  12. data/bundler/lib/bundler/fetcher/compact_index.rb +15 -24
  13. data/bundler/lib/bundler/installer/gem_installer.rb +0 -1
  14. data/bundler/lib/bundler/man/bundle-config.1 +1 -1
  15. data/bundler/lib/bundler/man/bundle-config.1.ronn +1 -1
  16. data/bundler/lib/bundler/rubygems_gem_installer.rb +4 -1
  17. data/bundler/lib/bundler/rubygems_integration.rb +14 -0
  18. data/bundler/lib/bundler/self_manager.rb +5 -0
  19. data/bundler/lib/bundler/settings.rb +12 -8
  20. data/bundler/lib/bundler/setup.rb +3 -0
  21. data/bundler/lib/bundler/shared_helpers.rb +2 -2
  22. data/bundler/lib/bundler/source/git.rb +14 -0
  23. data/bundler/lib/bundler/source/path.rb +0 -13
  24. data/bundler/lib/bundler/source/rubygems.rb +29 -13
  25. data/bundler/lib/bundler/version.rb +1 -1
  26. data/bundler/lib/bundler/yaml_serializer.rb +1 -8
  27. data/bundler/lib/bundler.rb +6 -1
  28. data/lib/rubygems/basic_specification.rb +27 -0
  29. data/lib/rubygems/commands/pristine_command.rb +3 -3
  30. data/lib/rubygems/specification.rb +11 -2
  31. data/lib/rubygems/specification_record.rb +0 -1
  32. data/lib/rubygems/stub_specification.rb +21 -0
  33. data/lib/rubygems/uninstaller.rb +13 -12
  34. data/lib/rubygems/yaml_serializer.rb +1 -8
  35. data/lib/rubygems.rb +1 -1
  36. data/rubygems-update.gemspec +1 -1
  37. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd4f648b70b6865239d7b78c7773946b5be7fa737c540ffcc33e1266e1ef3f88
4
- data.tar.gz: 4c94ce1d451e13399cf9c29154707d75b5bde5dfe2a663864dff4587bf724017
3
+ metadata.gz: ba43972154c4bfe3b9e6700736425ca2934a30e7225778447376219a7cc40a57
4
+ data.tar.gz: be68d1a1754f86847cceec72d9f27867f38c53c9b5c80c6f96123fed943a3e30
5
5
  SHA512:
6
- metadata.gz: 4ea473f16af7b832d500c6b5692039281f77f5f581fe1f114d7f183443bfb4149a415fc5f021d8255662d5712a369d0a52d943367962ea14b301b7f12ef859f5
7
- data.tar.gz: 492b437441e43a45505cb6223c7e317341eee786436cc44bd619dd00f765c07867bcd8b11824eef968360e6798aa9c83013e543a69466c48b81cb51f0a831979
6
+ metadata.gz: d54f3382258bcb1794e73d9c7fb4ce854435396bad2fe8ece3a5030bb3f0615c8d128590eceeb1cd0bd45c46958e2a924f905ec76878b014ec65223d685554c7
7
+ data.tar.gz: 5f26b6a23c3dc01f8c30988a9abc9d8c8c77a29d1cd48c28e22303468a39d7ddd94fd261ab3b70c18a4193f91dcea26c152747df51853368048c5d824ab4e9bc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ # 3.5.13 / 2024-06-14
2
+
3
+ ## Enhancements:
4
+
5
+ * Installs bundler 2.5.13 as a default gem.
6
+
7
+ ## Bug fixes:
8
+
9
+ * Never remove executables that may belong to a default gem. Pull request
10
+ [#7747](https://github.com/rubygems/rubygems/pull/7747) by
11
+ deivid-rodriguez
12
+
13
+ # 3.5.12 / 2024-06-13
14
+
15
+ ## Enhancements:
16
+
17
+ * Installs bundler 2.5.12 as a default gem.
18
+
19
+ ## Bug fixes:
20
+
21
+ * Fix `gem uninstall` unresolved specifications warning. Pull request
22
+ [#7667](https://github.com/rubygems/rubygems/pull/7667) by
23
+ deivid-rodriguez
24
+ * Fix `gem pristine` sometimes failing to pristine user installed gems.
25
+ Pull request [#7664](https://github.com/rubygems/rubygems/pull/7664) by
26
+ deivid-rodriguez
27
+
1
28
  # 3.5.11 / 2024-05-28
2
29
 
3
30
  ## Enhancements:
data/Manifest.txt CHANGED
@@ -54,6 +54,7 @@ bundler/lib/bundler/compact_index_client.rb
54
54
  bundler/lib/bundler/compact_index_client/cache.rb
55
55
  bundler/lib/bundler/compact_index_client/cache_file.rb
56
56
  bundler/lib/bundler/compact_index_client/gem_parser.rb
57
+ bundler/lib/bundler/compact_index_client/parser.rb
57
58
  bundler/lib/bundler/compact_index_client/updater.rb
58
59
  bundler/lib/bundler/constants.rb
59
60
  bundler/lib/bundler/current_ruby.rb
data/bundler/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ # 2.5.13 (June 14, 2024)
2
+
3
+ ## Bug fixes:
4
+
5
+ - Fix funding metadata not being printed in some situations [#7746](https://github.com/rubygems/rubygems/pull/7746)
6
+ - Make sure to not re-resolve when a not fully specific local platform is locked [#7751](https://github.com/rubygems/rubygems/pull/7751)
7
+ - Don't print bug report template when bin dir is not writable [#7748](https://github.com/rubygems/rubygems/pull/7748)
8
+
9
+ # 2.5.12 (June 13, 2024)
10
+
11
+ ## Enhancements:
12
+
13
+ - Keep credentials in lockfile if they are already there [#7720](https://github.com/rubygems/rubygems/pull/7720)
14
+ - Auto switch to locked bundler version even when using binstubs [#7719](https://github.com/rubygems/rubygems/pull/7719)
15
+ - Don't validate local gemspecs twice unnecessarily [#7725](https://github.com/rubygems/rubygems/pull/7725)
16
+ - Improve default gem handling by treating default gems as any other gem [#7673](https://github.com/rubygems/rubygems/pull/7673)
17
+
18
+ ## Bug fixes:
19
+
20
+ - Fix slow and incorrect resolution when adding `sorbet` to a Gemfile and the lockfile only includes "RUBY" in the platforms section [#7731](https://github.com/rubygems/rubygems/pull/7731)
21
+ - Fix duplicated config keys generated when `fallback_timeout` uri option is used [#7704](https://github.com/rubygems/rubygems/pull/7704)
22
+ - Fix `bundle exec` no longer working in truffleruby after explicit `require` of `pathname` was removed [#7703](https://github.com/rubygems/rubygems/pull/7703)
23
+ - Don't let `bundle config` report a path without a Gemfile as "local app" [#7687](https://github.com/rubygems/rubygems/pull/7687)
24
+
25
+ ## Documentation:
26
+
27
+ - Clarify BUNDLE_USER_CONFIG is a file [#7668](https://github.com/rubygems/rubygems/pull/7668)
28
+
1
29
  # 2.5.11 (May 28, 2024)
2
30
 
3
31
  ## Deprecations:
@@ -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 = "2024-05-28".freeze
8
- @git_commit_sha = "4afb2d450a".freeze
7
+ @built_at = "2024-06-14".freeze
8
+ @git_commit_sha = "5525a3d9b0".freeze
9
9
  @release = true
10
10
  # end ivars
11
11
 
@@ -65,7 +65,7 @@ module Bundler
65
65
  Bundler.reset_settings_and_root!
66
66
  end
67
67
 
68
- Bundler.self_manager.restart_with_locked_bundler_if_needed
68
+ Bundler.auto_switch
69
69
 
70
70
  Bundler.settings.set_command_option_if_given :retry, options[:retry]
71
71
 
@@ -767,13 +767,10 @@ module Bundler
767
767
 
768
768
  return unless SharedHelpers.md5_available?
769
769
 
770
- latest = Fetcher::CompactIndex.
771
- new(nil, Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org")), nil, nil).
772
- send(:compact_index_client).
773
- instance_variable_get(:@cache).
774
- dependencies("bundler").
775
- map {|d| Gem::Version.new(d.first) }.
776
- max
770
+ require_relative "vendored_uri"
771
+ remote = Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org"))
772
+ cache_path = Bundler.user_cache.join("compact_index", remote.cache_slug)
773
+ latest = Bundler::CompactIndexClient.new(cache_path).latest_version("bundler")
777
774
  return unless latest
778
775
 
779
776
  current = Gem::Version.new(VERSION)
@@ -7,123 +7,89 @@ module Bundler
7
7
  class Cache
8
8
  attr_reader :directory
9
9
 
10
- def initialize(directory)
10
+ def initialize(directory, fetcher = nil)
11
11
  @directory = Pathname.new(directory).expand_path
12
- info_roots.each {|dir| mkdir(dir) }
13
- mkdir(info_etag_root)
12
+ @updater = Updater.new(fetcher) if fetcher
13
+ @mutex = Thread::Mutex.new
14
+ @endpoints = Set.new
15
+
16
+ @info_root = mkdir("info")
17
+ @special_characters_info_root = mkdir("info-special-characters")
18
+ @info_etag_root = mkdir("info-etags")
14
19
  end
15
20
 
16
21
  def names
17
- lines(names_path)
22
+ fetch("names", names_path, names_etag_path)
18
23
  end
19
24
 
20
- def names_path
21
- directory.join("names")
25
+ def versions
26
+ fetch("versions", versions_path, versions_etag_path)
22
27
  end
23
28
 
24
- def names_etag_path
25
- directory.join("names.etag")
26
- end
29
+ def info(name, remote_checksum = nil)
30
+ path = info_path(name)
27
31
 
28
- def versions
29
- versions_by_name = Hash.new {|hash, key| hash[key] = [] }
30
- info_checksums_by_name = {}
31
-
32
- lines(versions_path).each do |line|
33
- name, versions_string, info_checksum = line.split(" ", 3)
34
- info_checksums_by_name[name] = info_checksum || ""
35
- versions_string.split(",") do |version|
36
- delete = version.delete_prefix!("-")
37
- version = version.split("-", 2).unshift(name)
38
- if delete
39
- versions_by_name[name].delete(version)
40
- else
41
- versions_by_name[name] << version
42
- end
43
- end
32
+ if remote_checksum && remote_checksum != SharedHelpers.checksum_for_file(path, :MD5)
33
+ fetch("info/#{name}", path, info_etag_path(name))
34
+ else
35
+ Bundler::CompactIndexClient.debug { "update skipped info/#{name} (#{remote_checksum ? "versions index checksum is nil" : "versions index checksum matches local"})" }
36
+ read(path)
44
37
  end
45
-
46
- [versions_by_name, info_checksums_by_name]
47
- end
48
-
49
- def versions_path
50
- directory.join("versions")
51
38
  end
52
39
 
53
- def versions_etag_path
54
- directory.join("versions.etag")
40
+ def reset!
41
+ @mutex.synchronize { @endpoints.clear }
55
42
  end
56
43
 
57
- def checksums
58
- lines(versions_path).each_with_object({}) do |line, checksums|
59
- parse_version_checksum(line, checksums)
60
- end
61
- end
44
+ private
62
45
 
63
- def dependencies(name)
64
- lines(info_path(name)).map do |line|
65
- parse_gem(line)
66
- end
67
- end
46
+ def names_path = directory.join("names")
47
+ def names_etag_path = directory.join("names.etag")
48
+ def versions_path = directory.join("versions")
49
+ def versions_etag_path = directory.join("versions.etag")
68
50
 
69
51
  def info_path(name)
70
52
  name = name.to_s
53
+ # TODO: converge this into the info_root by hashing all filenames like info_etag_path
71
54
  if /[^a-z0-9_-]/.match?(name)
72
55
  name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}"
73
- info_roots.last.join(name)
56
+ @special_characters_info_root.join(name)
74
57
  else
75
- info_roots.first.join(name)
58
+ @info_root.join(name)
76
59
  end
77
60
  end
78
61
 
79
62
  def info_etag_path(name)
80
63
  name = name.to_s
81
- info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}")
64
+ @info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}")
82
65
  end
83
66
 
84
- private
85
-
86
- def mkdir(dir)
87
- SharedHelpers.filesystem_access(dir) do
88
- FileUtils.mkdir_p(dir)
67
+ def mkdir(name)
68
+ directory.join(name).tap do |dir|
69
+ SharedHelpers.filesystem_access(dir) do
70
+ FileUtils.mkdir_p(dir)
71
+ end
89
72
  end
90
73
  end
91
74
 
92
- def lines(path)
93
- return [] unless path.file?
94
- lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n")
95
- header = lines.index("---")
96
- header ? lines[header + 1..-1] : lines
97
- end
98
-
99
- def parse_gem(line)
100
- @dependency_parser ||= GemParser.new
101
- @dependency_parser.parse(line)
102
- end
75
+ def fetch(remote_path, path, etag_path)
76
+ if already_fetched?(remote_path)
77
+ Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
78
+ else
79
+ Bundler::CompactIndexClient.debug { "fetching #{remote_path}" }
80
+ @updater&.update(remote_path, path, etag_path)
81
+ end
103
82
 
104
- # This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects.
105
- # This method gets called at least once for every gem when parsing versions.
106
- def parse_version_checksum(line, checksums)
107
- line.freeze # allows slicing into the string to not allocate a copy of the line
108
- name_end = line.index(" ")
109
- checksum_start = line.index(" ", name_end + 1) + 1
110
- checksum_end = line.size - checksum_start
111
- # freeze name since it is used as a hash key
112
- # pre-freezing means a frozen copy isn't created
113
- name = line[0, name_end].freeze
114
- checksum = line[checksum_start, checksum_end]
115
- checksums[name] = checksum
83
+ read(path)
116
84
  end
117
85
 
118
- def info_roots
119
- [
120
- directory.join("info"),
121
- directory.join("info-special-characters"),
122
- ]
86
+ def already_fetched?(remote_path)
87
+ @mutex.synchronize { !@endpoints.add?(remote_path) }
123
88
  end
124
89
 
125
- def info_etag_root
126
- directory.join("info-etags")
90
+ def read(path)
91
+ return unless path.file?
92
+ SharedHelpers.filesystem_access(path, :read, &:read)
127
93
  end
128
94
  end
129
95
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class CompactIndexClient
5
+ class Parser
6
+ # `compact_index` - an object responding to #names, #versions, #info(name, checksum),
7
+ # returning the file contents as a string
8
+ def initialize(compact_index)
9
+ @compact_index = compact_index
10
+ @info_checksums = nil
11
+ @versions_by_name = nil
12
+ @available = nil
13
+ @gem_parser = nil
14
+ end
15
+
16
+ def names
17
+ lines(@compact_index.names)
18
+ end
19
+
20
+ def versions
21
+ @versions_by_name ||= Hash.new {|hash, key| hash[key] = [] }
22
+ @info_checksums = {}
23
+
24
+ lines(@compact_index.versions).each do |line|
25
+ name, versions_string, checksum = line.split(" ", 3)
26
+ @info_checksums[name] = checksum || ""
27
+ versions_string.split(",") do |version|
28
+ delete = version.delete_prefix!("-")
29
+ version = version.split("-", 2).unshift(name)
30
+ if delete
31
+ @versions_by_name[name].delete(version)
32
+ else
33
+ @versions_by_name[name] << version
34
+ end
35
+ end
36
+ end
37
+
38
+ @versions_by_name
39
+ end
40
+
41
+ def info(name)
42
+ data = @compact_index.info(name, info_checksums[name])
43
+ lines(data).map {|line| gem_parser.parse(line).unshift(name) }
44
+ end
45
+
46
+ def available?
47
+ return @available unless @available.nil?
48
+ @available = !info_checksums.empty?
49
+ end
50
+
51
+ private
52
+
53
+ def info_checksums
54
+ @info_checksums ||= lines(@compact_index.versions).each_with_object({}) do |line, checksums|
55
+ parse_version_checksum(line, checksums)
56
+ end
57
+ end
58
+
59
+ def lines(data)
60
+ return [] if data.nil? || data.empty?
61
+ lines = data.split("\n")
62
+ header = lines.index("---")
63
+ header ? lines[header + 1..-1] : lines
64
+ end
65
+
66
+ def gem_parser
67
+ @gem_parser ||= GemParser.new
68
+ end
69
+
70
+ # This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects.
71
+ # This method gets called at least once for every gem when parsing versions.
72
+ def parse_version_checksum(line, checksums)
73
+ return unless (name_end = line.index(" ")) # Artifactory bug causes blank lines in artifactor index files
74
+ return unless (checksum_start = line.index(" ", name_end + 1) + 1)
75
+ checksum_end = line.size - checksum_start
76
+
77
+ line.freeze # allows slicing into the string to not allocate a copy of the line
78
+ name = line[0, name_end]
79
+ checksum = line[checksum_start, checksum_end]
80
+ checksums[name.freeze] = checksum # freeze name since it is used as a hash key
81
+ end
82
+ end
83
+ end
84
+ end
@@ -4,6 +4,29 @@ require "pathname"
4
4
  require "set"
5
5
 
6
6
  module Bundler
7
+ # The CompactIndexClient is responsible for fetching and parsing the compact index.
8
+ #
9
+ # The compact index is a set of caching optimized files that are used to fetch gem information.
10
+ # The files are:
11
+ # - names: a list of all gem names
12
+ # - versions: a list of all gem versions
13
+ # - info/[gem]: a list of all versions of a gem
14
+ #
15
+ # The client is instantiated with:
16
+ # - `directory`: the root directory where the cache files are stored.
17
+ # - `fetcher`: (optional) an object that responds to #call(uri_path, headers) and returns an http response.
18
+ # If the `fetcher` is not provided, the client will only read cached files from disk.
19
+ #
20
+ # The client is organized into:
21
+ # - `Updater`: updates the cached files on disk using the fetcher.
22
+ # - `Cache`: calls the updater, caches files, read and return them from disk
23
+ # - `Parser`: parses the compact index file data
24
+ # - `CacheFile`: a concurrency safe file reader/writer that verifies checksums
25
+ #
26
+ # The client is intended to optimize memory usage and performance.
27
+ # It is called 100s or 1000s of times, parsing files with hundreds of thousands of lines.
28
+ # It may be called concurrently without global interpreter lock in some Rubies.
29
+ # As a result, some methods may look more complex than necessary to save memory or time.
7
30
  class CompactIndexClient
8
31
  # NOTE: MD5 is here not because we expect a server to respond with it, but
9
32
  # because we use it to generate the etag on first request during the upgrade
@@ -12,6 +35,13 @@ module Bundler
12
35
  SUPPORTED_DIGESTS = { "sha-256" => :SHA256, "md5" => :MD5 }.freeze
13
36
  DEBUG_MUTEX = Thread::Mutex.new
14
37
 
38
+ # info returns an Array of INFO Arrays. Each INFO Array has the following indices:
39
+ INFO_NAME = 0
40
+ INFO_VERSION = 1
41
+ INFO_PLATFORM = 2
42
+ INFO_DEPS = 3
43
+ INFO_REQS = 4
44
+
15
45
  def self.debug
16
46
  return unless ENV["DEBUG_COMPACT_INDEX"]
17
47
  DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
@@ -21,106 +51,47 @@ module Bundler
21
51
 
22
52
  require_relative "compact_index_client/cache"
23
53
  require_relative "compact_index_client/cache_file"
54
+ require_relative "compact_index_client/parser"
24
55
  require_relative "compact_index_client/updater"
25
56
 
26
- attr_reader :directory
27
-
28
- def initialize(directory, fetcher)
29
- @directory = Pathname.new(directory)
30
- @updater = Updater.new(fetcher)
31
- @cache = Cache.new(@directory)
32
- @endpoints = Set.new
33
- @info_checksums_by_name = {}
34
- @parsed_checksums = false
35
- @mutex = Thread::Mutex.new
36
- end
37
-
38
- def execution_mode=(block)
39
- Bundler::CompactIndexClient.debug { "execution_mode=" }
40
- @endpoints = Set.new
41
-
42
- @execution_mode = block
43
- end
44
-
45
- # @return [Lambda] A lambda that takes an array of inputs and a block, and
46
- # maps the inputs with the block in parallel.
47
- #
48
- def execution_mode
49
- @execution_mode || sequentially
50
- end
51
-
52
- def sequential_execution_mode!
53
- self.execution_mode = sequentially
54
- end
55
-
56
- def sequentially
57
- @sequentially ||= lambda do |inputs, &blk|
58
- inputs.map(&blk)
59
- end
57
+ def initialize(directory, fetcher = nil)
58
+ @cache = Cache.new(directory, fetcher)
59
+ @parser = Parser.new(@cache)
60
60
  end
61
61
 
62
62
  def names
63
- Bundler::CompactIndexClient.debug { "/names" }
64
- update("names", @cache.names_path, @cache.names_etag_path)
65
- @cache.names
63
+ Bundler::CompactIndexClient.debug { "names" }
64
+ @parser.names
66
65
  end
67
66
 
68
67
  def versions
69
- Bundler::CompactIndexClient.debug { "/versions" }
70
- update("versions", @cache.versions_path, @cache.versions_etag_path)
71
- versions, @info_checksums_by_name = @cache.versions
72
- versions
68
+ Bundler::CompactIndexClient.debug { "versions" }
69
+ @parser.versions
73
70
  end
74
71
 
75
72
  def dependencies(names)
76
73
  Bundler::CompactIndexClient.debug { "dependencies(#{names})" }
77
- execution_mode.call(names) do |name|
78
- update_info(name)
79
- @cache.dependencies(name).map {|d| d.unshift(name) }
80
- end.flatten(1)
74
+ names.map {|name| info(name) }
81
75
  end
82
76
 
83
- def update_and_parse_checksums!
84
- Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
85
- return @info_checksums_by_name if @parsed_checksums
86
- update("versions", @cache.versions_path, @cache.versions_etag_path)
87
- @info_checksums_by_name = @cache.checksums
88
- @parsed_checksums = true
89
- end
90
-
91
- private
92
-
93
- def update(remote_path, local_path, local_etag_path)
94
- Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
95
- unless synchronize { @endpoints.add?(remote_path) }
96
- Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
97
- return
98
- end
99
- @updater.update(url(remote_path), local_path, local_etag_path)
77
+ def info(name)
78
+ Bundler::CompactIndexClient.debug { "info(#{name})" }
79
+ @parser.info(name)
100
80
  end
101
81
 
102
- def update_info(name)
103
- Bundler::CompactIndexClient.debug { "update_info(#{name})" }
104
- path = @cache.info_path(name)
105
- unless existing = @info_checksums_by_name[name]
106
- Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
107
- return
108
- end
109
- checksum = SharedHelpers.checksum_for_file(path, :MD5)
110
- if checksum == existing
111
- Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
112
- return
113
- end
114
- Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
115
- update("info/#{name}", path, @cache.info_etag_path(name))
82
+ def latest_version(name)
83
+ Bundler::CompactIndexClient.debug { "latest_version(#{name})" }
84
+ @parser.info(name).map {|d| Gem::Version.new(d[INFO_VERSION]) }.max
116
85
  end
117
86
 
118
- def url(path)
119
- path
87
+ def available?
88
+ Bundler::CompactIndexClient.debug { "available?" }
89
+ @parser.available?
120
90
  end
121
91
 
122
- def synchronize
123
- @mutex.synchronize { yield }
92
+ def reset!
93
+ Bundler::CompactIndexClient.debug { "reset!" }
94
+ @cache.reset!
124
95
  end
125
96
  end
126
97
  end
@@ -621,9 +621,16 @@ module Bundler
621
621
  end
622
622
 
623
623
  def start_resolution
624
+ @platforms |= [local_platform]
625
+
624
626
  result = SpecSet.new(resolver.start)
625
627
 
626
628
  @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
629
+
630
+ if most_specific_ruby_locked_platform_is_not_local_platform?
631
+ @platforms.delete(result.incomplete_for_platform?(dependencies, @current_ruby_locked_platform) ? @current_ruby_locked_platform : local_platform)
632
+ end
633
+
627
634
  @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
628
635
 
629
636
  result.complete_platforms!(platforms)
@@ -650,7 +657,6 @@ module Bundler
650
657
 
651
658
  def current_ruby_platform_locked?
652
659
  return false unless generic_local_platform_is_ruby?
653
- return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
654
660
 
655
661
  current_platform_locked?
656
662
  end
@@ -662,11 +668,16 @@ module Bundler
662
668
  end
663
669
 
664
670
  def add_current_platform
665
- return if current_ruby_platform_locked?
671
+ @current_ruby_locked_platform = most_specific_locked_platform if current_ruby_platform_locked?
672
+ return if most_specific_ruby_locked_platform_is_not_local_platform?
666
673
 
667
674
  add_platform(local_platform)
668
675
  end
669
676
 
677
+ def most_specific_ruby_locked_platform_is_not_local_platform?
678
+ @current_ruby_locked_platform && @current_ruby_locked_platform != local_platform
679
+ end
680
+
670
681
  def change_reason
671
682
  if unlocking?
672
683
  unlock_targets = if @gems_to_unlock.any?
@@ -1050,7 +1061,6 @@ module Bundler
1050
1061
  !@originally_locked_specs.incomplete_for_platform?(dependencies, platform)
1051
1062
 
1052
1063
  remove_platform(platform)
1053
- add_current_platform if platform == Gem::Platform::RUBY
1054
1064
  end
1055
1065
  end
1056
1066
 
@@ -92,6 +92,17 @@ module Bundler
92
92
  end
93
93
  end
94
94
 
95
+ # needed for `bundle fund`
96
+ def metadata
97
+ if @remote_specification
98
+ @remote_specification.metadata
99
+ elsif _local_specification
100
+ _local_specification.metadata
101
+ else
102
+ super
103
+ end
104
+ end
105
+
95
106
  def _local_specification
96
107
  return unless @loaded_from && File.exist?(local_specification_path)
97
108
  eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec|