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 end unless ARGV.force?
def brew_install install_formulae ARGV.formulae
############################################################ sanity checks end
def check_ppc
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,58 +34,69 @@ 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"
end puts "Homebrew. If formula fail to build uninstall Macports/Fink and reinstall any"
puts "affected formula."
################################################################# 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 end
end
def check_for_blacklisted_formula names def install_formulae formulae
return if ARGV.force? formulae = [formulae].flatten.compact
return if formulae.empty?
names.each do |name| 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 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/
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.
Install distribute using: Install distribute using:
brew install distribute brew install distribute
EOS EOS
end end
end end
end end

View File

@ -1,100 +1,57 @@
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
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
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
end end
FormulaInstaller.install_formula @f
end end
end end
def install f def self.check_external_deps f
if @install_deps [:ruby, :python, :perl, :jruby].each do |type|
check_external_deps f f.external_deps[type].each do |dep|
check_formula_deps f unless quiet_system(*external_dep_check(dep, type))
raise UnsatisfiedExternalDependencyError.new(dep, type)
end
end if f.external_deps[type]
end
end
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 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
# the easiest way to do this # the easiest way to do this
# 2. formulae have access to __END__ the only way to allow this is # 2. formulae have access to __END__ the only way to allow this is
# to make the formula script the executed script # to make the formula script the executed script
@ -102,24 +59,29 @@ 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',
exec '/usr/bin/nice', '/usr/bin/ruby', '-I', File.dirname(__FILE__), '-rinstall', f.path, '--', *ARGV.options_only '/usr/bin/ruby',
rescue => e '-I', Pathname.new(__FILE__).dirname,
Marshal.dump(e, write) '-rinstall',
write.close f.path,
exit! 1 '--',
end *ARGV.options_only
end rescue Exception => e
ignore_interrupts do # because child proc will get it and marshall it back Marshal.dump(e, write)
write.close write.close
Process.wait exit! 1
data = read.read
raise Marshal.load(data) unless data.nil? or data.empty?
raise "Suspicious installation failure" unless $?.success?
end end
end end
ignore_interrupts do # the fork will receive the interrupt and marshall it back
write.close
Process.wait
data = read.read
raise Marshal.load(data) unless data.nil? or data.empty?
raise "Suspicious installation failure" unless $?.success?
end
end end
end end