More modular cmd/install and FormulaInstaller

This commit is contained in:
Max Howell 2010-11-09 12:57:41 +00:00 committed by Adam Vandenberg
parent 768910283a
commit cf29569099
2 changed files with 109 additions and 132 deletions

View File

@ -3,26 +3,30 @@ require 'hardware'
module Homebrew extend self
def install
brew_install
end
end
blacklisted? ARGV.named do |msg, name|
abort msg
end unless ARGV.force?
def brew_install
############################################################ sanity checks
install_formulae ARGV.formulae
end
def check_ppc
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
end
def check_writable_install_location
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?
end
################################################################# warnings
begin
def check_cc
if MACOS_VERSION >= 10.6
opoo "You should upgrade to Xcode 3.2.3" if llvm_build < RECOMMENDED_LLVM
opoo "You should upgrade to Xcode 3.2.3" if MacOS.llvm_build_version < 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)
opoo "You should upgrade to Xcode 3.1.4" if (MacOS.gcc_40_build_version < RECOMMENDED_GCC_40) or (MacOS.gcc_42_build_version < RECOMMENDED_GCC_42)
end
rescue
# the reason we don't abort is some formula don't require Xcode
@ -30,43 +34,55 @@ def brew_install
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}"
def check_macports
if MacOS.macports_or_fink_installed?
opoo "It appears you have Macports or Fink installed"
puts "Software installed with other package managers causes known problems for"
puts "Homebrew. If formula fail to build uninstall Macports/Fink and reinstall any"
puts "affected formula."
end
end
end
def check_for_blacklisted_formula names
return if ARGV.force?
def install_formulae formulae
formulae = [formulae].flatten.compact
return if formulae.empty?
check_ppc
check_writable_install_location
check_cc
check_macports
formulae.each do |f|
begin
installer = FormulaInstaller.new f
installer.ignore_deps = ARGV.include? '--ignore-dependencies'
installer.go
rescue FormulaAlreadyInstalledError => e
opoo e.message
end
end
end
def blacklisted? names
names.each do |name|
msg = blacklisted_reason name
yield msg.undent, name if msg
end
end
def blacklisted_reason name
case name
when 'tex', 'tex-live', 'texlive' then abort <<-EOS.undent
when 'tex', 'tex-live', 'texlive' then <<-EOS
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
when 'mercurial', 'hg' then <<-EOS
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/
@ -74,7 +90,6 @@ def check_for_blacklisted_formula names
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.

View File

@ -1,97 +1,54 @@
require 'exceptions'
require 'formula'
require 'set'
class FormulaInstaller
@@attempted = Set.new
attr :ignore_deps, true
def initialize
@install_deps = true
def initialize f
@f = f
end
attr_writer :install_deps
def self.expand_deps f
deps = []
f.deps.collect do |dep|
dep = Formula.factory dep
deps += expand_deps dep
deps << dep
# raises Homebrew::InstallationErrors in the event of install failures
def go
if @f.installed? and not ARGV.force?
raise FormulaAlreadyInstalledError, @f
else
unless ignore_deps
@f.recursive_deps.each do |dep|
FormulaInstaller.install_formula dep unless dep.installed?
end
deps
FormulaInstaller.check_external_deps @f
end
def pyerr dep
brew_pip = ' brew install pip &&' unless Formula.factory('pip').installed?
<<-EOS.undent
Unsatisfied dependency, #{dep}
Homebrew does not provide Python dependencies, pip does:
#{brew_pip} pip install #{dep}
EOS
end
def plerr dep; <<-EOS.undent
Unsatisfied dependency, #{dep}
Homebrew does not provide Perl dependencies, cpan does:
cpan -i #{dep}
EOS
end
def rberr dep; <<-EOS.undent
Unsatisfied dependency "#{dep}"
Homebrew does not provide Ruby dependencies, rubygems does:
gem install #{dep}
EOS
end
def jrberr dep; <<-EOS.undent
Unsatisfied dependency "#{dep}"
Homebrew does not provide JRuby dependencies, rubygems does:
jruby -S gem install #{dep}
EOS
end
def check_external_deps f
return unless f.external_deps
f.external_deps[:python].each do |dep|
raise pyerr(dep) unless quiet_system "/usr/bin/env", "python", "-c", "import #{dep}"
end
f.external_deps[:perl].each do |dep|
raise plerr(dep) unless quiet_system "/usr/bin/env", "perl", "-e", "use #{dep}"
end
f.external_deps[:ruby].each do |dep|
raise rberr(dep) unless quiet_system "/usr/bin/env", "ruby", "-rubygems", "-e", "require '#{dep}'"
end
f.external_deps[:jruby].each do |dep|
raise jrberr(dep) unless quiet_system "/usr/bin/env", "jruby", "-rubygems", "-e", "require '#{dep}'"
FormulaInstaller.install_formula @f
end
end
def check_formula_deps f
FormulaInstaller.expand_deps(f).each do |dep|
begin
install_private dep unless dep.installed?
rescue
#TODO continue if this is an optional dep
raise
def self.check_external_deps f
[:ruby, :python, :perl, :jruby].each do |type|
f.external_deps[type].each do |dep|
unless quiet_system(*external_dep_check(dep, type))
raise UnsatisfiedExternalDependencyError.new(dep, type)
end
end if f.external_deps[type]
end
end
def install f
if @install_deps
check_external_deps f
check_formula_deps f
def self.external_dep_check dep, type
case type
when :python then %W{/usr/bin/env python -c import\ #{dep}}
when :jruby then %W{/usr/bin/env jruby -rubygems -e require\ '#{dep}'}
when :ruby then %W{/usr/bin/env ruby -rubygems -e require\ '#{dep}'}
when :perl then %W{/usr/bin/env perl -e use\ #{dep}}
end
install_private f
end
private
def install_private f
return if @@attempted.include? f.name
@@attempted << f.name
def self.install_formula f
@attempted ||= Set.new
raise FormulaInstallationAlreadyAttemptedError, f if @attempted.include? f
@attempted << f
# 1. formulae can modify ENV, so we must ensure that each
# installation has a pristine ENV when it starts, forking now is
@ -102,18 +59,24 @@ class FormulaInstaller
# I'm guessing this is not a good way to do this, but I'm no UNIX guru
ENV['HOMEBREW_ERROR_PIPE'] = write.to_i.to_s
begin #watch_out_for_spill do #disabled temporarily, see Issue #124
fork do
begin
read.close
exec '/usr/bin/nice', '/usr/bin/ruby', '-I', File.dirname(__FILE__), '-rinstall', f.path, '--', *ARGV.options_only
rescue => e
exec '/usr/bin/nice',
'/usr/bin/ruby',
'-I', Pathname.new(__FILE__).dirname,
'-rinstall',
f.path,
'--',
*ARGV.options_only
rescue Exception => e
Marshal.dump(e, write)
write.close
exit! 1
end
end
ignore_interrupts do # because child proc will get it and marshall it back
ignore_interrupts do # the fork will receive the interrupt and marshall it back
write.close
Process.wait
data = read.read
@ -121,5 +84,4 @@ class FormulaInstaller
raise "Suspicious installation failure" unless $?.success?
end
end
end
end