You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by gj...@apache.org on 2012/10/16 22:06:19 UTC

svn commit: r1398968 [2/28] - in /incubator/bloodhound/trunk/trac: ./ contrib/ doc/ doc/api/ doc/utils/ sample-plugins/ sample-plugins/permissions/ sample-plugins/workflow/ trac/ trac/admin/ trac/admin/templates/ trac/admin/tests/ trac/db/ trac/db/test...

Modified: incubator/bloodhound/trunk/trac/trac/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/__init__.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/__init__.py (original)
+++ incubator/bloodhound/trunk/trac/trac/__init__.py Tue Oct 16 20:06:09 2012
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2003-2009 Edgewall Software
+# Copyright (C) 2003-2012 Edgewall Software
 # All rights reserved.
 #
 # This software is licensed as described in the file COPYING, which
@@ -16,4 +16,4 @@ from pkg_resources import DistributionNo
 try:
     __version__ = get_distribution('Trac').version
 except DistributionNotFound:
-    __version__ = '0.13dev'
+    __version__ = '1.0'

Modified: incubator/bloodhound/trunk/trac/trac/admin/api.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/api.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/api.py (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/api.py Tue Oct 16 20:06:09 2012
@@ -16,6 +16,7 @@ import sys
 import traceback
 
 from trac.core import *
+from trac.util.text import levenshtein_distance
 from trac.util.translation import _
 
 
@@ -133,6 +134,23 @@ class AdminCommandManager(Component):
                         raise
         raise AdminCommandError(_("Command not found"), show_usage=True)
 
+    def get_similar_commands(self, arg, n=5):
+        if not arg:
+            return []
+
+        cmds = set()
+        for provider in self.providers:
+            for cmd in provider.get_admin_commands() or []:
+                cmds.add(cmd[0].split()[0]) # use only first token
+
+        def score(cmd, arg):
+            if cmd.startswith(arg):
+                return 0
+            return levenshtein_distance(cmd, arg) / float(len(cmd) + len(arg))
+        similars = sorted((score(cmd, arg), cmd) for cmd in cmds)
+        similars = [cmd for val, cmd in similars if val <= 0.5]
+        return similars[:n]
+
 
 class PrefixList(list):
     """A list of prefixes for command argument auto-completion."""

Modified: incubator/bloodhound/trunk/trac/trac/admin/console.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/console.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/console.py (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/console.py Tue Oct 16 20:06:09 2012
@@ -32,8 +32,8 @@ from trac.util import translation
 from trac.util.html import html
 from trac.util.text import console_print, exception_to_unicode, printout, \
                            printerr, raw_input, to_unicode
-from trac.util.translation import _, get_negotiated_locale, has_babel, \
-                                  cleandoc_
+from trac.util.translation import _, ngettext, get_negotiated_locale, \
+                                  has_babel, cleandoc_
 from trac.versioncontrol.api import RepositoryManager
 from trac.wiki.admin import WikiAdmin
 from trac.wiki.macros import WikiMacroBase
@@ -65,6 +65,7 @@ class TracAdmin(cmd.Cmd):
     prompt = "Trac> "
     envname = None
     __env = None
+    needs_upgrade = None
 
     def __init__(self, envdir=None):
         cmd.Cmd.__init__(self)
@@ -266,11 +267,19 @@ Type:  '?' or 'help' for help on command
         try:
             if not self.__env:
                 self._init_env()
+            if self.needs_upgrade is None:
+                self.needs_upgrade = self.__env.needs_upgrade()
         except TracError, e:
             raise AdminCommandError(to_unicode(e))
         except Exception, e:
             raise AdminCommandError(exception_to_unicode(e))
         args = self.arg_tokenize(line)
+        if args[0] == 'upgrade':
+            self.needs_upgrade = None
+        elif self.needs_upgrade:
+            raise TracError(_('The Trac Environment needs to be upgraded.\n\n'
+                              'Run "trac-admin %(path)s upgrade"',
+                              path=self.envname))
         cmd_mgr = AdminCommandManager(self.env)
         return cmd_mgr.execute_command(*args)
 
@@ -301,8 +310,17 @@ Type:  '?' or 'help' for help on command
             if doc:
                 self.print_doc(doc)
             else:
-                printerr(_("No documentation found for '%(cmd)s'",
+                printerr(_("No documentation found for '%(cmd)s'."
+                           " Use 'help' to see the list of commands.",
                            cmd=' '.join(arg)))
+                cmds = cmd_mgr.get_similar_commands(arg[0])
+                if cmds:
+                    printout('')
+                    printout(ngettext("Did you mean this?",
+                                      "Did you mean one of these?",
+                                      len(cmds)))
+                    for cmd in cmds:
+                        printout('    ' + cmd)
         else:
             printout(_("trac-admin - The Trac Administration Console "
                        "%(version)s", version=TRAC_VERSION))
@@ -568,7 +586,7 @@ def run(args=None):
             admin.env_set(env_path)
             if len(args) > 1:
                 s_args = ' '.join(["'%s'" % c for c in args[2:]])
-                command = args[1] + ' ' +s_args
+                command = args[1] + ' ' + s_args
                 return admin.onecmd(command)
             else:
                 while True:

Modified: incubator/bloodhound/trunk/trac/trac/admin/templates/admin_components.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/templates/admin_components.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/templates/admin_components.html (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/templates/admin_components.html Tue Oct 16 20:06:09 2012
@@ -15,7 +15,7 @@
 
     <py:def function="owner_field(default_owner='')">
       <div class="field">
-        <label>Owner: <br />
+        <label>Owner:
           <py:choose>
             <select py:when="owners" size="1" id="owner" name="owner">
               <option py:for="owner in owners"
@@ -38,7 +38,7 @@
           </div>
           ${owner_field(component.owner)}
           <div class="field">
-            <fieldset class="iefix">
+            <fieldset>
               <label for="description" i18n:msg="">
                 Description (you may use
                 <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a>
@@ -63,7 +63,7 @@ $component.description</textarea>
           <fieldset>
             <legend>Add Component:</legend>
             <div class="field">
-              <label>Name:<br /><input type="text" name="name" /></label>
+              <label>Name: <input type="text" name="name"/></label>
             </div>
             ${owner_field()}
             <div class="buttons">

Modified: incubator/bloodhound/trunk/trac/trac/admin/templates/admin_enums.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/templates/admin_enums.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/templates/admin_enums.html (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/templates/admin_enums.html Tue Oct 16 20:06:09 2012
@@ -32,7 +32,7 @@
           <fieldset>
             <legend i18n:msg="label_singular">Add $label_singular</legend>
             <div class="field">
-              <label>Name:<input type="text" name="name" id="name"/></label>
+              <label>Name: <input type="text" name="name" id="name"/></label>
             </div>
             <div class="buttons">
               <input type="submit" name="add" value="${_('Add')}"/>

Modified: incubator/bloodhound/trunk/trac/trac/admin/templates/admin_milestones.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/templates/admin_milestones.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/templates/admin_milestones.html (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/templates/admin_milestones.html Tue Oct 16 20:06:09 2012
@@ -8,6 +8,12 @@
   <xi:include href="admin.html" />
   <head>
     <title>Milestones</title>
+    <script type="text/javascript">/*<![CDATA[*/
+      jQuery(document).ready(function($) {
+        $("#duedate").datetimepicker();
+        $("#completeddate").datetimepicker();
+      });
+    /*]]>*/</script>
   </head>
 
   <body>
@@ -26,7 +32,7 @@
               <input type="text" id="duedate" name="duedate" size="${len(datetime_hint)}"
                      value="${milestone.due and format_datetime(milestone.due)}" readonly="${readonly}"
                      title="${_('Format: %(datehint)s', datehint=datetime_hint)}"/>
-              <em i18n:msg="datehint">Format: $datetime_hint</em>
+              <span class="hint" i18n:msg="datehint">Format: $datetime_hint</span>
             </label>
           </div>
           <div class="field">
@@ -40,7 +46,7 @@
                      size="${len(datetime_hint)}"
                      value="${format_datetime(milestone.completed)}" readonly="${readonly}"
                      title="${_('Format: %(datehint)s', datehint=datetime_hint)}"/>
-              <em i18n:msg="datehint">Format: $datetime_hint</em>
+              <span class="hint" i18n:msg="datehint">Format: $datetime_hint</span>
             </label>
             <script type="text/javascript">
               jQuery(document).ready(function($) {
@@ -53,7 +59,7 @@
             </script>
           </div>
           <div class="field">
-            <fieldset class="iefix">
+            <fieldset>
               <label for="description" i18n:msg="">
                 Description (you may use <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here):
               </label>
@@ -76,14 +82,14 @@ ${milestone.description}</textarea>
           <fieldset>
             <legend>Add Milestone:</legend>
             <div class="field">
-              <label>Name:<br /><input type="text" name="name" id="name" size="22" /></label>
+              <label>Name: <input type="text" name="name" id="name" size="22"/></label>
             </div>
             <div class="field">
               <label>
-                Due:<br />
+                Due:
                 <input type="text" id="duedate" name="duedate" size="${len(datetime_hint)}"
-                       title="${_('Format: %(datehint)s', datehint=datetime_hint)}" /><br/>
-                <em i18n:msg="datetimehint">Format: $datetime_hint</em>
+                       title="${_('Format: %(datehint)s', datehint=datetime_hint)}"/>
+                <span class="hint" i18n:msg="datetimehint">Format: $datetime_hint</span>
               </label>
             </div>
             <div class="buttons">

Modified: incubator/bloodhound/trunk/trac/trac/admin/templates/admin_perms.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/templates/admin_perms.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/templates/admin_perms.html (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/templates/admin_perms.html Tue Oct 16 20:06:09 2012
@@ -11,87 +11,101 @@
   </head>
 
   <body>
-    <h2>Manage Permissions</h2>
+    <h2>Manage Permissions and Groups</h2>
 
     <py:if test="'PERMISSION_GRANT' in perm">
-    <form id="addperm" class="addnew" method="post" action="">
-      <fieldset>
-        <legend>Grant Permission:</legend>
-        <table>
-          <tr class="field">
-            <th><label for="gp_subject">Subject:</label></th>
-            <td><input id="gp_subject" type="text" name="subject" /></td>
-          </tr>
-          <tr class="field">
-            <th><label for="action">Action:</label></th>
-            <td>
+      <form id="addperm" class="addnew" method="post" action="">
+        <fieldset>
+          <legend>Grant Permission:</legend>
+          <div class="field">
+            <label>Subject: <input id="gp_subject" type="text" name="subject" /></label>
+          </div>
+          <div class="field">
+            <label>Action:
               <select id="action" name="action">
                 <option py:for="action in sorted(actions)">$action</option>
               </select>
-            </td>
-          </tr>
-        </table>
-        <p class="help">
-          Grant permission for an action to a subject, which can be either a user
-          or a group.
-        </p>
-        <div class="buttons">
-          <input type="submit" name="add" value="${_('Add')}" />
-        </div>
-      </fieldset>
-    </form>
-
-    <form id="addsubj" class="addnew" method="post" action="">
-      <fieldset>
-        <legend>Add Subject to Group:</legend>
-        <table>
-          <tr class="field">
-            <th><label for="sg_subject">Subject:</label></th>
-            <td><input id="sg_subject" type="text" name="subject" /></td>
-          </tr>
-          <tr class="field">
-            <th><label for="sg_group">Group:</label></th>
-            <td><input id="sg_group" type="text" name="group" /></td>
-          </tr>
-        </table>
-        <p class="help">
-          Add a user or group to an existing permission group.
-        </p>
-        <div class="buttons">
-          <input type="submit" name="add" value="${_('Add')}"/>
-        </div>
-      </fieldset>
-    </form>
+            </label>
+          </div>
+          <div class="buttons">
+            <input type="submit" name="add" value="${_('Add')}" />
+          </div>
+          <p class="help">
+            Grant permission for an action to a subject, which can be either a user
+            or a group.
+          </p>
+        </fieldset>
+      </form>
+  
+      <form id="addsubj" class="addnew" method="post" action="">
+        <fieldset>
+          <legend>Add Subject to Group:</legend>
+          <div class="field">
+            <label>Subject: <input id="sg_subject" type="text" name="subject"/></label>
+          </div>
+          <div class="field">
+            <label>Group: <input id="sg_group" type="text" name="group" /></label>
+          </div>
+          <div class="buttons">
+            <input type="submit" name="add" value="${_('Add')}"/>
+          </div>
+          <p class="help">
+            Add a user or group to an existing permission group.
+          </p>
+        </fieldset>
+      </form>
     </py:if>
 
-    <form id="revokeform" method="post" py:with="revoke_perm = 'PERMISSION_REVOKE' in perm" action="">
+    <form id="revokeform" method="post" action="" py:with="can_revoke = 'PERMISSION_REVOKE' in perm">
+      <h3>Permissions</h3>
       <table class="listing" id="permlist">
         <thead>
           <tr><th>Subject</th><th>Action</th></tr>
         </thead>
         <tbody>
-          <tr py:for="idx, (subject, perm_group) in enumerate(groupby(sorted(perms), key=lambda tmp: tmp[0]))"
+          <tr py:for="idx, (subject, perm_group) in enumerate(groupby(sorted(perms), key=lambda p: p[0]))"
               class="${'odd' if idx % 2 else 'even'}">
             <td>$subject</td>
             <td>
-              <py:for each="cnt, (subject,action) in enumerate(perm_group)"
-                      py:with="subject_action='%s:%s' % (unicode_to_base64(subject),
-                                                         unicode_to_base64(action));
-                               subject_action_id='sa-%d-%d' % (idx, cnt)">
-                <!--! base64 make it safe to use ':' as separator when passing
+              <label py:for="subject, action in perm_group">
+                <!--! base64 makes it safe to use ':' as separator when passing
+                      both subject and action as one query parameter -->
+                <input py:if="can_revoke" type="checkbox" name="sel"
+                       value="${'%s:%s' % (unicode_to_base64(subject),
+                                           unicode_to_base64(action))}"/>
+                <span py:strip="action in actions" class="missing"
+                      title="Action is no longer defined">${action}</span>
+              </label>
+            </td>
+          </tr>
+          <tr py:if="not perms"><td colspan="2">No permissions</td></tr>
+        </tbody>
+      </table>
+
+      <h3>Group Membership</h3>
+      <table class="listing" id="grouplist">
+        <thead>
+          <tr><th>Group</th><th>Subject</th></tr>
+        </thead>
+        <tbody>
+          <tr py:for="idx, (group, subj_group) in enumerate(groupby(sorted(groups, key=lambda p: p[1]),
+                                                                    key=lambda p: p[1]))"
+              class="${'odd' if idx % 2 else 'even'}">
+            <td>$group</td>
+            <td>
+              <label py:for="subject, action in sorted(subj_group)">
+                <!--! base64 makes it safe to use ':' as separator when passing
                       both subject and action as one query parameter -->
-                <div>
-                  <input py:if="revoke_perm" type="checkbox"
-                         id="$subject_action_id"
-                         name="sel" value="$subject_action" />
-                  <label for="$subject_action_id">$action</label>
-                </div>
-              </py:for>
+                <input py:if="can_revoke" type="checkbox" name="sel"
+                       value="${'%s:%s' % (unicode_to_base64(subject),
+                                           unicode_to_base64(action))}"/> $subject
+              </label>
             </td>
           </tr>
+          <tr py:if="not groups"><td colspan="2">No group memberships</td></tr>
         </tbody>
       </table>
-      <div class="buttons" py:if="revoke_perm">
+      <div class="buttons" py:if="can_revoke">
         <input type="submit" name="remove" value="${_('Remove selected items')}" />
       </div>
     </form>

Modified: incubator/bloodhound/trunk/trac/trac/admin/templates/admin_plugins.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/templates/admin_plugins.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/templates/admin_plugins.html (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/templates/admin_plugins.html Tue Oct 16 20:06:09 2012
@@ -42,6 +42,10 @@
             File: <input type="file" name="plugin_file" disabled="${readonly or None}" />
           </label>
         </div>
+        <div class="buttons">
+          <input type="submit" name="install" value="${_('Install')}"
+                 disabled="${readonly or None}" />
+        </div>
         <p class="help" py:choose="readonly">
           <py:when test="True">
             The web server does not have sufficient permissions to store files in
@@ -51,10 +55,6 @@
             Upload a plugin packaged as Python egg.
           </py:otherwise>
         </p>
-        <div class="buttons">
-          <input type="submit" name="install" value="${_('Install')}"
-                 disabled="${readonly or None}" />
-        </div>
       </fieldset>
     </form>
 

Modified: incubator/bloodhound/trunk/trac/trac/admin/templates/admin_versions.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/templates/admin_versions.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/templates/admin_versions.html (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/templates/admin_versions.html Tue Oct 16 20:06:09 2012
@@ -8,6 +8,11 @@
   <xi:include href="admin.html" />
   <head>
     <title>Versions</title>
+    <script type="text/javascript">/*<![CDATA[*/
+      jQuery(document).ready(function($) {
+        $("#releaseddate").datetimepicker();
+      });
+    /*]]>*/</script>
   </head>
 
   <body>
@@ -24,14 +29,14 @@
           </div>
           <div class="field">
             <label>Date:<br />
-              <input type="text" id="versiondate" name="time" size="${len(datetime_hint)}"
+              <input type="text" id="releaseddate" name="time" size="${len(datetime_hint)}"
                      value="${format_datetime(version.time)}"
                      title="${_('Format: %(datehint)s', datehint=datetime_hint)}" />
-              <em i18n:msg="datehint">Format: $datetime_hint</em>
+              <span class="hint" i18n:msg="datehint">Format: $datetime_hint</span>
             </label>
           </div>
           <div class="field">
-            <fieldset class="iefix">
+            <fieldset>
               <label for="description" i18n:msg="">
                 Description (you may use <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here):
               </label>
@@ -53,15 +58,15 @@ $version.description</textarea>
           <fieldset>
             <legend>Add Version:</legend>
             <div class="field">
-              <label>Name:<br /><input type="text" name="name" id="name" size="22" /></label>
+              <label>Name: <input type="text" name="name" id="name" size="22"/></label>
             </div>
             <div class="field">
               <label>
-                Released:<br />
+                Released:
                 <input type="text" id="releaseddate" name="time" size="${len(datetime_hint)}"
                        title="${_('Format: %(datehint)s', datehint=datetime_hint)}"
-                       value="${format_datetime()}" /><br />
-                <em i18n:msg="datehint">Format: $datetime_hint</em>
+                       value="${format_datetime()}"/>
+                <span class="hint" i18n:msg="datehint">Format: $datetime_hint</span>
               </label>
             </div>
             <div class="buttons">

Modified: incubator/bloodhound/trunk/trac/trac/admin/tests/console-tests.txt
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/tests/console-tests.txt?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/tests/console-tests.txt (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/tests/console-tests.txt Tue Oct 16 20:06:09 2012
@@ -383,8 +383,8 @@ authenticated  TICKET_CREATE
 authenticated  TICKET_MODIFY
 authenticated  WIKI_CREATE
 authenticated  WIKI_MODIFY
-test_userɑ     TICKET_VIEW
-test_userɑ     WIKI_VIEW
+test_userɐ     TICKET_VIEW
+test_userɐ     WIKI_VIEW
 
 
 Available actions:

Modified: incubator/bloodhound/trunk/trac/trac/admin/tests/console.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/tests/console.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/tests/console.py (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/tests/console.py Tue Oct 16 20:06:09 2012
@@ -350,7 +350,7 @@ class TracadminTestCase(unittest.TestCas
         test exports additional permissions, removes them and imports them back.
         """
         test_name = sys._getframe().f_code.co_name
-        user = u'test_user\u0251' 
+        user = u'test_user\u0250'
         self._execute('permission add ' + user + ' WIKI_VIEW') 
         self._execute('permission add ' + user + ' TICKET_VIEW') 
         rv, output = self._execute('permission export')

Modified: incubator/bloodhound/trunk/trac/trac/admin/web_ui.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/admin/web_ui.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/admin/web_ui.py (original)
+++ incubator/bloodhound/trunk/trac/trac/admin/web_ui.py Tue Oct 16 20:06:09 2012
@@ -423,9 +423,11 @@ class PermissionAdminPanel(Component):
                                   'revoked.'))
                 req.redirect(req.href.admin(cat, page))
 
+        perms = [perm for perm in all_permissions if perm[1].isupper()]
+        groups = [perm for perm in all_permissions if not perm[1].isupper()]
+
         return 'admin_perms.html', {
-            'actions': all_actions,
-            'perms': all_permissions,
+            'actions': all_actions, 'perms': perms, 'groups': groups,
             'unicode_to_base64': unicode_to_base64
         }
 

Modified: incubator/bloodhound/trunk/trac/trac/attachment.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/attachment.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/attachment.py (original)
+++ incubator/bloodhound/trunk/trac/trac/attachment.py Tue Oct 16 20:06:09 2012
@@ -33,7 +33,6 @@ from trac.admin import AdminCommandError
                        console_datetime_format, get_dir_list
 from trac.config import BoolOption, IntOption
 from trac.core import *
-from trac.env import IEnvironmentSetupParticipant
 from trac.mimeview import *
 from trac.perm import PermissionError, IPermissionPolicy
 from trac.resource import *
@@ -43,12 +42,11 @@ from trac.util.compat import sha1
 from trac.util.datefmt import format_datetime, from_utimestamp, \
                               to_datetime, to_utimestamp, utc
 from trac.util.text import exception_to_unicode, path_to_unicode, \
-                           pretty_size, print_table, unicode_quote, \
-                           unicode_unquote, printerr
+                           pretty_size, print_table, unicode_unquote
 from trac.util.translation import _, tag_
 from trac.web import HTTPBadRequest, IRequestHandler, RequestDone
 from trac.web.chrome import (INavigationContributor, add_ctxtnav, add_link,
-                             add_stylesheet, web_context)
+                             add_stylesheet, web_context, add_warning)
 from trac.web.href import Href
 from trac.wiki.api import IWikiSyntaxProvider
 from trac.wiki.formatter import format_to
@@ -167,32 +165,43 @@ class Attachment(object):
                                      title=self.title),
                                    _('Invalid Attachment'))
 
-    def _get_path(self, parent_realm, parent_id, filename):
-        path = os.path.join(self.env.path, 'files', 'attachments',
+    # _get_path() and _get_hashed_filename() are class methods so that they
+    # can be used in db28.py.
+    
+    @classmethod
+    def _get_path(cls, env_path, parent_realm, parent_id, filename):
+        """Get the path of an attachment.
+        
+        WARNING: This method is used by db28.py for moving attachments from
+        the old "attachments" directory to the "files" directory. Please check
+        all changes so that they don't break the upgrade.
+        """
+        path = os.path.join(env_path, 'files', 'attachments',
                             parent_realm)
         hash = sha1(parent_id.encode('utf-8')).hexdigest()
         path = os.path.join(path, hash[0:3], hash)
         if filename:
-            path = os.path.join(path, self._get_hashed_filename(filename))
+            path = os.path.join(path, cls._get_hashed_filename(filename))
         return os.path.normpath(path)
 
     _extension_re = re.compile(r'\.[A-Za-z0-9]+\Z')
 
-    def _get_hashed_filename(self, filename):
+    @classmethod
+    def _get_hashed_filename(cls, filename):
+        """Get the hashed filename corresponding to the given filename.
+        
+        WARNING: This method is used by db28.py for moving attachments from
+        the old "attachments" directory to the "files" directory. Please check
+        all changes so that they don't break the upgrade.
+        """
         hash = sha1(filename.encode('utf-8')).hexdigest()
-        match = self._extension_re.search(filename)
+        match = cls._extension_re.search(filename)
         return hash + match.group(0) if match else hash
 
-    def _get_path_old(self, parent_realm, parent_id, filename):
-        path = os.path.join(self.env.path, 'attachments', parent_realm,
-                            unicode_quote(parent_id))
-        if filename:
-            path = os.path.join(path, unicode_quote(filename))
-        return os.path.normpath(path)
-    
     @property
     def path(self):
-        return self._get_path(self.parent_realm, self.parent_id, self.filename)
+        return self._get_path(self.env.path, self.parent_realm, self.parent_id,
+                              self.filename)
 
     @property
     def title(self):
@@ -202,9 +211,9 @@ class Attachment(object):
         """Delete the attachment, both the record in the database and 
         the file itself.
 
-        .. versionchanged :: 0.13
+        .. versionchanged :: 1.0
            the `db` parameter is no longer needed
-           (will be removed in version 0.14)
+           (will be removed in version 1.1.1)
         """
         assert self.filename, "Cannot delete non-existent attachment"
 
@@ -231,7 +240,8 @@ class Attachment(object):
     def reparent(self, new_realm, new_id):
         assert self.filename, "Cannot reparent non-existent attachment"
         new_id = unicode(new_id)
-        new_path = self._get_path(new_realm, new_id, self.filename)
+        new_path = self._get_path(self.env.path, new_realm, new_id,
+                                  self.filename)
 
         # Make sure the path to the attachment is inside the environment
         # attachments directory
@@ -280,9 +290,9 @@ class Attachment(object):
     def insert(self, filename, fileobj, size, t=None, db=None):
         """Create a new Attachment record and save the file content.
 
-        .. versionchanged :: 0.13
+        .. versionchanged :: 1.0
            the `db` parameter is no longer needed
-           (will be removed in version 0.14)
+           (will be removed in version 1.1.1)
         """
         self.size = int(size) if size else 0
         self.filename = None
@@ -328,9 +338,9 @@ class Attachment(object):
         """Iterator yielding all `Attachment` instances attached to
         resource identified by `parent_realm` and `parent_id`.
 
-        .. versionchanged :: 0.13
+        .. versionchanged :: 1.0
            the `db` parameter is no longer needed 
-           (will be removed in version 0.14)
+           (will be removed in version 1.1.1)
         """
         for row in env.db_query("""
                 SELECT filename, description, size, time, author, ipnr
@@ -344,9 +354,9 @@ class Attachment(object):
     def delete_all(cls, env, parent_realm, parent_id, db=None):
         """Delete all attachments of a given resource.
         
-        .. versionchanged :: 0.13
+        .. versionchanged :: 1.0
            the `db` parameter is no longer needed
-           (will be removed in version 0.14)
+           (will be removed in version 1.1.1)
         """
         attachment_dir = None
         with env.db_transaction as db:
@@ -406,75 +416,6 @@ class Attachment(object):
                 filename = '%s.%d%s' % (parts[0], idx, parts[1])
 
 
-class AttachmentSetup(Component):
-
-    implements(IEnvironmentSetupParticipant)
-
-    required = True
-
-    # IEnvironmentSetupParticipant methods
-
-    def environment_created(self):
-        """Create the attachments directory."""
-        path = self.env.path
-        if path:
-            os.makedirs(os.path.join(path, 'files', 'attachments'))
-
-    def environment_needs_upgrade(self, db):
-        path = self.env.path
-        if path:
-            return os.path.exists(os.path.join(path, 'attachments'))
-
-    def upgrade_environment(self, db):
-        """Migrate attachments from old-style directory to new-style
-        directory.
-        """
-        path = self.env.path
-        old_dir = os.path.join(path, 'attachments')
-        old_stat = os.stat(old_dir)
-        new_dir = os.path.join(path, 'files', 'attachments')
-        if not os.path.exists(new_dir):
-            os.makedirs(new_dir)
-
-        for row in db("""
-                SELECT type, id, filename, description, size, time, author,
-                ipnr FROM attachment ORDER BY type, id"""):
-            attachment = Attachment(self.env, row[0], row[1])
-            attachment._from_database(*row[2:])
-            self._move_attachment_file(attachment)
-
-        # Try to preserve permissions and ownerships of the attachments
-        # directory for $ENV/files
-        for dir, dirs, files in os.walk(os.path.join(path, 'files')):
-            try:
-                if hasattr(os, 'chmod'):
-                    os.chmod(dir, old_stat.st_mode)
-                if hasattr(os, 'chflags') and hasattr(old_stat, 'st_flags'):
-                    os.chflags(dir, old_stat.st_flags)
-                if hasattr(os, 'chown'):
-                    os.chown(dir, old_stat.st_uid, old_stat.st_gid)
-            except OSError:
-                pass
-
-        try:
-            for dir, dirs, files in os.walk(old_dir, topdown=False):
-                os.rmdir(dir)
-        except OSError, e:
-            self.log.error("Can't delete old attachments directory %s: %s",
-                           old_dir, exception_to_unicode(e, traceback=True))
-            printerr(_("Error while deleting old attachments directory. "
-                       "Please move or remove files in\nthe directory and try "
-                       "again."))
-            raise
-
-    def _move_attachment_file(self, attachment):
-        old_path = attachment._get_path_old(attachment.parent_realm,
-                                            attachment.parent_id,
-                                            attachment.filename)
-        if os.path.isfile(old_path):
-            os.renames(old_path, attachment.path)
-
-
 class AttachmentModule(Component):
 
     implements(IRequestHandler, INavigationContributor, IWikiSyntaxProvider,
@@ -492,7 +433,7 @@ class AttachmentModule(Component):
     max_zip_size = IntOption('attachment', 'max_zip_size', 2097152,
         """Maximum allowed total size (in bytes) for an attachment list to be
         downloadable as a `.zip`. Set this to -1 to disable download as `.zip`.
-        (''since 0.13'')""")
+        (''since 1.0'')""")
 
     render_unsafe_content = BoolOption('attachment', 'render_unsafe_content',
                                        'false',
@@ -565,7 +506,7 @@ class AttachmentModule(Component):
         
         if req.method == 'POST':
             if action == 'new':
-                self._do_save(req, attachment)
+                data = self._do_save(req, attachment)
             elif action == 'delete':
                 self._do_delete(req, attachment)
         elif action == 'delete':
@@ -779,16 +720,25 @@ class AttachmentModule(Component):
         attachment.ipnr = req.remote_addr
 
         # Validate attachment
+        valid = True
         for manipulator in self.manipulators:
             for field, message in manipulator.validate_attachment(req,
                                                                   attachment):
+                valid = False
                 if field:
-                    raise InvalidAttachment(
+                    add_warning(req,
                         _('Attachment field %(field)s is invalid: %(message)s',
                           field=field, message=message))
                 else:
-                    raise InvalidAttachment(
+                    add_warning(req,
                         _('Invalid attachment: %(message)s', message=message))
+        if not valid:
+            # Display the attach form with pre-existing data
+            # NOTE: Local file path not known, file field cannot be repopulated
+            add_warning(req, _('Note: File must be selected again.'))
+            data = self._render_form(req, attachment)
+            data['is_replace'] = req.args.get('replace')
+            return data
 
         if req.args.get('replace'):
             try:

Modified: incubator/bloodhound/trunk/trac/trac/cache.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/cache.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/cache.py (original)
+++ incubator/bloodhound/trunk/trac/trac/cache.py Tue Oct 16 20:06:09 2012
@@ -163,14 +163,14 @@ def cached(fn_or_attr=None):
     it is used has an ``env`` attribute containing the application
     `~trac.env.Environment`.
 
-    .. versionchanged:: 0.13 
+    .. versionchanged:: 1.0 
         The data retrieval method used to be called with a single
         argument ``db`` containing a reference to a database
         connection.  This is the same connection that can be retrieved
         via the normal `~trac.env.Environment.db_query` or
         `~trac.env.Environment.db_transaction`, so this is no longer
         needed, though methods supporting that argument are still
-        supported (but will be removed in version 0.14).
+        supported (but will be removed in version 1.1.1).
     """
     if hasattr(fn_or_attr, '__call__'):
         return CachedSingletonProperty(fn_or_attr)

Modified: incubator/bloodhound/trunk/trac/trac/config.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/config.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/config.py (original)
+++ incubator/bloodhound/trunk/trac/trac/config.py Tue Oct 16 20:06:09 2012
@@ -668,7 +668,11 @@ class ChoiceOption(Option):
             
     
 class PathOption(Option):
-    """Descriptor for file system path configuration options."""
+    """Descriptor for file system path configuration options.
+
+    Relative paths are resolved to absolute paths using the directory
+    containing the configuration file as the reference.
+    """
     accessor = Section.getpath
 
 

Modified: incubator/bloodhound/trunk/trac/trac/db/pool.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/db/pool.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/db/pool.py (original)
+++ incubator/bloodhound/trunk/trac/trac/db/pool.py Tue Oct 16 20:06:09 2012
@@ -19,6 +19,7 @@ from __future__ import with_statement
 import os
 import time
 
+from trac.core import TracError
 from trac.db.util import ConnectionWrapper
 from trac.util.concurrency import threading
 from trac.util.text import exception_to_unicode
@@ -101,7 +102,12 @@ class ConnectionPoolBackend(object):
                     cnx.close()
                 if op in ('close', 'create'):
                     cnx = connector.get_connection(**kwargs)
+            except TracError, e:
+                err = e
+                cnx = None
             except Exception, e:
+                if log:
+                    log.error('Exception caught on %s', op, exc_info=True)
                 err = e
                 cnx = None
         

Modified: incubator/bloodhound/trunk/trac/trac/db/tests/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/db/tests/__init__.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/db/tests/__init__.py (original)
+++ incubator/bloodhound/trunk/trac/trac/db/tests/__init__.py Tue Oct 16 20:06:09 2012
@@ -10,7 +10,7 @@ def suite():
     suite.addTest(api.suite())
     suite.addTest(mysql_test.suite())
     suite.addTest(postgres_test.suite())
-    #suite.addTest(util.suite())
+    suite.addTest(util.suite())
     return suite
 
 if __name__ == '__main__':

Modified: incubator/bloodhound/trunk/trac/trac/db/tests/util.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/db/tests/util.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/db/tests/util.py (original)
+++ incubator/bloodhound/trunk/trac/trac/db/tests/util.py Tue Oct 16 20:06:09 2012
@@ -13,4 +13,29 @@
 
 import unittest
 
-# TODO: test sql_escape_percent, IterableCursor, ConnectionWrapper ...
+from trac.db.util import sql_escape_percent
+
+# TODO: test IterableCursor, ConnectionWrapper
+
+class SQLEscapeTestCase(unittest.TestCase):
+    def test_sql_escape_percent(self):
+        self.assertEqual("%", sql_escape_percent("%"))
+        self.assertEqual("'%%'", sql_escape_percent("'%'"))
+        self.assertEqual("''%''", sql_escape_percent("''%''"))
+        self.assertEqual("'''%%'''", sql_escape_percent("'''%'''"))
+        self.assertEqual("'''%%'", sql_escape_percent("'''%'"))
+        self.assertEqual("%s", sql_escape_percent("%s"))
+        self.assertEqual("% %", sql_escape_percent("% %"))
+        self.assertEqual("%s %i", sql_escape_percent("%s %i"))
+        self.assertEqual("'%%s'", sql_escape_percent("'%s'"))
+        self.assertEqual("'%% %%'", sql_escape_percent("'% %'"))
+        self.assertEqual("'%%s %%i'", sql_escape_percent("'%s %i'"))
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(SQLEscapeTestCase, 'test'))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')

Modified: incubator/bloodhound/trunk/trac/trac/db/util.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/db/util.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/db/util.py (original)
+++ incubator/bloodhound/trunk/trac/trac/db/util.py Tue Oct 16 20:06:09 2012
@@ -92,8 +92,8 @@ class ConnectionWrapper(object):
     :since 0.12: This wrapper no longer makes cursors produced by the
     connection iterable using `IterableCursor`.
 
-    :since 0.13: added a 'readonly' flag preventing the forwarding of
-                 `commit` and `rollback`
+    :since 1.0: added a 'readonly' flag preventing the forwarding of
+                `commit` and `rollback`
     """
     __slots__ = ('cnx', 'log', 'readonly')
 

Modified: incubator/bloodhound/trunk/trac/trac/db_default.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/db_default.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/db_default.py (original)
+++ incubator/bloodhound/trunk/trac/trac/db_default.py Tue Oct 16 20:06:09 2012
@@ -17,7 +17,7 @@
 from trac.db import Table, Column, Index
 
 # Database version identifier. Used for automatic upgrades.
-db_version = 27
+db_version = 29
 
 def __mkreports(reports):
     """Utility function used to create report data in same syntax as the

Modified: incubator/bloodhound/trunk/trac/trac/dist.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/dist.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/dist.py (original)
+++ incubator/bloodhound/trunk/trac/trac/dist.py Tue Oct 16 20:06:09 2012
@@ -22,6 +22,7 @@ for compiling catalogs are issued upon i
 from __future__ import with_statement
 
 from StringIO import StringIO
+from itertools import izip
 import os
 import re
 from tokenize import generate_tokens, COMMENT, NAME, OP, STRING
@@ -33,11 +34,15 @@ from distutils.errors import DistutilsOp
 from setuptools.command.install_lib import install_lib as _install_lib
 
 try:
+    from babel.messages.catalog import TranslationError
     from babel.messages.extract import extract_javascript
     from babel.messages.frontend import extract_messages, init_catalog, \
                                         compile_catalog, update_catalog
-    from babel.util import parse_encoding
+    from babel.messages.pofile import read_po
     from babel.support import Translations
+    from babel.util import parse_encoding
+
+    _GENSHI_MARKUP_SEARCH = re.compile(r'\[[0-9]+:').search
 
 
     _DEFAULT_KWARGS_MAPS = {
@@ -309,6 +314,108 @@ try:
                 with open(js_file, 'w') as outfile:
                     write_js(outfile, catalog, self.domain, locale)
 
+
+    class check_catalog(Command):
+        """Check message catalog command for use ``setup.py`` scripts."""
+
+        description = 'check message catalog files, like `msgfmt --check`'
+        user_options = [
+            ('domain=', 'D',
+             "domain of PO file (default 'messages')"),
+            ('input-dir=', 'I',
+             'path to base directory containing the catalogs'),
+            ('input-file=', 'i',
+             'name of the input file'),
+            ('locale=', 'l',
+             'locale of the catalog to compile'),
+        ]
+
+        def initialize_options(self):
+            self.domain = 'messages'
+            self.input_dir = None
+            self.input_file = None
+            self.locale = None
+
+        def finalize_options(self):
+            if not self.input_file and not self.input_dir:
+                raise DistutilsOptionError('you must specify either the input '
+                                           'file or directory')
+
+        def run(self):
+            for filename in self._get_po_files():
+                log.info('checking catalog %s', filename)
+                f = open(filename)
+                try:
+                    catalog = read_po(f, domain=self.domain)
+                finally:
+                    f.close()
+                for message in catalog:
+                    for error in self._check_message(catalog, message):
+                        log.warn('%s:%d: %s', filename, message.lineno, error)
+
+        def _get_po_files(self):
+            if self.input_file:
+                return [self.input_file]
+
+            if self.locale:
+                return [os.path.join(self.input_dir, self.locale,
+                                     'LC_MESSAGES', self.domain + '.po')]
+
+            files = []
+            for locale in os.listdir(self.input_dir):
+                filename = os.path.join(self.input_dir, locale, 'LC_MESSAGES',
+                                        self.domain + '.po')
+                if os.path.exists(filename):
+                    files.append(filename)
+            return sorted(files)
+
+        def _check_message(self, catalog, message):
+            errors = [e for e in message.check(catalog)]
+            try:
+                check_genshi_markup(catalog, message)
+            except TranslationError, e:
+                errors.append(e)
+            return errors
+
+
+    def check_genshi_markup(catalog, message):
+        """Verify the genshi markups in the translation."""
+        msgids = message.id
+        if not isinstance(msgids, (list, tuple)):
+            msgids = (msgids,)
+        msgstrs = message.string
+        if not isinstance(msgstrs, (list, tuple)):
+            msgstrs = (msgstrs,)
+
+        # check using genshi-markup
+        if not _GENSHI_MARKUP_SEARCH(msgids[0]):
+            return
+
+        for msgid, msgstr in izip(msgids, msgstrs):
+            if msgstr:
+                _validate_genshi_markup(msgid, msgstr)
+
+
+    def _validate_genshi_markup(markup, alternative):
+        indices_markup = _parse_genshi_markup(markup)
+        indices_alternative = _parse_genshi_markup(alternative)
+        indices = indices_markup - indices_alternative
+        if indices:
+            raise TranslationError(
+                'genshi markups are unbalanced %s' % \
+                ' '.join(['[%d:]' % idx for idx in indices]))
+
+
+    def _parse_genshi_markup(message):
+        from genshi.filters.i18n import parse_msg
+        try:
+            return set([idx for idx, text in parse_msg(message)
+                            if idx > 0])
+        except Exception, e:
+            raise TranslationError('cannot parse message (%s: %s)' % \
+                                   (e.__class__.__name__, unicode(e)))
+
+
     def write_js(fileobj, catalog, domain, locale):
         from trac.util.presentation import to_json
         data = {'domain': domain, 'locale': locale}
@@ -364,7 +471,10 @@ try:
 
     def get_l10n_cmdclass():
         build, install_lib = get_command_overriders()
-        return {'build': build, 'install_lib': install_lib}
+        return {
+            'build': build, 'install_lib': install_lib,
+            'check_catalog': check_catalog,
+        }
 
     def get_l10n_js_cmdclass():
         build, _install_lib = get_command_overriders()
@@ -377,11 +487,13 @@ try:
                 self.run_command('compile_catalog')
         return {
             'build': build, 'install_lib': install_lib,
+            'check_catalog': check_catalog,
             'extract_messages_js': extract_messages,
             'init_catalog_js': init_catalog,
             'compile_catalog_js': compile_catalog,
             'update_catalog_js': update_catalog,
             'generate_messages_js': generate_messages_js,
+            'check_catalog_js': check_catalog,
         }
 
     def get_l10n_trac_cmdclass():
@@ -397,15 +509,18 @@ try:
                 self.run_command('compile_catalog')
         return {
             'build': build, 'install_lib': install_lib,
+            'check_catalog': check_catalog,
             'extract_messages_js': extract_messages,
             'init_catalog_js': init_catalog,
             'compile_catalog_js': compile_catalog,
             'update_catalog_js': update_catalog,
             'generate_messages_js': generate_messages_js,
+            'check_catalog_js': check_catalog,
             'extract_messages_tracini': extract_messages,
             'init_catalog_tracini': init_catalog,
             'compile_catalog_tracini': compile_catalog,
             'update_catalog_tracini': update_catalog,
+            'check_catalog_tracini': check_catalog,
         }
 
 

Modified: incubator/bloodhound/trunk/trac/trac/env.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/env.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/env.py (original)
+++ incubator/bloodhound/trunk/trac/trac/env.py Tue Oct 16 20:06:09 2012
@@ -32,7 +32,9 @@ from trac.core import Component, Compone
                       ExtensionPoint, TracError
 from trac.db.api import (DatabaseManager, QueryContextManager, 
                          TransactionContextManager, with_transaction)
-from trac.util import copytree, create_file, get_pkginfo, lazy, makedirs
+from trac.util import copytree, create_file, get_pkginfo, lazy, makedirs, \
+                      read_file
+from trac.util.compat import sha1
 from trac.util.concurrency import threading
 from trac.util.text import exception_to_unicode, path_to_unicode, printerr, \
                            printout
@@ -43,6 +45,10 @@ from trac.web.href import Href
 __all__ = ['Environment', 'IEnvironmentSetupParticipant', 'open_environment']
 
 
+# Content of the VERSION file in the environment
+_VERSION = 'Trac Environment Version 1'
+    
+
 class ISystemInfoProvider(Interface):
     """Provider of system information, displayed in the "About Trac"
     page and in internal error reports.
@@ -55,9 +61,15 @@ class ISystemInfoProvider(Interface):
 
 
 class IEnvironmentSetupParticipant(Interface):
-    """Extension point interface for components that need to
-    participate in the creation and upgrading of Trac environments,
-    for example to create additional database tables."""
+    """Extension point interface for components that need to participate in
+    the creation and upgrading of Trac environments, for example to create
+    additional database tables.
+    
+    Please note that `IEnvironmentSetupParticipant` instances are called in
+    arbitrary order. If your upgrades must be ordered consistently, please
+    implement the ordering in a single `IEnvironmentSetupParticipant`. See
+    the database upgrade infrastructure in Trac core for an example.
+    """
 
     def environment_created():
         """Called when a new Trac environment is created."""
@@ -84,16 +96,22 @@ class IEnvironmentSetupParticipant(Inter
         """
 
 
+class BackupError(RuntimeError):
+    """Exception raised during an upgrade when the DB backup fails."""
+
+
 class Environment(Component, ComponentManager):
     """Trac environment manager.
 
     Trac stores project information in a Trac environment. It consists
     of a directory structure containing among other things:
-        * a configuration file, 
-        * project-specific templates and plugins,
-        * the wiki and ticket attachments files,
-        * the SQLite database file (stores tickets, wiki pages...)
-          in case the database backend is sqlite
+
+    * a configuration file, 
+    * project-specific templates and plugins,
+    * the wiki and ticket attachments files,
+    * the SQLite database file (stores tickets, wiki pages...)
+      in case the database backend is sqlite
+
     """
 
     implements(ISystemInfoProvider)
@@ -231,9 +249,10 @@ class Environment(Component, ComponentMa
         In addition to regular key names supported by the Python
         logger library (see
         http://docs.python.org/library/logging.html), one could use:
-         - $(path)s     the path for the current environment
-         - $(basename)s the last path component of the current environment
-         - $(project)s  the project name
+
+        - $(path)s     the path for the current environment
+        - $(basename)s the last path component of the current environment
+        - $(project)s  the project name
 
         Note the usage of `$(...)s` instead of `%(...)s` as the latter form
         would be interpreted by the ConfigParser itself.
@@ -366,8 +385,13 @@ class Environment(Component, ComponentMa
     def verify(self):
         """Verify that the provided path points to a valid Trac environment
         directory."""
-        with open(os.path.join(self.path, 'VERSION'), 'r') as fd:
-            assert fd.read(26) == 'Trac Environment Version 1'
+        try:
+            tag = read_file(os.path.join(self.path, 'VERSION')).splitlines()[0]
+            if tag != _VERSION:
+                raise Exception("Unknown Trac environment type '%s'" % tag)
+        except Exception, e:
+            raise TracError("No Trac environment found at %s\n%s"
+                            % (self.path, e))
 
     def get_db_cnx(self):
         """Return a database connection from the connection pool
@@ -528,8 +552,7 @@ class Environment(Component, ComponentMa
         os.mkdir(os.path.join(self.path, 'plugins'))
 
         # Create a few files
-        create_file(os.path.join(self.path, 'VERSION'),
-                    'Trac Environment Version 1\n')
+        create_file(os.path.join(self.path, 'VERSION'), _VERSION + '\n')
         create_file(os.path.join(self.path, 'README'),
                     'This directory contains a Trac environment.\n'
                     'Visit http://trac.edgewall.org/ for more information.\n')
@@ -560,8 +583,8 @@ class Environment(Component, ComponentMa
 
         :since: 0.11
 
-        :since 0.13: deprecation warning: the `db` parameter is no
-                     longer used and will be removed in version 0.14
+        :since 1.0: deprecation warning: the `db` parameter is no
+                    longer used and will be removed in version 1.1.1
         """
         rows = self.db_query("""
                 SELECT value FROM system WHERE name='%sdatabase_version'
@@ -597,13 +620,14 @@ class Environment(Component, ComponentMa
         if logtype == 'file' and not os.path.isabs(logfile):
             logfile = os.path.join(self.get_log_dir(), logfile)
         format = self.log_format
+        logid = 'Trac.%s' % sha1(self.path).hexdigest()
         if format:
             format = format.replace('$(', '%(') \
                      .replace('%(path)s', self.path) \
                      .replace('%(basename)s', os.path.basename(self.path)) \
                      .replace('%(project)s', self.project_name)
         self.log, self._log_handler = logger_handler_factory(
-            logtype, logfile, self.log_level, self.path, format=format)
+            logtype, logfile, self.log_level, logid, format=format)
         from trac import core, __version__ as VERSION
         self.log.info('-' * 32 + ' environment startup [Trac %s] ' + '-' * 32,
                       get_pkginfo(core).get('version', VERSION))
@@ -619,8 +643,8 @@ class Environment(Component, ComponentMa
         :param cnx: the database connection; if ommitted, a new
                     connection is retrieved
 
-        :since 0.13: deprecation warning: the `cnx` parameter is no
-                     longer used and will be removed in version 0.14
+        :since 1.0: deprecation warning: the `cnx` parameter is no
+                    longer used and will be removed in version 1.1.1
         """
         for username, name, email in self.db_query("""
                 SELECT DISTINCT s.sid, n.value, e.value
@@ -643,13 +667,13 @@ class Environment(Component, ComponentMa
 
     def needs_upgrade(self):
         """Return whether the environment needs to be upgraded."""
-        with self.db_query as db:
-            for participant in self.setup_participants:
+        for participant in self.setup_participants:
+            with self.db_query as db:
                 if participant.environment_needs_upgrade(db):
                     self.log.warn("Component %s requires environment upgrade",
                                   participant)
                     return True
-            return False
+        return False
 
     def upgrade(self, backup=False, backup_dest=None):
         """Upgrade database.
@@ -659,15 +683,18 @@ class Environment(Component, ComponentMa
         :return: whether the upgrade was performed
         """
         upgraders = []
-        with self.db_query as db:
-            for participant in self.setup_participants:
+        for participant in self.setup_participants:
+            with self.db_query as db:
                 if participant.environment_needs_upgrade(db):
                     upgraders.append(participant)
         if not upgraders:
             return
 
         if backup:
-            self.backup(backup_dest)
+            try:
+                self.backup(backup_dest)
+            except Exception, e:
+                raise BackupError(e)
 
         for participant in upgraders:
             self.log.info("%s.%s upgrading...", participant.__module__,
@@ -943,10 +970,14 @@ class EnvironmentAdmin(Component):
 
         try:
             self.env.upgrade(backup=no_backup is None)
-        except TracError, e:
-            raise TracError(_("Backup failed: %(msg)s.\nUse '--no-backup' to "
-                              "upgrade without doing a backup.",
-                              msg=unicode(e)))
+        except BackupError, e:
+            printerr(_("The pre-upgrade backup failed.\nUse '--no-backup' to "
+                       "upgrade without doing a backup.\n"))
+            raise e.args[0]
+        except Exception, e:
+            printerr(_("The upgrade failed. Please fix the issue and try "
+                       "again.\n"))
+            raise
 
         # Remove wiki-macros if it is empty and warn if it isn't
         wiki_macros = os.path.join(self.env.path, 'wiki-macros')

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/admin.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/admin.css?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/htdocs/css/admin.css (original)
+++ incubator/bloodhound/trunk/trac/trac/htdocs/css/admin.css Tue Oct 16 20:06:09 2012
@@ -1,11 +1,18 @@
-/* Avoid layout issues with side fieldsets, see #8866 */
-.admin h1, .admin h2 { margin-top: 0; }
-
 #content.admin h1 { float: left; }
+.admin h1, .admin h2 { margin-top: 0; }
 
-#tabs { background: #f7f7f0; border: 1px solid black;
-  border-color: #ccc #666 #666 #ccc; clear: left;
-  margin: 1em 0 2em; padding: .5em 0 0; float: left; width: 12em;
+#tabs {
+ background: #f7f7f0;
+ border: 1px solid black;
+ border-color: #ccc #666 #666 #ccc;
+ clear: left;
+ margin: 1em 0 2em;
+ padding: .5em 0 0;
+ float: left;
+ width: 12em;
+ /* taken from #prefs */
+ border-radius: 1em;
+ box-shadow: .2em .2em .7em 0 #777;
 }
 #tabs ul { list-style: none; margin: 0 0 .5em; padding: 0; }
 #tabs li { color: #999; font-size: 90%; font-weight: bold; margin: 0;
@@ -14,23 +21,54 @@
 #tabs li li { color: #000; font-size: 110%; font-weight: normal;
   margin: 0 -3px; padding: 1px 0 1px 10px;
 }
-#tabs li li.active { background: #ddc; border: 1px solid;
-  border-color: #ccc #000 #666 #ccc; padding: 0 0 0 9px;
+#tabs li li.active {
+ background: #ddc;
+ border: 1px solid;
+ border-color: #ccc #999 #999 #ccc;
+ border-radius: .2em;
+ box-shadow: .1em .2em .5em #aa9;
+ padding: 0 0 0 9px;
 }
 #tabs :link, #tabs :visited { border: none; display: block }
-#tabs :link:hover, #tabs :visited:hover { background: transparent;
-  color: #000;
+#tabs :link:hover,
+#tabs :visited:hover {
+ background: transparent;
+ color: #000;
 }
 
 #tabcontent { padding: 0.4em 0 0.4em 2em; margin-left: 12em; min-height: 300px; }
 #tabcontent h2 { color: #333; }
-#tabcontent form { overflow: auto; padding: 0 1px; }
 p.help { color: #666; font-size: 90%; margin: 1em .5em .5em; }
 
 #enumlist tbody td { vertical-align: middle; }
 
-#tabcontent form.addnew { clear: right; float: right; margin: -2em 0 2em 2em; width: 33%; overflow: visible; padding: 0 }
-#tabcontent form.mod { margin-top: 1em; overflow: visible; padding: 0 }
+form.addnew,
+form.addnew + form.addnew { margin: 1em 0; }
+form.addnew + * { margin-top: 2em; }
+form.addnew fieldset { padding: 0.5em 1em; }
+form.addnew div { margin: 0; }
+form.addnew div.field,
+form.addnew div.buttons,
+form.addnew p.help {
+ display: inline-block;
+ /* IE7 hack to make inline-block effective on block element */
+ zoom: 1;
+ *display: inline;
+}
+form.addnew div.field,
+form.addnew div.buttons {
+ padding: 0.2em 0.5em 0.2em 0;
+ white-space: nowrap;
+}
+form.addnew div.buttons input { margin: 0 0.5em 0 0; }
+form.addnew p.hint,
+form.addnew span.hint {
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+}
+form.addnew p.help { margin-top: 0.5em; }
+form.addnew br { display: none; }
+form.mod { margin-top: 1em; }
 form.mod fieldset { margin: 0 }
 form.mod .field { margin: .5em 0; }
 form .field em { color: #888; font-size: smaller }
@@ -41,11 +79,10 @@ table.listing .sel, table.listing .defau
 table.listing .num { text-align: right; width: 1% }
 
 /* Plugins panel */
-form#addplug { width: 35% }
 .plugin {
  background: #f7f7f7;
  border: 1px solid #d7d7d7;
- margin: 0 0 2em;
+ margin: 2em 0 0;
  padding: 2px .5em;
  text-align: left;
 }
@@ -53,7 +90,7 @@ form#addplug { width: 35% }
 .plugin .buttons { margin-top: 0; text-align: right; }
 .plugin .uninstall { margin-top: -2.6em; padding: 0; }
 .plugin .summary, .plugin .info { padding-left: 16px; color: #999; font-size: 80%; }
-.plugin .summary { margin: -.5em 0 .5em; }
+.plugin .summary { margin: 1.2em 0 .5em; }
 .plugin .info { margin: 1em 0 .5em; }
 .plugin .info dt { float: left; width: 7em; }
 .plugin .info dd { padding: 0; margin: 0; }
@@ -70,11 +107,17 @@ form#addplug { width: 35% }
 .trac-component .trac-heading { margin-left: 2em; padding-left: 16px }
 .trac-component .trac-heading.foldable { text-indent: -16px }
 .trac-component > div { margin-left: 3em; }
-.trac-summary { color: #888; }
+.trac-summary { color: #888 }
+.trac-heading :link { padding: .1em .5em 0 20px }
 table.trac-pluglist td { padding-left: 1em; }
 
 /* Perm Panel */
-#permlist div { float: left; min-width: 13em; max-width: 33%;
-  padding: 0 2em 0 0;
+#permlist { margin-bottom: 2em; }
+#permlist label, #grouplist label {
+ float: left;
+ min-width: 13em;
+ max-width: 33%;
+ padding: 0 2em 0 0;
+ white-space: nowrap;
 }
 fieldset tr.field th { text-align: right; }

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/browser.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/browser.css?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/htdocs/css/browser.css (original)
+++ incubator/bloodhound/trunk/trac/trac/htdocs/css/browser.css Tue Oct 16 20:06:09 2012
@@ -119,7 +119,7 @@ table.dirlist td span.loading { 
 #content.browser div.description { padding: 0 0.5em }
 
 /* Style for the ''View Changes'' button and the diff preparation form */
-#anydiff { margin: 0 0 1em; float: left }
+#anydiff { margin-top: 1em; }
 #anydiff form, #anydiff div, #anydiff h2 { display: inline }
 #anydiff form th { text-align: right }
 #anydiff input {  vertical-align: baseline; margin: 0 -0.5em 0 1em }

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/code.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/code.css?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/htdocs/css/code.css (original)
+++ incubator/bloodhound/trunk/trac/trac/htdocs/css/code.css Tue Oct 16 20:06:09 2012
@@ -1,12 +1,16 @@
 div.code {
  background: #f7f7f7;
  border: 1px solid #d7d7d7;
+ border-radius: .3em;
  margin: 1em 1.75em;
  padding: .25em;
  overflow: auto
 }
 
-div.code pre { margin: 0; }
+div.code pre {
+ margin: 0;
+ overflow: auto;
+}
 
 table.code {
  border: 1px solid #ddd;

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/diff.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/diff.css?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/htdocs/css/diff.css (original)
+++ incubator/bloodhound/trunk/trac/trac/htdocs/css/diff.css Tue Oct 16 20:06:09 2012
@@ -6,7 +6,7 @@
 #overview dt.property {
  font-weight: bold;
  padding-right: .25em;
- position: absolute;
+ position: absolute; /* relies on #content { position: relative } */
  left: 0;
  text-align: right;
  width: 7.75em;

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-bg_diagonals-thick_18_ffddcc_40x40.png
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-bg_diagonals-thick_18_ffddcc_40x40.png?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
Binary files - no diff available.

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-bg_highlight-soft_30_303030_1x100.png
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-bg_highlight-soft_30_303030_1x100.png?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
Binary files - no diff available.

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-icons_505050_256x240.png
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-icons_505050_256x240.png?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
Binary files - no diff available.

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-icons_707070_256x240.png
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-icons_707070_256x240.png?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
Binary files - no diff available.

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-icons_b00000_256x240.png
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/images/ui-icons_b00000_256x240.png?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
Binary files - no diff available.

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/jquery-ui.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/jquery-ui.css?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/jquery-ui.css (original)
+++ incubator/bloodhound/trunk/trac/trac/htdocs/css/jquery-ui/jquery-ui.css Tue Oct 16 20:06:09 2012
@@ -1,7 +1,7 @@
-/*
- * jQuery UI CSS Framework 1.8.18
+/*!
+ * jQuery UI CSS Framework 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -38,24 +38,24 @@
 .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
 
 
-/*
- * jQuery UI CSS Framework 1.8.18
+/*!
+ * jQuery UI CSS Framework 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Theming/API
  *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,\\\\\\\\\\\\\\\\\'Bitstream%20Vera%20Sans\\\\\\\\\\\\\\\\\',Helvetica,sans-serif&fwDefault=normal&fsDefault=13px&cornerRadius=.3em&bgColorHeader=ffffdd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=80&borderColorHeader=bbbbbb&fcHeader=000000&iconColorHeader=707070&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=00&borderColorContent=bbbbbb&fcContent=000000&iconColorContent=222222&bgColorDefault=ffffff&bgTextureDefault=01_flat.png&bgImgOpacityDefault=0&borderColorDefault=bbbbbb&fcDefault=b00000&iconColorDefault=b00000&bgColorHover=ffffdd&bgTextureHover=01_flat.png&bgImgOpacityHover=0&borderColorHover=505050&fcHover=505050&iconColorHover=505050&bgColorActive=303030&bgTextureActive=03_highlight_soft.png&bgImgOpacityActive=30&borderColorActive=bbbbbb&fcActive=eeeeee&iconColorActive=d7d7d7&bgColorHighlight=c0f0c0&bgTextureHighlight=03_highlight_soft.p
 ng&bgImgOpacityHighlight=75&borderColorHighlight=c0f0c0&fcHighlight=363636&iconColorHighlight=4b954f&bgColorError=ffddcc&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=9b081d&fcError=500000&iconColorError=9b081d&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller&ffDefault=Verdana,Arial,\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'Bitstream%20Vera%20Sans\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\',Helvetica,sans-serif&fwDefault=normal&fsDefault=13px&cornerRadius=.3em&bgColorHeader=ffffdd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=80&borderColorHeader=bbbbbb&fcHeader=000000&iconColorHeader=707070&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=00&borderColorContent=bbbbbb&fcContent=000000&iconColorContent=222222&bgColorDefault=ffffff&bgTextureDefault=01_flat.png&bgImgOpacityDefault=0&borderColorDefault=bbbbbb&fcDefault=b00000&iconColorDefault=b00000&bgColorHover=ffffdd&bgTextureHover=01_flat.png&bgImgOpacityHover=0&borderColorHover=505050&fcHover=505050&iconColorHover=505050&bgColorActive=303030&bgTextureActive=03_highlight_soft.png&bgImgOpacityActive=30&borderColorActive=bbbbbb&fcActive=eeeeee&iconColorActive=d7d7d7&bgColorHig
 hlight=c0f0c0&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=c0f0c0&fcHighlight=363636&iconColorHighlight=4b954f&bgColorError=ffddcc&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=9b081d&fcError=500000&iconColorError=9b081d&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
  */
 
 
 /* Component containers
 ----------------------------------*/
-.ui-widget { font-family: Verdana,Arial,\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'Bitstream Vera Sans\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\',Helvetica,sans-serif; font-size: 13px; }
+.ui-widget { font-family: Verdana,Arial,\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'Bitstream Vera Sans\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\',Helvetica,sans-serif; font-size: 13px; }
 .ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'Bitstream Vera Sans\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\',Helvetica,sans-serif; font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'Bitstream Vera Sans\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\',Helvetica,sans-serif; font-size: 1em; }
 .ui-widget-content { border: 1px solid #bbbbbb; background: #ffffff url(images/ui-bg_flat_00_ffffff_40x100.png) 50% 50% repeat-x; color: #000000; }
 .ui-widget-content a { color: #000000; }
 .ui-widget-header { border: 1px solid #bbbbbb; background: #ffffdd url(images/ui-bg_highlight-soft_80_ffffdd_1x100.png) 50% 50% repeat-x; color: #000000; font-weight: bold; }
@@ -284,17 +284,17 @@
 
 /* Overlays */
 .ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
-.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
- * jQuery UI Resizable 1.8.18
+.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*!
+ * jQuery UI Resizable 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Resizable#theming
  */
 .ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
 .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
 .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
 .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
@@ -303,20 +303,20 @@
 .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
 .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
 .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
- * jQuery UI Selectable 1.8.18
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*!
+ * jQuery UI Selectable 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Selectable#theming
  */
 .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*
- * jQuery UI Accordion 1.8.18
+/*!
+ * jQuery UI Accordion 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -332,10 +332,10 @@
 .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
 .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
 .ui-accordion .ui-accordion-content-active { display: block; }
-/*
- * jQuery UI Autocomplete 1.8.18
+/*!
+ * jQuery UI Autocomplete 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -347,7 +347,7 @@
 * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
 
 /*
- * jQuery UI Menu 1.8.18
+ * jQuery UI Menu 1.8.21
  *
  * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
@@ -385,16 +385,16 @@
 	font-weight: normal;
 	margin: -1px;
 }
-/*
- * jQuery UI Button 1.8.18
+/*!
+ * jQuery UI Button 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Button#theming
  */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: hidden; *overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
 .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
 button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
 .ui-button-icons-only { width: 3.4em; } 
@@ -423,10 +423,10 @@ input.ui-button { padding: .4em 1em; }
 
 /* workarounds */
 button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-/*
- * jQuery UI Dialog 1.8.18
+/*!
+ * jQuery UI Dialog 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -444,10 +444,10 @@ button.ui-button::-moz-focus-inner { bor
 .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
 .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
 .ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*
- * jQuery UI Slider 1.8.18
+/*!
+ * jQuery UI Slider 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -467,10 +467,10 @@ button.ui-button::-moz-focus-inner { bor
 .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
 .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
 .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
- * jQuery UI Tabs 1.8.18
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*!
+ * jQuery UI Tabs 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -485,10 +485,10 @@ button.ui-button::-moz-focus-inner { bor
 .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
 .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
 .ui-tabs .ui-tabs-hide { display: none !important; }
-/*
- * jQuery UI Datepicker 1.8.18
+/*!
+ * jQuery UI Datepicker 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
@@ -552,10 +552,10 @@ button.ui-button::-moz-focus-inner { bor
     left: -4px; /*must have*/
     width: 200px; /*must have*/
     height: 200px; /*must have*/
-}/*
- * jQuery UI Progressbar 1.8.18
+}/*!
+ * jQuery UI Progressbar 1.8.21
  *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *

Modified: incubator/bloodhound/trunk/trac/trac/htdocs/css/prefs.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/htdocs/css/prefs.css?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/htdocs/css/prefs.css (original)
+++ incubator/bloodhound/trunk/trac/trac/htdocs/css/prefs.css Tue Oct 16 20:06:09 2012
@@ -1,25 +1,46 @@
-#content.prefs #tabs { list-style: none; margin: 2em 1em 0; padding: 1px; }
-#content.prefs #tabs li { background: #e6e6e6; border: 1px solid;
-  border-color: #ccc #666 #ccc #ccc; color: #666; position: relative;
-  bottom: -1px; float: left; font-size: 90%; margin: 0 .5em;
-  padding: .2em 1em .3em;
+#content.prefs #tabs {
+ list-style: none;
+ margin: 2em 1em 0;
+ padding: 1px;
+}
+#content.prefs #tabs li { 
+ background: #e6e6e6;
+ border: 1px solid;
+ border-color: #ccc #666 #ccc #ccc;
+ border-top-left-radius: .5em;
+ border-top-right-radius: .5em;
+ color: #666; 
+ position: relative;
+ bottom: -1px;
+ float: left;
+ font-size: 90%;
+ margin: 0 .3em;
+ padding: .2em 1em .3em;
 }
 #content.prefs #tabs :link, #content.prefs #tabs :visited {
-  border: none; color: #999;
+ border: none;
+ color: #999;
 }
 #content.prefs #tabs :link:hover, #content.prefs #tabs :visited:hover {
-  background: transparent; color: #333;
+ background: transparent; 
+ color: #333;
 }
-#content.prefs #tabs li.active { background: #fff;
-  border-bottom: 1px solid #fff;
+#content.prefs #tabs li.active {
+ background: #fff;
+ border-bottom: 1px solid #fff;
 }
 #content.prefs #tabs #tab_advanced { float: right; }
-#content.prefs #tabcontent { background: url(../vgradient.png) 0 1px repeat-x;
-  border-top: 1px solid #ccc; clear: left; padding: 20px 5px;
+#content.prefs #tabcontent {
+ background: url(../vgradient.png) 0 1px repeat-x;
+ border-top: 1px solid #ccc;
+ clear: left;
+ padding: 20px 5px;
 }
 * html #content.prefs #tabcontent { padding-top: 0; }
 
 #content.prefs div.field { margin-bottom: 1em; }
-#content.prefs tr.field th { text-align: right; vertical-align: middle;
-  white-space: nowrap;
+#content.prefs tr.field th {
+ text-align: right;
+ vertical-align: middle;
+ white-space: nowrap;
 }