summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSamuel Giddins <[email protected]>2025-05-18 11:37:35 -0400
committerHiroshi SHIBATA <[email protected]>2025-06-06 10:22:18 +0900
commitc0a1e877b3c0c5dd69bb634262bd4e73a07eb27e ()
treedabebfbdd5389f04e180f4f4c4286f7a8800168a /lib
parent6a9af9f0b566f8a13f82a1ca402efa99a3464794 (diff)
Move most of Bundler::GemHelpers to Gem::Platform
This will help centralize wheel platform selection logic eventually Signed-off-by: Samuel Giddins <[email protected]>
-rw-r--r--lib/bundler.rb5
-rw-r--r--lib/bundler/cli/outdated.rb2
-rw-r--r--lib/bundler/cli/update.rb2
-rw-r--r--lib/bundler/current_ruby.rb2
-rw-r--r--lib/bundler/definition.rb26
-rw-r--r--lib/bundler/dependency.rb2
-rw-r--r--lib/bundler/dsl.rb2
-rw-r--r--lib/bundler/gem_helpers.rb144
-rw-r--r--lib/bundler/lazy_specification.rb8
-rw-r--r--lib/bundler/lockfile_parser.rb4
-rw-r--r--lib/bundler/match_platform.rb43
-rw-r--r--lib/bundler/materialization.rb4
-rw-r--r--lib/bundler/resolver.rb4
-rw-r--r--lib/bundler/resolver/package.rb2
-rw-r--r--lib/bundler/rubygems_ext.rb133
-rw-r--r--lib/bundler/spec_set.rb6
-rw-r--r--lib/rubygems/basic_specification.rb7
-rw-r--r--lib/rubygems/platform.rb114
18 files changed, 307 insertions, 203 deletions
@@ -53,7 +53,6 @@ module Bundler
autoload :FeatureFlag, File.expand_path("bundler/feature_flag", __dir__)
autoload :FREEBSD, File.expand_path("bundler/constants", __dir__)
autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__)
- autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__)
autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__)
autoload :Graph, File.expand_path("bundler/graph", __dir__)
autoload :Index, File.expand_path("bundler/index", __dir__)
@@ -459,6 +458,10 @@ module Bundler
Gem::Platform.local
end
def default_gemfile
SharedHelpers.default_gemfile
end
@@ -155,7 +155,7 @@ module Bundler
return active_spec if strict
- active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1
active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
end
@@ -92,7 +92,7 @@ module Bundler
locked_spec = locked_info[:spec]
new_spec = Bundler.definition.specs[name].first
unless new_spec
- unless locked_spec.match_platform(Bundler.local_platform)
Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one"
end
@@ -32,7 +32,7 @@ module Bundler
end.freeze
def ruby?
- return true if Bundler::GemHelpers.generic_local_platform_is_ruby?
!windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
end
@@ -4,8 +4,6 @@ require_relative "lockfile_parser"
module Bundler
class Definition
- include GemHelpers
-
class << self
# Do not create or modify a lockfile (Makes #lock a noop)
attr_accessor :no_lock
@@ -282,7 +280,7 @@ module Bundler
end
def filter_relevant(dependencies)
- platforms_array = [generic_local_platform].freeze
dependencies.select do |d|
d.should_include? && !d.gem_platforms(platforms_array).empty?
end
@@ -456,8 +454,8 @@ module Bundler
return if current_platform_locked? || @platforms.include?(Gem::Platform::RUBY)
raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
- "but your local platform is #{local_platform}. " \
- "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
end
def normalize_platforms
@@ -568,7 +566,7 @@ module Bundler
end
def should_add_extra_platforms?
- !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
end
def lockfile_exists?
@@ -632,7 +630,7 @@ module Bundler
@resolution_base ||= begin
last_resolve = converge_locked_specs
remove_invalid_platforms!
- new_resolution_platforms = @current_platform_missing ? @new_platforms + [local_platform] : @new_platforms
base = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlocking_all || @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms)
base = additional_base_requirements_to_prevent_downgrades(base)
base = additional_base_requirements_to_force_updates(base)
@@ -738,8 +736,8 @@ module Bundler
end
def start_resolution
- local_platform_needed_for_resolvability = @most_specific_non_local_locked_platform && [email protected]?(local_platform)
- @platforms << local_platform if local_platform_needed_for_resolvability
add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
result = SpecSet.new(resolver.start)
@@ -758,7 +756,7 @@ module Bundler
if result.incomplete_for_platform?(current_dependencies, @most_specific_non_local_locked_platform)
@platforms.delete(@most_specific_non_local_locked_platform)
elsif local_platform_needed_for_resolvability
- @platforms.delete(local_platform)
end
end
@@ -777,17 +775,17 @@ module Bundler
def current_platform_locked?
@platforms.any? do |bundle_platform|
- generic_local_platform == bundle_platform || local_platform === bundle_platform
end
end
def add_current_platform
- return if @platforms.include?(local_platform)
@most_specific_non_local_locked_platform = find_most_specific_locked_platform
return if @most_specific_non_local_locked_platform
- @platforms << local_platform
true
end
@@ -1167,7 +1165,7 @@ module Bundler
def remove_invalid_platforms!
return if Bundler.frozen_bundle?
- skips = (@new_platforms + [local_platform]).uniq
# We should probably avoid removing non-ruby platforms, since that means
# lockfile will no longer install on those platforms, so a error to give
@@ -99,7 +99,7 @@ module Bundler
return RUBY_PLATFORM_ARRAY if force_ruby_platform
return valid_platforms if platforms.empty?
- valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) }
end
def expanded_platforms
@@ -73,7 +73,7 @@ module Bundler
case specs_by_name_and_version.size
when 1
specs = specs_by_name_and_version.values.first
- spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first
@gemspecs << spec
@@ -1,144 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module GemHelpers
- GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant
- GENERICS = [
- Gem::Platform::JAVA,
- *Gem::Platform::WINDOWS,
- ].freeze
-
- def generic(p)
- GENERIC_CACHE[p] ||= begin
- found = GENERICS.find do |match|
- p === match
- end
- found || Gem::Platform::RUBY
- end
- end
- module_function :generic
-
- def generic_local_platform
- generic(local_platform)
- end
- module_function :generic_local_platform
-
- def local_platform
- Bundler.local_platform
- end
- module_function :local_platform
-
- def generic_local_platform_is_ruby?
- generic_local_platform == Gem::Platform::RUBY
- end
- module_function :generic_local_platform_is_ruby?
-
- def platform_specificity_match(spec_platform, user_platform)
- spec_platform = Gem::Platform.new(spec_platform)
-
- PlatformMatch.specificity_score(spec_platform, user_platform)
- end
- module_function :platform_specificity_match
-
- def select_all_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
- matching = if force_ruby
- specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
- else
- specs.select {|spec| spec.match_platform(platform) }
- end
-
- if prefer_locked
- locked_originally = matching.select {|spec| spec.is_a?(LazySpecification) }
- return locked_originally if locked_originally.any?
- end
-
- matching
- end
- module_function :select_all_platform_match
-
- def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
- matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked)
-
- sort_and_filter_best_platform_match(matching, platform)
- end
- module_function :select_best_platform_match
-
- def select_best_local_platform_match(specs, force_ruby: false)
- matching = select_all_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
-
- sort_best_platform_match(matching, local_platform)
- end
- module_function :select_best_local_platform_match
-
- def sort_and_filter_best_platform_match(matching, platform)
- return matching if matching.one?
-
- exact = matching.select {|spec| spec.platform == platform }
- return exact if exact.any?
-
- sorted_matching = sort_best_platform_match(matching, platform)
- exemplary_spec = sorted_matching.first
-
- sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) }
- end
- module_function :sort_and_filter_best_platform_match
-
- def sort_best_platform_match(matching, platform)
- matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
- end
- module_function :sort_best_platform_match
-
- class PlatformMatch
- def self.specificity_score(spec_platform, user_platform)
- return -1 if spec_platform == user_platform
- return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
-
- os_match(spec_platform, user_platform) +
- cpu_match(spec_platform, user_platform) * 10 +
- platform_version_match(spec_platform, user_platform) * 100
- end
-
- def self.os_match(spec_platform, user_platform)
- if spec_platform.os == user_platform.os
- 0
- else
- 1
- end
- end
-
- def self.cpu_match(spec_platform, user_platform)
- if spec_platform.cpu == user_platform.cpu
- 0
- elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm")
- 0
- elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal"
- 1
- else
- 2
- end
- end
-
- def self.platform_version_match(spec_platform, user_platform)
- if spec_platform.version == user_platform.version
- 0
- elsif spec_platform.version.nil?
- 1
- else
- 2
- end
- end
- end
-
- def same_specificity(platform, spec, exemplary_spec)
- platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform)
- end
- module_function :same_specificity
-
- def same_deps(spec, exemplary_spec)
- same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort
- same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version
- same_runtime_deps && same_metadata_deps
- end
- module_function :same_deps
- end
-end
@@ -142,15 +142,15 @@ module Bundler
end
else
materialize([name, version]) do |matching_specs|
- target_platform = source.is_a?(Source::Path) ? platform : local_platform
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
return specification unless specification.nil?
if target_platform != platform
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, platform)
end
choose_compatible(installable_candidates)
@@ -190,7 +190,7 @@ module Bundler
end
def ruby_platform_materializes_to_ruby_platform?
- generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
(most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform]
end
@@ -4,8 +4,6 @@ require_relative "shared_helpers"
module Bundler
class LockfileParser
- include GemHelpers
-
class Position
attr_reader :line, :column
def initialize(line, column)
@@ -157,7 +155,7 @@ module Bundler
end
@most_specific_locked_platform = @platforms.min_by do |bundle_platform|
- platform_specificity_match(bundle_platform, local_platform)
end
@specs = @specs.values.sort_by!(&:full_name).each do |spec|
spec.most_specific_locked_platform = @most_specific_locked_platform
@@ -1,23 +1,42 @@
# frozen_string_literal: true
-require_relative "gem_helpers"
-
module Bundler
module MatchPlatform
- include GemHelpers
- def match_platform(p)
- MatchPlatform.platforms_match?(platform, p)
end
- def self.platforms_match?(gemspec_platform, local_platform)
- return true if gemspec_platform.nil?
- return true if gemspec_platform == Gem::Platform::RUBY
- return true if local_platform == gemspec_platform
- gemspec_platform = Gem::Platform.new(gemspec_platform)
- return true if gemspec_platform === local_platform
- false
end
end
end
@@ -22,9 +22,9 @@ module Bundler
@specs ||= if @candidates.nil?
[]
elsif platform
- GemHelpers.select_best_platform_match(@candidates, platform, force_ruby: dep.force_ruby_platform)
else
- GemHelpers.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
end
end
@@ -14,8 +14,6 @@ module Bundler
require_relative "resolver/root"
require_relative "resolver/strategy"
- include GemHelpers
-
def initialize(base, gem_version_promoter, most_specific_locked_platform = nil)
@source_requirements = base.source_requirements
@base = base
@@ -273,7 +271,7 @@ module Bundler
next groups if platform_specs.all?(&:empty?)
end
- ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY)
ruby_group = Resolver::SpecGroup.new(ruby_specs)
unless ruby_group.empty?
@@ -30,7 +30,7 @@ module Bundler
def platform_specs(specs)
platforms.map do |platform|
prefer_locked = @new_platforms.include?(platform) ? false : !unlock?
- GemHelpers.select_best_platform_match(specs, platform, prefer_locked: prefer_locked)
end
end
@@ -52,16 +52,123 @@ module Gem
require "rubygems/platform"
class Platform
- JAVA = Gem::Platform.new("java")
- MSWIN = Gem::Platform.new("mswin32")
- MSWIN64 = Gem::Platform.new("mswin64")
- MINGW = Gem::Platform.new("x86-mingw32")
- X64_MINGW_LEGACY = Gem::Platform.new("x64-mingw32")
- X64_MINGW = Gem::Platform.new("x64-mingw-ucrt")
- UNIVERSAL_MINGW = Gem::Platform.new("universal-mingw")
- WINDOWS = [MSWIN, MSWIN64, UNIVERSAL_MINGW].flatten.freeze
- X64_LINUX = Gem::Platform.new("x86_64-linux")
- X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl")
end
require "rubygems/specification"
@@ -80,7 +187,6 @@ module Gem
require_relative "match_platform"
include ::Bundler::MatchMetadata
- include ::Bundler::MatchPlatform
attr_accessor :remote, :relative_loaded_from
@@ -285,6 +391,11 @@ module Gem
@ignored = missing_extensions?
end
end
end
require "rubygems/name_tuple"
@@ -76,7 +76,7 @@ module Bundler
new_platforms = all_platforms.select do |platform|
next if platforms.include?(platform)
- next unless GemHelpers.generic(platform) == Gem::Platform::RUBY
complete_platform(platform)
end
@@ -183,7 +183,7 @@ module Bundler
end
def find_by_name_and_platform(name, platform)
- @specs.detect {|spec| spec.name == name && spec.match_platform(platform) }
end
def specs_with_additional_variants_from(other)
@@ -280,7 +280,7 @@ module Bundler
valid_platform = lookup.all? do |_, specs|
spec = specs.first
matching_specs = spec.source.specs.search([spec.name, spec.version])
- platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s|
valid?(s)
end
@@ -256,6 +256,13 @@ class Gem::BasicSpecification
raise NotImplementedError
end
def raw_require_paths # :nodoc:
raise NotImplementedError
end
@@ -255,4 +255,118 @@ class Gem::Platform
# This will be replaced with Gem::Platform::local.
CURRENT = "current"
end