
The Cellar may not actually be "`brew --prefix`/Cellar". We support the Cellar existing only in the repo but not linked into the prefix, for installs that aren't directly in /usr/local (or other chosen prefix.)
374 lines
11 KiB
Ruby
Executable File
374 lines
11 KiB
Ruby
Executable File
#!/usr/bin/ruby
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Many Pathname operations use getwd when they shouldn't, and then throw
|
|
# odd exceptions. Reduce our support burden by showing a user-friendly error.
|
|
Dir.getwd rescue abort "The current working directory doesn't exist, cannot proceed."
|
|
|
|
HOMEBREW_BREW_FILE = ENV['HOMEBREW_BREW_FILE'] = File.expand_path(__FILE__)
|
|
|
|
require 'pathname'
|
|
HOMEBREW_LIBRARY_PATH = (Pathname.new(__FILE__).realpath.dirname.parent+"Library"+"Homebrew").to_s
|
|
$:.unshift(HOMEBREW_LIBRARY_PATH)
|
|
require 'global'
|
|
|
|
case ARGV.first
|
|
when '--cache'
|
|
puts HOMEBREW_CACHE
|
|
exit 0
|
|
when '-h', '--help', '--usage', '-?', 'help', nil
|
|
puts ARGV.usage
|
|
exit 0
|
|
when '--version'
|
|
puts HOMEBREW_VERSION
|
|
exit 0
|
|
when '-v'
|
|
if ARGV.length > 1
|
|
puts "Homebrew #{HOMEBREW_VERSION}"
|
|
# continue in verbose mode
|
|
ARGV << ARGV.shift
|
|
else
|
|
puts HOMEBREW_VERSION
|
|
exit 0
|
|
end
|
|
end
|
|
|
|
case HOMEBREW_PREFIX.to_s when '/', '/usr'
|
|
# it may work, but I only see pain this route and don't want to support it
|
|
abort "Cowardly refusing to continue at this prefix: #{HOMEBREW_PREFIX}"
|
|
end
|
|
if MACOS_VERSION < 10.5
|
|
abort "Homebrew requires Leopard or higher, but you could fork it and fix that..."
|
|
end
|
|
|
|
def dump_config
|
|
require 'hardware'
|
|
bits = Hardware.bits
|
|
cores = Hardware.cores_as_words
|
|
llvm = llvm_build
|
|
gcc = gcc_build
|
|
sha = `cd #{HOMEBREW_REPOSITORY} && git rev-parse --verify HEAD 2> /dev/null`.chomp
|
|
kernel_arch = `uname -m`.chomp
|
|
|
|
puts <<-EOS
|
|
HOMEBREW_VERSION: #{HOMEBREW_VERSION}
|
|
HEAD: #{sha}
|
|
HOMEBREW_PREFIX: #{HOMEBREW_PREFIX}
|
|
HOMEBREW_CELLAR: #{HOMEBREW_CELLAR}
|
|
HOMEBREW_CACHE: #{HOMEBREW_CACHE}
|
|
HOMEBREW_REPOSITORY: #{HOMEBREW_REPOSITORY}
|
|
HOMEBREW_LIBRARY_PATH: #{HOMEBREW_LIBRARY_PATH}
|
|
Hardware: #{cores}-core #{bits}-bit #{Hardware.intel_family}
|
|
OS X: #{MACOS_FULL_VERSION}
|
|
Kernel Architecture: #{kernel_arch}
|
|
Ruby: #{RUBY_VERSION}-#{RUBY_PATCHLEVEL}
|
|
GCC-4.2: #{gcc ? "build #{gcc}" : "N/A"} (5577 or newer recommended)
|
|
LLVM: #{llvm ? "build #{llvm}" : "N/A" } #{llvm ? "(2206 or newer recommended)" : "" }
|
|
MacPorts or Fink? #{macports_or_fink_installed?}
|
|
X11 installed? #{x11_installed?}
|
|
EOS
|
|
end
|
|
|
|
begin
|
|
require 'brew.h'
|
|
|
|
case arg = ARGV.shift
|
|
when '--prefix'
|
|
puts HOMEBREW_PREFIX
|
|
when '--repository'
|
|
puts HOMEBREW_REPOSITORY
|
|
when '--cellar'
|
|
puts HOMEBREW_CELLAR
|
|
when '--config'
|
|
dump_config
|
|
|
|
when 'home', 'homepage'
|
|
if ARGV.named.empty?
|
|
exec "open", HOMEBREW_WWW
|
|
else
|
|
exec "open", *ARGV.formulae.collect {|f| f.homepage}
|
|
end
|
|
|
|
when 'ls', 'list'
|
|
if ARGV.flag? '--unbrewed'
|
|
dirs = HOMEBREW_PREFIX.children.select { |pn| pn.directory? }.collect { |pn| pn.basename.to_s }
|
|
dirs -= ['Library', 'Cellar', '.git']
|
|
Dir.chdir HOMEBREW_PREFIX
|
|
exec 'find', *dirs + %w[-type f ( ! -iname .ds_store ! -iname brew )]
|
|
elsif ARGV.named.empty?
|
|
ENV['CLICOLOR']=nil
|
|
exec 'ls', *ARGV.options<<HOMEBREW_CELLAR if HOMEBREW_CELLAR.exist?
|
|
elsif ARGV.verbose? or not $stdout.tty?
|
|
exec "find", *ARGV.kegs+%w[-not -type d -print]
|
|
else
|
|
ARGV.kegs.each { |keg| PrettyListing.new keg }
|
|
end
|
|
|
|
when 'search', '-S'
|
|
check_for_blacklisted_formula(ARGV.named)
|
|
|
|
require "formula"
|
|
formulae = Formulary.names with_aliases=true
|
|
|
|
if ARGV.first =~ /^\/(.*)\/$/
|
|
puts_columns formulae.grep(Regexp.new($1))
|
|
else
|
|
puts_columns formulae.grep(/.*#{ARGV.first}.*/)
|
|
end
|
|
|
|
when 'edit'
|
|
if ARGV.named.empty?
|
|
# EDITOR isn't a good fit here, we need a GUI client that actually has
|
|
# a UI for projects, so apologies if this wasn't what you expected,
|
|
# please improve it! :)
|
|
exec 'mate', *Dir["#{HOMEBREW_REPOSITORY}/Library/*"]<<
|
|
"#{HOMEBREW_REPOSITORY}/bin/brew"<<
|
|
"#{HOMEBREW_REPOSITORY}/README.md"
|
|
else
|
|
# we don't use ARGV.formulae as that will throw if the file doesn't parse
|
|
paths = ARGV.named.collect do |name|
|
|
unless File.exist? path = "#{HOMEBREW_REPOSITORY}/Library/Formula/#{name}.rb"
|
|
require 'formula'
|
|
raise FormulaUnavailableError, name
|
|
else
|
|
path
|
|
end
|
|
end
|
|
exec_editor *paths
|
|
end
|
|
|
|
when 'up', 'update'
|
|
if system "/usr/bin/which -s git"
|
|
require 'update'
|
|
updater = RefreshBrew.new
|
|
old_revision = updater.current_revision
|
|
unless updater.update_from_masterbrew!
|
|
puts "Already up-to-date."
|
|
else
|
|
puts "Updated Homebrew from #{old_revision[0,8]} to #{updater.current_revision[0,8]}."
|
|
if updater.pending_formulae_changes?
|
|
ohai "The following formulae were updated:"
|
|
puts_columns updater.updated_formulae
|
|
else
|
|
puts "No formulae were updated." unless updater.pending_formulae_changes?
|
|
end
|
|
end
|
|
else
|
|
abort "Please `brew install git' first."
|
|
end
|
|
|
|
when 'ln', 'link'
|
|
ARGV.kegs.each {|keg| puts "#{keg.link} links created for #{keg}"}
|
|
|
|
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.unlink
|
|
keg.uninstall
|
|
end
|
|
|
|
when 'prune'
|
|
prune
|
|
|
|
# 'make' supported until 0.7 for historic reasons
|
|
when 'mk', 'make'
|
|
opoo "`brew make' has changed to `brew create'"
|
|
puts "This is because make can be confused with the `make' tool."
|
|
puts "brew make will continue working until Homebrew 0.7"
|
|
exec __FILE__, "create", *ARGV
|
|
|
|
when 'create'
|
|
if ARGV.include? '--macports'
|
|
exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
|
|
elsif ARGV.named.empty?
|
|
raise UsageError
|
|
else
|
|
exec_editor *ARGV.named.collect {|name| make name}
|
|
end
|
|
|
|
when 'diy', 'configure'
|
|
puts diy
|
|
|
|
when 'info', 'abv'
|
|
if ARGV.named.empty?
|
|
if ARGV.include? "--all"
|
|
require 'formula'
|
|
Formulary.names.each do |name|
|
|
info name
|
|
puts '---'
|
|
end
|
|
else
|
|
puts `ls #{HOMEBREW_CELLAR} | wc -l`.strip+" kegs, "+HOMEBREW_CELLAR.abv
|
|
end
|
|
elsif ARGV[0][0..6] == 'http://'
|
|
puts Pathname.new(ARGV.shift).version
|
|
else
|
|
ARGV.named.each {|name| info name}
|
|
end
|
|
|
|
when 'cleanup'
|
|
if ARGV.named.empty?
|
|
require 'formula'
|
|
HOMEBREW_CELLAR.children.each do |rack|
|
|
begin
|
|
cleanup(rack.basename.to_s) if rack.directory?
|
|
rescue FormulaUnavailableError => e
|
|
opoo "Formula not found for #{e.name}"
|
|
end
|
|
end
|
|
prune # seems like a good time to do some additional cleanup
|
|
else
|
|
ARGV.named.each { |name| cleanup name}
|
|
end
|
|
|
|
when 'install'
|
|
check_for_blacklisted_formula(ARGV.named)
|
|
|
|
require 'formula_installer'
|
|
require 'hardware'
|
|
|
|
############################################################ sanity checks
|
|
case Hardware.cpu_type when :ppc, :dunno
|
|
abort "Sorry, Homebrew does not support your computer's CPU architecture."
|
|
end
|
|
|
|
raise "Cannot write to #{HOMEBREW_CELLAR}" if HOMEBREW_CELLAR.exist? and not HOMEBREW_CELLAR.writable?
|
|
raise "Cannot write to #{HOMEBREW_PREFIX}" unless HOMEBREW_PREFIX.writable?
|
|
|
|
################################################################# warnings
|
|
begin
|
|
if MACOS_VERSION >= 10.6
|
|
opoo "You should upgrade to Xcode 3.2.1" if llvm_build < 2206
|
|
else
|
|
opoo "You should upgrade to Xcode 3.1.4" if gcc_build < 5577
|
|
end
|
|
rescue
|
|
# the reason we don't abort is some formula don't require Xcode
|
|
# TODO allow formula to declare themselves as "not needing Xcode"
|
|
opoo "Xcode is not installed! Builds may fail!"
|
|
end
|
|
|
|
if macports_or_fink_installed?
|
|
opoo "It appears you have Macports or Fink installed"
|
|
puts "Although, unlikely, this can break builds or cause obscure runtime issues."
|
|
puts "If you experience problems try uninstalling these tools."
|
|
end
|
|
|
|
################################################################# install!
|
|
installer = FormulaInstaller.new
|
|
installer.install_deps = !ARGV.include?('--ignore-dependencies')
|
|
|
|
ARGV.formulae.each do |f|
|
|
if not f.installed? or ARGV.force?
|
|
installer.install f
|
|
else
|
|
puts "Formula already installed: #{f.prefix}"
|
|
end
|
|
end
|
|
|
|
when 'log'
|
|
Dir.chdir HOMEBREW_REPOSITORY
|
|
exec "git", "log", ARGV.formulae.first.path, *ARGV.options
|
|
|
|
when 'uses'
|
|
# For each formula given, show which other formulas depend on it.
|
|
# We only go one level up, direct dependencies.
|
|
require 'formula'
|
|
require 'utils'
|
|
|
|
deps = Formula.get_used_by
|
|
|
|
ARGV.formulae.each do |f|
|
|
name = f.name
|
|
our_deps = deps[name]
|
|
if our_deps == nil
|
|
puts "#{name} is not a dependency."
|
|
else
|
|
puts "#{name} is a dependency for #{our_deps.join(', ')}."
|
|
end
|
|
end
|
|
|
|
when 'deps'
|
|
require 'formula'
|
|
|
|
ARGV.formulae.each do |f|
|
|
name = f.name
|
|
|
|
our_deps = []
|
|
checked = {}
|
|
to_check = [name]
|
|
|
|
until to_check.empty?
|
|
item = to_check.pop
|
|
checked[item] = true
|
|
|
|
formula = Formulary.read item
|
|
next if formula == nil || formula.deps == nil || formula.deps.empty?
|
|
|
|
our_deps.push(*formula.deps)
|
|
to_check.push(*formula.deps.select{|g| !checked[g]})
|
|
end
|
|
|
|
our_deps.uniq!
|
|
|
|
if our_deps.empty?
|
|
puts "#{name} has no dependencies."
|
|
else
|
|
our_deps.sort!
|
|
puts "#{name} depends on #{our_deps.join(", ")}"
|
|
end
|
|
end
|
|
|
|
when 'branch', 'checkout', 'pull', 'push', 'reset'
|
|
onoe "Unknown command: #{arg} (did you mean 'git #{arg}'?)"
|
|
|
|
when 'cat'
|
|
Dir.chdir HOMEBREW_REPOSITORY
|
|
exec "cat", ARGV.formulae.first.path, *ARGV.options
|
|
|
|
else
|
|
onoe "Unknown command: #{arg}"
|
|
end
|
|
|
|
rescue FormulaUnspecifiedError
|
|
abort "This command requires a formula argument"
|
|
rescue KegUnspecifiedError
|
|
abort "This command requires a keg argument"
|
|
rescue UsageError
|
|
onoe "Invalid usage"
|
|
abort ARGV.usage
|
|
rescue SystemExit
|
|
puts "Kernel.exit" if ARGV.verbose?
|
|
raise
|
|
rescue Interrupt => e
|
|
puts # seemingly a newline is typical
|
|
exit 130
|
|
rescue BuildError => e
|
|
e.backtrace[1] =~ %r{Library/Formula/(.+)\.rb:(\d+)}
|
|
formula_name = $1
|
|
puts "http://github.com/mxcl/homebrew/blob/master/Library/Formula/#{formula_name}.rb#L#{$2}"
|
|
ohai "Environment"
|
|
dump_config
|
|
puts "Exit status: #{e.exit_status}"
|
|
onoe e
|
|
puts PLEASE_REPORT_BUG
|
|
# this feature can be slow (depends on network conditions and if github is up)
|
|
# so ideally we'd show feedback, eg. "checking for existin issues..." and
|
|
# then replace that string with the following when the github api returns
|
|
issues = issues_for_formula(formula_name)
|
|
puts "These existing issues may help you:", *issues unless issues.empty?
|
|
exit 1
|
|
rescue RuntimeError, SystemCallError => e
|
|
onoe e
|
|
puts e.backtrace if ARGV.debug?
|
|
exit 1
|
|
rescue Exception => e
|
|
onoe e
|
|
puts PLEASE_REPORT_BUG
|
|
puts e.backtrace
|
|
exit 1
|
|
end
|