297 lines
8.9 KiB
Python
297 lines
8.9 KiB
Python
#
|
|
# exception.py - general exception formatting and saving
|
|
#
|
|
# Matt Wilson <msw@redhat.com>
|
|
# Erik Troan <ewt@redhat.com>
|
|
# Harald Hoyer <harald@redhat.com>
|
|
#
|
|
# Copyright 2001, 2002 Red Hat, Inc.
|
|
#
|
|
# This software may be freely redistributed under the terms of the GNU
|
|
# library public license.
|
|
#
|
|
# You should have received a copy of the GNU Library Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
#
|
|
|
|
import os, sys
|
|
import signal
|
|
import traceback
|
|
import types
|
|
from string import joinfields
|
|
from cPickle import Pickler
|
|
dumpHash = {}
|
|
#from rhpl.translate import _
|
|
def _(x):
|
|
return x
|
|
|
|
|
|
#
|
|
# ExceptionWindow class
|
|
#
|
|
class ExceptionWindow:
|
|
def __init__ (self, text, component_name):
|
|
import gtk
|
|
win = gtk.Dialog(_("Exception Occured"), None, gtk.DIALOG_MODAL)
|
|
win.add_button(_("Debug"), 0)
|
|
win.add_button(_("Save to file"), 1)
|
|
win.add_button(gtk.STOCK_QUIT, 2)
|
|
buffer = gtk.TextBuffer(None)
|
|
buffer.set_text(text)
|
|
textbox = gtk.TextView()
|
|
textbox.set_buffer(buffer)
|
|
textbox.set_property("editable", gtk.FALSE)
|
|
textbox.set_property("cursor_visible", gtk.FALSE)
|
|
sw = gtk.ScrolledWindow ()
|
|
sw.add (textbox)
|
|
sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
hbox = gtk.HBox (gtk.FALSE)
|
|
hbox.set_border_width(5)
|
|
txt = _("An unhandled exception has occured. This "
|
|
"is most likely a bug. Please save the crash "
|
|
"dump and file a detailed bug "
|
|
"report against %s at "
|
|
"https://bugzilla.redhat.com/bugzilla") % \
|
|
component_name
|
|
info = gtk.Label(txt)
|
|
info.set_line_wrap(gtk.TRUE)
|
|
hbox.pack_start (sw, gtk.TRUE)
|
|
win.vbox.pack_start (info, gtk.FALSE)
|
|
win.vbox.pack_start (hbox, gtk.TRUE)
|
|
win.vbox.set_border_width(5)
|
|
win.set_size_request (500, 300)
|
|
win.set_position (gtk.WIN_POS_CENTER)
|
|
addFrame(win)
|
|
win.show_all ()
|
|
self.window = win
|
|
self.rc = self.window.run ()
|
|
self.window.destroy()
|
|
|
|
def quit (self, dialog, button):
|
|
self.rc = button
|
|
|
|
def getrc (self):
|
|
# I did it this way for future expantion
|
|
# 0 is debug
|
|
if self.rc == 0:
|
|
return 1
|
|
# 1 is save
|
|
if self.rc == 1:
|
|
return 2
|
|
# 2 is OK
|
|
elif self.rc == 2:
|
|
return 0
|
|
|
|
def addFrame(dialog):
|
|
import gtk
|
|
contents = dialog.get_children()[0]
|
|
dialog.remove(contents)
|
|
frame = gtk.Frame()
|
|
frame.set_shadow_type(gtk.SHADOW_OUT)
|
|
frame.add(contents)
|
|
dialog.add(frame)
|
|
|
|
# XXX do length limits on obj dumps.
|
|
def dumpClass(instance, fd, level=0):
|
|
# protect from loops
|
|
if not dumpHash.has_key(instance):
|
|
dumpHash[instance] = None
|
|
else:
|
|
fd.write("Already dumped\n")
|
|
return
|
|
if (instance.__class__.__dict__.has_key("__str__") or
|
|
instance.__class__.__dict__.has_key("__repr__")):
|
|
fd.write("%s\n" % (instance,))
|
|
return
|
|
fd.write("%s instance, containing members:\n" %
|
|
(instance.__class__.__name__))
|
|
pad = ' ' * ((level) * 2)
|
|
for key, value in instance.__dict__.items():
|
|
if type(value) == types.ListType:
|
|
fd.write("%s%s: [" % (pad, key))
|
|
first = 1
|
|
for item in value:
|
|
if not first:
|
|
fd.write(", ")
|
|
else:
|
|
first = 0
|
|
if type(item) == types.InstanceType:
|
|
dumpClass(item, fd, level + 1)
|
|
else:
|
|
fd.write("%s" % (item,))
|
|
fd.write("]\n")
|
|
elif type(value) == types.DictType:
|
|
fd.write("%s%s: {" % (pad, key))
|
|
first = 1
|
|
for k, v in value.items():
|
|
if not first:
|
|
fd.write(", ")
|
|
else:
|
|
first = 0
|
|
if type(k) == types.StringType:
|
|
fd.write("'%s': " % (k,))
|
|
else:
|
|
fd.write("%s: " % (k,))
|
|
if type(v) == types.InstanceType:
|
|
dumpClass(v, fd, level + 1)
|
|
else:
|
|
fd.write("%s" % (v,))
|
|
fd.write("}\n")
|
|
elif type(value) == types.InstanceType:
|
|
fd.write("%s%s: " % (pad, key))
|
|
dumpClass(value, fd, level + 1)
|
|
else:
|
|
fd.write("%s%s: %s\n" % (pad, key, value))
|
|
|
|
def dumpException(out, text, tb):
|
|
p = Pickler(out)
|
|
|
|
out.write(text)
|
|
|
|
trace = tb
|
|
while trace.tb_next:
|
|
trace = trace.tb_next
|
|
frame = trace.tb_frame
|
|
out.write ("\nLocal variables in innermost frame:\n")
|
|
try:
|
|
for (key, value) in frame.f_locals.items():
|
|
out.write ("%s: %s\n" % (key, value))
|
|
except:
|
|
pass
|
|
|
|
|
|
def exceptionWindow(title, text, name):
|
|
import gtk
|
|
#print text
|
|
win = ExceptionWindow (text, name)
|
|
|
|
return win.getrc ()
|
|
|
|
|
|
def generic_error_dialog (message, parent_dialog,
|
|
message_type=None,
|
|
widget=None, page=0, broken_widget=None):
|
|
import gtk
|
|
if message_type == None:
|
|
message_type = gtk.MESSAGE_ERROR
|
|
|
|
dialog = gtk.MessageDialog(parent_dialog,
|
|
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
message_type, gtk.BUTTONS_OK,
|
|
message)
|
|
|
|
if widget != None:
|
|
if isinstance (widget, gtk.CList):
|
|
widget.select_row (page, 0)
|
|
elif isinstance (widget, gtk.Notebook):
|
|
widget.set_current_page (page)
|
|
if broken_widget != None:
|
|
broken_widget.grab_focus ()
|
|
if isinstance (broken_widget, gtk.Entry):
|
|
broken_widget.select_region (0, -1)
|
|
|
|
if parent_dialog:
|
|
dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
|
|
dialog.set_transient_for(parent_dialog)
|
|
else:
|
|
dialog.set_position (gtk.WIN_POS_CENTER)
|
|
|
|
ret = dialog.run ()
|
|
dialog.destroy()
|
|
return ret
|
|
|
|
#
|
|
# FileSelection class
|
|
#
|
|
class FileSelection:
|
|
def __init__(self, text):
|
|
import gtk
|
|
import gnome.ui
|
|
win = gtk.Dialog (_("Select a file:"))
|
|
#win.connect ("clicked", self.quit)
|
|
win.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK)
|
|
win.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
|
|
hbox = gtk.HBox (FALSE)
|
|
|
|
info = gtk.Label(text)
|
|
self.entry = gnome.ui.FileEntry("", "")
|
|
self.entry.set_modal(TRUE)
|
|
win.vbox.pack_start (info, FALSE)
|
|
win.vbox.pack_start (self.entry, TRUE)
|
|
win.set_position (gtk.WIN_POS_CENTER)
|
|
win.show_all ()
|
|
self.window = win
|
|
self.rc = self.window.run ()
|
|
|
|
def quit (self, dialog, button):
|
|
self.rc = button
|
|
|
|
def getrc (self):
|
|
return self.rc
|
|
|
|
def get_filename(self):
|
|
return self.entry.get_full_path(FALSE)
|
|
|
|
#
|
|
# handleException function
|
|
#
|
|
def handleException((type, value, tb), progname, version):
|
|
import gtk
|
|
list = traceback.format_exception (type, value, tb)
|
|
tblast = traceback.extract_tb(tb, limit=None)
|
|
if len(tblast):
|
|
tblast = tblast[len(tblast)-1]
|
|
extxt = traceback.format_exception_only(type, value)
|
|
text = "Component: %s\n" % progname
|
|
text = text + "Version: %s\n" % version
|
|
text = text + "Summary: TB "
|
|
if tblast and len(tblast) > 3:
|
|
tblast = tblast[:3]
|
|
for t in tblast:
|
|
text = text + str(t) + ":"
|
|
text = text + extxt[0]
|
|
text = text + joinfields(list, "")
|
|
|
|
while 1:
|
|
rc = exceptionWindow (_("Exception Occurred"), text, progname)
|
|
|
|
if rc == 1 and tb:
|
|
print text
|
|
import pdb
|
|
pdb.post_mortem (tb)
|
|
os.kill(os.getpid(), signal.SIGKILL)
|
|
elif not rc:
|
|
sys.exit(10)
|
|
else:
|
|
fs = FileSelection(_("Please specify a file to save the dump"))
|
|
rc = fs.getrc()
|
|
if rc == gtk.RESPONSE_OK:
|
|
file = fs.get_filename()
|
|
print file
|
|
fs.window.destroy()
|
|
|
|
if not file or file=="":
|
|
file = "/tmp/dump"
|
|
|
|
try:
|
|
out = open(file, "w")
|
|
dumpException (out, text, tb)
|
|
out.close()
|
|
|
|
except IOError:
|
|
generic_error_dialog(_("Failed to write to file %s.") \
|
|
% (file), None)
|
|
else:
|
|
generic_error_dialog(
|
|
_("The application's state has been successfully\n"
|
|
"written to the file '%s'.") % (file), None,
|
|
message_type = "info")
|
|
sys.exit(10)
|
|
|
|
else:
|
|
continue
|
|
|
|
sys.exit(10)
|
|
|