~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/failure.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: iso-8859-1 -*-
 
2
""" MoinMoin failure
 
3
 
 
4
    Handle fatal errors by showing a message and debugging information.
 
5
 
 
6
    @copyright: 2004-2005 Nir Soffer <nirs@freeshell.org>
 
7
    @license: GNU GPL, see COPYING for details.
 
8
"""
 
9
import sys, os
 
10
 
 
11
from MoinMoin import log
 
12
logging = log.getLogger(__name__)
 
13
 
 
14
from MoinMoin.support import cgitb
 
15
from MoinMoin.error import ConfigurationError
 
16
from traceback import extract_tb
 
17
 
 
18
 
 
19
class View(cgitb.View):
 
20
    """ Display an error message and debugging information
 
21
 
 
22
    Additions to cgitb.View:
 
23
     - Multiple tracebacks support
 
24
     - Debugging information is shown only in debug mode
 
25
     - Moin application information
 
26
     - General help text and links
 
27
     - Handle multiple paragraphs in exception message
 
28
 
 
29
    cgitb is heavily modified cgitb, but fully backward compatible with
 
30
    the standard cgitb. It should not contain any moin specific code.
 
31
 
 
32
    cgitb was refactored to be easy to customize by applications
 
33
    developers. This moin specific subclass is an example.
 
34
    """
 
35
    debugInfoID = 'debug-info'
 
36
 
 
37
    def formatContent(self):
 
38
        content = (
 
39
            self.script(),
 
40
            self.formatStylesheet(),
 
41
            self.formatTitle(),
 
42
            self.formatMessage(),
 
43
            self.formatButtons(),
 
44
            self.formatDebugInfo(),
 
45
            self.formatTextTraceback()
 
46
            )
 
47
        return ''.join(content)
 
48
 
 
49
    def script(self):
 
50
        return '''
 
51
<script type="text/javascript">
 
52
function toggleDebugInfo() {
 
53
    var tb = document.getElementById('%s');
 
54
    if (tb == null) return;
 
55
    tb.style.display = tb.style.display ? '' : 'none';
 
56
}
 
57
</script>
 
58
''' % self.debugInfoID
 
59
 
 
60
    def stylesheet(self):
 
61
        return cgitb.View.stylesheet(self) + """
 
62
.cgitb .buttons {margin: 0.5em 0; padding: 5px 10px;}
 
63
.cgitb .buttons li {display: inline; margin: 0; padding: 0 0.25em;}
 
64
"""
 
65
 
 
66
    def formatMessage(self):
 
67
        """ handle multiple paragraphs messages and add general help """
 
68
        f = self.formatter
 
69
        text = [self.formatExceptionMessage(self.info)]
 
70
 
 
71
        if self.info[0] == ConfigurationError:
 
72
            tbt = extract_tb(self.info[1].exceptions()[-1][2])[-1]
 
73
            text.append(
 
74
                f.paragraph('Error in your configuration file "%s"'
 
75
                            ' around line %d.' % tbt[:2]))
 
76
        else:
 
77
            text.append(
 
78
                f.paragraph("If you want to report a bug, please save "
 
79
                            "this page and  attach it to your bug report."))
 
80
        return ''.join(text)
 
81
 
 
82
    def formatButtons(self):
 
83
        """ Add 'buttons' to the error dialog """
 
84
        f = self.formatter
 
85
        buttons = [f.link('javascript:toggleDebugInfo()',
 
86
                          'Show debugging information')]
 
87
        if self.info[0] != ConfigurationError:
 
88
            buttons.append(
 
89
                   f.link('http://moinmo.in/MoinMoinBugs',
 
90
                          'Report bug'))
 
91
            buttons.append(
 
92
                   f.link('http://moinmo.in/FrontPage',
 
93
                          'Visit MoinMoin wiki'))
 
94
        return f.list(buttons, {'class': 'buttons'})
 
95
 
 
96
    def formatDebugInfo(self):
 
97
        """ Put debugging information in a hidden div """
 
98
        attributes = {'id': self.debugInfoID}
 
99
        info = [self.debugInfoHideScript(),
 
100
                self.formatTraceback(),
 
101
                self.formatSystemDetails(), ]
 
102
        return self.formatter.section(''.join(info), attributes)
 
103
 
 
104
    def debugInfoHideScript(self):
 
105
        """ Hide debug info for javascript enabled browsers """
 
106
        if self.debug:
 
107
            return ''
 
108
        return '''
 
109
<script type="text/javascript">toggleDebugInfo()</script>
 
110
'''
 
111
 
 
112
    def formatTraceback(self):
 
113
        return self.formatAllTracebacks(self.formatOneTraceback)
 
114
 
 
115
    def formatTextTraceback(self):
 
116
        template = self.textTracebackTemplate()
 
117
        return template % self.formatAllTracebacks(self.formatOneTextTraceback)
 
118
 
 
119
    def formatAllTracebacks(self, formatFuction):
 
120
        """ Format multiple tracebacks using formatFunction """
 
121
        tracebacks = []
 
122
        for ttype, tvalue, tb in self.exceptions():
 
123
            if ttype is None:
 
124
                break
 
125
            tracebacks.append(formatFuction((ttype, tvalue, tb)))
 
126
            del tb
 
127
        return ''.join(tracebacks)
 
128
 
 
129
    def exceptions(self):
 
130
        """ Return a list of exceptions info, starting at self.info """
 
131
        try:
 
132
            return [self.info] + self.info[1].exceptions()
 
133
        except AttributeError:
 
134
            return [self.info]
 
135
 
 
136
    def applicationDetails(self):
 
137
        """ Add MoinMoin details to system details """
 
138
        from MoinMoin import version
 
139
        return ['MoinMoin: Release %s (%s)' % (version.release,
 
140
                                              version.revision)]
 
141
 
 
142
    def formatExceptionMessage(self, info):
 
143
        """ Handle multiple paragraphs in exception message """
 
144
        text = cgitb.View.exceptionMessage(self, info)
 
145
        text = text.split('\n\n')
 
146
        text = ''.join([self.formatter.paragraph(item) for item in text])
 
147
        return text
 
148
 
 
149
 
 
150
def handle(request, err):
 
151
    """ Handle failures
 
152
 
 
153
    Display fancy error view, or fallback to simple text traceback
 
154
    """
 
155
    if 'MOIN_DEBUG' in os.environ:
 
156
        raise err
 
157
 
 
158
    savedError = sys.exc_info()
 
159
    logging.exception('An exception occured.')
 
160
    try:
 
161
        debug = 'debug' in getattr(request, 'form', {})
 
162
        # default to True here to allow an admin setting up the wiki
 
163
        # to see the errors made in the configuration file
 
164
        display = True
 
165
        logdir = None
 
166
        if hasattr(request, 'cfg'):
 
167
            display = request.cfg.traceback_show
 
168
            logdir = request.cfg.traceback_log_dir
 
169
        handler = cgitb.Hook(file=request, display=display, logdir=logdir,
 
170
                             viewClass=View, debug=debug)
 
171
        handler.handle()
 
172
    except:
 
173
        request.write('<pre>\n')
 
174
        printTextException(request, savedError)
 
175
        request.write('\nAdditionally cgitb raised this exception:\n')
 
176
        printTextException(request)
 
177
        request.write('</pre>\n')
 
178
 
 
179
 
 
180
def printTextException(request, info=None):
 
181
    """ Simple text exception that should never fail
 
182
 
 
183
    Print all exceptions in a composite error.
 
184
    """
 
185
    import traceback
 
186
    from MoinMoin import wikiutil
 
187
    if info is None:
 
188
        info = sys.exc_info()
 
189
    try:
 
190
        exceptions = [info] + info[1].exceptions()
 
191
    except AttributeError:
 
192
        exceptions = [info]
 
193
    for info in exceptions:
 
194
        text = ''.join(traceback.format_exception(*info))
 
195
        text = wikiutil.escape(text)
 
196
        request.write(text)
 
197