brew/Library/Homebrew/dependency.rb
Jack Nagel fd86e6d636 Remove confusing implicit options handling
This code is supposed to allow

  depends_on "foo" => "with-bar"

to work when foo has only a "without-bar" option.

The options system was not designed to support this. Unfortunately, it
was bolted on anyway. The implementation is extremely difficult to
understand, and it only works for certain types of options, which is
confusing from a user's point of view. Luckily, no formulae in core or
the official taps rely on the behavior in order to function.

It is hindering progress in improving this code, so I am removing it.
2014-07-30 21:46:22 -05:00

145 lines
3.3 KiB
Ruby

require 'dependable'
# A dependency on another Homebrew formula.
class Dependency
include Dependable
attr_reader :name, :tags, :env_proc, :option_name
DEFAULT_ENV_PROC = proc {}
def initialize(name, tags=[], env_proc=DEFAULT_ENV_PROC, option_name=name)
@name = name
@tags = tags
@env_proc = env_proc
@option_name = option_name
end
def to_s
name
end
def ==(other)
instance_of?(other.class) && name == other.name
end
alias_method :eql?, :==
def hash
name.hash
end
def to_formula
f = Formulary.factory(name)
# Add this dependency's options to the formula's build args
f.build.args = f.build.args.concat(options)
f
end
def installed?
to_formula.installed?
end
def satisfied?(inherited_options)
installed? && missing_options(inherited_options).empty?
end
def missing_options(inherited_options=[])
missing = options | inherited_options
missing -= Tab.for_formula(to_formula).used_options
missing
end
def modify_build_environment
env_proc.call unless env_proc.nil?
end
def inspect
"#<#{self.class.name}: #{name.inspect} #{tags.inspect}>"
end
# Define marshaling semantics because we cannot serialize @env_proc
def _dump(*)
Marshal.dump([name, tags])
end
def self._load(marshaled)
new(*Marshal.load(marshaled))
end
class << self
# Expand the dependencies of dependent recursively, optionally yielding
# [dependent, dep] 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 expand(dependent, deps=dependent.deps, &block)
expanded_deps = []
deps.each do |dep|
# FIXME don't hide cyclic dependencies
next if dependent.name == dep.name
case action(dependent, dep, &block)
when :prune
next
when :skip
expanded_deps.concat(expand(dep.to_formula, &block))
when :keep_but_prune_recursive_deps
expanded_deps << dep
else
expanded_deps.concat(expand(dep.to_formula, &block))
expanded_deps << dep
end
end
merge_repeats(expanded_deps)
end
def action(dependent, dep, &block)
catch(:action) do
if block_given?
yield dependent, dep
elsif dep.optional? || dep.recommended?
prune unless dependent.build.with?(dep)
end
end
end
# Prune a dependency and its dependencies recursively
def prune
throw(:action, :prune)
end
# Prune a single dependency but do not prune its dependencies
def skip
throw(:action, :skip)
end
# Keep a dependency, but prune its dependencies
def keep_but_prune_recursive_deps
throw(:action, :keep_but_prune_recursive_deps)
end
def merge_repeats(deps)
grouped = deps.group_by(&:name)
deps.uniq.map do |dep|
tags = grouped.fetch(dep.name).map(&:tags).flatten.uniq
dep.class.new(dep.name, tags, dep.env_proc)
end
end
end
end
class TapDependency < Dependency
def initialize(name, tags=[], env_proc=DEFAULT_ENV_PROC, option_name=name)
super(name, tags, env_proc, name.split("/").last)
end
def installed?
super
rescue FormulaUnavailableError
false
end
end