aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Howell2010-09-11 20:22:54 +0100
committerAdam Vandenberg2011-03-12 11:55:02 -0800
commit9afc85ad338f9e053fe36127937d308ad62593bc (patch)
tree610d3c0ae869d9e58e283f065c914566316ddd8c
parentf57463eee6333f8dbeb42a122290677d6c755871 (diff)
downloadhomebrew-9afc85ad338f9e053fe36127937d308ad62593bc.tar.bz2
Refactor the brew command into one file per command
The code was sucking. To the extent that maintenance was hard. It's a lot easier to work with code that is sensibly split at sensible boundaries. So now it is more like that. But the refactor is minimal. Because we don't want you to have more merge hell than absolutely necessary. If you merge you will need to pay attention to brew.h.rb (as it is deleted) and bin/brew (as command logic is gone). It will be painful, but you will just have to help git out by moving any changes around manually. Note compatibility.rb. It ensures that any function renames or removals don't break anything. We're pretty serious about backwards compatibility. And that's because we encourage you to hack around with the innards. And we couldn't do that if we would then just make stuff disappear behind your back.
-rwxr-xr-xLibrary/Contributions/examples/brew-missing.rb17
-rwxr-xr-xLibrary/Contributions/examples/brew-server1
-rwxr-xr-xLibrary/Contributions/examples/brew-upgrade.rb10
-rw-r--r--Library/Homebrew/beer_events.rb199
-rw-r--r--Library/Homebrew/brew.h.rb600
-rw-r--r--Library/Homebrew/cleaner.rb15
-rw-r--r--Library/Homebrew/cmd/--cache.rb9
-rw-r--r--Library/Homebrew/cmd/--cellar.rb9
-rw-r--r--Library/Homebrew/cmd/--config.rb66
-rw-r--r--Library/Homebrew/cmd/--env.rb32
-rw-r--r--Library/Homebrew/cmd/--prefix.rb9
-rw-r--r--Library/Homebrew/cmd/--repository.rb5
-rw-r--r--Library/Homebrew/cmd/cat.rb10
-rw-r--r--Library/Homebrew/cmd/cleanup.rb42
-rw-r--r--Library/Homebrew/cmd/create.rb153
-rw-r--r--Library/Homebrew/cmd/deps.rb14
-rw-r--r--Library/Homebrew/cmd/diy.rb34
-rw-r--r--Library/Homebrew/cmd/doctor.rb (renamed from Library/Homebrew/brew_doctor.rb)4
-rw-r--r--Library/Homebrew/cmd/edit.rb26
-rw-r--r--Library/Homebrew/cmd/home.rb9
-rw-r--r--Library/Homebrew/cmd/info.rb92
-rw-r--r--Library/Homebrew/cmd/install.rb87
-rw-r--r--Library/Homebrew/cmd/link.rb8
-rw-r--r--Library/Homebrew/cmd/list.rb88
-rw-r--r--Library/Homebrew/cmd/log.rb10
-rw-r--r--Library/Homebrew/cmd/outdated.rb28
-rw-r--r--Library/Homebrew/cmd/prune.rb31
-rw-r--r--Library/Homebrew/cmd/search.rb42
-rw-r--r--Library/Homebrew/cmd/uninstall.rb31
-rw-r--r--Library/Homebrew/cmd/unlink.rb8
-rw-r--r--Library/Homebrew/cmd/update.rb (renamed from Library/Homebrew/update.rb)13
-rw-r--r--Library/Homebrew/cmd/uses.rb25
-rw-r--r--Library/Homebrew/compatibility.rb47
-rw-r--r--Library/Homebrew/exceptions.rb99
-rw-r--r--Library/Homebrew/extend/ENV.rb2
-rw-r--r--Library/Homebrew/formula.rb66
-rw-r--r--Library/Homebrew/global.rb10
-rwxr-xr-xLibrary/Homebrew/install.rb5
-rw-r--r--Library/Homebrew/keg.rb4
-rw-r--r--Library/Homebrew/test/test_ENV.rb1
-rw-r--r--Library/Homebrew/test/test_bucket.rb28
-rw-r--r--Library/Homebrew/test/test_external_deps.rb34
-rw-r--r--Library/Homebrew/test/test_formula.rb1
-rw-r--r--Library/Homebrew/test/test_formula_install.rb2
-rw-r--r--Library/Homebrew/test/test_updater.rb2
-rw-r--r--Library/Homebrew/test/testing_env.rb6
-rw-r--r--Library/Homebrew/utils.rb143
-rwxr-xr-xbin/brew345
48 files changed, 1284 insertions, 1238 deletions
diff --git a/Library/Contributions/examples/brew-missing.rb b/Library/Contributions/examples/brew-missing.rb
index 68206278c..701bb1ca2 100755
--- a/Library/Contributions/examples/brew-missing.rb
+++ b/Library/Contributions/examples/brew-missing.rb
@@ -1,21 +1,18 @@
require "formula"
-require 'formula_installer'
+require "cmd/outdated"
def main
# Names of outdated brews; they count as installed.
- outdated = outdated_brews.collect {|b| b[1]}
+ outdated = Homebrew.outdated_brews.collect{ |b| b[1] }
- HOMEBREW_CELLAR.subdirs.each do |keg|
- next unless keg.subdirs
- if ((f = Formula.factory(keg.basename.to_s)).installed? rescue false)
- f_deps = FormulaInstaller.expand_deps(f).collect{|g| g.name}.uniq
- next if f_deps.empty?
-
- missing_deps = f_deps.reject do |dep_name|
+ HOMEBREW_CELLAR.subdirs.each do |rack|
+ f = Formula.factory rack.basename.to_s rescue nil
+ if f and f.installed?
+ missing_deps = f.recursive_deps.map{ |g| g.name }.uniq.reject do |dep_name|
Formula.factory(dep_name).installed? or outdated.include?(dep_name)
end
- puts "#{f.name}: #{missing_deps.join(', ')}" unless missing_deps.empty?
+ puts "#{f.name}: #{missing_deps * ', '}" unless missing_deps.empty?
end
end
end
diff --git a/Library/Contributions/examples/brew-server b/Library/Contributions/examples/brew-server
index b9919cf7a..5e7f80b58 100755
--- a/Library/Contributions/examples/brew-server
+++ b/Library/Contributions/examples/brew-server
@@ -82,7 +82,6 @@ get '/' do
end
get '/search' do
- require 'brew.h'
q = params['q']
results = search_brews(q)
diff --git a/Library/Contributions/examples/brew-upgrade.rb b/Library/Contributions/examples/brew-upgrade.rb
index 6c7831fde..3ffb570ac 100755
--- a/Library/Contributions/examples/brew-upgrade.rb
+++ b/Library/Contributions/examples/brew-upgrade.rb
@@ -1,11 +1,7 @@
# Updates all outdated brews
# See: http://github.com/mxcl/homebrew/issues/issue/1324
-# patch ARGV to use all of the outdated packages as the names passed in
-module HomebrewArgvExtension
- def formulae
- @formulae = outdated_brews.map {|_keg, name, _version| Formula.factory name}
- end
-end
+require 'cmd/outdated'
+require 'cmd/install'
-brew_install
+Homebrew.install_formulae Homebrew.outdated_brews.map{ |_keg, name, _version| Formula.factory name }
diff --git a/Library/Homebrew/beer_events.rb b/Library/Homebrew/beer_events.rb
deleted file mode 100644
index 18d0d0a6c..000000000
--- a/Library/Homebrew/beer_events.rb
+++ /dev/null
@@ -1,199 +0,0 @@
-# Vendored from Rucola: http://github.com/alloy/rucola/tree/master
-#
-# Copyright (c) 2007, 2008, 2009 Eloy Duran <eloy.de.enige@gmail.com>
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation
-# files (the "Software"), to deal in the Software without
-# restriction, including without limitation the rights to use,
-# copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following
-# conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-
-begin
- require 'osx/cocoa'
- OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
-
- module Rucola
- class FSEvents
- class FSEvent
- attr_reader :fsevents_object
- attr_reader :id
- attr_reader :path
- def initialize(fsevents_object, id, path)
- @fsevents_object, @id, @path = fsevents_object, id, path
- end
-
- # Returns an array of the files/dirs in the path that the event occurred in.
- # The files are sorted by the modification time, the first entry is the last modified file.
- def files
- Dir.glob("#{File.expand_path(path)}/*").sort_by {|f| File.mtime(f) }.reverse
- end
-
- # Returns the last modified file in the path that the event occurred in.
- def last_modified_file
- files.first
- end
- end
-
- class StreamError < StandardError; end
-
- attr_reader :paths
- attr_reader :stream
-
- attr_accessor :allocator
- attr_accessor :context
- attr_accessor :since
- attr_accessor :latency
- attr_accessor :flags
-
- # Initializes a new FSEvents `watchdog` object and starts watching the directories you specify for events. The
- # block is used as a handler for events, which are passed as the block's argument. This method is the easiest
- # way to start watching some directories if you don't care about the details of setting up the event stream.
- #
- # Rucola::FSEvents.start_watching('/tmp') do |events|
- # events.each { |event| log.debug("#{event.files.inspect} were changed.") }
- # end
- #
- # Rucola::FSEvents.start_watching('/var/log/system.log', '/var/log/secure.log', :since => last_id, :latency => 5) do
- # Growl.notify("Something was added to your log files!")
- # end
- #
- # Note that the method also returns the FSEvents object. This enables you to control the event stream if you want to.
- #
- # fsevents = Rucola::FSEvents.start_watching('/Volumes') do |events|
- # events.each { |event| Growl.notify("Volume changes: #{event.files.to_sentence}") }
- # end
- # fsevents.stop
- def self.start_watching(*params, &block)
- fsevents = new(*params, &block)
- fsevents.create_stream
- fsevents.start
- fsevents
- end
-
- # Creates a new FSEvents `watchdog` object. You can specify a list of paths to watch and options to control the
- # behaviour of the watchdog. The block you pass serves as a callback when an event is generated on one of the
- # specified paths.
- #
- # fsevents = FSEvents.new('/etc/passwd') { Mailer.send_mail("Someone touched the password file!") }
- # fsevents.create_stream
- # fsevents.start
- #
- # fsevents = FSEvents.new('/home/upload', :since => UploadWatcher.last_event_id) do |events|
- # events.each do |event|
- # UploadWatcher.last_event_id = event.id
- # event.files.each do |file|
- # UploadWatcher.logfile.append("#{file} was changed")
- # end
- # end
- # end
- #
- # *:since: The service will report events that have happened after the supplied event ID. Never use 0 because that
- # will cause every fsevent since the "beginning of time" to be reported. Use OSX::KFSEventStreamEventIdSinceNow
- # if you want to receive events that have happened after this call. (Default: OSX::KFSEventStreamEventIdSinceNow).
- # You can find the ID's passed with :since in the events passed to your block.
- # *:latency: Number of seconds to wait until an FSEvent is reported, this allows the service to bundle events. (Default: 0.0)
- #
- # Please refer to the Cocoa documentation for the rest of the options.
- def initialize(*params, &block)
- raise ArgumentError, 'No callback block was specified.' unless block_given?
-
- options = params.last.kind_of?(Hash) ? params.pop : {}
- @paths = params.flatten
-
- paths.each { |path| raise ArgumentError, "The specified path (#{path}) does not exist." unless File.exist?(path) }
-
- @allocator = options[:allocator] || OSX::KCFAllocatorDefault
- @context = options[:context] || nil
- @since = options[:since] || OSX::KFSEventStreamEventIdSinceNow
- @latency = options[:latency] || 0.0
- @flags = options[:flags] || 0
- @stream = options[:stream] || nil
-
- @user_callback = block
- @callback = Proc.new do |stream, client_callback_info, number_of_events, paths_pointer, event_flags, event_ids|
- paths_pointer.regard_as('*')
- events = []
- number_of_events.times {|i| events << Rucola::FSEvents::FSEvent.new(self, event_ids[i], paths_pointer[i]) }
- @user_callback.call(events)
- end
- end
-
- # Create the stream.
- # Raises a Rucola::FSEvents::StreamError if the stream could not be created.
- def create_stream
- @stream = OSX.FSEventStreamCreate(@allocator, @callback, @context, @paths, @since, @latency, @flags)
- raise(StreamError, 'Unable to create FSEvents stream.') unless @stream
- OSX.FSEventStreamScheduleWithRunLoop(@stream, OSX.CFRunLoopGetCurrent, OSX::KCFRunLoopDefaultMode)
- end
-
- # Start the stream.
- # Raises a Rucola::FSEvents::StreamError if the stream could not be started.
- def start
- raise(StreamError, 'Unable to start FSEvents stream.') unless OSX.FSEventStreamStart(@stream)
- end
-
- # Stop the stream.
- # You can resume it by calling `start` again.
- def stop
- OSX.FSEventStreamStop(@stream)
- end
- end
- end
-
- # The complete BeerEvents API :)
- HOMEBREW_KEEP_DRY = %w{ /System /usr /etc /sbin /bin /Applications /Library }
-
- def watch_out_for_spill
- # Disable the RubyCocoa thread hook as apparently Laurent did not apply the
- # thread patches to the OS X system Ruby
- ENV['RUBYCOCOA_THREAD_HOOK_DISABLE'] = 'kampai'
-
- Thread.new { OSX.CFRunLoopRun() }
-
- start = Time.now
- dog = Rucola::FSEvents.start_watching(*HOMEBREW_KEEP_DRY) do |events|
- spill = events.map { |e| e.files }.flatten
- spill.reject! { |f| File.mtime(f) < start }
- spill.reject! { |path| path =~ /^#{HOMEBREW_PREFIX}/ }
- # irrelevent files that change a lot
- spill.reject! { |path| path == "/Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist-lock" }
- spill.reject! { |path| path =~ %r{^(/System)?/Library/Caches/} }
- unless spill.empty?
- opoo "Detected installation of files outside the Homebrew prefix:"
- puts *spill
- end
- end
- yield
- ensure
- dog.stop
- end
-rescue LoadError => e
- onoe "RubyCocoa could not be loaded, therefore checking for spill is disabled."
- puts "When using a custom Ruby installation, you'll need to install RubyCocoa."
- puts "If this is not the case, see if the following ticket applies, or create one."
- puts " http://github.com/mxcl/homebrew/issues#issue/37"
-
- if ARGV.verbose?
- onoe e.message
- puts e.backtrace
- end
-
- def watch_out_for_spill
- yield
- end
-end \ No newline at end of file
diff --git a/Library/Homebrew/brew.h.rb b/Library/Homebrew/brew.h.rb
deleted file mode 100644
index c4bfd1de1..000000000
--- a/Library/Homebrew/brew.h.rb
+++ /dev/null
@@ -1,600 +0,0 @@
-FORMULA_META_FILES = %w[README README.md ChangeLog COPYING LICENSE LICENCE COPYRIGHT AUTHORS]
-PLEASE_REPORT_BUG = "#{Tty.white}Please follow the instructions to report this bug at: #{Tty.em}\nhttps://github.com/mxcl/homebrew/wiki/new-issue#{Tty.reset}"
-
-def check_for_blacklisted_formula names
- return if ARGV.force?
-
- names.each do |name|
- case name
- when 'tex', 'tex-live', 'texlive' then abort <<-EOS.undent
- Installing TeX from source is weird and gross, requires a lot of patches,
- and only builds 32-bit (and thus can't use Homebrew deps on Snow Leopard.)
-
- We recommend using a MacTeX distribution:
- http://www.tug.org/mactex/
- EOS
-
- when 'mercurial', 'hg' then abort <<-EOS.undent
- Mercurial can be install thusly:
- brew install pip && pip install mercurial
- EOS
-
- when 'npm' then abort <<-EOS.undent
- npm can be installed thusly by following the instructions at
- http://npmjs.org/
-
- To do it in one line, use this command:
- curl http://npmjs.org/install.sh | sh
- EOS
-
-
- when 'setuptools' then abort <<-EOS.undent
- When working with a Homebrew-built Python, distribute is preferred
- over setuptools, and can be used as the prerequisite for pip.
-
- Install distribute using:
- brew install distribute
- EOS
- end
- end
-end
-
-def __make url, name
- require 'formula'
- require 'digest'
- require 'erb'
-
- path = Formula.path(name)
- raise "#{path} already exists" if path.exist?
-
- if Formula.aliases.include? name and not ARGV.force?
- realname = Formula.resolve_alias(name)
- raise <<-EOS.undent
- "#{name}" is an alias for formula "#{realname}".
- Please check that you are not creating a duplicate.
- To force creation use --force.
- EOS
- end
-
- if ARGV.include? '--cmake'
- mode = :cmake
- elsif ARGV.include? '--autotools'
- mode = :autotools
- else
- mode = nil
- end
-
- version = Pathname.new(url).version
- if version.nil?
- opoo "Version cannot be determined from URL."
- puts "You'll need to add an explicit 'version' to the formula."
- else
- puts "Version detected as #{version}."
- end
-
- md5 = ''
- if ARGV.include? "--cache" and version != nil
- strategy = detect_download_strategy url
- if strategy == CurlDownloadStrategy
- d = strategy.new url, name, version, nil
- the_tarball = d.fetch
- md5 = the_tarball.md5
- puts "MD5 is #{md5}"
- else
- puts "--cache requested, but we can only cache formulas that use Curl."
- end
- end
-
- formula_template = <<-EOS
-require 'formula'
-
-class #{Formula.class_s name} <Formula
- url '#{url}'
- homepage ''
- md5 '#{md5}'
-
-<% if mode == :cmake %>
- depends_on 'cmake'
-<% elsif mode == nil %>
- # depends_on 'cmake'
-<% end %>
-
- def install
-<% if mode == :cmake %>
- system "cmake . \#{std_cmake_parameters}"
-<% elsif mode == :autotools %>
- system "./configure", "--disable-debug", "--disable-dependency-tracking",
- "--prefix=\#{prefix}"
-<% else %>
- system "./configure", "--disable-debug", "--disable-dependency-tracking",
- "--prefix=\#{prefix}"
- # system "cmake . \#{std_cmake_parameters}"
-<% end %>
- system "make install"
- end
-end
- EOS
-
- path.write(ERB.new(formula_template, nil, '>').result(binding))
- return path
-end
-
-def make url
- path = Pathname.new url
-
- /(.*?)[-_.]?#{path.version}/.match path.basename
-
- unless $1.to_s.empty?
- name = $1
- else
- print "Formula name [#{path.stem}]: "
- gots = $stdin.gets.chomp
- if gots.empty?
- name = path.stem
- else
- name = gots
- end
- end
-
- force_text = "If you really want to make this formula use --force."
-
- case name.downcase
- when 'vim', 'screen'
- raise <<-EOS
-#{name} is blacklisted for creation
-Apple distributes this program with OS X.
-
-#{force_text}
- EOS
- when 'libarchive', 'libpcap'
- raise <<-EOS
-#{name} is blacklisted for creation
-Apple distributes this library with OS X, you can find it in /usr/lib.
-
-#{force_text}
- EOS
- when 'libxml', 'libxlst', 'freetype', 'libpng'
- raise <<-EOS
-#{name} is blacklisted for creation
-Apple distributes this library with OS X, you can find it in /usr/X11/lib.
-However not all build scripts look here, so you may need to call ENV.x11 or
-ENV.libxml2 in your formula's install function.
-
-#{force_text}
- EOS
- when 'rubygem'
- raise "Sorry RubyGems comes with OS X so we don't package it.\n\n#{force_text}"
- when 'wxwidgets'
- raise <<-EOS
-#{name} is blacklisted for creation
-An older version of wxWidgets is provided by Apple with OS X, but
-a formula for wxWidgets 2.8.10 is provided:
-
- brew install wxmac
-
- #{force_text}
- EOS
- end unless ARGV.force?
-
- __make url, name
-end
-
-def github_info name
- formula_name = Formula.path(name).basename
- user = 'mxcl'
- branch = 'master'
-
- if system "/usr/bin/which -s git"
- gh_user=`git config --global github.user 2>/dev/null`.chomp
- /^\*\s*(.*)/.match(`git --work-tree=#{HOMEBREW_REPOSITORY} branch 2>/dev/null`)
- unless $1.nil? || $1.empty? || gh_user.empty?
- branch = $1.chomp
- user = gh_user
- end
- end
-
- return "http://github.com/#{user}/homebrew/commits/#{branch}/Library/Formula/#{formula_name}"
-end
-
-def info f
- exec 'open', github_info(f.name) if ARGV.flag? '--github'
-
- puts "#{f.name} #{f.version}"
- puts f.homepage
-
- puts "Depends on: #{f.deps.join(', ')}" unless f.deps.empty?
-
- if f.prefix.parent.directory?
- kids=f.prefix.parent.children
- kids.each do |keg|
- next if keg.basename.to_s == '.DS_Store'
- print "#{keg} (#{keg.abv})"
- print " *" if f.installed_prefix == keg and kids.length > 1
- puts
- end
- else
- puts "Not installed"
- end
-
- if f.caveats
- puts
- puts f.caveats
- puts
- end
-
- history = github_info(f.name)
- puts history if 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 issues_for_formula name
- # bit basic as depends on the issue at github having the exact name of the
- # formula in it. Which for stuff like objective-caml is unlikely. So we
- # really should search for aliases too.
-
- name = f.name if Formula === name
-
- require 'open-uri'
- require 'yaml'
-
- issues = []
-
- open("http://github.com/api/v2/yaml/issues/search/mxcl/homebrew/open/"+name) do |f|
- YAML::load(f.read)['issues'].each do |issue|
- issues << 'http://github.com/mxcl/homebrew/issues/#issue/%s' % issue['number']
- end
- end
-
- issues
-rescue
- []
-end
-
-def cleanup name
- require 'formula'
-
- f = Formula.factory name
- formula_cellar = f.prefix.parent
-
- if f.installed? and formula_cellar.directory?
- kids = f.prefix.parent.children
- kids.each do |keg|
- next if f.installed_prefix == keg
- print "Uninstalling #{keg}..."
- FileUtils.rm_rf keg
- puts
- end
- else
- # If the cellar only has one version installed, don't complain
- # that we can't tell which one to keep.
- if formula_cellar.children.length > 1
- opoo "Skipping #{name}: most recent version #{f.version} not installed"
- end
- end
-end
-
-def clean f
- require 'cleaner'
- Cleaner.new f
-
- # Hunt for empty folders and nuke them unless they are
- # protected by f.skip_clean?
- # We want post-order traversal, so put the dirs in a stack
- # and then pop them off later.
- paths = []
- f.prefix.find do |path|
- paths << path if path.directory?
- end
-
- until paths.empty? do
- d = paths.pop
- if d.children.empty? and not f.skip_clean? d
- puts "rmdir: #{d} (empty)" if ARGV.verbose?
- d.rmdir
- end
- end
-end
-
-
-def prune
- $n=0
- $d=0
-
- dirs=Array.new
- paths=%w[bin sbin 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<<path
- end
- end
- end
-
- dirs.sort.reverse_each {|d| d.rmdir_if_possible}
-
- if $n == 0 and $d == 0
- puts "Nothing pruned" if ARGV.verbose?
- else
- # always showing symlinks text is deliberate
- print "Pruned #{$n} symbolic links "
- print "and #{$d} directories " if $d > 0
- puts "from #{HOMEBREW_PREFIX}"
- end
-end
-
-
-def diy
- path=Pathname.getwd
-
- if ARGV.include? '--set-version'
- version=ARGV.next
- else
- version=path.version
- raise "Couldn't determine version, try --set-version" if version.to_s.empty?
- end
-
- if ARGV.include? '--set-name'
- name=ARGV.next
- else
- path.basename.to_s =~ /(.*?)-?#{version}/
- if $1.nil? or $1.empty?
- name=path.basename
- else
- name=$1
- end
- end
-
- prefix=HOMEBREW_CELLAR+name+version
-
- if File.file? 'CMakeLists.txt'
- "-DCMAKE_INSTALL_PREFIX=#{prefix}"
- elsif File.file? 'Makefile.am'
- "--prefix=#{prefix}"
- else
- raise "Couldn't determine build system"
- end
-end
-
-def macports_or_fink_installed?
- # See these issues for some history:
- # http://github.com/mxcl/homebrew/issues/#issue/13
- # http://github.com/mxcl/homebrew/issues/#issue/41
- # http://github.com/mxcl/homebrew/issues/#issue/48
-
- %w[port fink].each do |ponk|
- path = `/usr/bin/which -s #{ponk}`
- return ponk unless path.empty?
- end
-
- # we do the above check because macports can be relocated and fink may be
- # able to be relocated in the future. This following check is because if
- # fink and macports are not in the PATH but are still installed it can
- # *still* break the build -- because some build scripts hardcode these paths:
- %w[/sw/bin/fink /opt/local/bin/port].each do |ponk|
- return ponk if File.exist? ponk
- end
-
- # finally, sometimes people make their MacPorts or Fink read-only so they
- # can quickly test Homebrew out, but still in theory obey the README's
- # advise to rename the root directory. This doesn't work, many build scripts
- # error out when they try to read from these now unreadable directories.
- %w[/sw /opt/local].each do |path|
- path = Pathname.new(path)
- return path if path.exist? and not path.readable?
- end
-
- false
-end
-
-def versions_of(keg_name)
- `/bin/ls #{HOMEBREW_CELLAR}/#{keg_name}`.collect { |version| version.strip }.reverse
-end
-
-
-def outdated_brews
- require 'formula'
-
- results = []
- HOMEBREW_CELLAR.subdirs.each do |keg|
- # Skip kegs with no versions installed
- next unless keg.subdirs
-
- # Skip HEAD formulae, consider them "evergreen"
- next if keg.subdirs.collect{|p|p.basename.to_s}.include? "HEAD"
-
- name = keg.basename.to_s
- if (not (f = Formula.factory(name)).installed? rescue nil)
- results << [keg, name, f.version]
- end
- end
- return results
-end
-
-def search_brews text
- require "formula"
-
- return Formula.names if text.to_s.empty?
-
- rx = if text =~ %r{^/(.*)/$}
- Regexp.new($1)
- else
- /.*#{Regexp.escape text}.*/i
- end
-
- aliases = Formula.aliases
- results = (Formula.names+aliases).grep rx
-
- # Filter out aliases when the full name was also found
- results.reject do |alias_name|
- if aliases.include? alias_name
- results.include? Formula.resolve_alias(alias_name)
- end
- end
-end
-
-def brew_install
- 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.\n"+
- "For PPC support, see: http://github.com/sceaga/homebrew/tree/powerpc"
- 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.3" if llvm_build < RECOMMENDED_LLVM
- else
- opoo "You should upgrade to Xcode 3.1.4" if (gcc_40_build < RECOMMENDED_GCC_40) or (gcc_42_build < RECOMMENDED_GCC_42)
- 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 "Software installed with MacPorts and Fink are known to cause problems."
- puts "If you experience issues 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
-end
-
-########################################################## class PrettyListing
-class PrettyListing
- def initialize path
- Pathname.new(path).children.sort{ |a,b| a.to_s.downcase <=> b.to_s.downcase }.each do |pn|
- case pn.basename.to_s
- when 'bin', 'sbin'
- pn.find { |pnn| puts pnn unless pnn.directory? }
- when 'lib'
- print_dir pn do |pnn|
- # dylibs have multiple symlinks and we don't care about them
- (pnn.extname == '.dylib' or pnn.extname == '.pc') and not pnn.symlink?
- end
- else
- if pn.directory?
- if pn.symlink?
- puts "#{pn} -> #{pn.readlink}"
- else
- print_dir pn
- end
- elsif not (FORMULA_META_FILES.include? pn.basename.to_s or pn.basename.to_s == '.DS_Store')
- puts pn
- end
- end
- end
- end
-
-private
- def print_dir root
- dirs = []
- remaining_root_files = []
- other = ''
-
- root.children.sort.each do |pn|
- if pn.directory?
- dirs << pn
- elsif block_given? and yield pn
- puts pn
- other = 'other '
- else
- remaining_root_files << pn unless pn.basename.to_s == '.DS_Store'
- end
- end
-
- dirs.each do |d|
- files = []
- d.find { |pn| files << pn unless pn.directory? }
- print_remaining_files files, d
- end
-
- print_remaining_files remaining_root_files, root, other
- end
-
- def print_remaining_files files, root, other = ''
- case files.length
- when 0
- # noop
- when 1
- puts files
- else
- puts "#{root}/ (#{files.length} #{other}files)"
- end
- end
-end
-
-
-def gcc_42_build
- `/usr/bin/gcc-4.2 -v 2>&1` =~ /build (\d{4,})/
- if $1
- $1.to_i
- elsif system "/usr/bin/which gcc"
- # Xcode 3.0 didn't come with gcc-4.2
- # We can't change the above regex to use gcc because the version numbers
- # are different and thus, not useful.
- # FIXME I bet you 20 quid this causes a side effect — magic values tend to
- 401
- else
- nil
- end
-end
-alias :gcc_build :gcc_42_build # For compatibility
-
-def gcc_40_build
- `/usr/bin/gcc-4.0 -v 2>&1` =~ /build (\d{4,})/
- if $1
- $1.to_i
- else
- nil
- end
-end
-
-def llvm_build
- if MACOS_VERSION >= 10.6
- xcode_path = `/usr/bin/xcode-select -print-path`.chomp
- return nil if xcode_path.empty?
- `#{xcode_path}/usr/bin/llvm-gcc -v 2>&1` =~ /LLVM build (\d{4,})/
- $1.to_i
- end
-end
-
-def xcode_version
- `xcodebuild -version 2>&1` =~ /Xcode (\d(\.\d)*)/
- return $1 ? $1 : nil
-end
-
-def _compiler_recommendation build, recommended
- message = (!build.nil? && build < recommended) ? "(#{recommended} or newer recommended)" : ""
- return build, message
-end
diff --git a/Library/Homebrew/cleaner.rb b/Library/Homebrew/cleaner.rb
index 84335f8a3..f19efc23b 100644
--- a/Library/Homebrew/cleaner.rb
+++ b/Library/Homebrew/cleaner.rb
@@ -6,6 +6,21 @@ class Cleaner
unless ENV['HOMEBREW_KEEP_INFO'].nil?
f.info.rmtree if f.info.directory? and not f.skip_clean? f.info
end
+
+ # Hunt for empty folders and nuke them unless they are protected by
+ # f.skip_clean? We want post-order traversal, so put the dirs in a stack
+ # and then pop them off later.
+ paths = []
+ f.prefix.find do |path|
+ paths << path if path.directory?
+ end
+
+ paths.each do |d|
+ if d.children.empty? and not f.skip_clean? d
+ puts "rmdir: #{d} (empty)" if ARGV.verbose?
+ d.rmdir
+ end
+ end
end
private
diff --git a/Library/Homebrew/cmd/--cache.rb b/Library/Homebrew/cmd/--cache.rb
new file mode 100644
index 000000000..f0a5b22f2
--- /dev/null
+++ b/Library/Homebrew/cmd/--cache.rb
@@ -0,0 +1,9 @@
+module Homebrew extend self
+ def __cache
+ if ARGV.named.empty?
+ puts HOMEBREW_CACHE
+ else
+ puts ARGV.formulae.map{ |f| f.cached_download }
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/--cellar.rb b/Library/Homebrew/cmd/--cellar.rb
new file mode 100644
index 000000000..c7e140dc5
--- /dev/null
+++ b/Library/Homebrew/cmd/--cellar.rb
@@ -0,0 +1,9 @@
+module Homebrew extend self
+ def __cellar
+ if ARGV.named.empty?
+ puts HOMEBREW_CELLAR
+ else
+ puts ARGV.formulae.map{ |f| HOMEBREW_CELLAR/f }
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/--config.rb b/Library/Homebrew/cmd/--config.rb
new file mode 100644
index 000000000..7a70df007
--- /dev/null
+++ b/Library/Homebrew/cmd/--config.rb
@@ -0,0 +1,66 @@
+require 'hardware'
+
+module Homebrew extend self
+ def __config
+ puts config_s
+ end
+
+ def llvm
+ @llvm ||= MacOS.llvm_build_version
+ end
+
+ def gcc_42
+ @gcc_42 ||= MacOS.gcc_42_build_version
+ end
+
+ def gcc_40
+ @gcc_40 ||= MacOS.gcc_40_build_version
+ end
+
+ def xcode_version
+ `xcodebuild -version 2>&1` =~ /Xcode (\d(\.\d)*)/
+ $1
+ end
+
+ def llvm_recommendation
+ "(#{RECOMMENDED_LLVM} or newer recommended)" if llvm and llvm < RECOMMENDED_LLVM
+ end
+
+ def gcc_42_recommendation
+ "(#{RECOMMENDED_GCC_42} or newer recommended)" if gcc_42 and gcc_42 < RECOMMENDED_GCC_42
+ end
+
+ def gcc_40_recommendation
+ "(#{RECOMMENDED_GCC_40} or newer recommended)" if gcc_40.nil? and gcc_40 < RECOMMENDED_GCC_40
+ end
+
+ def sha
+ sha = `cd #{HOMEBREW_REPOSITORY} && git rev-parse --verify HEAD 2> /dev/null`.chomp
+ if sha.empty? then "(none)" else sha end
+ end
+
+ def system_ruby
+ Pathname.new('/usr/bin/ruby').realpath.to_s
+ end
+
+ def config_s; <<-EOS.undent
+ HOMEBREW_VERSION: #{HOMEBREW_VERSION}
+ HEAD: #{sha}
+ HOMEBREW_PREFIX: #{HOMEBREW_PREFIX}
+ HOMEBREW_CELLAR: #{HOMEBREW_CELLAR}
+ HOMEBREW_REPOSITORY: #{HOMEBREW_REPOSITORY}
+ HOMEBREW_LIBRARY_PATH: #{HOMEBREW_LIBRARY_PATH}
+ Hardware: #{Hardware.cores_as_words}-core #{Hardware.bits}-bit #{Hardware.intel_family}
+ OS X: #{MACOS_FULL_VERSION}
+ Kernel Architecture: #{`uname -m`.chomp}
+ Ruby: #{RUBY_VERSION}-#{RUBY_PATCHLEVEL}
+ /usr/bin/ruby => #{system_ruby}
+ Xcode: #{xcode_version}
+ GCC-4.0: #{gcc_40 ? "build #{gcc_40}" : "N/A"} #{gcc_40_recommendation}
+ GCC-4.2: #{gcc_42 ? "build #{gcc_42}" : "N/A"} #{gcc_42_recommendation}
+ LLVM: #{llvm ? "build #{llvm}" : "N/A" } #{llvm_recommendation}
+ MacPorts or Fink? #{macports_or_fink_installed?}
+ X11 installed? #{x11_installed?}
+ EOS
+ end
+end
diff --git a/Library/Homebrew/cmd/--env.rb b/Library/Homebrew/cmd/--env.rb
new file mode 100644
index 000000000..07623171d
--- /dev/null
+++ b/Library/Homebrew/cmd/--env.rb
@@ -0,0 +1,32 @@
+require 'extend/ENV'
+require 'hardware'
+
+module Homebrew extend self
+ def __env
+ ENV.extend(HomebrewEnvExtension)
+ ENV.setup_build_environment
+ dump_build_env ENV
+ end
+
+ def dump_build_env env
+ puts %["--use-llvm" was specified] if ARGV.include? '--use-llvm'
+
+ %w[ CC CXX LD ].each do |k|
+ value = env[k]
+ if value
+ results = value
+ if File.exists? value and File.symlink? value
+ target = Pathname.new(value)
+ results += " => #{target.realpath}"
+ end
+ puts "#{k}: #{results}"
+ end
+ end
+
+ %w[ CFLAGS CXXFLAGS CPPFLAGS LDFLAGS MACOSX_DEPLOYMENT_TARGET MAKEFLAGS PKG_CONFIG_PATH
+ HOMEBREW_DEBUG HOMEBREW_VERBOSE HOMEBREW_USE_LLVM HOMEBREW_SVN ].each do |k|
+ value = env[k]
+ puts "#{k}: #{value}" if value
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/--prefix.rb b/Library/Homebrew/cmd/--prefix.rb
new file mode 100644
index 000000000..9a15203a9
--- /dev/null
+++ b/Library/Homebrew/cmd/--prefix.rb
@@ -0,0 +1,9 @@
+module Homebrew extend self
+ def __prefix
+ if ARGV.named.empty?
+ puts HOMEBREW_PREFIX
+ else
+ puts ARGV.formulae.map{ |f| f.prefix }
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/--repository.rb b/Library/Homebrew/cmd/--repository.rb
new file mode 100644
index 000000000..f14ab9901
--- /dev/null
+++ b/Library/Homebrew/cmd/--repository.rb
@@ -0,0 +1,5 @@
+module Homebrew extend self
+ def __repository
+ puts HOMEBREW_REPOSITORY
+ end
+end
diff --git a/Library/Homebrew/cmd/cat.rb b/Library/Homebrew/cmd/cat.rb
new file mode 100644
index 000000000..a87eba61e
--- /dev/null
+++ b/Library/Homebrew/cmd/cat.rb
@@ -0,0 +1,10 @@
+module Homebrew extend self
+ def cat
+ # do not "fix" this to support multiple arguments, the output would be
+ # unparsable, if the user wants to cat multiple formula they can call
+ # brew cat multiple times.
+
+ cd HOMEBREW_REPOSITORY
+ exec "cat", ARGV.formulae.first.path, *ARGV.options_only
+ end
+end
diff --git a/Library/Homebrew/cmd/cleanup.rb b/Library/Homebrew/cmd/cleanup.rb
new file mode 100644
index 000000000..f5e4637ec
--- /dev/null
+++ b/Library/Homebrew/cmd/cleanup.rb
@@ -0,0 +1,42 @@
+require 'formula'
+require 'cmd/prune'
+
+module Homebrew extend self
+ def cleanup
+ if ARGV.named.empty?
+ HOMEBREW_CELLAR.children.each do |rack|
+ begin
+ cleanup_formula rack.basename.to_s if rack.directory?
+ rescue FormulaUnavailableError => e
+ opoo "Formula not found for #{e.name}"
+ end
+ end
+ # seems like a good time to do some additional cleanup
+ Homebrew.prune
+ else
+ ARGV.formulae.each do |f|
+ cleanup_formula f
+ end
+ end
+ end
+
+ def cleanup_formula f
+ f = Formula.factory f
+ rack = f.prefix.parent
+
+ if f.installed? and rack.directory?
+ rack.children.each do |keg|
+ if f.installed_prefix != keg
+ print "Uninstalling #{keg}..."
+ rm_rf keg
+ puts
+ end
+ end
+ elsif rack.children.length > 1
+ # If the cellar only has one version installed, don't complain
+ # that we can't tell which one to keep.
+ opoo "Skipping #{name}: most recent version #{f.version} not installed"
+ end
+ end
+
+end
diff --git a/Library/Homebrew/cmd/create.rb b/Library/Homebrew/cmd/create.rb
new file mode 100644
index 000000000..e21c9a524
--- /dev/null
+++ b/Library/Homebrew/cmd/create.rb
@@ -0,0 +1,153 @@
+require 'formula'
+
+module Homebrew extend self
+ def create
+ if ARGV.include? '--macports'
+ exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
+ elsif ARGV.include? '--fink'
+ exec "open", "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
+ elsif ARGV.named.empty?
+ raise UsageError
+ else
+ paths = ARGV.named.map do |url|
+ fc = FormulaCreator.new
+ fc.url = url
+ fc.mode = if ARGV.include? '--cmake'
+ :cmake
+ elsif ARGV.include? '--autotools'
+ :autotools
+ end
+
+ if fc.name.to_s.strip.empty?
+ path = Pathname.new url
+ print "Formula name [#{path.stem}]: "
+ fc.name = __gets || path.stem
+ end
+
+ unless ARGV.force?
+ if msg = blacklisted?(fc.name)
+ raise "#{msg}\n\nIf you really want to make this formula use --force."
+ end
+
+ if Formula.aliases.include? fc.name
+ realname = Formula.caniconical_name fc.name
+ raise <<-EOS.undent
+ The formula #{realname} is already aliased to #{fc.name}
+ Please check that you are not creating a duplicate.
+ To force creation use --force.
+ EOS
+ end
+ end
+ fc.generate
+ fc.path
+ end
+ exec_editor *paths
+ end
+ end
+
+ def __gets
+ gots = $stdin.gets.chomp
+ if gots.empty? then nil else gots end
+ end
+
+ def blacklisted? name
+ case name.downcase
+ when 'vim', 'screen' then <<-EOS.undent
+ #{name} is blacklisted for creation
+ Apple distributes this program with OS X.
+ EOS
+ when 'libarchive', 'libpcap' then <<-EOS.undent
+ #{name} is blacklisted for creation
+ Apple distributes this library with OS X, you can find it in /usr/lib.
+ EOS
+ when 'libxml', 'libxlst', 'freetype', 'libpng' then <<-EOS.undent
+ #{name} is blacklisted for creation
+ Apple distributes this library with OS X, you can find it in /usr/X11/lib.
+ However not all build scripts look here, so you may need to call ENV.x11 or
+ ENV.libxml2 in your formula's install function.
+ EOS
+ when /^rubygems?$/
+ "Sorry RubyGems comes with OS X so we don't package it."
+ when 'wxwidgets' then <<-EOS.undent
+ #{name} is blacklisted for creation
+ An older version of wxWidgets is provided by Apple with OS X, but
+ a formula for wxWidgets 2.8.10 is provided:
+
+ brew install wxmac
+ EOS
+ end
+ end
+end
+
+class FormulaCreator
+ attr :url
+ attr :md5
+ attr :name, true
+ attr :path
+ attr :mode, true
+
+ def url= url
+ @url = url
+ path = Pathname.new url
+ /(.*?)[-_.]?#{path.version}/.match path.basename
+ @name = $1
+ @path = Formula.path $1
+ end
+
+ def version
+ Pathname.new(url).version
+ end
+
+ def generate
+ raise "#{path} already exists" if path.exist?
+ raise VersionUndetermined if version.nil?
+
+ require 'digest'
+ require 'erb'
+
+ if version.nil?
+ opoo "Version cannot be determined from URL."
+ puts "You'll need to add an explicit 'version' to the formula."
+ else
+ puts "Version detected as #{version}."
+ end
+
+ unless ARGV.include? "--no-md5" and version
+ strategy = detect_download_strategy url
+ @md5 = strategy.new(url, name, version, nil).fetch.md5 if strategy == CurlDownloadStrategy
+ end
+
+ path.write ERB.new(template, nil, '>').result(binding)
+ end
+
+ def template; <<-EOS.undent
+ require 'formula'
+
+ class #{Formula.class_s name} <Formula
+ url '#{url}'
+ homepage ''
+ md5 '#{md5}'
+
+ <% if mode == :cmake %>
+ depends_on 'cmake'
+ <% elsif mode == nil %>
+ # depends_on 'cmake'
+ <% end %>
+
+ def install
+ <% if mode == :cmake %>
+ system "cmake . \#{std_cmake_parameters}"
+ <% elsif mode == :autotools %>
+ system "./configure", "--disable-debug", "--disable-dependency-tracking",
+ "--prefix=\#{prefix}"
+ <% else %>
+ system "./configure", "--disable-debug", "--disable-dependency-tracking",
+ "--prefix=\#{prefix}"
+ # system "cmake . \#{std_cmake_parameters}"
+ <% end %>
+ system "make install"
+ end
+ end
+ EOS
+ end
+end
diff --git a/Library/Homebrew/cmd/deps.rb b/Library/Homebrew/cmd/deps.rb
new file mode 100644
index 000000000..2e9a723f4
--- /dev/null
+++ b/Library/Homebrew/cmd/deps.rb
@@ -0,0 +1,14 @@
+module Homebrew extend self
+ def deps
+ puts if ARGV.include?('--all')
+ require 'formula'
+ Formula.all.each do |f|
+ "#{f.name}:#{f.deps.join(' ')}"
+ end
+ elsif ARGV.include?("-1") or ARGV.include?("--1")
+ *ARGV.formulae.map{ |f| f.deps or [] }.flatten.uniq.sort
+ else
+ *ARGV.formulae.map{ |f| f.recursive_deps.map{ |f| f.name } }.flatten.uniq.sort
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/diy.rb b/Library/Homebrew/cmd/diy.rb
new file mode 100644
index 000000000..174626afc
--- /dev/null
+++ b/Library/Homebrew/cmd/diy.rb
@@ -0,0 +1,34 @@
+module Homebrew extend self
+ def diy
+ path = Pathname.getwd
+
+ version = if ARGV.include? '--set-version'
+ ARGV.next
+ elsif path.version.to_s.empty?
+ raise "Couldn't determine version, try --set-version"
+ else
+ path.version
+ end
+
+ name = if ARGV.include? '--set-name'
+ ARGV.next
+ else
+ path.basename.to_s =~ /(.*?)-?#{version}/
+ if $1.to_s.empty?
+ path.basename
+ else
+ $1
+ end
+ end
+
+ prefix = HOMEBREW_CELLAR/name/version
+
+ if File.file? 'CMakeLists.txt'
+ puts "-DCMAKE_INSTALL_PREFIX=#{prefix}"
+ elsif File.file? 'Makefile.am'
+ puts "--prefix=#{prefix}"
+ else
+ raise "Couldn't determine build system"
+ end
+ end
+end
diff --git a/Library/Homebrew/brew_doctor.rb b/Library/Homebrew/cmd/doctor.rb
index b26cd4f5d..bad3a5dc0 100644
--- a/Library/Homebrew/brew_doctor.rb
+++ b/Library/Homebrew/cmd/doctor.rb
@@ -583,7 +583,8 @@ def check_for_other_vars
end
end
-def brew_doctor
+module Homebrew extend self
+def doctor
read, write = IO.pipe
if fork == nil
@@ -629,3 +630,4 @@ def brew_doctor
end
end
end
+end
diff --git a/Library/Homebrew/cmd/edit.rb b/Library/Homebrew/cmd/edit.rb
new file mode 100644
index 000000000..6ab91dccf
--- /dev/null
+++ b/Library/Homebrew/cmd/edit.rb
@@ -0,0 +1,26 @@
+require 'formula'
+
+module Homebrew extend self
+ def 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', HOMEBREW_REPOSITORY/"bin/brew",
+ HOMEBREW_REPOSITORY/'README.md',
+ HOMEBREW_REPOSITORY/".gitignore",
+ *Dir[HOMEBREW_REPOSITORY/"Library/*"]
+ else
+ # Don't use ARGV.formulae as that will throw if the file doesn't parse
+ paths = ARGV.named.map do |name|
+ HOMEBREW_REPOSITORY/"Library/Formula/#{Formula.caniconical_name name}.rb"
+ end
+ unless ARGV.force?
+ paths.each do |path|
+ raise FormulaUnavailableError, path.basename('.rb').to_s unless path.file?
+ end
+ end
+ exec_editor *paths
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/home.rb b/Library/Homebrew/cmd/home.rb
new file mode 100644
index 000000000..a91607988
--- /dev/null
+++ b/Library/Homebrew/cmd/home.rb
@@ -0,0 +1,9 @@
+module Homebrew extend self
+ def home
+ if ARGV.named.empty?
+ exec "open", HOMEBREW_WWW
+ else
+ exec "open", *ARGV.formulae.map{ |f| f.homepage }
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb
new file mode 100644
index 000000000..7f9767e07
--- /dev/null
+++ b/Library/Homebrew/cmd/info.rb
@@ -0,0 +1,92 @@
+require 'formula'
+
+module Homebrew extend self
+ def info
+ if ARGV.named.empty?
+ if ARGV.include? "--all"
+ Formula.each do |f|
+ info_formula f
+ puts '---'
+ end
+ else
+ puts "#{HOMEBREW_CELLAR.children.length} kegs, #{HOMEBREW_CELLAR.abv}"
+ end
+ elsif valid_url ARGV[0]
+ path = Pathname.new(ARGV.shift)
+ /(.*?)[-_.]?#{path.version}/.match path.basename
+ unless $1.to_s.empty?
+ name = $1
+ else
+ name = path.stem
+ end
+ puts "#{name} #{path.version}"
+ else
+ ARGV.formulae.each{ |f| info_formula f }
+ end
+ end
+
+ def github_info name
+ formula_name = Formula.path(name).basename
+ user = 'mxcl'
+ branch = 'master'
+
+ if system "/usr/bin/which -s git"
+ gh_user=`git config --global github.user 2>/dev/null`.chomp
+ /^\*\s*(.*)/.match(`git --work-tree=#{HOMEBREW_REPOSITORY} branch 2>/dev/null`)
+ unless $1.nil? || $1.empty? || gh_user.empty?
+ branch = $1.chomp
+ user = gh_user
+ end
+ end
+
+ "http://github.com/#{user}/homebrew/commits/#{branch}/Library/Formula/#{formula_name}"
+ end
+
+ def info_formula f
+ exec 'open', github_info(f.name) if ARGV.flag? '--github'
+
+ puts "#{f.name} #{f.version}"
+ puts f.homepage
+
+ puts "Depends on: #{f.deps*', '}" unless f.deps.empty?
+
+ rack = f.prefix.parent
+ if rack.directory?
+ kegs = rack.children
+ kegs.each do |keg|
+ next if keg.basename.to_s == '.DS_Store'
+ print "#{keg} (#{keg.abv})"
+ print " *" if f.installed_prefix == keg and kegs.length > 1
+ puts
+ end
+ else
+ puts "Not installed"
+ end
+
+ if f.caveats
+ puts
+ puts f.caveats
+ puts
+ end
+
+ history = github_info f.name
+ puts history if 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
+
+ private
+
+ def valid_url u
+ u[0..6] == 'http://' or u[0..7] == 'https://' or u[0..5] == 'ftp://'
+ end
+
+end
diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb
new file mode 100644
index 000000000..ed5fb6777
--- /dev/null
+++ b/Library/Homebrew/cmd/install.rb
@@ -0,0 +1,87 @@
+require 'formula_installer'
+require 'hardware'
+
+module Homebrew extend self
+ def install
+ brew_install
+ end
+end
+
+def brew_install
+ ############################################################ sanity checks
+ case Hardware.cpu_type when :ppc, :dunno
+ abort "Sorry, Homebrew does not support your computer's CPU architecture.\n"+
+ "For PPC support, see: http://github.com/sceaga/homebrew/tree/powerpc"
+ 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.3" if llvm_build < RECOMMENDED_LLVM
+ else
+ opoo "You should upgrade to Xcode 3.1.4" if (gcc_40_build < RECOMMENDED_GCC_40) or (gcc_42_build < RECOMMENDED_GCC_42)
+ 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 "Software installed with MacPorts and Fink are known to cause problems."
+ puts "If you experience issues 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
+end
+
+def check_for_blacklisted_formula names
+ return if ARGV.force?
+
+ names.each do |name|
+ case name
+ when 'tex', 'tex-live', 'texlive' then abort <<-EOS.undent
+ Installing TeX from source is weird and gross, requires a lot of patches,
+ and only builds 32-bit (and thus can't use Homebrew deps on Snow Leopard.)
+
+ We recommend using a MacTeX distribution:
+ http://www.tug.org/mactex/
+ EOS
+
+ when 'mercurial', 'hg' then abort <<-EOS.undent
+ Mercurial can be install thusly:
+ brew install pip && pip install mercurial
+ EOS
+
+ when 'npm' then abort <<-EOS.undent
+ npm can be installed thusly by following the instructions at
+ http://npmjs.org/
+
+ To do it in one line, use this command:
+ curl http://npmjs.org/install.sh | sudo sh
+ EOS
+
+ when 'setuptools' then abort <<-EOS.undent
+ When working with a Homebrew-built Python, distribute is preferred
+ over setuptools, and can be used as the prerequisite for pip.
+
+ Install distribute using:
+ brew install distribute
+ EOS
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/link.rb b/Library/Homebrew/cmd/link.rb
new file mode 100644
index 000000000..5565309e2
--- /dev/null
+++ b/Library/Homebrew/cmd/link.rb
@@ -0,0 +1,8 @@
+module Homebrew extend self
+ def link
+ ARGV.kegs.each do |keg|
+ print "Linking #{keg}... "
+ puts "#{keg.link} links created"
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/list.rb b/Library/Homebrew/cmd/list.rb
new file mode 100644
index 000000000..8e35530fd
--- /dev/null
+++ b/Library/Homebrew/cmd/list.rb
@@ -0,0 +1,88 @@
+module Homebrew extend self
+ def list
+ if ARGV.flag? '--unbrewed'
+ dirs = HOMEBREW_PREFIX.children.select{ |pn| pn.directory? }.map{ |pn| pn.basename.to_s }
+ dirs -= %w[Library Cellar .git]
+ cd HOMEBREW_PREFIX
+ exec 'find', *dirs + %w[-type f ( ! -iname .ds_store ! -iname brew )]
+ elsif ARGV.flag? '--versions'
+ if ARGV.named.empty?
+ HOMEBREW_CELLAR.children.select{ |pn| pn.directory? }
+ else
+ ARGV.named.map{ |n| HOMEBREW_CELLAR/n }.select{ |pn| pn.exist? }
+ end.each do |d|
+ versions = d.children.select{ |pn| pn.directory? }.map{ |pn| pn.basename.to_s }
+ puts "#{d.basename} #{versions*' '}"
+ end
+ elsif ARGV.named.empty?
+ ENV['CLICOLOR'] = nil
+ exec 'ls', *ARGV.options_only << 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
+ end
+end
+
+class PrettyListing
+ def initialize path
+ Pathname.new(path).children.sort{ |a,b| a.to_s.downcase <=> b.to_s.downcase }.each do |pn|
+ case pn.basename.to_s
+ when 'bin', 'sbin'
+ pn.find { |pnn| puts pnn unless pnn.directory? }
+ when 'lib'
+ print_dir pn do |pnn|
+ # dylibs have multiple symlinks and we don't care about them
+ (pnn.extname == '.dylib' or pnn.extname == '.pc') and not pnn.symlink?
+ end
+ else
+ if pn.directory?
+ if pn.symlink?
+ puts "#{pn} -> #{pn.readlink}"
+ else
+ print_dir pn
+ end
+ elsif not (FORMULA_META_FILES + ['.DS_Store']).include? pn.basename.to_s
+ puts pn
+ end
+ end
+ end
+ end
+
+ def print_dir root
+ dirs = []
+ remaining_root_files = []
+ other = ''
+
+ root.children.sort.each do |pn|
+ if pn.directory?
+ dirs << pn
+ elsif block_given? and yield pn
+ puts pn
+ other = 'other '
+ else
+ remaining_root_files << pn unless pn.basename.to_s == '.DS_Store'
+ end
+ end
+
+ dirs.each do |d|
+ files = []
+ d.find { |pn| files << pn unless pn.directory? }
+ print_remaining_files files, d
+ end
+
+ print_remaining_files remaining_root_files, root, other
+ end
+
+ def print_remaining_files files, root, other = ''
+ case files.length
+ when 0
+ # noop
+ when 1
+ puts files
+ else
+ puts "#{root}/ (#{files.length} #{other}files)"
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/log.rb b/Library/Homebrew/cmd/log.rb
new file mode 100644
index 000000000..ceb0c8e02
--- /dev/null
+++ b/Library/Homebrew/cmd/log.rb
@@ -0,0 +1,10 @@
+module Homebrew extend self
+ def log
+ cd HOMEBREW_REPOSITORY
+ if ARGV.named.empty?
+ exec "git", "log", *ARGV.options_only
+ else
+ exec "git", "log", *ARGV.formulae.map(&:path), *ARGV.options_only
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb
new file mode 100644
index 000000000..37fba0f99
--- /dev/null
+++ b/Library/Homebrew/cmd/outdated.rb
@@ -0,0 +1,28 @@
+require 'formula'
+
+module Homebrew extend self
+ def outdated
+ outdated_brews.each do |keg, name, version|
+ if $stdout.tty? and not ARGV.flag? '--quiet'
+ versions = keg.cd{ Dir['*'] }.join(', ')
+ puts "#{name} (#{versions} < #{version})"
+ else
+ puts name
+ end
+ end
+ end
+
+ def outdated_brews
+ HOMEBREW_CELLAR.subdirs.map do |rack|
+ # Skip kegs with no versions installed
+ next unless rack.subdirs
+
+ # Skip HEAD formulae, consider them "evergreen"
+ next if rack.subdirs.map{ |keg| keg.basename.to_s }.include? "HEAD"
+
+ name = rack.basename.to_s
+ f = Formula.factory name rescue nil
+ [rack, name, f.version] if f and not f.installed?
+ end.compact
+ end
+end \ No newline at end of file
diff --git a/Library/Homebrew/cmd/prune.rb b/Library/Homebrew/cmd/prune.rb
new file mode 100644
index 000000000..ba4bbc8e5
--- /dev/null
+++ b/Library/Homebrew/cmd/prune.rb
@@ -0,0 +1,31 @@
+module Homebrew extend self
+ # $n and $d are used by the ObserverPathnameExtension to keep track of
+ # certain filesystem actions.
+
+ def prune
+ $n = 0
+ $d = 0
+ dirs = []
+
+ %w[bin sbin etc lib include share].map{ |d| HOMEBREW_PREFIX/d }.each do |path|
+ path.find do |path|
+ path.extend ObserverPathnameExtension
+ if path.symlink?
+ path.unlink unless path.resolved_path_exists?
+ elsif path.directory?
+ dirs << path
+ end
+ end
+ end
+
+ dirs.sort.reverse_each{ |d| d.rmdir_if_possible }
+
+ if $n == 0 and $d == 0
+ puts "Nothing pruned" if ARGV.verbose?
+ else
+ print "Pruned #{$n} symbolic links "
+ print "and #{$d} directories " if $d > 0
+ puts "from #{HOMEBREW_PREFIX}"
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb
new file mode 100644
index 000000000..b6a0e971d
--- /dev/null
+++ b/Library/Homebrew/cmd/search.rb
@@ -0,0 +1,42 @@
+require "formula"
+
+module Homebrew extend self
+ def search
+ if ARGV.include? '--macports'
+ exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
+ elsif ARGV.include? '--fink'
+ exec "open", "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
+ end
+
+ require 'cmd/install' # for blacklisted? function
+ blacklisted? ARGV.named do |msg, _|
+ abort msg
+ end unless ARGV.force?
+
+ puts_columns search_brews(ARGV.first)
+ end
+
+ def search_brews text
+ if text.to_s.empty?
+ Formula.names
+ else
+ rx = if text =~ %r{^/(.*)/$}
+ Regexp.new($1)
+ else
+ /.*#{Regexp.escape text}.*/i
+ end
+
+ aliases = Formula.aliases
+ results = (Formula.names+aliases).grep rx
+
+ # Filter out aliases when the full name was also found
+ results.reject do |alias_name|
+ if aliases.include? alias_name
+ resolved_name = (HOMEBREW_REPOSITORY/"Library/Aliases"/alias_name).readlink.basename('.rb').to_s
+ results.include? resolved_name
+ end
+ end
+ end
+ end
+
+end
diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb
new file mode 100644
index 000000000..34de88130
--- /dev/null
+++ b/Library/Homebrew/cmd/uninstall.rb
@@ -0,0 +1,31 @@
+require 'keg'
+
+module Homebrew extend self
+ def uninstall
+ unless ARGV.force?
+ ARGV.kegs.each do |keg|
+ puts "Uninstalling #{keg}..."
+ keg.unlink
+ keg.uninstall
+ end
+ else
+ ARGV.formulae.each do |f|
+ rack = f.prefix.parent
+ if rack.directory?
+ puts "Uninstalling #{f}..."
+ rack.children do |keg|
+ if keg.directory?
+ keg = Keg.new(keg)
+ keg.unlink
+ keg.rmtree
+ end
+ end
+ rack.rmdir
+ end
+ end
+ end
+ rescue MultipleVersionsInstalledError => e
+ onoe e
+ puts "Use `brew remove --force #{e.name}` to remove all versions."
+ end
+end
diff --git a/Library/Homebrew/cmd/unlink.rb b/Library/Homebrew/cmd/unlink.rb
new file mode 100644
index 000000000..d4749ab76
--- /dev/null
+++ b/Library/Homebrew/cmd/unlink.rb
@@ -0,0 +1,8 @@
+module Homebrew extend self
+ def unlink
+ ARGV.kegs.each do |keg|
+ print "Unlinking #{keg}... "
+ puts "#{keg.unlink} links removed"
+ end
+ end
+end
diff --git a/Library/Homebrew/update.rb b/Library/Homebrew/cmd/update.rb
index 9e4fb90d9..32f144c8e 100644
--- a/Library/Homebrew/update.rb
+++ b/Library/Homebrew/cmd/update.rb
@@ -1,3 +1,16 @@
+module Homebrew extend self
+ def update
+ abort "Please `brew install git' first." unless system "/usr/bin/which -s git"
+
+ updater = RefreshBrew.new
+ if updater.update_from_masterbrew!
+ updater.report
+ else
+ puts "Already up-to-date."
+ end
+ end
+end
+
class RefreshBrew
REPOSITORY_URL = "http://github.com/mxcl/homebrew.git"
INIT_COMMAND = "git init"
diff --git a/Library/Homebrew/cmd/uses.rb b/Library/Homebrew/cmd/uses.rb
new file mode 100644
index 000000000..455b29b31
--- /dev/null
+++ b/Library/Homebrew/cmd/uses.rb
@@ -0,0 +1,25 @@
+require 'formula'
+
+# `brew uses foo bar` now returns formula that use both foo and bar
+# Rationale: If you want the union just run the command twice and
+# concatenate the results.
+# The intersection is harder to achieve with shell tools.
+
+module Homebrew extend self
+ def uses
+ uses = Formula.all.select do |f|
+ ARGV.formulae.all? do |ff|
+ # For each formula given, show which other formulas depend on it.
+ # We only go one level up, ie. direct dependencies.
+ f.deps.include? ff.name
+ end
+ end
+ if ARGV.include? "--installed"
+ uses = uses.select do |f|
+ keg = HOMEBREW_CELLAR/f
+ keg.directory? and not keg.subdirs.empty?
+ end
+ end
+ puts uses.sort
+ end
+end
diff --git a/Library/Homebrew/compatibility.rb b/Library/Homebrew/compatibility.rb
new file mode 100644
index 000000000..52f98416a
--- /dev/null
+++ b/Library/Homebrew/compatibility.rb
@@ -0,0 +1,47 @@
+
+# maybe never used by anyone, but alas it must continue to exist
+def versions_of(keg_name)
+ `/bin/ls #{HOMEBREW_CELLAR}/#{keg_name}`.collect { |version| version.strip }.reverse
+end
+
+def dump_config
+ require 'cmd/--config'
+ Homebrew.__config
+end
+
+def dump_build_env env
+ require 'cmd/--env'
+ Homebrew.dump_build_env env
+end
+
+def gcc_42_build
+ MacOS.gcc_42_build_version
+end
+
+alias :gcc_build :gcc_42_build
+
+def gcc_40_build
+ MacOS.gcc_40_build_version
+end
+
+def llvm_build
+ MacOS.llvm_build_version
+end
+
+def x11_installed?
+ MacOS.x11_installed?
+end
+
+def macports_or_fink_installed?
+ MacOS.macports_or_fink_installed?
+end
+
+def outdated_brews
+ require 'cmd/outdated'
+ Homebrew.outdated_brews
+end
+
+def search_brews text
+ require 'cmd/search'
+ Homebrew.search_brews text
+end
diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb
new file mode 100644
index 000000000..73cda01e5
--- /dev/null
+++ b/Library/Homebrew/exceptions.rb
@@ -0,0 +1,99 @@
+
+class NotAKegError < RuntimeError
+end
+
+class FormulaUnavailableError < RuntimeError
+ attr :name
+ def initialize name
+ @name = name
+ super "No available formula for #{name}"
+ end
+end
+
+module Homebrew
+ class InstallationError < RuntimeError
+ attr :formula
+ def initialize formula
+ @formula = formula
+ end
+ def initialize formula, message
+ super message
+ @formula = formula
+ end
+ end
+end
+
+class FormulaAlreadyInstalledError < Homebrew::InstallationError
+ def message
+ "Formula already installed: #{formula}"
+ end
+end
+
+class FormulaInstallationAlreadyAttemptedError < Homebrew::InstallationError
+ def message
+ "Formula installation already attempted: #{formula}"
+ end
+end
+
+class UnsatisfiedExternalDependencyError < Homebrew::InstallationError
+ attr :type
+
+ def initialize formula, type
+ @type = type
+ @formula = formula
+ end
+
+ def message
+ <<-EOS.undent
+ Unsatisfied dependency: #{formula}
+ Homebrew does not provide #{type.to_s.capitalize} dependencies, #{tool} does:
+
+ #{command_line} #{formula}
+ EOS
+ end
+
+ private
+
+ def tool
+ case type
+ when :python then 'pip'
+ when :ruby, :jruby then 'rubygems'
+ when :perl then 'cpan'
+ end
+ end
+
+ def command_line
+ case type
+ when :python
+ "#{brew_pip}pip install"
+ when :ruby
+ "gem install"
+ when :perl
+ "cpan -i"
+ when :jruby
+ "jruby -S gem install"
+ end
+ end
+
+ def brew_pip
+ 'brew install pip && ' unless Formula.factory('pip').installed?
+ end
+end
+
+class BuildError < Homebrew::InstallationError
+ attr :exit_status
+ attr :command
+ attr :env
+
+ def initialize formula, cmd, args, es
+ @command = cmd
+ @env = ENV.to_hash
+ @exit_status = es.exitstatus rescue 1
+ args = args.map{ |arg| arg.gsub " ", "\\ " }.join(" ")
+ super formula, "Failed executing: #{command} #{args}"
+ end
+
+ def was_running_configure?
+ @command == './configure'
+ end
+end
diff --git a/Library/Homebrew/extend/ENV.rb b/Library/Homebrew/extend/ENV.rb
index 61fb3c2b3..a4e290d5f 100644
--- a/Library/Homebrew/extend/ENV.rb
+++ b/Library/Homebrew/extend/ENV.rb
@@ -152,7 +152,7 @@ module HomebrewEnvExtension
end
def x11
- opoo "You do not have X11 installed, this formula may not build." if not x11_installed?
+ opoo "You do not have X11 installed, this formula may not build." if not MacOS.x11_installed?
# There are some config scripts (e.g. freetype) here that should go in the path
prepend 'PATH', '/usr/X11/bin', ':'
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 0e3266351..78e438726 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -1,15 +1,6 @@
require 'download_strategy'
require 'fileutils'
-class FormulaUnavailableError <RuntimeError
- def initialize name
- @name = name
- super "No available formula for #{name}"
- end
-
- attr_reader :name
-end
-
class SoftwareSpecification
attr_reader :url, :specs, :using
@@ -223,6 +214,22 @@ class Formula
end
end
+ def == b
+ name == b.name
+ end
+ def eql? b
+ self == b and self.class.equal? b.class
+ end
+ def hash
+ name.hash
+ end
+ def <=> b
+ name <=> b.name
+ end
+ def to_s
+ name
+ end
+
# Standard parameters for CMake builds.
# Using Build Type "None" tells cmake to use our CFLAGS,etc. settings.
# Setting it to Release would ignore our flags.
@@ -266,15 +273,25 @@ class Formula
# an array of all Formula, instantiated
def self.all
- all = []
+ map{ |f| f }
+ end
+ def self.map
+ rv = []
+ each{ |f| rv << yield(f) }
+ rv
+ end
+ def self.each
names.each do |n|
begin
- all << Formula.factory(n)
+ yield Formula.factory(n)
rescue
# Don't let one broken formula break commands.
end
end
- return all
+ end
+
+ def inspect
+ name
end
def self.aliases
@@ -320,8 +337,9 @@ class Formula
install_type = :from_path
target_file = path.to_s
else
+ name = Formula.caniconical_name(name)
# For names, map to the path and then require
- require self.path(name)
+ require Formula.path(name)
install_type = :from_name
end
end
@@ -344,7 +362,7 @@ class Formula
end
def self.path name
- HOMEBREW_REPOSITORY+"Library/Formula/#{name.downcase}.rb"
+ HOMEBREW_REPOSITORY/"Library/Formula/#{name.downcase}.rb"
end
def deps
@@ -352,7 +370,20 @@ class Formula
end
def external_deps
- self.class.external_deps
+ self.class.external_deps or {}
+ end
+
+ # deps are in an installable order
+ # which means if a depends on b then b will be ordered before a in this list
+ def recursive_deps
+ Formula.expand_deps(self).flatten.uniq
+ end
+
+ def self.expand_deps f
+ f.deps.map do |dep|
+ dep = Formula.factory dep
+ expand_deps(dep) << dep
+ end
end
protected
@@ -381,11 +412,8 @@ protected
raise
end
end
- rescue SystemCallError
- # usually because exec could not be find the command that was requested
- raise
rescue
- raise BuildError.new(cmd, args, $?)
+ raise BuildError.new(self, cmd, args, $?)
end
private
diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb
index 0555b1267..3cc1024e7 100644
--- a/Library/Homebrew/global.rb
+++ b/Library/Homebrew/global.rb
@@ -2,6 +2,8 @@ require 'extend/pathname'
require 'extend/ARGV'
require 'extend/string'
require 'utils'
+require 'exceptions'
+require 'compatibility'
ARGV.extend(HomebrewArgvExtension)
@@ -40,3 +42,11 @@ HOMEBREW_USER_AGENT = "Homebrew #{HOMEBREW_VERSION} (Ruby #{RUBY_VERSION}-#{RUBY
RECOMMENDED_LLVM = 2326
RECOMMENDED_GCC_40 = (MACOS_VERSION >= 10.6) ? 5494 : 5493
RECOMMENDED_GCC_42 = (MACOS_VERSION >= 10.6) ? 5664 : 5577
+
+require 'fileutils'
+module Homebrew extend self
+ include FileUtils
+end
+
+FORMULA_META_FILES = %w[README README.md ChangeLog COPYING LICENSE LICENCE COPYRIGHT AUTHORS]
+PLEASE_REPORT_BUG = "#{Tty.white}Please report this bug at #{Tty.em}\nhttps://github.com/mxcl/homebrew/wiki/new-issue#{Tty.reset}"
diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb
index f3ca8d2bd..6b338ea83 100755
--- a/Library/Homebrew/install.rb
+++ b/Library/Homebrew/install.rb
@@ -30,7 +30,7 @@ at_exit do
require 'fileutils'
require 'hardware'
require 'keg'
- require 'brew.h.rb'
+ require 'compatibility'
ENV.extend(HomebrewEnvExtension)
ENV.setup_build_environment
@@ -121,7 +121,8 @@ def install f
ohai 'Finishing up' if ARGV.verbose?
begin
- clean f
+ require 'cleaner'
+ Cleaner.new f
rescue Exception => e
opoo "The cleaning step did not complete successfully"
puts "Still, the installation was successful, so we will link it into your prefix"
diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb
index e278a5ce7..22bf40bc3 100644
--- a/Library/Homebrew/keg.rb
+++ b/Library/Homebrew/keg.rb
@@ -1,3 +1,5 @@
+require 'extend/pathname'
+
class Keg <Pathname
def initialize path
super path
@@ -5,8 +7,6 @@ class Keg <Pathname
raise "#{to_s} is not a directory" unless directory?
end
- class NotAKegError <RuntimeError; end
-
# if path is a file in a keg then this will return the containing Keg object
def self.for path
path = path.realpath
diff --git a/Library/Homebrew/test/test_ENV.rb b/Library/Homebrew/test/test_ENV.rb
index 1cd716dfd..da3a9d6af 100644
--- a/Library/Homebrew/test/test_ENV.rb
+++ b/Library/Homebrew/test/test_ENV.rb
@@ -1,6 +1,5 @@
require 'testing_env'
require 'utils'
-require 'brew.h'
require 'extend/ENV'
ENV.extend(HomebrewEnvExtension)
diff --git a/Library/Homebrew/test/test_bucket.rb b/Library/Homebrew/test/test_bucket.rb
index 8492b4929..086297dd2 100644
--- a/Library/Homebrew/test/test_bucket.rb
+++ b/Library/Homebrew/test/test_bucket.rb
@@ -5,7 +5,6 @@ ARGV.extend(HomebrewArgvExtension)
require 'test/testball'
require 'utils'
-require 'brew.h'
class MockFormula <Formula
def initialize url
@@ -79,19 +78,24 @@ class BeerTasting < Test::Unit::TestCase
# end
def test_brew_h
+ require 'cmd/info'
+ require 'cmd/prune'
+ require 'cleaner'
+
nostdout do
assert_nothing_raised do
f=TestBall.new
- make f.url
- info f
- clean f
- prune
+ Homebrew.info_formula f
+ Cleaner.new f
+ Homebrew.prune
#TODO test diy function too
end
end
end
def test_brew_cleanup
+ require 'cmd/cleanup'
+
f1=TestBall.new
f1.instance_eval { @version = "0.1" }
f2=TestBall.new
@@ -110,7 +114,7 @@ class BeerTasting < Test::Unit::TestCase
assert f3.installed?
nostdout do
- cleanup f3
+ Homebrew.cleanup_formula f3
end
assert !f1.installed?
@@ -175,4 +179,16 @@ class BeerTasting < Test::Unit::TestCase
assert_equal 'foo-0.1', foo1.stem
assert_equal '0.1', foo1.version
end
+
+ class MockMockFormula < Struct.new(:name); end
+
+ def test_formula_equality
+ f = MockFormula.new('http://example.com/test-0.1.tgz')
+ g = MockMockFormula.new('test')
+
+ assert f == f
+ assert f == g
+ assert f.eql? f
+ assert (not (f.eql? g))
+ end
end
diff --git a/Library/Homebrew/test/test_external_deps.rb b/Library/Homebrew/test/test_external_deps.rb
index 2b96e7678..30b3540d9 100644
--- a/Library/Homebrew/test/test_external_deps.rb
+++ b/Library/Homebrew/test/test_external_deps.rb
@@ -3,38 +3,12 @@ require 'testing_env'
require 'extend/ARGV' # needs to be after test/unit to avoid conflict with OptionsParser
ARGV.extend(HomebrewArgvExtension)
+require 'extend/string'
require 'test/testball'
require 'formula_installer'
require 'utils'
-# Custom formula installer that checks deps but does not
-# run the install code. We also override the external dep
-# install messages, so for instance the Python check doesnt
-# look for the pip formula (which isn't avaialble in test
-# mode.)
-class DontActuallyInstall < FormulaInstaller
- def install_private f ; end
-
- def pyerr dep
- "Python module install message."
- end
-
- def plerr dep
- "Perl module install message."
- end
-
- def rberr dep
- "Ruby module install message."
- end
-
- def jrberr dep
- "JRuby module install message."
- end
-end
-
-
-
class BadPerlBall <TestBall
depends_on "notapackage" => :perl
@@ -102,14 +76,14 @@ end
class ExternalDepsTests < Test::Unit::TestCase
def check_deps_fail f
- assert_raises(RuntimeError) do
- DontActuallyInstall.new.install f.new
+ assert_raises(UnsatisfiedExternalDependencyError) do
+ FormulaInstaller.check_external_deps f.new
end
end
def check_deps_pass f
assert_nothing_raised do
- DontActuallyInstall.new.install f.new
+ FormulaInstaller.check_external_deps f.new
end
end
diff --git a/Library/Homebrew/test/test_formula.rb b/Library/Homebrew/test/test_formula.rb
index aa545f6d4..fd3987168 100644
--- a/Library/Homebrew/test/test_formula.rb
+++ b/Library/Homebrew/test/test_formula.rb
@@ -5,7 +5,6 @@ ARGV.extend(HomebrewArgvExtension)
require 'test/testball'
require 'utils'
-require 'brew.h'
class MostlyAbstractFormula <Formula
diff --git a/Library/Homebrew/test/test_formula_install.rb b/Library/Homebrew/test/test_formula_install.rb
index db1a2b103..059d7656b 100644
--- a/Library/Homebrew/test/test_formula_install.rb
+++ b/Library/Homebrew/test/test_formula_install.rb
@@ -26,7 +26,7 @@ class ConfigureTests < Test::Unit::TestCase
f=ConfigureFails.new
begin
f.brew { f.install }
- rescue ExecutionError => e
+ rescue BuildError => e
assert e.was_running_configure?
end
end
diff --git a/Library/Homebrew/test/test_updater.rb b/Library/Homebrew/test/test_updater.rb
index 1d733560b..5659f9c67 100644
--- a/Library/Homebrew/test/test_updater.rb
+++ b/Library/Homebrew/test/test_updater.rb
@@ -7,7 +7,7 @@ ARGV.extend(HomebrewArgvExtension)
require 'formula'
require 'utils'
-require 'update'
+require 'cmd/update'
class RefreshBrewMock < RefreshBrew
def in_prefix_expect(expect, returns = '')
diff --git a/Library/Homebrew/test/testing_env.rb b/Library/Homebrew/test/testing_env.rb
index ffc8b3003..0933185bb 100644
--- a/Library/Homebrew/test/testing_env.rb
+++ b/Library/Homebrew/test/testing_env.rb
@@ -8,6 +8,7 @@ ABS__FILE__=File.expand_path(__FILE__)
$:.push(File.expand_path(__FILE__+'/../..'))
require 'extend/pathname'
+require 'exceptions'
# these are defined in global.rb, but we don't want to break our actual
# homebrew tree, and we do want to test everything :)
@@ -26,4 +27,9 @@ at_exit { HOMEBREW_PREFIX.parent.rmtree }
# Test fixtures and files can be found relative to this path
TEST_FOLDER = Pathname.new(ABS__FILE__).parent.realpath
+require 'fileutils'
+module Homebrew extend self
+ include FileUtils
+end
+
require 'test/unit' # must be after at_exit
diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb
index de16df994..6dedf764b 100644
--- a/Library/Homebrew/utils.rb
+++ b/Library/Homebrew/utils.rb
@@ -1,38 +1,3 @@
-class ExecutionError <RuntimeError
- attr :exit_status
- attr :command
-
- def initialize cmd, args = [], es = nil
- @command = cmd
- super "Failure while executing: #{cmd} #{pretty(args)*' '}"
- @exit_status = es.exitstatus rescue 1
- end
-
- def was_running_configure?
- @command == './configure'
- end
-
- private
-
- def pretty args
- args.collect do |arg|
- if arg.to_s.include? ' '
- "'#{ arg.gsub "'", "\\'" }'"
- else
- arg
- end
- end
- end
-end
-
-class BuildError <ExecutionError
- attr :env
-
- def initialize cmd, args = [], es = nil
- super
- @env = ENV.to_hash
- end
-end
class Tty
class <<self
@@ -112,7 +77,10 @@ end
# Kernel.system but with exceptions
def safe_system cmd, *args
- raise ExecutionError.new(cmd, args, $?) unless Homebrew.system(cmd, *args)
+ unless Homebrew.system cmd, *args
+ args = args.map{ |arg| arg.gsub " ", "\\ " } * " "
+ raise "Failure while executing: #{cmd} #{args}"
+ end
end
# prints no output
@@ -263,28 +231,97 @@ def nostdout
end
end
-def dump_build_env env
- puts "\"--use-llvm\" was specified" if ARGV.include? '--use-llvm'
+module MacOS extend self
+ def gcc_42_build_version
+ `/usr/bin/gcc-4.2 -v 2>&1` =~ /build (\d{4,})/
+ if $1
+ $1.to_i
+ elsif system "/usr/bin/which gcc"
+ # Xcode 3.0 didn't come with gcc-4.2
+ # We can't change the above regex to use gcc because the version numbers
+ # are different and thus, not useful.
+ # FIXME I bet you 20 quid this causes a side effect — magic values tend to
+ 401
+ else
+ nil
+ end
+ end
- %w[ CC CXX LD ].each do |k|
- value = env[k]
- if value
- results = value
- if File.exists? value and File.symlink? value
- target = Pathname.new(value)
- results += " => #{target.realpath}"
- end
- puts "#{k}: #{results}"
+ def gcc_40_build_version
+ `/usr/bin/gcc-4.0 -v 2>&1` =~ /build (\d{4,})/
+ if $1
+ $1.to_i
+ else
+ nil
end
end
- %w[ CFLAGS CXXFLAGS CPPFLAGS LDFLAGS MACOSX_DEPLOYMENT_TARGET MAKEFLAGS PKG_CONFIG_PATH
- HOMEBREW_DEBUG HOMEBREW_VERBOSE HOMEBREW_USE_LLVM HOMEBREW_SVN ].each do |k|
- value = env[k]
- puts "#{k}: #{value}" if value
+ def llvm_build_version
+ if MACOS_VERSION >= 10.6
+ xcode_path = `/usr/bin/xcode-select -print-path`.chomp
+ return nil if xcode_path.empty?
+ `#{xcode_path}/usr/bin/llvm-gcc -v 2>&1` =~ /LLVM build (\d{4,})/
+ $1.to_i
+ end
end
-end
def x11_installed?
Pathname.new('/usr/X11/lib/libpng.dylib').exist?
-end \ No newline at end of file
+end
+
+ def macports_or_fink_installed?
+ # See these issues for some history:
+ # http://github.com/mxcl/homebrew/issues/#issue/13
+ # http://github.com/mxcl/homebrew/issues/#issue/41
+ # http://github.com/mxcl/homebrew/issues/#issue/48
+
+ %w[port fink].each do |ponk|
+ path = `/usr/bin/which -s #{ponk}`
+ return ponk unless path.empty?
+ end
+
+ # we do the above check because macports can be relocated and fink may be
+ # able to be relocated in the future. This following check is because if
+ # fink and macports are not in the PATH but are still installed it can
+ # *still* break the build -- because some build scripts hardcode these paths:
+ %w[/sw/bin/fink /opt/local/bin/port].each do |ponk|
+ return ponk if File.exist? ponk
+ end
+
+ # finally, sometimes people make their MacPorts or Fink read-only so they
+ # can quickly test Homebrew out, but still in theory obey the README's
+ # advise to rename the root directory. This doesn't work, many build scripts
+ # error out when they try to read from these now unreadable directories.
+ %w[/sw /opt/local].each do |path|
+ path = Pathname.new(path)
+ return path if path.exist? and not path.readable?
+ end
+
+ false
+ end
+end
+
+module GitHub extend self
+ def issues_for_formula name
+ # bit basic as depends on the issue at github having the exact name of the
+ # formula in it. Which for stuff like objective-caml is unlikely. So we
+ # really should search for aliases too.
+
+ name = f.name if Formula === name
+
+ require 'open-uri'
+ require 'yaml'
+
+ issues = []
+
+ open "http://github.com/api/v2/yaml/issues/search/mxcl/homebrew/open/#{name}" do |f|
+ YAML::load(f.read)['issues'].each do |issue|
+ issues << 'http://github.com/mxcl/homebrew/issues/#issue/%s' % issue['number']
+ end
+ end
+
+ issues
+ rescue
+ []
+ end
+end
diff --git a/bin/brew b/bin/brew
index 4ec64f0a1..645e933e4 100755
--- a/bin/brew
+++ b/bin/brew
@@ -38,313 +38,48 @@ if MACOS_VERSION < 10.5
abort "Homebrew requires Leopard or higher. For Tiger support, see:\nhttp://github.com/sceaga/homebrew/tree/tiger"
end
-def dump_config
- require 'hardware'
- sha = `cd #{HOMEBREW_REPOSITORY} && git rev-parse --verify HEAD 2> /dev/null`.chomp
- sha = "(none)" if sha.empty?
- bits = Hardware.bits
- cores = Hardware.cores_as_words
- kernel_arch = `uname -m`.chomp
- system_ruby = Pathname.new("/usr/bin/ruby")
-
- llvm, llvm_msg = _compiler_recommendation llvm_build, RECOMMENDED_LLVM
- gcc_42, gcc_42_msg = _compiler_recommendation gcc_42_build, RECOMMENDED_GCC_42
- gcc_40, gcc_40_msg = _compiler_recommendation gcc_40_build, RECOMMENDED_GCC_40
- xcode = xcode_version || "?"
-
- puts <<-EOS
-HOMEBREW_VERSION: #{HOMEBREW_VERSION}
-HEAD: #{sha}
-HOMEBREW_PREFIX: #{HOMEBREW_PREFIX}
-HOMEBREW_CELLAR: #{HOMEBREW_CELLAR}
-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}
-/usr/bin/ruby => #{system_ruby.realpath}
-Xcode: #{xcode}
-GCC-4.0: #{gcc_40 ? "build #{gcc_40}" : "N/A"} #{gcc_42_msg}
-GCC-4.2: #{gcc_42 ? "build #{gcc_42}" : "N/A"} #{gcc_40_msg}
-LLVM: #{llvm ? "build #{llvm}" : "N/A" } #{llvm_msg}
-MacPorts or Fink? #{macports_or_fink_installed?}
-X11 installed? #{x11_installed?}
-EOS
+def require? path
+ require path.to_s.chomp
+rescue LoadError => e
+ # HACK :( because we should raise on syntax errors but
+ # not if the file doesn't exist. TODO make robust!
+ raise unless e.to_s.include? path
end
begin
- require 'brew.h'
-
- case arg = ARGV.shift
- when '--cache'
- if ARGV.named.empty?
- puts HOMEBREW_CACHE
- else
- puts ARGV.formulae.collect {|f| f.cached_download}
- end
- when '--prefix'
- if ARGV.named.empty?
- puts HOMEBREW_PREFIX
- else
- puts ARGV.formulae.collect {|f| f.prefix}
- end
- when '--repository'
- puts HOMEBREW_REPOSITORY
- when '--cellar'
- if ARGV.named.empty?
- puts HOMEBREW_CELLAR
- else
- puts ARGV.formulae.collect {|f| HOMEBREW_CELLAR+f.name}
- end
- when '--config'
- dump_config
- when '--env'
- require 'hardware'
- require 'extend/ENV'
- ENV.extend(HomebrewEnvExtension)
- ENV.setup_build_environment
- dump_build_env ENV
-
- 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.flag? '--versions'
- if ARGV.named.empty?
- to_list = HOMEBREW_CELLAR.children.select { |pn| pn.directory? }
- else
- to_list = ARGV.named.collect { |n| HOMEBREW_CELLAR+n }.select { |pn| pn.exist? }
- end
- to_list.each do |d|
- versions = d.children.select { |pn| pn.directory? }.collect { |pn| pn.basename.to_s }
- puts "#{d.basename} #{versions *' '}"
- end
- elsif ARGV.named.empty?
- ENV['CLICOLOR']=nil
- exec 'ls', *ARGV.options_only<<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'
- if ARGV.include? '--macports'
- exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
- elsif ARGV.include? '--fink'
- exec "open", "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
- end
-
- check_for_blacklisted_formula(ARGV.named)
- puts_columns search_brews(ARGV.first)
-
- 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
- require 'formula'
- # Don't use ARGV.formulae as that will throw if the file doesn't parse
- paths = ARGV.named.collect do |name|
- path = Formula.path(Formula.resolve_alias(name))
- unless File.exist? path
- raise FormulaUnavailableError, name
- else
- path
- end
- end
- exec_editor(*paths)
- end
-
- when 'up', 'update'
- abort "Please `brew install git' first." unless system "/usr/bin/which -s git"
-
- require 'update'
- updater = RefreshBrew.new
- unless updater.update_from_masterbrew!
- puts "Already up-to-date."
- else
- updater.report
- 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'
- if ARGV.flag? "--force"
- require 'formula'
- ARGV.formulae.each do |f|
- formula_cellar = f.prefix.parent
- next unless File.exist? formula_cellar
- puts "Uninstalling #{f.name}..."
- formula_cellar.children do |k|
- keg = Keg.new(k)
- keg.unlink
- end
-
- formula_cellar.rmtree
- end
- else
- begin
- ARGV.kegs.each do |keg|
- puts "Uninstalling #{keg}..."
- keg.unlink
- keg.uninstall
- end
- rescue MultipleVersionsInstalledError => e
- onoe e
- puts "Use `brew remove --force #{e.name}` to remove all versions."
- end
- end
-
- when 'prune'
- prune
-
- when 'create'
- if ARGV.include? '--macports'
- exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
- elsif ARGV.include? '--fink'
- exec "open", "http://pdb.finkproject.org/pdb/browse.php?summary=#{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'
- Formula.all.each do |f|
- info f
- puts '---'
- end
- else
- puts `ls #{HOMEBREW_CELLAR} | wc -l`.strip+" kegs, "+HOMEBREW_CELLAR.abv
- end
- elsif ARGV[0][0..6] == 'http://' or ARGV[0][0..7] == 'https://' or ARGV[0][0..5] == 'ftp://'
- path = Pathname.new(ARGV.shift)
- /(.*?)[-_.]?#{path.version}/.match path.basename
- unless $1.to_s.empty?
- name = $1
- else
- name = path.stem
- end
- puts "#{name} #{path.version}"
- else
- ARGV.formulae.each{ |f| info f }
- 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)
- brew_install
-
- when 'log'
- Dir.chdir HOMEBREW_REPOSITORY
- args = ARGV.options_only
- args += ARGV.formulae.map{ |formula| formula.path } unless ARGV.named.empty?
- exec "git", "log", *args
-
- # For each formula given, show which other formulas depend on it.
- # We only go one level up, ie. direct dependencies.
- when 'uses'
- uses = ARGV.formulae.map{ |f| Formula.all.select{ |ff| ff.deps.include? f.name }.map{|f| f.name} }.flatten.uniq
- if ARGV.include? "--installed"
- uses = uses.select { |f| f = HOMEBREW_CELLAR+f; f.directory? and not f.subdirs.empty? }
- end
- puts uses.sort
-
- when 'deps'
- if ARGV.include?('--all')
- require 'formula'
- Formula.all.each do |f|
- puts "#{f.name}:#{f.deps.join(' ')}"
- end
- elsif ARGV.include?("-1") or ARGV.include?("--1")
- puts ARGV.formulae.map {|f| f.deps or []}.flatten.uniq.sort
- else
- require 'formula_installer'
- puts ARGV.formulae.map {|f| FormulaInstaller.expand_deps(f).map {|f| f.name} }.flatten.uniq.sort
- end
-
- when 'cat'
- Dir.chdir HOMEBREW_REPOSITORY
- exec "cat", ARGV.formulae.first.path, *ARGV.options_only
-
- when 'outdated'
- outdated_brews.each do |keg, name, version|
- if $stdout.tty? and not ARGV.flag? '--quiet'
- versions = keg.cd{ Dir['*'] }.join(', ')
- puts "#{name} (#{versions} < #{version})"
- else
- puts name
- end
+ aliases = {'ls' => :list,
+ 'homepage' => :home,
+ '-S' => :search,
+ 'up' => :update,
+ 'ln' => :link,
+ 'rm' => :uninstall,
+ 'remove' => :uninstall,
+ 'configure' => :diy,
+ 'abv' => :info,
+ 'dr' => :doctor,
+ '--repo' => '--repository'}
+
+ cmd = ARGV.shift
+ cmd = aliases[cmd] if aliases[cmd]
+
+ # Add example external commands to PATH before checking.
+ ENV['PATH'] += ":#{HOMEBREW_REPOSITORY}/Library/Contributions/examples"
+
+ if system "/usr/bin/which -s brew-#{cmd}"
+ %w[CACHE CELLAR LIBRARY_PATH PREFIX REPOSITORY].each do |e|
+ ENV["HOMEBREW_#{e}"] = eval "HOMEBREW_#{e}"
end
-
- when 'doctor', 'dr'
- require 'brew_doctor'
- brew_doctor
-
+ exec "brew-#{cmd}", *ARGV
+ elsif require? `/usr/bin/which brew-#{cmd}.rb`
+ exit 0
+ elsif require? HOMEBREW_REPOSITORY/"Library/Homebrew/cmd"/cmd
+ Homebrew.send cmd.to_s.gsub('-', '_')
else
- # Add example external commands to PATH before checking.
- ENV['PATH'] += ":#{HOMEBREW_REPOSITORY}/Library/Contributions/examples"
-
- # Check for an external shell command
- if system "/usr/bin/which -s brew-#{arg}"
- # Add some Homebrew vars to the ENV
- %w(CACHE CELLAR LIBRARY_PATH PREFIX REPOSITORY).each do |e|
- ENV["HOMEBREW_#{e}"] = eval("HOMEBREW_#{e}")
- end
- exec("brew-#{arg}", *ARGV)
- end
-
- # Check for an external ruby command
- external_rb = `/usr/bin/which brew-#{arg}.rb`.chomp
- unless external_rb.empty?
- require external_rb
- exit 0
- end
-
# Check for git commands
- if %w(branch checkout pull push rebase reset).include? arg
- onoe "Unknown command '#{arg}' (did you mean 'git #{arg}'?)"
+ if %w[branch checkout pull push rebase reset].include? cmd
+ onoe "Unknown command: #{cmd} (did you mean `git #{cmd}'?)"
else
- onoe "Unknown command '#{arg}'"
+ onoe "Unknown command: #{cmd}"
end
end
@@ -362,24 +97,28 @@ rescue Interrupt => e
puts # seemingly a newline is typical
exit 130
rescue BuildError => e
+ require 'cmd/--config'
+ require 'cmd/--env'
+
e.backtrace[1] =~ %r{Library/Formula/(.+)\.rb:(\d+)}
formula_name = $1
error_line = $2
+
puts "Exit status: #{e.exit_status}"
puts
puts "http://github.com/mxcl/homebrew/blob/master/Library/Formula/#{formula_name}.rb#L#{error_line}"
puts
ohai "Environment"
- dump_config
+ puts Homebrew.config_s
puts
ohai "Build Flags"
- dump_build_env e.env
+ Homebrew.dump_build_env e.env
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 existing issues..." and
# then replace that string with the following when the github api returns
- issues = issues_for_formula(formula_name)
+ issues = GitHub.issues_for_formula formula_name
puts "These existing issues may help you:", *issues unless issues.empty?
if e.was_running_configure?
puts "It looks like an autotools configure failed."