summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Giddins <segiddins@segiddins.me>2016-08-05 16:50:31 -0500
committerSamuel Giddins <segiddins@segiddins.me>2016-08-25 11:16:58 -0500
commit46f375e19c7483a8a4c4f3c3b3338ed5334023bf (patch)
treec54ec4cf1197d5e99e52ceb882cc30990fbfb98e
parent7edf2e1f13d8a0a9c6dacc7c79bc4f252f1912a3 (diff)
downloadbundler-46f375e19c7483a8a4c4f3c3b3338ed5334023bf.tar.gz
Refactor best-platform matching
-rw-r--r--lib/bundler/gem_helpers.rb51
-rw-r--r--lib/bundler/match_platform.rb3
-rw-r--r--lib/bundler/resolver.rb3
-rw-r--r--lib/bundler/spec_set.rb16
4 files changed, 53 insertions, 20 deletions
diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb
index 03c1f33fe2..6d926ce83f 100644
--- a/lib/bundler/gem_helpers.rb
+++ b/lib/bundler/gem_helpers.rb
@@ -31,16 +31,50 @@ module Bundler
def platform_specificity_match(spec_platform, user_platform)
spec_platform = Gem::Platform.new(spec_platform)
- return [-1, -1, -1] if spec_platform == user_platform
- return [5, 5, 5] if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
+ return PlatformMatch::EXACT_MATCH if spec_platform == user_platform
+ return PlatformMatch::WORST_MATCH if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
- [
+ PlatformMatch.new(
+ PlatformMatch.os_match(spec_platform, user_platform),
+ PlatformMatch.cpu_match(spec_platform, user_platform),
+ PlatformMatch.platform_version_match(spec_platform, user_platform)
+ )
+ end
+ module_function :platform_specificity_match
+
+ def select_best_platform_match(specs, platform)
+ specs.select {|spec| spec.match_platform(platform) }.
+ min_by {|spec| platform_specificity_match(spec.platform, platform) }
+ end
+ module_function :select_best_platform_match
+
+ PlatformMatch = Struct.new(:os_match, :cpu_match, :platform_version_match)
+ class PlatformMatch
+ def <=>(other)
+ return nil unless other.is_a?(PlatformMatch)
+
+ m = os_match <=> other.os_match
+ return m unless m.zero?
+
+ m = cpu_match <=> other.cpu_match
+ return m unless m.zero?
+
+ m = platform_version_match <=> other.platform_version_match
+ m
+ end
+
+ EXACT_MATCH = new(-1, -1, -1).freeze
+ WORST_MATCH = new(1_000_000, 1_000_000, 1_000_000).freeze
+
+ def self.os_match(spec_platform, user_platform)
if spec_platform.os == user_platform.os
0
else
1
- end,
+ 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")
@@ -49,17 +83,18 @@ module Bundler
1
else
2
- end,
+ 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
end
- module_function :platform_specificity_match
end
end
diff --git a/lib/bundler/match_platform.rb b/lib/bundler/match_platform.rb
index fed418b593..0a4e4c7e3a 100644
--- a/lib/bundler/match_platform.rb
+++ b/lib/bundler/match_platform.rb
@@ -8,7 +8,8 @@ module Bundler
def match_platform(p)
Gem::Platform::RUBY == platform ||
platform.nil? || p == platform ||
- generic(Gem::Platform.new(platform)) === p
+ generic(Gem::Platform.new(platform)) === p ||
+ Gem::Platform.new(platform) === p
end
end
end
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index 55deefbd6c..b8016b37a9 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -77,8 +77,7 @@ module Bundler
@activated_platforms = []
@dependencies = nil
@specs = Hash.new do |specs, platform|
- specs[platform] = select {|spec| spec.match_platform(platform) }.
- min_by {|spec| platform_specificity_match(spec.platform, platform) }
+ specs[platform] = select_best_platform_match(self, platform)
end
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 48699abfe4..92b1c0dac1 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -24,12 +24,13 @@ module Bundler
dep = deps.shift
next if handled[dep] || skip.include?(dep.name)
- spec = lookup[dep.name].find do |s|
- if match_current_platform
- Gem::Platform.match(s.platform)
- else
- s.match_platform(dep.__platform)
+ spec = if match_current_platform
+ Bundler.rubygems.platforms.reverse_each do |pl|
+ match = GemHelpers.select_best_platform_match(lookup[dep.name], pl)
+ break match if match
end
+ else
+ GemHelpers.select_best_platform_match(lookup[dep.name], dep.__platform)
end
handled[dep] = true
@@ -147,10 +148,7 @@ module Bundler
def lookup
@lookup ||= begin
lookup = Hash.new {|h, k| h[k] = [] }
- specs = @specs.sort_by do |s|
- s.platform.to_s == "ruby" ? "\0" : s.platform.to_s
- end
- specs.reverse_each do |s|
+ Index.sort_specs(@specs).reverse_each do |s|
lookup[s.name] << s
end
lookup