1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
# 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
|