summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/toastergui/views.py')
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py103
1 files changed, 66 insertions, 37 deletions
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index e718ced570..6ccbf5452d 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -22,7 +22,7 @@
22import operator,re 22import operator,re
23import HTMLParser 23import HTMLParser
24 24
25from django.db.models import Q, Sum 25from django.db.models import Q, Sum, Count
26from django.db import IntegrityError 26from django.db import IntegrityError
27from django.shortcuts import render, redirect 27from django.shortcuts import render, redirect
28from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable 28from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
@@ -117,7 +117,8 @@ def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs):
117 return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs) 117 return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs)
118 118
119FIELD_SEPARATOR = ":" 119FIELD_SEPARATOR = ":"
120VALUE_SEPARATOR = "!" 120AND_VALUE_SEPARATOR = "!"
121OR_VALUE_SEPARATOR = "|"
121DESCENDING = "-" 122DESCENDING = "-"
122 123
123def __get_q_for_val(name, value): 124def __get_q_for_val(name, value):
@@ -126,20 +127,31 @@ def __get_q_for_val(name, value):
126 if "AND" in value: 127 if "AND" in value:
127 return reduce(operator.and_, map(lambda x: __get_q_for_val(name, x), [ x for x in value.split("AND") ])) 128 return reduce(operator.and_, map(lambda x: __get_q_for_val(name, x), [ x for x in value.split("AND") ]))
128 if value.startswith("NOT"): 129 if value.startswith("NOT"):
129 kwargs = { name : value.strip("NOT") } 130 value = value[3:]
131 if value == 'None':
132 value = None
133 kwargs = { name : value }
130 return ~Q(**kwargs) 134 return ~Q(**kwargs)
131 else: 135 else:
136 if value == 'None':
137 value = None
132 kwargs = { name : value } 138 kwargs = { name : value }
133 return Q(**kwargs) 139 return Q(**kwargs)
134 140
135def _get_filtering_query(filter_string): 141def _get_filtering_query(filter_string):
136 142
137 search_terms = filter_string.split(FIELD_SEPARATOR) 143 search_terms = filter_string.split(FIELD_SEPARATOR)
138 keys = search_terms[0].split(VALUE_SEPARATOR) 144 and_keys = search_terms[0].split(AND_VALUE_SEPARATOR)
139 values = search_terms[1].split(VALUE_SEPARATOR) 145 and_values = search_terms[1].split(AND_VALUE_SEPARATOR)
146
147 and_query = []
148 for kv in zip(and_keys, and_values):
149 or_keys = kv[0].split(OR_VALUE_SEPARATOR)
150 or_values = kv[1].split(OR_VALUE_SEPARATOR)
151 querydict = dict(zip(or_keys, or_values))
152 and_query.append(reduce(operator.or_, map(lambda x: __get_q_for_val(x, querydict[x]), [k for k in querydict])))
140 153
141 querydict = dict(zip(keys, values)) 154 return reduce(operator.and_, [k for k in and_query])
142 return reduce(operator.and_, map(lambda x: __get_q_for_val(x, querydict[x]), [k for k in querydict]))
143 155
144def _get_toggle_order(request, orderkey, reverse = False): 156def _get_toggle_order(request, orderkey, reverse = False):
145 if reverse: 157 if reverse:
@@ -169,13 +181,13 @@ def _validate_input(input, model):
169 return None, invalid 181 return None, invalid
170 182
171 # Check we have an equal number of terms both sides of the colon 183 # Check we have an equal number of terms both sides of the colon
172 if len(input_list[0].split(VALUE_SEPARATOR)) != len(input_list[1].split(VALUE_SEPARATOR)): 184 if len(input_list[0].split(AND_VALUE_SEPARATOR)) != len(input_list[1].split(AND_VALUE_SEPARATOR)):
173 invalid = "Not all arg names got values" 185 invalid = "Not all arg names got values"
174 return None, invalid + str(input_list) 186 return None, invalid + str(input_list)
175 187
176 # Check we are looking for a valid field 188 # Check we are looking for a valid field
177 valid_fields = model._meta.get_all_field_names() 189 valid_fields = model._meta.get_all_field_names()
178 for field in input_list[0].split(VALUE_SEPARATOR): 190 for field in input_list[0].split(AND_VALUE_SEPARATOR):
179 if not reduce(lambda x, y: x or y, map(lambda x: field.startswith(x), [ x for x in valid_fields ])): 191 if not reduce(lambda x, y: x or y, map(lambda x: field.startswith(x), [ x for x in valid_fields ])):
180 return None, (field, [ x for x in valid_fields ]) 192 return None, (field, [ x for x in valid_fields ])
181 193
@@ -216,6 +228,7 @@ def _search_tuple(request, model):
216def _get_queryset(model, queryset, filter_string, search_term, ordering_string, ordering_secondary=''): 228def _get_queryset(model, queryset, filter_string, search_term, ordering_string, ordering_secondary=''):
217 if filter_string: 229 if filter_string:
218 filter_query = _get_filtering_query(filter_string) 230 filter_query = _get_filtering_query(filter_string)
231# raise Exception(filter_query)
219 queryset = queryset.filter(filter_query) 232 queryset = queryset.filter(filter_query)
220 else: 233 else:
221 queryset = queryset.all() 234 queryset = queryset.all()
@@ -1780,12 +1793,13 @@ if toastermain.settings.MANAGED:
1780 # for that object type. copypasta for all needed table searches 1793 # for that object type. copypasta for all needed table searches
1781 (filter_string, search_term, ordering_string) = _search_tuple(request, BuildRequest) 1794 (filter_string, search_term, ordering_string) = _search_tuple(request, BuildRequest)
1782 # we don't display in-progress or deleted builds 1795 # we don't display in-progress or deleted builds
1783 queryset_all = buildrequests 1796 queryset_all = buildrequests.exclude(state = BuildRequest.REQ_DELETED)
1784 queryset_with_search = _get_queryset(BuildRequest, queryset_all, None, search_term, ordering_string, '-updated') 1797 queryset_all = queryset_all.annotate(Count('brerror'))
1785 queryset = _get_queryset(BuildRequest, queryset_all, filter_string, search_term, ordering_string, '-updated') 1798 queryset_with_search = _get_queryset(BuildRequest, queryset_all, filter_string, search_term, ordering_string, '-updated')
1799
1786 1800
1787 # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display 1801 # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display
1788 build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) 1802 build_info = _build_page_range(Paginator(queryset_with_search, pagesize), request.GET.get('page', 1))
1789 1803
1790 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) 1804 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
1791 # most recent build is like projects' most recent builds, but across all projects 1805 # most recent build is like projects' most recent builds, but across all projects
@@ -1842,8 +1856,8 @@ if toastermain.settings.MANAGED:
1842 'filter' : {'class' : 'outcome', 1856 'filter' : {'class' : 'outcome',
1843 'label': 'Show:', 1857 'label': 'Show:',
1844 'options' : [ 1858 'options' : [
1845 ('Successful builds', 'state:' + str(BuildRequest.REQ_COMPLETED), queryset_with_search.filter(state=str(BuildRequest.REQ_COMPLETED)).count()), # this is the field search expression 1859 ('Successful builds', 'state:' + str(BuildRequest.REQ_COMPLETED), queryset_all.filter(state=str(BuildRequest.REQ_COMPLETED)).count()), # this is the field search expression
1846 ('Failed builds', 'state:'+ str(BuildRequest.REQ_FAILED), queryset_with_search.filter(state=str(BuildRequest.REQ_FAILED)).count()), 1860 ('Failed builds', 'state:'+ str(BuildRequest.REQ_FAILED), queryset_all.filter(state=str(BuildRequest.REQ_FAILED)).count()),
1847 ] 1861 ]
1848 } 1862 }
1849 }, 1863 },
@@ -1865,9 +1879,9 @@ if toastermain.settings.MANAGED:
1865 'filter' : {'class' : 'created', 1879 'filter' : {'class' : 'created',
1866 'label': 'Show:', 1880 'label': 'Show:',
1867 'options' : [ 1881 'options' : [
1868 ("Today's builds" , 'created__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_with_search.filter(created__gte=timezone.now()).count()), 1882 ("Today's builds" , 'created__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_all.filter(created__gte=timezone.now()).count()),
1869 ("Yesterday's builds", 'created__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_with_search.filter(created__gte=(timezone.now()-timedelta(hours=24))).count()), 1883 ("Yesterday's builds", 'created__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_all.filter(created__gte=(timezone.now()-timedelta(hours=24))).count()),
1870 ("This week's builds", 'created__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_with_search.filter(created__gte=(timezone.now()-timedelta(days=7))).count()), 1884 ("This week's builds", 'created__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_all.filter(created__gte=(timezone.now()-timedelta(days=7))).count()),
1871 ] 1885 ]
1872 } 1886 }
1873 }, 1887 },
@@ -1879,9 +1893,9 @@ if toastermain.settings.MANAGED:
1879 'filter' : {'class' : 'updated', 1893 'filter' : {'class' : 'updated',
1880 'label': 'Show:', 1894 'label': 'Show:',
1881 'options' : [ 1895 'options' : [
1882 ("Today's builds", 'updated__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_with_search.filter(updated__gte=timezone.now()).count()), 1896 ("Today's builds", 'updated__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=timezone.now()).count()),
1883 ("Yesterday's builds", 'updated__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_with_search.filter(updated__gte=(timezone.now()-timedelta(hours=24))).count()), 1897 ("Yesterday's builds", 'updated__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=(timezone.now()-timedelta(hours=24))).count()),
1884 ("This week's builds", 'updated__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_with_search.filter(updated__gte=(timezone.now()-timedelta(days=7))).count()), 1898 ("This week's builds", 'updated__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=(timezone.now()-timedelta(days=7))).count()),
1885 ] 1899 ]
1886 } 1900 }
1887 }, 1901 },
@@ -1890,8 +1904,10 @@ if toastermain.settings.MANAGED:
1890 'filter' : {'class' : 'failed_tasks', 1904 'filter' : {'class' : 'failed_tasks',
1891 'label': 'Show:', 1905 'label': 'Show:',
1892 'options' : [ 1906 'options' : [
1893 ('Build with failed tasks', 'build__task_build__outcome:4', queryset_with_search.filter(build__task_build__outcome=4).count()), 1907 ('Builds with failed tasks', 'build__task_build__outcome:%d' % Task.OUTCOME_FAILED,
1894 ('Build without failed tasks', 'build__task_build__outcome:NOT4', queryset_with_search.filter(~Q(build__task_build__outcome=4)).count()), 1908 queryset_all.filter(build__task_build__outcome=Task.OUTCOME_FAILED).count()),
1909 ('Builds without failed tasks', 'build__task_build__outcome:%d' % Task.OUTCOME_FAILED,
1910 queryset_all.filter(~Q(build__task_build__outcome=Task.OUTCOME_FAILED)).count()),
1895 ] 1911 ]
1896 } 1912 }
1897 }, 1913 },
@@ -1903,8 +1919,10 @@ if toastermain.settings.MANAGED:
1903 'filter' : {'class' : 'errors_no', 1919 'filter' : {'class' : 'errors_no',
1904 'label': 'Show:', 1920 'label': 'Show:',
1905 'options' : [ 1921 'options' : [
1906 ('Build with errors', 'build__errors_no__gte:1', queryset_with_search.filter(build__errors_no__gte=1).count()), 1922 ('Builds with errors', 'build|build__errors_no__gt:None|0',
1907 ('Build without errors', 'build__errors_no:0', queryset_with_search.filter(build__errors_no=0).count()), 1923 queryset_all.filter(Q(build=None) | Q(build__errors_no__gt=0)).count()),
1924 ('Builds without errors', 'build__errors_no:0',
1925 queryset_all.filter(build__errors_no=0).count()),
1908 ] 1926 ]
1909 } 1927 }
1910 }, 1928 },
@@ -1916,8 +1934,8 @@ if toastermain.settings.MANAGED:
1916 'filter' : {'class' : 'build__warnings_no', 1934 'filter' : {'class' : 'build__warnings_no',
1917 'label': 'Show:', 1935 'label': 'Show:',
1918 'options' : [ 1936 'options' : [
1919 ('Build with warnings','build__warnings_no__gte:1', queryset_with_search.filter(build__warnings_no__gte=1).count()), 1937 ('Builds with warnings','build__warnings_no__gte:1', queryset_all.filter(build__warnings_no__gte=1).count()),
1920 ('Build without warnings','build__warnings_no:0', queryset_with_search.filter(build__warnings_no=0).count()), 1938 ('Builds without warnings','build__warnings_no:0', queryset_all.filter(build__warnings_no=0).count()),
1921 ] 1939 ]
1922 } 1940 }
1923 }, 1941 },
@@ -2016,7 +2034,7 @@ if toastermain.settings.MANAGED:
2016 2034
2017 context = { 2035 context = {
2018 "project" : prj, 2036 "project" : prj,
2019 "completedbuilds": Build.objects.filter(project = prj).exclude(outcome = Build.IN_PROGRESS), 2037 "completedbuilds": BuildRequest.objects.filter(project_id = pid).exclude(state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED),
2020 "prj" : {"name": prj.name, "release": { "id": prj.release.pk, "name": prj.release.name, "desc": prj.release.description}}, 2038 "prj" : {"name": prj.name, "release": { "id": prj.release.pk, "name": prj.release.name, "desc": prj.release.description}},
2021 #"buildrequests" : prj.buildrequest_set.filter(state=BuildRequest.REQ_QUEUED), 2039 #"buildrequests" : prj.buildrequest_set.filter(state=BuildRequest.REQ_QUEUED),
2022 "builds" : _project_recent_build_list(prj), 2040 "builds" : _project_recent_build_list(prj),
@@ -2061,7 +2079,7 @@ if toastermain.settings.MANAGED:
2061 try: 2079 try:
2062 if request.method != "POST": 2080 if request.method != "POST":
2063 raise BadParameterException("invalid method") 2081 raise BadParameterException("invalid method")
2064 request.session['project_id'] = pid 2082 request.session['project_id'] = pid
2065 prj = Project.objects.get(id = pid) 2083 prj = Project.objects.get(id = pid)
2066 2084
2067 2085
@@ -2167,11 +2185,11 @@ if toastermain.settings.MANAGED:
2167 try: 2185 try:
2168 prj = None 2186 prj = None
2169 if request.GET.has_key('project_id'): 2187 if request.GET.has_key('project_id'):
2170 prj = Project.objects.get(pk = request.GET['project_id']) 2188 prj = Project.objects.get(pk = request.GET['project_id'])
2171 elif 'project_id' in request.session: 2189 elif 'project_id' in request.session:
2172 prj = Project.objects.get(pk = request.session['project_id']) 2190 prj = Project.objects.get(pk = request.session['project_id'])
2173 else: 2191 else:
2174 raise Exception("No valid project selected") 2192 raise Exception("No valid project selected")
2175 2193
2176 2194
2177 def _lv_to_dict(x): 2195 def _lv_to_dict(x):
@@ -2819,10 +2837,10 @@ if toastermain.settings.MANAGED:
2819 2837
2820 vars_blacklist = { 2838 vars_blacklist = {
2821 'DL_DR','PARALLEL_MAKE','BB_NUMBER_THREADS','SSTATE_DIR', 2839 'DL_DR','PARALLEL_MAKE','BB_NUMBER_THREADS','SSTATE_DIR',
2822 'BB_DISKMON_DIRS','BB_NUMBER_THREADS','CVS_PROXY_HOST','CVS_PROXY_PORT', 2840 'BB_DISKMON_DIRS','BB_NUMBER_THREADS','CVS_PROXY_HOST','CVS_PROXY_PORT',
2823 'DL_DIR','PARALLEL_MAKE','SSTATE_DIR','SSTATE_DIR','SSTATE_MIRRORS','TMPDIR', 2841 'DL_DIR','PARALLEL_MAKE','SSTATE_DIR','SSTATE_DIR','SSTATE_MIRRORS','TMPDIR',
2824 'all_proxy','ftp_proxy','http_proxy ','https_proxy' 2842 'all_proxy','ftp_proxy','http_proxy ','https_proxy'
2825 } 2843 }
2826 2844
2827 vars_fstypes = { 2845 vars_fstypes = {
2828 'btrfs','cpio','cpio.gz','cpio.lz4','cpio.lzma','cpio.xz','cramfs', 2846 'btrfs','cpio','cpio.gz','cpio.lz4','cpio.lzma','cpio.xz','cramfs',
@@ -2874,7 +2892,7 @@ if toastermain.settings.MANAGED:
2874 2892
2875 def projectbuilds(request, pid): 2893 def projectbuilds(request, pid):
2876 template = 'projectbuilds.html' 2894 template = 'projectbuilds.html'
2877 buildrequests = BuildRequest.objects.exclude(project_id = pid, state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED) 2895 buildrequests = BuildRequest.objects.filter(project_id = pid).exclude(state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED)
2878 2896
2879 try: 2897 try:
2880 context, pagesize, orderby = _build_list_helper(request, buildrequests) 2898 context, pagesize, orderby = _build_list_helper(request, buildrequests)
@@ -3012,6 +3030,14 @@ if toastermain.settings.MANAGED:
3012 } 3030 }
3013 return render(request, template, context) 3031 return render(request, template, context)
3014 3032
3033 def buildrequestdetails(request, pid, brid):
3034 template = "buildrequestdetails.html"
3035 context = {
3036 'buildrequest' : BuildRequest.objects.get(pk = brid, project_id = pid)
3037 }
3038 return render(request, template, context)
3039
3040
3015else: 3041else:
3016 # these are pages that are NOT available in interactive mode 3042 # these are pages that are NOT available in interactive mode
3017 def managedcontextprocessor(request): 3043 def managedcontextprocessor(request):
@@ -3256,3 +3282,6 @@ else:
3256 3282
3257 def xhr_updatelayer(request): 3283 def xhr_updatelayer(request):
3258 raise Exception("page not available in interactive mode") 3284 raise Exception("page not available in interactive mode")
3285
3286 def buildrequestdetails(request, pid, brid):
3287 raise Exception("page not available in interactive mode")