blob: bd398f00124b8d581740fb7cb3f6723739c11b90 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002# BitBake Toaster Implementation
3#
4# Copyright (C) 2013 Intel Corporation
5#
Brad Bishopc342db32019-05-15 21:57:59 -04006# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05008
Andrew Geissler82c905d2020-04-13 13:39:40 -05009from datetime import timedelta
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010from os.path import relpath
11import re
12from django import template
13from django.utils import timezone
14from django.template.defaultfilters import filesizeformat
15import json as JsonLib
16from django.utils.safestring import mark_safe
17
18register = template.Library()
19
20@register.simple_tag
21def time_difference(start_time, end_time):
22 return end_time - start_time
23
24@register.filter(name = 'sectohms')
25def sectohms(time):
26 try:
27 tdsec = int(time)
28 except ValueError:
29 tdsec = 0
30 hours = int(tdsec / 3600)
31 return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60)
32
33
34@register.filter(name = 'get_tasks')
35def get_tasks(queryset):
36 return list(target + ':' + task if task else target \
37 for target, task in queryset.values_list('target', 'task'))
38
39
40@register.filter(name = "json")
41def json(value, default = None):
42 # JSON spec says that "\/" is functionally identical to "/" to allow for HTML-tag embedding in JSON strings
43 # unfortunately, I can't find any option in the json module to turn on forward-slash escaping, so we do
44 # it manually here
45 return mark_safe(JsonLib.dumps(value, indent=2, default = default, ensure_ascii=False).replace('</', '<\\/'))
46
Andrew Geissler82c905d2020-04-13 13:39:40 -050047@register.simple_tag
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048def query(qs, **kwargs):
49 """ template tag which allows queryset filtering. Usage:
50 {% query books author=author as mybooks %}
51 {% for book in mybooks %}
52 ...
53 {% endfor %}
54 """
55 return qs.filter(**kwargs)
56
57
58@register.filter("whitespace_slice")
59def whitespace_space_filter(value, arg):
60 try:
61 bits = []
62 for x in arg.split(":"):
63 if len(x) == 0:
64 bits.append(None)
65 else:
66 # convert numeric value to the first whitespace after
67 first_whitespace = value.find(" ", int(x))
68 if first_whitespace == -1:
69 bits.append(int(x))
70 else:
71 bits.append(first_whitespace)
72 return value[slice(*bits)]
73 except (ValueError, TypeError):
74 raise
75
76@register.filter
77def divide(value, arg):
78 if int(arg) == 0:
79 return -1
Patrick Williamsc0f7c042017-02-23 20:41:17 -060080 return int(value) // int(arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050081
82@register.filter
83def multiply(value, arg):
84 return int(value) * int(arg)
85
Andrew Geissler82c905d2020-04-13 13:39:40 -050086@register.simple_tag
Patrick Williamsc124f4f2015-09-15 14:41:29 -050087def datecompute(delta, start = timezone.now()):
88 return start + timedelta(delta)
89
90
91@register.filter(name = 'sortcols')
92def sortcols(tablecols):
93 return sorted(tablecols, key = lambda t: t['name'])
94
95@register.filter
96def task_color(task_object, show_green=False):
97 """ Return css class depending on Task execution status and execution outcome.
98 By default, green is not returned for executed and successful tasks;
99 show_green argument should be True to get green color.
100 """
101 if not task_object.task_executed:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600102 return 'class=text-muted'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500103 elif task_object.outcome == task_object.OUTCOME_FAILED:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104 return 'class=text-danger'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500105 elif task_object.outcome == task_object.OUTCOME_SUCCESS and show_green:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600106 return 'class=text-success'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107 else:
108 return ''
109
110@register.filter
111def filtered_icon(options, filter):
112 """Returns btn-primary if the filter matches one of the filter options
113 """
114 for option in options:
115 if filter == option[1]:
116 return "btn-primary"
117 if ('daterange' == option[1]) and filter.startswith(option[4]):
118 return "btn-primary"
119 return ""
120
121@register.filter
122def filtered_tooltip(options, filter):
123 """Returns tooltip for the filter icon if the filter matches one of the filter options
124 """
125 for option in options:
126 if filter == option[1]:
127 return "Showing only %s"%option[0]
128 if ('daterange' == option[1]) and filter.startswith(option[4]):
129 return "Showing only %s"%option[0]
130 return ""
131
132@register.filter
133def format_none_and_zero(value):
134 """Return empty string if the value is None, zero or Not Applicable
135 """
136 return "" if (not value) or (value == 0) or (value == "0") or (value == 'Not Applicable') else value
137
138@register.filter
139def filtered_filesizeformat(value):
140 """
141 If the value is -1 return an empty string. Otherwise,
142 change output from fileformatsize to suppress trailing '.0'
143 and change 'bytes' to 'B'.
144 """
145 if value == -1:
146 return ''
147
148 return filesizeformat(value).replace("bytes", "B")
149
150@register.filter
151def filtered_packagespec(value):
152 """Strip off empty version and revision"""
153 return re.sub(r'(--$)', '', value)
154
155@register.filter
156def check_filter_status(options, filter):
157 """Check if the active filter is among the available options, and return 'checked'
158 if filter is not active.
159 Used in FilterDialog to select the first radio button if the filter is not active.
160 """
161 for option in options:
162 if filter == option[1]:
163 return ""
164 return "checked"
165
166@register.filter
167def variable_parent_name(value):
168 """ filter extended variable names to the parent name
169 """
Patrick Williams169d7bc2024-01-05 11:33:25 -0600170 value = re.sub(r'_\$.*', '', value)
171 return re.sub(r'_[a-z].*', '', value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172
173@register.filter
174def filter_setin_files(file_list, matchstr):
175 """Filter/search the 'set in' file lists."""
176 result = []
177 search, filter = matchstr.split(':')
178 for pattern in (search, filter):
179 if pattern:
180 for fobj in file_list:
181 fname = fobj.file_name
182 if fname not in result and re.search(pattern, fname):
183 result.append(fname)
184
185 # no filter, show last file (if any)
186 last = list(file_list)[-1].file_name
187 if not filter and last not in result:
188 result.append(last)
189
190 return result
191
192@register.filter
193def string_slice(strvar,slicevar):
194 """ slice a string with |string_slice:'[first]:[last]'
195 """
196 first,last= slicevar.partition(':')[::2]
197 if first=='':
198 return strvar[:int(last)]
199 elif last=='':
200 return strvar[int(first):]
201 else:
202 return strvar[int(first):int(last)]
203
204@register.filter
205def string_remove_regex(value,ex):
206 """ remove sub-string of string that matches regex
207 """
208 return re.sub(ex, '', value)
209
210@register.filter
211def filtered_installedsize(size, installed_size):
212 """If package.installed_size not null and not empty return it,
213 else return package.size
214 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500215 return size if (installed_size == 0) or (installed_size == "") or (installed_size is None) else installed_size
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500216
217@register.filter
218def filtered_packageversion(version, revision):
219 """ Emit "version-revision" if version and revision are not null
220 else "version" if version is not null
221 else ""
222 """
223 return "" if (not version or version == "") else version if (not revision or revision == "") else version + "-" + revision
224
225@register.filter
226def filter_sizeovertotal(package_object, total_size):
227 """ Return the % size of the package over the total size argument
228 formatted nicely.
229 """
230 size = package_object.installed_size
Andrew Geissler82c905d2020-04-13 13:39:40 -0500231 if size is None or size == '':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232 size = package_object.size
233
234 return '{:.1%}'.format(float(size)/float(total_size))
235
236from django.utils.safestring import mark_safe
237@register.filter
238def format_vpackage_rowclass(size):
239 if size == -1:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600240 return mark_safe('class="text-muted"')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500241 return ''
242
243@register.filter
244def format_vpackage_namehelp(name):
245 r = name + '&nbsp;'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600246 r += '<span class="glyphicon glyphicon-question-sign get-help hover-help"'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500247 r += ' title = "' + name + ' has not been built">'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600248 r += '</span>'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500249 return mark_safe(r)
250
251@register.filter
252def get_dict_value(dictionary, key):
253 """ return the value of a dictionary key
254 """
255 try:
256 return dictionary[key]
257 except (KeyError, IndexError):
258 return ''
259
260@register.filter
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261def is_shaid(text):
262 """ return True if text length is 40 characters and all hex-digits
263 """
264 try:
265 int(text, 16)
266 if len(text) == 40:
267 return True
268 return False
269 except ValueError:
270 return False
271
272@register.filter
273def cut_path_prefix(fullpath, prefixes):
274 """Cut path prefix from fullpath."""
275 for prefix in prefixes:
276 if fullpath.startswith(prefix):
277 return relpath(fullpath, prefix)
278 return fullpath
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600279
280
281@register.filter
282def for_target(package_dependencies, target):
283 """ filter the dependencies to be displayed by the supplied target
284 if no dependences are found for the target then return the predicted
285 dependences"""
286 return package_dependencies.for_target_or_none(target)