Dependency resolution

Specify dependencies in your formula's deps function. You can return an Array,
String or Hash, eg:

    def deps
      { :optional => 'libogg', :required => %w[flac sdl], :recommended => 'cmake' }
    end

Note currently the Hash is flattened and qualifications are ignored. If you
only return an Array or String, the qualification is assumed to be :required.

Other packaging systems have problems when it comes to packages requiring a
specific version of a package, or some patches that may not work well with
other software. With Homebrew we have some options:

1.  If the formula is vanilla but an older version we can cherry-pick the old
    version and install it in the Cellar in parallel, but just not symlink it
    into /usr/local while forcing the formula that depends on it to link to
    that one and not any other versions of it.
2.  If the dependency requires patches then we shouldn't install this for use
    by any other tools, (I guess this needs to be decided on a per-situation
    basis). It can be installed into the parent formula's prefix, and not
    symlinked into /usr/local. In this case the dependency's Formula
    derivation should be saved in the parent formula's file (check git or
    flac for an example of this).

Both the above can be done currently with hacks, so I'll flesh out a proper
way sometime this week.
This commit is contained in:
Max Howell 2009-09-07 01:06:08 +01:00
parent 111a75d262
commit 0a31190fdc
4 changed files with 59 additions and 24 deletions

View File

@ -144,6 +144,33 @@ def clean f
end
# NOTE this is ugly code, and inefficient too, and can have infinite cycles
# I have no time currently to improve it, feel free to submit a more elegant
# solution. Thanks! --mxcl
def expand_deps fae
deps = []
fae.each do |f|
case f.deps
when String, Array
f.deps.each do |name|
f = Formula.factory name
deps << expand_deps(f) if f.deps # hideous inefficient
deps << f
end
when Hash
# TODO implement optional and recommended
names = []
f.deps.each_value {|v| names << v}
ff=names.flatten.collect {|name| Formula.factory name}
deps << expand_deps(ff)
end
deps << f
end
# TODO much more efficient to use a set and not recurse stuff already done
return deps.flatten.uniq
end
def install f
f.brew do
if ARGV.flag? '--interactive'

View File

@ -123,7 +123,7 @@ class Formula
def brew
validate_variable :name
validate_variable :version
stage do
begin
patch

View File

@ -41,7 +41,8 @@ class MostlyAbstractFormula <Formula
end
class TestBall <Formula
def initialize
# name parameter required for some Formula::factory
def initialize name=nil
@url="file:///#{Pathname.new(ABS__FILE__).parent.realpath}/testball-0.1.tbz"
super "testball"
end
@ -98,9 +99,13 @@ def nostdout
end
module ExtendArgvPlusYeast
def stick_an_arg_in_thar
def reset
@named=nil
unshift 'foo'
@formulae=nil
@kegs=nil
while ARGV.count > 0
ARGV.shift
end
end
end
ARGV.extend ExtendArgvPlusYeast
@ -347,8 +352,9 @@ class BeerTasting <Test::Unit::TestCase
end
def test_no_ARGV_dupes
ARGV.unshift'foo'
ARGV.unshift'foo'
ARGV.reset
ARGV.unshift 'foo'
ARGV.unshift 'foo'
n=0
ARGV.named.each{|arg| n+=1 if arg == 'foo'}
assert_equal 1, n
@ -360,9 +366,10 @@ class BeerTasting <Test::Unit::TestCase
assert_raises(UsageError) { ARGV.kegs }
assert ARGV.named_empty?
(HOMEBREW_CELLAR+'foo'+'0.1').mkpath
(HOMEBREW_CELLAR+'mxcl'+'10.0').mkpath
ARGV.stick_an_arg_in_thar
ARGV.reset
ARGV.unshift 'mxcl'
assert_equal 1, ARGV.named.length
assert_equal 1, ARGV.kegs.length
assert_raises(FormulaUnavailableError) { ARGV.formulae }
@ -395,7 +402,7 @@ class BeerTasting <Test::Unit::TestCase
nostdout do
assert_nothing_raised do
f=TestBall.new
make 'http://example.com/testball-0.1.tbz'
make f.url
info f.name
clean f
prune

View File

@ -95,20 +95,24 @@ begin
raise "We cannot find a c compiler, have you installed the latest Xcode?"
end
require 'beer_events'
watch_out_for_spill do
ARGV.formulae.each do |f|
if f.installed? and not ARGV.force?
message = "Formula already installed: #{f.prefix}"
if ARGV.formulae.count > 1
opoo message
else
puts message # if only one is being installed a warning looks severe
end
next
fae = ARGV.formulae.reject do |f|
if f.installed? and not ARGV.force?
message = "Formula already installed: #{f.prefix}"
if ARGV.formulae.count > 1
opoo message
else
puts message # if only one is being installed a warning looks severe
end
true
end
end
fae=expand_deps ARGV.formulae
require 'beer_events'
watch_out_for_spill do
fae.each do |f|
# we need to ensure a pristine ENV for each process or the formula
# will start with the ENV from the previous build
pid=fork
@ -162,9 +166,6 @@ begin
when 'unlink'
ARGV.kegs.each {|keg| puts "#{keg.unlink} links removed for #{keg}"}
when 'unlink'
ARGV.kegs.each {|keg| puts "#{keg.unlink} links removed for #{keg}"}
when 'rm', 'uninstall', 'remove'
ARGV.kegs.each do |keg|
puts "Uninstalling #{keg}..."