2009-10-15 09:07:12 +01:00
|
|
|
require 'download_strategy'
|
2009-12-01 10:54:59 +00:00
|
|
|
require 'fileutils'
|
2009-10-15 09:07:12 +01:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
class FormulaUnavailableError <RuntimeError
|
|
|
|
def initialize name
|
2009-09-23 10:06:19 -07:00
|
|
|
@name = name
|
2009-08-10 16:48:30 +01:00
|
|
|
super "No available formula for #{name}"
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2009-09-23 10:06:19 -07:00
|
|
|
|
|
|
|
attr_reader :name
|
2009-08-10 16:48:30 +01:00
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
|
2009-08-11 18:16:12 +01:00
|
|
|
|
2009-11-16 13:24:41 -08:00
|
|
|
# The Formulary is the collection of all Formulae, of course.
|
|
|
|
class Formulary
|
|
|
|
# Returns all formula names as strings, with or without aliases
|
|
|
|
def self.names with_aliases=false
|
2010-01-11 09:07:53 -08:00
|
|
|
filenames = (HOMEBREW_REPOSITORY+'Library/Formula').children.select {|f| f.to_s =~ /\.rb$/ }
|
|
|
|
everything = filenames.map{|f| f.basename('.rb').to_s }
|
2009-11-23 10:07:23 -08:00
|
|
|
everything.push *Formulary.get_aliases.keys if with_aliases
|
2009-11-16 13:24:41 -08:00
|
|
|
everything.sort
|
|
|
|
end
|
2009-11-19 14:10:47 -08:00
|
|
|
|
|
|
|
def self.paths
|
|
|
|
Dir["#{HOMEBREW_REPOSITORY}/Library/Formula/*.rb"]
|
|
|
|
end
|
2009-11-16 13:24:41 -08:00
|
|
|
|
2009-11-16 23:12:24 -08:00
|
|
|
def self.read name
|
2009-12-08 16:02:30 -08:00
|
|
|
require Formula.path(name) rescue return nil
|
|
|
|
klass_name = Formula.class_s(name)
|
|
|
|
eval(klass_name)
|
2009-11-16 23:12:24 -08:00
|
|
|
end
|
|
|
|
|
2009-11-16 13:24:41 -08:00
|
|
|
def self.read_all
|
2010-01-13 11:07:42 +00:00
|
|
|
# yields once for each
|
2009-11-16 13:24:41 -08:00
|
|
|
Formulary.names.each do |name|
|
2010-03-23 07:01:02 -07:00
|
|
|
begin
|
|
|
|
require Formula.path(name)
|
|
|
|
klass_name = Formula.class_s(name)
|
|
|
|
klass = eval(klass_name)
|
|
|
|
yield name, klass
|
|
|
|
rescue Exception=>e
|
|
|
|
opoo "Error importing #{name}:"
|
|
|
|
puts "#{e}"
|
|
|
|
end
|
2009-11-16 13:24:41 -08:00
|
|
|
end
|
|
|
|
end
|
2009-11-16 15:31:15 -08:00
|
|
|
|
2010-01-13 11:07:42 +00:00
|
|
|
# returns a map of aliases to actual names
|
|
|
|
# eg { 'ocaml' => 'objective-caml' }
|
2009-11-16 15:31:15 -08:00
|
|
|
def self.get_aliases
|
|
|
|
aliases = {}
|
|
|
|
Formulary.read_all do |name, klass|
|
|
|
|
aka = klass.aliases
|
|
|
|
next if aka == nil
|
|
|
|
|
|
|
|
aka.each {|item| aliases[item.to_s] = name }
|
|
|
|
end
|
|
|
|
return aliases
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.find_alias name
|
|
|
|
aliases = Formulary.get_aliases
|
|
|
|
return aliases[name]
|
|
|
|
end
|
2009-11-16 13:24:41 -08:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2009-08-21 20:20:44 +01:00
|
|
|
# Derive and define at least @url, see Library/Formula for examples
|
|
|
|
class Formula
|
2009-12-01 10:54:59 +00:00
|
|
|
include FileUtils
|
|
|
|
|
2010-06-15 12:35:55 -07:00
|
|
|
attr_reader :url, :version, :homepage, :name, :specs, :downloader
|
|
|
|
|
2009-08-21 20:20:44 +01:00
|
|
|
# Homebrew determines the name
|
2009-08-22 17:26:15 +01:00
|
|
|
def initialize name='__UNKNOWN__'
|
2009-09-22 13:03:46 -04:00
|
|
|
set_instance_variable 'url'
|
|
|
|
set_instance_variable 'head'
|
2009-10-17 14:35:24 +02:00
|
|
|
set_instance_variable 'specs'
|
2009-08-23 17:57:45 +01:00
|
|
|
|
2010-07-18 09:20:47 -07:00
|
|
|
if @head and (not @url or ARGV.build_head?)
|
2009-08-23 17:57:45 +01:00
|
|
|
@url=@head
|
|
|
|
@version='HEAD'
|
|
|
|
end
|
|
|
|
|
2009-12-17 23:00:20 +00:00
|
|
|
raise "No url provided for formula #{name}" if @url.nil?
|
2009-08-21 20:20:44 +01:00
|
|
|
@name=name
|
2009-08-22 17:26:15 +01:00
|
|
|
validate_variable :name
|
2009-09-22 13:03:46 -04:00
|
|
|
|
|
|
|
set_instance_variable 'version'
|
|
|
|
@version ||= Pathname.new(@url).version
|
2009-08-22 17:26:15 +01:00
|
|
|
validate_variable :version if @version
|
2009-09-22 13:03:46 -04:00
|
|
|
|
|
|
|
set_instance_variable 'homepage'
|
|
|
|
|
2009-09-07 16:10:50 +02:00
|
|
|
CHECKSUM_TYPES.each do |type|
|
2009-09-22 13:03:46 -04:00
|
|
|
set_instance_variable type
|
2009-09-07 16:10:50 +02:00
|
|
|
end
|
2010-01-16 17:54:14 -08:00
|
|
|
|
|
|
|
@downloader=download_strategy.new url, name, version, specs
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# if the dir is there, but it's empty we consider it not installed
|
|
|
|
def installed?
|
2009-07-29 00:57:55 +01:00
|
|
|
return prefix.children.length > 0
|
2009-07-24 15:10:01 +01:00
|
|
|
rescue
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
def prefix
|
2009-08-22 17:26:15 +01:00
|
|
|
validate_variable :name
|
|
|
|
validate_variable :version
|
2009-07-31 02:51:17 +01:00
|
|
|
HOMEBREW_CELLAR+@name+@version
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2009-08-01 17:54:18 +01:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
def path
|
2009-08-21 20:20:44 +01:00
|
|
|
self.class.path name
|
2009-08-10 16:48:30 +01:00
|
|
|
end
|
|
|
|
|
2010-02-19 21:55:17 -08:00
|
|
|
def cached_download
|
2010-05-05 21:16:32 -07:00
|
|
|
@downloader.cached_location
|
2010-02-19 21:55:17 -08:00
|
|
|
end
|
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
def bin; prefix+'bin' end
|
2009-08-12 09:43:16 +08:00
|
|
|
def sbin; prefix+'sbin' end
|
2010-03-17 16:50:33 -07:00
|
|
|
def doc; prefix+'share/doc'+name end
|
2009-08-10 16:48:30 +01:00
|
|
|
def lib; prefix+'lib' end
|
2009-08-21 16:24:14 -07:00
|
|
|
def libexec; prefix+'libexec' end
|
2010-03-17 16:50:33 -07:00
|
|
|
def man; prefix+'share/man' end
|
2009-08-01 17:54:18 +01:00
|
|
|
def man1; man+'man1' end
|
2010-03-17 16:50:33 -07:00
|
|
|
def info; prefix+'share/info' end
|
2009-08-01 17:54:18 +01:00
|
|
|
def include; prefix+'include' end
|
2009-09-08 22:01:41 +01:00
|
|
|
def share; prefix+'share' end
|
2009-10-02 15:55:34 +01:00
|
|
|
|
2009-10-03 15:23:28 +01:00
|
|
|
# generally we don't want var stuff inside the keg
|
2009-10-01 14:44:40 +01:00
|
|
|
def var; HOMEBREW_PREFIX+'var' end
|
2009-10-03 15:23:28 +01:00
|
|
|
# configuration needs to be preserved past upgrades
|
2009-10-02 15:55:34 +01:00
|
|
|
def etc; HOMEBREW_PREFIX+'etc' end
|
2009-10-03 15:23:28 +01:00
|
|
|
|
2009-08-11 12:20:55 -07:00
|
|
|
# reimplement if we don't autodetect the download strategy you require
|
|
|
|
def download_strategy
|
2010-04-10 14:48:53 +02:00
|
|
|
if @specs and @url == @head
|
2010-04-06 13:13:50 -07:00
|
|
|
vcs = @specs.delete :using
|
|
|
|
if vcs != nil
|
|
|
|
# If a class is passed, assume it is a download strategy
|
|
|
|
return vcs if vcs.kind_of? Class
|
|
|
|
|
|
|
|
case vcs
|
|
|
|
when :bzr then return BazaarDownloadStrategy
|
|
|
|
when :curl then return CurlDownloadStrategy
|
|
|
|
when :cvs then return CVSDownloadStrategy
|
|
|
|
when :git then return GitDownloadStrategy
|
|
|
|
when :hg then return MercurialDownloadStrategy
|
|
|
|
when :svn then return SubversionDownloadStrategy
|
|
|
|
end
|
|
|
|
|
|
|
|
raise "Unknown strategy #{vcs} was requested."
|
2010-03-17 16:56:06 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-03-22 21:19:20 -07:00
|
|
|
detect_download_strategy url
|
2009-08-11 12:20:55 -07:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
|
|
|
# tell the user about any caveats regarding this package, return a string
|
2009-08-10 16:48:30 +01:00
|
|
|
def caveats; nil end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
# patches are automatically applied after extracting the tarball
|
2009-11-13 14:27:21 -05:00
|
|
|
# return an array of strings, or if you need a patch level other than -p1
|
2009-08-11 18:16:12 +01:00
|
|
|
# return a Hash eg.
|
|
|
|
# {
|
|
|
|
# :p0 => ['http://foo.com/patch1', 'http://foo.com/patch2'],
|
|
|
|
# :p1 => 'http://bar.com/patch2',
|
|
|
|
# :p2 => ['http://moo.com/patch5', 'http://moo.com/patch6']
|
|
|
|
# }
|
2009-09-17 21:10:39 +01:00
|
|
|
# The final option is to return DATA, then put a diff after __END__. You
|
2009-09-04 15:28:18 +01:00
|
|
|
# can still return a Hash with DATA as the value for a patch level key.
|
2009-09-21 23:51:31 +01:00
|
|
|
def patches; end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2009-09-17 21:10:39 +01:00
|
|
|
# rarely, you don't want your library symlinked into the main prefix
|
|
|
|
# see gettext.rb for an example
|
|
|
|
def keg_only?; false end
|
2009-08-10 16:48:30 +01:00
|
|
|
|
2009-09-28 14:06:53 -07:00
|
|
|
# sometimes the clean process breaks things
|
|
|
|
# skip cleaning paths in a formula with a class method like this:
|
|
|
|
# skip_clean [bin+"foo", lib+"bar"]
|
|
|
|
# redefining skip_clean? in formulas is now deprecated
|
|
|
|
def skip_clean? path
|
|
|
|
to_check = path.relative_path_from(prefix).to_s
|
2009-11-23 10:07:23 -08:00
|
|
|
self.class.skip_clean_paths.include? to_check
|
2009-09-28 14:06:53 -07:00
|
|
|
end
|
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
# yields self with current working directory set to the uncompressed tarball
|
|
|
|
def brew
|
2009-08-22 17:26:15 +01:00
|
|
|
validate_variable :name
|
|
|
|
validate_variable :version
|
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.
2009-09-07 01:06:08 +01:00
|
|
|
|
2009-08-11 12:20:55 -07:00
|
|
|
stage do
|
2009-08-10 16:48:30 +01:00
|
|
|
begin
|
|
|
|
patch
|
2009-09-04 15:28:18 +01:00
|
|
|
# we allow formulas to do anything they want to the Ruby process
|
|
|
|
# so load any deps before this point! And exit asap afterwards
|
2009-08-10 16:48:30 +01:00
|
|
|
yield self
|
|
|
|
rescue Interrupt, RuntimeError, SystemCallError => e
|
|
|
|
raise unless ARGV.debug?
|
|
|
|
onoe e.inspect
|
|
|
|
puts e.backtrace
|
|
|
|
ohai "Rescuing build..."
|
2010-04-03 08:44:41 -07:00
|
|
|
if (e.was_running_configure? rescue false) and File.exist? 'config.log'
|
|
|
|
puts "It looks like an autotools configure failed."
|
|
|
|
puts "Gist 'config.log' and any error output when reporting an issue."
|
|
|
|
puts
|
|
|
|
end
|
|
|
|
|
2009-08-27 13:46:19 -07:00
|
|
|
puts "When you exit this shell Homebrew will attempt to finalise the installation."
|
|
|
|
puts "If nothing is installed or the shell exits with a non-zero error code,"
|
|
|
|
puts "Homebrew will abort. The installation prefix is:"
|
|
|
|
puts prefix
|
2010-06-11 17:18:05 -07:00
|
|
|
ENV['HOMEBREW_DEBUG_INSTALL'] = name
|
2009-08-10 16:48:30 +01:00
|
|
|
interactive_shell
|
|
|
|
end
|
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2009-08-10 16:48:30 +01:00
|
|
|
|
2009-08-21 20:20:44 +01:00
|
|
|
# we don't have a std_autotools variant because autotools is a lot less
|
|
|
|
# consistent and the standard parameters are more memorable
|
|
|
|
# really Homebrew should determine what works inside brew() then
|
|
|
|
# we could add --disable-dependency-tracking when it will work
|
|
|
|
def std_cmake_parameters
|
|
|
|
# The None part makes cmake use the environment's CFLAGS etc. settings
|
2009-12-09 04:47:17 +01:00
|
|
|
"-DCMAKE_INSTALL_PREFIX='#{prefix}' -DCMAKE_BUILD_TYPE=None -Wno-dev"
|
2009-08-21 20:20:44 +01:00
|
|
|
end
|
|
|
|
|
2009-09-11 14:22:46 +01:00
|
|
|
def self.class_s name
|
2010-01-13 11:07:42 +00:00
|
|
|
#remove invalid characters and then camelcase it
|
2009-10-19 13:05:47 +01:00
|
|
|
name.capitalize.gsub(/[-_.\s]([a-zA-Z0-9])/) { $1.upcase } \
|
|
|
|
.gsub('+', 'x')
|
2009-08-21 20:20:44 +01:00
|
|
|
end
|
2009-11-16 15:35:58 -08:00
|
|
|
|
|
|
|
def self.get_used_by
|
|
|
|
used_by = {}
|
|
|
|
Formulary.read_all do |name, klass|
|
|
|
|
deps = klass.deps
|
|
|
|
next if deps == nil
|
|
|
|
|
|
|
|
deps.each do |dep|
|
|
|
|
_deps = used_by[dep] || []
|
|
|
|
_deps << name unless _deps.include? name
|
|
|
|
used_by[dep] = _deps
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return used_by
|
|
|
|
end
|
2009-08-21 20:20:44 +01:00
|
|
|
|
|
|
|
def self.factory name
|
2009-09-18 19:16:39 +01:00
|
|
|
return name if name.kind_of? Formula
|
2009-09-04 15:28:18 +01:00
|
|
|
path = Pathname.new(name)
|
|
|
|
if path.absolute?
|
|
|
|
require name
|
|
|
|
name = path.stem
|
|
|
|
else
|
2009-11-16 15:31:15 -08:00
|
|
|
begin
|
|
|
|
require self.path(name)
|
|
|
|
rescue LoadError => e
|
|
|
|
# Couldn't find formula 'name', so look for an alias.
|
|
|
|
real_name = Formulary.find_alias name
|
|
|
|
raise e if real_name == nil
|
|
|
|
puts "#{name} is an alias for #{real_name}"
|
|
|
|
name = real_name
|
|
|
|
end
|
2009-09-04 15:28:18 +01:00
|
|
|
end
|
2009-09-23 10:06:19 -07:00
|
|
|
begin
|
|
|
|
klass_name =self.class_s(name)
|
|
|
|
klass = eval(klass_name)
|
|
|
|
rescue NameError
|
|
|
|
# TODO really this text should be encoded into the exception
|
|
|
|
# and only shown if the UI deems it correct to show it
|
|
|
|
onoe "class \"#{klass_name}\" expected but not found in #{name}.rb"
|
|
|
|
puts "Double-check the name of the class in that formula."
|
|
|
|
raise LoadError
|
|
|
|
end
|
|
|
|
return klass.new(name)
|
2009-08-21 20:20:44 +01:00
|
|
|
rescue LoadError
|
|
|
|
raise FormulaUnavailableError.new(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.path name
|
2009-12-16 10:41:00 -08:00
|
|
|
HOMEBREW_REPOSITORY+"Library/Formula/#{name.downcase}.rb"
|
2009-08-21 20:20:44 +01:00
|
|
|
end
|
|
|
|
|
2009-09-18 19:16:39 +01:00
|
|
|
def deps
|
|
|
|
self.class.deps or []
|
|
|
|
end
|
|
|
|
|
2010-01-13 09:00:24 +00:00
|
|
|
def external_deps
|
|
|
|
self.class.external_deps
|
|
|
|
end
|
|
|
|
|
2010-06-16 11:50:36 -07:00
|
|
|
def fails_with_llvm msg="", data=nil
|
|
|
|
return unless (ENV['HOMEBREW_USE_LLVM'] or ARGV.include? '--use-llvm')
|
|
|
|
|
|
|
|
build = data.delete :build rescue nil
|
|
|
|
msg = "(No specific reason was given)" if msg.empty?
|
|
|
|
|
|
|
|
opoo "LLVM was requested, but this formula is reported as not working with LLVM:"
|
|
|
|
puts msg
|
|
|
|
puts "Tested with LLVM build #{build}" unless build == nil
|
|
|
|
end
|
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
protected
|
2009-07-24 15:10:01 +01:00
|
|
|
# Pretty titles the command and buffers stdout/stderr
|
|
|
|
# Throws if there's an error
|
2009-08-10 16:48:30 +01:00
|
|
|
def system cmd, *args
|
2009-11-06 17:09:14 +00:00
|
|
|
ohai "#{cmd} #{args*' '}".strip
|
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
if ARGV.verbose?
|
|
|
|
safe_system cmd, *args
|
2009-07-24 15:10:01 +01:00
|
|
|
else
|
2009-11-06 17:09:14 +00:00
|
|
|
rd, wr = IO.pipe
|
2009-11-09 17:45:22 +00:00
|
|
|
pid = fork do
|
2009-11-06 17:09:14 +00:00
|
|
|
rd.close
|
|
|
|
$stdout.reopen wr
|
|
|
|
$stderr.reopen wr
|
2009-11-11 19:42:35 +00:00
|
|
|
exec(cmd, *args) rescue nil
|
|
|
|
exit! 1 # never gets here unless exec threw or failed
|
2009-11-06 17:09:14 +00:00
|
|
|
end
|
2009-11-09 17:45:22 +00:00
|
|
|
wr.close
|
2009-11-06 17:09:14 +00:00
|
|
|
out = ''
|
2009-11-09 17:45:22 +00:00
|
|
|
out << rd.read until rd.eof?
|
2009-11-07 18:23:21 +00:00
|
|
|
Process.wait
|
2009-11-06 17:09:14 +00:00
|
|
|
unless $?.success?
|
2009-08-10 16:48:30 +01:00
|
|
|
puts out
|
|
|
|
raise
|
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2009-12-09 15:15:19 +00:00
|
|
|
rescue SystemCallError
|
|
|
|
# usually because exec could not be find the command that was requested
|
|
|
|
raise
|
|
|
|
rescue
|
2009-11-06 17:06:12 +00:00
|
|
|
raise BuildError.new(cmd, args, $?)
|
2009-08-10 16:48:30 +01:00
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
private
|
2009-08-11 12:20:55 -07:00
|
|
|
# creates a temporary directory then yields, when the block returns it
|
|
|
|
# recursively deletes the temporary directory
|
2009-08-10 16:48:30 +01:00
|
|
|
def mktemp
|
2009-08-23 17:57:45 +01:00
|
|
|
# I used /tmp rather than mktemp -td because that generates a directory
|
|
|
|
# name with exotic characters like + in it, and these break badly written
|
|
|
|
# scripts that don't escape strings before trying to regexp them :(
|
2010-05-01 14:06:23 -07:00
|
|
|
|
|
|
|
# If the user has FileVault enabled, then we can't mv symlinks from the
|
|
|
|
# /tmp volume to the other volume. So we let the user override the tmp
|
|
|
|
# prefix if they need to.
|
|
|
|
tmp_prefix = ENV['HOMEBREW_TEMP'] || '/tmp'
|
|
|
|
tmp=Pathname.new `/usr/bin/mktemp -d #{tmp_prefix}/homebrew-#{name}-#{version}-XXXX`.strip
|
2009-08-23 17:57:45 +01:00
|
|
|
raise "Couldn't create build sandbox" if not tmp.directory? or $? != 0
|
2009-08-10 16:48:30 +01:00
|
|
|
begin
|
|
|
|
wd=Dir.pwd
|
|
|
|
Dir.chdir tmp
|
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
Dir.chdir wd
|
|
|
|
tmp.rmtree
|
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
|
2009-09-07 16:10:50 +02:00
|
|
|
CHECKSUM_TYPES=[:md5, :sha1, :sha256].freeze
|
|
|
|
|
2009-07-31 11:05:23 -07:00
|
|
|
def verify_download_integrity fn
|
|
|
|
require 'digest'
|
2009-09-07 16:10:50 +02:00
|
|
|
type=CHECKSUM_TYPES.detect { |type| instance_variable_defined?("@#{type}") }
|
|
|
|
type ||= :md5
|
|
|
|
supplied=instance_variable_get("@#{type}")
|
|
|
|
type=type.to_s.upcase
|
2010-03-23 19:56:20 -05:00
|
|
|
hasher = Digest.const_get(type)
|
2010-03-27 10:41:24 -05:00
|
|
|
hash = fn.incremental_hash(hasher)
|
2009-07-31 11:05:23 -07:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
if supplied and not supplied.empty?
|
2010-06-18 13:42:12 -07:00
|
|
|
message = <<-EOF
|
|
|
|
#{type} mismatch
|
|
|
|
Expected: #{supplied}
|
|
|
|
Got: #{hash}
|
|
|
|
Archive: #{fn}
|
|
|
|
(To retry an incomplete download, remove the file above.)
|
|
|
|
EOF
|
|
|
|
raise message unless supplied.upcase == hash.upcase
|
2009-07-31 11:05:23 -07:00
|
|
|
else
|
|
|
|
opoo "Cannot verify package integrity"
|
|
|
|
puts "The formula did not provide a download checksum"
|
2009-08-11 12:20:55 -07:00
|
|
|
puts "For your reference the #{type} is: #{hash}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def stage
|
|
|
|
HOMEBREW_CACHE.mkpath
|
2010-01-16 17:54:14 -08:00
|
|
|
|
|
|
|
downloaded_tarball = @downloader.fetch
|
|
|
|
if downloaded_tarball.kind_of? Pathname
|
|
|
|
verify_download_integrity downloaded_tarball
|
|
|
|
end
|
|
|
|
|
2009-08-11 12:20:55 -07:00
|
|
|
mktemp do
|
2010-01-16 17:54:14 -08:00
|
|
|
@downloader.stage
|
2009-08-11 12:20:55 -07:00
|
|
|
yield
|
2009-07-31 11:05:23 -07:00
|
|
|
end
|
|
|
|
end
|
2009-09-04 15:28:18 +01:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
def patch
|
2009-09-16 17:08:32 +01:00
|
|
|
return if patches.nil?
|
2009-09-15 20:07:40 +01:00
|
|
|
|
2009-09-09 11:59:46 -04:00
|
|
|
if not patches.kind_of? Hash
|
2009-11-13 14:27:21 -05:00
|
|
|
# We assume -p1
|
2009-09-16 17:08:32 +01:00
|
|
|
patch_defns = { :p1 => patches }
|
2009-09-09 11:59:46 -04:00
|
|
|
else
|
|
|
|
patch_defns = patches
|
|
|
|
end
|
|
|
|
|
|
|
|
patch_list=[]
|
|
|
|
n=0
|
|
|
|
patch_defns.each do |arg, urls|
|
2009-09-16 17:08:32 +01:00
|
|
|
# DATA.each does each line, which doesn't work so great
|
|
|
|
urls = [urls] unless urls.kind_of? Array
|
|
|
|
|
2009-09-09 11:59:46 -04:00
|
|
|
urls.each do |url|
|
2009-09-04 15:28:18 +01:00
|
|
|
p = {:filename => '%03d-homebrew.diff' % n+=1, :compression => false}
|
2009-09-15 20:07:40 +01:00
|
|
|
|
2009-09-04 15:28:18 +01:00
|
|
|
if defined? DATA and url == DATA
|
|
|
|
pn=Pathname.new p[:filename]
|
|
|
|
pn.write DATA.read
|
|
|
|
elsif url =~ %r[^\w+\://]
|
2009-09-15 20:07:40 +01:00
|
|
|
out_fn = p[:filename]
|
|
|
|
case url
|
|
|
|
when /\.gz$/
|
|
|
|
p[:compression] = :gzip
|
2009-09-04 15:28:18 +01:00
|
|
|
out_fn += '.gz'
|
2009-09-15 20:07:40 +01:00
|
|
|
when /\.bz2$/
|
|
|
|
p[:compression] = :bzip2
|
2009-09-04 15:28:18 +01:00
|
|
|
out_fn += '.bz2'
|
2009-09-15 20:07:40 +01:00
|
|
|
end
|
|
|
|
p[:curl_args] = [url, '-o', out_fn]
|
|
|
|
else
|
|
|
|
# it's a file on the local filesystem
|
|
|
|
p[:filename] = url
|
2009-08-11 18:16:12 +01:00
|
|
|
end
|
2009-09-15 20:07:40 +01:00
|
|
|
|
|
|
|
p[:args] = ["-#{arg}", '-i', p[:filename]]
|
|
|
|
|
|
|
|
patch_list << p
|
2009-08-11 18:16:12 +01:00
|
|
|
end
|
2009-09-09 11:59:46 -04:00
|
|
|
end
|
2009-09-04 15:28:18 +01:00
|
|
|
|
|
|
|
return if patch_list.empty?
|
2009-09-15 20:07:40 +01:00
|
|
|
|
2010-05-11 08:34:29 -07:00
|
|
|
ohai "Downloading patches"
|
2009-09-09 11:59:46 -04:00
|
|
|
# downloading all at once is much more efficient, espeically for FTP
|
2009-09-04 15:28:18 +01:00
|
|
|
curl *(patch_list.collect{|p| p[:curl_args]}.select{|p| p}.flatten)
|
2009-09-15 20:07:40 +01:00
|
|
|
|
2010-05-11 08:34:29 -07:00
|
|
|
ohai "Patching"
|
2009-09-09 11:59:46 -04:00
|
|
|
patch_list.each do |p|
|
|
|
|
case p[:compression]
|
2009-09-23 16:44:10 +01:00
|
|
|
when :gzip then safe_system "/usr/bin/gunzip", p[:filename]+'.gz'
|
|
|
|
when :bzip2 then safe_system "/usr/bin/bunzip2", p[:filename]+'.bz2'
|
2009-08-11 18:16:12 +01:00
|
|
|
end
|
2009-09-09 11:59:46 -04:00
|
|
|
# -f means it doesn't prompt the user if there are errors, if just
|
|
|
|
# exits with non-zero status
|
2009-09-23 16:44:10 +01:00
|
|
|
safe_system '/usr/bin/patch', '-f', *(p[:args])
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
end
|
2009-08-11 18:16:12 +01:00
|
|
|
|
2009-08-22 17:26:15 +01:00
|
|
|
def validate_variable name
|
2009-09-28 14:10:20 -07:00
|
|
|
v = instance_variable_get("@#{name}")
|
2009-08-30 16:11:44 +01:00
|
|
|
raise "Invalid @#{name}" if v.to_s.empty? or v =~ /\s/
|
2009-08-22 17:26:15 +01:00
|
|
|
end
|
2009-09-28 14:10:20 -07:00
|
|
|
|
2009-09-22 13:03:46 -04:00
|
|
|
def set_instance_variable(type)
|
2009-11-23 10:07:23 -08:00
|
|
|
unless instance_variable_defined? "@#{type}"
|
2009-09-22 13:03:46 -04:00
|
|
|
class_value = self.class.send(type)
|
|
|
|
instance_variable_set("@#{type}", class_value) if class_value
|
|
|
|
end
|
|
|
|
end
|
2009-08-22 17:26:15 +01:00
|
|
|
|
2009-07-31 14:17:56 +01:00
|
|
|
def method_added method
|
|
|
|
raise 'You cannot override Formula.brew' if method == 'brew'
|
|
|
|
end
|
2009-08-21 20:20:44 +01:00
|
|
|
|
2009-09-28 14:06:53 -07:00
|
|
|
class << self
|
|
|
|
|
2009-09-22 12:31:53 -04:00
|
|
|
def self.attr_rw(*attrs)
|
|
|
|
attrs.each do |attr|
|
|
|
|
class_eval %Q{
|
|
|
|
def #{attr}(val=nil)
|
|
|
|
val.nil? ? @#{attr} : @#{attr} = val
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2010-01-13 09:00:24 +00:00
|
|
|
attr_rw :url, :version, :homepage, :specs, :deps, :external_deps, :aliases, *CHECKSUM_TYPES
|
2009-10-17 14:35:24 +02:00
|
|
|
|
|
|
|
def head val=nil, specs=nil
|
|
|
|
if specs
|
|
|
|
@specs = specs
|
|
|
|
end
|
|
|
|
val.nil? ? @head : @head = val
|
|
|
|
end
|
2009-11-16 15:31:15 -08:00
|
|
|
|
|
|
|
def aka *args
|
|
|
|
@aliases ||= []
|
2009-11-23 10:07:23 -08:00
|
|
|
args.each { |item| @aliases << item.to_s }
|
2009-11-16 15:31:15 -08:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2010-01-13 09:00:24 +00:00
|
|
|
def depends_on name
|
2009-09-18 19:16:39 +01:00
|
|
|
@deps ||= []
|
2010-04-08 14:50:06 -07:00
|
|
|
@external_deps ||= {:python => [], :perl => [], :ruby => [], :jruby => []}
|
2009-09-18 19:16:39 +01:00
|
|
|
|
|
|
|
case name
|
|
|
|
when String
|
|
|
|
# noop
|
|
|
|
when Hash
|
2010-01-13 09:00:24 +00:00
|
|
|
key, value = name.shift
|
|
|
|
case value
|
2010-04-08 14:50:06 -07:00
|
|
|
when :python, :perl, :ruby, :jruby
|
2010-01-13 09:00:24 +00:00
|
|
|
@external_deps[value] << key
|
|
|
|
return
|
|
|
|
when :optional, :recommended
|
|
|
|
name = key
|
|
|
|
end
|
2009-09-18 19:16:39 +01:00
|
|
|
when Symbol
|
|
|
|
name = name.to_s
|
|
|
|
when Formula
|
2010-01-13 09:00:24 +00:00
|
|
|
# noop
|
2009-09-18 19:16:39 +01:00
|
|
|
else
|
|
|
|
raise "Unsupported type #{name.class}"
|
|
|
|
end
|
|
|
|
|
2010-01-13 09:00:24 +00:00
|
|
|
@deps << name
|
2009-09-18 19:16:39 +01:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
|
|
|
def skip_clean paths
|
|
|
|
@skip_clean_paths ||= []
|
|
|
|
[paths].flatten.each do |p|
|
|
|
|
@skip_clean_paths << p.to_s unless @skip_clean_paths.include? p.to_s
|
|
|
|
end
|
|
|
|
end
|
2009-09-29 23:51:37 +01:00
|
|
|
|
|
|
|
def skip_clean_paths
|
|
|
|
@skip_clean_paths or []
|
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# see ack.rb for an example usage
|
2009-08-21 20:20:44 +01:00
|
|
|
class ScriptFileFormula <Formula
|
2009-07-24 15:10:01 +01:00
|
|
|
def install
|
2009-08-11 12:20:55 -07:00
|
|
|
bin.install Dir['*']
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
# see flac.rb for example usage
|
2009-07-24 15:10:01 +01:00
|
|
|
class GithubGistFormula <ScriptFileFormula
|
2009-08-30 15:32:15 +01:00
|
|
|
def initialize name='__UNKNOWN__'
|
2009-08-21 20:20:44 +01:00
|
|
|
super name
|
2009-08-30 15:32:15 +01:00
|
|
|
@version=File.basename(File.dirname(url))[0,6]
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
end
|