Adds dash/panel app templates, mgmt commands, template loader.
Implements blueprint scaffolding. Using custom management commands you can now create the majority of the boilerplate code for a new dashboard or panel from a set of basic templates with a single command. See the docs for more info. Additionally, in support of the new commands (and inherent codified directory structure) there's a new template loader included which can load templates from "templates" directories in any registered panel. Change-Id: I1df5eb152cb18694dc89d562799c8d3e8950ca6f
This commit is contained in:
parent
8396026722
commit
1721ba9c4a
@ -43,6 +43,48 @@ tests by using the ``--skip-selenium`` flag::
|
|||||||
This isn't recommended, but can be a timesaver when you only need to run
|
This isn't recommended, but can be a timesaver when you only need to run
|
||||||
the code tests and not the frontend tests during development.
|
the code tests and not the frontend tests during development.
|
||||||
|
|
||||||
|
Using Dashboard and Panel Templates
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Horizon has a set of convenient management commands for creating new
|
||||||
|
dashboards and panels based on basic templates.
|
||||||
|
|
||||||
|
Dashboards
|
||||||
|
----------
|
||||||
|
|
||||||
|
To create a new dashboard, run the following:
|
||||||
|
|
||||||
|
./run_tests.sh -m startdash <dash_name>
|
||||||
|
|
||||||
|
This will create a directory with the given dashboard name, a ``dashboard.py``
|
||||||
|
module with the basic dashboard code filled in, and various other common
|
||||||
|
"boilerplate" code.
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
|
||||||
|
* --target: the directory in which the dashboard files should be created.
|
||||||
|
Default: A new directory within the current directory.
|
||||||
|
|
||||||
|
Panels
|
||||||
|
------
|
||||||
|
|
||||||
|
To create a new panel, run the following:
|
||||||
|
|
||||||
|
./run_tests -m startpanel <panel_name> --dashboard=<dashboard_path>
|
||||||
|
|
||||||
|
This will create a directory with the given panel name, and ``panel.py``
|
||||||
|
module with the basic panel code filled in, and various other common
|
||||||
|
"boilerplate" code.
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
|
||||||
|
* -d, --dashboard: The dotted python path to your dashboard app (the module
|
||||||
|
which containers the ``dashboard.py`` file.).
|
||||||
|
* --target: the directory in which the panel files should be created.
|
||||||
|
If the value is ``auto`` the panel will be created as a new directory inside
|
||||||
|
the dashboard module's directory structure. Default: A new directory within
|
||||||
|
the current directory.
|
||||||
|
|
||||||
Give me metrics!
|
Give me metrics!
|
||||||
================
|
================
|
||||||
|
|
||||||
|
@ -31,6 +31,17 @@ Creating a dashboard
|
|||||||
incorporate it into an existing dashboard. See the section
|
incorporate it into an existing dashboard. See the section
|
||||||
:ref:`overrides <overrides>` later in this document.
|
:ref:`overrides <overrides>` later in this document.
|
||||||
|
|
||||||
|
The quick version
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Horizon provides a custom management command to create a typical base
|
||||||
|
dashboard structure for you. The following command generates most of the
|
||||||
|
boilerplate code explained below::
|
||||||
|
|
||||||
|
./run_tests.sh -m startdash visualizations
|
||||||
|
|
||||||
|
It's still recommended that you read the rest of this section to understand
|
||||||
|
what that command creates and why.
|
||||||
|
|
||||||
Structure
|
Structure
|
||||||
---------
|
---------
|
||||||
@ -116,13 +127,32 @@ but it could also go elsewhere, such as in an override file (see below).
|
|||||||
Creating a panel
|
Creating a panel
|
||||||
================
|
================
|
||||||
|
|
||||||
Now that we have our dashboard written, we can also create our panel.
|
Now that we have our dashboard written, we can also create our panel. We'll
|
||||||
|
call it "flocking".
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
You don't need to write a custom dashboard to add a panel. The structure
|
You don't need to write a custom dashboard to add a panel. The structure
|
||||||
here is for the sake of completeness in the tutorial.
|
here is for the sake of completeness in the tutorial.
|
||||||
|
|
||||||
|
The quick version
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Horizon provides a custom management command to create a typical base
|
||||||
|
panel structure for you. The following command generates most of the
|
||||||
|
boilerplate code explained below::
|
||||||
|
|
||||||
|
./run_tests.sh -m startpanel flocking --dashboard=visualizations --target=auto
|
||||||
|
|
||||||
|
The ``dashboard`` argument is required, and tells the command which dashboard
|
||||||
|
this panel will be registered with. The ``target`` argument is optional, and
|
||||||
|
respects ``auto`` as a special value which means that the files for the panel
|
||||||
|
should be created inside the dashboard module as opposed to the current
|
||||||
|
directory (the default).
|
||||||
|
|
||||||
|
It's still recommended that you read the rest of this section to understand
|
||||||
|
what that command creates and why.
|
||||||
|
|
||||||
Structure
|
Structure
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import collections
|
|||||||
import copy
|
import copy
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.defaults import patterns, url, include
|
from django.conf.urls.defaults import patterns, url, include
|
||||||
@ -37,6 +38,7 @@ from django.utils.importlib import import_module
|
|||||||
from django.utils.module_loading import module_has_submodule
|
from django.utils.module_loading import module_has_submodule
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from horizon import loaders
|
||||||
from horizon.decorators import (require_auth, require_roles,
|
from horizon.decorators import (require_auth, require_roles,
|
||||||
require_services, _current_component)
|
require_services, _current_component)
|
||||||
|
|
||||||
@ -541,12 +543,26 @@ class Dashboard(Registry, HorizonComponent):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def register(cls, panel):
|
def register(cls, panel):
|
||||||
""" Registers a :class:`~horizon.Panel` with this dashboard. """
|
""" Registers a :class:`~horizon.Panel` with this dashboard. """
|
||||||
return Horizon.register_panel(cls, panel)
|
panel_class = Horizon.register_panel(cls, panel)
|
||||||
|
# Support template loading from panel template directories.
|
||||||
|
panel_mod = import_module(panel.__module__)
|
||||||
|
panel_dir = os.path.dirname(panel_mod.__file__)
|
||||||
|
template_dir = os.path.join(panel_dir, "templates")
|
||||||
|
if os.path.exists(template_dir):
|
||||||
|
key = os.path.join(cls.slug, panel.slug)
|
||||||
|
loaders.panel_template_dirs[key] = template_dir
|
||||||
|
return panel_class
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def unregister(cls, panel):
|
def unregister(cls, panel):
|
||||||
""" Unregisters a :class:`~horizon.Panel` from this dashboard. """
|
""" Unregisters a :class:`~horizon.Panel` from this dashboard. """
|
||||||
return Horizon.unregister_panel(cls, panel)
|
success = Horizon.unregister_panel(cls, panel)
|
||||||
|
if success:
|
||||||
|
# Remove the panel's template directory.
|
||||||
|
key = os.path.join(cls.slug, panel.slug)
|
||||||
|
if key in loaders.panel_template_dirs:
|
||||||
|
del loaders.panel_template_dirs[key]
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
class Workflow(object):
|
class Workflow(object):
|
||||||
|
0
horizon/conf/__init__.py
Normal file
0
horizon/conf/__init__.py
Normal file
0
horizon/conf/dash_template/__init__.py
Normal file
0
horizon/conf/dash_template/__init__.py
Normal file
13
horizon/conf/dash_template/dashboard.py
Normal file
13
horizon/conf/dash_template/dashboard.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class {{ dash_name|title }}(horizon.Dashboard):
|
||||||
|
name = _("{{ dash_name|title }}")
|
||||||
|
slug = "{{ dash_name|slugify }}"
|
||||||
|
panels = () # Add your panels here.
|
||||||
|
default_panel = '' # Specify the slug of the dashboard's default panel.
|
||||||
|
|
||||||
|
|
||||||
|
horizon.register({{ dash_name|title }})
|
3
horizon/conf/dash_template/models.py
Normal file
3
horizon/conf/dash_template/models.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
|
||||||
|
"""
|
@ -0,0 +1 @@
|
|||||||
|
/* Additional CSS for {{ dash_name }}. */
|
@ -0,0 +1 @@
|
|||||||
|
/* Additional JavaScript for {{ dash_name }}. */
|
11
horizon/conf/dash_template/templates/dash_name/base.html
Normal file
11
horizon/conf/dash_template/templates/dash_name/base.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% load horizon %}{% jstemplate %}[% extends 'base.html' %]
|
||||||
|
|
||||||
|
[% block sidebar %]
|
||||||
|
[% include 'horizon/common/_sidebar.html' %]
|
||||||
|
[% endblock %]
|
||||||
|
|
||||||
|
[% block main %]
|
||||||
|
[% include "horizon/_messages.html" %]
|
||||||
|
[% block {{ dash_name }}_main %][% endblock %]
|
||||||
|
[% endblock %]
|
||||||
|
{% endjstemplate %}
|
0
horizon/conf/panel_template/__init__.py
Normal file
0
horizon/conf/panel_template/__init__.py
Normal file
3
horizon/conf/panel_template/models.py
Normal file
3
horizon/conf/panel_template/models.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
|
||||||
|
"""
|
13
horizon/conf/panel_template/panel.py
Normal file
13
horizon/conf/panel_template/panel.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from {{ dash_path }} import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class {{ panel_name|title }}(horizon.Panel):
|
||||||
|
name = _("{{ panel_name|title }}")
|
||||||
|
slug = "{{ panel_name|slugify }}"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.register({{ panel_name|title }})
|
12
horizon/conf/panel_template/templates/panel_name/index.html
Normal file
12
horizon/conf/panel_template/templates/panel_name/index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% load horizon %}{% jstemplate %}[% extends '{{ dash_name }}/base.html' %]
|
||||||
|
[% load i18n %]
|
||||||
|
[% block title %][% trans "{{ panel_name|title }}" %][% endblock %]
|
||||||
|
|
||||||
|
[% block page_header %]
|
||||||
|
[% include "horizon/common/_page_header.html" with title=_("{{ panel_name|title }}") %]
|
||||||
|
[% endblock page_header %]
|
||||||
|
|
||||||
|
[% block {{ dash_name }}_main %]
|
||||||
|
[% endblock %]
|
||||||
|
|
||||||
|
{% endjstemplate %}
|
7
horizon/conf/panel_template/tests.py
Normal file
7
horizon/conf/panel_template/tests.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from horizon import test
|
||||||
|
|
||||||
|
|
||||||
|
class {{ panel_name|title}}Tests(test.TestCase):
|
||||||
|
# Unit tests for {{ panel_name }}.
|
||||||
|
def test_me(self):
|
||||||
|
self.assertTrue(1 + 1 == 2)
|
7
horizon/conf/panel_template/urls.py
Normal file
7
horizon/conf/panel_template/urls.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from django.conf.urls.defaults import patterns, url
|
||||||
|
|
||||||
|
from .views import IndexView
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^$', IndexView.as_view(), name='index'),
|
||||||
|
)
|
10
horizon/conf/panel_template/views.py
Normal file
10
horizon/conf/panel_template/views.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from horizon import views
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(views.APIView):
|
||||||
|
# A very simple class-based view...
|
||||||
|
template_name = '{{ panel_name }}/index.html'
|
||||||
|
|
||||||
|
def get_data(self, request, context, *args, **kwargs):
|
||||||
|
# Add data to the context here...
|
||||||
|
return context
|
46
horizon/loaders.py
Normal file
46
horizon/loaders.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
Wrapper for loading templates from "templates" directories in panel modules.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template.base import TemplateDoesNotExist
|
||||||
|
from django.template.loader import BaseLoader
|
||||||
|
from django.utils._os import safe_join
|
||||||
|
|
||||||
|
# Set up a cache of the panel directories to search.
|
||||||
|
panel_template_dirs = {}
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateLoader(BaseLoader):
|
||||||
|
is_usable = True
|
||||||
|
|
||||||
|
def get_template_sources(self, template_name):
|
||||||
|
dash_name, panel_name, remainder = template_name.split(os.path.sep, 2)
|
||||||
|
key = os.path.join(dash_name, panel_name)
|
||||||
|
if key in panel_template_dirs:
|
||||||
|
template_dir = panel_template_dirs[key]
|
||||||
|
try:
|
||||||
|
yield safe_join(template_dir, panel_name, remainder)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
# The template dir name wasn't valid UTF-8.
|
||||||
|
raise
|
||||||
|
except ValueError:
|
||||||
|
# The joined path was located outside of template_dir.
|
||||||
|
pass
|
||||||
|
|
||||||
|
def load_template_source(self, template_name, template_dirs=None):
|
||||||
|
for path in self.get_template_sources(template_name):
|
||||||
|
try:
|
||||||
|
file = open(path)
|
||||||
|
try:
|
||||||
|
return (file.read().decode(settings.FILE_CHARSET), path)
|
||||||
|
finally:
|
||||||
|
file.close()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
raise TemplateDoesNotExist(template_name)
|
||||||
|
|
||||||
|
|
||||||
|
_loader = TemplateLoader()
|
0
horizon/management/__init__.py
Normal file
0
horizon/management/__init__.py
Normal file
0
horizon/management/commands/__init__.py
Normal file
0
horizon/management/commands/__init__.py
Normal file
49
horizon/management/commands/startdash.py
Normal file
49
horizon/management/commands/startdash.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from optparse import make_option
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.management.base import CommandError
|
||||||
|
from django.core.management.templates import TemplateCommand
|
||||||
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class Command(TemplateCommand):
|
||||||
|
template = os.path.join(horizon.__path__[0], "conf", "dash_template")
|
||||||
|
option_list = TemplateCommand.option_list + (
|
||||||
|
make_option('--target',
|
||||||
|
dest='target',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='The directory in which the panel '
|
||||||
|
'should be created. Defaults to the '
|
||||||
|
'current directory. The value "auto" '
|
||||||
|
'may also be used to automatically '
|
||||||
|
'create the panel inside the specified '
|
||||||
|
'dashboard module.'),)
|
||||||
|
help = ("Creates a Django app directory structure for a new dashboard "
|
||||||
|
"with the given name in the current directory or optionally in "
|
||||||
|
"the given directory.")
|
||||||
|
|
||||||
|
def handle(self, dash_name=None, **options):
|
||||||
|
if dash_name is None:
|
||||||
|
raise CommandError("You must provide a dashboard name.")
|
||||||
|
|
||||||
|
# Use our default template if one isn't specified.
|
||||||
|
if not options.get("template", None):
|
||||||
|
options["template"] = self.template
|
||||||
|
|
||||||
|
# We have html templates as well, so make sure those are included.
|
||||||
|
options["extensions"].extend(["html", "js", "css"])
|
||||||
|
|
||||||
|
# Check that the app_name cannot be imported.
|
||||||
|
try:
|
||||||
|
import_module(dash_name)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise CommandError("%r conflicts with the name of an existing "
|
||||||
|
"Python module and cannot be used as an app "
|
||||||
|
"name. Please try another name." % dash_name)
|
||||||
|
|
||||||
|
super(Command, self).handle('dash', dash_name, **options)
|
89
horizon/management/commands/startpanel.py
Normal file
89
horizon/management/commands/startpanel.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
from optparse import make_option
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.management.base import CommandError
|
||||||
|
from django.core.management.templates import TemplateCommand
|
||||||
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class Command(TemplateCommand):
|
||||||
|
args = "[name] [dashboard name] [optional destination directory]"
|
||||||
|
option_list = TemplateCommand.option_list + (
|
||||||
|
make_option('--dashboard', '-d',
|
||||||
|
dest='dashboard',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='The dotted python path to the '
|
||||||
|
'dashboard which this panel will be '
|
||||||
|
'registered with, e.g. '
|
||||||
|
'"horizon.dashboards.syspanel".'),
|
||||||
|
make_option('--target',
|
||||||
|
dest='target',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='The directory in which the panel '
|
||||||
|
'should be created. Defaults to the '
|
||||||
|
'current directory. The value "auto" '
|
||||||
|
'may also be used to automatically '
|
||||||
|
'create the panel inside the specified '
|
||||||
|
'dashboard module.'),)
|
||||||
|
template = os.path.join(horizon.__path__[0], "conf", "panel_template")
|
||||||
|
help = ("Creates a Django app directory structure for a new panel "
|
||||||
|
"with the given name in the current directory or optionally in "
|
||||||
|
"the given directory.")
|
||||||
|
|
||||||
|
def handle(self, panel_name=None, **options):
|
||||||
|
if panel_name is None:
|
||||||
|
raise CommandError("You must provide a panel name.")
|
||||||
|
|
||||||
|
if options.get('dashboard') is None:
|
||||||
|
raise CommandError("You must specify the name of the dashboard "
|
||||||
|
"this panel will be registered with using the "
|
||||||
|
"-d or --dashboard option.")
|
||||||
|
|
||||||
|
dashboard_path = options.get('dashboard')
|
||||||
|
dashboard_mod_path = ".".join([dashboard_path, "dashboard"])
|
||||||
|
|
||||||
|
# Check the the dashboard.py file in the dashboard app can be imported.
|
||||||
|
# Add the dashboard information to our options to pass along if all
|
||||||
|
# goes well.
|
||||||
|
try:
|
||||||
|
dashboard_mod = import_module(dashboard_mod_path)
|
||||||
|
options["dash_path"] = dashboard_path
|
||||||
|
options["dash_name"] = dashboard_path.split(".")[-1]
|
||||||
|
except ImportError:
|
||||||
|
raise CommandError("A dashboard.py module could not be imported "
|
||||||
|
" from the dashboard at %r."
|
||||||
|
% options.get("dashboard"))
|
||||||
|
|
||||||
|
target = options.pop("target", None)
|
||||||
|
if target == "auto":
|
||||||
|
target = os.path.join(os.path.dirname(dashboard_mod.__file__),
|
||||||
|
panel_name)
|
||||||
|
if not os.path.exists(target):
|
||||||
|
try:
|
||||||
|
os.mkdir(target)
|
||||||
|
except OSError, exc:
|
||||||
|
raise CommandError("Unable to create panel directory: %s"
|
||||||
|
% exc)
|
||||||
|
|
||||||
|
# Use our default template if one isn't specified.
|
||||||
|
if not options.get("template", None):
|
||||||
|
options["template"] = self.template
|
||||||
|
|
||||||
|
# We have html templates as well, so make sure those are included.
|
||||||
|
options["extensions"].extend(["html"])
|
||||||
|
|
||||||
|
# Check that the app_name cannot be imported.
|
||||||
|
try:
|
||||||
|
import_module(panel_name)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise CommandError("%r conflicts with the name of an existing "
|
||||||
|
"Python module and cannot be used as an app "
|
||||||
|
"name. Please try another name." % panel_name)
|
||||||
|
|
||||||
|
super(Command, self).handle('panel', panel_name, target, **options)
|
@ -132,13 +132,16 @@ class JSTemplateNode(template.Node):
|
|||||||
|
|
||||||
def render(self, context, ):
|
def render(self, context, ):
|
||||||
output = self.nodelist.render(context)
|
output = self.nodelist.render(context)
|
||||||
return output.replace('[[', '{{').replace(']]', '}}')
|
output = output.replace('[[', '{{').replace(']]', '}}')
|
||||||
|
output = output.replace('[%', '{%').replace('%]', '%}')
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
@register.tag
|
@register.tag
|
||||||
def jstemplate(parser, token):
|
def jstemplate(parser, token):
|
||||||
"""
|
"""
|
||||||
Replaces ``[[`` and ``]]`` with ``{{`` and ``}}`` to avoid conflicts
|
Replaces ``[[`` and ``]]`` with ``{{`` and ``}}`` and
|
||||||
|
``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts
|
||||||
with Django's template engine when using any of the Mustache-based
|
with Django's template engine when using any of the Mustache-based
|
||||||
templating libraries.
|
templating libraries.
|
||||||
"""
|
"""
|
||||||
|
@ -72,6 +72,7 @@ SITE_NAME = 'openstack'
|
|||||||
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
|
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
|
||||||
NOSE_ARGS = ['--nocapture',
|
NOSE_ARGS = ['--nocapture',
|
||||||
'--nologcapture',
|
'--nologcapture',
|
||||||
|
'--exclude-dir=horizon/conf/',
|
||||||
'--cover-package=horizon',
|
'--cover-package=horizon',
|
||||||
'--cover-inclusive']
|
'--cover-inclusive']
|
||||||
|
|
||||||
|
@ -78,7 +78,8 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
|||||||
|
|
||||||
TEMPLATE_LOADERS = (
|
TEMPLATE_LOADERS = (
|
||||||
'django.template.loaders.filesystem.Loader',
|
'django.template.loaders.filesystem.Loader',
|
||||||
'django.template.loaders.app_directories.Loader'
|
'django.template.loaders.app_directories.Loader',
|
||||||
|
'horizon.loaders.TemplateLoader'
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
TEMPLATE_DIRS = (
|
||||||
|
24
run_tests.sh
24
run_tests.sh
@ -6,7 +6,7 @@ set -o errexit
|
|||||||
# Increment me any time the environment should be rebuilt.
|
# Increment me any time the environment should be rebuilt.
|
||||||
# This includes dependncy changes, directory renames, etc.
|
# This includes dependncy changes, directory renames, etc.
|
||||||
# Simple integer secuence: 1, 2, 3...
|
# Simple integer secuence: 1, 2, 3...
|
||||||
environment_version=16
|
environment_version=17
|
||||||
#--------------------------------------------------------#
|
#--------------------------------------------------------#
|
||||||
|
|
||||||
function usage {
|
function usage {
|
||||||
@ -21,7 +21,8 @@ function usage {
|
|||||||
echo " -f, --force Force a clean re-build of the virtual"
|
echo " -f, --force Force a clean re-build of the virtual"
|
||||||
echo " environment. Useful when dependencies have"
|
echo " environment. Useful when dependencies have"
|
||||||
echo " been added."
|
echo " been added."
|
||||||
echo " -m, --makemessages Update all translation files."
|
echo " -m, --manage Run a Django management command."
|
||||||
|
echo " --makemessages Update all translation files."
|
||||||
echo " -p, --pep8 Just run pep8"
|
echo " -p, --pep8 Just run pep8"
|
||||||
echo " -t, --tabs Check for tab characters in files."
|
echo " -t, --tabs Check for tab characters in files."
|
||||||
echo " -y, --pylint Just run pylint"
|
echo " -y, --pylint Just run pylint"
|
||||||
@ -68,6 +69,7 @@ selenium=0
|
|||||||
testargs=""
|
testargs=""
|
||||||
with_coverage=0
|
with_coverage=0
|
||||||
makemessages=0
|
makemessages=0
|
||||||
|
manage=0
|
||||||
|
|
||||||
# Jenkins sets a "JOB_NAME" variable, if it's not set, we'll make it "default"
|
# Jenkins sets a "JOB_NAME" variable, if it's not set, we'll make it "default"
|
||||||
[ "$JOB_NAME" ] || JOB_NAME="default"
|
[ "$JOB_NAME" ] || JOB_NAME="default"
|
||||||
@ -83,7 +85,8 @@ function process_option {
|
|||||||
-t|--tabs) just_tabs=1;;
|
-t|--tabs) just_tabs=1;;
|
||||||
-q|--quiet) quiet=1;;
|
-q|--quiet) quiet=1;;
|
||||||
-c|--coverage) with_coverage=1;;
|
-c|--coverage) with_coverage=1;;
|
||||||
-m|--makemessages) makemessages=1;;
|
-m|--manage) manage=1;;
|
||||||
|
--makemessages) makemessages=1;;
|
||||||
--with-selenium) selenium=1;;
|
--with-selenium) selenium=1;;
|
||||||
--docs) just_docs=1;;
|
--docs) just_docs=1;;
|
||||||
--runserver) runserver=1;;
|
--runserver) runserver=1;;
|
||||||
@ -94,6 +97,10 @@ function process_option {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function run_management_command {
|
||||||
|
${command_wrapper} python $root/manage.py $testargs
|
||||||
|
}
|
||||||
|
|
||||||
function run_server {
|
function run_server {
|
||||||
echo "Starting Django development server..."
|
echo "Starting Django development server..."
|
||||||
${command_wrapper} python $root/manage.py runserver $testargs
|
${command_wrapper} python $root/manage.py runserver $testargs
|
||||||
@ -117,7 +124,7 @@ function run_pylint {
|
|||||||
function run_pep8 {
|
function run_pep8 {
|
||||||
echo "Running pep8 ..."
|
echo "Running pep8 ..."
|
||||||
rm -f pep8.txt
|
rm -f pep8.txt
|
||||||
PEP8_EXCLUDE=vcsversion.py
|
PEP8_EXCLUDE=vcsversion.py,panel_template,dash_template
|
||||||
PEP8_IGNORE=W602
|
PEP8_IGNORE=W602
|
||||||
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --ignore=$PEP8_IGNORE --repeat"
|
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --ignore=$PEP8_IGNORE --repeat"
|
||||||
${command_wrapper} pep8 $PEP8_OPTIONS $included_dirs | perl -ple 's/: ([WE]\d+)/: [$1]/' > pep8.txt || true
|
${command_wrapper} pep8 $PEP8_OPTIONS $included_dirs | perl -ple 's/: ([WE]\d+)/: [$1]/' > pep8.txt || true
|
||||||
@ -188,6 +195,9 @@ function environment_check {
|
|||||||
read update_env
|
read update_env
|
||||||
if [ "x$update_env" = "xY" -o "x$update_env" = "x" -o "x$update_env" = "xy" ]; then
|
if [ "x$update_env" = "xY" -o "x$update_env" = "x" -o "x$update_env" = "xy" ]; then
|
||||||
install_venv
|
install_venv
|
||||||
|
else
|
||||||
|
# Set our command wrapper anyway.
|
||||||
|
command_wrapper="${root}/${with_venv}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -346,6 +356,12 @@ fi
|
|||||||
|
|
||||||
# ---------EXERCISE THE CODE------------ #
|
# ---------EXERCISE THE CODE------------ #
|
||||||
|
|
||||||
|
# Run management commands
|
||||||
|
if [ $manage -eq 1 ]; then
|
||||||
|
run_management_command
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
# Build the docs
|
# Build the docs
|
||||||
if [ $just_docs -eq 1 ]; then
|
if [ $just_docs -eq 1 ]; then
|
||||||
run_sphinx
|
run_sphinx
|
||||||
|
@ -3,6 +3,7 @@ coverage
|
|||||||
django-nose
|
django-nose
|
||||||
mox
|
mox
|
||||||
nose
|
nose
|
||||||
|
nose-exclude
|
||||||
pep8
|
pep8
|
||||||
pylint
|
pylint
|
||||||
distribute>=0.6.24
|
distribute>=0.6.24
|
||||||
|
Loading…
Reference in New Issue
Block a user