Dependency resolution with fancy syntax

Is it a DSL? No. But people call it that apparently.

To add a dependency:

class Doe <Formula
  depends_on 'ray'
  depends_on 'mee' => :optional
  depends_on 'far' => :recommended
  depends_on Sew.new
end

Sew would be a formula you have defined in this Formula file. This is useful,
eg. see Python's formula. Formula specified in this fashion cannot be linked
into the HOMEBREW_PREFIX, they are considered private libraries. This allows
you to create custom installations that are very specific to your formula.

More features to come, like specifying versions
This commit is contained in:
Max Howell 2009-09-18 19:16:39 +01:00
parent a793e30405
commit 77dd27e8e6
3 changed files with 47 additions and 36 deletions

View File

@ -144,31 +144,12 @@ 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
def expand_deps ff
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 unless f.installed?
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
ff.deps.collect do |f|
deps += expand_deps(Formula.factory(f))
end
# TODO much more efficient to use a set and not recurse stuff already done
return deps.flatten.uniq
deps << ff
end

View File

@ -114,8 +114,6 @@ class Formula
# :p2 => ['http://moo.com/patch5', 'http://moo.com/patch6']
# }
def patches; [] end
# reimplement and specify dependencies
def deps; end
# sometimes the clean process breaks things, return true to skip anything
def skip_clean? path; false end
@ -157,6 +155,7 @@ class Formula
end
def self.factory name
return name if name.kind_of? Formula
require self.path(name)
return eval(self.class(name)).new(name)
rescue LoadError
@ -167,6 +166,10 @@ class Formula
HOMEBREW_PREFIX+'Library'+'Formula'+"#{name.downcase}.rb"
end
def deps
self.class.deps or []
end
protected
# Pretty titles the command and buffers stdout/stderr
# Throws if there's an error
@ -280,8 +283,30 @@ private
end
class <<self
attr_reader :url, :version, :homepage, :head
attr_reader :url, :version, :homepage, :head, :deps
attr_reader *CHECKSUM_TYPES
def depends_on name, *args
@deps ||= []
case name
when String
# noop
when Hash
name = name.keys.first # indeed, we only support one mapping
when Symbol
name = name.to_s
when Formula
@deps << name
return # we trust formula dev to not dupe their own instantiations
else
raise "Unsupported type #{name.class}"
end
# we get duplicates because every new fork of this process repeats this
# step for some reason I am not sure about
@deps << name unless @deps.include? name
end
end
end

View File

@ -38,6 +38,7 @@ unless system "which -s gcc-4.2" and $?.success?
abort "Sorry, Homebrew requires gcc 4.2, which is provided by Xcode 3.1"
end
begin
case ARGV.shift
when '--prefix' then puts HOMEBREW_PREFIX
@ -104,7 +105,7 @@ begin
unless system "which #{ENV['CC'] or 'cc'} &> /dev/null" and $?.success?
raise "We cannot find a c compiler, have you installed the latest Xcode?"
end
fae = ARGV.formulae.reject do |f|
formulae = ARGV.formulae.reject do |f|
if f.installed?
message = "Formula already installed: #{f.prefix}"
if ARGV.formulae.count > 1
@ -115,20 +116,24 @@ begin
true
end
end
exit 0 if fae.empty?
exit 0 if formulae.empty?
else
fae=ARGV.formulae
formulae = ARGV.formulae
end
# the resulting order will be optimal for super-deps and deps
fae=expand_deps fae
deps = []
formulae.each { |f| deps += expand_deps f }
formulae = deps.reject { |f| f.installed? }
require 'set'
done = Set.new
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
formulae.each do |f|
next if done.include? f.class
done << f.class
pid=fork
if pid.nil?
exec __FILE__, "install-just-one", f.name, *ARGV.options