610 lines
25 KiB
Python
610 lines
25 KiB
Python
|
#
|
||
|
# ex:ts=4:sw=4:sts=4:et
|
||
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||
|
#
|
||
|
# BitBake Toaster Implementation
|
||
|
#
|
||
|
# Copyright (C) 2016 Intel Corporation
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License version 2 as
|
||
|
# published by the Free Software Foundation.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License along
|
||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
|
||
|
from orm.models import Build, Task, Target, Package
|
||
|
from django.db.models import Q, Sum
|
||
|
|
||
|
import toastergui.tables as tables
|
||
|
from toastergui.widgets import ToasterTable
|
||
|
from toastergui.tablefilter import TableFilter
|
||
|
from toastergui.tablefilter import TableFilterActionToggle
|
||
|
|
||
|
|
||
|
class BuildTablesMixin(ToasterTable):
|
||
|
def get_context_data(self, **kwargs):
|
||
|
# We need to be explicit about which superclass we're calling here
|
||
|
# Otherwise the MRO gets in a right mess
|
||
|
context = ToasterTable.get_context_data(self, **kwargs)
|
||
|
context['build'] = Build.objects.get(pk=kwargs['build_id'])
|
||
|
return context
|
||
|
|
||
|
|
||
|
class BuiltPackagesTableBase(tables.PackagesTable):
|
||
|
""" Table to display all the packages built in a build """
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuiltPackagesTableBase, self).__init__(*args, **kwargs)
|
||
|
self.title = "Packages built"
|
||
|
self.default_orderby = "name"
|
||
|
|
||
|
def setup_queryset(self, *args, **kwargs):
|
||
|
build = Build.objects.get(pk=kwargs['build_id'])
|
||
|
self.static_context_extra['build'] = build
|
||
|
self.static_context_extra['target_name'] = None
|
||
|
self.queryset = build.package_set.all().exclude(recipe=None)
|
||
|
self.queryset = self.queryset.order_by(self.default_orderby)
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
super(BuiltPackagesTableBase, self).setup_columns(*args, **kwargs)
|
||
|
|
||
|
def pkg_link_template(val):
|
||
|
""" return the template used for the link with the val as the
|
||
|
element value i.e. inside the <a></a>"""
|
||
|
|
||
|
return ('''
|
||
|
<a href="
|
||
|
{%% url "package_built_detail" extra.build.pk data.pk %%}
|
||
|
">%s</a>
|
||
|
''' % val)
|
||
|
|
||
|
def recipe_link_template(val):
|
||
|
return ('''
|
||
|
{%% if data.recipe %%}
|
||
|
<a href="
|
||
|
{%% url "recipe" extra.build.pk data.recipe.pk %%}
|
||
|
">%(value)s</a>
|
||
|
{%% else %%}
|
||
|
%(value)s
|
||
|
{%% endif %%}
|
||
|
''' % {'value': val})
|
||
|
|
||
|
add_pkg_link_to = 'name'
|
||
|
add_recipe_link_to = 'recipe__name'
|
||
|
|
||
|
# Add the recipe and pkg build links to the required columns
|
||
|
for column in self.columns:
|
||
|
# Convert to template field style accessors
|
||
|
tmplv = column['field_name'].replace('__', '.')
|
||
|
tmplv = "{{data.%s}}" % tmplv
|
||
|
|
||
|
if column['field_name'] is add_pkg_link_to:
|
||
|
# Don't overwrite an existing template
|
||
|
if column['static_data_template']:
|
||
|
column['static_data_template'] =\
|
||
|
pkg_link_template(column['static_data_template'])
|
||
|
else:
|
||
|
column['static_data_template'] = pkg_link_template(tmplv)
|
||
|
|
||
|
column['static_data_name'] = column['field_name']
|
||
|
|
||
|
elif column['field_name'] is add_recipe_link_to:
|
||
|
# Don't overwrite an existing template
|
||
|
if column['static_data_template']:
|
||
|
column['static_data_template'] =\
|
||
|
recipe_link_template(column['static_data_template'])
|
||
|
else:
|
||
|
column['static_data_template'] =\
|
||
|
recipe_link_template(tmplv)
|
||
|
column['static_data_name'] = column['field_name']
|
||
|
|
||
|
self.add_column(title="Layer",
|
||
|
field_name="recipe__layer_version__layer__name",
|
||
|
hidden=True,
|
||
|
orderable=True)
|
||
|
|
||
|
layer_branch_template = '''
|
||
|
{%if not data.recipe.layer_version.layer.local_source_dir %}
|
||
|
<span class="text-muted">{{data.recipe.layer_version.branch}}</span>
|
||
|
{% else %}
|
||
|
<span class="text-muted">Not applicable</span>
|
||
|
<span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.recipe.layer_version.layer.name}} is not in a Git repository, so there is no branch associated with it"> </span>
|
||
|
{% endif %}
|
||
|
'''
|
||
|
|
||
|
self.add_column(title="Layer branch",
|
||
|
field_name="recipe__layer_version__branch",
|
||
|
hidden=True,
|
||
|
static_data_name="recipe__layer_version__branch",
|
||
|
static_data_template=layer_branch_template,
|
||
|
orderable=True)
|
||
|
|
||
|
git_rev_template = '''
|
||
|
{% if not data.recipe.layer_version.layer.local_source_dir %}
|
||
|
{% with vcs_ref=data.recipe.layer_version.commit %}
|
||
|
{% include 'snippets/gitrev_popover.html' %}
|
||
|
{% endwith %}
|
||
|
{% else %}
|
||
|
<span class="text-muted">Not applicable</span>
|
||
|
<span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.recipe.layer_version.layer.name}} is not in a Git repository, so there is no revision associated with it"> </span>
|
||
|
{% endif %}
|
||
|
'''
|
||
|
|
||
|
self.add_column(title="Layer commit",
|
||
|
static_data_name='vcs_ref',
|
||
|
static_data_template=git_rev_template,
|
||
|
hidden=True)
|
||
|
|
||
|
|
||
|
class BuiltPackagesTable(BuildTablesMixin, BuiltPackagesTableBase):
|
||
|
""" Show all the packages built for the selected build """
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuiltPackagesTable, self).__init__(*args, **kwargs)
|
||
|
self.title = "Packages built"
|
||
|
self.default_orderby = "name"
|
||
|
|
||
|
self.empty_state =\
|
||
|
('<strong>No packages were built.</strong> How did this happen? '
|
||
|
'Well, BitBake reuses as much stuff as possible. '
|
||
|
'If all of the packages needed were already built and available '
|
||
|
'in your build infrastructure, BitBake '
|
||
|
'will not rebuild any of them. This might be slightly confusing, '
|
||
|
'but it does make everything faster.')
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
super(BuiltPackagesTable, self).setup_columns(*args, **kwargs)
|
||
|
|
||
|
def remove_dep_cols(columns):
|
||
|
for column in columns:
|
||
|
# We don't need these fields
|
||
|
if column['static_data_name'] in ['reverse_dependencies',
|
||
|
'dependencies']:
|
||
|
continue
|
||
|
|
||
|
yield column
|
||
|
|
||
|
self.columns = list(remove_dep_cols(self.columns))
|
||
|
|
||
|
|
||
|
class InstalledPackagesTable(BuildTablesMixin, BuiltPackagesTableBase):
|
||
|
""" Show all packages installed in an image """
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(InstalledPackagesTable, self).__init__(*args, **kwargs)
|
||
|
self.title = "Packages Included"
|
||
|
self.default_orderby = "name"
|
||
|
|
||
|
def make_package_list(self, target):
|
||
|
# The database design means that you get the intermediate objects and
|
||
|
# not package objects like you'd really want so we get them here
|
||
|
pkgs = target.target_installed_package_set.values_list('package',
|
||
|
flat=True)
|
||
|
return Package.objects.filter(pk__in=pkgs)
|
||
|
|
||
|
def get_context_data(self, **kwargs):
|
||
|
context = super(InstalledPackagesTable,
|
||
|
self).get_context_data(**kwargs)
|
||
|
|
||
|
target = Target.objects.get(pk=kwargs['target_id'])
|
||
|
packages = self.make_package_list(target)
|
||
|
|
||
|
context['packages_sum'] = packages.aggregate(
|
||
|
Sum('installed_size'))['installed_size__sum']
|
||
|
|
||
|
context['target'] = target
|
||
|
return context
|
||
|
|
||
|
def setup_queryset(self, *args, **kwargs):
|
||
|
build = Build.objects.get(pk=kwargs['build_id'])
|
||
|
self.static_context_extra['build'] = build
|
||
|
|
||
|
target = Target.objects.get(pk=kwargs['target_id'])
|
||
|
# We send these separately because in the case of image details table
|
||
|
# we don't have a target just the recipe name as the target
|
||
|
self.static_context_extra['target_name'] = target.target
|
||
|
self.static_context_extra['target_id'] = target.pk
|
||
|
|
||
|
self.static_context_extra['add_links'] = True
|
||
|
|
||
|
self.queryset = self.make_package_list(target)
|
||
|
self.queryset = self.queryset.order_by(self.default_orderby)
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
super(InstalledPackagesTable, self).setup_columns(**kwargs)
|
||
|
self.add_column(title="Installed size",
|
||
|
static_data_name="installed_size",
|
||
|
static_data_template="{% load projecttags %}"
|
||
|
"{{data.size|filtered_filesizeformat}}",
|
||
|
orderable=True,
|
||
|
hidden=True)
|
||
|
|
||
|
# Add the template to show installed name for installed packages
|
||
|
install_name_tmpl =\
|
||
|
('<a href="{% url "package_included_detail" extra.build.pk'
|
||
|
' extra.target_id data.pk %}">{{data.name}}</a>'
|
||
|
'{% if data.installed_name and data.installed_name !='
|
||
|
' data.name %}'
|
||
|
'<span class="text-muted"> as {{data.installed_name}}</span>'
|
||
|
' <span class="glyphicon glyphicon-question-sign get-help hover-help"'
|
||
|
' title="{{data.name}} was renamed at packaging time and'
|
||
|
' was installed in your image as {{data.installed_name}}'
|
||
|
'"></span>{% endif %} ')
|
||
|
|
||
|
for column in self.columns:
|
||
|
if column['static_data_name'] == 'name':
|
||
|
column['static_data_template'] = install_name_tmpl
|
||
|
break
|
||
|
|
||
|
|
||
|
class BuiltRecipesTable(BuildTablesMixin):
|
||
|
""" Table to show the recipes that have been built in this build """
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuiltRecipesTable, self).__init__(*args, **kwargs)
|
||
|
self.title = "Recipes built"
|
||
|
self.default_orderby = "name"
|
||
|
|
||
|
def setup_queryset(self, *args, **kwargs):
|
||
|
build = Build.objects.get(pk=kwargs['build_id'])
|
||
|
self.static_context_extra['build'] = build
|
||
|
self.queryset = build.get_recipes()
|
||
|
self.queryset = self.queryset.order_by(self.default_orderby)
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
recipe_name_tmpl =\
|
||
|
'<a href="{% url "recipe" extra.build.pk data.pk %}">'\
|
||
|
'{{data.name}}'\
|
||
|
'</a>'
|
||
|
|
||
|
recipe_file_tmpl =\
|
||
|
'{{data.file_path}}'\
|
||
|
'{% if data.pathflags %}<i>({{data.pathflags}})</i>'\
|
||
|
'{% endif %}'
|
||
|
|
||
|
git_branch_template = '''
|
||
|
{% if data.layer_version.layer.local_source_dir %}
|
||
|
<span class="text-muted">Not applicable</span>
|
||
|
<span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.layer_version.layer.name}} is not in a Git repository, so there is no branch associated with it"> </span>
|
||
|
{% else %}
|
||
|
<span>{{data.layer_version.branch}}</span>
|
||
|
{% endif %}
|
||
|
'''
|
||
|
|
||
|
git_rev_template = '''
|
||
|
{% if data.layer_version.layer.local_source_dir %}
|
||
|
<span class="text-muted">Not applicable</span>
|
||
|
<span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.layer_version.layer.name}} is not in a Git repository, so there is no commit associated with it"> </span>
|
||
|
{% else %}
|
||
|
{% with vcs_ref=data.layer_version.commit %}
|
||
|
{% include 'snippets/gitrev_popover.html' %}
|
||
|
{% endwith %}
|
||
|
{% endif %}
|
||
|
'''
|
||
|
|
||
|
depends_on_tmpl = '''
|
||
|
{% with deps=data.r_dependencies_recipe.all %}
|
||
|
{% with count=deps|length %}
|
||
|
{% if count %}
|
||
|
<a class="btn btn-default" title="
|
||
|
<a href='{% url "recipe" extra.build.pk data.pk %}#dependencies'>
|
||
|
{{data.name}}</a> dependencies"
|
||
|
data-content="<ul class='list-unstyled'>
|
||
|
{% for dep in deps|dictsort:"depends_on.name"%}
|
||
|
<li><a href='{% url "recipe" extra.build.pk dep.depends_on.pk %}'>
|
||
|
{{dep.depends_on.name}}</a></li>
|
||
|
{% endfor %}
|
||
|
</ul>">
|
||
|
{{count}}
|
||
|
</a>
|
||
|
{% endif %}{% endwith %}{% endwith %}
|
||
|
'''
|
||
|
|
||
|
rev_depends_tmpl = '''
|
||
|
{% with revs=data.r_dependencies_depends.all %}
|
||
|
{% with count=revs|length %}
|
||
|
{% if count %}
|
||
|
<a class="btn btn-default"
|
||
|
title="
|
||
|
<a href='{% url "recipe" extra.build.pk data.pk %}#brought-in-by'>
|
||
|
{{data.name}}</a> reverse dependencies"
|
||
|
data-content="<ul class='list-unstyled'>
|
||
|
{% for dep in revs|dictsort:"recipe.name" %}
|
||
|
<li>
|
||
|
<a href='{% url "recipe" extra.build.pk dep.recipe.pk %}'>
|
||
|
{{dep.recipe.name}}
|
||
|
</a></li>
|
||
|
{% endfor %}
|
||
|
</ul>">
|
||
|
{{count}}
|
||
|
</a>
|
||
|
{% endif %}{% endwith %}{% endwith %}
|
||
|
'''
|
||
|
|
||
|
self.add_column(title="Recipe",
|
||
|
field_name="name",
|
||
|
static_data_name='name',
|
||
|
orderable=True,
|
||
|
hideable=False,
|
||
|
static_data_template=recipe_name_tmpl)
|
||
|
|
||
|
self.add_column(title="Version",
|
||
|
hideable=False,
|
||
|
field_name="version")
|
||
|
|
||
|
self.add_column(title="Dependencies",
|
||
|
static_data_name="dependencies",
|
||
|
static_data_template=depends_on_tmpl)
|
||
|
|
||
|
self.add_column(title="Reverse dependencies",
|
||
|
static_data_name="revdeps",
|
||
|
static_data_template=rev_depends_tmpl,
|
||
|
help_text='Recipe build-time reverse dependencies'
|
||
|
' (i.e. the recipes that depend on this recipe)')
|
||
|
|
||
|
self.add_column(title="Recipe file",
|
||
|
field_name="file_path",
|
||
|
static_data_name="file_path",
|
||
|
static_data_template=recipe_file_tmpl,
|
||
|
hidden=True)
|
||
|
|
||
|
self.add_column(title="Section",
|
||
|
field_name="section",
|
||
|
orderable=True,
|
||
|
hidden=True)
|
||
|
|
||
|
self.add_column(title="License",
|
||
|
field_name="license",
|
||
|
help_text='Multiple license names separated by the'
|
||
|
' pipe character indicates a choice between licenses.'
|
||
|
' Multiple license names separated by the ampersand'
|
||
|
' character indicates multiple licenses exist that'
|
||
|
' cover different parts of the source',
|
||
|
orderable=True)
|
||
|
|
||
|
self.add_column(title="Layer",
|
||
|
field_name="layer_version__layer__name",
|
||
|
orderable=True)
|
||
|
|
||
|
self.add_column(title="Layer branch",
|
||
|
field_name="layer_version__branch",
|
||
|
static_data_name="layer_version__branch",
|
||
|
static_data_template=git_branch_template,
|
||
|
orderable=True,
|
||
|
hidden=True)
|
||
|
|
||
|
self.add_column(title="Layer commit",
|
||
|
static_data_name="commit",
|
||
|
static_data_template=git_rev_template,
|
||
|
hidden=True)
|
||
|
|
||
|
|
||
|
class BuildTasksTable(BuildTablesMixin):
|
||
|
""" Table to show the tasks that run in this build """
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuildTasksTable, self).__init__(*args, **kwargs)
|
||
|
self.title = "Tasks"
|
||
|
self.default_orderby = "order"
|
||
|
|
||
|
# Toggle these columns on off for Time/CPU usage/Disk I/O tables
|
||
|
self.toggle_columns = {}
|
||
|
|
||
|
def setup_queryset(self, *args, **kwargs):
|
||
|
build = Build.objects.get(pk=kwargs['build_id'])
|
||
|
self.static_context_extra['build'] = build
|
||
|
self.queryset = build.task_build.filter(~Q(order=None))
|
||
|
self.queryset = self.queryset.order_by(self.default_orderby)
|
||
|
|
||
|
def setup_filters(self, *args, **kwargs):
|
||
|
# Execution outcome types filter
|
||
|
executed_outcome = TableFilter(name="execution_outcome",
|
||
|
title="Filter Tasks by 'Executed")
|
||
|
|
||
|
exec_outcome_action_exec = TableFilterActionToggle(
|
||
|
"executed",
|
||
|
"Executed Tasks",
|
||
|
Q(task_executed=True))
|
||
|
|
||
|
exec_outcome_action_not_exec = TableFilterActionToggle(
|
||
|
"not_executed",
|
||
|
"Not Executed Tasks",
|
||
|
Q(task_executed=False))
|
||
|
|
||
|
executed_outcome.add_action(exec_outcome_action_exec)
|
||
|
executed_outcome.add_action(exec_outcome_action_not_exec)
|
||
|
|
||
|
# Task outcome types filter
|
||
|
task_outcome = TableFilter(name="task_outcome",
|
||
|
title="Filter Task by 'Outcome'")
|
||
|
|
||
|
for outcome_enum, title in Task.TASK_OUTCOME:
|
||
|
if outcome_enum is Task.OUTCOME_NA:
|
||
|
continue
|
||
|
action = TableFilterActionToggle(
|
||
|
title.replace(" ", "_").lower(),
|
||
|
"%s Tasks" % title,
|
||
|
Q(outcome=outcome_enum))
|
||
|
|
||
|
task_outcome.add_action(action)
|
||
|
|
||
|
# SSTATE outcome types filter
|
||
|
sstate_outcome = TableFilter(name="sstate_outcome",
|
||
|
title="Filter Task by 'Cache attempt'")
|
||
|
|
||
|
for sstate_result_enum, title in Task.SSTATE_RESULT:
|
||
|
action = TableFilterActionToggle(
|
||
|
title.replace(" ", "_").lower(),
|
||
|
"Tasks with '%s' attempts" % title,
|
||
|
Q(sstate_result=sstate_result_enum))
|
||
|
|
||
|
sstate_outcome.add_action(action)
|
||
|
|
||
|
self.add_filter(sstate_outcome)
|
||
|
self.add_filter(executed_outcome)
|
||
|
self.add_filter(task_outcome)
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
self.toggle_columns['order'] = len(self.columns)
|
||
|
|
||
|
recipe_name_tmpl =\
|
||
|
'<a href="{% url "recipe" extra.build.pk data.recipe.pk %}">'\
|
||
|
'{{data.recipe.name}}'\
|
||
|
'</a>'
|
||
|
|
||
|
def task_link_tmpl(val):
|
||
|
return ('<a name="task-{{data.order}}"'
|
||
|
'href="{%% url "task" extra.build.pk data.pk %%}">'
|
||
|
'%s'
|
||
|
'</a>') % str(val)
|
||
|
|
||
|
self.add_column(title="Order",
|
||
|
static_data_name="order",
|
||
|
static_data_template='{{data.order}}',
|
||
|
hideable=False,
|
||
|
orderable=True)
|
||
|
|
||
|
self.add_column(title="Task",
|
||
|
static_data_name="task_name",
|
||
|
static_data_template=task_link_tmpl(
|
||
|
"{{data.task_name}}"),
|
||
|
hideable=False,
|
||
|
orderable=True)
|
||
|
|
||
|
self.add_column(title="Recipe",
|
||
|
static_data_name='recipe__name',
|
||
|
static_data_template=recipe_name_tmpl,
|
||
|
hideable=False,
|
||
|
orderable=True)
|
||
|
|
||
|
self.add_column(title="Recipe version",
|
||
|
field_name='recipe__version',
|
||
|
hidden=True)
|
||
|
|
||
|
self.add_column(title="Executed",
|
||
|
static_data_name="task_executed",
|
||
|
static_data_template='{{data.get_executed_display}}',
|
||
|
filter_name='execution_outcome',
|
||
|
orderable=True)
|
||
|
|
||
|
self.static_context_extra['OUTCOME_FAILED'] = Task.OUTCOME_FAILED
|
||
|
outcome_tmpl = '{{data.outcome_text}}'
|
||
|
outcome_tmpl = ('%s '
|
||
|
'{%% if data.outcome = extra.OUTCOME_FAILED %%}'
|
||
|
'<a href="{%% url "build_artifact" extra.build.pk '
|
||
|
' "tasklogfile" data.pk %%}">'
|
||
|
' <span class="glyphicon glyphicon-download-alt'
|
||
|
' get-help" title="Download task log file"></span>'
|
||
|
'</a> {%% endif %%}'
|
||
|
'<span class="glyphicon glyphicon-question-sign'
|
||
|
' get-help hover-help" style="visibility: hidden;" '
|
||
|
'title="{{data.get_outcome_help}}"></span>'
|
||
|
) % outcome_tmpl
|
||
|
|
||
|
self.add_column(title="Outcome",
|
||
|
static_data_name="outcome",
|
||
|
static_data_template=outcome_tmpl,
|
||
|
filter_name="task_outcome",
|
||
|
orderable=True)
|
||
|
|
||
|
self.toggle_columns['sstate_result'] = len(self.columns)
|
||
|
|
||
|
self.add_column(title="Cache attempt",
|
||
|
static_data_name="sstate_result",
|
||
|
static_data_template='{{data.sstate_text}}',
|
||
|
filter_name="sstate_outcome",
|
||
|
orderable=True)
|
||
|
|
||
|
self.toggle_columns['elapsed_time'] = len(self.columns)
|
||
|
|
||
|
self.add_column(
|
||
|
title="Time (secs)",
|
||
|
static_data_name="elapsed_time",
|
||
|
static_data_template='{% load projecttags %}{% load humanize %}'
|
||
|
'{{data.elapsed_time|format_none_and_zero|floatformat:2}}',
|
||
|
orderable=True,
|
||
|
hidden=True)
|
||
|
|
||
|
self.toggle_columns['cpu_time_sys'] = len(self.columns)
|
||
|
|
||
|
self.add_column(
|
||
|
title="System CPU time (secs)",
|
||
|
static_data_name="cpu_time_system",
|
||
|
static_data_template='{% load projecttags %}{% load humanize %}'
|
||
|
'{{data.cpu_time_system|format_none_and_zero|floatformat:2}}',
|
||
|
hidden=True,
|
||
|
orderable=True)
|
||
|
|
||
|
self.toggle_columns['cpu_time_user'] = len(self.columns)
|
||
|
|
||
|
self.add_column(
|
||
|
title="User CPU time (secs)",
|
||
|
static_data_name="cpu_time_user",
|
||
|
static_data_template='{% load projecttags %}{% load humanize %}'
|
||
|
'{{data.cpu_time_user|format_none_and_zero|floatformat:2}}',
|
||
|
hidden=True,
|
||
|
orderable=True)
|
||
|
|
||
|
self.toggle_columns['disk_io'] = len(self.columns)
|
||
|
|
||
|
self.add_column(
|
||
|
title="Disk I/O (ms)",
|
||
|
static_data_name="disk_io",
|
||
|
static_data_template='{% load projecttags %}{% load humanize %}'
|
||
|
'{{data.disk_io|format_none_and_zero|filtered_filesizeformat}}',
|
||
|
hidden=True,
|
||
|
orderable=True)
|
||
|
|
||
|
|
||
|
class BuildTimeTable(BuildTasksTable):
|
||
|
""" Same as tasks table but the Time column is default displayed"""
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuildTimeTable, self).__init__(*args, **kwargs)
|
||
|
self.default_orderby = "-elapsed_time"
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
super(BuildTimeTable, self).setup_columns(**kwargs)
|
||
|
|
||
|
self.columns[self.toggle_columns['order']]['hidden'] = True
|
||
|
self.columns[self.toggle_columns['order']]['hideable'] = True
|
||
|
self.columns[self.toggle_columns['sstate_result']]['hidden'] = True
|
||
|
self.columns[self.toggle_columns['elapsed_time']]['hidden'] = False
|
||
|
|
||
|
|
||
|
class BuildCPUTimeTable(BuildTasksTable):
|
||
|
""" Same as tasks table but the CPU usage columns are default displayed"""
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuildCPUTimeTable, self).__init__(*args, **kwargs)
|
||
|
self.default_orderby = "-cpu_time_system"
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
super(BuildCPUTimeTable, self).setup_columns(**kwargs)
|
||
|
|
||
|
self.columns[self.toggle_columns['order']]['hidden'] = True
|
||
|
self.columns[self.toggle_columns['order']]['hideable'] = True
|
||
|
self.columns[self.toggle_columns['sstate_result']]['hidden'] = True
|
||
|
self.columns[self.toggle_columns['cpu_time_sys']]['hidden'] = False
|
||
|
self.columns[self.toggle_columns['cpu_time_user']]['hidden'] = False
|
||
|
|
||
|
|
||
|
class BuildIOTable(BuildTasksTable):
|
||
|
""" Same as tasks table but the Disk IO column is default displayed"""
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super(BuildIOTable, self).__init__(*args, **kwargs)
|
||
|
self.default_orderby = "-disk_io"
|
||
|
|
||
|
def setup_columns(self, *args, **kwargs):
|
||
|
super(BuildIOTable, self).setup_columns(**kwargs)
|
||
|
|
||
|
self.columns[self.toggle_columns['order']]['hidden'] = True
|
||
|
self.columns[self.toggle_columns['order']]['hideable'] = True
|
||
|
self.columns[self.toggle_columns['sstate_result']]['hidden'] = True
|
||
|
self.columns[self.toggle_columns['disk_io']]['hidden'] = False
|