300 lines
9.2 KiB
Python
300 lines
9.2 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) 2013 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 datetime import datetime, timedelta
|
|
from os.path import relpath
|
|
import re
|
|
from django import template
|
|
from django.utils import timezone
|
|
from django.template.defaultfilters import filesizeformat
|
|
import json as JsonLib
|
|
from django.utils.safestring import mark_safe
|
|
|
|
register = template.Library()
|
|
|
|
@register.simple_tag
|
|
def time_difference(start_time, end_time):
|
|
return end_time - start_time
|
|
|
|
@register.filter(name = 'sectohms')
|
|
def sectohms(time):
|
|
try:
|
|
tdsec = int(time)
|
|
except ValueError:
|
|
tdsec = 0
|
|
hours = int(tdsec / 3600)
|
|
return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60)
|
|
|
|
|
|
@register.filter(name = 'get_tasks')
|
|
def get_tasks(queryset):
|
|
return list(target + ':' + task if task else target \
|
|
for target, task in queryset.values_list('target', 'task'))
|
|
|
|
|
|
@register.filter(name = "json")
|
|
def json(value, default = None):
|
|
# JSON spec says that "\/" is functionally identical to "/" to allow for HTML-tag embedding in JSON strings
|
|
# unfortunately, I can't find any option in the json module to turn on forward-slash escaping, so we do
|
|
# it manually here
|
|
return mark_safe(JsonLib.dumps(value, indent=2, default = default, ensure_ascii=False).replace('</', '<\\/'))
|
|
|
|
@register.assignment_tag
|
|
def query(qs, **kwargs):
|
|
""" template tag which allows queryset filtering. Usage:
|
|
{% query books author=author as mybooks %}
|
|
{% for book in mybooks %}
|
|
...
|
|
{% endfor %}
|
|
"""
|
|
return qs.filter(**kwargs)
|
|
|
|
|
|
@register.filter("whitespace_slice")
|
|
def whitespace_space_filter(value, arg):
|
|
try:
|
|
bits = []
|
|
for x in arg.split(":"):
|
|
if len(x) == 0:
|
|
bits.append(None)
|
|
else:
|
|
# convert numeric value to the first whitespace after
|
|
first_whitespace = value.find(" ", int(x))
|
|
if first_whitespace == -1:
|
|
bits.append(int(x))
|
|
else:
|
|
bits.append(first_whitespace)
|
|
return value[slice(*bits)]
|
|
except (ValueError, TypeError):
|
|
raise
|
|
|
|
@register.filter
|
|
def divide(value, arg):
|
|
if int(arg) == 0:
|
|
return -1
|
|
return int(value) // int(arg)
|
|
|
|
@register.filter
|
|
def multiply(value, arg):
|
|
return int(value) * int(arg)
|
|
|
|
@register.assignment_tag
|
|
def datecompute(delta, start = timezone.now()):
|
|
return start + timedelta(delta)
|
|
|
|
|
|
@register.filter(name = 'sortcols')
|
|
def sortcols(tablecols):
|
|
return sorted(tablecols, key = lambda t: t['name'])
|
|
|
|
@register.filter
|
|
def task_color(task_object, show_green=False):
|
|
""" Return css class depending on Task execution status and execution outcome.
|
|
By default, green is not returned for executed and successful tasks;
|
|
show_green argument should be True to get green color.
|
|
"""
|
|
if not task_object.task_executed:
|
|
return 'class=text-muted'
|
|
elif task_object.outcome == task_object.OUTCOME_FAILED:
|
|
return 'class=text-danger'
|
|
elif task_object.outcome == task_object.OUTCOME_SUCCESS and show_green:
|
|
return 'class=text-success'
|
|
else:
|
|
return ''
|
|
|
|
@register.filter
|
|
def filtered_icon(options, filter):
|
|
"""Returns btn-primary if the filter matches one of the filter options
|
|
"""
|
|
for option in options:
|
|
if filter == option[1]:
|
|
return "btn-primary"
|
|
if ('daterange' == option[1]) and filter.startswith(option[4]):
|
|
return "btn-primary"
|
|
return ""
|
|
|
|
@register.filter
|
|
def filtered_tooltip(options, filter):
|
|
"""Returns tooltip for the filter icon if the filter matches one of the filter options
|
|
"""
|
|
for option in options:
|
|
if filter == option[1]:
|
|
return "Showing only %s"%option[0]
|
|
if ('daterange' == option[1]) and filter.startswith(option[4]):
|
|
return "Showing only %s"%option[0]
|
|
return ""
|
|
|
|
@register.filter
|
|
def format_none_and_zero(value):
|
|
"""Return empty string if the value is None, zero or Not Applicable
|
|
"""
|
|
return "" if (not value) or (value == 0) or (value == "0") or (value == 'Not Applicable') else value
|
|
|
|
@register.filter
|
|
def filtered_filesizeformat(value):
|
|
"""
|
|
If the value is -1 return an empty string. Otherwise,
|
|
change output from fileformatsize to suppress trailing '.0'
|
|
and change 'bytes' to 'B'.
|
|
"""
|
|
if value == -1:
|
|
return ''
|
|
|
|
return filesizeformat(value).replace("bytes", "B")
|
|
|
|
@register.filter
|
|
def filtered_packagespec(value):
|
|
"""Strip off empty version and revision"""
|
|
return re.sub(r'(--$)', '', value)
|
|
|
|
@register.filter
|
|
def check_filter_status(options, filter):
|
|
"""Check if the active filter is among the available options, and return 'checked'
|
|
if filter is not active.
|
|
Used in FilterDialog to select the first radio button if the filter is not active.
|
|
"""
|
|
for option in options:
|
|
if filter == option[1]:
|
|
return ""
|
|
return "checked"
|
|
|
|
@register.filter
|
|
def variable_parent_name(value):
|
|
""" filter extended variable names to the parent name
|
|
"""
|
|
value=re.sub('_\$.*', '', value)
|
|
return re.sub('_[a-z].*', '', value)
|
|
|
|
@register.filter
|
|
def filter_setin_files(file_list, matchstr):
|
|
"""Filter/search the 'set in' file lists."""
|
|
result = []
|
|
search, filter = matchstr.split(':')
|
|
for pattern in (search, filter):
|
|
if pattern:
|
|
for fobj in file_list:
|
|
fname = fobj.file_name
|
|
if fname not in result and re.search(pattern, fname):
|
|
result.append(fname)
|
|
|
|
# no filter, show last file (if any)
|
|
last = list(file_list)[-1].file_name
|
|
if not filter and last not in result:
|
|
result.append(last)
|
|
|
|
return result
|
|
|
|
@register.filter
|
|
def string_slice(strvar,slicevar):
|
|
""" slice a string with |string_slice:'[first]:[last]'
|
|
"""
|
|
first,last= slicevar.partition(':')[::2]
|
|
if first=='':
|
|
return strvar[:int(last)]
|
|
elif last=='':
|
|
return strvar[int(first):]
|
|
else:
|
|
return strvar[int(first):int(last)]
|
|
|
|
@register.filter
|
|
def string_remove_regex(value,ex):
|
|
""" remove sub-string of string that matches regex
|
|
"""
|
|
return re.sub(ex, '', value)
|
|
|
|
@register.filter
|
|
def filtered_installedsize(size, installed_size):
|
|
"""If package.installed_size not null and not empty return it,
|
|
else return package.size
|
|
"""
|
|
return size if (installed_size == 0) or (installed_size == "") or (installed_size == None) else installed_size
|
|
|
|
@register.filter
|
|
def filtered_packageversion(version, revision):
|
|
""" Emit "version-revision" if version and revision are not null
|
|
else "version" if version is not null
|
|
else ""
|
|
"""
|
|
return "" if (not version or version == "") else version if (not revision or revision == "") else version + "-" + revision
|
|
|
|
@register.filter
|
|
def filter_sizeovertotal(package_object, total_size):
|
|
""" Return the % size of the package over the total size argument
|
|
formatted nicely.
|
|
"""
|
|
size = package_object.installed_size
|
|
if size == None or size == '':
|
|
size = package_object.size
|
|
|
|
return '{:.1%}'.format(float(size)/float(total_size))
|
|
|
|
from django.utils.safestring import mark_safe
|
|
@register.filter
|
|
def format_vpackage_rowclass(size):
|
|
if size == -1:
|
|
return mark_safe('class="text-muted"')
|
|
return ''
|
|
|
|
@register.filter
|
|
def format_vpackage_namehelp(name):
|
|
r = name + ' '
|
|
r += '<span class="glyphicon glyphicon-question-sign get-help hover-help"'
|
|
r += ' title = "' + name + ' has not been built">'
|
|
r += '</span>'
|
|
return mark_safe(r)
|
|
|
|
@register.filter
|
|
def get_dict_value(dictionary, key):
|
|
""" return the value of a dictionary key
|
|
"""
|
|
try:
|
|
return dictionary[key]
|
|
except (KeyError, IndexError):
|
|
return ''
|
|
|
|
@register.filter
|
|
def is_shaid(text):
|
|
""" return True if text length is 40 characters and all hex-digits
|
|
"""
|
|
try:
|
|
int(text, 16)
|
|
if len(text) == 40:
|
|
return True
|
|
return False
|
|
except ValueError:
|
|
return False
|
|
|
|
@register.filter
|
|
def cut_path_prefix(fullpath, prefixes):
|
|
"""Cut path prefix from fullpath."""
|
|
for prefix in prefixes:
|
|
if fullpath.startswith(prefix):
|
|
return relpath(fullpath, prefix)
|
|
return fullpath
|
|
|
|
|
|
@register.filter
|
|
def for_target(package_dependencies, target):
|
|
""" filter the dependencies to be displayed by the supplied target
|
|
if no dependences are found for the target then return the predicted
|
|
dependences"""
|
|
return package_dependencies.for_target_or_none(target)
|