Skip to content

Commit 15240f2

Browse files
homusegiddins
authored andcommitted
Auto merge of #1856 - rubygems:seg-resolver-sorting, r=segiddins
[Resolver] Use improved bundler sorting algorithm # Description: Fixes #1851 # Tasks: - [ ] Describe the problem / feature - [ ] Write tests - [ ] Write code to solve the problem - [ ] Get code review from coworkers / friends I will abide by the [code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md). (cherry picked from commit fa87e95)
1 parent 660aafa commit 15240f2

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

lib/rubygems/resolver.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,44 @@ def allow_missing?(dependency)
253253
@soft_missing
254254
end
255255

256+
def sort_dependencies(dependencies, activated, conflicts)
257+
dependencies.sort_by do |dependency|
258+
name = name_for(dependency)
259+
[
260+
activated.vertex_named(name).payload ? 0 : 1,
261+
amount_constrained(dependency),
262+
conflicts[name] ? 0 : 1,
263+
activated.vertex_named(name).payload ? 0 : search_for(dependency).count,
264+
]
265+
end
266+
end
267+
268+
SINGLE_POSSIBILITY_CONSTRAINT_PENALTY = 1_000_000
269+
private_constant :SINGLE_POSSIBILITY_CONSTRAINT_PENALTY if defined?(private_constant)
270+
271+
# returns an integer \in (-\infty, 0]
272+
# a number closer to 0 means the dependency is less constraining
273+
#
274+
# dependencies w/ 0 or 1 possibilities (ignoring version requirements)
275+
# are given very negative values, so they _always_ sort first,
276+
# before dependencies that are unconstrained
277+
def amount_constrained(dependency)
278+
@amount_constrained ||= {}
279+
@amount_constrained[dependency.name] ||= begin
280+
name_dependency = Gem::Dependency.new(dependency.name)
281+
dependency_request_for_name = Gem::Resolver::DependencyRequest.new(name_dependency, dependency.requester)
282+
all = @set.find_all(dependency_request_for_name).size
283+
284+
if all <= 1
285+
all - SINGLE_POSSIBILITY_CONSTRAINT_PENALTY
286+
else
287+
search = search_for(dependency).size
288+
search - all
289+
end
290+
end
291+
end
292+
private :amount_constrained
293+
256294
end
257295

258296
##

test/rubygems/test_gem_resolver.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,11 +521,11 @@ def test_raises_when_possibles_are_exhausted
521521
assert_equal req('>= 0'), dependency.requirement
522522

523523
activated = e.conflict.activated
524-
assert_equal 'c-2', activated.full_name
524+
assert_equal 'c-1', activated.full_name
525525

526-
assert_equal dep('c', '>= 2'), activated.request.dependency
526+
assert_equal dep('c', '= 1'), activated.request.dependency
527527

528-
assert_equal [dep('c', '= 1'), dep('c', '>= 2')],
528+
assert_equal [dep('c', '>= 2'), dep('c', '= 1')],
529529
e.conflict.conflicting_dependencies
530530
end
531531

0 commit comments

Comments
 (0)