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 module Homebrew extend self
def install def install
brew_install blacklisted? ARGV.named do |msg, name|
end abort msg
end unless ARGV.force?
install_formulae ARGV.formulae
end end
def brew_install def check_ppc
############################################################ sanity checks
case Hardware.cpu_type when :ppc, :dunno case Hardware.cpu_type when :ppc, :dunno
abort "Sorry, Homebrew does not support your computer's CPU architecture.\n"+ abort "Sorry, Homebrew does not support your computer's CPU architecture.\n"+
"For PPC support, see: http://github.com/sceaga/homebrew/tree/powerpc" "For PPC support, see: http://github.com/sceaga/homebrew/tree/powerpc"
end 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_CELLAR}" if HOMEBREW_CELLAR.exist? and not HOMEBREW_CELLAR.writable?
raise "Cannot write to #{HOMEBREW_PREFIX}" unless HOMEBREW_PREFIX.writable? raise "Cannot write to #{HOMEBREW_PREFIX}" unless HOMEBREW_PREFIX.writable?
end
################################################################# warnings def check_cc
begin
if MACOS_VERSION >= 10.6 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 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 end
rescue rescue
# the reason we don't abort is some formula don't require Xcode # 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!" opoo "Xcode is not installed! Builds may fail!"
end end
if macports_or_fink_installed? def check_macports
opoo "It appears you have MacPorts or Fink installed." if MacOS.macports_or_fink_installed?
puts "Software installed with MacPorts and Fink are known to cause problems." opoo "It appears you have Macports or Fink installed"
puts "If you experience issues try uninstalling these tools." 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
################################################################# install! def install_formulae formulae
installer = FormulaInstaller.new formulae = [formulae].flatten.compact
installer.install_deps = !ARGV.include?('--ignore-dependencies') return if formulae.empty?
ARGV.formulae.each do |f| check_ppc
if not f.installed? or ARGV.force? check_writable_install_location
installer.install f check_cc
else check_macports
puts "Formula already installed: #{f.prefix}"
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 end
end end
def check_for_blacklisted_formula names def blacklisted? names
return if ARGV.force?
names.each do |name| names.each do |name|
msg = blacklisted_reason name
yield msg.undent, name if msg
end
end
def blacklisted_reason name
case 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, 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.) and only builds 32-bit (and thus can't use Homebrew deps on Snow Leopard.)
We recommend using a MacTeX distribution: We recommend using a MacTeX distribution:
http://www.tug.org/mactex/ http://www.tug.org/mactex/
EOS EOS
when 'mercurial', 'hg' then <<-EOS
when 'mercurial', 'hg' then abort <<-EOS.undent
Mercurial can be install thusly: Mercurial can be install thusly:
brew install pip && pip install mercurial brew install pip && pip install mercurial
EOS EOS
when 'npm' then abort <<-EOS.undent when 'npm' then abort <<-EOS.undent
npm can be installed thusly by following the instructions at npm can be installed thusly by following the instructions at
http://npmjs.org/ http://npmjs.org/
@ -74,7 +90,6 @@ def check_for_blacklisted_formula names
To do it in one line, use this command: To do it in one line, use this command:
curl http://npmjs.org/install.sh | sudo sh curl http://npmjs.org/install.sh | sudo sh
EOS EOS
when 'setuptools' then abort <<-EOS.undent when 'setuptools' then abort <<-EOS.undent
When working with a Homebrew-built Python, distribute is preferred When working with a Homebrew-built Python, distribute is preferred
over setuptools, and can be used as the prerequisite for pip. over setuptools, and can be used as the prerequisite for pip.

View File

@ -1,97 +1,54 @@
require 'exceptions'
require 'formula' require 'formula'
require 'set' require 'set'
class FormulaInstaller class FormulaInstaller
@@attempted = Set.new attr :ignore_deps, true
def initialize def initialize f
@install_deps = true @f = f
end end
attr_writer :install_deps # raises Homebrew::InstallationErrors in the event of install failures
def go
def self.expand_deps f if @f.installed? and not ARGV.force?
deps = [] raise FormulaAlreadyInstalledError, @f
f.deps.collect do |dep| else
dep = Formula.factory dep unless ignore_deps
deps += expand_deps dep @f.recursive_deps.each do |dep|
deps << dep FormulaInstaller.install_formula dep unless dep.installed?
end end
deps FormulaInstaller.check_external_deps @f
end end
FormulaInstaller.install_formula @f
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}'"
end end
end end
def check_formula_deps f def self.check_external_deps f
FormulaInstaller.expand_deps(f).each do |dep| [:ruby, :python, :perl, :jruby].each do |type|
begin f.external_deps[type].each do |dep|
install_private dep unless dep.installed? unless quiet_system(*external_dep_check(dep, type))
rescue raise UnsatisfiedExternalDependencyError.new(dep, type)
#TODO continue if this is an optional dep
raise
end end
end if f.external_deps[type]
end end
end end
def install f def self.external_dep_check dep, type
if @install_deps case type
check_external_deps f when :python then %W{/usr/bin/env python -c import\ #{dep}}
check_formula_deps f 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 end
install_private f
end end
private private
def install_private f def self.install_formula f
return if @@attempted.include? f.name @attempted ||= Set.new
@@attempted << f.name raise FormulaInstallationAlreadyAttemptedError, f if @attempted.include? f
@attempted << f
# 1. formulae can modify ENV, so we must ensure that each # 1. formulae can modify ENV, so we must ensure that each
# installation has a pristine ENV when it starts, forking now is # 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 # 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 ENV['HOMEBREW_ERROR_PIPE'] = write.to_i.to_s
begin #watch_out_for_spill do #disabled temporarily, see Issue #124
fork do fork do
begin begin
read.close read.close
exec '/usr/bin/nice', '/usr/bin/ruby', '-I', File.dirname(__FILE__), '-rinstall', f.path, '--', *ARGV.options_only exec '/usr/bin/nice',
rescue => e '/usr/bin/ruby',
'-I', Pathname.new(__FILE__).dirname,
'-rinstall',
f.path,
'--',
*ARGV.options_only
rescue Exception => e
Marshal.dump(e, write) Marshal.dump(e, write)
write.close write.close
exit! 1 exit! 1
end end
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 write.close
Process.wait Process.wait
data = read.read data = read.read
@ -122,4 +85,3 @@ class FormulaInstaller
end end
end end
end end
end