
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.
145 lines
3.3 KiB
Ruby
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
|