projecttags.py 8.5 KB

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