Allow formulae to use __END__

For this to work the "running script" must be the formulae file. Making this
so wasn't so hard, there is now an install.rb script which is included with
the -r flag to the ruby executable. An at_exit handler calls the install
function.

Having the install logic in its own file made it feel like there was so much
space that I added extra error handling. So there is something to be said for
separating functionality out into its own files.

Still the error handling sucks, we'll need to marshall the exception back to
the bin/brew command. Which is another PITA.

Still overall I think this will prove worthwhile. But if it doesn't we'll
revert.

As a first usage, you can put a diff after __END__ and return DATA from
Formula::patches to make Homebrew aware of it.
This commit is contained in:
Max Howell 2009-09-04 15:28:18 +01:00
parent fd5ed391be
commit c28bd7b571
7 changed files with 153 additions and 90 deletions

View File

@ -144,31 +144,6 @@ def clean f
end
def install f
f.brew do
if ARGV.flag? '--interactive'
ohai "Entering interactive mode"
puts "Type `exit' to return and finalize the installation"
puts "Install to this prefix: #{f.prefix}"
interactive_shell
nil
elsif ARGV.include? '--help'
system './configure --help'
exit $?
else
f.prefix.mkpath
beginning=Time.now
f.install
%w[README ChangeLog COPYING LICENSE COPYRIGHT AUTHORS].each do |file|
FileUtils.mv "#{file}.txt", file rescue nil
f.prefix.install file rescue nil
end
return Time.now-beginning
end
end
end
def prune
$n=0
$d=0

View File

@ -114,6 +114,8 @@ class Formula
# :p1 => 'http://bar.com/patch2',
# :p2 => ['http://moo.com/patch5', 'http://moo.com/patch6']
# }
# The final option is to return DATA, then put a diff after __END__ and you
# can still return a Hash with DATA as the value for a patch level key.
def patches; [] end
# reimplement and specify dependencies
def deps; end
@ -128,6 +130,8 @@ class Formula
stage do
begin
patch
# we allow formulas to do anything they want to the Ruby process
# so load any deps before this point! And exit asap afterwards
yield self
rescue Interrupt, RuntimeError, SystemCallError => e
raise unless ARGV.debug?
@ -158,7 +162,13 @@ class Formula
end
def self.factory name
path = Pathname.new(name)
if path.absolute?
require name
name = path.stem
else
require self.path(name)
end
return eval(self.class_s(name)).new(name)
rescue LoadError
raise FormulaUnavailableError.new(name)
@ -258,17 +268,20 @@ private
n=0
patch_defns.each do |arg, urls|
urls.each do |url|
p = {:filename => '%03d-homebrew.patch' % n+=1, :compression => false}
p = {:filename => '%03d-homebrew.diff' % n+=1, :compression => false}
if url =~ %r[^\w+\://]
if defined? DATA and url == DATA
pn=Pathname.new p[:filename]
pn.write DATA.read
elsif url =~ %r[^\w+\://]
out_fn = p[:filename]
case url
when /\.gz$/
p[:compression] = :gzip
out_fn << '.gz'
out_fn += '.gz'
when /\.bz2$/
p[:compression] = :bzip2
out_fn << '.bz2'
out_fn += '.bz2'
end
p[:curl_args] = [url, '-o', out_fn]
else
@ -282,8 +295,10 @@ private
end
end
return if patch_list.empty?
# downloading all at once is much more efficient, espeically for FTP
curl *(patch_list.collect { |p| p[:curl_args] }).flatten
curl *(patch_list.collect{|p| p[:curl_args]}.select{|p| p}.flatten)
patch_list.each do |p|
case p[:compression]

View File

@ -0,0 +1,41 @@
# Copyright 2009 Max Howell and other contributors.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'pathname+yeast'
require 'ARGV+yeast'
require 'utils'
require 'hardware'
if Process.uid == 0
# technically this is not the correct place, this cache is for *all users*
# so in that case, maybe we should always use it, root or not?
HOMEBREW_CACHE=Pathname.new("/Library/Caches/Homebrew")
else
HOMEBREW_CACHE=Pathname.new("~/Library/Caches/Homebrew").expand_path
end
HOMEBREW_PREFIX=(Pathname.getwd+__FILE__).dirname.parent.parent.cleanpath
HOMEBREW_CELLAR=HOMEBREW_PREFIX+'Cellar'
HOMEBREW_VERSION='0.4'
HOMEBREW_WWW='http://bit.ly/Homebrew'
HOMEBREW_USER_AGENT="Homebrew #{HOMEBREW_VERSION} (Ruby #{VERSION}; Mac OS X 10.5 Leopard)"

78
Library/Homebrew/install.rb Executable file
View File

@ -0,0 +1,78 @@
#!/usr/bin/ruby
require 'global'
require 'formula'
require 'keg'
require 'brew.h'
def install f
build_time=nil
begin
f.brew do
if ARGV.flag? '--interactive'
ohai "Entering interactive mode"
puts "Type `exit' to return and finalize the installation"
puts "Install to this prefix: #{f.prefix}"
interactive_shell
nil
elsif ARGV.include? '--help'
system './configure --help'
exit $?
else
f.prefix.mkpath
beginning=Time.now
f.install
%w[README ChangeLog COPYING LICENSE COPYRIGHT AUTHORS].each do |file|
FileUtils.mv "#{file}.txt", file rescue nil
f.prefix.install file rescue nil
end
build_time=Time.now-beginning
end
end
rescue Exception
if f.prefix.directory?
f.prefix.rmtree
f.prefix.parent.rmdir_if_possible
end
raise
end
ohai "Caveats", f.caveats, ''
ohai 'Finishing up' if ARGV.verbose?
begin
clean 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"
ohai e, e.inspect if ARGV.debug?
end
raise "Nothing was installed to #{f.prefix}" unless f.installed?
begin
Keg.new(f.prefix).link
rescue Exception
onoe "The linking step did not complete successfully"
puts "The package built, but is not symlinked into #{HOMEBREW_PREFIX}"
puts "You can try again using `brew link #{f.name}'"
ohai e, e.inspect if ARGV.debug?
ohai "Summary"
else
ohai "Summary" if ARGV.verbose?
end
print "#{f.prefix}: #{f.prefix.abv}"
print ", built in #{pretty_duration build_time}" if build_time
puts
rescue Exception => e
#TODO propogate exception back to brew script
onoe e
puts e.backtrace
end
# I like this little at all, but see no alternative seeing as the formula
# rb file has to be the running script to allow it to use __END__ and DATA
at_exit { install(Formula.factory($0)) }

View File

@ -14,7 +14,7 @@ require 'utils'
require 'brew.h'
require 'hardware.rb'
# these are defined in bin/brew, but we don't want to break our actual
# these are defined in global.rb, but we don't want to break our actual
# homebrew tree, and we do want to test everything :)
HOMEBREW_PREFIX=Pathname.new '/tmp/testbrew/prefix'
HOMEBREW_CACHE=HOMEBREW_PREFIX.parent+"cache"

View File

@ -75,8 +75,8 @@ def safe_system cmd, *args
end
end
def curl url, *args
safe_system 'curl', '-f#LA', HOMEBREW_USER_AGENT, url, *args
def curl *args
safe_system 'curl', '-f#LA', HOMEBREW_USER_AGENT, *args unless args.empty?
end
def puts_columns items, cols = 4

View File

@ -1,26 +1,10 @@
#!/usr/bin/ruby
# -*- coding: utf-8 -*-
$:.unshift ENV['RUBYLIB']=File.expand_path(__FILE__+'/../../Library/Homebrew')
require 'pathname+yeast'
require 'ARGV+yeast'
require 'utils'
require 'hardware'
ENV['RUBYLIB']=HOMEBREW_RUBYLIB=File.expand_path(__FILE__+'/../../Library/Homebrew')
$:.unshift HOMEBREW_RUBYLIB
require 'global'
require 'brew.h'
if Process.uid == 0
# technically this is not the correct place, this cache is for *all users*
# so in that case, maybe we should always use it, root or not?
HOMEBREW_CACHE=Pathname.new("/Library/Caches/Homebrew")
else
HOMEBREW_CACHE=Pathname.new("~/Library/Caches/Homebrew").expand_path
end
HOMEBREW_PREFIX=(Pathname.getwd+__FILE__).dirname.parent.cleanpath
HOMEBREW_CELLAR=HOMEBREW_PREFIX+'Cellar'
HOMEBREW_VERSION='0.4'
HOMEBREW_WWW='http://bit.ly/Homebrew'
HOMEBREW_USER_AGENT="Homebrew #{HOMEBREW_VERSION} (Ruby #{VERSION}; Mac OS X 10.5 Leopard)"
if %w[/ /usr].include? HOMEBREW_PREFIX.to_s then abort <<-EOS
You have placed Homebrew at the prefix: #{HOMEBREW_PREFIX}
This is not currently supported. Voice your support for this feature at:
@ -109,11 +93,14 @@ begin
next
end
# we need to ensure a pristine ENV for each process or the formula
# will start with the ENV from the previous build
# 1. formulae can modify ENV, so we must ensure that each
# 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
pid=fork
if pid.nil?
exec __FILE__, "install-just-one", f.name, *ARGV.options
exec 'ruby', '-r', "#{HOMEBREW_RUBYLIB}/install", f.path, '--', *ARGV.options
else
Process.wait pid
end
@ -122,39 +109,6 @@ begin
end
end
# this is an internal option, don't expose it to the user
when 'install-just-one'
require 'keg'
f=ARGV.formulae.shift
begin
build_time=install f
ohai "Caveats", f.caveats, ''
ohai 'Finishing up' if ARGV.verbose?
clean f
raise "Nothing was installed to #{f.prefix}" unless f.installed?
rescue Exception
if f.prefix.directory?
f.prefix.rmtree
f.prefix.parent.rmdir_if_possible
end
raise
end
begin
Keg.new(f.prefix).link
rescue Exception
onoe "The linking step did not complete successfully"
puts "The package built, but is not symlinked into #{HOMEBREW_PREFIX}"
puts "You can try again using `brew link #{f.name}'"
ohai "Summary" unless ARGV.verbose?
end
ohai "Summary" if ARGV.verbose?
print "#{f.prefix}: #{f.prefix.abv}"
print ", built in #{pretty_duration build_time}" if build_time
puts
when 'ln', 'link'
ARGV.kegs.each {|keg| puts "#{keg.link} links created for #{keg}"}