blob: 75f2261be8cf1b2d318f6536577b971229e81f4f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
7# Copyright (C) 2013 Intel Corporation
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22from datetime import datetime, timedelta
23from os.path import relpath
24import re
25from django import template
26from django.utils import timezone
27from django.template.defaultfilters import filesizeformat
28import json as JsonLib
29from django.utils.safestring import mark_safe
30
31register = template.Library()
32
33@register.simple_tag
34def time_difference(start_time, end_time):
35 return end_time - start_time
36
37@register.filter(name = 'sectohms')
38def sectohms(time):
39 try:
40 tdsec = int(time)
41 except ValueError:
42 tdsec = 0
43 hours = int(tdsec / 3600)
44 return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60)
45
46
47@register.filter(name = 'get_tasks')
48def get_tasks(queryset):
49 return list(target + ':' + task if task else target \
50 for target, task in queryset.values_list('target', 'task'))
51
52
53@register.filter(name = "json")
54def json(value, default = None):
55 # JSON spec says that "\/" is functionally identical to "/" to allow for HTML-tag embedding in JSON strings
56 # unfortunately, I can't find any option in the json module to turn on forward-slash escaping, so we do
57 # it manually here
58 return mark_safe(JsonLib.dumps(value, indent=2, default = default, ensure_ascii=False).replace('</', '<\\/'))
59
60@register.assignment_tag
61def query(qs, **kwargs):
62 """ template tag which allows queryset filtering. Usage:
63 {% query books author=author as mybooks %}
64 {% for book in mybooks %}
65 ...
66 {% endfor %}
67 """
68 return qs.filter(**kwargs)
69
70
71@register.filter("whitespace_slice")
72def whitespace_space_filter(value, arg):
73 try:
74 bits = []
75 for x in arg.split(":"):
76 if len(x) == 0:
77 bits.append(None)
78 else:
79 # convert numeric value to the first whitespace after
80 first_whitespace = value.find(" ", int(x))
81 if first_whitespace == -1:
82 bits.append(int(x))
83 else:
84 bits.append(first_whitespace)
85 return value[slice(*bits)]
86 except (ValueError, TypeError):
87 raise
88
89@register.filter
90def divide(value, arg):
91 if int(arg) == 0:
92 return -1
93 return int(value) / int(arg)
94
95@register.filter
96def multiply(value, arg):
97 return int(value) * int(arg)
98
99@register.assignment_tag
100def datecompute(delta, start = timezone.now()):
101 return start + timedelta(delta)
102
103
104@register.filter(name = 'sortcols')
105def sortcols(tablecols):
106 return sorted(tablecols, key = lambda t: t['name'])
107
108@register.filter
109def task_color(task_object, show_green=False):
110 """ Return css class depending on Task execution status and execution outcome.
111 By default, green is not returned for executed and successful tasks;
112 show_green argument should be True to get green color.
113 """
114 if not task_object.task_executed:
115 return 'class=muted'
116 elif task_object.outcome == task_object.OUTCOME_FAILED:
117 return 'class=error'
118 elif task_object.outcome == task_object.OUTCOME_SUCCESS and show_green:
119 return 'class=green'
120 else:
121 return ''
122
123@register.filter
124def filtered_icon(options, filter):
125 """Returns btn-primary if the filter matches one of the filter options
126 """
127 for option in options:
128 if filter == option[1]:
129 return "btn-primary"
130 if ('daterange' == option[1]) and filter.startswith(option[4]):
131 return "btn-primary"
132 return ""
133
134@register.filter
135def filtered_tooltip(options, filter):
136 """Returns tooltip for the filter icon if the filter matches one of the filter options
137 """
138 for option in options:
139 if filter == option[1]:
140 return "Showing only %s"%option[0]
141 if ('daterange' == option[1]) and filter.startswith(option[4]):
142 return "Showing only %s"%option[0]
143 return ""
144
145@register.filter
146def format_none_and_zero(value):
147 """Return empty string if the value is None, zero or Not Applicable
148 """
149 return "" if (not value) or (value == 0) or (value == "0") or (value == 'Not Applicable') else value
150
151@register.filter
152def filtered_filesizeformat(value):
153 """
154 If the value is -1 return an empty string. Otherwise,
155 change output from fileformatsize to suppress trailing '.0'
156 and change 'bytes' to 'B'.
157 """
158 if value == -1:
159 return ''
160
161 return filesizeformat(value).replace("bytes", "B")
162
163@register.filter
164def filtered_packagespec(value):
165 """Strip off empty version and revision"""
166 return re.sub(r'(--$)', '', value)
167
168@register.filter
169def check_filter_status(options, filter):
170 """Check if the active filter is among the available options, and return 'checked'
171 if filter is not active.
172 Used in FilterDialog to select the first radio button if the filter is not active.
173 """
174 for option in options:
175 if filter == option[1]:
176 return ""
177 return "checked"
178
179@register.filter
180def variable_parent_name(value):
181 """ filter extended variable names to the parent name
182 """
183 value=re.sub('_\$.*', '', value)
184 return re.sub('_[a-z].*', '', value)
185
186@register.filter
187def filter_setin_files(file_list, matchstr):
188 """Filter/search the 'set in' file lists."""
189 result = []
190 search, filter = matchstr.split(':')
191 for pattern in (search, filter):
192 if pattern:
193 for fobj in file_list:
194 fname = fobj.file_name
195 if fname not in result and re.search(pattern, fname):
196 result.append(fname)
197
198 # no filter, show last file (if any)
199 last = list(file_list)[-1].file_name
200 if not filter and last not in result:
201 result.append(last)
202
203 return result
204
205@register.filter
206def string_slice(strvar,slicevar):
207 """ slice a string with |string_slice:'[first]:[last]'
208 """
209 first,last= slicevar.partition(':')[::2]
210 if first=='':
211 return strvar[:int(last)]
212 elif last=='':
213 return strvar[int(first):]
214 else:
215 return strvar[int(first):int(last)]
216
217@register.filter
218def string_remove_regex(value,ex):
219 """ remove sub-string of string that matches regex
220 """
221 return re.sub(ex, '', value)
222
223@register.filter
224def filtered_installedsize(size, installed_size):
225 """If package.installed_size not null and not empty return it,
226 else return package.size
227 """
228 return size if (installed_size == 0) or (installed_size == "") or (installed_size == None) else installed_size
229
230@register.filter
231def filtered_packageversion(version, revision):
232 """ Emit "version-revision" if version and revision are not null
233 else "version" if version is not null
234 else ""
235 """
236 return "" if (not version or version == "") else version if (not revision or revision == "") else version + "-" + revision
237
238@register.filter
239def filter_sizeovertotal(package_object, total_size):
240 """ Return the % size of the package over the total size argument
241 formatted nicely.
242 """
243 size = package_object.installed_size
244 if size == None or size == '':
245 size = package_object.size
246
247 return '{:.1%}'.format(float(size)/float(total_size))
248
249from django.utils.safestring import mark_safe
250@register.filter
251def format_vpackage_rowclass(size):
252 if size == -1:
253 return mark_safe('class="muted"')
254 return ''
255
256@register.filter
257def format_vpackage_namehelp(name):
258 r = name + '&nbsp;'
259 r += '<i class="icon-question-sign get-help hover-help"'
260 r += ' title = "' + name + ' has not been built">'
261 r += '</i>'
262 return mark_safe(r)
263
264@register.filter
265def get_dict_value(dictionary, key):
266 """ return the value of a dictionary key
267 """
268 try:
269 return dictionary[key]
270 except (KeyError, IndexError):
271 return ''
272
273@register.filter
274def format_build_date(completed_on):
275 now = timezone.now()
276 delta = now - completed_on
277
278 if delta.days >= 1:
279 return True
280
281@register.filter
282def is_shaid(text):
283 """ return True if text length is 40 characters and all hex-digits
284 """
285 try:
286 int(text, 16)
287 if len(text) == 40:
288 return True
289 return False
290 except ValueError:
291 return False
292
293@register.filter
294def cut_path_prefix(fullpath, prefixes):
295 """Cut path prefix from fullpath."""
296 for prefix in prefixes:
297 if fullpath.startswith(prefix):
298 return relpath(fullpath, prefix)
299 return fullpath