Refactor--object orientate where sensible
This commit is contained in:
parent
5eb9d6519d
commit
fb5aefd4a0
@ -15,9 +15,8 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Homebrew. If not, see <http://www.gnu.org/licenses/>.
|
# along with Homebrew. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
require 'pathname'
|
|
||||||
require 'osx/cocoa' # to get number of cores
|
require 'osx/cocoa' # to get number of cores
|
||||||
require 'env'
|
require 'formula'
|
||||||
|
|
||||||
# optimise all the way to eleven, references:
|
# optimise all the way to eleven, references:
|
||||||
# http://en.gentoo-wiki.com/wiki/Safe_Cflags/Intel
|
# http://en.gentoo-wiki.com/wiki/Safe_Cflags/Intel
|
||||||
@ -38,343 +37,7 @@ unless $root.to_s == '/usr/local'
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def ohai title
|
######################################################################## utils
|
||||||
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 <RuntimeError
|
|
||||||
def initialize cmd
|
|
||||||
super "Build failed during: #{cmd}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# pass in the basename of the filename _without_ any file extension
|
|
||||||
def extract_version basename
|
|
||||||
# eg. boost_1_39_0
|
|
||||||
/((\d+_)+\d+)$/.match basename
|
|
||||||
return $1.gsub('_', '.') if $1
|
|
||||||
|
|
||||||
# eg. foobar-4.5.1-1
|
|
||||||
/-((\d+\.)*\d+-\d+)$/.match basename
|
|
||||||
return $1 if $1
|
|
||||||
|
|
||||||
# eg. foobar-4.5.1
|
|
||||||
/-((\d+\.)*\d+)$/.match basename
|
|
||||||
return $1 if $1
|
|
||||||
|
|
||||||
# eg. foobar-4.5.1b
|
|
||||||
/-((\d+\.)*\d+([abc]|rc\d))$/.match basename
|
|
||||||
return $1 if $1
|
|
||||||
|
|
||||||
# eg foobar-4.5.0-beta1
|
|
||||||
/-((\d+\.)*\d+-beta\d+)$/.match basename
|
|
||||||
return $1 if $1
|
|
||||||
|
|
||||||
# eg. foobar4.5.1
|
|
||||||
/((\d+\.)*\d+)$/.match basename
|
|
||||||
return $1 if $1
|
|
||||||
|
|
||||||
# eg. otp_src_R13B (this is erlang's style)
|
|
||||||
# eg. astyle_1.23_macosx.tar.gz
|
|
||||||
basename.scan /_([^_]+)/ do |match|
|
|
||||||
return match.first if /\d/.match $1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# make our code neater
|
|
||||||
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 cp symlinks because FileUtils.mv is shit and won't mv a symlink
|
|
||||||
# if its final destination has an invalid target! FFS. Ruby is shit.
|
|
||||||
FileUtils.cp 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
|
|
||||||
|
|
||||||
# for filetypes we support
|
|
||||||
def extname
|
|
||||||
/\.(zip|tar\.(gz|bz2)|tgz)$/.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
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# the base class variety of formula, you don't get a prefix, so it's not really
|
|
||||||
# useful. See the derived classes for fun and games.
|
|
||||||
class AbstractFormula
|
|
||||||
require 'find'
|
|
||||||
require 'fileutils'
|
|
||||||
|
|
||||||
# fuck knows, ruby is weird
|
|
||||||
# TODO please fix!
|
|
||||||
def self.url
|
|
||||||
@url
|
|
||||||
end
|
|
||||||
def url
|
|
||||||
self.class.url
|
|
||||||
end
|
|
||||||
def self.md5
|
|
||||||
@md5
|
|
||||||
end
|
|
||||||
def md5
|
|
||||||
self.class.md5
|
|
||||||
end
|
|
||||||
def self.homepage
|
|
||||||
@homepage
|
|
||||||
end
|
|
||||||
def homepage
|
|
||||||
self.class.homepage
|
|
||||||
end
|
|
||||||
# end ruby is weird section
|
|
||||||
|
|
||||||
def version
|
|
||||||
@version
|
|
||||||
end
|
|
||||||
def name
|
|
||||||
@name
|
|
||||||
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
|
|
||||||
prefix+'share'+'man'+'man1'
|
|
||||||
end
|
|
||||||
def lib
|
|
||||||
prefix+'lib'
|
|
||||||
end
|
|
||||||
def include
|
|
||||||
prefix+'include'
|
|
||||||
end
|
|
||||||
|
|
||||||
def caveats
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# yields self with current working directory set to the uncompressed tarball
|
|
||||||
def brew
|
|
||||||
ohai "Downloading #{@url}"
|
|
||||||
Dir.chdir 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
|
|
||||||
|
|
||||||
def clean
|
|
||||||
#TODO strip libexec too
|
|
||||||
[bin,lib].each {|path| path.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
|
|
||||||
`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 <AbstractFormula
|
|
||||||
def initialize name=nil
|
|
||||||
super name
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def uncompress(path)
|
|
||||||
if path.extname == '.zip'
|
|
||||||
`unzip -qq "#{path}"`
|
|
||||||
else
|
|
||||||
`tar xf "#{path}"`
|
|
||||||
end
|
|
||||||
|
|
||||||
raise "Compression tool failed" if $? != 0
|
|
||||||
|
|
||||||
entries=Dir['*']
|
|
||||||
if entries.nil? or entries.length == 0
|
|
||||||
raise "Empty tarball!"
|
|
||||||
elsif entries.length == 1
|
|
||||||
# if one dir enter it as that will be where the build is
|
|
||||||
entries.first
|
|
||||||
else
|
|
||||||
# if there's more than one dir, then this is the build directory already
|
|
||||||
Dir.pwd
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# this is what you will mostly use, reimplement install, prefix won't raise
|
|
||||||
class Formula <UnidentifiedFormula
|
|
||||||
def initialize name
|
|
||||||
super name
|
|
||||||
@version=extract_version Pathname.new(File.basename(@url)).stem unless @version
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# see ack.rb for an example usage
|
|
||||||
class ScriptFileFormula <AbstractFormula
|
|
||||||
def install
|
|
||||||
bin.install name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class GithubGistFormula <ScriptFileFormula
|
|
||||||
def initialize
|
|
||||||
super File.basename(url)
|
|
||||||
@version=File.basename(File.dirname(url))[0,6]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def inreplace(path, before, after)
|
def inreplace(path, before, after)
|
||||||
before=before.to_s.gsub('"', '\"').gsub('/', '\/')
|
before=before.to_s.gsub('"', '\"').gsub('/', '\/')
|
||||||
@ -385,34 +48,6 @@ def inreplace(path, before, after)
|
|||||||
#TODO optimise it by taking before and after as arrays
|
#TODO optimise it by taking before and after as arrays
|
||||||
#Bah, just make the script writers do it themselves with a standard collect block
|
#Bah, just make the script writers do it themselves with a standard collect block
|
||||||
#TODO use ed -- less to escape
|
#TODO use ed -- less to escape
|
||||||
|
#TODO the above doesn't escape all regexp symbols!
|
||||||
`perl -pi -e "s/#{before}/#{after}/g" "#{path}"`
|
`perl -pi -e "s/#{before}/#{after}/g" "#{path}"`
|
||||||
end
|
end
|
||||||
|
|
||||||
def system cmd
|
|
||||||
ohai cmd
|
|
||||||
|
|
||||||
out=''
|
|
||||||
IO.popen("#{cmd} 2>&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
|
|
@ -21,4 +21,97 @@ $root=Pathname.new(__FILE__).dirname.parent.parent.realpath
|
|||||||
$formula=$root+'Library'+'Formula'
|
$formula=$root+'Library'+'Formula'
|
||||||
$cellar=$root+'Cellar'
|
$cellar=$root+'Cellar'
|
||||||
|
|
||||||
HOMEBREW_VERSION='0.2'
|
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
|
||||||
|
263
Library/Homebrew/formula.rb
Normal file
263
Library/Homebrew/formula.rb
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
# Copyright 2009 Max Howell <max@methylblue.com>
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
require 'env'
|
||||||
|
|
||||||
|
class BuildError <RuntimeError
|
||||||
|
def initialize cmd
|
||||||
|
super "Build failed during: #{cmd}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# the base class variety of formula, you don't get a prefix, so it's not really
|
||||||
|
# useful. See the derived classes for fun and games.
|
||||||
|
class AbstractFormula
|
||||||
|
require 'find'
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
# fuck knows, ruby is weird
|
||||||
|
# TODO please fix!
|
||||||
|
def self.url
|
||||||
|
@url
|
||||||
|
end
|
||||||
|
def url
|
||||||
|
self.class.url
|
||||||
|
end
|
||||||
|
def self.md5
|
||||||
|
@md5
|
||||||
|
end
|
||||||
|
def md5
|
||||||
|
self.class.md5
|
||||||
|
end
|
||||||
|
def self.homepage
|
||||||
|
@homepage
|
||||||
|
end
|
||||||
|
def homepage
|
||||||
|
self.class.homepage
|
||||||
|
end
|
||||||
|
# end ruby is weird section
|
||||||
|
|
||||||
|
def version
|
||||||
|
@version
|
||||||
|
end
|
||||||
|
def name
|
||||||
|
@name
|
||||||
|
end
|
||||||
|
|
||||||
|
# if the dir is there, but it's empty we consider it not installed
|
||||||
|
def installed?
|
||||||
|
return prefix.children.count > 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 <AbstractFormula
|
||||||
|
def initialize name=nil
|
||||||
|
super name
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def uncompress(path)
|
||||||
|
if path.extname == '.zip'
|
||||||
|
`unzip -qq "#{path}"`
|
||||||
|
else
|
||||||
|
`tar xf "#{path}"`
|
||||||
|
end
|
||||||
|
|
||||||
|
raise "Compression tool failed" if $? != 0
|
||||||
|
|
||||||
|
entries=Dir['*']
|
||||||
|
if entries.nil? or entries.length == 0
|
||||||
|
raise "Empty tarball!"
|
||||||
|
elsif entries.length == 1
|
||||||
|
# if one dir enter it as that will be where the build is
|
||||||
|
entries.first
|
||||||
|
else
|
||||||
|
# if there's more than one dir, then this is the build directory already
|
||||||
|
Dir.pwd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# this is what you will mostly use, reimplement install, prefix won't raise
|
||||||
|
class Formula <UnidentifiedFormula
|
||||||
|
def initialize name
|
||||||
|
super name
|
||||||
|
@version=Pathname.new(@url).version unless @version
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.class name
|
||||||
|
#remove invalid characters and camelcase
|
||||||
|
name.capitalize.gsub(/[-_\s]([a-zA-Z0-9])/) { $1.upcase }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.path name
|
||||||
|
$formula+(name.downcase+'.rb')
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create name
|
||||||
|
require Formula.path(name)
|
||||||
|
return eval(Formula.class(name)).new(name)
|
||||||
|
rescue
|
||||||
|
raise "No formula for #{name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# see ack.rb for an example usage
|
||||||
|
class ScriptFileFormula <AbstractFormula
|
||||||
|
def install
|
||||||
|
bin.install name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class GithubGistFormula <ScriptFileFormula
|
||||||
|
def initialize
|
||||||
|
super File.basename(url)
|
||||||
|
@version=File.basename(File.dirname(url))[0,6]
|
||||||
|
end
|
||||||
|
end
|
153
Library/Homebrew/keg.rb
Normal file
153
Library/Homebrew/keg.rb
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# Copyright 2009 Max Howell <max@methylblue.com>
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
$:.unshift File.dirname(__FILE__)
|
$:.unshift File.dirname(__FILE__)
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
require 'brewkit'
|
require 'formula'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
|
||||||
class TestFormula <Formula
|
class TestFormula <Formula
|
||||||
|
33
README
33
README
@ -1,7 +1,7 @@
|
|||||||
Homebrew
|
Homebrew
|
||||||
========
|
========
|
||||||
Homebrew's purpose is the same as MacPorts or Fink, ie. to let you easily
|
Homebrew's purpose is basically the same as MacPorts or Fink, ie. to let you
|
||||||
install other open source software on your Mac.
|
easily install other open source software on your Mac.
|
||||||
|
|
||||||
Here's why you may prefer Homebrew to the alternatives:
|
Here's why you may prefer Homebrew to the alternatives:
|
||||||
|
|
||||||
@ -34,30 +34,43 @@ Here's why you may prefer Homebrew to the alternatives:
|
|||||||
Homebrew will automatically open it for you to tweak with TextMate or
|
Homebrew will automatically open it for you to tweak with TextMate or
|
||||||
$EDITOR.
|
$EDITOR.
|
||||||
|
|
||||||
Or skip going via a package entirely, just install into the Cellar and use
|
6. DIY package installation
|
||||||
"brew ln" to symlink it into the main tree.
|
MacPorts doesn't support the beta version? Need an older version? Need
|
||||||
|
custom compile flags? The Homebrew toolchain is carefully segregated so
|
||||||
|
you can just build your own stuff while still reaping the benefits of
|
||||||
|
package management.
|
||||||
|
|
||||||
6. Optimisation
|
Just install to the Cellar and then call brew ln to symlink that
|
||||||
|
installation into /usr/local, eg.
|
||||||
|
|
||||||
|
./configure --prefix=/usr/local/Cellar/wget/1.10
|
||||||
|
make install
|
||||||
|
brew ln wget
|
||||||
|
|
||||||
|
This means you can also install multiple versions of the same package and
|
||||||
|
switch on demand.
|
||||||
|
|
||||||
|
7. Optimisation
|
||||||
We optimise for Leopard Intel, binaries are stripped, compile flags
|
We optimise for Leopard Intel, binaries are stripped, compile flags
|
||||||
tweaked. Nobody wants crappy, slow software. Apart from MacPorts and Fink.
|
tweaked. Nobody wants crappy, slow software. Apart from MacPorts and Fink.
|
||||||
|
|
||||||
7. Integration with existing OS X technologies
|
8. Integration with existing OS X technologies
|
||||||
Homebrew integrates with Ruby gems, CPAN and Python disttools. These tools
|
Homebrew integrates with Ruby gems, CPAN and Python disttools. These tools
|
||||||
exist already and do the job great. We don't reinvent the wheel, we just
|
exist already and do the job great. We don't reinvent the wheel, we just
|
||||||
improve it by making these tools install with more management options.
|
improve it by making these tools install with more management options.
|
||||||
|
|
||||||
8. Complimenting what OS X already has
|
9. Complimenting what OS X already has
|
||||||
Macports is an autarky. You get a duplicate copy of libz, OpenSSL, Python
|
Macports is an autarky. You get a duplicate copy of libz, OpenSSL, Python
|
||||||
etc. They do this to support OS X Tiger, etc. more easily. We don't support
|
etc. They do this to support OS X Tiger, etc. more easily. We don't support
|
||||||
Tiger, we duplicate nothing. Homebrew compliments OS X, it doesn't seek to
|
Tiger, we duplicate nothing. Homebrew compliments OS X, it doesn't seek to
|
||||||
operate independently of it.
|
operate independently of it.
|
||||||
|
|
||||||
9. Homebrew has a beer theme
|
A. Homebrew has a beer theme
|
||||||
Beer goggles will help you to evangelise Homebrew more effectively.
|
Beer goggles will help you to evangelise Homebrew more effectively.
|
||||||
|
|
||||||
X. Homebrew helps you get chicks
|
B. Homebrew helps get you chicks
|
||||||
There's no conclusive scientific evidence as yet, but I firmly believe it's
|
There's no conclusive scientific evidence as yet, but I firmly believe it's
|
||||||
just a matter of statistics and time.
|
just a matter of time and statistics.
|
||||||
|
|
||||||
I know I've made it sound so awesome you can hardly wait to rip MacPorts out
|
I know I've made it sound so awesome you can hardly wait to rip MacPorts out
|
||||||
and embrace the fresh hoppy taste of Homebrew, but I should point out that it
|
and embrace the fresh hoppy taste of Homebrew, but I should point out that it
|
||||||
|
374
bin/brew
374
bin/brew
@ -8,6 +8,7 @@ require 'env'
|
|||||||
# often causes Ruby to throw exception ffs
|
# often causes Ruby to throw exception ffs
|
||||||
Dir.chdir '/' unless File.directory? ENV['PWD']
|
Dir.chdir '/' unless File.directory? ENV['PWD']
|
||||||
|
|
||||||
|
######################################################################## funcs
|
||||||
def prune
|
def prune
|
||||||
n=0
|
n=0
|
||||||
dirs=Array.new
|
dirs=Array.new
|
||||||
@ -37,130 +38,113 @@ def prune
|
|||||||
return n
|
return n
|
||||||
end
|
end
|
||||||
|
|
||||||
def formulize name
|
# we actually remove formulae from ARGV so that any other analysis of ARGV
|
||||||
name=Pathname.new name
|
# only includes relevent arguments
|
||||||
return name if name.directory? and name.parent.realpath == $cellar
|
# TODO require will throw if no formula, so we should catch no?
|
||||||
return File.basename(name, '.rb') if name.file? and name.extname == '.rb' and name.parent.realpath == $formula
|
def extract_named_args
|
||||||
|
args=Array.new
|
||||||
name=name.to_s
|
ARGV.delete_if do |arg|
|
||||||
raise "#{name} is an invalid name for a formula" if name.include? '/'
|
if arg[0,1] == '-'
|
||||||
|
false
|
||||||
return name if ($formula+(name+'.rb')).file?
|
|
||||||
return name if ($cellar+name).directory?
|
|
||||||
|
|
||||||
raise "No formula or keg for #{name} found"
|
|
||||||
end
|
|
||||||
|
|
||||||
def shift_formulae_from_ARGV
|
|
||||||
fae=Array.new
|
|
||||||
i=0
|
|
||||||
while name=ARGV[i]
|
|
||||||
unless name[0,1] == '-'
|
|
||||||
fae<<formulize(ARGV.shift).to_s
|
|
||||||
else
|
else
|
||||||
i+=1
|
args<<arg
|
||||||
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
raise "You must specify a formula" if fae.empty?
|
return args
|
||||||
return fae
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def __class name
|
def extract_kegs
|
||||||
#remove invalid characters and camelcase
|
require 'keg'
|
||||||
name.capitalize.gsub(/[-_\s]([a-zA-Z0-9])/) { $1.upcase }
|
kegs=extract_named_args.collect {|name| Keg.new name}
|
||||||
|
raise "Expecting the name of a keg or formula, eg:\n\tbrew #{ARGV.join ' '} wget" if kegs.empty?
|
||||||
|
return kegs
|
||||||
end
|
end
|
||||||
|
|
||||||
def __rb name
|
def abv keg=nil
|
||||||
$formula+(name+'.rb')
|
path=keg ? keg.path : $cellar
|
||||||
end
|
if path.directory?
|
||||||
|
`find #{path} -type f | wc -l`.strip+' files, '+`du -hd0 #{path} | cut -d"\t" -f1`.strip
|
||||||
def __obj name
|
else
|
||||||
require "#{__rb name}"
|
nil
|
||||||
return eval(__class(name)).new(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def rm keg
|
|
||||||
#TODO if multiple versions don't rm all unless --force
|
|
||||||
path=$cellar+keg
|
|
||||||
`chmod -R u+rw #{path}` # we leave things read only
|
|
||||||
path.rmtree
|
|
||||||
puts "#{path} removed (#{prune} files)"
|
|
||||||
end
|
|
||||||
|
|
||||||
def ln name
|
|
||||||
keg=$cellar+name
|
|
||||||
keg=keg.realpath
|
|
||||||
|
|
||||||
if keg.parent.parent == $root
|
|
||||||
# we are one dir too high
|
|
||||||
kids=keg.children
|
|
||||||
raise "#{keg} is empty :(" if kids.length == 0
|
|
||||||
raise "There are multiple versions of #{keg.basename} installed please specify one" if kids.length > 1
|
|
||||||
keg=keg.children.first
|
|
||||||
raise "#{keg} is not a directory" unless keg.directory?
|
|
||||||
elsif keg.parent.parent.parent != $root
|
|
||||||
raise '#{keg} is not a keg'
|
|
||||||
end
|
|
||||||
|
|
||||||
# yeah indeed, you have to force anything you need in the main tree into
|
|
||||||
# these directories :P
|
|
||||||
# NOTE that not everything needs to be in the main tree
|
|
||||||
# TODO consider using hardlinks
|
|
||||||
$n=0
|
|
||||||
lnd(keg, 'etc') {:mkdir}
|
|
||||||
lnd(keg, 'include') {:link}
|
|
||||||
lnd(keg, 'bin') {:link}
|
|
||||||
lnd(keg, 'lib') {|path| :mkpath if ['pkgconfig','php'].include? path.to_s}
|
|
||||||
lnd(keg, 'share') do |path|
|
|
||||||
mkpaths=(1..9).collect {|x| "man/man#{x}"} <<'man'<<'doc'<<'locale'<<'info'<<'aclocal'
|
|
||||||
:mkpath if mkpaths.include? path.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
return $n
|
|
||||||
end
|
|
||||||
|
|
||||||
def symlink_relative_to from, to
|
|
||||||
tod=to.dirname
|
|
||||||
tod.mkpath
|
|
||||||
Dir.chdir(tod) do
|
|
||||||
#TODO use ruby function so we get exceptions
|
|
||||||
`ln -sf "#{from.relative_path_from tod}"`
|
|
||||||
$n+=1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# symlinks a directory recursively into our FHS tree
|
def install formula
|
||||||
def lnd keg, start
|
require 'keg'
|
||||||
start=keg+start
|
|
||||||
return unless start.directory?
|
|
||||||
|
|
||||||
start.find do |from|
|
raise "#{formula.name} already installed!\n\t#{formula.prefix}" if formula.installed?
|
||||||
next if from == start
|
|
||||||
|
beginning = Time.now
|
||||||
|
|
||||||
prune=false
|
formula.brew do
|
||||||
relative_path=from.relative_path_from keg
|
if ARGV.include? '--interactive'
|
||||||
to=$root+relative_path
|
ohai "Entering interactive mode"
|
||||||
|
puts "Type `exit' to return and finalize the installation"
|
||||||
if from.directory?
|
puts "Install to this prefix: #{formula.prefix}"
|
||||||
# no need to put .app bundles in the path, the user can just use
|
pid=fork
|
||||||
# spotlight, or the open command and actual mac apps use an equivalent
|
if pid.nil?
|
||||||
Find.prune if from.extname.to_s == '.app'
|
exec 'bash'
|
||||||
|
|
||||||
cmd=yield from.relative_path_from(start)
|
|
||||||
|
|
||||||
if :skip == cmd
|
|
||||||
Find.prune
|
|
||||||
elsif :mkpath == cmd
|
|
||||||
to.mkpath
|
|
||||||
$n+=1
|
|
||||||
else
|
else
|
||||||
symlink_relative_to from, to
|
Process.wait pid
|
||||||
Find.prune
|
end
|
||||||
|
elsif ARGV.include? '--help'
|
||||||
|
ohai './configure --help'
|
||||||
|
puts `./configure --help`
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
formula.prefix.mkpath
|
||||||
|
formula.install
|
||||||
|
%w[README ChangeLog COPYING COPYRIGHT AUTHORS].each do |file|
|
||||||
|
formula.prefix.install file if File.file? file
|
||||||
end
|
end
|
||||||
elsif from.file?
|
|
||||||
symlink_relative_to from, to
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
ohai 'Finishing up'
|
||||||
|
keg=Keg.new formula
|
||||||
|
keg.clean
|
||||||
|
keg.ln
|
||||||
|
if formula.caveats
|
||||||
|
ohai "Caveats"
|
||||||
|
puts formula.caveats
|
||||||
|
ohai "Summary"
|
||||||
|
end
|
||||||
|
puts "#{keg.path}: "+abv(keg)+", built in #{pretty_duration Time.now-beginning}"
|
||||||
|
rescue Exception
|
||||||
|
formula.prefix.rmtree
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
def mk url
|
||||||
|
require 'formula'
|
||||||
|
path=Pathname.new(url)
|
||||||
|
|
||||||
|
/(.*?)[-_.]?#{path.version}/.match path.basename
|
||||||
|
raise "Couldn't parse name from #{url}" if $1.nil? or $1.empty?
|
||||||
|
|
||||||
|
path=Formula.path $1
|
||||||
|
raise "#{path} already exists!" if File.exist? path
|
||||||
|
|
||||||
|
f=File.new path, 'w'
|
||||||
|
f.puts "require 'brewkit'"
|
||||||
|
f.puts
|
||||||
|
f.puts "class #{Formula.class $1} <Formula"
|
||||||
|
f.puts " @url='#{url}'"
|
||||||
|
f.puts " @homepage=''" # second because you fill in these two first
|
||||||
|
f.puts " @md5=''"
|
||||||
|
f.puts
|
||||||
|
f.puts " def install"
|
||||||
|
f.puts " system \"./configure --disable-debug --prefix='\#{prefix}'\""
|
||||||
|
f.puts " system \"make install\""
|
||||||
|
f.puts " end"
|
||||||
|
f.print "end"
|
||||||
|
f.close
|
||||||
|
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
def prefix
|
||||||
|
Pathname.new(__FILE__).dirname.parent.expand_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def usage
|
def usage
|
||||||
@ -181,11 +165,6 @@ Commands:
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def abv keg=''
|
|
||||||
keg=$cellar+keg
|
|
||||||
return nil if not File.directory? keg
|
|
||||||
`find #{keg} -type f | wc -l`.strip+' files, '+`du -hd0 #{keg} | cut -d"\t" -f1`.strip
|
|
||||||
end
|
|
||||||
|
|
||||||
######################################################################## utils
|
######################################################################## utils
|
||||||
def pretty_duration s
|
def pretty_duration s
|
||||||
@ -197,147 +176,80 @@ end
|
|||||||
######################################################################### impl
|
######################################################################### impl
|
||||||
begin
|
begin
|
||||||
case ARGV.shift
|
case ARGV.shift
|
||||||
when 'prune'
|
when '--prefix' then puts prefix
|
||||||
puts "Pruned #{prune} files"
|
when '--cache' then puts Homebrew::cache
|
||||||
when '--prefix'
|
when '-h', '--help', '--usage', '-?' then puts usage
|
||||||
# we use the cwd because __FILE__ can be relative and expand_path
|
when '-v', '--version' then puts HOMEBREW_VERSION
|
||||||
# resolves the symlink for the working directory if fed a relative path
|
when 'macports' then exec "open 'http://www.macports.org/ports.php?by=name&substr=#{ARGV.shift}'"
|
||||||
# NOTE we don't use Dir.pwd because it resolves the symlink :(
|
|
||||||
cwd=Pathname.new `pwd`.strip
|
when 'ls', 'list'
|
||||||
puts File.expand_path(cwd+__FILE__+'../../')
|
dirs=extract_kegs.collect {|keg| keg.path}
|
||||||
when '--cache'
|
exec "find #{dirs.join' '} -not -type d -print"
|
||||||
puts File.expand_path('~/Library/Application Support/Homebrew')
|
|
||||||
when '-h', '--help', '--usage', '-?'
|
|
||||||
puts usage
|
|
||||||
when '-v', '--version'
|
|
||||||
puts HOMEBREW_VERSION
|
|
||||||
when 'list'
|
|
||||||
fae=shift_formulae_from_ARGV.collect do |name|
|
|
||||||
keg=$cellar+name
|
|
||||||
keg.directory? ? keg : nil
|
|
||||||
end
|
|
||||||
raise 'No such keg' if fae.first.nil? and fae.length == 1
|
|
||||||
puts `find #{fae.join' '} -type f -print`
|
|
||||||
when 'macports'
|
|
||||||
exec "open 'http://www.macports.org/ports.php?by=name&substr=#{ARGV.shift}'"
|
|
||||||
when 'edit'
|
when 'edit'
|
||||||
if ARGV.empty?
|
if ARGV.empty?
|
||||||
exec "mate #{$formula} #{$root}/Library/Homebrew #{$root}/bin/brew #{$root}/README"
|
exec "mate #{$formula} #{$root}/Library/Homebrew #{$root}/bin/brew #{$root}/README"
|
||||||
else
|
else
|
||||||
exec "mate #{$formula}/#{ARGV.shift}.rb"
|
paths=extract_kegs.collect {|keg| keg.formula_path.to_s.gsub ' ', '\\ '}
|
||||||
|
exec "mate #{paths.join ' '}"
|
||||||
end
|
end
|
||||||
|
|
||||||
when 'install'
|
when 'install'
|
||||||
shift_formulae_from_ARGV.each do |name|
|
require 'formula'
|
||||||
beginning = Time.now
|
extract_named_args.each do |name|
|
||||||
o=__obj(name)
|
install Formula.create(name)
|
||||||
begin
|
|
||||||
raise "#{o.prefix} already exists!" if o.prefix.exist?
|
|
||||||
o.brew do
|
|
||||||
if ARGV.include? '--interactive'
|
|
||||||
ohai "Entering interactive mode, type `exit' to return to finalize installation"
|
|
||||||
puts "Install to this prefix: #{o.prefix}"
|
|
||||||
pid=fork
|
|
||||||
if pid.nil?
|
|
||||||
exec 'bash'
|
|
||||||
else
|
|
||||||
Process.wait pid
|
|
||||||
end
|
|
||||||
elsif ARGV.include? '--help'
|
|
||||||
ohai './configure --help'
|
|
||||||
puts `./configure --help`
|
|
||||||
exit
|
|
||||||
else
|
|
||||||
o.prefix.mkpath
|
|
||||||
o.install
|
|
||||||
%w[README ChangeLog COPYING COPYRIGHT AUTHORS].each do |file|
|
|
||||||
FileUtils.cp file, o.prefix if File.file? file
|
|
||||||
end
|
|
||||||
#this is common, and we don't want it
|
|
||||||
versioned_docs=o.doc.parent+"#{o.name}-#{o.version}"
|
|
||||||
versioned_docs.rename o.doc if versioned_docs.exist?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ohai 'Finishing up'
|
|
||||||
o.clean
|
|
||||||
ln name
|
|
||||||
if o.caveats
|
|
||||||
ohai "Caveats"
|
|
||||||
puts o.caveats
|
|
||||||
ohai "Summary"
|
|
||||||
end
|
|
||||||
puts "#{o.prefix}: "+abv(name)+", built in #{pretty_duration Time.now-beginning}"
|
|
||||||
rescue Exception
|
|
||||||
FileUtils.rm_rf o.prefix
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
when 'ln'
|
when 'ln', 'link'
|
||||||
n=0
|
n=0
|
||||||
shift_formulae_from_ARGV.each {|name| n+=ln name}
|
(kegs=extract_kegs).each do |keg|
|
||||||
|
n+=nn=keg.ln
|
||||||
|
puts "Created #{nn} links for #{keg.name}" if kegs.length > 1
|
||||||
|
end
|
||||||
puts "Created #{n} links"
|
puts "Created #{n} links"
|
||||||
|
|
||||||
when 'rm', 'uninstall'
|
when 'rm', 'uninstall'
|
||||||
shift_formulae_from_ARGV.each {|name| rm name}
|
extract_kegs.each do |keg|
|
||||||
|
puts "Removing #{keg.name}..."
|
||||||
|
keg.rm
|
||||||
|
end
|
||||||
|
print "Pruning #{prefix}/..."
|
||||||
|
puts " #{prune} symbolic links pruned"
|
||||||
|
|
||||||
when 'mk'
|
when 'prune'
|
||||||
require 'brewkit'
|
puts "Pruned #{prune} symbolic links"
|
||||||
url=ARGV.shift
|
|
||||||
version=extract_version File.basename(url, Pathname.new(url).extname)
|
|
||||||
|
|
||||||
/(.*?)[-_.]?#{version}/.match File.basename(url)
|
when 'mk', 'make'
|
||||||
raise "Couldn't parse name from #{url}" if $1.nil? or $1.empty?
|
paths=ARGV.collect {|arg| mk arg}
|
||||||
|
if paths.empty?
|
||||||
path=$formula+($1.downcase+'.rb')
|
raise "Invalid URL"
|
||||||
raise "#{path} already exists!" if File.exist? path
|
elsif Kernel.system "which mate > /dev/null" and $? == 0
|
||||||
|
paths=paths.collect {|path| path.to_s.gsub " ", "\\ "}
|
||||||
f=File.new path, 'w'
|
exec "mate #{paths.join ' '}"
|
||||||
f.puts "require 'brewkit'"
|
|
||||||
f.puts
|
|
||||||
f.puts "class #{__class $1} <Formula"
|
|
||||||
f.puts " @url='#{url}'"
|
|
||||||
f.puts " @homepage=''" # second because you fill in these two first
|
|
||||||
f.puts " @md5=''"
|
|
||||||
f.puts
|
|
||||||
f.puts " def install"
|
|
||||||
f.puts " system \"./configure --disable-debug --prefix='\#{prefix}'\""
|
|
||||||
f.puts " system \"make install\""
|
|
||||||
f.puts " end"
|
|
||||||
f.print "end"
|
|
||||||
f.close
|
|
||||||
|
|
||||||
if Kernel.system "which mate > /dev/null" and $? == 0
|
|
||||||
exec "mate #{path}"
|
|
||||||
else
|
else
|
||||||
puts path
|
puts paths.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
when 'info','abv'
|
when 'info', 'abv'
|
||||||
if ARGV.empty?
|
if ARGV.empty?
|
||||||
puts abv
|
puts abv
|
||||||
|
elsif ARGV[0][0..6] == 'http://'
|
||||||
|
puts Pathname.new(ARGV.shift).version
|
||||||
else
|
else
|
||||||
if ARGV[0][0..6] == 'http://'
|
#TODO show outdated status and that
|
||||||
require 'brewkit'
|
keg=extract_kegs[0]
|
||||||
path=Pathname.new ARGV[0]
|
frm=Formula.create keg.name
|
||||||
basename=File.basename path, path.extname
|
puts "#{keg.name} #{keg.version}"
|
||||||
v=extract_version basename
|
puts frm.homepage
|
||||||
puts v
|
if keg.installed?
|
||||||
else
|
puts "#{abv keg} (installed to #{keg.path})"
|
||||||
o=__obj shift_formulae_from_ARGV[0]
|
end
|
||||||
puts "#{o.name} #{o.version}"
|
if frm.caveats
|
||||||
puts o.homepage
|
ohai 'Caveats'
|
||||||
if abv=abv(o.name)
|
puts frm.caveats
|
||||||
ohai "Installation"
|
|
||||||
puts abv
|
|
||||||
end
|
|
||||||
if o.caveats
|
|
||||||
ohai 'Caveats'
|
|
||||||
puts o.caveats
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
puts usage
|
puts usage
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user