Edgewall Software

Ticket #5516: show-enabled-plugins-in-error-page-r6675.diff

File show-enabled-plugins-in-error-page-r6675.diff, 12.2 kB (added by cboos, 6 months ago)

Fixed and improved version of the patch

  • trac/htdocs/css/trac.css

     
    489489#content.error form.newticket { display: inline; } 
    490490#content.error form.newticket textarea { display: none; } 
    491491 
    492 #content.error #systeminfo { margin: 1em; width: auto; } 
    493 #content.error #systeminfo th { font-weight: bold; text-align: right; } 
     492#content.error #systeminfo, 
     493#content.error #plugins { margin: 1em; width: auto; } 
     494#content.error #systeminfo th, 
     495#content.error #plugins th { font-weight: bold; text-align: right; } 
    494496 
    495497#content.error #traceback { margin-left: 1em; } 
    496498#content.error #traceback :link, #content.error #traceback :visited { 
     
    504506  font-style: normal; 
    505507  font-weight: bold; 
    506508} 
    507 #content.error #traceback span.file { color: #666; font-size: 85%; } 
     509#content.error #traceback span.file, 
     510#content.error #plugins span.file { color: #666; font-size: 85%; } 
     511 
    508512#content.error #traceback ul { list-style: none; margin: .5em 0; padding: 0; } 
    509513#content.error #traceback ol { 
    510514  border: 1px dotted #d7d7d7; 
  • trac/admin/web_ui.py

     
    467467        if changes: 
    468468            self.config.save() 
    469469 
    470     def _render_view(self, req): 
     470    def get_plugins_data(self): 
    471471        plugins = {} 
    472472        plugins_dir = os.path.realpath(os.path.join(self.env.path, 'plugins')) 
    473473        plugins_dir = os.path.normcase(plugins_dir) # needs to match loader.py 
     
    490490                if plugin_filename and os.access(dist.location, 
    491491                                                 os.F_OK + os.W_OK): 
    492492                    readonly = False 
    493                 if plugin_filename: 
     493                # retrieve plugin metadata 
     494                info = get_pkginfo(dist) 
     495                if not info: 
    494496                    info = {'summary': description} 
    495                     for k in 'author author_email home_page license'.split(): 
     497                    for k in ('author author_email home_page url license trac' 
     498                              .split()): 
    496499                        v = getattr(module, k, '') 
    497500                        if v: 
     501                            if k == 'home_page' or k == 'url': 
     502                                k = 'home_page' 
     503                                v = v.replace('$', '').replace('URL: ', '')  
    498504                            info[k] = v 
     505                # retrieve plugin version info 
     506                version = dist.version 
     507                if not version: 
    499508                    version = (getattr(module, 'version', '') or 
    500509                               getattr(module, 'revision', '')) 
    501510                    # special handling for "$Rev$" strings 
    502511                    version = version.replace('$', '').replace('Rev: ', 'r')  
    503                 else: 
    504                     info = get_pkginfo(dist) 
    505                     version = dist.version 
    506512                plugins[dist.project_name] = { 
    507513                    'name': dist.project_name, 'version': version, 
    508514                    'path': dist.location, 'description': description, 
     
    531537        addons.sort() 
    532538        plugin_list += [plugins[category] for category in addons] 
    533539 
    534         data = { 
     540        return { 
    535541            'plugins': plugin_list, 
    536542            'readonly': not os.access(plugins_dir, os.F_OK + os.W_OK) 
    537543        } 
    538         return 'admin_plugins.html', data 
    539544 
     545    def _render_view(self, req): 
     546        return 'admin_plugins.html', self.get_plugins_data() 
     547 
    540548    def _find_distribution(self, module): 
    541549        path = get_module_path(module) 
    542550        if path == self.trac_path: 
  • trac/templates/error.html

     
    4242       descr = descr.replace(/==== System Information ====\s+/m, 
    4343         "User Agent was: `" + navigator.userAgent + "`\n\n$&" 
    4444       ); 
    45        descr = descr.replace(/\|\|\s+==== Python Traceback ====/m, 
     45       descr = descr.replace(/\|\|\s+==== Enabled Plugins ====/m, 
    4646         "||\n|| '''jQuery:''' || `" + $().jquery + "` $&" 
    4747       ); 
    4848       $("#description").text(descr); 
     
    7575<py:for each="k, v in trac.systeminfo"> 
    7676|| '''$k''' || ${'`%s`' % (v and v.replace('\n', '` [[br]] `'))} ||</py:for> 
    7777 
     78<py:if test="plugins_list"> 
     79==== Enabled Plugins ==== 
     80<py:for each="plugin in plugins_list"> 
     81|| '''`$plugin.name`''' || `$plugin.version` || ${('frame_idx' in plugin and "'''`%s`'''" or "`%s`") % plugin.path} ||</py:for> 
     82</py:if> 
     83 
    7884==== Python Traceback ==== 
    7985{{{ 
    8086${traceback} 
     
    121127              </p> 
    122128            </py:when> 
    123129            <py:otherwise> 
    124               <p>If you think this should work you can reproduce the problem, 
    125               you should consider reporting this to the Trac team.</p> 
     130              <p>If you think this should work and you can reproduce the problem, 
     131              you should consider creating a bug report.</p> 
     132              <py:with vars="faulty_plugins = [p for p in plugins_list if 'frame_idx' in p]"> 
     133                <p py:if="faulty_plugins" py:choose="len(faulty_plugins)"> 
     134                  <py:when test="1"> 
     135                    Note that the ${faulty_plugins[0].name} plugin seems to be involved in this problem.  
     136                  </py:when> 
     137                  <py:otherwise> 
     138                    Note that the following plugins seem to be involved in this problem:  
     139                    ${', '.join([p.name for p in faulty_plugins])}. 
     140                  </py:otherwise> 
     141                  <br /> 
     142                  <strong>Please report this issue to the ${tracker.name} plugin maintainer.</strong> 
     143                </p> 
     144              </py:with> 
    126145              <p>Before you do that, though, please first try 
    127146                <a py:with="q = quote_plus(message[:80])" 
    128                    href="${trac.homepage}/search?ticket=yes&amp;noquickjump=1&amp;q=$q">searching</a> 
     147                   href='${tracker.url}/search?ticket=yes&amp;noquickjump=1&amp;q="$q"'>searching</a> 
    129148                for similar issues, as it is quite likely that this problem 
    130149                has been reported before. For questions about installation 
    131                 and configuration of Trac, please try the 
     150                and configuration of Trac or its plugins, please try the 
    132151                <a href="${trac.homepage}/wiki/MailingList">mailing list</a> 
    133                 instead of filing a ticket. 
     152                instead of creating a ticket. 
    134153              </p> 
    135               <form class="newticket" method="get" action="${trac.homepage}/newticket"> 
    136                 <p>Otherwise, please ${create_ticket(True)} a new ticket at 
    137                 the Trac project site, where you can describe the problem and 
     154              <form class="newticket" method="get" action="${tracker.url}/newticket"> 
     155                <p>Otherwise, please ${create_ticket(teo=tracker.url=='http://trac.egdewall.org')} a new bug report at 
     156                the ${tracker.name}'s Trac, where you can describe the problem and 
    138157                explain how to reproduce it.</p> 
    139158              </form> 
    140159              <py:if test="traceback"> 
     
    184203                  <td>$value</td> 
    185204                </tr> 
    186205              </table> 
     206              <py:if test="plugins_list"> 
     207                <h2>Enabled Plugins</h2> 
     208                <table class="listing" id="plugins"> 
     209                  <tr py:for="plugin in plugins_list"> 
     210                    <th py:with="url = plugin.info.home_page; 
     211                                 email = plugin.info.author_email; 
     212                                 report_url = url or email and 'mailto:'+email"> 
     213                        <a py:strip="not report_url" href="$report_url">$plugin.name</a> 
     214                    </th> 
     215                    <td>$plugin.version</td> 
     216                    <td> 
     217                      <span class="file"><a py:strip="not plugin.frame_idx" href="#frame$plugin.frame_idx">$plugin.path</a></span> 
     218                    </td> 
     219                  </tr> 
     220                </table> 
     221              </py:if> 
     222 
    187223            </py:otherwise> 
    188224          </py:choose> 
    189225        </py:when> 
  • trac/web/main.py

     
    3939from trac.perm import PermissionCache, PermissionError, PermissionSystem 
    4040from trac.resource import ResourceNotFound 
    4141from trac.util import get_lines_from_file, get_last_traceback, hex_entropy 
    42 from trac.util.compat import partial, reversed 
     42from trac.util.compat import partial, reversed, any 
    4343from trac.util.datefmt import format_datetime, http_date, localtz, timezone 
    4444from trac.util.text import shorten_line, to_unicode 
    4545from trac.web.api import * 
     
    446446            message = "%s: %s" % (e.__class__.__name__, to_unicode(e)) 
    447447            traceback = get_last_traceback() 
    448448 
     449            # gather frame information 
    449450            frames = [] 
    450451            has_admin = False 
    451452            try: 
     
    471472                                    'vars': tb.tb_frame.f_locals}] 
    472473                    tb = tb.tb_next 
    473474 
     475            # gather plugins information 
     476            from trac.admin.web_ui import PluginAdminPanel 
     477            plugins_data = PluginAdminPanel(env).get_plugins_data() 
     478            # plugins: only keep those which have at least one component enabled 
     479            plugins_list = [p for p in plugins_data['plugins'][1:] 
     480                            if any([c['enabled'] for c in p['components']])] 
     481            # plugins: verify if one of their source file is in the backtrace 
     482            egg_frames = [(i, f) for i, f in enumerate(frames)  
     483                          if f['filename'].startswith('build')] 
     484            for plugin in plugins_list: 
     485                plugin_base, ext = os.path.splitext(plugin['path']) 
     486                if ext == '.egg' and egg_frames: 
     487                    try: 
     488                        for dist in pkg_resources.find_distributions( 
     489                                plugin['path'], only=True): 
     490                            sources = dist.get_metadata("SOURCES.txt") 
     491                            for src in sources.splitlines(): 
     492                                if src.endswith('.py'): 
     493                                    nsrc = os.path.normpath(src) 
     494                                    for i, f in egg_frames: 
     495                                        if f['filename'].endswith(nsrc): 
     496                                            plugin['frame_idx'] = i 
     497                                            raise StopIteration 
     498                    except StopIteration: 
     499                        pass 
     500                else: 
     501                    for i, f in enumerate(frames): 
     502                        if f['filename'].startswith(plugin_base): 
     503                            plugin['frame_idx'] = i 
     504                            break 
     505            # identify tracker in which the bug should be reported 
     506            teo = 'http://trac.edgewall.org' 
     507            th = 'http://trac-hacks.org' 
     508            tracker_name = 'Trac project' 
     509            tracker_url = teo 
     510            topmost = 0 
     511            for plugin in plugins_list: 
     512                if 'frame_idx' in plugin: 
     513                    i = plugin['frame_idx'] 
     514                    if i > topmost: 
     515                        topmost = i 
     516                        tracker_name = plugin['name'] 
     517                        if 'trac' in plugin['info']: 
     518                            tracker_url = plugin['info']['trac'] 
     519                        elif plugin['info'].get('home_page', '').startswith(th): 
     520                            tracker_url = th 
     521 
    474522            data = {'title': 'Internal Error', 
    475523                    'type': 'internal', 'message': message, 
    476524                    'traceback': traceback, 'frames': frames, 
    477                     'shorten_line': shorten_line} 
     525                    'shorten_line': shorten_line,  
     526                    'plugins_list': plugins_list,  
     527                    'tracker': {'name': tracker_name, 'url': tracker_url}} 
    478528 
    479529            try: 
    480530                req.send_error(exc_info, status=500, env=env, data=data)