Proper recursive expansion of requirements with filtering

Expand requirements recursively while applying the same optional? and
recommended? filters that dependencies are run through. Options
generated by requirements are now checked against the correct list of
requirements, eliminating the temporary "best guess" logic in the
installer.
This commit is contained in:
Jack Nagel 2013-01-30 17:55:04 -06:00
parent f4b126cc14
commit 1408610b81
5 changed files with 59 additions and 16 deletions

View File

@ -7,7 +7,6 @@ require 'patches'
require 'compilers' require 'compilers'
require 'build_environment' require 'build_environment'
require 'build_options' require 'build_options'
require 'extend/set'
class Formula class Formula
@ -489,10 +488,8 @@ class Formula
end end
# The full set of Requirements for this formula's dependency tree. # The full set of Requirements for this formula's dependency tree.
def recursive_requirements def recursive_requirements(&block)
reqs = ComparableSet.new Requirement.expand(self, &block)
recursive_dependencies.each { |d| reqs.merge d.to_formula.requirements }
reqs.merge requirements
end end
def to_hash def to_hash

View File

@ -105,18 +105,14 @@ class FormulaInstaller
def check_requirements def check_requirements
unsatisfied = ARGV.filter_for_dependencies do unsatisfied = ARGV.filter_for_dependencies do
f.recursive_requirements.select do |req| f.recursive_requirements do |dependent, req|
if req.satisfied? if req.optional? || req.recommended?
false Requirement.prune unless dependent.build.with?(req.name)
elsif req.build? elsif req.build?
not pour_bottle? Requirement.prune unless install_bottle?(dependent)
elsif req.optional? || req.recommended?
f.recursive_dependencies.map(&:to_formula).any? do |dep|
dep.build.with?(req.name)
end || f.build.with?(req.name)
else
true
end end
Requirement.prune if req.satisfied?
end end
end end

View File

@ -106,4 +106,54 @@ class Requirement
end end
end end
end end
# Expand the requirements of dependent recursively, optionally yielding
# [dependent, req] pairs to allow callers to apply arbitrary filters to
# the list.
# The default filter, which is applied when a block is not given, omits
# optionals and recommendeds based on what the dependent has asked for.
def self.expand(dependent, &block)
reqs = ComparableSet.new
formulae = dependent.recursive_dependencies.map(&:to_formula)
formulae.unshift(dependent)
formulae.map(&:requirements).each do |requirements|
requirements.each do |req|
prune = catch(:prune) do
if block_given?
yield dependent, req
elsif req.optional? || req.recommended?
Requirement.prune unless dependent.build.with?(req.name)
end
end
next if prune
reqs << req
end
end
# We special case handling of X11Dependency and its subclasses to
# ensure the correct dependencies are present in the final list.
# If an X11Dependency is present after filtering, we eliminate
# all X11Dependency::Proxy objects from the list. If there aren't
# any X11Dependency objects, then we eliminate all but one of the
# proxy objects.
proxy = unless reqs.any? { |r| r.instance_of?(X11Dependency) }
reqs.find { |r| r.kind_of?(X11Dependency::Proxy) }
end
reqs.reject! do |r|
r.kind_of?(X11Dependency::Proxy)
end
reqs << proxy unless proxy.nil?
reqs
end
# Used to prune requirements when calling expand with a block.
def self.prune
throw(:prune, true)
end
end end

View File

@ -1,4 +1,5 @@
require 'requirement' require 'requirement'
require 'extend/set'
# A dependency on a language-specific module. # A dependency on a language-specific module.
class LanguageModuleDependency < Requirement class LanguageModuleDependency < Requirement

View File

@ -1,6 +1,5 @@
require 'testing_env' require 'testing_env'
require 'requirements' require 'requirements'
require 'extend/set'
class X11DependencyTests < Test::Unit::TestCase class X11DependencyTests < Test::Unit::TestCase
def test_eql_instances_are_eql def test_eql_instances_are_eql