diff options
Diffstat (limited to 'Library/Homebrew/debrew.rb')
| -rw-r--r-- | Library/Homebrew/debrew.rb | 193 |
1 files changed, 133 insertions, 60 deletions
diff --git a/Library/Homebrew/debrew.rb b/Library/Homebrew/debrew.rb index e8df1aeec..fbddadbd5 100644 --- a/Library/Homebrew/debrew.rb +++ b/Library/Homebrew/debrew.rb @@ -1,75 +1,148 @@ -require 'debrew/menu' -require 'debrew/raise_plus' -require 'set' - -unless ENV['HOMEBREW_NO_READLINE'] - begin - require 'rubygems' - require 'ruby-debug' - rescue LoadError +require "mutex_m" +require "debrew/irb" unless ENV["HOMEBREW_NO_READLINE"] + +module Debrew + extend Mutex_m + + Ignorable = Module.new + + module Raise + def raise(*) + super + rescue Exception => e + e.extend(Ignorable) + super(e) unless Debrew.debug(e) == :ignore + end + + alias_method :fail, :raise end - require 'debrew/irb' -end + module Formula + def install + Debrew.debrew { super } + end + end -class Object - include RaisePlus -end + module Resource + def unpack(target=nil) + return super if target + super do + begin + yield self + rescue Exception => e + Debrew.debug(e) + end + end + end + end + + class Menu + Entry = Struct.new(:name, :action) + + attr_accessor :prompt, :entries + + def initialize + @entries = [] + end + + def choice(name, &action) + entries << Entry.new(name.to_s, action) + end + + def self.choose + menu = new + yield menu + + choice = nil + while choice.nil? + menu.entries.each_with_index { |e, i| puts "#{i+1}. #{e.name}" } + print menu.prompt unless menu.prompt.nil? -module ResourceDebugger - def stage(target=nil, &block) - return super if target + input = $stdin.gets.chomp - super do - begin - block.call(self) - rescue Exception => e - if ARGV.debug? - debrew e + i = input.to_i + if i > 0 + choice = menu.entries[i-1] else - raise + possible = menu.entries.find_all { |e| e.name.start_with?(input) } + + case possible.size + when 0 then puts "No such option" + when 1 then choice = possible.first + else puts "Multiple options match: #{possible.map(&:name).join(" ")}" + end end end + + choice[:action].call end end -end -$debugged_exceptions = Set.new - -def debrew(exception, formula=nil) - raise exception unless $debugged_exceptions.add?(exception) - - puts "#{exception.backtrace.first}" - puts "#{Tty.red}#{exception.class.name}#{Tty.reset}: #{exception}" - - begin - again = false - choose do |menu| - menu.prompt = "Choose an action: " - menu.choice(:raise) { original_raise exception } - menu.choice(:ignore) { exception.restart } if exception.continuation - menu.choice(:backtrace) { puts exception.backtrace; again = true } - menu.choice(:debug) do - puts "When you exit the debugger, execution will continue." - exception.restart { debugger } - end if Object.const_defined?(:Debugger) - menu.choice(:irb) do - puts "When you exit this IRB session, execution will continue." - exception.restart do - # we need to capture the binding after returning from raise - set_trace_func proc { |event, file, line, id, binding, classname| - if event == 'return' - set_trace_func nil - IRB.start_within(binding) - end - } + class << self + alias_method :original_raise, :raise + end + + @active = false + @debugged_exceptions = Set.new + + def self.active? + @active + end + + def self.debugged_exceptions + @debugged_exceptions + end + + def self.debrew + @active = true + Object.send(:include, Raise) + + begin + yield + rescue Exception => e + debug(e) + ensure + @active = false + end + end + + def self.debug(e) + original_raise(e) unless active? && + debugged_exceptions.add?(e) && + try_lock + + begin + puts "#{e.backtrace.first}" + puts "#{Tty.red}#{e.class.name}#{Tty.reset}: #{e}" + + loop do + Menu.choose do |menu| + menu.prompt = "Choose an action: " + + menu.choice(:raise) { original_raise(e) } + menu.choice(:ignore) { return :ignore } if Ignorable === e + menu.choice(:backtrace) { puts e.backtrace } + + menu.choice(:irb) do + puts "When you exit this IRB session, execution will continue." + set_trace_func proc { |event, _, _, id, binding, klass| + if klass == Raise && id == :raise && event == "return" + set_trace_func(nil) + synchronize { IRB.start_within(binding) } + end + } + + return :ignore + end if Object.const_defined?(:IRB) && Ignorable === e + + menu.choice(:shell) do + puts "When you exit this shell, you will return to the menu." + interactive_shell + end end - end if Object.const_defined?(:IRB) && exception.continuation - menu.choice(:shell) do - puts "When you exit this shell, you will return to the menu." - interactive_shell formula - again=true end + ensure + unlock end - end while again + end end |
