incubator-bloodhound-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g..@apache.org
Subject svn commit: r1307953 - in /incubator/bloodhound/trunk/bloodhound_dashboard: ./ bhdashboard/ bhdashboard/templates/ bhdashboard/tests/ bhdashboard/tests/data/ bhdashboard/widgets/ void/
Date Sun, 01 Apr 2012 00:20:10 GMT
Author: gjm
Date: Sun Apr  1 00:20:09 2012
New Revision: 1307953

URL: http://svn.apache.org/viewvc?rev=1307953&view=rev
Log:
Dashboard code import: BH_Dashboard: Initial version. (Simple) initialization and exception test cases ... PASS

Added:
    incubator/bloodhound/trunk/bloodhound_dashboard/
    incubator/bloodhound/trunk/bloodhound_dashboard/CHANGES
    incubator/bloodhound/trunk/bloodhound_dashboard/COPYRIGHT
    incubator/bloodhound/trunk/bloodhound_dashboard/MANIFEST.in   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/NOTICE   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/README   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/TESTING_README
    incubator/bloodhound/trunk/bloodhound_dashboard/TODO
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/__init__.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/api.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/__init__.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/data/
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/data/ticket_data.ini
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/test_report.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/util.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/web_ui.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/__init__.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/report.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/setup.cfg
    incubator/bloodhound/trunk/bloodhound_dashboard/setup.py   (with props)
    incubator/bloodhound/trunk/bloodhound_dashboard/void/
    incubator/bloodhound/trunk/bloodhound_dashboard/void/__init__.py   (with props)

Added: incubator/bloodhound/trunk/bloodhound_dashboard/CHANGES
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/CHANGES?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/CHANGES (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/CHANGES Sun Apr  1 00:20:09 2012
@@ -0,0 +1,5 @@
+
+What's new in version 1.0.0
+---------------------------
+
+- 

Added: incubator/bloodhound/trunk/bloodhound_dashboard/COPYRIGHT
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/COPYRIGHT?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/COPYRIGHT (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/COPYRIGHT Sun Apr  1 00:20:09 2012
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

Added: incubator/bloodhound/trunk/bloodhound_dashboard/MANIFEST.in
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/MANIFEST.in?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/MANIFEST.in (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/MANIFEST.in Sun Apr  1 00:20:09 2012
@@ -0,0 +1,7 @@
+
+include CHANGES COPYRIGHT NOTICE README TODO
+graft bhdashboard/templates
+graft bhdashboard/htdocs
+graft bhdashboard/widgets/templates
+graft bhdashboard/widgets/htdocs
+graft bhdashboard/tests/data

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/MANIFEST.in
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/NOTICE
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/NOTICE?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/NOTICE (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/NOTICE Sun Apr  1 00:20:09 2012
@@ -0,0 +1 @@
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/NOTICE
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/README
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/README?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/README (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/README Sun Apr  1 00:20:09 2012
@@ -0,0 +1,63 @@
+
+= Project dashboard for Apache(TM) Bloodhound =
+
+ Add custom dashboards in multiple pages of Bloodhound sites.
+
+== !ToDo ==
+
+Outstanding tasks are :
+
+[[TicketQuery(component=bhdashboard&priority=major, format=list, rows=id|summary)]]
+
+== Dependencies ==
+
+This plugin depends on the following components to be installed:
+
+
+  - [http:trac.edgewall.org Trac]  ,,Since version 
+    ''' 1.0 ''',, . 
+
+
+== Installation ==
+
+This plugin has been tested with 
+[http://trac.edgewall.org/ Trac]  [http://trac.edgewall.org/wiki/0.11 0.11]  [http://trac.edgewall.org/wiki/0.12 0.12]  [http://trac.edgewall.org/wiki/0.13 0.13] .
+
+The first step to make it work is to [wiki:TracPlugins install this plugin] 
+either for a particular environment or otherwise make it available to
+all the environments:
+
+{{{
+$ easy_install /path/to/unpacked/BloodhoundDashboardPlugin-x.y.z.zip
+}}}
+
+,, where ''x.y.z'' is the version of the plugin,,
+
+... or alternately ...
+
+{{{
+$ easy_install BloodhoundDashboardPlugin
+}}}
+
+In case of having internet connection and access to 
+[http://pypi.python.org/pypi PyPI] or a simlar repository, both these 
+methods '''should''' automatically retrieve the [#Dependencies external 
+dependencies] from there.
+
+== Configuration ==
+
+In order to enable [wiki:/En/Devel/BloodhoundDashboardPlugin BloodhoundDashboardPlugin] plugin, 
+the only thing to do is to add the following lines to [wiki:TracIni trac.ini].
+
+{{{
+[components]
+bhdashboard.* = enabled
+}}}
+
+== Bug / feature requests ==
+
+Existing bugs and feature requests for [wiki:/En/Devel/BloodhoundDashboardPlugin BloodhoundDashboardPlugin] are
+[query:status=new|assigned|reopened&component=bhdashboard here].
+If you have any issues, please create a [/newticket?component=bhdashboard new ticket].
+
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/README
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/TESTING_README
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/TESTING_README?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/TESTING_README (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/TESTING_README Sun Apr  1 00:20:09 2012
@@ -0,0 +1,53 @@
+
+= Testing Bloodhound Dashboard plugin =
+
+== Overview ==
+
+This plugin makes use of `setuptools` `test` command. Therefore all 
+test-support libraries needed to run the test suite should be installed 
+automatically (... considering the fact that they are listed in 
+`tests_require` and `install_requires` entries in `setup.ini` script ;).
+Recommended is the use of virtual Python environments. 
+
+== How to run tests ==
+
+All tests are written in files under `bhdashboard/tests` folder 
+(sub-modules of `bhdashboard.tests`) having names starting with prefix 
+`test_`. The following command should be enough so as to run tests 
+in one such module :
+
+{{{
+#!sh
+
+$ /path/to/python setup.py test -m bhdashboard.tests.test_<something>
+
+}}}
+
+... where `<something>` should be replaced to match the name of an existing 
+file containing tests e.g.
+
+{{{
+#!sh
+
+$ /path/to/python setup.py test -m bhdashboard.tests.test_report
+
+}}}
+
+== Continuous integration ==
+
+*TODO*
+
+== How do we run tests ==
+
+At present members of the team run tests on their computers as mentioned below :
+
+  - ''Python'' '''2.6''' virtual environment , Trac '''0.11.7''' .
+
+Besides there's a whole continuous integration infrastructure behind the 
+project (but that's TBD so far, should be documented later so that's in the 
+*TODO* list).
+
+PS: ... much more details missing here BTW ... should be added as soon 
+as possible ;) . Unfortunately weeks only have 7 days , 
+days only have 24 hours ... :-/
+

Added: incubator/bloodhound/trunk/bloodhound_dashboard/TODO
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/TODO?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/TODO (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/TODO Sun Apr  1 00:20:09 2012
@@ -0,0 +1,5 @@
+
+Outstanding tasks
+-----------------
+
+- 

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/__init__.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/__init__.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/__init__.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+Add custom dashboards in multiple pages of Bloodhound sites.
+"""
+
+# Ignore errors to avoid Internal Server Errors
+from trac.core import TracError
+TracError.__str__ = lambda self: unicode(self).encode('ascii', 'ignore')
+
+try:
+    from bhdashboard import *
+    msg = 'Ok'
+except Exception, exc:
+#    raise
+    msg = "Exception %s raised: '%s'" % (exc.__class__.__name__, str(exc))

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/__init__.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/api.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/api.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/api.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/api.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+The core of the dashboard architecture.
+"""
+
+from trac.core import Component, ExtensionPoint, implements, \
+        Interface, TracError
+from trac.perm import IPermissionRequestor
+from trac.util.translation import _
+
+class IWidgetProvider(Interface):
+    r"""Extension point interface for components providing widgets.
+    These may be seen as web parts more sophisticated than WikiMacro 
+    as they expose much more meta-data, but more simple than gadgets
+    because they belong in the environment and are built on top of Trac
+    architecture. This makes them more suitable to be used in 
+    environments where flexibility and configurability is needed 
+    (i.e. dashboards).
+    """
+    def get_widgets():
+        """Return an iterable listing the names of the provided widgets."""
+
+    def get_widget_description(name):
+        """Return plain text description of the widget with specified name."""
+
+    def get_widget_params(name):
+        """Return a dictionary describing wigdet preference for the widget 
+        with specified name. Used to customize widget behavior."""
+
+    def render_widget(name, context, options):
+        """Render widget considering given options."""
+
+    # TODO: Add methods to specify widget metadata (e.g. parameters)
+
+class DashboardSystem(Component):
+    implements(IPermissionRequestor)
+
+    providers = ExtensionPoint(IWidgetProvider)
+
+    # IPermissionRequestor methods
+    def get_permission_actions(self):
+        return ['DASHBOARD_VIEW',
+                # 'DASHBOARD_CREATE', 'DASHBOARD_EDIT' <= Coming soon ;)
+               ]
+
+    # Public API
+    def bind_params(self, options, spec, *params):
+        """Extract values for widget arguments from `options` and ensure 
+        they are valid and properly formatted.
+        """
+        # Should this helper function be part of public API ?
+        def get_and_check(p):
+            try:
+                param_spec = spec[p]
+            except KeyError:
+                raise InvalidWidgetArgument("Unknown parameter `%s`" % (p,))
+            try:
+                argtype = param_spec.get('type') or unicode
+                return argtype(options['args'][p])
+            except KeyError:
+                if param_spec.get('required'):
+                    raise InvalidWidgetArgument(p,
+                            "Required parameter expected")
+        return (get_and_check(param) for param in params)
+
+# Maybe it is better to move these to a separate file 
+# (if this gets as big as it seems it will be)
+
+class WidgetException(TracError):
+    """Base class for all errors related to Trac widgets"""
+
+class InvalidIdentifier(WidgetException):
+    """Invalid value for a field used to identify an internal object"""
+
+    title = 'Invalid identifier'
+
+class InvalidWidgetArgument(WidgetException):
+    """Something went wrong with widget parameter"""
+    
+    title = 'Invalid Argument'
+    
+    def __init__(self, argname, message, title=None, show_traceback=False):
+        TracError.__init__(self, message, title, show_traceback)
+        self.argname = argname
+    
+    def __unicode__(self):
+        return unicode(_("Invalid argument `") + self.argname + "`. " + \
+                self.message)
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/api.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html Sun Apr  1 00:20:09 2012
@@ -0,0 +1,30 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude">
+  <xi:include href="layout.html" />
+  <head>
+    <title>$title</title>
+  </head>
+
+  <body class="yui-skin-sam">
+    <div id="content" class="dashboard">
+      <div id="doc3" class="yui-t7">  
+        <div id="hd" role="banner"><h1>Header</h1></div>  
+        <div id="bd" role="main">  
+          <div class="yui-g">  
+            <div class="yui-u first">  
+              
+            </div>  
+            <div class="yui-u">  
+              
+            </div>  
+          </div>  
+        </div>  
+        <div id="ft" role="contentinfo"><p>Footer</p></div>  
+      </div>  
+    </div>
+  </body>
+</html>

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/templates/dashboard.html
------------------------------------------------------------------------------
    svn:mime-type = text/html

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/__init__.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/__init__.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/__init__.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,377 @@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+r"""Test artifacts.
+
+The test suites have been run using Trac=0.11.1 , Trac=0.11.5 , Trac=0.11.7
+"""
+
+__metaclass__ = type
+
+from trac.core import ComponentMeta
+from trac.db.api import _parse_db_str, DatabaseManager
+from trac.mimeview.api import Context
+from trac.test import EnvironmentStub
+from trac.util.compat import set
+
+import sys
+
+#------------------------------------------------------
+#    Trac environments used for testing purposes
+#------------------------------------------------------
+
+class EnvironmentStub(EnvironmentStub):
+  r"""Enhanced stub of the trac.env.Environment object for testing.
+  """
+
+  # Dont break lazy evaluation. Otherwise RPC calls misteriously fail.
+  @property
+  def _abs_href(self):
+    return self.abs_href
+
+  def enable_component(self, clsdef):
+    r"""Enable a plugin temporarily at testing time.
+    """
+    if clsdef not in self.enabled_components :
+      self.enabled_components.append(clsdef)
+
+  def disable_component(self, clsdef):
+    r"""Disable a plugin temporarily at testing time.
+    """
+    try:
+      self.enabled_components.remove(clsdef)
+    except ValueError :
+      self.log.warning("Component %s was not enabled", clsdef)
+
+  def rip_component(self, cls):
+    r"""Disable a plugin forever and RIP it using the super-laser beam.
+    """
+    self.disable_component(cls)
+    for reg in ComponentMeta._registry.itervalues():
+      try:
+        reg.remove(cls)
+      except ValueError :
+        pass
+
+  if not hasattr(EnvironmentStub, 'reset_db'):
+
+    # Copycat trac.test.EnvironmentStub.reset_db (Trac=0.11.5)
+    def reset_db(self, default_data=None):
+        r"""Remove all data from Trac tables, keeping the tables themselves.
+        :param default_data: after clean-up, initialize with default data
+        :return: True upon success
+        """
+        from trac import db_default
+
+        db = self.get_db_cnx()
+        db.rollback() # make sure there's no transaction in progress
+        cursor = db.cursor()
+
+        defdata = list(db_default.get_data(db))
+
+        for table, cols, vals in defdata:
+            cursor.execute("DELETE FROM %s" % (table,) )
+
+        db.commit()
+
+        if default_data:
+            for table, cols, vals in defdata:
+                cursor.executemany("INSERT INTO %s (%s) VALUES (%s)"
+                                   % (table, ','.join(cols),
+                                      ','.join(['%s' for c in cols])),
+                                   vals)
+        else:
+            cursor.execute("INSERT INTO system (name, value) "
+                           "VALUES (%s, %s)",
+                           ('database_version', str(db_default.db_version)))
+        db.commit()
+
+#------------------------------------------------------
+#    Minimalistic testing framework for Trac
+#------------------------------------------------------
+
+from dutest import DocTestLoader, DocTestSuiteFixture
+from os.path import dirname
+from types import MethodType
+
+from bhdashboard.util import dummy_request
+
+# Hide this module from tracebacks written into test results.
+__unittest = False
+
+class DocTestTracLoader(DocTestLoader):
+  r"""A generic XUnit loader that allows to load doctests written 
+  to check that Trac plugins behave as expected.
+  """
+  def set_env(self, env):
+    if self.extraglobs is None :
+      self.extraglobs = dict(env=env)
+    else :
+      self.extraglobs['env'] = env
+
+  env = property(lambda self : self.extraglobs.get('env'), set_env, \
+                  doc="""The Trac environment used in doctests.""")
+  del set_env
+
+  def __init__(self, dt_finder=None, globs=None, extraglobs=None, \
+                          load=None, default_data=False, enable=None, \
+                          **opts):
+    r"""Initialization. It basically works like `DocTestLoader`'s 
+    initializer but creates also the Trac environment used for 
+    testing purposes. The default behavior is to create an instance 
+    of `EnvironmentStub` class. Subclasses can add more specific 
+    keyword parameters in order to use them to create the 
+    environment. Next it loads (and | or) enables the components 
+    needed by the test suite.
+
+    The following variables are magically available at testing time. 
+    They can be used directly in doctests :
+
+    - req         A dummy request object setup for anonymous access.
+    - auth_req    A dummy request object setup like if user `murphy` was  
+                  accessing the site.
+    - env         the Trac environment used as a stub for testing 
+                  purposes (i.e. `self.env`).
+
+    @param dt_finder        see docs for `DocTestLoader.__init__` 
+                            method.
+    @param globs            see docs for `DocTestLoader.__init__` 
+                            method.
+    @param extraglobs       see docs for `DocTestLoader.__init__` 
+                            method.
+    @param load             a list of packages containing components 
+                            that will be loaded to ensure they are 
+                            available at testing time. It should be 
+                            the top level module in that package 
+                            (e.g. 'trac').
+    @param default_data     If true, populate the database with some 
+                            defaults. This parameter has to be 
+                            handled by `createTracEnv` method.
+    @param enable           a list of UNIX patterns specifying which 
+                            components need to be enabled by default 
+                            at testing time. This parameter should be 
+                            handled by `createTracEnv` method.
+    """
+    super(DocTestTracLoader, self).__init__(dt_finder, globs, \
+                                              extraglobs, **opts)
+    self.env = self.createTracEnv(default_data, enable, **opts)
+    self.load_components(load is None and self.default_packages or load)
+
+  # Load trac built-in components by default
+  default_packages = ['trac']
+
+  def createTracEnv(self, default_data=False, enable=None, **params):
+    r"""Create the Trac environment used for testing purposes. The 
+    default behavior is to create an instance of `EnvironmentStub` 
+    class. Subclasses can override this decision and add more specific 
+    keyword parameters in order to control environment creation in 
+    more detail. 
+
+    All parameters supplied at initialization time. By default they 
+    are ignored.
+    @param default_data     If True, populate the database with some 
+                            defaults.
+    @param enable           a list of UNIX patterns specifying which 
+                            components need to be enabled by default 
+                            at testing time.
+    @return                 the environment used for testing purpose.
+    """
+    return EnvironmentStub(default_data, enable)
+
+  def load_components(self, pkgs):
+    r"""Load some packages to ensure that the components they 
+    implement are available at testing time.
+    """
+    from trac.loader import load_components
+    for pkg in pkgs :
+      try :
+        __import__(pkg)
+      except ImportError :
+        pass                        # Skip pkg. What a shame !
+      else :
+        mdl = sys.modules[pkg]
+        load_components(self.env, dirname(dirname(mdl.__file__)))
+
+  class doctestSuiteClass(DocTestSuiteFixture):
+    r"""Prepare the global namespace before running all doctests 
+    in the suite. Reset the Trac environment.
+    """
+    username = 'murphy'
+
+    @property
+    def env(self):
+      r"""The Trac environment involved in this test. It is 
+      retrieved using the global namespace ;o).
+      """
+      return self.globalns['env']
+
+    def new_request(self, uname=None, args=None):
+      r"""Create and initialize a new request object.
+      """
+      req = dummy_request(self.env, uname)
+      if args is not None :
+        req.args = args
+      return req
+
+    def setUp(self):
+      r"""Include two (i.e. `req` anonymous and `auth_req` 
+      authenticated) request objects in the global namespace, before 
+      running the doctests. Besides, clean up environment data and 
+      include only default data.
+      """
+      globs = self.globalns
+      req = self.new_request(args=dict())
+      auth_req = self.new_request(uname=self.username, args=dict())
+      globs['req'] = req
+      globs['auth_req'] = auth_req
+      # TODO: If the source docstrings belong to a Trac component, 
+      #       then instantiate it and include in the global 
+      #       namespace.
+
+      # Delete data in Trac tables
+      from trac import db_default
+      db = self.env.get_db_cnx()
+      cursor = db.cursor()
+      for table in db_default.schema:
+        cursor.execute("DELETE FROM " + table.name)
+      db.commit()
+
+      self.env.reset_db(default_data=True)
+
+#------------------------------------------------------
+#    Test artifacts used to test widget providers
+#------------------------------------------------------
+
+from bhdashboard.api import InvalidIdentifier
+
+class DocTestWidgetLoader(DocTestTracLoader):
+  r"""Load doctests used to test Trac RPC handlers.
+  """
+  class doctestSuiteClass(DocTestTracLoader.doctestSuiteClass):
+    r"""Include the appropriate RPC handler in global namespace 
+    before running all test cases in the suite.
+    """
+
+    def ns_from_name(self):
+      r"""Extract the target namespace under test using the name
+      of the DocTest instance manipulated by the suite.
+      """
+      try :
+        return self._dt.name.split(':', 1)[0].split('|', 1)[-1]
+      except :
+        return None
+
+    def partial_setup(self):
+      r"""Perform partial setup due to some minor failure (e.g. 
+      namespace missing in test name).
+      """
+      globs = self.globalns
+      globs['widget'] = globs['ctx'] = globs['auth_ctx'] = None
+
+    def setup_widget(self, widgetns):
+      r"""(Insert | update) the IWidgetProvider in the global 
+      namespace.
+
+      @param widgetns             widget name.
+      @throws RuntimeError        if a widget with requested name cannot 
+                                  be found.
+      """
+      globs = self.globalns
+      globs['ctx'] = Context.from_request(globs['req'])
+      globs['auth_ctx'] = Context.from_request(globs['auth_req'])
+      for wp in self.dbsys.providers :
+        if widgetns in set(wp.get_widgets()) :
+          globs['widget'] = wp
+          break
+      else :
+        raise InvalidIdentifier('Cannot load widget provider for %s' % widgetns)
+
+    def setUp(self):
+      r"""Include the appropriate widget provider in global namespace 
+      before running all test cases in the suite. In this case three
+      objects are added to the global namespace :
+
+        - `widget`       the component implementing the widget under test
+        - `ctx`          context used to render the widget for 
+                         anonymous user
+        - `auth_ctx`     context used to render the widget for 
+                         authenticated user
+      """
+      # Fail here if BloodhoundDashboardPlugin is not available. Thus 
+      # this fact will be reported as a failure and subsequent test 
+      # cases will be run anyway.
+      from bhdashboard.api import DashboardSystem
+      self.dbsys = DashboardSystem(self.env)
+
+      # Add request objects
+      DocTestTracLoader.doctestSuiteClass.setUp(self)
+
+      widgetns = self.ns_from_name()
+      if widgetns is None :
+        # TODO: If doctests belong to a widget provider class then 
+        #       instantiate it. In the mean time ...
+        self.partial_setup()
+      else :
+        try :
+          self.setup_widget(widgetns)
+        except InvalidIdentifier:
+          self.partial_setup()
+
+#------------------------------------------------------
+#    Helper functions used in test cases
+#------------------------------------------------------
+
+def clear_perm_cache(_env, _req):
+  r"""Ensure that cache policies will not prevent test cases from 
+  altering user permissions right away.
+  """
+  from trac.perm import PermissionSystem, DefaultPermissionPolicy
+
+  _req.perm._cache.clear()            # Clear permission cache
+  for policy in PermissionSystem(_env).policies :
+    if isinstance(policy, DefaultPermissionPolicy):
+      policy.permission_cache.clear() # Clear policy cache
+      break
+
+#------------------------------------------------------
+#    Global test data
+#------------------------------------------------------
+
+from ConfigParser import RawConfigParser
+from pkg_resources import resource_stream
+
+def load_test_data(key):
+  r"""Load data used for testing purposes. Currently such data is 
+  stored in .INI files inside `data` directory.
+
+  @param key          currently the path to the file containing the 
+                      data, relative to `data` folder. 
+  """
+  fo = resource_stream(__name__, 'data/%s.ini' % key)
+  try :
+    p = RawConfigParser()
+    p.readfp(fo)
+    for section in p.sections():
+      yield section, dict(p.items(section))
+  finally :
+    fo.close()
+
+# The set of tickets used by test cases.
+ticket_data = [(attrs.pop('summary'), attrs.pop('description'), attrs) \
+                for _, attrs in sorted(load_test_data('ticket_data'))]
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/__init__.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/data/ticket_data.ini
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/data/ticket_data.ini?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/data/ticket_data.ini (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/data/ticket_data.ini Sun Apr  1 00:20:09 2012
@@ -0,0 +1,86 @@
+
+[ticket1]
+summary = Ticket 1
+description = Description 1
+priority = major
+milestone = milestone1
+type = defect
+owner = murphy
+status = accepted
+component = component1
+version = 1.0
+
+[ticket2]
+summary = Ticket 2
+description = Description 2
+priority = major
+milestone = milestone4
+type = task
+owner = murphy
+status = accepted
+
+[ticket3]
+summary = Ticket 3
+description = Description 3
+priority = critical
+milestone = milestone3
+type = enhancement
+owner = tester
+version = 2.0
+
+[ticket4]
+summary = Ticket 4
+description = Description 4
+priority = minor
+milestone = milestone3
+type = task
+owner = murphy
+status = closed
+component = component1
+version = 1.0
+
+[ticket5]
+summary = Ticket 5
+description = Description 5
+priority = minor
+milestone = milestone3
+type = task
+owner = murphy
+version = 2.0
+
+[ticket6]
+summary = Ticket 6
+description = Description 6
+priority = minor
+milestone = milestone1
+type = task
+owner = tester
+status = assigned
+component = component2
+version = 1.0
+
+[ticket7]
+summary = Ticket 7
+description = Description 7
+priority = critical
+type = enhancement
+owner = murphy
+status = closed
+
+[ticket8]
+summary = Ticket 8
+description = Description 8
+priority = major
+type = task
+owner = murphy
+status = closed
+component = component1
+
+[ticket9]
+summary = Ticket 9
+description = Description 9
+priority = minor
+type = enhancement
+owner = tester
+status = closed
+version = 2.0

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/test_report.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/test_report.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/test_report.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/test_report.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+In this file you'll find part of the tests written to ensure that
+widgets displaying contents generated by TracReports behave as expected.
+
+Only the tests requiring minimal setup effort are included below. 
+This means that the environment used to run these tests contains the 
+barely minimal information included in an environment (i.e. only the 
+data specified by `trac.db_default.get_data`.).
+
+Once the tests are started all built-in components (except 
+trac.versioncontrol.* ) as well as widget system and extensions
+are loaded. Besides the following values are (auto-magically)
+made available in the global namespace (i.e. provided that 
+the test name be written like `|widget_name: Descriptive message`):
+
+  - req         A dummy request object setup for anonymous access.
+  - auth_req    A dummy request object setup like if user `murphy` was  
+                accessing the site.
+  - env         the Trac environment used as a stub for testing purposes.
+                This object is an instance of 
+                `bhdashboard.tests.EnvironmentStub`.
+  - widget      the widget provider under test.
+  - ctx         context used to render widget for anonymous user.
+  - ctx_auth    context used to render widget for `murphy` user.
+  - ticket_data A set of tickets used for testing purposes.
+"""
+
+#------------------------------------------------------
+#    Test artifacts
+#------------------------------------------------------
+
+def test_suite():
+  from doctest import NORMALIZE_WHITESPACE, ELLIPSIS, REPORT_UDIFF
+  from dutest import MultiTestLoader
+  from unittest import defaultTestLoader
+  
+  from __init__ import DocTestWidgetLoader, ticket_data
+  
+  magic_vars = dict(ticket_data=ticket_data)
+  l = MultiTestLoader(
+        [defaultTestLoader, \
+          DocTestWidgetLoader(extraglobs=magic_vars, \
+                            enable=['trac.[a-uw-z]*', 'bhdashboard.*'], \
+                            default_data=True, \
+                            optionflags=ELLIPSIS | # REPORT_UDIFF | \
+                                        NORMALIZE_WHITESPACE) \
+        ])
+  
+  import sys
+  return l.loadTestsFromModule(sys.modules[__name__])
+
+#------------------------------------------------------
+#    Helper functions
+#------------------------------------------------------
+
+from datetime import datetime, time, date
+from itertools import izip
+from pprint import pprint
+
+from __init__ import clear_perm_cache
+
+def print_report_metadata(report_desc):
+  for attrnm in ('id', 'title', 'description', 'query'):
+    print attrnm.capitalize()
+    print '-' * len(attrnm)
+    print report_desc[attrnm]
+
+def print_report_columns(cols):
+  for coldsc in cols:
+    print 'Column:', coldsc[0], 'Type:', coldsc[1] or '_', \
+          'Label:', 
+    try :
+      print coldsc[2] or '_'
+    except IndexError :
+      print '_'
+
+def print_report_result(cols, data):
+  for i, row in enumerate(data):
+    print '= Row', i, '='
+    for coldsc in cols:
+      colnm = coldsc[0]
+      print 'Column:', colnm, 'Value:', row.get(colnm) or None, ''
+
+TICKET_ATTRS = ('summary', 'description', 'priority', \
+                'milestone', 'type', 'owner', 'status', \
+                'component', 'version')
+
+def prepare_ticket_workflow(tcktrpc, ticket_data, auth_req):
+  r"""Set ticket status considering the actions defined in standard 
+  ticket workflow. Needed for TracRpc>=1.0.6
+  """
+  from time import sleep
+  
+  TICKET_ACTIONS = {'accepted': 'accept', 'closed' : 'resolve',
+                    'assigned': 'reassign'}
+  sleep(1)
+  for idx, (_, __, td) in enumerate(ticket_data) :
+    action = TICKET_ACTIONS.get(td.get('status'))
+    if action is not None :
+      aux_attrs = {'action' : action}
+      aux_attrs.update(td)
+      tcktrpc.update(auth_req, idx + 1, "", aux_attrs)
+  sleep(1)
+  for idx, (_, __, td) in enumerate(ticket_data) :
+    tcktrpc.update(auth_req, idx + 1, "", td)
+
+__test__ = {
+    'Initialization: Report widgets' : r"""
+      >>> from trac.core import ComponentMeta
+      >>> from bhdashboard.api import IWidgetProvider
+      >>> from bhdashboard.widgets.report import *
+      >>> allcls = ComponentMeta._registry.get(IWidgetProvider, [])
+      >>> for wpcls in (TicketReportWidget,):
+      ...   print wpcls in allcls
+      ...
+      True
+      """,
+    '|TicketReport: Metadata' : r"""
+      >>> list(widget.get_widgets())
+      ['TicketReport']
+      >>> params = widget.get_widget_params('TicketReport')
+      >>> pprint(params)
+      {'id': {'desc': 'Report number',
+                  'required': True,
+                  'type': <type 'int'>},
+       'limit': {'default': 0,
+                  'desc': 'Number of results to retrieve',
+                  'type': <type 'int'>}}
+      """,
+    '|TicketReport: Render My Tickets report' : r"""
+      >>> widget.render_widget('TicketReport', ctx, {
+      ...     'args' : {'id' : 7}
+      ...   })
+      ...
+      """,
+    '|TicketReport: Render a subset of My Tickets report' : r"""
+      >>> widget.render_widget('TicketReport', ctx, {
+      ...     'args' : {'id' : 7}
+      ...   })
+      ...
+      """,
+    '|TicketReport: Invalid widget name' : r"""
+      >>> widget.render_widget('OlkswSk', ctx, {
+      ...     'args' : {'id' : 1, 'limit' : 8}
+      ...   })
+      ...
+      Traceback (most recent call last):
+        ...
+      InvalidIdentifier: Widget name MUST match any of TicketReport
+      """,
+    '|TicketReport: Invalid report ID in arguments' : r"""
+      >>> widget.render_widget('TicketReport', ctx, {
+      ...     'args' : {'id' : 99999}
+      ...   })
+      ...
+      Traceback (most recent call last):
+        ...
+      InvalidIdentifier: Report 99999 does not exist
+      """,
+    '|TicketReport: Missing required arguments' : r"""
+      >>> widget.render_widget('TicketReport', ctx, {
+      ...     'args' : {}
+      ...   })
+      ...
+      Traceback (most recent call last):
+        ...
+      InvalidWidgetArgument: Invalid argument `id`. Required parameter expected
+
+      >>> widget.render_widget('TicketReport', ctx, {
+      ...     'args' : {}
+      ...   })
+      ...
+      Traceback (most recent call last):
+        ...
+      InvalidWidgetArgument: Invalid argument `id`. Required parameter expected
+      """,
+    '|TicketReport: Invalid widget parameter' : r"""
+      >>> widget.render_widget('TicketReport', ctx, {
+      ...     'args' : {'newjums' : 7, 'id' : 3}
+      ...   })
+      ...
+      """,
+    '|TicketReport: Invalid report definition' : r"""
+      >>> raise NotImplementedError()
+      """,
+  }
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/tests/test_report.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/util.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/util.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/util.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/util.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+Helper functions and classes.
+"""
+
+from functools import update_wrapper
+import inspect
+from urlparse import urlparse
+
+from trac.core import Component, implements
+from trac.web.api import Request
+from trac.web.chrome import Chrome
+from trac.web.main import RequestDispatcher
+
+from bhdashboard.api import DashboardSystem, IWidgetProvider, InvalidIdentifier
+
+def dummy_request(env, uname=None):
+    environ = {
+                'trac.base_url' : str(env._abs_href()), 
+                'SCRIPT_NAME' : urlparse(str(env._abs_href())).path
+                }
+    req = Request(environ, lambda *args, **kwds: None)
+    # Intercept redirection
+    req.redirect = lambda *args, **kwds: None
+    # Setup user information
+    if uname is not None :
+      environ['REMOTE_USER'] = req.authname = uname
+    
+    rd = RequestDispatcher(env)
+    chrome = Chrome(env)
+    req.callbacks.update({
+        'authname': rd.authenticate,
+        'chrome': chrome.prepare_request,
+        'hdf': rd._get_hdf,
+        'perm': rd._get_perm,
+        'session': rd._get_session,
+        'tz': rd._get_timezone,
+        'form_token': rd._get_form_token
+    })
+    return req
+
+
+class WidgetBase(Component):
+    """Abstract base class for widgets"""
+
+    implements(IWidgetProvider)
+    abstract = True
+
+    def get_widgets(self):
+        """Yield the name of the widget based on the class name."""
+        name = self.__class__.__name__
+        if name.endswith('Widget'):
+            name = name[:-6]
+        yield name
+
+    def get_widget_description(self, name):
+        """Return the subclass's docstring."""
+        return to_unicode(inspect.getdoc(self.__class__))
+
+    def get_widget_params(self, name):
+        """Return a dictionary containing arguments specification for
+        the widget with specified name.
+        """
+        raise NotImplementedError
+
+    def render_widget(self, context, name, options):
+        """Render widget considering given options."""
+        raise NotImplementedError
+
+    # Helper methods
+    def bind_params(self, name, options, *params):
+        return DashboardSystem(self.env).bind_params(options, 
+                self.get_widget_params(name), *params)
+
+def check_widget_name(f):
+    """Decorator used to wrap methods of widget providers so as to ensure
+    widget names will match those listed by `get_widgets` method.
+    """
+    def widget_name_checker(self, name, *args, **kwargs):
+        names = set(self.get_widgets())
+        if name not in names: 
+            raise InvalidIdentifier('Widget name MUST match any of ' + 
+                        ', '.join(names), 
+                    title='Invalid widget identifier')
+        return f(self, name, *args, **kwargs)
+    return widget_name_checker
+
+def pretty_wrapper(wrapped, *decorators):
+    """Apply multiple decorators to a given function and make the result 
+    look like wrapped function.
+    """
+    wrapper = wrapped
+    for f in decorators:
+        wrapper = f(wrapper)
+    return update_wrapper(wrapper, wrapped)
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/util.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/web_ui.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/web_ui.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/web_ui.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/web_ui.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+Implementing dashboard user interface.
+"""
+
+import pkg_resources
+import re
+
+from trac.core import Component, implements
+from trac.config import Option
+from trac.web.api import IRequestHandler
+from trac.web.chrome import INavigationContributor, ITemplateProvider
+
+class DashboardModule(Component):
+    implements(IRequestHandler, INavigationContributor, ITemplateProvider)
+
+    mainnav_label = Option('dashboard', 'mainnav', 'Dashboard', \
+                            """Dashboard label in mainnav""")
+
+    # IRequestHandler methods
+    def match_request(self, req):
+        """Match dashboard prefix"""
+        return bool(re.match(r'^/dashboard(/.)?', req.path_info))
+
+    def process_request(self, req):
+        """Initially this will render static widgets. With time it will be 
+        more and more dynamic and flexible.
+        """
+
+    # INavigationContributor methods
+    def get_active_navigation_item(self, req):
+        """Highlight dashboard mainnav item.
+        """
+        return 'dashboard'
+
+    def get_navigation_items(self, req):
+        """Add an item in mainnav to access global dashboard
+        """
+        if 'DASHBOARD_VIEW' in req.perm:
+            yield ('mainnav', 'dashboard', 
+                    tag.a(_(self.mainnav_label), href=req.href.dashboard()))
+
+    # ITemplateProvider methods
+    def get_htdocs_dirs(self):
+        """List `htdocs` dirs for dashboard and widgets.
+        """
+        resource_filename = pkg_resources.resource_filename
+        return [
+                ('dashboard', resource_filename('bhdashboard', 'htdocs')),
+                ('widgets', resource_filename('bhdashboard.widgets', 'htdocs'))]
+
+    def get_templates_dirs(self):
+        """List `templates` folders for dashboard and widgets.
+        """
+        resource_filename = pkg_resources.resource_filename
+        return [resource_filename('bhdashboard', 'templates'),
+                resource_filename('bhdashboard.widgets', 'templates')]
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/web_ui.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/__init__.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/__init__.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/__init__.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+Available widgets.
+"""
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/__init__.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/report.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/report.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/report.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/report.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+r"""Project dashboard for Apache(TM) Bloodhound
+
+Widgets displaying report data.
+"""
+
+from datetime import datetime, date, time
+from itertools import imap
+
+from trac.core import implements, TracError
+from trac.ticket.report import ReportModule
+from trac.util.translation import _
+
+from bhdashboard.util import WidgetBase, InvalidIdentifier, \
+                              check_widget_name, pretty_wrapper
+
+class TicketReportWidget(WidgetBase):
+    """Display tickets in saved report using a grid
+    """
+    def get_widget_params(self, name):
+        """Return a dictionary containing arguments specification for
+        the widget with specified name.
+        """
+        return {
+                'id' : {
+                        'desc' : """Report number""",
+                        'required' : True,
+                        'type' : int,
+                    },
+                'limit' : {
+                        'default' : 0,
+                        'desc' : """Number of results to retrieve""",
+                        'type' : int,
+                },
+            }
+    get_widget_params = pretty_wrapper(get_widget_params, check_widget_name)
+
+    def render_widget(self, name, context, options):
+        """Execute stored report and render data using a grid
+        """
+        metadata = data = None
+        req = context.req
+        try:
+            rptid, limit = self.bind_params(name, options, 'id', 'limit')
+            metadata = self.get(req, rptid)
+            # TODO: Should metadata also contain columns definition ?
+            data = list(self.execute(req, rptid))
+        except TracError, exc:
+            if metadata is not None :
+                exc.title = metadata.get('title', 'TracReports')
+            else:
+                exc.title = 'TracReports'
+            raise
+        else:
+            return 'widget_grid', data, context
+
+    render_widget = pretty_wrapper(render_widget, check_widget_name)
+
+    # Internal methods
+
+    # These have been imported verbatim from existing 
+    # `tracgviz.rpc.ReportRPC` class in TracGViz plugin ;)
+    def get(self, req, id):
+        r"""Return information about an specific report as a dict 
+        containing the following fields.
+        
+        - id :            the report ID.
+        - title:          the report title.
+        - description:    the report description.
+        - query:          the query string used to select the tickets 
+                          to be included in this report. This field 
+                          is returned only if `REPORT_SQL_VIEW` has 
+                          been granted to the client performing the 
+                          request. Otherwise it is empty.
+        """
+        if 'REPORT_SQL_VIEW' in req.perm:
+            sql = "SELECT id,title,query,description from report " \
+                   "WHERE id=%s" % (id,)
+        else :
+            sql = "SELECT id,title,NULL,description from report " \
+                   "WHERE id=%s" % (id,)
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
+        try:
+            cursor.execute(sql)
+            for report_info in cursor:
+                return dict(zip(['id','title','query','description'], report_info))
+            else:
+                return None
+        finally:
+            cursor.close()
+
+    def _execute_sql(self, req, id, sql, limit=0):
+        r"""Execute a SQL report and return no more than `limit` rows 
+        (or all rows if limit == 0).
+        """
+        repmdl = ReportModule(self.env)
+        db = self.env.get_db_cnx()
+        try:
+            args = repmdl.get_var_args(req)
+        except ValueError,e:
+            raise ValueError(_('Report failed: %(error)s', error=e))
+        try:
+            try:
+                # Paginated exec (>=0.11)
+                exec_proc = repmdl.execute_paginated_report
+                kwargs = dict(limit=limit)
+            except AttributeError:
+                # Legacy exec (<=0.10)
+                exec_proc = repmdl.execute_report
+                kwargs = {}
+            return exec_proc(req, db, id, sql, args, **kwargs)[:2]
+        except Exception, e:
+            db.rollback()
+            raise 
+
+    def execute(self, req, id, limit=0):
+        r"""Execute a Trac report.
+
+        @param id     the report ID.
+        @return       a list containing the data provided by the 
+                      target report.
+        @throws       `NotImplementedError` if the report definition 
+                      consists of saved custom query specified 
+                      using a URL.
+        @throws       `QuerySyntaxError` if the report definition 
+                      consists of a `TracQuery` containing syntax errors.
+        @throws       `Exception` in case of detecting any other error.
+        """
+        report_spec = self.get(req, id)
+        if report_spec is None:
+            raise InvalidIdentifier('Report %s does not exist' % (id,))
+        sql = report_spec['query']
+        query = ''.join([line.strip() for line in sql.splitlines()])
+        if query and (query[0] == '?' or query.startswith('query:?')):
+            raise NotImplementedError('Saved custom queries specified ' \
+                                  'using URLs are not supported.')
+        elif query.startswith('query:'):
+            query = Query.from_string(self.env, query[6:], report=id)
+            server_url = urlparse(req.base_url)
+            server_href = Href(urlunparse((server_url.scheme, \
+                                        server_url.netloc, \
+                                        '', '', '', '')))
+            def rel2abs(row):
+                """Turn relative value in 'href' into absolute URLs."""
+                self.log.debug('IG: Query Row %s', row)
+                url = row['href']
+                urlobj = urlparse(url)
+                if not urlobj.netloc:
+                    row['href'] = server_href(url)
+                return row
+            
+            return imap(rel2abs, query.execute(req))
+        else:
+            cols, results = self._execute_sql(req, id, sql, limit=limit)
+            return (dict(zip(cols, list(row))) for row in results)
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/report.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/setup.cfg
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/setup.cfg?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/setup.cfg (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/setup.cfg Sun Apr  1 00:20:09 2012
@@ -0,0 +1,7 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
+[sdist]
+formats = gztar,bztar,ztar,tar,zip

Added: incubator/bloodhound/trunk/bloodhound_dashboard/setup.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/setup.py?rev=1307953&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/setup.py (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/setup.py Sun Apr  1 00:20:09 2012
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+try:
+    from setuptools import setup
+except ImportError:
+    from distutils.core import setup
+
+from bhdashboard.__init__ import __doc__ as DESC
+
+versions = [
+    (1, 0, 0),
+    ]
+    
+latest = '.'.join(str(x) for x in versions[-1])
+
+status = {
+            'planning' :  "Development Status :: 1 - Planning",
+            'pre-alpha' : "Development Status :: 2 - Pre-Alpha",
+            'alpha' :     "Development Status :: 3 - Alpha",
+            'beta' :      "Development Status :: 4 - Beta",
+            'stable' :    "Development Status :: 5 - Production/Stable",
+            'mature' :    "Development Status :: 6 - Mature",
+            'inactive' :  "Development Status :: 7 - Inactive"
+         }
+dev_status = status["alpha"]
+
+cats = [
+      dev_status,
+      "Environment :: Plugins", 
+      "Environment :: Web Environment", 
+      "Framework :: Trac", 
+      "Intended Audience :: Developers", 
+      "Intended Audience :: Information Technology", 
+      "Intended Audience :: Other Audience", 
+      "Intended Audience :: System Administrators", 
+      "License :: Unknown", 
+      "Operating System :: OS Independent", 
+      "Programming Language :: Python", 
+      "Programming Language :: Python :: 2.5", 
+      "Programming Language :: Python :: 2.6",
+      "Programming Language :: Python :: 2.7",
+      "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries", 
+      "Topic :: Internet :: WWW/HTTP :: HTTP Servers", 
+      "Topic :: Internet :: WWW/HTTP :: WSGI", 
+      "Topic :: Software Development :: Bug Tracking", 
+      "Topic :: Software Development :: Libraries :: Application Frameworks", 
+      "Topic :: Software Development :: Libraries :: Python Modules", 
+      "Topic :: Software Development :: User Interfaces",
+      "Topic :: Software Development :: Widget Sets"
+    ]
+
+# Be compatible with older versions of Python
+from sys import version
+if version < '2.2.3':
+    from distutils.dist import DistributionMetadata
+    DistributionMetadata.classifiers = None
+    DistributionMetadata.download_url = None
+
+# Add the change log to the package description.
+chglog = None
+try:
+    from os.path import dirname, join
+    chglog = open(join(dirname(__file__), "CHANGES"))
+    DESC+= ('\n\n' + chglog.read())
+finally:
+    if chglog:
+        chglog.close()
+
+DIST_NM = 'BloodhoundDashboardPlugin'
+PKG_INFO = {'bhdashboard' : ('bhdashboard',                     # Package dir
+                            # Package data
+                            ['../CHANGES', '../TODO', '../COPYRIGHT', 
+                              '../NOTICE', '../README', '../TESTING_README'
+                              'templates/*', 'htdocs/*'],
+                          ), 
+            'bhdashboard.widgets' : ('bhdashboard/widgets',     # Package dir
+                            # Package data
+                            ['templates/*', 'htdocs/*'],
+                          ), 
+            'bhdashboard.tests' : ('bhdashboard/tests',     # Package dir
+                            # Package data
+                            ['data/**'],
+                          ), 
+            }
+
+ENTRY_POINTS = r"""
+               [trac.plugins]
+               bhdashboard.api = bhdashboard.api
+               bhdashboard.web_ui = bhdashboard.web_ui
+               bhdashboard.widgets.report = bhdashboard.widgets.report
+               """
+
+setup(
+    name=DIST_NM,
+    version=latest,
+    description=DESC.split('\n', 1)[0],
+    requires = ['trac'],
+    tests_require = ['dutest>=0.2.4'],
+    install_requires = [
+        'setuptools>=0.6b1',
+        'Trac>=0.11',
+    ],
+    package_dir = dict([p, i[0]] for p, i in PKG_INFO.iteritems()),
+    packages = PKG_INFO.keys(),
+    package_data = dict([p, i[1]] for p, i in PKG_INFO.iteritems()),
+    include_package_data=True,
+    provides = ['%s (%s)' % (p, latest) for p in PKG_INFO.keys()],
+    obsoletes = ['%s (>=%s.0.0, <%s)' % (p, versions[-1][0], latest) \
+                  for p in PKG_INFO.keys()],
+    entry_points = ENTRY_POINTS,
+    classifiers = cats,
+    long_description= DESC
+    )
+

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/setup.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/trunk/bloodhound_dashboard/void/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/void/__init__.py?rev=1307953&view=auto
==============================================================================
    (empty)

Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/void/__init__.py
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message