Clean up and improve build-error output and logs
All logs are now stored from each command executed in Formula.install. Error output is truncated to five lines in an attempt to not overwhelm the user and to encourage users to read the error output and report the bug properly. Maybe we can get that figure up from 70% to 90%.
This commit is contained in:
parent
1100818100
commit
a217b03952
@ -168,9 +168,10 @@ class Cmd
|
||||
dels = @args - args
|
||||
adds = args - @args
|
||||
dups = dels & args
|
||||
puts "brew: Superenv removed: #{dels*' '}" unless dels.empty?
|
||||
puts "brew: Superenv deduped: #{dels}" unless dups.empty?
|
||||
puts "brew: Superenv added: #{adds*' '}" unless adds.empty?
|
||||
|
||||
STDERR.puts "brew: superenv removed: #{dels*' '}" unless dels.empty?
|
||||
STDERR.puts "brew: superenv deduped: #{dels}" unless dups.empty?
|
||||
STDERR.puts "brew: superenv added: #{adds*' '}" unless adds.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -128,7 +128,6 @@ def install f
|
||||
end
|
||||
|
||||
interactive_shell f
|
||||
nil
|
||||
else
|
||||
f.prefix.mkpath
|
||||
f.install
|
||||
|
||||
@ -95,54 +95,13 @@ class BuildError < Homebrew::InstallationError
|
||||
end
|
||||
|
||||
def dump
|
||||
e = self
|
||||
|
||||
require 'cmd/--config'
|
||||
require 'cmd/--env'
|
||||
|
||||
e.backtrace[1] =~ %r{Library/Formula/(.+)\.rb:(\d+)}
|
||||
formula_name = $1
|
||||
error_line = $2
|
||||
|
||||
path = HOMEBREW_REPOSITORY/"Library/Formula/#{formula_name}.rb"
|
||||
if path.symlink? and path.realpath.to_s =~ %r{^#{HOMEBREW_REPOSITORY}/Library/Taps/(\w+)-(\w+)/}
|
||||
repo = "#$1/homebrew-#$2"
|
||||
repo_path = path.realpath.relative_path_from(HOMEBREW_REPOSITORY/"Library/Taps/#$1-#$2").parent.to_s
|
||||
issues_url = "https://github.com/#$1/homebrew-#$2/issues/new"
|
||||
else
|
||||
repo = "mxcl/master"
|
||||
repo_path = "Library/Formula"
|
||||
issues_url = ISSUES_URL
|
||||
end
|
||||
|
||||
if ARGV.verbose?
|
||||
ohai "Exit Status: #{e.exit_status}"
|
||||
puts "https://github.com/#{repo}/blob/master/#{repo_path}/#{formula_name}.rb#L#{error_line}"
|
||||
end
|
||||
ohai "Build Environment"
|
||||
Homebrew.dump_build_config
|
||||
puts %["--use-clang" was specified] if ARGV.include? '--use-clang'
|
||||
puts %["--use-llvm" was specified] if ARGV.include? '--use-llvm'
|
||||
puts %["--use-gcc" was specified] if ARGV.include? '--use-gcc'
|
||||
Homebrew.dump_build_env e.env
|
||||
logs = "#{ENV['HOME']}/Library/Logs/Homebrew/#{formula}/"
|
||||
puts
|
||||
onoe "#{e.to_s.strip} (#{formula_name}.rb:#{error_line})"
|
||||
issues = GitHub.issues_for_formula formula_name
|
||||
puts
|
||||
if issues.empty?
|
||||
puts "This link will help resolve the above errors:"
|
||||
puts " #{Tty.em}#{issues_url}#{Tty.reset}"
|
||||
else
|
||||
puts "These existing issues may help you:", *issues.map{ |s| " #{Tty.em}#{s}#{Tty.reset}" }
|
||||
puts "Otherwise, this may help you fix or report the issue:"
|
||||
puts " #{Tty.em}#{issues_url}#{Tty.reset}"
|
||||
end
|
||||
if e.was_running_configure?
|
||||
puts "We saved the configure log:"
|
||||
puts " ~/Library/Logs/Homebrew/config.log"
|
||||
puts "When you report the issue please paste the build output above and the config.log here:"
|
||||
puts " #{Tty.em}http://gist.github.com/#{Tty.reset}"
|
||||
end
|
||||
onoe "#{formula.name} did not build"
|
||||
puts "Logs: #{logs}" unless Dir["#{logs}/*"].empty?
|
||||
puts "Help: #{Tty.em}https://github.com/mxcl/homebrew/wiki/troubleshooting#{Tty.reset}"
|
||||
issues = GitHub.issues_for_formula(formula.name)
|
||||
puts *issues.map{ |s| " #{Tty.em}#{s}#{Tty.reset}" } unless issues.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ module FileUtils extend self
|
||||
# /tmp volume to the other volume. So we let the user override the tmp
|
||||
# prefix if they need to.
|
||||
tmp = ENV['HOMEBREW_TEMP'].chuzzle || '/tmp'
|
||||
tempd = `/usr/bin/mktemp -d #{tmp}/brew-#{name}-#{version}-XXXX`.chuzzle
|
||||
tempd = `/usr/bin/mktemp -d #{tmp}/#{name}-XXXX`.chuzzle
|
||||
raise "Failed to create sandbox" if tempd.nil?
|
||||
prevd = pwd
|
||||
cd tempd
|
||||
|
||||
@ -223,25 +223,17 @@ class Formula
|
||||
# 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
|
||||
puts if Interrupt === e # don't print next to the ^C
|
||||
unless ARGV.debug?
|
||||
%w(config.log CMakeCache.txt).select{|f| File.exist? f}.each do |f|
|
||||
HOMEBREW_LOGS.install f
|
||||
puts "#{f} was copied to #{HOMEBREW_LOGS}"
|
||||
rescue RuntimeError, SystemCallError => e
|
||||
if not ARGV.debug?
|
||||
%w(config.log CMakeCache.txt).each do |fn|
|
||||
(HOMEBREW_LOGS/name).install(fn) if File.file?(fn)
|
||||
end
|
||||
raise
|
||||
end
|
||||
|
||||
onoe e.inspect
|
||||
puts e.backtrace
|
||||
|
||||
puts e.backtrace unless e.kind_of? BuildError
|
||||
ohai "Rescuing build..."
|
||||
if (e.was_running_configure? rescue false) and File.exist? 'config.log'
|
||||
puts "It looks like an autotools configure failed."
|
||||
puts "Gist 'config.log' and any error output when reporting an issue."
|
||||
puts
|
||||
end
|
||||
|
||||
puts "When you exit this shell Homebrew will attempt to finalise the installation."
|
||||
puts "If nothing is installed or the shell exits with a non-zero error code,"
|
||||
puts "Homebrew will abort. The installation prefix is:"
|
||||
@ -529,23 +521,30 @@ protected
|
||||
if ARGV.verbose?
|
||||
safe_system cmd, *args
|
||||
else
|
||||
@exec_count ||= 0
|
||||
@exec_count += 1
|
||||
logd = HOMEBREW_LOGS/name
|
||||
logfn = "#{logd}/%02d.%s" % [@exec_count, File.basename(cmd).split(' ').first]
|
||||
mkdir_p(logd)
|
||||
|
||||
rd, wr = IO.pipe
|
||||
pid = fork do
|
||||
ENV['VERBOSE'] = '1' # helps with many tool's logging outputs
|
||||
rd.close
|
||||
$stdout.reopen wr
|
||||
$stderr.reopen wr
|
||||
args.collect!{|arg| arg.to_s}
|
||||
exec(cmd, *args) rescue nil
|
||||
puts "Failed to execute: #{cmd}"
|
||||
exit! 1 # never gets here unless exec threw or failed
|
||||
end
|
||||
wr.close
|
||||
out = ''
|
||||
out << rd.read until rd.eof?
|
||||
|
||||
f = File.open(logfn, 'w')
|
||||
f.write(rd.read) until rd.eof?
|
||||
|
||||
Process.wait
|
||||
unless $?.success?
|
||||
puts out
|
||||
raise
|
||||
end
|
||||
raise unless $?.success?
|
||||
end
|
||||
|
||||
removed_ENV_variables.each do |key, value|
|
||||
@ -553,7 +552,21 @@ protected
|
||||
end if removed_ENV_variables
|
||||
|
||||
rescue
|
||||
if f
|
||||
f.flush
|
||||
Kernel.system "/usr/bin/tail -n 5 #{logfn}"
|
||||
require 'cmd/--config'
|
||||
$f = f
|
||||
def Homebrew.puts(*foo); $f.puts *foo end
|
||||
f.puts
|
||||
Homebrew.dump_build_config
|
||||
class << Homebrew; undef :puts end
|
||||
else
|
||||
puts "No logs recorded :(" unless ARGV.verbose?
|
||||
end
|
||||
raise BuildError.new(self, cmd, args, $?)
|
||||
ensure
|
||||
f.close if f
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
@ -200,6 +200,8 @@ class FormulaInstaller
|
||||
end
|
||||
|
||||
def build
|
||||
FileUtils.rm Dir["#{HOMEBREW_LOGS}/#{f}/*"]
|
||||
|
||||
@start_time = Time.now
|
||||
|
||||
# 1. formulae can modify ENV, so we must ensure that each
|
||||
@ -236,7 +238,7 @@ class FormulaInstaller
|
||||
end
|
||||
end
|
||||
|
||||
ignore_interrupts do # the fork will receive the interrupt and marshall it back
|
||||
ignore_interrupts(:quietly) do # the fork will receive the interrupt and marshall it back
|
||||
write.close
|
||||
Process.wait
|
||||
data = read.read
|
||||
@ -245,18 +247,14 @@ class FormulaInstaller
|
||||
raise "Suspicious installation failure" unless $?.success?
|
||||
end
|
||||
|
||||
# This is the installation receipt. The reason this comment is necessary
|
||||
# is because some numpty decided to call the class Tab rather than
|
||||
# the far more appropriate InstallationReceipt :P
|
||||
Tab.for_install(f, args).write
|
||||
raise "Empty installation" if Dir["#{f.prefix}/*"].empty?
|
||||
|
||||
Tab.for_install(f, args).write # INSTALL_RECEIPT.json
|
||||
|
||||
rescue Exception => e
|
||||
ignore_interrupts do
|
||||
# any exceptions must leave us with nothing installed
|
||||
if f.prefix.directory?
|
||||
puts "One sec, just cleaning up..." if e.kind_of? Interrupt
|
||||
f.prefix.rmtree
|
||||
end
|
||||
f.prefix.rmtree if f.prefix.directory?
|
||||
f.rack.rmdir_if_possible
|
||||
end
|
||||
raise
|
||||
|
||||
@ -216,8 +216,10 @@ def inreplace path, before=nil, after=nil
|
||||
end
|
||||
end
|
||||
|
||||
def ignore_interrupts
|
||||
std_trap = trap("INT") { puts "One sec, just cleaning up" }
|
||||
def ignore_interrupts(opt = nil)
|
||||
std_trap = trap("INT") do
|
||||
puts "One sec, just cleaning up" unless opt = :quietly
|
||||
end
|
||||
yield
|
||||
ensure
|
||||
trap("INT", std_trap)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user