diff options
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/builds.html | 125 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/projects.html | 92 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 430 |
3 files changed, 0 insertions, 647 deletions
diff --git a/bitbake/lib/toaster/toastergui/templates/builds.html b/bitbake/lib/toaster/toastergui/templates/builds.html deleted file mode 100644 index c3cc266daf..0000000000 --- a/bitbake/lib/toaster/toastergui/templates/builds.html +++ /dev/null | |||
| @@ -1,125 +0,0 @@ | |||
| 1 | {% extends "base.html" %} | ||
| 2 | |||
| 3 | {% load static %} | ||
| 4 | {% load projecttags %} | ||
| 5 | {% load project_url_tag %} | ||
| 6 | {% load humanize %} | ||
| 7 | |||
| 8 | {% block title %} All builds - Toaster {% endblock %} | ||
| 9 | {% block extraheadcontent %} | ||
| 10 | <link rel="stylesheet" href="/static/css/jquery-ui.min.css" type='text/css'> | ||
| 11 | <link rel="stylesheet" href="/static/css/jquery-ui.structure.min.css" type='text/css'> | ||
| 12 | <link rel="stylesheet" href="/static/css/jquery-ui.theme.min.css" type='text/css'> | ||
| 13 | <script src="/static/js/jquery-ui.min.js"></script> | ||
| 14 | <script src="/static/js/filtersnippet.js"></script> | ||
| 15 | {% endblock %} | ||
| 16 | |||
| 17 | {% block pagecontent %} | ||
| 18 | |||
| 19 | {% if last_date_from and last_date_to %} | ||
| 20 | <script> | ||
| 21 | // initialize the date range controls | ||
| 22 | $(document).ready(function () { | ||
| 23 | date_init('started_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_started_on}}','{{dateMax_started_on}}','{{daterange_selected}}'); | ||
| 24 | date_init('completed_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_completed_on}}','{{dateMax_completed_on}}','{{daterange_selected}}'); | ||
| 25 | }); | ||
| 26 | </script> | ||
| 27 | {%endif%} {# last_date_from and last_date_to #} | ||
| 28 | |||
| 29 | <div class="row-fluid"> | ||
| 30 | |||
| 31 | {% include "mrb_section.html" %} | ||
| 32 | |||
| 33 | <div class="page-header top-air"> | ||
| 34 | <h1> | ||
| 35 | {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} | ||
| 36 | {{objects.paginator.count}} build{{objects.paginator.count|pluralize}} found | ||
| 37 | {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %} | ||
| 38 | No builds found | ||
| 39 | {%else%} | ||
| 40 | All builds | ||
| 41 | {%endif%} | ||
| 42 | </h1> | ||
| 43 | </div> | ||
| 44 | |||
| 45 | {% if objects.paginator.count == 0 %} | ||
| 46 | <div class="row-fluid"> | ||
| 47 | <div class="alert"> | ||
| 48 | <form class="no-results input-append" id="searchform"> | ||
| 49 | <input id="search" name="search" class="input-xxlarge" type="text" value=" | ||
| 50 | {% if request.GET.search %} | ||
| 51 | {{request.GET.search}} | ||
| 52 | {% endif %}"/> | ||
| 53 | {% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %} | ||
| 54 | <button class="btn" type="submit" value="Search">Search</button> | ||
| 55 | <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all builds</button> | ||
| 56 | </form> | ||
| 57 | </div> | ||
| 58 | </div> | ||
| 59 | {% else %} | ||
| 60 | {% include "basetable_top.html" %} | ||
| 61 | <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> | ||
| 62 | {% for build in objects %} | ||
| 63 | <tr class="data" data-table-build-result="{{ build.id }}"> | ||
| 64 | <td class="outcome"> | ||
| 65 | <a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a> | ||
| 66 | {% if build.cooker_log_path %} | ||
| 67 | | ||
| 68 | <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}"> | ||
| 69 | <i class="icon-download-alt" title="Download build log"></i> | ||
| 70 | </a> | ||
| 71 | {% endif %} | ||
| 72 | </td> | ||
| 73 | <td class="target"> | ||
| 74 | {% for t in build.target_set.all %} | ||
| 75 | <a href="{% url "builddashboard" build.id %}"> | ||
| 76 | {% if t.task %} | ||
| 77 | {{t.target}}:{{t.task}} | ||
| 78 | {% else %} | ||
| 79 | {{t.target}} | ||
| 80 | {% endif %} | ||
| 81 | </a> <br /> | ||
| 82 | {% endfor %} | ||
| 83 | </td> | ||
| 84 | <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> | ||
| 85 | <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> | ||
| 86 | <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on|date:"d/m/y H:i"}}</a></td> | ||
| 87 | <td class="failed_tasks error"> | ||
| 88 | {% query build.task_build outcome=4 order__gt=0 as exectask%} | ||
| 89 | {% if exectask.count == 1 %} | ||
| 90 | <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a> | ||
| 91 | <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}"> | ||
| 92 | <i class="icon-download-alt" title="" data-original-title="Download task log file"></i> | ||
| 93 | </a> | ||
| 94 | {% elif exectask.count > 1%} | ||
| 95 | <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a> | ||
| 96 | {%endif%} | ||
| 97 | </td> | ||
| 98 | <td class="errors.count errors_no"> | ||
| 99 | {% if build.errors.count %} | ||
| 100 | <a class="errors.count error" href="{% url "builddashboard" build.id %}#errors">{{build.errors.count}} error{{build.errors.count|pluralize}}</a> | ||
| 101 | {%endif%} | ||
| 102 | </td> | ||
| 103 | <td class="warnings.count warnings_no">{% if build.warnings.count %}<a class="warnings.count warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a>{%endif%}</td> | ||
| 104 | <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent_seconds|sectohms}}</a></td> | ||
| 105 | <td class="output"> | ||
| 106 | {% if build.outcome == build.SUCCEEDED %} | ||
| 107 | <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a> | ||
| 108 | {% endif %} | ||
| 109 | </td> | ||
| 110 | <td class="project-name"> | ||
| 111 | <a href="{% project_url build.project %}">{{build.project.name}}</a> | ||
| 112 | {% if build.project.is_default %} | ||
| 113 | <i class="icon-question-sign get-help hover-help" title="" data-original-title="This project shows information about the builds you start from the command line while Toaster is running" style="visibility: hidden;"></i> | ||
| 114 | {% endif %} | ||
| 115 | </td> | ||
| 116 | </tr> | ||
| 117 | |||
| 118 | {% endfor %} | ||
| 119 | |||
| 120 | |||
| 121 | {% include "basetable_bottom.html" %} | ||
| 122 | {% endif %} {# objects.paginator.count #} | ||
| 123 | </div><!-- end row-fluid--> | ||
| 124 | |||
| 125 | {% endblock %} | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/projects.html b/bitbake/lib/toaster/toastergui/templates/projects.html deleted file mode 100644 index 678a7963b7..0000000000 --- a/bitbake/lib/toaster/toastergui/templates/projects.html +++ /dev/null | |||
| @@ -1,92 +0,0 @@ | |||
| 1 | {% extends "base.html" %} | ||
| 2 | |||
| 3 | {% load static %} | ||
| 4 | {% load projecttags %} | ||
| 5 | {% load project_url_tag %} | ||
| 6 | {% load humanize %} | ||
| 7 | |||
| 8 | {% block title %} All projects - Toaster {% endblock %} | ||
| 9 | |||
| 10 | {% block pagecontent %} | ||
| 11 | |||
| 12 | |||
| 13 | <div class="page-header top-air"> | ||
| 14 | <h1> | ||
| 15 | {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} | ||
| 16 | {{objects.paginator.count}} project{{objects.paginator.count|pluralize}} found | ||
| 17 | {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %} | ||
| 18 | No projects found | ||
| 19 | {%else%} | ||
| 20 | All projects | ||
| 21 | {%endif%} | ||
| 22 | </h1> | ||
| 23 | </div> | ||
| 24 | |||
| 25 | {% if objects.paginator.count == 0 %} | ||
| 26 | <div class="row-fluid"> | ||
| 27 | <div class="alert"> | ||
| 28 | <form class="no-results input-append" id="searchform"> | ||
| 29 | <input id="search" name="search" class="input-xxlarge" type="text" value=" | ||
| 30 | {% if request.GET.search %} | ||
| 31 | {{request.GET.search}} | ||
| 32 | {% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %} | ||
| 33 | <button class="btn" type="submit" value="Search">Search</button> | ||
| 34 | <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all projects</button> | ||
| 35 | </form> | ||
| 36 | </div> | ||
| 37 | </div> | ||
| 38 | |||
| 39 | {% else %} {# We have builds to display #} | ||
| 40 | {% include "basetable_top.html" %} | ||
| 41 | {% for o in objects %} | ||
| 42 | <tr class="data" data-project="{{ o.id }}"> | ||
| 43 | <td data-project-field="name"> | ||
| 44 | <a href="{% project_url o %}">{{o.name}}</a> | ||
| 45 | </td> | ||
| 46 | <td class="updated"><a href="{% project_url o %}">{{o.updated|date:"d/m/y H:i"}}</a></td> | ||
| 47 | <td data-project-field="release"> | ||
| 48 | {% if o.release %} | ||
| 49 | <a href="{% url 'project' o.id %}#project-details">{{o.release.name}}</a> | ||
| 50 | {% elif o.is_default %} | ||
| 51 | <span class="muted">Not applicable</span> | ||
| 52 | <i class="icon-question-sign get-help hover-help" title="" data-original-title="This project does not have a release set. It simply collects information about the builds you start from the command line while Toaster is running" style="visibility: hidden;"></i> | ||
| 53 | {% else %} | ||
| 54 | No release available | ||
| 55 | {% endif %} | ||
| 56 | </td> | ||
| 57 | <td data-project-field="machine"> | ||
| 58 | {% if o.is_default %} | ||
| 59 | <span class="muted">Not applicable</span> | ||
| 60 | <i class="icon-question-sign get-help hover-help" title="" data-original-title="This project does not have a machine set. It simply collects information about the builds you start from the command line while Toaster is running" style="visibility: hidden;"></i> | ||
| 61 | {% else %} | ||
| 62 | <a href="{% url 'project' o.id %}#machine-distro">{{o.get_current_machine_name}}</a> | ||
| 63 | {% endif %} | ||
| 64 | </td> | ||
| 65 | {% if o.get_number_of_builds == 0 %} | ||
| 66 | <td class="muted">{{o.get_number_of_builds}}</td> | ||
| 67 | <td class="loutcome"></td> | ||
| 68 | <td class="ltarget"></td> | ||
| 69 | <td class="lerrors"></td> | ||
| 70 | <td class="lwarnings"></td> | ||
| 71 | <td class="limagefiles"></td> | ||
| 72 | {% else %} | ||
| 73 | <td><a href="{% url 'projectbuilds' o.id %}">{{o.get_number_of_builds}}</a></td> | ||
| 74 | <td class="loutcome"><a href="{% url "builddashboard" o.get_last_build_id %}">{%if o.get_last_outcome == build_SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif o.get_last_outcome == build_FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td> | ||
| 75 | <td class="ltarget"><a href="{% url "builddashboard" o.get_last_build_id %}">{{o.get_last_target}} </a></td> | ||
| 76 | <td class="lerrors">{% if o.get_last_errors %}<a class="errors.count error" href="{% url "builddashboard" o.get_last_build_id %}#errors">{{o.get_last_errors}} error{{o.get_last_errors|pluralize}}</a>{%endif%}</td> | ||
| 77 | <td class="lwarnings">{% if o.get_last_warnings %}<a class="warnings.count warning" href="{% url "builddashboard" o.get_last_build_id %}#warnings">{{o.get_last_warnings}} warning{{o.get_last_warnings|pluralize}}</a>{%endif%}</td> | ||
| 78 | <td class="limagefiles"> | ||
| 79 | {% if o.get_last_outcome == build_SUCCEEDED %} | ||
| 80 | <a href="{%url "builddashboard" o.get_last_build_id %}#images">{{fstypes|get_dict_value:o.id}}</a> | ||
| 81 | {% endif %} | ||
| 82 | </td> | ||
| 83 | |||
| 84 | {% endif %} | ||
| 85 | </tr> | ||
| 86 | {% endfor %} | ||
| 87 | {% include "basetable_bottom.html" %} | ||
| 88 | {% endif %} {# empty #} | ||
| 89 | |||
| 90 | {% endblock %} | ||
| 91 | |||
| 92 | |||
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 3e8a66bfb1..4f7b50f9dc 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -92,50 +92,6 @@ def landing(request): | |||
| 92 | 92 | ||
| 93 | return render(request, 'landing.html', context) | 93 | return render(request, 'landing.html', context) |
| 94 | 94 | ||
| 95 | """ | ||
| 96 | # returns a list for most recent builds; | ||
| 97 | def _get_latest_builds(prj=None): | ||
| 98 | queryset = Build.objects.all() | ||
| 99 | |||
| 100 | if prj is not None: | ||
| 101 | queryset = queryset.filter(project = prj) | ||
| 102 | |||
| 103 | return list(itertools.chain( | ||
| 104 | queryset.filter(outcome=Build.IN_PROGRESS).order_by("-started_on"), | ||
| 105 | queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-started_on")[:3] )) | ||
| 106 | """ | ||
| 107 | |||
| 108 | """ | ||
| 109 | # a JSON-able dict of recent builds; for use in the Project page, xhr_ updates, and other places, as needed | ||
| 110 | def _project_recent_build_list(prj): | ||
| 111 | data = [] | ||
| 112 | # take the most recent 3 completed builds, plus any builds in progress | ||
| 113 | for x in _get_latest_builds(prj): | ||
| 114 | d = { | ||
| 115 | "id": x.pk, | ||
| 116 | "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.target_set.all()), # TODO: create the task entry in the Target table | ||
| 117 | "status": x.get_current_status(), | ||
| 118 | "errors": map(lambda y: {"type": y.lineno, "msg": y.message, "tb": y.pathname}, (x.logmessage_set.filter(level__gte=LogMessage.WARNING)|x.logmessage_set.filter(level=LogMessage.EXCEPTION))), | ||
| 119 | "updated": x.completed_on.strftime('%s')+"000", | ||
| 120 | "command_time": (x.completed_on - x.started_on).total_seconds(), | ||
| 121 | "br_page_url": reverse('builddashboard', args=(x.pk,) ), | ||
| 122 | "build" : map( lambda y: {"id": y.pk, | ||
| 123 | "status": y.get_outcome_display(), | ||
| 124 | "completed_on" : y.completed_on.strftime('%s')+"000", | ||
| 125 | "build_time" : (y.completed_on - y.started_on).total_seconds(), | ||
| 126 | "build_page_url" : reverse('builddashboard', args=(y.pk,)), | ||
| 127 | 'build_time_page_url': reverse('buildtime', args=(y.pk,)), | ||
| 128 | "errors": y.errors.count(), | ||
| 129 | "warnings": y.warnings.count(), | ||
| 130 | "completeper": y.completeper() if y.outcome == Build.IN_PROGRESS else "0", | ||
| 131 | "eta": y.eta().strftime('%s')+"000" if y.outcome == Build.IN_PROGRESS else "0", | ||
| 132 | }, [x]), | ||
| 133 | } | ||
| 134 | data.append(d) | ||
| 135 | |||
| 136 | return data | ||
| 137 | """ | ||
| 138 | |||
| 139 | def objtojson(obj): | 95 | def objtojson(obj): |
| 140 | from django.db.models.query import QuerySet | 96 | from django.db.models.query import QuerySet |
| 141 | from django.db.models import Model | 97 | from django.db.models import Model |
| @@ -1919,215 +1875,6 @@ if True: | |||
| 1919 | ''' The exception raised on invalid POST requests ''' | 1875 | ''' The exception raised on invalid POST requests ''' |
| 1920 | pass | 1876 | pass |
| 1921 | 1877 | ||
| 1922 | """ | ||
| 1923 | # helper function, to be used on "all builds" and "project builds" pages | ||
| 1924 | def _build_list_helper(request, queryset_all, redirect_page, pid=None): | ||
| 1925 | default_orderby = 'completed_on:-' | ||
| 1926 | (pagesize, orderby) = _get_parameters_values(request, 10, default_orderby) | ||
| 1927 | mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } | ||
| 1928 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
| 1929 | if retval: | ||
| 1930 | params = {} | ||
| 1931 | if pid: | ||
| 1932 | params = {'pid': pid} | ||
| 1933 | raise RedirectException(redirect_page, | ||
| 1934 | request.GET, | ||
| 1935 | mandatory_parameters, | ||
| 1936 | **params) | ||
| 1937 | |||
| 1938 | # boilerplate code that takes a request for an object type and returns a queryset | ||
| 1939 | # for that object type. copypasta for all needed table searches | ||
| 1940 | (filter_string, search_term, ordering_string) = _search_tuple(request, Build) | ||
| 1941 | |||
| 1942 | # post-process any date range filters | ||
| 1943 | filter_string, daterange_selected = _modify_date_range_filter(filter_string) | ||
| 1944 | |||
| 1945 | # don't show "in progress" builds in "all builds" or "project builds" | ||
| 1946 | queryset_all = queryset_all.exclude(outcome = Build.IN_PROGRESS) | ||
| 1947 | |||
| 1948 | # append project info | ||
| 1949 | queryset_all = queryset_all.select_related("project") | ||
| 1950 | |||
| 1951 | # annotate with number of ERROR and EXCEPTION log messages | ||
| 1952 | queryset_all = queryset_all.annotate( | ||
| 1953 | errors_no = Count( | ||
| 1954 | 'logmessage', | ||
| 1955 | only=Q(logmessage__level=LogMessage.ERROR) | | ||
| 1956 | Q(logmessage__level=LogMessage.EXCEPTION) | ||
| 1957 | ) | ||
| 1958 | ) | ||
| 1959 | |||
| 1960 | # annotate with number of warnings | ||
| 1961 | q_warnings = Q(logmessage__level=LogMessage.WARNING) | ||
| 1962 | queryset_all = queryset_all.annotate( | ||
| 1963 | warnings_no = Count('logmessage', only=q_warnings) | ||
| 1964 | ) | ||
| 1965 | |||
| 1966 | queryset_with_search = _get_queryset(Build, queryset_all, | ||
| 1967 | None, search_term, | ||
| 1968 | ordering_string, '-completed_on') | ||
| 1969 | |||
| 1970 | queryset = _get_queryset(Build, queryset_all, | ||
| 1971 | filter_string, search_term, | ||
| 1972 | ordering_string, '-completed_on') | ||
| 1973 | |||
| 1974 | # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display | ||
| 1975 | build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) | ||
| 1976 | |||
| 1977 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | ||
| 1978 | build_mru = _get_latest_builds()[:3] | ||
| 1979 | |||
| 1980 | # calculate the exact begining of local today and yesterday, append context | ||
| 1981 | context_date,today_begin,yesterday_begin = _add_daterange_context(queryset_all, request, {'started_on','completed_on'}) | ||
| 1982 | |||
| 1983 | # set up list of fstypes for each build | ||
| 1984 | fstypes_map = {} | ||
| 1985 | |||
| 1986 | for build in build_info: | ||
| 1987 | fstypes_map[build.id] = build.get_image_file_extensions() | ||
| 1988 | |||
| 1989 | # send the data to the template | ||
| 1990 | context = { | ||
| 1991 | # specific info for | ||
| 1992 | 'mru' : build_mru, | ||
| 1993 | # TODO: common objects for all table views, adapt as needed | ||
| 1994 | 'objects' : build_info, | ||
| 1995 | 'objectname' : "builds", | ||
| 1996 | 'default_orderby' : default_orderby, | ||
| 1997 | 'fstypes' : fstypes_map, | ||
| 1998 | 'search_term' : search_term, | ||
| 1999 | 'total_count' : queryset_with_search.count(), | ||
| 2000 | 'daterange_selected' : daterange_selected, | ||
| 2001 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns | ||
| 2002 | 'tablecols' : [ | ||
| 2003 | {'name': 'Outcome', # column with a single filter | ||
| 2004 | 'qhelp' : "The outcome tells you if a build successfully completed or failed", # the help button content | ||
| 2005 | 'dclass' : "span2", # indication about column width; comes from the design | ||
| 2006 | 'orderfield': _get_toggle_order(request, "outcome"), # adds ordering by the field value; default ascending unless clicked from ascending into descending | ||
| 2007 | 'ordericon':_get_toggle_order_icon(request, "outcome"), | ||
| 2008 | # filter field will set a filter on that column with the specs in the filter description | ||
| 2009 | # the class field in the filter has no relation with clclass; the control different aspects of the UI | ||
| 2010 | # still, it is recommended for the values to be identical for easy tracking in the generated HTML | ||
| 2011 | 'filter' : {'class' : 'outcome', | ||
| 2012 | 'label': 'Show:', | ||
| 2013 | 'options' : [ | ||
| 2014 | ('Successful builds', 'outcome:' + str(Build.SUCCEEDED), queryset_with_search.filter(outcome=str(Build.SUCCEEDED)).count()), # this is the field search expression | ||
| 2015 | ('Failed builds', 'outcome:'+ str(Build.FAILED), queryset_with_search.filter(outcome=str(Build.FAILED)).count()), | ||
| 2016 | ] | ||
| 2017 | } | ||
| 2018 | }, | ||
| 2019 | {'name': 'Recipe', # default column, disabled box, with just the name in the list | ||
| 2020 | 'qhelp': "What you built (i.e. one or more recipes or image recipes)", | ||
| 2021 | 'orderfield': _get_toggle_order(request, "target__target"), | ||
| 2022 | 'ordericon':_get_toggle_order_icon(request, "target__target"), | ||
| 2023 | }, | ||
| 2024 | {'name': 'Machine', | ||
| 2025 | 'qhelp': "The machine is the hardware for which you are building a recipe or image recipe", | ||
| 2026 | 'orderfield': _get_toggle_order(request, "machine"), | ||
| 2027 | 'ordericon':_get_toggle_order_icon(request, "machine"), | ||
| 2028 | 'dclass': 'span3' | ||
| 2029 | }, # a slightly wider column | ||
| 2030 | {'name': 'Started on', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column | ||
| 2031 | 'qhelp': "The date and time you started the build", | ||
| 2032 | 'orderfield': _get_toggle_order(request, "started_on", True), | ||
| 2033 | 'ordericon':_get_toggle_order_icon(request, "started_on"), | ||
| 2034 | 'orderkey' : "started_on", | ||
| 2035 | 'filter' : {'class' : 'started_on', | ||
| 2036 | 'label': 'Show:', | ||
| 2037 | 'options' : [ | ||
| 2038 | ("Today's builds" , 'started_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(started_on__gte=today_begin).count()), | ||
| 2039 | ("Yesterday's builds", | ||
| 2040 | 'started_on__gte!started_on__lt:' | ||
| 2041 | +yesterday_begin.strftime("%Y-%m-%d")+'!' | ||
| 2042 | +today_begin.strftime("%Y-%m-%d"), | ||
| 2043 | queryset_all.filter( | ||
| 2044 | started_on__gte=yesterday_begin, | ||
| 2045 | started_on__lt=today_begin | ||
| 2046 | ).count()), | ||
| 2047 | ("Build date range", 'daterange', 1, '', 'started_on'), | ||
| 2048 | ] | ||
| 2049 | } | ||
| 2050 | }, | ||
| 2051 | {'name': 'Completed on', | ||
| 2052 | 'qhelp': "The date and time the build finished", | ||
| 2053 | 'orderfield': _get_toggle_order(request, "completed_on", True), | ||
| 2054 | 'ordericon':_get_toggle_order_icon(request, "completed_on"), | ||
| 2055 | 'orderkey' : 'completed_on', | ||
| 2056 | 'filter' : {'class' : 'completed_on', | ||
| 2057 | 'label': 'Show:', | ||
| 2058 | 'options' : [ | ||
| 2059 | ("Today's builds" , 'completed_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(completed_on__gte=today_begin).count()), | ||
| 2060 | ("Yesterday's builds", | ||
| 2061 | 'completed_on__gte!completed_on__lt:' | ||
| 2062 | +yesterday_begin.strftime("%Y-%m-%d")+'!' | ||
| 2063 | +today_begin.strftime("%Y-%m-%d"), | ||
| 2064 | queryset_all.filter( | ||
| 2065 | completed_on__gte=yesterday_begin, | ||
| 2066 | completed_on__lt=today_begin | ||
| 2067 | ).count()), | ||
| 2068 | ("Build date range", 'daterange', 1, '', 'completed_on'), | ||
| 2069 | ] | ||
| 2070 | } | ||
| 2071 | }, | ||
| 2072 | {'name': 'Failed tasks', 'clclass': 'failed_tasks', # specifing a clclass will enable the checkbox | ||
| 2073 | 'qhelp': "How many tasks failed during the build", | ||
| 2074 | 'filter' : {'class' : 'failed_tasks', | ||
| 2075 | 'label': 'Show:', | ||
| 2076 | 'options' : [ | ||
| 2077 | ('Builds with failed tasks', 'task_build__outcome:4', queryset_with_search.filter(task_build__outcome=4).count()), | ||
| 2078 | ('Builds without failed tasks', 'task_build__outcome:NOT4', queryset_with_search.filter(~Q(task_build__outcome=4)).count()), | ||
| 2079 | ] | ||
| 2080 | } | ||
| 2081 | }, | ||
| 2082 | {'name': 'Errors', 'clclass': 'errors_no', | ||
| 2083 | 'qhelp': "How many errors were encountered during the build (if any)", | ||
| 2084 | # Comment out sorting and filter until YOCTO #8131 is fixed | ||
| 2085 | #'orderfield': _get_toggle_order(request, "errors_no", True), | ||
| 2086 | #'ordericon':_get_toggle_order_icon(request, "errors_no"), | ||
| 2087 | #'orderkey' : 'errors_no', | ||
| 2088 | #'filter' : {'class' : 'errors_no', | ||
| 2089 | # 'label': 'Show:', | ||
| 2090 | # 'options' : [ | ||
| 2091 | # ('Builds with errors', 'errors_no__gte:1', queryset_with_search.filter(errors_no__gte=1).count()), | ||
| 2092 | # ('Builds without errors', 'errors_no:0', queryset_with_search.filter(errors_no=0).count()), | ||
| 2093 | # ] | ||
| 2094 | # } | ||
| 2095 | }, | ||
| 2096 | {'name': 'Warnings', 'clclass': 'warnings_no', | ||
| 2097 | 'qhelp': "How many warnings were encountered during the build (if any)", | ||
| 2098 | # Comment out sorting and filter until YOCTO #8131 is fixed | ||
| 2099 | #'orderfield': _get_toggle_order(request, "warnings_no", True), | ||
| 2100 | #'ordericon':_get_toggle_order_icon(request, "warnings_no"), | ||
| 2101 | #'orderkey' : 'warnings_no', | ||
| 2102 | #'filter' : {'class' : 'warnings_no', | ||
| 2103 | # 'label': 'Show:', | ||
| 2104 | # 'options' : [ | ||
| 2105 | # ('Builds with warnings','warnings_no__gte:1', queryset_with_search.filter(warnings_no__gte=1).count()), | ||
| 2106 | # ('Builds without warnings','warnings_no:0', queryset_with_search.filter(warnings_no=0).count()), | ||
| 2107 | # ] | ||
| 2108 | # } | ||
| 2109 | }, | ||
| 2110 | {'name': 'Time', 'clclass': 'time', 'hidden' : 1, | ||
| 2111 | 'qhelp': "How long it took the build to finish", | ||
| 2112 | # Comment out sorting until YOCTO #8131 is fixed | ||
| 2113 | #'orderfield': _get_toggle_order(request, "timespent", True), | ||
| 2114 | #'ordericon':_get_toggle_order_icon(request, "timespent"), | ||
| 2115 | #'orderkey' : 'timespent', | ||
| 2116 | }, | ||
| 2117 | {'name': 'Image files', 'clclass': 'output', | ||
| 2118 | 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory", | ||
| 2119 | # TODO: compute image fstypes from Target_Image_File | ||
| 2120 | } | ||
| 2121 | ] | ||
| 2122 | } | ||
| 2123 | |||
| 2124 | # merge daterange values | ||
| 2125 | context.update(context_date) | ||
| 2126 | return context, pagesize, orderby | ||
| 2127 | """ | ||
| 2128 | |||
| 2129 | |||
| 2130 | |||
| 2131 | # new project | 1878 | # new project |
| 2132 | def newproject(request): | 1879 | def newproject(request): |
| 2133 | template = "newproject.html" | 1880 | template = "newproject.html" |
| @@ -2829,64 +2576,6 @@ if True: | |||
| 2829 | 2576 | ||
| 2830 | return context | 2577 | return context |
| 2831 | 2578 | ||
| 2832 | # WARNING _build_list_helper() may raise a RedirectException, which | ||
| 2833 | # will set the GET parameters and redirect back to the | ||
| 2834 | # all-builds or projectbuilds page as appropriate; | ||
| 2835 | # TODO don't use exceptions to control program flow | ||
| 2836 | """ | ||
| 2837 | def projectbuilds(request, pid): | ||
| 2838 | if request.method == "POST": | ||
| 2839 | # process any build request | ||
| 2840 | |||
| 2841 | if 'buildCancel' in request.POST: | ||
| 2842 | for i in request.POST['buildCancel'].strip().split(" "): | ||
| 2843 | try: | ||
| 2844 | br = BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_QUEUED) | ||
| 2845 | br.state = BuildRequest.REQ_DELETED | ||
| 2846 | br.save() | ||
| 2847 | except BuildRequest.DoesNotExist: | ||
| 2848 | pass | ||
| 2849 | |||
| 2850 | if 'buildDelete' in request.POST: | ||
| 2851 | for i in request.POST['buildDelete'].strip().split(" "): | ||
| 2852 | try: | ||
| 2853 | BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_DELETED).delete() | ||
| 2854 | except BuildRequest.DoesNotExist: | ||
| 2855 | pass | ||
| 2856 | |||
| 2857 | if 'targets' in request.POST: | ||
| 2858 | ProjectTarget.objects.filter(project = prj).delete() | ||
| 2859 | s = str(request.POST['targets']) | ||
| 2860 | for t in s.translate(None, ";%|\"").split(" "): | ||
| 2861 | if ":" in t: | ||
| 2862 | target, task = t.split(":") | ||
| 2863 | else: | ||
| 2864 | target = t | ||
| 2865 | task = "" | ||
| 2866 | ProjectTarget.objects.create(project = prj, | ||
| 2867 | target = target, | ||
| 2868 | task = task) | ||
| 2869 | prj.schedule_build() | ||
| 2870 | |||
| 2871 | queryset = Build.objects.filter(project_id = pid) | ||
| 2872 | |||
| 2873 | redirect_page = resolve(request.path_info).url_name | ||
| 2874 | |||
| 2875 | context, pagesize, orderby = _build_list_helper(request, | ||
| 2876 | queryset, | ||
| 2877 | redirect_page, | ||
| 2878 | pid) | ||
| 2879 | |||
| 2880 | context['project'] = prj | ||
| 2881 | _set_parameters_values(pagesize, orderby, request) | ||
| 2882 | |||
| 2883 | # add the most recent builds for this project | ||
| 2884 | context['mru'] = _get_latest_builds(prj) | ||
| 2885 | |||
| 2886 | return context | ||
| 2887 | """ | ||
| 2888 | |||
| 2889 | |||
| 2890 | def _file_name_for_artifact(b, artifact_type, artifact_id): | 2579 | def _file_name_for_artifact(b, artifact_type, artifact_id): |
| 2891 | file_name = None | 2580 | file_name = None |
| 2892 | # Target_Image_File file_name | 2581 | # Target_Image_File file_name |
| @@ -2962,122 +2651,3 @@ if True: | |||
| 2962 | 'build' : Build.objects.get(pk = build_id), | 2651 | 'build' : Build.objects.get(pk = build_id), |
| 2963 | } | 2652 | } |
| 2964 | return render(request, "unavailable_artifact.html", context) | 2653 | return render(request, "unavailable_artifact.html", context) |
| 2965 | |||
| 2966 | """ | ||
| 2967 | @_template_renderer("projects.html") | ||
| 2968 | def projects(request): | ||
| 2969 | (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') | ||
| 2970 | mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } | ||
| 2971 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
| 2972 | if retval: | ||
| 2973 | raise RedirectException( 'all-projects', request.GET, mandatory_parameters ) | ||
| 2974 | |||
| 2975 | queryset_all = Project.objects.all() | ||
| 2976 | |||
| 2977 | # annotate each project with its number of builds | ||
| 2978 | queryset_all = queryset_all.annotate(num_builds=Count('build')) | ||
| 2979 | |||
| 2980 | # exclude the command line builds project if it has no builds | ||
| 2981 | q_default_with_builds = Q(is_default=True) & Q(num_builds__gt=0) | ||
| 2982 | queryset_all = queryset_all.filter(Q(is_default=False) | | ||
| 2983 | q_default_with_builds) | ||
| 2984 | |||
| 2985 | # boilerplate code that takes a request for an object type and returns a queryset | ||
| 2986 | # for that object type. copypasta for all needed table searches | ||
| 2987 | (filter_string, search_term, ordering_string) = _search_tuple(request, Project) | ||
| 2988 | queryset_with_search = _get_queryset(Project, queryset_all, None, search_term, ordering_string, '-updated') | ||
| 2989 | queryset = _get_queryset(Project, queryset_all, filter_string, search_term, ordering_string, '-updated') | ||
| 2990 | |||
| 2991 | # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display | ||
| 2992 | project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) | ||
| 2993 | |||
| 2994 | # add fields needed in JSON dumps for API call support | ||
| 2995 | for p in project_info.object_list: | ||
| 2996 | p.id = p.pk | ||
| 2997 | p.projectPageUrl = reverse('project', args=(p.id,)) | ||
| 2998 | p.layersTypeAheadUrl = reverse('xhr_layerstypeahead', args=(p.id,)) | ||
| 2999 | p.recipesTypeAheadUrl = reverse('xhr_recipestypeahead', args=(p.id,)) | ||
| 3000 | p.projectBuildsUrl = reverse('projectbuilds', args=(p.id,)) | ||
| 3001 | |||
| 3002 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | ||
| 3003 | build_mru = _get_latest_builds() | ||
| 3004 | |||
| 3005 | # translate the project's build target strings | ||
| 3006 | fstypes_map = {}; | ||
| 3007 | for project in project_info: | ||
| 3008 | try: | ||
| 3009 | targets = Target.objects.filter( build_id = project.get_last_build_id() ) | ||
| 3010 | comma = ""; | ||
| 3011 | extensions = ""; | ||
| 3012 | for t in targets: | ||
| 3013 | if ( not t.is_image ): | ||
| 3014 | continue | ||
| 3015 | tif = Target_Image_File.objects.filter( target_id = t.id ) | ||
| 3016 | for i in tif: | ||
| 3017 | s=re.sub('.*tar.bz2', 'tar.bz2', i.file_name) | ||
| 3018 | if s == i.file_name: | ||
| 3019 | s=re.sub('.*\.', '', i.file_name) | ||
| 3020 | if None == re.search(s,extensions): | ||
| 3021 | extensions += comma + s | ||
| 3022 | comma = ", " | ||
| 3023 | fstypes_map[project.id]=extensions | ||
| 3024 | except (Target.DoesNotExist,IndexError): | ||
| 3025 | fstypes_map[project.id]=project.get_last_imgfiles | ||
| 3026 | |||
| 3027 | context = { | ||
| 3028 | 'mru' : build_mru, | ||
| 3029 | |||
| 3030 | 'objects' : project_info, | ||
| 3031 | 'objectname' : "projects", | ||
| 3032 | 'default_orderby' : 'id:-', | ||
| 3033 | 'search_term' : search_term, | ||
| 3034 | 'total_count' : queryset_with_search.count(), | ||
| 3035 | 'fstypes' : fstypes_map, | ||
| 3036 | 'build_FAILED' : Build.FAILED, | ||
| 3037 | 'build_SUCCEEDED' : Build.SUCCEEDED, | ||
| 3038 | 'tablecols': [ | ||
| 3039 | {'name': 'Project', | ||
| 3040 | 'orderfield': _get_toggle_order(request, "name"), | ||
| 3041 | 'ordericon':_get_toggle_order_icon(request, "name"), | ||
| 3042 | 'orderkey' : 'name', | ||
| 3043 | }, | ||
| 3044 | {'name': 'Last activity on', | ||
| 3045 | 'clclass': 'updated', | ||
| 3046 | 'qhelp': "Shows the starting date and time of the last project build. If the project has no builds, it shows the date the project was created", | ||
| 3047 | 'orderfield': _get_toggle_order(request, "updated", True), | ||
| 3048 | 'ordericon':_get_toggle_order_icon(request, "updated"), | ||
| 3049 | 'orderkey' : 'updated', | ||
| 3050 | }, | ||
| 3051 | {'name': 'Release', | ||
| 3052 | 'qhelp' : "The version of the build system used by the project", | ||
| 3053 | 'orderfield': _get_toggle_order(request, "release__name"), | ||
| 3054 | 'ordericon':_get_toggle_order_icon(request, "release__name"), | ||
| 3055 | 'orderkey' : 'release__name', | ||
| 3056 | }, | ||
| 3057 | {'name': 'Machine', | ||
| 3058 | 'qhelp': "The hardware currently selected for the project", | ||
| 3059 | }, | ||
| 3060 | {'name': 'Number of builds', | ||
| 3061 | 'qhelp': "How many builds have been run for the project", | ||
| 3062 | }, | ||
| 3063 | {'name': 'Last build outcome', 'clclass': 'loutcome', | ||
| 3064 | 'qhelp': "Tells you if the last project build completed successfully or failed", | ||
| 3065 | }, | ||
| 3066 | {'name': 'Recipe', 'clclass': 'ltarget', | ||
| 3067 | 'qhelp': "The last recipe that was built in this project", | ||
| 3068 | }, | ||
| 3069 | {'name': 'Errors', 'clclass': 'lerrors', | ||
| 3070 | 'qhelp': "How many errors were encountered during the last project build (if any)", | ||
| 3071 | }, | ||
| 3072 | {'name': 'Warnings', 'clclass': 'lwarnings', | ||
| 3073 | 'qhelp': "How many warnigns were encountered during the last project build (if any)", | ||
| 3074 | }, | ||
| 3075 | {'name': 'Image files', 'clclass': 'limagefiles', 'hidden': 1, | ||
| 3076 | 'qhelp': "The root file system types produced by the last project build", | ||
| 3077 | }, | ||
| 3078 | ] | ||
| 3079 | } | ||
| 3080 | |||
| 3081 | _set_parameters_values(pagesize, orderby, request) | ||
| 3082 | return context | ||
| 3083 | """ | ||
