diff options
Diffstat (limited to 'bitbake/lib/toaster/toastergui/views.py')
-rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 103 |
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 @@ | |||
22 | import operator,re | 22 | import operator,re |
23 | import HTMLParser | 23 | import HTMLParser |
24 | 24 | ||
25 | from django.db.models import Q, Sum | 25 | from django.db.models import Q, Sum, Count |
26 | from django.db import IntegrityError | 26 | from django.db import IntegrityError |
27 | from django.shortcuts import render, redirect | 27 | from django.shortcuts import render, redirect |
28 | from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable | 28 | from 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 | ||
119 | FIELD_SEPARATOR = ":" | 119 | FIELD_SEPARATOR = ":" |
120 | VALUE_SEPARATOR = "!" | 120 | AND_VALUE_SEPARATOR = "!" |
121 | OR_VALUE_SEPARATOR = "|" | ||
121 | DESCENDING = "-" | 122 | DESCENDING = "-" |
122 | 123 | ||
123 | def __get_q_for_val(name, value): | 124 | def __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 | ||
135 | def _get_filtering_query(filter_string): | 141 | def _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 | ||
144 | def _get_toggle_order(request, orderkey, reverse = False): | 156 | def _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): | |||
216 | def _get_queryset(model, queryset, filter_string, search_term, ordering_string, ordering_secondary=''): | 228 | def _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 | |||
3015 | else: | 3041 | else: |
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") | ||