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.py437
1 files changed, 103 insertions, 334 deletions
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 060d680b85..0324d17065 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -55,11 +55,23 @@ def landing(request):
55 55
56 return render(request, 'landing.html', context) 56 return render(request, 'landing.html', context)
57 57
58# returns a list for most recent builds; for use in the Project page, xhr_ updates, and other places, as needed 58
59
60# returns a list for most recent builds;
61def _get_latest_builds(prj=None):
62 queryset = Build.objects.all()
63
64 if prj is not None:
65 queryset = queryset.filter(project = prj)
66
67 return itertools.chain(queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-pk")[:3], queryset.filter(outcome=Build.IN_PROGRESS).order_by("-pk"))
68
69
70# a JSON-able dict of recent builds; for use in the Project page, xhr_ updates, and other places, as needed
59def _project_recent_build_list(prj): 71def _project_recent_build_list(prj):
60 data = [] 72 data = []
61 # take the most recent 3 completed builds, plus any builds in progress 73 # take the most recent 3 completed builds, plus any builds in progress
62 for x in itertools.chain(prj.build_set.filter(outcome__lt=Build.IN_PROGRESS).order_by("-pk")[:3], prj.build_set.filter(outcome=Build.IN_PROGRESS).order_by("-pk")): 74 for x in _get_latest_builds(prj):
63 d = { 75 d = {
64 "id": x.pk, 76 "id": x.pk,
65 "targets" : map(lambda y: {"target": y.target, "task": None }, x.target_set.all()), # TODO: create the task entry in the Target table 77 "targets" : map(lambda y: {"target": y.target, "task": None }, x.target_set.all()), # TODO: create the task entry in the Target table
@@ -1866,10 +1878,10 @@ if True:
1866 # be able to display something. 'count' and 'page' are mandatory for all views 1878 # be able to display something. 'count' and 'page' are mandatory for all views
1867 # that use paginators. 1879 # that use paginators.
1868 1880
1869 buildrequests = BuildRequest.objects.exclude(state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED) 1881 queryset = Build.objects.filter(outcome__lte = Build.IN_PROGRESS)
1870 1882
1871 try: 1883 try:
1872 context, pagesize, orderby = _build_list_helper(request, buildrequests, True) 1884 context, pagesize, orderby = _build_list_helper(request, queryset)
1873 except InvalidRequestException as e: 1885 except InvalidRequestException as e:
1874 raise RedirectException( builds, request.GET, e.response) 1886 raise RedirectException( builds, request.GET, e.response)
1875 1887
@@ -1878,66 +1890,37 @@ if True:
1878 1890
1879 1891
1880 # helper function, to be used on "all builds" and "project builds" pages 1892 # helper function, to be used on "all builds" and "project builds" pages
1881 def _build_list_helper(request, buildrequests, insert_projects): 1893 def _build_list_helper(request, queryset_all):
1882 # ATTN: we use here the ordering parameters for interactive mode; the translation for BuildRequest fields will happen below 1894
1883 default_orderby = 'completed_on:-' 1895 default_orderby = 'completed_on:-'
1884 (pagesize, orderby) = _get_parameters_values(request, 10, default_orderby) 1896 (pagesize, orderby) = _get_parameters_values(request, 10, default_orderby)
1885 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 1897 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
1886 retval = _verify_parameters( request.GET, mandatory_parameters ) 1898 retval = _verify_parameters( request.GET, mandatory_parameters )
1887 if retval: 1899 if retval:
1888 raise InvalidRequestException(mandatory_parameters) 1900 raise RedirectException( 'all-builds', request.GET, mandatory_parameters)
1889
1890 orig_orderby = orderby
1891 # translate interactive mode ordering to managed mode ordering
1892 ordering_params = orderby.split(":")
1893 if ordering_params[0] == "completed_on":
1894 ordering_params[0] = "updated"
1895 if ordering_params[0] == "started_on":
1896 ordering_params[0] = "created"
1897 if ordering_params[0] == "errors_no":
1898 ordering_params[0] = "build__errors_no"
1899 if ordering_params[0] == "warnings_no":
1900 ordering_params[0] = "build__warnings_no"
1901 if ordering_params[0] == "machine":
1902 ordering_params[0] = "build__machine"
1903 if ordering_params[0] == "target__target":
1904 ordering_params[0] = "brtarget__target"
1905 if ordering_params[0] == "timespent":
1906 ordering_params[0] = "id"
1907 orderby = default_orderby
1908
1909 request.GET = request.GET.copy() # get a mutable copy of the GET QueryDict
1910 request.GET['orderby'] = ":".join(ordering_params)
1911 1901
1912 # boilerplate code that takes a request for an object type and returns a queryset 1902 # boilerplate code that takes a request for an object type and returns a queryset
1913 # for that object type. copypasta for all needed table searches 1903 # for that object type. copypasta for all needed table searches
1914 (filter_string, search_term, ordering_string) = _search_tuple(request, BuildRequest) 1904 (filter_string, search_term, ordering_string) = _search_tuple(request, Build)
1915 # post-process any date range filters 1905 # post-process any date range filters
1916 filter_string,daterange_selected = _modify_date_range_filter(filter_string) 1906 filter_string,daterange_selected = _modify_date_range_filter(filter_string)
1917 1907 queryset_all = queryset_all.select_related("project")
1918 # we don't display in-progress or deleted builds 1908 queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on')
1919 queryset_all = buildrequests.exclude(state = BuildRequest.REQ_DELETED) 1909 queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on')
1920 queryset_all = queryset_all.select_related("build", "build__project").annotate(Count('brerror'))
1921 queryset_with_search = _get_queryset(BuildRequest, queryset_all, filter_string, search_term, ordering_string, '-updated')
1922
1923 1910
1924 # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display 1911 # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display
1925 build_info = _build_page_range(Paginator(queryset_with_search, pagesize), request.GET.get('page', 1)) 1912 build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))
1926 1913
1927 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) 1914 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
1928 # most recent build is like projects' most recent builds, but across all projects 1915 build_mru = Build.objects.order_by("-started_on")[:3]
1929 build_mru = _managed_get_latest_builds() 1916
1917 # calculate the exact begining of local today and yesterday, append context
1918 context_date,today_begin,yesterday_begin = _add_daterange_context(queryset_all, request, {'started_on','completed_on'})
1930 1919
1920 # set up list of fstypes for each build
1931 fstypes_map = {}; 1921 fstypes_map = {};
1932 for build_request in build_info: 1922 for build in build_info:
1933 # set display variables for build request 1923 targets = Target.objects.filter( build_id = build.id )
1934 build_request.machine = build_request.brvariable_set.get(name="MACHINE").value
1935 build_request.timespent = build_request.updated - build_request.created
1936
1937 # set up list of fstypes for each build
1938 if build_request.build is None:
1939 continue
1940 targets = Target.objects.filter( build_id = build_request.build.id )
1941 comma = ""; 1924 comma = "";
1942 extensions = ""; 1925 extensions = "";
1943 for t in targets: 1926 for t in targets:
@@ -1951,8 +1934,7 @@ if True:
1951 if None == re.search(s,extensions): 1934 if None == re.search(s,extensions):
1952 extensions += comma + s 1935 extensions += comma + s
1953 comma = ", " 1936 comma = ", "
1954 fstypes_map[build_request.build.id]=extensions 1937 fstypes_map[build.id]=extensions
1955
1956 1938
1957 # send the data to the template 1939 # send the data to the template
1958 context = { 1940 context = {
@@ -1961,7 +1943,7 @@ if True:
1961 # TODO: common objects for all table views, adapt as needed 1943 # TODO: common objects for all table views, adapt as needed
1962 'objects' : build_info, 1944 'objects' : build_info,
1963 'objectname' : "builds", 1945 'objectname' : "builds",
1964 'default_orderby' : 'updated:-', 1946 'default_orderby' : default_orderby,
1965 'fstypes' : fstypes_map, 1947 'fstypes' : fstypes_map,
1966 'search_term' : search_term, 1948 'search_term' : search_term,
1967 'total_count' : queryset_with_search.count(), 1949 'total_count' : queryset_with_search.count(),
@@ -1971,151 +1953,137 @@ if True:
1971 {'name': 'Outcome', # column with a single filter 1953 {'name': 'Outcome', # column with a single filter
1972 'qhelp' : "The outcome tells you if a build successfully completed or failed", # the help button content 1954 'qhelp' : "The outcome tells you if a build successfully completed or failed", # the help button content
1973 'dclass' : "span2", # indication about column width; comes from the design 1955 'dclass' : "span2", # indication about column width; comes from the design
1974 'orderfield': _get_toggle_order(request, "state"), # adds ordering by the field value; default ascending unless clicked from ascending into descending 1956 'orderfield': _get_toggle_order(request, "outcome"), # adds ordering by the field value; default ascending unless clicked from ascending into descending
1975 'ordericon':_get_toggle_order_icon(request, "state"), 1957 'ordericon':_get_toggle_order_icon(request, "outcome"),
1976 # filter field will set a filter on that column with the specs in the filter description 1958 # filter field will set a filter on that column with the specs in the filter description
1977 # the class field in the filter has no relation with clclass; the control different aspects of the UI 1959 # the class field in the filter has no relation with clclass; the control different aspects of the UI
1978 # still, it is recommended for the values to be identical for easy tracking in the generated HTML 1960 # still, it is recommended for the values to be identical for easy tracking in the generated HTML
1979 'filter' : {'class' : 'outcome', 1961 'filter' : {'class' : 'outcome',
1980 'label': 'Show:', 1962 'label': 'Show:',
1981 'options' : [ 1963 'options' : [
1982 ('Successful builds', 'build__outcome:' + str(Build.SUCCEEDED), queryset_all.filter(build__outcome = Build.SUCCEEDED).count()), # this is the field search expression 1964 ('Successful builds', 'outcome:' + str(Build.SUCCEEDED), queryset_with_search.filter(outcome=str(Build.SUCCEEDED)).count()), # this is the field search expression
1983 ('Failed builds', 'build__outcome:NOT'+ str(Build.SUCCEEDED), queryset_all.exclude(build__outcome = Build.SUCCEEDED).count()), 1965 ('Failed builds', 'outcome:'+ str(Build.FAILED), queryset_with_search.filter(outcome=str(Build.FAILED)).count()),
1984 ] 1966 ]
1985 } 1967 }
1986 }, 1968 },
1987 {'name': 'Recipe', # default column, disabled box, with just the name in the list 1969 {'name': 'Recipe', # default column, disabled box, with just the name in the list
1988 'qhelp': "What you built (i.e. one or more recipes or image recipes)", 1970 'qhelp': "What you built (i.e. one or more recipes or image recipes)",
1989 'orderfield': _get_toggle_order(request, "brtarget__target"), 1971 'orderfield': _get_toggle_order(request, "target__target"),
1990 'ordericon':_get_toggle_order_icon(request, "brtarget__target"), 1972 'ordericon':_get_toggle_order_icon(request, "target__target"),
1991 }, 1973 },
1992 {'name': 'Machine', 1974 {'name': 'Machine',
1993 'qhelp': "The machine is the hardware for which you are building a recipe or image recipe", 1975 'qhelp': "The machine is the hardware for which you are building a recipe or image recipe",
1994 'orderfield': _get_toggle_order(request, "build__machine"), 1976 'orderfield': _get_toggle_order(request, "machine"),
1995 'ordericon':_get_toggle_order_icon(request, "build__machine"), 1977 'ordericon':_get_toggle_order_icon(request, "machine"),
1996 'dclass': 'span3' 1978 'dclass': 'span3'
1997 }, # a slightly wider column 1979 }, # a slightly wider column
1998 ]
1999 }
2000
2001 if (insert_projects):
2002 context['tablecols'].append(
2003 {'name': 'Project', 'clclass': 'project_column',
2004 }
2005 )
2006
2007 # calculate the exact begining of local today and yesterday
2008 context_date,today_begin,yesterday_begin = _add_daterange_context(queryset_all, request, {'created','updated'})
2009 context.update(context_date)
2010
2011 context['tablecols'].append(
2012 {'name': 'Started on', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column 1980 {'name': 'Started on', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column
2013 'qhelp': "The date and time you started the build", 1981 'qhelp': "The date and time you started the build",
2014 'orderfield': _get_toggle_order(request, "created", True), 1982 'orderfield': _get_toggle_order(request, "started_on", True),
2015 'ordericon':_get_toggle_order_icon(request, "created"), 1983 'ordericon':_get_toggle_order_icon(request, "started_on"),
2016 'filter' : {'class' : 'created', 1984 'orderkey' : "started_on",
1985 'filter' : {'class' : 'started_on',
2017 'label': 'Show:', 1986 'label': 'Show:',
2018 'options' : [ 1987 'options' : [
2019 ("Today's builds" , 'created__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(created__gte=today_begin).count()), 1988 ("Today's builds" , 'started_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(started_on__gte=today_begin).count()),
2020 ("Yesterday's builds", 1989 ("Yesterday's builds",
2021 'created__gte!created__lt:' 1990 'started_on__gte!started_on__lt:'
2022 +yesterday_begin.strftime("%Y-%m-%d")+'!' 1991 +yesterday_begin.strftime("%Y-%m-%d")+'!'
2023 +today_begin.strftime("%Y-%m-%d"), 1992 +today_begin.strftime("%Y-%m-%d"),
2024 queryset_all.filter( 1993 queryset_all.filter(
2025 created__gte=yesterday_begin, 1994 started_on__gte=yesterday_begin,
2026 created__lt=today_begin 1995 started_on__lt=today_begin
2027 ).count()), 1996 ).count()),
2028 ("Build date range", 'daterange', 1, '', 'created'), 1997 ("Build date range", 'daterange', 1, '', 'started_on'),
2029 ] 1998 ]
2030 } 1999 }
2031 } 2000 },
2032 )
2033 context['tablecols'].append(
2034 {'name': 'Completed on', 2001 {'name': 'Completed on',
2035 'qhelp': "The date and time the build finished", 2002 'qhelp': "The date and time the build finished",
2036 'orderfield': _get_toggle_order(request, "updated", True), 2003 'orderfield': _get_toggle_order(request, "completed_on", True),
2037 'ordericon':_get_toggle_order_icon(request, "updated"), 2004 'ordericon':_get_toggle_order_icon(request, "completed_on"),
2038 'orderkey' : 'updated', 2005 'orderkey' : 'completed_on',
2039 'filter' : {'class' : 'updated', 2006 'filter' : {'class' : 'completed_on',
2040 'label': 'Show:', 2007 'label': 'Show:',
2041 'options' : [ 2008 'options' : [
2042 ("Today's builds" , 'updated__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=today_begin).count()), 2009 ("Today's builds" , 'completed_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(completed_on__gte=today_begin).count()),
2043 ("Yesterday's builds", 2010 ("Yesterday's builds",
2044 'updated__gte!updated__lt:' 2011 'completed_on__gte!completed_on__lt:'
2045 +yesterday_begin.strftime("%Y-%m-%d")+'!' 2012 +yesterday_begin.strftime("%Y-%m-%d")+'!'
2046 +today_begin.strftime("%Y-%m-%d"), 2013 +today_begin.strftime("%Y-%m-%d"),
2047 queryset_all.filter( 2014 queryset_all.filter(
2048 updated__gte=yesterday_begin, 2015 completed_on__gte=yesterday_begin,
2049 updated__lt=today_begin 2016 completed_on__lt=today_begin
2050 ).count()), 2017 ).count()),
2051 ("Build date range", 'daterange', 1, '', 'updated'), 2018 ("Build date range", 'daterange', 1, '', 'completed_on'),
2052 ] 2019 ]
2053 } 2020 }
2054 } 2021 },
2055 )
2056 context['tablecols'].append(
2057 {'name': 'Failed tasks', 'clclass': 'failed_tasks', # specifing a clclass will enable the checkbox 2022 {'name': 'Failed tasks', 'clclass': 'failed_tasks', # specifing a clclass will enable the checkbox
2058 'qhelp': "How many tasks failed during the build", 2023 'qhelp': "How many tasks failed during the build",
2059 'filter' : {'class' : 'failed_tasks', 2024 'filter' : {'class' : 'failed_tasks',
2060 'label': 'Show:', 2025 'label': 'Show:',
2061 'options' : [ 2026 'options' : [
2062 ('Builds with failed tasks', 'build__task_build__outcome:%d' % Task.OUTCOME_FAILED, 2027 ('Builds with failed tasks', 'task_build__outcome:4', queryset_with_search.filter(task_build__outcome=4).count()),
2063 queryset_all.filter(build__task_build__outcome=Task.OUTCOME_FAILED).count()), 2028 ('Builds without failed tasks', 'task_build__outcome:NOT4', queryset_with_search.filter(~Q(task_build__outcome=4)).count()),
2064 ('Builds without failed tasks', 'build__task_build__outcome:%d' % Task.OUTCOME_FAILED,
2065 queryset_all.filter(~Q(build__task_build__outcome=Task.OUTCOME_FAILED)).count()),
2066 ] 2029 ]
2067 } 2030 }
2068 } 2031 },
2069 )
2070 context['tablecols'].append(
2071 {'name': 'Errors', 'clclass': 'errors_no', 2032 {'name': 'Errors', 'clclass': 'errors_no',
2072 'qhelp': "How many errors were encountered during the build (if any)", 2033 'qhelp': "How many errors were encountered during the build (if any)",
2073 'orderfield': _get_toggle_order(request, "build__errors_no", True), 2034 'orderfield': _get_toggle_order(request, "errors_no", True),
2074 'ordericon':_get_toggle_order_icon(request, "build__errors_no"), 2035 'ordericon':_get_toggle_order_icon(request, "errors_no"),
2075 'orderkey' : 'errors_no', 2036 'orderkey' : 'errors_no',
2076 'filter' : {'class' : 'errors_no', 2037 'filter' : {'class' : 'errors_no',
2077 'label': 'Show:', 2038 'label': 'Show:',
2078 'options' : [ 2039 'options' : [
2079 ('Builds with errors', 'build|build__errors_no__gt:None|0', 2040 ('Builds with errors', 'errors_no__gte:1', queryset_with_search.filter(errors_no__gte=1).count()),
2080 queryset_all.filter(Q(build=None) | Q(build__errors_no__gt=0)).count()), 2041 ('Builds without errors', 'errors_no:0', queryset_with_search.filter(errors_no=0).count()),
2081 ('Builds without errors', 'build__errors_no:0',
2082 queryset_all.filter(build__errors_no=0).count()),
2083 ] 2042 ]
2084 } 2043 }
2085 } 2044 },
2086 )
2087 context['tablecols'].append(
2088 {'name': 'Warnings', 'clclass': 'warnings_no', 2045 {'name': 'Warnings', 'clclass': 'warnings_no',
2089 'qhelp': "How many warnings were encountered during the build (if any)", 2046 'qhelp': "How many warnings were encountered during the build (if any)",
2090 'orderfield': _get_toggle_order(request, "build__warnings_no", True), 2047 'orderfield': _get_toggle_order(request, "warnings_no", True),
2091 'ordericon':_get_toggle_order_icon(request, "build__warnings_no"), 2048 'ordericon':_get_toggle_order_icon(request, "warnings_no"),
2092 'orderkey' : 'build__warnings_no', 2049 'orderkey' : 'warnings_no',
2093 'filter' : {'class' : 'build__warnings_no', 2050 'filter' : {'class' : 'warnings_no',
2094 'label': 'Show:', 2051 'label': 'Show:',
2095 'options' : [ 2052 'options' : [
2096 ('Builds with warnings','build__warnings_no__gte:1', queryset_all.filter(build__warnings_no__gte=1).count()), 2053 ('Builds with warnings','warnings_no__gte:1', queryset_with_search.filter(warnings_no__gte=1).count()),
2097 ('Builds without warnings','build__warnings_no:0', queryset_all.filter(build__warnings_no=0).count()), 2054 ('Builds without warnings','warnings_no:0', queryset_with_search.filter(warnings_no=0).count()),
2098 ] 2055 ]
2099 } 2056 }
2100 } 2057 },
2101 ) 2058 {'name': 'Log',
2102 context['tablecols'].append( 2059 'dclass': "span4",
2060 'qhelp': "Path to the build main log file",
2061 'clclass': 'log', 'hidden': 1,
2062 'orderfield': _get_toggle_order(request, "cooker_log_path"),
2063 'ordericon':_get_toggle_order_icon(request, "cooker_log_path"),
2064 'orderkey' : 'cooker_log_path',
2065 },
2103 {'name': 'Time', 'clclass': 'time', 'hidden' : 1, 2066 {'name': 'Time', 'clclass': 'time', 'hidden' : 1,
2104 'qhelp': "How long it took the build to finish", 2067 'qhelp': "How long it took the build to finish",
2105# 'orderfield': _get_toggle_order(request, "timespent", True), 2068 'orderfield': _get_toggle_order(request, "timespent", True),
2106# 'ordericon':_get_toggle_order_icon(request, "timespent"), 2069 'ordericon':_get_toggle_order_icon(request, "timespent"),
2107 'orderkey' : 'timespent', 2070 'orderkey' : 'timespent',
2108 } 2071 },
2109 )
2110 context['tablecols'].append(
2111 {'name': 'Image files', 'clclass': 'output', 2072 {'name': 'Image files', 'clclass': 'output',
2112 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory", 2073 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory",
2113 # TODO: compute image fstypes from Target_Image_File 2074 # TODO: compute image fstypes from Target_Image_File
2075 },
2076 {'name': 'Project', 'clcalss': 'project_column',
2114 } 2077 }
2115 ) 2078 ]
2079 }
2116 2080
2081 # merge daterange values
2082 context.update(context_date)
2117 return context, pagesize, orderby 2083 return context, pagesize, orderby
2118 2084
2085
2086
2119 # new project 2087 # new project
2120 def newproject(request): 2088 def newproject(request):
2121 template = "newproject.html" 2089 template = "newproject.html"
@@ -2236,7 +2204,7 @@ if True:
2236 "lvs_nos" : Layer_Version.objects.all().count(), 2204 "lvs_nos" : Layer_Version.objects.all().count(),
2237 "completedbuilds": Build.objects.filter(project_id = pid).filter(outcome__lte = Build.IN_PROGRESS), 2205 "completedbuilds": Build.objects.filter(project_id = pid).filter(outcome__lte = Build.IN_PROGRESS),
2238 "prj" : {"name": prj.name, }, 2206 "prj" : {"name": prj.name, },
2239 #"buildrequests" : prj.buildrequest_set.filter(state=BuildRequest.REQ_QUEUED), 2207 "buildrequests" : prj.build_set.filter(outcome=Build.IN_PROGRESS),
2240 "builds" : _project_recent_build_list(prj), 2208 "builds" : _project_recent_build_list(prj),
2241 "layers" : map(lambda x: { 2209 "layers" : map(lambda x: {
2242 "id": x.layercommit.pk, 2210 "id": x.layercommit.pk,
@@ -2607,9 +2575,10 @@ if True:
2607 2575
2608 @_template_renderer('projectbuilds.html') 2576 @_template_renderer('projectbuilds.html')
2609 def projectbuilds(request, pid): 2577 def projectbuilds(request, pid):
2610 # process any build request
2611 prj = Project.objects.get(id = pid) 2578 prj = Project.objects.get(id = pid)
2579
2612 if request.method == "POST": 2580 if request.method == "POST":
2581 # process any build request
2613 2582
2614 if 'buildCancel' in request.POST: 2583 if 'buildCancel' in request.POST:
2615 for i in request.POST['buildCancel'].strip().split(" "): 2584 for i in request.POST['buildCancel'].strip().split(" "):
@@ -2641,10 +2610,10 @@ if True:
2641 br = prj.schedule_build() 2610 br = prj.schedule_build()
2642 2611
2643 2612
2644 buildrequests = BuildRequest.objects.filter(project = prj).exclude(state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED) 2613 queryset = Build.objects.filter(outcome__lte = Build.IN_PROGRESS)
2645 2614
2646 try: 2615 try:
2647 context, pagesize, orderby = _build_list_helper(request, buildrequests, False) 2616 context, pagesize, orderby = _build_list_helper(request, queryset)
2648 except InvalidRequestException as e: 2617 except InvalidRequestException as e:
2649 raise RedirectException('projectbuilds', request.GET, e.response, pid = pid) 2618 raise RedirectException('projectbuilds', request.GET, e.response, pid = pid)
2650 2619
@@ -2759,12 +2728,6 @@ if True:
2759 } 2728 }
2760 return render(request, "unavailable_artifact.html", context) 2729 return render(request, "unavailable_artifact.html", context)
2761 2730
2762 # This returns the mru object that is needed for the
2763 # managed_mrb_section.html template
2764 def _managed_get_latest_builds():
2765 build_mru = BuildRequest.objects.all()
2766 build_mru = list(build_mru.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) + list(build_mru.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])
2767 return build_mru
2768 2731
2769 2732
2770 2733
@@ -2796,7 +2759,7 @@ if True:
2796 p.projectTargetsUrl = reverse('projectavailabletargets', args=(p.id,)) 2759 p.projectTargetsUrl = reverse('projectavailabletargets', args=(p.id,))
2797 2760
2798 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) 2761 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
2799 build_mru = _managed_get_latest_builds() 2762 build_mru = _get_latest_builds()
2800 2763
2801 # translate the project's build target strings 2764 # translate the project's build target strings
2802 fstypes_map = {}; 2765 fstypes_map = {};
@@ -2878,202 +2841,8 @@ if True:
2878 return context 2841 return context
2879 2842
2880 @_template_renderer("buildrequestdetails.html") 2843 @_template_renderer("buildrequestdetails.html")
2881 def buildrequestdetails(request, pid, brid): 2844 def buildrequestdetails(request, pid, bid):
2882 context = { 2845 context = {
2883 'buildrequest' : BuildRequest.objects.get(pk = brid, project_id = pid) 2846 'buildrequest' : Build.objects.get(pk = bid, project_id = pid).buildrequest
2884 } 2847 }
2885 return context 2848 return context
2886
2887
2888 @_template_renderer('builds.html')
2889 def builds_old(request):
2890 # define here what parameters the view needs in the GET portion in order to
2891 # be able to display something. 'count' and 'page' are mandatory for all views
2892 # that use paginators.
2893 (pagesize, orderby) = _get_parameters_values(request, 10, 'completed_on:-')
2894 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
2895 retval = _verify_parameters( request.GET, mandatory_parameters )
2896 if retval:
2897 raise RedirectException( 'all-builds', request.GET, mandatory_parameters)
2898
2899 # boilerplate code that takes a request for an object type and returns a queryset
2900 # for that object type. copypasta for all needed table searches
2901 (filter_string, search_term, ordering_string) = _search_tuple(request, Build)
2902 # post-process any date range filters
2903 filter_string,daterange_selected = _modify_date_range_filter(filter_string)
2904 queryset_all = Build.objects.exclude(outcome = Build.IN_PROGRESS)
2905 queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on')
2906 queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on')
2907
2908 # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display
2909 build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))
2910
2911 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
2912 build_mru = Build.objects.order_by("-started_on")[:3]
2913
2914 # calculate the exact begining of local today and yesterday, append context
2915 context_date,today_begin,yesterday_begin = _add_daterange_context(queryset_all, request, {'started_on','completed_on'})
2916
2917 # set up list of fstypes for each build
2918 fstypes_map = {};
2919 for build in build_info:
2920 targets = Target.objects.filter( build_id = build.id )
2921 comma = "";
2922 extensions = "";
2923 for t in targets:
2924 if ( not t.is_image ):
2925 continue
2926 tif = Target_Image_File.objects.filter( target_id = t.id )
2927 for i in tif:
2928 s=re.sub('.*tar.bz2', 'tar.bz2', i.file_name)
2929 if s == i.file_name:
2930 s=re.sub('.*\.', '', i.file_name)
2931 if None == re.search(s,extensions):
2932 extensions += comma + s
2933 comma = ", "
2934 fstypes_map[build.id]=extensions
2935
2936 # send the data to the template
2937 context = {
2938 # specific info for
2939 'mru' : build_mru,
2940 # TODO: common objects for all table views, adapt as needed
2941 'objects' : build_info,
2942 'objectname' : "builds",
2943 'default_orderby' : 'completed_on:-',
2944 'fstypes' : fstypes_map,
2945 'search_term' : search_term,
2946 'total_count' : queryset_with_search.count(),
2947 'daterange_selected' : daterange_selected,
2948 # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns
2949 'tablecols' : [
2950 {'name': 'Outcome', # column with a single filter
2951 'qhelp' : "The outcome tells you if a build successfully completed or failed", # the help button content
2952 'dclass' : "span2", # indication about column width; comes from the design
2953 'orderfield': _get_toggle_order(request, "outcome"), # adds ordering by the field value; default ascending unless clicked from ascending into descending
2954 'ordericon':_get_toggle_order_icon(request, "outcome"),
2955 # filter field will set a filter on that column with the specs in the filter description
2956 # the class field in the filter has no relation with clclass; the control different aspects of the UI
2957 # still, it is recommended for the values to be identical for easy tracking in the generated HTML
2958 'filter' : {'class' : 'outcome',
2959 'label': 'Show:',
2960 'options' : [
2961 ('Successful builds', 'outcome:' + str(Build.SUCCEEDED), queryset_with_search.filter(outcome=str(Build.SUCCEEDED)).count()), # this is the field search expression
2962 ('Failed builds', 'outcome:'+ str(Build.FAILED), queryset_with_search.filter(outcome=str(Build.FAILED)).count()),
2963 ]
2964 }
2965 },
2966 {'name': 'Recipe', # default column, disabled box, with just the name in the list
2967 'qhelp': "What you built (i.e. one or more recipes or image recipes)",
2968 'orderfield': _get_toggle_order(request, "target__target"),
2969 'ordericon':_get_toggle_order_icon(request, "target__target"),
2970 },
2971 {'name': 'Machine',
2972 'qhelp': "The machine is the hardware for which you are building a recipe or image recipe",
2973 'orderfield': _get_toggle_order(request, "machine"),
2974 'ordericon':_get_toggle_order_icon(request, "machine"),
2975 'dclass': 'span3'
2976 }, # a slightly wider column
2977 {'name': 'Started on', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column
2978 'qhelp': "The date and time you started the build",
2979 'orderfield': _get_toggle_order(request, "started_on", True),
2980 'ordericon':_get_toggle_order_icon(request, "started_on"),
2981 'filter' : {'class' : 'started_on',
2982 'label': 'Show:',
2983 'options' : [
2984 ("Today's builds" , 'started_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(started_on__gte=today_begin).count()),
2985 ("Yesterday's builds",
2986 'started_on__gte!started_on__lt:'
2987 +yesterday_begin.strftime("%Y-%m-%d")+'!'
2988 +today_begin.strftime("%Y-%m-%d"),
2989 queryset_all.filter(
2990 started_on__gte=yesterday_begin,
2991 started_on__lt=today_begin
2992 ).count()),
2993 ("Build date range", 'daterange', 1, '', 'started_on'),
2994 ]
2995 }
2996 },
2997 {'name': 'Completed on',
2998 'qhelp': "The date and time the build finished",
2999 'orderfield': _get_toggle_order(request, "completed_on", True),
3000 'ordericon':_get_toggle_order_icon(request, "completed_on"),
3001 'orderkey' : 'completed_on',
3002 'filter' : {'class' : 'completed_on',
3003 'label': 'Show:',
3004 'options' : [
3005 ("Today's builds" , 'completed_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(completed_on__gte=today_begin).count()),
3006 ("Yesterday's builds",
3007 'completed_on__gte!completed_on__lt:'
3008 +yesterday_begin.strftime("%Y-%m-%d")+'!'
3009 +today_begin.strftime("%Y-%m-%d"),
3010 queryset_all.filter(
3011 completed_on__gte=yesterday_begin,
3012 completed_on__lt=today_begin
3013 ).count()),
3014 ("Build date range", 'daterange', 1, '', 'completed_on'),
3015 ]
3016 }
3017 },
3018 {'name': 'Failed tasks', 'clclass': 'failed_tasks', # specifing a clclass will enable the checkbox
3019 'qhelp': "How many tasks failed during the build",
3020 'filter' : {'class' : 'failed_tasks',
3021 'label': 'Show:',
3022 'options' : [
3023 ('Builds with failed tasks', 'task_build__outcome:4', queryset_with_search.filter(task_build__outcome=4).count()),
3024 ('Builds without failed tasks', 'task_build__outcome:NOT4', queryset_with_search.filter(~Q(task_build__outcome=4)).count()),
3025 ]
3026 }
3027 },
3028 {'name': 'Errors', 'clclass': 'errors_no',
3029 'qhelp': "How many errors were encountered during the build (if any)",
3030 'orderfield': _get_toggle_order(request, "errors_no", True),
3031 'ordericon':_get_toggle_order_icon(request, "errors_no"),
3032 'orderkey' : 'errors_no',
3033 'filter' : {'class' : 'errors_no',
3034 'label': 'Show:',
3035 'options' : [
3036 ('Builds with errors', 'errors_no__gte:1', queryset_with_search.filter(errors_no__gte=1).count()),
3037 ('Builds without errors', 'errors_no:0', queryset_with_search.filter(errors_no=0).count()),
3038 ]
3039 }
3040 },
3041 {'name': 'Warnings', 'clclass': 'warnings_no',
3042 'qhelp': "How many warnings were encountered during the build (if any)",
3043 'orderfield': _get_toggle_order(request, "warnings_no", True),
3044 'ordericon':_get_toggle_order_icon(request, "warnings_no"),
3045 'orderkey' : 'warnings_no',
3046 'filter' : {'class' : 'warnings_no',
3047 'label': 'Show:',
3048 'options' : [
3049 ('Builds with warnings','warnings_no__gte:1', queryset_with_search.filter(warnings_no__gte=1).count()),
3050 ('Builds without warnings','warnings_no:0', queryset_with_search.filter(warnings_no=0).count()),
3051 ]
3052 }
3053 },
3054 {'name': 'Log',
3055 'dclass': "span4",
3056 'qhelp': "Path to the build main log file",
3057 'clclass': 'log', 'hidden': 1,
3058 'orderfield': _get_toggle_order(request, "cooker_log_path"),
3059 'ordericon':_get_toggle_order_icon(request, "cooker_log_path"),
3060 'orderkey' : 'cooker_log_path',
3061 },
3062 {'name': 'Time', 'clclass': 'time', 'hidden' : 1,
3063 'qhelp': "How long it took the build to finish",
3064 'orderfield': _get_toggle_order(request, "timespent", True),
3065 'ordericon':_get_toggle_order_icon(request, "timespent"),
3066 'orderkey' : 'timespent',
3067 },
3068 {'name': 'Image files', 'clclass': 'output',
3069 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory",
3070 # TODO: compute image fstypes from Target_Image_File
3071 },
3072 ]
3073 }
3074
3075 # merge daterange values
3076 context.update(context_date)
3077 _set_parameters_values(pagesize, orderby, request)
3078
3079 return context