347 lines
9.1 KiB
Ruby
Executable File
347 lines
9.1 KiB
Ruby
Executable File
#!/usr/bin/ruby
|
|
|
|
require 'find'
|
|
require 'pathname'
|
|
$:.unshift Pathname.new(__FILE__).dirname.parent.realpath+'Library'+'Homebrew'
|
|
require 'env'
|
|
|
|
# often causes Ruby to throw exception ffs
|
|
Dir.chdir '/' unless File.exist? Dir.getwd
|
|
|
|
def prune
|
|
n=0
|
|
dirs=Array.new
|
|
$root.find do |path|
|
|
if path.directory?
|
|
name=path.relative_path_from($root).to_s
|
|
if name == '.git' or name == 'Cellar' or name == 'Library/Homebrew' or name == 'Library/Formula'
|
|
Find.prune
|
|
else
|
|
dirs<<path
|
|
end
|
|
elsif path.symlink?
|
|
resolved_path=path.dirname+path.readlink
|
|
unless resolved_path.exist?
|
|
path.unlink
|
|
n+=1
|
|
end
|
|
end
|
|
end
|
|
# entries lists '.' and '..' so 2 is minimum basically
|
|
dirs.sort.reverse_each do |d|
|
|
if d.children.length == 0
|
|
d.rmdir
|
|
n+=1
|
|
end
|
|
end
|
|
return n
|
|
end
|
|
|
|
def formulize name
|
|
name=Pathname.new name
|
|
return name if name.directory? and name.parent.realpath == $cellar
|
|
return File.basename(name, '.rb') if name.file? and name.extname == '.rb' and name.parent.realpath == $formula
|
|
|
|
name=name.to_s
|
|
raise "#{name} is an invalid name for a formula" if name.include? '/'
|
|
|
|
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
|
|
i+=1
|
|
end
|
|
end
|
|
raise "You must specify a formula" if fae.empty?
|
|
return fae
|
|
end
|
|
|
|
def __class name
|
|
#remove invalid characters and camelcase
|
|
name.capitalize.gsub(/[-_\s]([a-zA-Z0-9])/) { $1.upcase }
|
|
end
|
|
|
|
def __rb name
|
|
$formula+(name+'.rb')
|
|
end
|
|
|
|
def __obj name
|
|
require "#{__rb name}"
|
|
return eval(__class(name)).new(name)
|
|
end
|
|
|
|
def rm keg
|
|
#TODO if multiple versions don't rm all unless --force
|
|
path=$cellar+keg
|
|
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
|
|
|
|
# symlinks a directory recursively into our FHS tree
|
|
def lnd keg, start
|
|
start=keg+start
|
|
return unless start.directory?
|
|
|
|
start.find do |from|
|
|
next if from == start
|
|
|
|
prune=false
|
|
relative_path=from.relative_path_from keg
|
|
to=$root+relative_path
|
|
|
|
if 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'
|
|
|
|
cmd=yield from.relative_path_from(start)
|
|
|
|
if :skip == cmd
|
|
Find.prune
|
|
elsif :mkpath == cmd
|
|
to.mkpath
|
|
$n+=1
|
|
else
|
|
symlink_relative_to from, to
|
|
Find.prune
|
|
end
|
|
elsif from.file?
|
|
symlink_relative_to from, to
|
|
end
|
|
end
|
|
end
|
|
|
|
def usage
|
|
name=File.basename $0
|
|
<<-EOS
|
|
Usage: #{name} command [formula] ...
|
|
Usage: #{name} [--prefix] [--cache] [--version]
|
|
Usage: #{name} [--verbose]
|
|
|
|
Commands:
|
|
install formula ... [--debug] [--interactive]
|
|
rm formula ...
|
|
list formula ...
|
|
ln formula ...
|
|
info [formula]
|
|
mk url
|
|
prune
|
|
EOS
|
|
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
|
|
def pretty_duration s
|
|
return "#{(s*1000).to_i} milliseconds" if s < 3
|
|
return "#{s.to_i} seconds" if s < 10*60
|
|
return "#{(s/60).to_i} minutes"
|
|
end
|
|
|
|
######################################################################### impl
|
|
begin
|
|
case ARGV.shift
|
|
when 'prune'
|
|
puts "Pruned #{prune} files"
|
|
when '--prefix'
|
|
# we use the cwd because __FILE__ can be relative and expand_path
|
|
# resolves the symlink for the working directory if fed a relative path
|
|
# NOTE we don't use Dir.pwd because it resolves the symlink :(
|
|
cwd=Pathname.new `pwd`.strip
|
|
puts File.expand_path(cwd+__FILE__+'../../')
|
|
when '--cache'
|
|
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'
|
|
if ARGV.empty?
|
|
exec "mate #{$formula} #{$root}/Library/Homebrew #{$root}/bin/brew #{$root}/README"
|
|
else
|
|
exec "mate #{$formula}/#{ARGV.shift}.rb"
|
|
end
|
|
|
|
when 'install'
|
|
shift_formulae_from_ARGV.each do |name|
|
|
beginning = Time.now
|
|
o=__obj(name)
|
|
begin
|
|
raise "#{o.prefix} already exists!" if o.prefix.exist?
|
|
o.prefix.mkpath
|
|
o.brew do
|
|
if ARGV.include? '--interactive'
|
|
ohai "Entering interactive mode, type `exit' to return to this shell"
|
|
exec "bash" # exec() because system() didn't work :(
|
|
elsif ARGV.include? '--help'
|
|
ohai './configure --help'
|
|
puts `./configure --help`
|
|
exit
|
|
else
|
|
o.install
|
|
['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
|
|
when 'ln'
|
|
n=0
|
|
shift_formulae_from_ARGV.each {|name| n+=ln name}
|
|
puts "Created #{n} links"
|
|
when 'rm', 'uninstall'
|
|
shift_formulae_from_ARGV.each {|name| rm name}
|
|
when 'mk'
|
|
require 'brewkit'
|
|
url=ARGV.shift
|
|
version=extract_version File.basename(url, Pathname.new(url).extname)
|
|
|
|
/(.*?)[-_.]?#{version}/.match File.basename(url)
|
|
raise "Couldn't parse name from #{url}" if $1.nil?
|
|
|
|
path=$formula+($1.downcase+'.rb')
|
|
raise "#{path} already exists!" if File.exist? path
|
|
|
|
f=File.new path, 'w'
|
|
f.puts "require 'brewkit'"
|
|
f.puts
|
|
f.puts "class #{__class $1} <Formula"
|
|
f.puts " @url='#{url}'"
|
|
f.puts " @md5=''"
|
|
f.puts " @homepage=''"
|
|
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
|
|
puts path
|
|
end
|
|
|
|
when 'info','abv'
|
|
if ARGV.empty?
|
|
puts abv
|
|
else
|
|
if ARGV[0][0..6] == 'http://'
|
|
require 'brewkit'
|
|
path=Pathname.new ARGV[0]
|
|
basename=File.basename path, path.extname
|
|
v=extract_version basename
|
|
puts v
|
|
else
|
|
o=__obj shift_formulae_from_ARGV[0]
|
|
puts "#{o.name} #{o.version}"
|
|
puts o.homepage
|
|
if abv=abv(o.name)
|
|
ohai "Installation"
|
|
puts abv
|
|
end
|
|
if o.caveats
|
|
ohai 'Caveats'
|
|
puts o.caveats
|
|
end
|
|
end
|
|
end
|
|
|
|
else
|
|
puts usage
|
|
end
|
|
|
|
rescue StandardError, Interrupt => e
|
|
if ARGV.include? '--verbose' or ENV['HOMEBREW_DEBUG']
|
|
raise
|
|
elsif e.kind_of? Interrupt
|
|
puts # seeimgly a newline is typical
|
|
exit 130
|
|
elsif e.kind_of? StandardError and not e.kind_of? NameError
|
|
puts "\033[1;31mError\033[0;0m: #{e}"
|
|
exit 1
|
|
else
|
|
raise
|
|
end
|
|
end |