More modular cmd/install and FormulaInstaller
This commit is contained in:
parent
768910283a
commit
cf29569099
@ -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,58 +34,69 @@ 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?
|
||||
|
||||
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
|
||||
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
|
||||
EOS
|
||||
when 'mercurial', 'hg' then <<-EOS
|
||||
Mercurial can be install thusly:
|
||||
brew install pip && pip install mercurial
|
||||
EOS
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,100 +1,57 @@
|
||||
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
|
||||
end
|
||||
deps
|
||||
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
|
||||
# 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
|
||||
FormulaInstaller.check_external_deps @f
|
||||
end
|
||||
FormulaInstaller.install_formula @f
|
||||
end
|
||||
end
|
||||
|
||||
def install f
|
||||
if @install_deps
|
||||
check_external_deps f
|
||||
check_formula_deps f
|
||||
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 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
|
||||
# installation has a pristine ENV when it starts, forking now is
|
||||
# the easiest way to do this
|
||||
# 2. formulae have access to __END__ the only way to allow this is
|
||||
# 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
|
||||
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
|
||||
Marshal.dump(e, write)
|
||||
write.close
|
||||
exit! 1
|
||||
end
|
||||
end
|
||||
ignore_interrupts do # because child proc will get it and marshall it back
|
||||
fork do
|
||||
begin
|
||||
read.close
|
||||
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
|
||||
Process.wait
|
||||
data = read.read
|
||||
raise Marshal.load(data) unless data.nil? or data.empty?
|
||||
raise "Suspicious installation failure" unless $?.success?
|
||||
exit! 1
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user