From 760c083c0c0c9934e4118b4669c8c8dfd0a3587d Mon Sep 17 00:00:00 2001 From: Max Howell Date: Mon, 10 Aug 2009 16:48:30 +0100 Subject: [PATCH] Refactor Large refactor to Formula, mostly improving reliability and error handling but also layout and readability. General improvements so testing can be more complete. Patches are automatically downloaded and applied for Formula that return a list of urls from Formula::patches. Split out the brew command logic to facilitate testing. Facility from Adam Vandenberg to allow selective cleaning of files, added because Python doesn't work when stripped. --- Library/Contributions/brew_bash_completion.sh | 2 +- Library/Homebrew/brew.h.rb | 238 ++++++++++++ Library/Homebrew/env.rb | 25 -- Library/Homebrew/formula.rb | 349 +++++++++--------- Library/Homebrew/keg.rb | 165 ++------- Library/Homebrew/pathname+yeast.rb | 54 +++ Library/Homebrew/unittest.rb | 60 ++- Library/Homebrew/utils.rb | 21 +- README | 5 +- bin/brew | 349 +++++------------- 10 files changed, 677 insertions(+), 591 deletions(-) create mode 100644 Library/Homebrew/brew.h.rb delete mode 100644 Library/Homebrew/env.rb diff --git a/Library/Contributions/brew_bash_completion.sh b/Library/Contributions/brew_bash_completion.sh index dd18faa030..f33204d369 100644 --- a/Library/Contributions/brew_bash_completion.sh +++ b/Library/Contributions/brew_bash_completion.sh @@ -35,7 +35,7 @@ _brew_to_completion() ;; # Commands that take an existing brew... - abv|info|list|link|ls|ln|rm|uninstall) + abv|info|list|link|ls|ln|rm|remove|uninstall) cellar_contents=`ls ${brew_base}/Cellar/` COMPREPLY=( $(compgen -W "${cellar_contents}" -- ${cur}) ) return 0 diff --git a/Library/Homebrew/brew.h.rb b/Library/Homebrew/brew.h.rb new file mode 100644 index 0000000000..3dee3ec2dc --- /dev/null +++ b/Library/Homebrew/brew.h.rb @@ -0,0 +1,238 @@ +# 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 . + +def make 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 path.exist? + + template=<<-EOS + require 'brewkit' + + class #{Formula.class $1} 1 + puts + end + else + puts "Not installed" + end + + if f.caveats + puts + puts f.caveats + puts + end + + puts history + +rescue FormulaUnavailableError + # check for DIY installation + d=HOMEBREW_PREFIX+name + if d.directory? + ohai "DIY Installation" + d.children.each {|keg| puts "#{keg} (#{keg.abv})"} + else + raise "No such formula or keg" + end +end + + +def clean f + Cleaner.new f + # remove empty directories TODO Rubyize! + `perl -MFile::Find -e"finddepth(sub{rmdir},'#{f.prefix}')"` +end + + +def install f + f.brew do + if ARGV.flag? '--interactive' + ohai "Entering interactive mode" + puts "Type `exit' to return and finalize the installation" + puts "Install to this prefix: #{f.prefix}" + interactive_shell + elsif ARGV.include? '--help' + system './configure --help' + exit $? + else + f.prefix.mkpath + f.install + %w[README ChangeLog COPYING LICENSE COPYRIGHT AUTHORS].each do |file| + f.prefix.install file if File.file? file + end + end + end +end + + +def prune + $n=0 + $d=0 + + dirs=Array.new + paths=%w[bin etc lib include share].collect {|d| HOMEBREW_PREFIX+d} + + paths.each do |path| + path.find do |path| + path.extend ObserverPathnameExtension + if path.symlink? + path.unlink unless path.resolved_path_exists? + elsif path.directory? + dirs< 0 + puts "from #{HOMEBREW_PREFIX}" + end +end + + +################################################################ class Cleaner +class Cleaner + def initialize f + @f=f + [f.bin, f.lib].each {|d| clean_dir d} + end + +private + def strip path, args='' + return if @f.skip_clean? path + puts "strip #{path}" if ARGV.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 #{args} -o #{tmp} #{path}` + `cat #{tmp} > #{path}` + File.unlink tmp + end + end + + def clean_file path + perms=0444 + case `file -h #{path}` + when /Mach-O dynamically linked shared library/ + strip path, '-SxX' + when /Mach-O [^ ]* ?executable/ + strip path + perms=0544 + when /script text executable/ + perms=0544 + end + path.chmod perms + end + + def clean_dir d + d.find do |path| + if not path.file? + next + elsif path.extname == '.la' and not @f.skip_clean? path + # *.la files are stupid + path.unlink + else + clean_file path + end + end + end +end diff --git a/Library/Homebrew/env.rb b/Library/Homebrew/env.rb deleted file mode 100644 index 3710aa7937..0000000000 --- a/Library/Homebrew/env.rb +++ /dev/null @@ -1,25 +0,0 @@ -# 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 'pathname+yeast' -require 'utils' - -# TODO if whoami == root then use /Library/Caches/Homebrew instead -HOMEBREW_VERSION='0.3' -HOMEBREW_CACHE=Pathname.new("~/Library/Caches/Homebrew").expand_path -HOMEBREW_PREFIX=Pathname.new(__FILE__).dirname.parent.parent.cleanpath -HOMEBREW_CELLAR=HOMEBREW_PREFIX+'Cellar' diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 4f02e20779..f01798eba6 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -15,30 +15,31 @@ # You should have received a copy of the GNU General Public License # along with Homebrew. If not, see . -require 'utils' -class BuildError e + raise unless ARGV.debug? + onoe e.inspect + puts e.backtrace + ohai "Rescuing build..." + puts "Type `exit' and Homebrew will attempt to finalize the installation" + puts "If nothing is installed to #{prefix}, then Homebrew will abort" + interactive_shell + end + end end - + +protected # 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 + def system cmd, *args + full="#{cmd} #{args*' '}".strip + ohai full + if ARGV.verbose? + safe_system cmd, *args else out='' - IO.popen "#{cmd} 2>&1" do |f| + # TODO write a ruby extension that does a good popen :P + IO.popen "#{full} 2>&1" do |f| until f.eof? out+=f.gets end end - puts out unless $? == 0 + unless $? == 0 + puts out + raise + end end + rescue + raise BuildError.new(cmd, args) + end - raise BuildError.new(cmd) unless $? == 0 +private + def mktemp + tmp=Pathname.new `mktemp -dt #{File.basename @url}`.strip + raise if not tmp.directory? or $? != 0 + begin + wd=Dir.pwd + Dir.chdir tmp + yield + ensure + Dir.chdir wd + tmp.rmtree + end + end + + # Kernel.system but with exceptions + def safe_system cmd, *args + puts "#{cmd} #{args*' '}" if ARGV.verbose? + # stderr is shown, so hopefully that will explain the problem + raise ExecutionError.new(cmd, args) unless Kernel.system cmd, *args and $? == 0 + end + + def curl url, *args + safe_system 'curl', '-f#LA', HOMEBREW_USER_AGENT, url, *args + end + + def verify_download_integrity fn + require 'digest' + type='MD5' + type='SHA1' if @sha1 + supplied=eval "@#{type.downcase}" + hash=eval("Digest::#{type}").hexdigest(fn.read) + + if supplied and not supplied.empty? + raise "#{type} mismatch: #{hash}" unless supplied.upcase == hash.upcase + else + opoo "Cannot verify package integrity" + puts "The formula did not provide a download checksum" + puts "For your reference the #{type} is: #{hash}" + end + end + + def patch + unless patches.empty? + ohai "Patching" + ff=(1..patches.length).collect {|n| '%03d-homebrew.patch'%n} + curl *patches+ff.collect {|f|"-o#{f}"} + ff.each {|f| safe_system 'patch', '-p0', '-i', f} + end + end + + class <. - -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 - path=HOMEBREW_CELLAR+formula - kids=path.children - raise "Empty installation: #{path}" if kids.length < 1 - raise "Multiple versions installed" if kids.length > 1 - @path=kids[0] - @name=formula - @version=@path.basename - end +# +class Keg 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}')"` + def uninstall + chmod_R 0777 # ensure we have permission to delete + rmtree + parent.rmdir_if_possible end - def rm - # don't rmtree shit if we aren't positive about our location! - raise "Bad stuff!" unless path.parent.parent == HOMEBREW_CELLAR + def link + $n=0 + $d=0 - if path.directory? - FileUtils.chmod_R 0777, path # ensure we have permission to delete - path.rmtree # HOMEBREW_CELLAR/foo/1.2.0 - path.parent.rmdir if path.parent.children.length == 0 # HOMEBREW_CELLAR/foo - end + mkpaths=(1..9).collect {|x| "man/man#{x}"} <<'man'<<'doc'<<'locale'<<'info'<<'aclocal' + + # 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 + link_dir('etc') {:mkpath} + link_dir('bin') {:link} + link_dir('lib') {|path| :mkpath if %w[pkgconfig php].include? path.to_s} + link_dir('include') {:link} + link_dir('share') {|path| :mkpath if mkpaths.include? path.to_s} + + return $n+$d 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 the contents of self+foo recursively into /usr/local/foo + def link_dir foo + root=self+foo - # symlinks a directory recursively into our FHS tree - def __ln start - start=path+start - return unless start.directory? + root.find do |src| + next if src == root - root=Pathname.new HOMEBREW_PREFIX - start.find do |from| - next if from == start + dst=HOMEBREW_PREFIX+src.relative_path_from(self) + dst.extend ObserverPathnameExtension - prune=false - - relative_path=from.relative_path_from path - to=root+relative_path - - if from.file? - __symlink_relative_to from, to - elsif from.directory? + if src.file? + dst.make_relative_symlink src + elsif src.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' + Find.prune if src.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 + case yield src.relative_path_from(root) + when :skip then Find.prune + when :mkpath then dst.mkpath + else dst.make_relative_symlink src; 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 +end diff --git a/Library/Homebrew/pathname+yeast.rb b/Library/Homebrew/pathname+yeast.rb index 67a21cfc28..43c07c5abf 100644 --- a/Library/Homebrew/pathname+yeast.rb +++ b/Library/Homebrew/pathname+yeast.rb @@ -68,6 +68,24 @@ class Pathname return File.basename(to_s, extname) end + # I don't trust the children.length == 0 check particularly, not to mention + # it is slow to enumerate the whole directory just to see if it is empty, + # instead rely on good ol' libc and the filesystem + def rmdir_if_possible + rmdir + rescue SystemCallError => e + raise unless e.errno == Errno::ENOTEMPTY::Errno + end + + def chmod_R perms + require 'fileutils' + FileUtils.chmod_R perms, to_s + end + + def abv + `find #{to_s} -type f | wc -l`.strip+' files, '+`du -hd0 #{to_s} | cut -d"\t" -f1`.strip + end + def version # eg. boost_1_39_0 /((\d+_)+\d+)$/.match stem @@ -100,3 +118,39 @@ class Pathname end end end + +# sets $n and $d so you can observe creation of stuff +module ObserverPathnameExtension + def unlink + super + puts "rm #{to_s}" if ARGV.verbose? + $n+=1 + end + def rmdir + super + puts "rmdir #{to_s}" if ARGV.verbose? + $d+=1 + end + def resolved_path_exists? + (dirname+readlink).exist? + end + def mkpath + super + puts "mkpath #{to_s}" if ARGV.verbose? + $d+=1 + end + def make_relative_symlink src + dirname.mkpath + Dir.chdir dirname do + # TODO use Ruby function so we get exceptions + # NOTE Ruby functions may work, but I had a lot of problems + rv=system 'ln', '-sf', src.relative_path_from(dirname) + raise "Could not create symlink #{to_s}" unless rv and $? == 0 + puts "ln #{to_s}" if ARGV.verbose? + $n+=1 + end + end +end + +$n=0 +$d=0 diff --git a/Library/Homebrew/unittest.rb b/Library/Homebrew/unittest.rb index 878b05ab9c..1bee7b3a61 100755 --- a/Library/Homebrew/unittest.rb +++ b/Library/Homebrew/unittest.rb @@ -1,9 +1,8 @@ #!/usr/bin/ruby $:.unshift File.dirname(__FILE__) +require 'pathname+yeast' require 'formula' require 'keg' -require 'pathname+yeast' -require 'stringio' require 'utils' # these are defined in env.rb usually, but we don't want to break our actual @@ -17,6 +16,7 @@ HOMEBREW_CELLAR.mkpath raise "HOMEBREW_CELLAR couldn't be created!" unless HOMEBREW_CELLAR.directory? at_exit { HOMEBREW_PREFIX.parent.rmtree } require 'test/unit' # must be after at_exit +require 'ARGV+yeast' # needs to be after test/unit to avoid conflict with OptionsParser class MockFormula #{path}` - assert_not_nil Formula.create(FOOBAR) + assert_not_nil Formula.factory(FOOBAR) end def test_cant_override_brew assert_raises(RuntimeError) { TestBallOverrideBrew.new } end + + def test_abstract_formula + f=MostlyAbstractFormula.new + assert_nil f.name + assert_raises(RuntimeError) { f.prefix } + nostdout { assert_raises(ExecutionError) { f.brew } } + end end diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 112c6b6b60..bb64c38519 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -22,5 +22,24 @@ end # shows a warning in delicious pink def opoo warning - puts "WARNING \033[1;35m#{warning}\033[0;0m" + puts "\033[1;35m==>\033[0;0;1m Warning\033[0;0m: #{warning}" +end + +def onoe error + puts "\033[1;31m==>\033[0;0;1m Error\033[0;0m: #{error}" +end + +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 + +def interactive_shell + pid=fork + if pid.nil? + exec ENV['SHELL'] + else + Process.wait pid + end end diff --git a/README b/README index a79b4f17ff..e981eda098 100644 --- a/README +++ b/README @@ -53,7 +53,10 @@ Here's why you may prefer Homebrew to the alternatives: We optimise for Leopard Intel, binaries are stripped, compile flags tweaked. Nobody wants crappy, slow software. Apart from MacPorts and Fink. -8. Integration with existing OS X technologies +8. Making the most of OS X + Homebrew knows how many cores you have thanks to RubyCocoa, so it makes + sure when it builds it uses all of them, (unless you don't want it to of + course). 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 improve it by making these tools install with more management options. diff --git a/bin/brew b/bin/brew index 6af4460ace..d4162986ab 100755 --- a/bin/brew +++ b/bin/brew @@ -1,306 +1,135 @@ #!/usr/bin/ruby -$:.unshift __FILE__+'/../../Library/Homebrew' -require 'env' -require 'find' +$:.unshift ENV['RUBYLIB']=File.expand_path(__FILE__+'/../../Library/Homebrew') -PRISTINE_ARGV=ARGV.dup +require 'pathname+yeast' +require 'ARGV+yeast' +require 'utils' +require 'brew.h' + +# TODO if whoami == root then use /Library/Caches/Homebrew instead +HOMEBREW_CACHE=Pathname.new("~/Library/Caches/Homebrew").expand_path +HOMEBREW_PREFIX=Pathname.new(__FILE__).dirname.parent.cleanpath +HOMEBREW_CELLAR=HOMEBREW_PREFIX+'Cellar' +HOMEBREW_VERSION='0.4' +HOMEBREW_WWW='http://bit.ly/Homebrew' HOMEBREW_USER_AGENT="Homebrew #{HOMEBREW_VERSION} (Ruby #{VERSION}; Mac OS X 10.5 Leopard)" -# often causes Ruby to throw exception ffs +if %w[/ /usr].include? HOMEBREW_PREFIX.to_s then abort <<-troba +You have placed Homebrew at the prefix: #{HOMEBREW_PREFIX} +This is not currently supported. Voice your support for this feature at: +#{HOMEBREW_WWW} +troba +end + +# Pathname often throws if CWD doesn't exist Dir.chdir '/' unless File.directory? ENV['PWD'] -######################################################################## funcs -# remove symlinks that no longer point to files -def prune - n=0 - dirs=Array.new - HOMEBREW_PREFIX.find do |path| - if path.directory? - name=path.relative_path_from(HOMEBREW_PREFIX).to_s - if name == '.git' or name == 'Cellar' or name == 'Library' - Find.prune - else - dirs< brew #{PRISTINE_ARGV.join ' '} wget" if args.empty? - return args -end - -def extract_kegs - require 'keg' - kegs=extract_named_args.collect {|name| Keg.new name} - return kegs -end - -def abv keg=nil - path=keg ? keg.path : HOMEBREW_CELLAR - if path.directory? - `find #{path} -type f | wc -l`.strip+' files, '+`du -hd0 #{path} | cut -d"\t" -f1`.strip - else - '' - end -end - -def install formula - require 'keg' - - beginning = Time.now - - formula.brew do - if ARGV.include? '--interactive' - ohai "Entering interactive mode" - puts "Type `exit' to return and finalize the installation" - puts "Install to this prefix: #{formula.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 - formula.prefix.mkpath - formula.install - %w[README ChangeLog COPYING LICENSE COPYRIGHT AUTHORS].each do |file| - formula.prefix.install file if File.file? file - end - end - end - - raise "Nothing was installed to #{formula.prefix}" unless formula.installed? - - 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 if formula.prefix.directory? - raise -end - -def mk url, mode='make' - 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} #{f.prefix}" if f.installed? unless ARGV.include? '--force' - install f + require 'keg' + ARGV.formulae.each do |f| + raise "#{f.name} is already installed" if f.installed? unless ARGV.force? + start_time=Time.now + begin + install f + if f.caveats + ohai "Caveats" + puts f.caveats + puts + end + ohai 'Finishing up' + clean f + raise "Nothing was installed to #{f.prefix}" unless f.installed? + Keg.new(f.prefix).link + rescue + f.prefix.rmtree if f.prefix.directory? + raise + end + puts "#{f.prefix}: "+f.prefix.abv+", built in #{pretty_duration Time.now-start_time}" end when 'ln', 'link' - n=0 - (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" + ARGV.kegs.each {|keg| puts "#{keg.link} links created for #{keg}"} - when 'rm', 'uninstall' - extract_kegs.each do |keg| - puts "Removing #{keg.name}..." - keg.rm + when 'unlink' + ARGV.kegs.each {|keg| puts "#{keg.unlink} links removed for #{keg}"} + + when 'rm', 'uninstall', 'remove' + ARGV.kegs.each do |keg| + puts "Uninstalling #{keg}..." + keg.uninstall end - print "Pruning #{prefix}/..." - puts " #{prune} symbolic links pruned" + prune + + when 'up', 'update' + puts "Reserved command" when 'prune' - puts "Pruned #{prune} symbolic links" + prune when 'mk', 'make' - mode = "make" - if ARGV.length > 0 - if ARGV[0] == '--cmake' - ARGV.shift - mode = "cmake" - end - end - - paths=ARGV.collect {|arg| mk arg, mode} - if paths.empty? - raise "Invalid URL" - elsif Kernel.system "which mate > /dev/null" and $? == 0 - paths=paths.collect {|path| path.to_s.gsub " ", "\\ "} - exec "mate #{paths.join ' '}" + if ARGV.include? '--macports' + exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}" else - puts paths.join("\n") + exec "mate", *ARGV.named.collect {|name| make name} end when 'info', 'abv' - if ARGV.empty? - puts `ls #{HOMEBREW_CELLAR} | wc -l`.strip+" kegs, "+abv + if ARGV.named.empty? + puts `ls #{HOMEBREW_CELLAR} | wc -l`.strip+" kegs, "+HOMEBREW_CELLAR.abv elsif ARGV[0][0..6] == 'http://' puts Pathname.new(ARGV.shift).version else - require 'formula' - #TODO show outdated status and that - frm=Formula.create(extract_named_args[0]) - puts "#{frm.name} #{frm.version}" - puts frm.homepage - if frm.installed? - require 'keg' - keg=Keg.new frm - puts "#{abv keg} (installed to #{keg.path})" - end - if frm.caveats - ohai 'Caveats' - puts frm.caveats - end + ARGV.named.each {|name| info name} end else - puts usage + puts ARGV.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 +rescue SystemExit + ohai "Kernel.exit" if ARGV.verbose? +rescue Interrupt => e + puts # seemingly a newline is typical + exit 130 +rescue SystemCallError, RuntimeError => e + if ARGV.verbose? or ARGV.debug? + onoe e.inspect + puts e.backtrace else - raise + onoe e end + exit 1 +rescue Exception => e + onoe "Homebrew has failed you :(" + puts "Please report this bug at: #{HOMEBREW_WWW}" + puts "Please include this backtrace:" + ohai e.inspect + puts e.backtrace end