From fb5aefd4a053d718637ea8690c6eeba2d6e56008 Mon Sep 17 00:00:00 2001
From: Max Howell
Date: Fri, 24 Jul 2009 15:10:01 +0100
Subject: Refactor--object orientate where sensible
---
Library/Homebrew/brewkit.rb | 371 +------------------------------------------
Library/Homebrew/env.rb | 95 ++++++++++-
Library/Homebrew/formula.rb | 263 ++++++++++++++++++++++++++++++
Library/Homebrew/keg.rb | 153 ++++++++++++++++++
Library/Homebrew/unittest.rb | 2 +-
5 files changed, 514 insertions(+), 370 deletions(-)
create mode 100644 Library/Homebrew/formula.rb
create mode 100644 Library/Homebrew/keg.rb
(limited to 'Library/Homebrew')
diff --git a/Library/Homebrew/brewkit.rb b/Library/Homebrew/brewkit.rb
index a32f015d5..f5d819f1b 100644
--- a/Library/Homebrew/brewkit.rb
+++ b/Library/Homebrew/brewkit.rb
@@ -15,9 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with Homebrew. If not, see .
-require 'pathname'
require 'osx/cocoa' # to get number of cores
-require 'env'
+require 'formula'
# optimise all the way to eleven, references:
# http://en.gentoo-wiki.com/wiki/Safe_Cflags/Intel
@@ -38,343 +37,7 @@ unless $root.to_s == '/usr/local'
end
-def ohai title
- n=`tput cols`.strip.to_i-4
- puts "\033[0;34m==>\033[0;0;1m #{title[0,n]}\033[0;0m"
-end
-
-def cache
- cache=File.expand_path "~/Library/Caches/Homebrew"
- FileUtils.mkpath cache
- return cache
-end
-
-class BuildError 1
- `strip #{args} #{path}`
- else
- # strip unlinks the file and recreates it, thus breaking hard links!
- # is this expected behaviour? patch does it too… still,mktm this fixes it
- tmp=`mktemp -t #{path.basename}`.strip
- `strip -o #{tmp} #{path}`
- `cat #{tmp} > #{path}`
- File.unlink tmp
- end
- end
- path.chmod perms
- end
- end}
-
- # remove empty directories
- `perl -MFile::Find -e"finddepth(sub{rmdir},'#{prefix}')"`
- end
-
-protected
- def uncompress path
- path.dirname
- end
-
-private
- def fetch
- %r[http://(www.)?github.com/.*/(zip|tar)ball/].match @url
- if $2
- # curl doesn't do the redirect magic that we would like, so we get a
- # stupidly named file, this is why wget would be beter, but oh well
- tgz="#{@name}-#{@version}.#{$2=='tar' ? 'tgz' : $2}"
- oarg="-o #{tgz}"
- else
- oarg='-O' #use the filename that curl gets
- tgz=File.expand_path File.basename(@url)
- end
-
- agent="Homebrew #{HOMEBREW_VERSION} (Ruby #{VERSION}; Mac OS X 10.5 Leopard)"
-
- unless File.exists? tgz
- `curl -#LA "#{agent}" #{oarg} "#{@url}"`
- raise "Download failed" unless $? == 0
- else
- puts "File already downloaded and cached"
- end
- return tgz
- end
-
- def method_added method
- raise 'You cannot override Formula.brew' if method == 'brew'
- end
-end
-
-# somewhat useful, it'll raise if you call prefix, but it'll unpack a tar/zip
-# for you, check the md5, and allow you to yield from brew
-class UnidentifiedFormula &1") do |f|
- until f.eof?
- s=f.gets
- if ARGV.include? '--verbose'
- puts s
- else
- out+=s
- end
- end
- end
-
- unless $? == 0
- puts out unless ARGV.include? '--verbose' #already did that above
- raise BuildError.new(cmd)
- end
-end
-
-####################################################################### script
-if $0 == __FILE__
- d=$cellar.parent+'bin'
- d.mkpath unless d.exist?
- Dir.chdir d
- Pathname.new('brew').make_symlink Pathname.new('../Cellar')+'homebrew'+'brew'
-end
\ No newline at end of file
diff --git a/Library/Homebrew/env.rb b/Library/Homebrew/env.rb
index 951d9f9dc..dbba19e8a 100644
--- a/Library/Homebrew/env.rb
+++ b/Library/Homebrew/env.rb
@@ -21,4 +21,97 @@ $root=Pathname.new(__FILE__).dirname.parent.parent.realpath
$formula=$root+'Library'+'Formula'
$cellar=$root+'Cellar'
-HOMEBREW_VERSION='0.2'
\ No newline at end of file
+HOMEBREW_VERSION='0.3'
+HOMEBREW_CACHE=File.expand_path "~/Library/Caches/Homebrew"
+
+
+######################################################################## utils
+def ohai title
+ n=`tput cols`.strip.to_i-4
+ puts "\033[0;34m==>\033[0;0;1m #{title[0,n]}\033[0;0m"
+end
+
+
+############################################################### class Pathname
+# we enhance Pathname to make our code more legible
+# of course this kind of thing is evil, but meh
+class Pathname
+ def mv dst
+ FileUtils.mv to_s, dst
+ end
+
+ def rename dst
+ dst=Pathname.new dst
+ dst.unlink if dst.exist?
+ mv dst
+ end
+
+ def install src
+ if src.is_a? Array
+ src.each {|src| install src }
+ elsif File.exist? src
+ mkpath
+ if File.symlink? src
+ # we use the BSD mv command because FileUtils copies the target and
+ # not the link! I'm beginning to wish I'd used Python quite honestly!
+ `mv #{src} #{to_s}`
+ else
+ # we mv when possible as it is faster and you should only be using
+ # this function when installing from the temporary build directory
+ FileUtils.mv src, to_s
+ end
+ end
+ end
+
+ def cp dst
+ if file?
+ FileUtils.cp to_s, dst
+ else
+ FileUtils.cp_r to_s, dst
+ end
+ end
+
+ # extended to support the double extensions .tar.gz and .tar.bz2
+ def extname
+ /(\.tar\.(gz|bz2))$/.match to_s
+ return $1 if $1
+ return File.extname(to_s)
+ end
+
+ # for filetypes we support, basename without extension
+ def stem
+ return File.basename(to_s, extname)
+ end
+
+ def version
+ # eg. boost_1_39_0
+ /((\d+_)+\d+)$/.match stem
+ return $1.gsub('_', '.') if $1
+
+ # eg. foobar-4.5.1-1
+ /-((\d+\.)*\d+-\d+)$/.match stem
+ return $1 if $1
+
+ # eg. foobar-4.5.1
+ /-((\d+\.)*\d+)$/.match stem
+ return $1 if $1
+
+ # eg. foobar-4.5.1b
+ /-((\d+\.)*\d+([abc]|rc\d))$/.match stem
+ return $1 if $1
+
+ # eg foobar-4.5.0-beta1
+ /-((\d+\.)*\d+-beta\d+)$/.match stem
+ return $1 if $1
+
+ # eg. foobar4.5.1
+ /((\d+\.)*\d+)$/.match stem
+ return $1 if $1
+
+ # eg. otp_src_R13B (this is erlang's style)
+ # eg. astyle_1.23_macosx.tar.gz
+ stem.scan /_([^_]+)/ do |match|
+ return match.first if /\d/.match $1
+ end
+ end
+end
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
new file mode 100644
index 000000000..443ab1de1
--- /dev/null
+++ b/Library/Homebrew/formula.rb
@@ -0,0 +1,263 @@
+# Copyright 2009 Max Howell
+#
+# This file is part of Homebrew.
+#
+# Homebrew is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Homebrew is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Homebrew. If not, see .
+
+require 'env'
+
+class BuildError 0
+ rescue
+ return false
+ end
+
+ def initialize name=nil
+ @name=name
+ # fuck knows, ruby is weird
+ @url=url if @url.nil?
+ raise "@url.nil?" if @url.nil?
+ @md5=md5 if @md5.nil?
+ # end ruby is weird section
+ end
+
+public
+ def prefix
+ raise "@name.nil!" if @name.nil?
+ raise "@version.nil?" if @version.nil?
+ $cellar+@name+@version
+ end
+ def bin
+ prefix+'bin'
+ end
+ def doc
+ prefix+'share'+'doc'+name
+ end
+ def man
+ prefix+'share'+'man'
+ end
+ def man1
+ man+'man1'
+ end
+ def lib
+ prefix+'lib'
+ end
+ def include
+ prefix+'include'
+ end
+
+ def caveats
+ nil
+ end
+
+ # Pretty titles the command and buffers stdout/stderr
+ # Throws if there's an error
+ def system cmd
+ ohai cmd
+ if ARGV.include? '--verbose'
+ Kernel.system cmd
+ else
+ out=''
+ IO.popen "#{cmd} 2>&1" do |f|
+ until f.eof?
+ out+=f.gets
+ end
+ end
+ puts out unless $? == 0
+ end
+
+ raise BuildError.new(cmd) unless $? == 0
+ end
+
+ # yields self with current working directory set to the uncompressed tarball
+ def brew
+ ohai "Downloading #{@url}"
+ FileUtils.mkpath HOMEBREW_CACHE
+ Dir.chdir HOMEBREW_CACHE do
+ tmp=tgz=nil
+ begin
+ tgz=Pathname.new(fetch()).realpath
+ md5=`md5 -q "#{tgz}"`.strip
+ raise "MD5 mismatch: #{md5}" unless @md5 and md5 == @md5.downcase
+
+ # we make an additional subdirectory so know exactly what we are
+ # recursively deleting later
+ # we use mktemp rather than appsupport/blah because some build scripts
+ # can't handle being built in a directory with spaces in it :P
+ tmp=`mktemp -dt #{File.basename @url}`.strip
+ Dir.chdir tmp do
+ Dir.chdir uncompress(tgz) do
+ yield self
+ end
+ end
+ rescue Interrupt, RuntimeError
+ if ARGV.include? '--debug'
+ # debug mode allows the packager to intercept a failed build and
+ # investigate the problems
+ puts "Rescued build at: #{tmp}"
+ exit! 1
+ else
+ raise
+ end
+ ensure
+ FileUtils.rm_rf tmp if tmp
+ end
+ end
+ end
+
+protected
+ # returns the directory where the archive was uncompressed
+ # in this Abstract case we assume there is no archive
+ def uncompress path
+ path.dirname
+ end
+
+private
+ def fetch
+ %r[http://(www.)?github.com/.*/(zip|tar)ball/].match @url
+ if $2
+ # curl doesn't do the redirect magic that we would like, so we get a
+ # stupidly named file, this is why wget would be beter, but oh well
+ tgz="#{@name}-#{@version}.#{$2=='tar' ? 'tgz' : $2}"
+ oarg="-o #{tgz}"
+ else
+ oarg='-O' #use the filename that curl gets
+ tgz=File.expand_path File.basename(@url)
+ end
+
+ agent="Homebrew #{HOMEBREW_VERSION} (Ruby #{VERSION}; Mac OS X 10.5 Leopard)"
+
+ unless File.exists? tgz
+ `curl -#LA "#{agent}" #{oarg} "#{@url}"`
+ raise "Download failed" unless $? == 0
+ else
+ puts "File already downloaded and cached"
+ end
+ return tgz
+ end
+
+ def method_added method
+ raise 'You cannot override Formula.brew' if method == 'brew'
+ end
+end
+
+# somewhat useful, it'll raise if you call prefix, but it'll unpack a tar/zip
+# for you, check the md5, and allow you to yield from brew
+class UnidentifiedFormula
+#
+# This file is part of Homebrew.
+#
+# Homebrew is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Homebrew is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Homebrew. If not, see .
+
+require 'env'
+require 'formula'
+
+class Keg
+ attr_reader :path, :version, :name
+
+ def initialize formula
+ if formula.is_a? AbstractFormula
+ @path=formula.prefix
+ @name=formula.name
+ @version=formula.version
+ elsif formula.is_a? Pathname
+ # TODO
+ elsif formula.is_a? String
+ kids=($cellar+formula).children
+ raise "Multiple versions installed" if kids.length > 1
+ @path=kids[0]
+ @name=formula
+ @version=@path.basename
+ end
+ end
+
+ def clean
+ # TODO unset write permission more
+ %w[bin lib].each {|d| (Pathname.new(path)+d).find do |path|
+ if not path.file?
+ next
+ elsif path.extname == '.la'
+ # .la files are stupid
+ path.unlink
+ else
+ fo=`file -h #{path}`
+ args=nil
+ perms=0444
+ if fo =~ /Mach-O dynamically linked shared library/
+ args='-SxX'
+ elsif fo =~ /Mach-O executable/ # defaults strip everything
+ args='' # still do the strip
+ perms=0544
+ elsif fo =~ /script text executable/
+ perms=0544
+ end
+ if args
+ puts "Stripping: #{path}" if ARGV.include? '--verbose'
+ path.chmod 0644 # so we can strip
+ unless path.stat.nlink > 1
+ `strip #{args} #{path}`
+ else
+ # strip unlinks the file and recreates it, thus breaking hard links!
+ # is this expected behaviour? patch does it too… still,mktm this fixes it
+ tmp=`mktemp -t #{path.basename}`.strip
+ `strip -o #{tmp} #{path}`
+ `cat #{tmp} > #{path}`
+ File.unlink tmp
+ end
+ end
+ path.chmod perms
+ end
+ end}
+
+ # remove empty directories TODO Rubyize!
+ `perl -MFile::Find -e"finddepth(sub{rmdir},'#{path}')"`
+ end
+
+ def rm
+ if path.directory?
+ FileUtils.chmod_R 0777, path # ensure we have permission to delete
+ path.rmtree
+ end
+ end
+
+private
+ def __symlink_relative_to from, to
+ tod=to.dirname
+ tod.mkpath
+ Dir.chdir(tod) do
+ #TODO use Ruby function so we get exceptions
+ #NOTE Ruby functions are fucked up!
+ `ln -sf "#{from.relative_path_from tod}"`
+ @n+=1
+ end
+ end
+
+ # symlinks a directory recursively into our FHS tree
+ def __ln start
+ start=path+start
+ return unless start.directory?
+
+ start.find do |from|
+ next if from == start
+
+ prune=false
+
+ relative_path=from.relative_path_from path
+ to=$root+relative_path
+
+ if from.file?
+ __symlink_relative_to from, to
+ elsif from.directory?
+ # no need to put .app bundles in the path, the user can just use
+ # spotlight, or the open command and actual mac apps use an equivalent
+ Find.prune if from.extname.to_s == '.app'
+
+ branch=from.relative_path_from start
+
+ case yield branch when :skip
+ Find.prune
+ when :mkpath
+ to.mkpath
+ @n+=1
+ else
+ __symlink_relative_to from, to
+ Find.prune
+ end
+ end
+ end
+ end
+
+public
+ def ln
+ # yeah indeed, you have to force anything you need in the main tree into
+ # these dirs REMEMBER that *NOT* everything needs to be in the main tree
+ # TODO consider using hardlinks
+ @n=0
+
+ __ln('etc') {:mkpath}
+ __ln('bin') {:link}
+ __ln('lib') {|path| :mkpath if ['pkgconfig','php'].include? path.to_s}
+ __ln('include') {:link}
+
+ mkpaths=(1..9).collect {|x| "man/man#{x}"} <<'man'<<'doc'<<'locale'<<'info'<<'aclocal'
+ __ln('share') {|path| :mkpath if mkpaths.include? path.to_s}
+
+ return @n
+ end
+end
\ No newline at end of file
diff --git a/Library/Homebrew/unittest.rb b/Library/Homebrew/unittest.rb
index 84f0d3f81..7b15b2949 100755
--- a/Library/Homebrew/unittest.rb
+++ b/Library/Homebrew/unittest.rb
@@ -2,7 +2,7 @@
$:.unshift File.dirname(__FILE__)
require 'test/unit'
-require 'brewkit'
+require 'formula'
require 'stringio'
class TestFormula