summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitbake/lib/bb/ui/buildinfohelper.py70
-rw-r--r--bitbake/lib/bb/ui/toasterui.py3
-rw-r--r--bitbake/lib/toaster/bldcontrol/localhostbecontroller.py2
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py10
-rw-r--r--bitbake/lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py353
-rw-r--r--bitbake/lib/toaster/orm/models.py19
-rw-r--r--bitbake/lib/toaster/toastergui/templates/builddashboard.html23
-rw-r--r--bitbake/lib/toaster/toastergui/templates/builds.html22
-rw-r--r--bitbake/lib/toaster/toastergui/templates/configuration.html6
-rw-r--r--bitbake/lib/toaster/toastergui/templates/filtersnippet.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/landing.html37
-rw-r--r--bitbake/lib/toaster/toastergui/templates/mrb_section.html29
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_detail_base.html7
-rw-r--r--bitbake/lib/toaster/toastergui/templates/projectbuilds.html29
-rw-r--r--bitbake/lib/toaster/toastergui/templates/projects.html9
-rw-r--r--bitbake/lib/toaster/toastergui/templates/recipe.html9
-rw-r--r--bitbake/lib/toaster/toastergui/templates/recipes.html7
-rw-r--r--bitbake/lib/toaster/toastergui/templates/runagain.html7
-rw-r--r--bitbake/lib/toaster/toastergui/templates/target.html5
-rw-r--r--bitbake/lib/toaster/toastergui/templates/task.html36
-rw-r--r--bitbake/lib/toaster/toastergui/templates/tasks.html7
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py3
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py17
23 files changed, 503 insertions, 209 deletions
diff --git a/bitbake/lib/bb/ui/buildinfohelper.py b/bitbake/lib/bb/ui/buildinfohelper.py
index 8b63f70a07..63976b57e0 100644
--- a/bitbake/lib/bb/ui/buildinfohelper.py
+++ b/bitbake/lib/bb/ui/buildinfohelper.py
@@ -16,7 +16,6 @@
16# with this program; if not, write to the Free Software Foundation, Inc., 16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 18
19import datetime
20import sys 19import sys
21import bb 20import bb
22import re 21import re
@@ -24,6 +23,7 @@ import ast
24 23
25os.environ["DJANGO_SETTINGS_MODULE"] = "toaster.toastermain.settings" 24os.environ["DJANGO_SETTINGS_MODULE"] = "toaster.toastermain.settings"
26 25
26from django.utils import timezone
27import toaster.toastermain.settings as toaster_django_settings 27import toaster.toastermain.settings as toaster_django_settings
28from toaster.orm.models import Build, Task, Recipe, Layer_Version, Layer, Target, LogMessage, HelpText 28from toaster.orm.models import Build, Task, Recipe, Layer_Version, Layer, Target, LogMessage, HelpText
29from toaster.orm.models import Target_Image_File, BuildArtifact 29from toaster.orm.models import Target_Image_File, BuildArtifact
@@ -41,7 +41,7 @@ import logging
41 41
42from django.db import transaction, connection 42from django.db import transaction, connection
43 43
44logger = logging.getLogger("BitBake") 44logger = logging.getLogger("ToasterLogger")
45 45
46 46
47class NotExisting(Exception): 47class NotExisting(Exception):
@@ -135,16 +135,18 @@ class ORMWrapper(object):
135 135
136 if buildrequest is not None: 136 if buildrequest is not None:
137 build = buildrequest.build 137 build = buildrequest.build
138 build.machine=build_info['machine'], 138 logger.info("Updating existing build, with %s" % build_info)
139 build.distro=build_info['distro'], 139 build.machine=build_info['machine']
140 build.distro_version=build_info['distro_version'], 140 build.distro=build_info['distro']
141 build.completed_on=build_info['started_on'], 141 build.distro_version=build_info['distro_version']
142 build.cooker_log_path=build_info['cooker_log_path'], 142 started_on=build_info['started_on']
143 build.build_name=build_info['build_name'], 143 completed_on=build_info['started_on']
144 build.cooker_log_path=build_info['cooker_log_path']
145 build.build_name=build_info['build_name']
144 build.bitbake_version=build_info['bitbake_version'] 146 build.bitbake_version=build_info['bitbake_version']
145 build.save() 147 build.save()
146 148
147 build.target_set.delete() 149 Target.objects.filter(build = build).delete()
148 150
149 else: 151 else:
150 build = Build.objects.create( 152 build = Build.objects.create(
@@ -188,10 +190,7 @@ class ORMWrapper(object):
188 if errors or taskfailures: 190 if errors or taskfailures:
189 outcome = Build.FAILED 191 outcome = Build.FAILED
190 192
191 build.completed_on = datetime.datetime.now() 193 build.completed_on = timezone.now()
192 build.timespent = int((build.completed_on - build.started_on).total_seconds())
193 build.errors_no = errors
194 build.warnings_no = warnings
195 build.outcome = outcome 194 build.outcome = outcome
196 build.save() 195 build.save()
197 196
@@ -687,8 +686,8 @@ class BuildInfoHelper(object):
687 build_info['machine'] = self.server.runCommand(["getVariable", "MACHINE"])[0] 686 build_info['machine'] = self.server.runCommand(["getVariable", "MACHINE"])[0]
688 build_info['distro'] = self.server.runCommand(["getVariable", "DISTRO"])[0] 687 build_info['distro'] = self.server.runCommand(["getVariable", "DISTRO"])[0]
689 build_info['distro_version'] = self.server.runCommand(["getVariable", "DISTRO_VERSION"])[0] 688 build_info['distro_version'] = self.server.runCommand(["getVariable", "DISTRO_VERSION"])[0]
690 build_info['started_on'] = datetime.datetime.now() 689 build_info['started_on'] = timezone.now()
691 build_info['completed_on'] = datetime.datetime.now() 690 build_info['completed_on'] = timezone.now()
692 build_info['cooker_log_path'] = self.server.runCommand(["getVariable", "BB_CONSOLELOG"])[0] 691 build_info['cooker_log_path'] = self.server.runCommand(["getVariable", "BB_CONSOLELOG"])[0]
693 build_info['build_name'] = self.server.runCommand(["getVariable", "BUILDNAME"])[0] 692 build_info['build_name'] = self.server.runCommand(["getVariable", "BUILDNAME"])[0]
694 build_info['bitbake_version'] = self.server.runCommand(["getVariable", "BB_VERSION"])[0] 693 build_info['bitbake_version'] = self.server.runCommand(["getVariable", "BB_VERSION"])[0]
@@ -857,6 +856,30 @@ class BuildInfoHelper(object):
857 856
858 # Save build configuration 857 # Save build configuration
859 data = self.server.runCommand(["getAllKeysWithFlags", ["doc", "func"]])[0] 858 data = self.server.runCommand(["getAllKeysWithFlags", ["doc", "func"]])[0]
859
860 # convert the paths from absolute to relative to either the build directory or layer checkouts
861 path_prefixes = []
862
863 br_id, be_id = self.brbe.split(":")
864 from bldcontrol.models import BuildEnvironment, BuildRequest
865 be = BuildEnvironment.objects.get(pk = be_id)
866 path_prefixes.append(be.builddir)
867
868 for layer in sorted(self.orm_wrapper.layer_version_objects, key = lambda x:len(x.local_path), reverse=True):
869 path_prefixes.append(layer.local_path)
870
871 # we strip the prefixes
872 for k in data:
873 if not bool(data[k]['func']):
874 for vh in data[k]['history']:
875 if not 'documentation.conf' in vh['file']:
876 abs_file_name = vh['file']
877 for pp in path_prefixes:
878 if abs_file_name.startswith(pp + "/"):
879 vh['file']=abs_file_name[len(pp + "/"):]
880 break
881
882 # save the variables
860 self.orm_wrapper.save_build_variables(build_obj, data) 883 self.orm_wrapper.save_build_variables(build_obj, data)
861 884
862 return self.brbe 885 return self.brbe
@@ -1031,7 +1054,7 @@ class BuildInfoHelper(object):
1031 mevent.taskhash = taskhash 1054 mevent.taskhash = taskhash
1032 task_information = self._get_task_information(mevent,recipe) 1055 task_information = self._get_task_information(mevent,recipe)
1033 1056
1034 task_information['start_time'] = datetime.datetime.now() 1057 task_information['start_time'] = timezone.now()
1035 task_information['outcome'] = Task.OUTCOME_NA 1058 task_information['outcome'] = Task.OUTCOME_NA
1036 task_information['sstate_checksum'] = taskhash 1059 task_information['sstate_checksum'] = taskhash
1037 task_information['sstate_result'] = Task.SSTATE_MISS 1060 task_information['sstate_result'] = Task.SSTATE_MISS
@@ -1206,6 +1229,7 @@ class BuildInfoHelper(object):
1206 ) 1229 )
1207 1230
1208 def _store_build_done(self, errorcode): 1231 def _store_build_done(self, errorcode):
1232 logger.info("Build exited with errorcode %d", errorcode)
1209 br_id, be_id = self.brbe.split(":") 1233 br_id, be_id = self.brbe.split(":")
1210 from bldcontrol.models import BuildEnvironment, BuildRequest 1234 from bldcontrol.models import BuildEnvironment, BuildRequest
1211 be = BuildEnvironment.objects.get(pk = be_id) 1235 be = BuildEnvironment.objects.get(pk = be_id)
@@ -1225,7 +1249,7 @@ class BuildInfoHelper(object):
1225 mockevent.levelno = format.ERROR 1249 mockevent.levelno = format.ERROR
1226 mockevent.msg = text 1250 mockevent.msg = text
1227 mockevent.pathname = '-- None' 1251 mockevent.pathname = '-- None'
1228 mockevent.lineno = -1 1252 mockevent.lineno = LogMessage.ERROR
1229 self.store_log_event(mockevent) 1253 self.store_log_event(mockevent)
1230 1254
1231 def store_log_exception(self, text, backtrace = ""): 1255 def store_log_exception(self, text, backtrace = ""):
@@ -1249,13 +1273,12 @@ class BuildInfoHelper(object):
1249 if not 'backlog' in self.internal_state: 1273 if not 'backlog' in self.internal_state:
1250 self.internal_state['backlog'] = [] 1274 self.internal_state['backlog'] = []
1251 self.internal_state['backlog'].append(event) 1275 self.internal_state['backlog'].append(event)
1252 else: # we're under Toaster control, post the errors to the build request 1276 return
1277 else: # we're under Toaster control, the build is already created
1253 from bldcontrol.models import BuildRequest, BRError 1278 from bldcontrol.models import BuildRequest, BRError
1254 br, be = self.brbe.split(":") 1279 br, be = self.brbe.split(":")
1255 buildrequest = BuildRequest.objects.get(pk = br) 1280 buildrequest = BuildRequest.objects.get(pk = br)
1256 brerror = BRError.objects.create(req = buildrequest, errtype="build", errmsg = event.msg) 1281 self.internal_state['build'] = buildrequest.build
1257
1258 return
1259 1282
1260 if 'build' in self.internal_state and 'backlog' in self.internal_state: 1283 if 'build' in self.internal_state and 'backlog' in self.internal_state:
1261 # if we have a backlog of events, do our best to save them here 1284 # if we have a backlog of events, do our best to save them here
@@ -1273,14 +1296,15 @@ class BuildInfoHelper(object):
1273 log_information['level'] = LogMessage.ERROR 1296 log_information['level'] = LogMessage.ERROR
1274 elif event.levelno == format.WARNING: 1297 elif event.levelno == format.WARNING:
1275 log_information['level'] = LogMessage.WARNING 1298 log_information['level'] = LogMessage.WARNING
1276 elif event.levelno == -1: # toaster self-logging 1299 elif event.levelno == -2: # toaster self-logging
1277 log_information['level'] = -1 1300 log_information['level'] = -2
1278 else: 1301 else:
1279 log_information['level'] = LogMessage.INFO 1302 log_information['level'] = LogMessage.INFO
1280 1303
1281 log_information['message'] = event.msg 1304 log_information['message'] = event.msg
1282 log_information['pathname'] = event.pathname 1305 log_information['pathname'] = event.pathname
1283 log_information['lineno'] = event.lineno 1306 log_information['lineno'] = event.lineno
1307 logger.info("Logging error 2: %s" % log_information)
1284 self.orm_wrapper.create_logmessage(log_information) 1308 self.orm_wrapper.create_logmessage(log_information)
1285 1309
1286 def close(self, errorcode): 1310 def close(self, errorcode):
diff --git a/bitbake/lib/bb/ui/toasterui.py b/bitbake/lib/bb/ui/toasterui.py
index 9c59fd07c6..28fdd8200e 100644
--- a/bitbake/lib/bb/ui/toasterui.py
+++ b/bitbake/lib/bb/ui/toasterui.py
@@ -140,6 +140,9 @@ def main(server, eventHandler, params ):
140 continue 140 continue
141 141
142 if isinstance(event, logging.LogRecord): 142 if isinstance(event, logging.LogRecord):
143 if event.levelno == -1:
144 event.levelno = format.ERROR
145
143 buildinfohelper.store_log_event(event) 146 buildinfohelper.store_log_event(event)
144 if event.levelno >= format.ERROR: 147 if event.levelno >= format.ERROR:
145 errors = errors + 1 148 errors = errors + 1
diff --git a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
index ad0a561398..3e16837be1 100644
--- a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
+++ b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
@@ -113,7 +113,7 @@ class LocalhostBEController(BuildEnvironmentController):
113 # get the file length; we need to detect the _last_ start of the toaster UI, not the first 113 # get the file length; we need to detect the _last_ start of the toaster UI, not the first
114 toaster_ui_log_filelength = 0 114 toaster_ui_log_filelength = 0
115 if os.path.exists(toaster_ui_log_filepath): 115 if os.path.exists(toaster_ui_log_filepath):
116 with open(toaster_ui_log_filepath, "r") as f: 116 with open(toaster_ui_log_filepath, "w") as f:
117 f.seek(0, 2) # jump to the end 117 f.seek(0, 2) # jump to the end
118 toaster_ui_log_filelength = f.tell() 118 toaster_ui_log_filelength = f.tell()
119 119
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
index bcf3b04cf0..33cc94ea89 100644
--- a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
@@ -107,20 +107,24 @@ class Command(NoArgsCommand):
107 def cleanup(self): 107 def cleanup(self):
108 from django.utils import timezone 108 from django.utils import timezone
109 from datetime import timedelta 109 from datetime import timedelta
110 # DISABLED environments locked for more than 30 seconds - they should be unlocked 110 # environments locked for more than 30 seconds - they should be unlocked
111 #BuildEnvironment.objects.filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE) 111 BuildEnvironment.objects.filter(buildrequest__state__in=[BuildRequest.REQ_FAILED, BuildRequest.REQ_COMPLETED]).filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
112 112
113 113
114 # update all Builds that failed to start 114 # update all Builds that failed to start
115 115
116 for br in BuildRequest.objects.filter(state = BuildRequest.REQ_FAILED, build__outcome = Build.IN_PROGRESS): 116 for br in BuildRequest.objects.filter(state = BuildRequest.REQ_FAILED, build__outcome = Build.IN_PROGRESS):
117 br.build.outcome = Build.FAILED
118 # transpose the launch errors in ToasterExceptions 117 # transpose the launch errors in ToasterExceptions
118 br.build.outcome = Build.FAILED
119 for brerror in br.brerror_set.all(): 119 for brerror in br.brerror_set.all():
120 logger.debug("Saving error %s" % brerror) 120 logger.debug("Saving error %s" % brerror)
121 LogMessage.objects.create(build = br.build, level = LogMessage.EXCEPTION, message = brerror.errmsg) 121 LogMessage.objects.create(build = br.build, level = LogMessage.EXCEPTION, message = brerror.errmsg)
122 br.build.save() 122 br.build.save()
123 123
124 # we don't have a true build object here; hence, toasterui didn't have a change to release the BE lock
125 br.environment.lock = BuildEnvironment.LOCK_FREE
126 br.environment.save()
127
124 128
125 129
126 # update all BuildRequests without a build created 130 # update all BuildRequests without a build created
diff --git a/bitbake/lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py b/bitbake/lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py
new file mode 100644
index 0000000000..b5b200cdd8
--- /dev/null
+++ b/bitbake/lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py
@@ -0,0 +1,353 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Deleting field 'Build.warnings_no'
12 db.delete_column(u'orm_build', 'warnings_no')
13
14 # Deleting field 'Build.errors_no'
15 db.delete_column(u'orm_build', 'errors_no')
16
17 # Deleting field 'Build.timespent'
18 db.delete_column(u'orm_build', 'timespent')
19
20
21 def backwards(self, orm):
22 # Adding field 'Build.warnings_no'
23 db.add_column(u'orm_build', 'warnings_no',
24 self.gf('django.db.models.fields.IntegerField')(default=0),
25 keep_default=False)
26
27 # Adding field 'Build.errors_no'
28 db.add_column(u'orm_build', 'errors_no',
29 self.gf('django.db.models.fields.IntegerField')(default=0),
30 keep_default=False)
31
32 # Adding field 'Build.timespent'
33 db.add_column(u'orm_build', 'timespent',
34 self.gf('django.db.models.fields.IntegerField')(default=0),
35 keep_default=False)
36
37
38 models = {
39 u'orm.bitbakeversion': {
40 'Meta': {'object_name': 'BitbakeVersion'},
41 'branch': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
42 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
43 'giturl': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
44 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
45 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
46 },
47 u'orm.branch': {
48 'Meta': {'unique_together': "(('layer_source', 'name'), ('layer_source', 'up_id'))", 'object_name': 'Branch'},
49 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
50 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'True', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
51 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
52 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
53 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
54 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
55 },
56 u'orm.build': {
57 'Meta': {'object_name': 'Build'},
58 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
59 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
60 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
61 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
62 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
63 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
64 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
65 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
66 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
67 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
68 'started_on': ('django.db.models.fields.DateTimeField', [], {})
69 },
70 u'orm.buildartifact': {
71 'Meta': {'object_name': 'BuildArtifact'},
72 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
73 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '100'}),
74 'file_size': ('django.db.models.fields.IntegerField', [], {}),
75 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
76 },
77 u'orm.helptext': {
78 'Meta': {'object_name': 'HelpText'},
79 'area': ('django.db.models.fields.IntegerField', [], {}),
80 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'helptext_build'", 'to': u"orm['orm.Build']"}),
81 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
82 'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
83 'text': ('django.db.models.fields.TextField', [], {})
84 },
85 u'orm.layer': {
86 'Meta': {'unique_together': "(('layer_source', 'up_id'), ('layer_source', 'name'))", 'object_name': 'Layer'},
87 'description': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
88 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
89 'layer_index_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
90 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
91 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
92 'summary': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
93 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
94 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
95 'vcs_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
96 'vcs_web_file_base_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
97 'vcs_web_tree_base_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
98 'vcs_web_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'})
99 },
100 u'orm.layer_version': {
101 'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'Layer_Version'},
102 'branch': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
103 'build': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'layer_version_build'", 'null': 'True', 'to': u"orm['orm.Build']"}),
104 'commit': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
105 'dirpath': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
106 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
107 'layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_layer'", 'to': u"orm['orm.Layer']"}),
108 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
109 'local_path': ('django.db.models.fields.FilePathField', [], {'default': "'/'", 'max_length': '1024'}),
110 'priority': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
111 'project': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.Project']", 'null': 'True'}),
112 'up_branch': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.Branch']", 'null': 'True'}),
113 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
114 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
115 },
116 u'orm.layersource': {
117 'Meta': {'unique_together': "(('sourcetype', 'apiurl'),)", 'object_name': 'LayerSource'},
118 'apiurl': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
119 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
120 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '63'}),
121 'sourcetype': ('django.db.models.fields.IntegerField', [], {})
122 },
123 u'orm.layerversiondependency': {
124 'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'LayerVersionDependency'},
125 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependees'", 'to': u"orm['orm.Layer_Version']"}),
126 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
127 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
128 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependencies'", 'to': u"orm['orm.Layer_Version']"}),
129 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
130 },
131 u'orm.logmessage': {
132 'Meta': {'object_name': 'LogMessage'},
133 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
134 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
135 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
136 'lineno': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
137 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}),
138 'pathname': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
139 'task': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Task']", 'null': 'True', 'blank': 'True'})
140 },
141 u'orm.machine': {
142 'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'Machine'},
143 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
144 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
145 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
146 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Layer_Version']"}),
147 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
148 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
149 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
150 },
151 u'orm.package': {
152 'Meta': {'object_name': 'Package'},
153 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
154 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
155 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
156 'installed_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
157 'installed_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
158 'license': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
159 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
160 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Recipe']", 'null': 'True'}),
161 'revision': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
162 'section': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
163 'size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
164 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
165 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
166 },
167 u'orm.package_dependency': {
168 'Meta': {'object_name': 'Package_Dependency'},
169 'dep_type': ('django.db.models.fields.IntegerField', [], {}),
170 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_target'", 'to': u"orm['orm.Package']"}),
171 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
172 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_source'", 'to': u"orm['orm.Package']"}),
173 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']", 'null': 'True'})
174 },
175 u'orm.package_file': {
176 'Meta': {'object_name': 'Package_File'},
177 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
178 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildfilelist_package'", 'to': u"orm['orm.Package']"}),
179 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
180 'size': ('django.db.models.fields.IntegerField', [], {})
181 },
182 u'orm.project': {
183 'Meta': {'object_name': 'Project'},
184 'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']", 'null': 'True'}),
185 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
186 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
187 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
188 'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']", 'null': 'True'}),
189 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
190 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
191 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
192 },
193 u'orm.projectlayer': {
194 'Meta': {'unique_together': "(('project', 'layercommit'),)", 'object_name': 'ProjectLayer'},
195 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
196 'layercommit': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Layer_Version']", 'null': 'True'}),
197 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
198 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"})
199 },
200 u'orm.projecttarget': {
201 'Meta': {'object_name': 'ProjectTarget'},
202 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
203 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
204 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
205 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
206 },
207 u'orm.projectvariable': {
208 'Meta': {'object_name': 'ProjectVariable'},
209 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
210 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
211 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
212 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
213 },
214 u'orm.recipe': {
215 'Meta': {'unique_together': "(('layer_version', 'file_path', 'pathflags'),)", 'object_name': 'Recipe'},
216 'bugtracker': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
217 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
218 'file_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}),
219 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
220 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
221 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
222 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recipe_layer_version'", 'to': u"orm['orm.Layer_Version']"}),
223 'license': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
224 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
225 'pathflags': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
226 'section': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
227 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
228 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
229 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
230 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
231 },
232 u'orm.recipe_dependency': {
233 'Meta': {'object_name': 'Recipe_Dependency'},
234 'dep_type': ('django.db.models.fields.IntegerField', [], {}),
235 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_depends'", 'to': u"orm['orm.Recipe']"}),
236 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
237 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_recipe'", 'to': u"orm['orm.Recipe']"})
238 },
239 u'orm.release': {
240 'Meta': {'object_name': 'Release'},
241 'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
242 'branch_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50'}),
243 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
244 'helptext': ('django.db.models.fields.TextField', [], {'null': 'True'}),
245 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
246 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
247 },
248 u'orm.releasedefaultlayer': {
249 'Meta': {'object_name': 'ReleaseDefaultLayer'},
250 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
251 'layer_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
252 'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"})
253 },
254 u'orm.releaselayersourcepriority': {
255 'Meta': {'unique_together': "(('release', 'layer_source'),)", 'object_name': 'ReleaseLayerSourcePriority'},
256 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
257 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.LayerSource']"}),
258 'priority': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
259 'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"})
260 },
261 u'orm.target': {
262 'Meta': {'object_name': 'Target'},
263 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
264 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
265 'image_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
266 'is_image': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
267 'license_manifest_path': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
268 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
269 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
270 },
271 u'orm.target_file': {
272 'Meta': {'object_name': 'Target_File'},
273 'directory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'directory_set'", 'null': 'True', 'to': u"orm['orm.Target_File']"}),
274 'group': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
275 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
276 'inodetype': ('django.db.models.fields.IntegerField', [], {}),
277 'owner': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
278 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '100'}),
279 'permission': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
280 'size': ('django.db.models.fields.IntegerField', [], {}),
281 'sym_target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'symlink_set'", 'null': 'True', 'to': u"orm['orm.Target_File']"}),
282 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
283 },
284 u'orm.target_image_file': {
285 'Meta': {'object_name': 'Target_Image_File'},
286 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '254'}),
287 'file_size': ('django.db.models.fields.IntegerField', [], {}),
288 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
289 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
290 },
291 u'orm.target_installed_package': {
292 'Meta': {'object_name': 'Target_Installed_Package'},
293 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
294 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildtargetlist_package'", 'to': u"orm['orm.Package']"}),
295 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
296 },
297 u'orm.task': {
298 'Meta': {'ordering': "('order', 'recipe')", 'unique_together': "(('build', 'recipe', 'task_name'),)", 'object_name': 'Task'},
299 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_build'", 'to': u"orm['orm.Build']"}),
300 'cpu_usage': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '8', 'decimal_places': '2'}),
301 'disk_io': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
302 'elapsed_time': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '8', 'decimal_places': '2'}),
303 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
304 'line_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
305 'logfile': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
306 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}),
307 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
308 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
309 'path_to_sstate_obj': ('django.db.models.fields.FilePathField', [], {'max_length': '500', 'blank': 'True'}),
310 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'to': u"orm['orm.Recipe']"}),
311 'script_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
312 'source_url': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
313 'sstate_checksum': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
314 'sstate_result': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
315 'task_executed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
316 'task_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
317 'work_directory': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'})
318 },
319 u'orm.task_dependency': {
320 'Meta': {'object_name': 'Task_Dependency'},
321 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_depends'", 'to': u"orm['orm.Task']"}),
322 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
323 'task': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_task'", 'to': u"orm['orm.Task']"})
324 },
325 u'orm.toastersetting': {
326 'Meta': {'object_name': 'ToasterSetting'},
327 'helptext': ('django.db.models.fields.TextField', [], {}),
328 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
329 'name': ('django.db.models.fields.CharField', [], {'max_length': '63'}),
330 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
331 },
332 u'orm.variable': {
333 'Meta': {'object_name': 'Variable'},
334 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variable_build'", 'to': u"orm['orm.Build']"}),
335 'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
336 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
337 'human_readable_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
338 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
339 'variable_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
340 'variable_value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
341 },
342 u'orm.variablehistory': {
343 'Meta': {'object_name': 'VariableHistory'},
344 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}),
345 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
346 'line_number': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
347 'operation': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
348 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
349 'variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vhistory'", 'to': u"orm['orm.Variable']"})
350 }
351 }
352
353 complete_apps = ['orm'] \ No newline at end of file
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py
index e93629b7ba..077c94d818 100644
--- a/bitbake/lib/toaster/orm/models.py
+++ b/bitbake/lib/toaster/orm/models.py
@@ -147,7 +147,7 @@ class Project(models.Model):
147 if (-1 == build_id): 147 if (-1 == build_id):
148 return( 0 ) 148 return( 0 )
149 try: 149 try:
150 return Build.objects.filter(id = build_id)[ 0 ].errors_no 150 return Build.objects.filter(id = build_id)[ 0 ].errors.count()
151 except (Build.DoesNotExist,IndexError): 151 except (Build.DoesNotExist,IndexError):
152 return( "not_found" ) 152 return( "not_found" )
153 153
@@ -156,7 +156,7 @@ class Project(models.Model):
156 if (-1 == build_id): 156 if (-1 == build_id):
157 return( 0 ) 157 return( 0 )
158 try: 158 try:
159 return Build.objects.filter(id = build_id)[ 0 ].warnings_no 159 return Build.objects.filter(id = build_id)[ 0 ].warnings.count()
160 except (Build.DoesNotExist,IndexError): 160 except (Build.DoesNotExist,IndexError):
161 return( "not_found" ) 161 return( "not_found" )
162 162
@@ -248,10 +248,7 @@ class Build(models.Model):
248 distro_version = models.CharField(max_length=100) 248 distro_version = models.CharField(max_length=100)
249 started_on = models.DateTimeField() 249 started_on = models.DateTimeField()
250 completed_on = models.DateTimeField() 250 completed_on = models.DateTimeField()
251 timespent = models.IntegerField(default=0)
252 outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS) 251 outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS)
253 errors_no = models.IntegerField(default=0)
254 warnings_no = models.IntegerField(default=0)
255 cooker_log_path = models.CharField(max_length=500) 252 cooker_log_path = models.CharField(max_length=500)
256 build_name = models.CharField(max_length=100) 253 build_name = models.CharField(max_length=100)
257 bitbake_version = models.CharField(max_length=50) 254 bitbake_version = models.CharField(max_length=50)
@@ -281,6 +278,17 @@ class Build(models.Model):
281 def toaster_exceptions(self): 278 def toaster_exceptions(self):
282 return self.logmessage_set.filter(level=LogMessage.EXCEPTION) 279 return self.logmessage_set.filter(level=LogMessage.EXCEPTION)
283 280
281 @property
282 def errors(self):
283 return (self.logmessage_set.filter(level=LogMessage.ERROR)|self.logmessage_set.filter(level=LogMessage.EXCEPTION))
284
285 @property
286 def warnings(self):
287 return self.logmessage_set.filter(level=LogMessage.WARNING)
288
289 @property
290 def timespent_seconds(self):
291 return (self.completed_on - self.started_on).total_seconds()
284 292
285 def get_current_status(self): 293 def get_current_status(self):
286 from bldcontrol.models import BuildRequest 294 from bldcontrol.models import BuildRequest
@@ -298,7 +306,6 @@ class BuildArtifact(models.Model):
298 file_name = models.FilePathField() 306 file_name = models.FilePathField()
299 file_size = models.IntegerField() 307 file_size = models.IntegerField()
300 308
301
302 def get_local_file_name(self): 309 def get_local_file_name(self):
303 try: 310 try:
304 deploydir = Variable.objects.get(build = self.build, variable_name="DEPLOY_DIR").variable_value 311 deploydir = Variable.objects.get(build = self.build, variable_name="DEPLOY_DIR").variable_value
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
index 47b8d7aa1f..bab8e388f5 100644
--- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html
+++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
@@ -23,22 +23,23 @@
23 </strong> on 23 </strong> on
24 {{build.completed_on|date:"d/m/y H:i"}} 24 {{build.completed_on|date:"d/m/y H:i"}}
25</span> 25</span>
26{% if build.warnings_no or build.errors_no %} 26{% if build.warnings.count or build.errors.count %}
27&nbsp;with 27&nbsp;with
28{% endif %} 28{% endif %}
29{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} 29{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
30{% if build.errors_no %} 30{% if build.errors.count %}
31 <span > <i class="icon-minus-sign red"></i><strong><a href="#errors" class="error show-errors"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span> 31 <span > <i class="icon-minus-sign red"></i><strong><a href="#errors" class="error show-errors"> {{build.errors.count}} error{{build.errors.count|pluralize}}</a></strong></span>
32{% endif %} 32{% endif %}
33{% if build.warnings_no %} 33{% if build.warnings.count %}
34{% if build.errors_no %} 34{% if build.errors.count %}
35 and 35 and
36{% endif %} 36{% endif %}
37 <span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning show-warnings"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span> 37 <span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning show-warnings"> {{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a></strong></span>
38{% endif %} 38{% endif %}
39 <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> 39 <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent_seconds|sectohms }}</a>
40 <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%else%}btn-danger{%endif%} pull-right log" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a> 40 <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%else%}btn-danger{%endif%} pull-right log" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a>
41 </span> 41 </span>
42
42{%endif%} 43{%endif%}
43 </div> 44 </div>
44 {% if build.toaster_exceptions.count > 0 %} 45 {% if build.toaster_exceptions.count > 0 %}
@@ -52,14 +53,14 @@
52 </div> 53 </div>
53</div> 54</div>
54 55
55{% if build.errors_no %} 56{% if build.errors.count %}
56<div class="accordion span10 pull-right" id="errors"> 57<div class="accordion span10 pull-right" id="errors">
57 <div class="accordion-group"> 58 <div class="accordion-group">
58 <div class="accordion-heading"> 59 <div class="accordion-heading">
59 <a class="accordion-toggle error toggle-errors"> 60 <a class="accordion-toggle error toggle-errors">
60 <h2 id="error-toggle"> 61 <h2 id="error-toggle">
61 <i class="icon-minus-sign"></i> 62 <i class="icon-minus-sign"></i>
62 {{build.errors_no}} error{{build.errors_no|pluralize}} 63 {{build.errors.count}} error{{build.errors.count|pluralize}}
63 </h2> 64 </h2>
64 </a> 65 </a>
65 </div> 66 </div>
@@ -241,14 +242,14 @@
241 </div> 242 </div>
242</div> 243</div>
243 244
244{% if build.warnings_no %} 245{% if build.warnings.count %}
245<div class="accordion span10 pull-right" id="warnings"> 246<div class="accordion span10 pull-right" id="warnings">
246 <div class="accordion-group"> 247 <div class="accordion-group">
247 <div class="accordion-heading"> 248 <div class="accordion-heading">
248 <a class="accordion-toggle warning toggle-warnings"> 249 <a class="accordion-toggle warning toggle-warnings">
249 <h2 id="warning-toggle"> 250 <h2 id="warning-toggle">
250 <i class="icon-warning-sign"></i> 251 <i class="icon-warning-sign"></i>
251 {{build.warnings_no}} warning{{build.warnings_no|pluralize}} 252 {{build.warnings.count}} warning{{build.warnings.count|pluralize}}
252 </h2> 253 </h2>
253 </a> 254 </a>
254 </div> 255 </div>
diff --git a/bitbake/lib/toaster/toastergui/templates/builds.html b/bitbake/lib/toaster/toastergui/templates/builds.html
index e9211affcd..00d1d4edd1 100644
--- a/bitbake/lib/toaster/toastergui/templates/builds.html
+++ b/bitbake/lib/toaster/toastergui/templates/builds.html
@@ -46,7 +46,11 @@
46 <div class="row-fluid"> 46 <div class="row-fluid">
47 <div class="alert"> 47 <div class="alert">
48 <form class="no-results input-append" id="searchform"> 48 <form class="no-results input-append" id="searchform">
49 <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %} 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 %}
50 <button class="btn" type="submit" value="Search">Search</button> 54 <button class="btn" type="submit" value="Search">Search</button>
51 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all builds</button> 55 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all builds</button>
52 </form> 56 </form>
@@ -60,8 +64,8 @@
60 {% for build in objects %} 64 {% for build in objects %}
61 <tr class="data"> 65 <tr class="data">
62 <td class="outcome"> 66 <td class="outcome">
63 <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> &nbsp; 67 <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> &nbsp;
64 </td> 68 </td>
65 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td> 69 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
66 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> 70 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
67 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> 71 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
@@ -77,19 +81,19 @@
77 <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a> 81 <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a>
78 {%endif%} 82 {%endif%}
79 </td> 83 </td>
80 <td class="errors_no"> 84 <td class="errors.count">
81 {% if build.errors_no %} 85 {% if build.errors.count %}
82 <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> 86 <a class="errors.count error" href="{% url "builddashboard" build.id %}#errors">{{build.errors.count}} error{{build.errors.count|pluralize}}</a>
83 {%endif%} 87 {%endif%}
84 </td> 88 </td>
85 <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> 89 <td class="warnings.count">{% 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>
86 <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td> 90 <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent_seconds|sectohms}}</a></td>
87 <td class="output"> 91 <td class="output">
88 {% if build.outcome == build.SUCCEEDED %} 92 {% if build.outcome == build.SUCCEEDED %}
89 <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a> 93 <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
90 {% endif %} 94 {% endif %}
91 </td> 95 </td>
92 <td> 96 <td>
93 <a href="{% url 'project' build.project.id %}">{{build.project.name}}</a> 97 <a href="{% url 'project' build.project.id %}">{{build.project.name}}</a>
94 </td> 98 </td>
95 </tr> 99 </tr>
diff --git a/bitbake/lib/toaster/toastergui/templates/configuration.html b/bitbake/lib/toaster/toastergui/templates/configuration.html
index 2aa1ae1a49..3e489918d2 100644
--- a/bitbake/lib/toaster/toastergui/templates/configuration.html
+++ b/bitbake/lib/toaster/toastergui/templates/configuration.html
@@ -50,9 +50,6 @@
50 <th>Layer</th> 50 <th>Layer</th>
51 <th>Layer branch</th> 51 <th>Layer branch</th>
52 <th>Layer commit</th> 52 <th>Layer commit</th>
53 {% if not MANAGED or not build.project %}
54 <th>Layer directory</th>
55 {% endif %}
56 </tr> 53 </tr>
57 </thead> 54 </thead>
58 <tbody>{% for lv in build.layer_version_build.all|dictsort:"layer.name" %} 55 <tbody>{% for lv in build.layer_version_build.all|dictsort:"layer.name" %}
@@ -63,9 +60,6 @@
63 <li>{{lv.commit}}</li> </ul>"> 60 <li>{{lv.commit}}</li> </ul>">
64 {{lv.commit|truncatechars:13}} 61 {{lv.commit|truncatechars:13}}
65 </a></td> 62 </a></td>
66 {% if not MANAGED or not build.project %}
67 <td>{{lv.local_path}}</td>
68 {% endif %}
69 </tr>{% endfor %} 63 </tr>{% endfor %}
70 </tbody> 64 </tbody>
71 </table> 65 </table>
diff --git a/bitbake/lib/toaster/toastergui/templates/filtersnippet.html b/bitbake/lib/toaster/toastergui/templates/filtersnippet.html
index 56e2b21cc0..1101aa8100 100644
--- a/bitbake/lib/toaster/toastergui/templates/filtersnippet.html
+++ b/bitbake/lib/toaster/toastergui/templates/filtersnippet.html
@@ -40,8 +40,10 @@
40 {% endif %} 40 {% endif %}
41 {% endfor %} 41 {% endfor %}
42 <!-- daterange persistence --> 42 <!-- daterange persistence -->
43 {% if last_date_from and last_date_to %}
43 <input type="hidden" id="last_date_from_{{key}}" name="last_date_from" value="{{last_date_from}}"/> 44 <input type="hidden" id="last_date_from_{{key}}" name="last_date_from" value="{{last_date_from}}"/>
44 <input type="hidden" id="last_date_to_{{key}}" name="last_date_to" value="{{last_date_to}}"/> 45 <input type="hidden" id="last_date_to_{{key}}" name="last_date_to" value="{{last_date_to}}"/>
46 {% endif %}
45 </div> 47 </div>
46 <div class="modal-footer"> 48 <div class="modal-footer">
47 <button type="submit" class="btn btn-primary" data-key="{{key}}">Apply</button> 49 <button type="submit" class="btn btn-primary" data-key="{{key}}">Apply</button>
diff --git a/bitbake/lib/toaster/toastergui/templates/landing.html b/bitbake/lib/toaster/toastergui/templates/landing.html
index 4af849c2b3..15cac47b39 100644
--- a/bitbake/lib/toaster/toastergui/templates/landing.html
+++ b/bitbake/lib/toaster/toastergui/templates/landing.html
@@ -9,7 +9,7 @@
9 <div class="container-fluid"> 9 <div class="container-fluid">
10 <div class="row-fluid"> 10 <div class="row-fluid">
11 <!-- Empty - no data in database --> 11 <!-- Empty - no data in database -->
12 <div class="hero-unit span12 {%if MANAGED%}well-transparent{%endif%}"> 12 <div class="hero-unit span12 well-transparent">
13 <div class="row-fluid"> 13 <div class="row-fluid">
14 <div class="span6"> 14 <div class="span6">
15 <h1> 15 <h1>
@@ -17,7 +17,6 @@
17 </h1> 17 </h1>
18 <p>A web interface to <a href="http://www.openembedded.org">OpenEmbedded</a> and <a href="http://www.yoctoproject.org/tools-resources/projects/bitbake">BitBake</a>, the <a href="http://www.yoctoproject.org">Yocto Project</a> build system.</p> 18 <p>A web interface to <a href="http://www.openembedded.org">OpenEmbedded</a> and <a href="http://www.yoctoproject.org/tools-resources/projects/bitbake">BitBake</a>, the <a href="http://www.yoctoproject.org">Yocto Project</a> build system.</p>
19 19
20 {% if MANAGED %}
21 20
22 {% if lvs_nos %} 21 {% if lvs_nos %}
23 <p class="hero-actions"> 22 <p class="hero-actions">
@@ -37,7 +36,7 @@
37 </li> 36 </li>
38 </ul> 37 </ul>
39 </div> 38 </div>
40 {% endif %} 39 {% endif %}
41 40
42 <ul class="unstyled"> 41 <ul class="unstyled">
43 <li> 42 <li>
@@ -48,18 +47,6 @@
48 </li> 47 </li>
49 </ul> 48 </ul>
50 49
51 {% else %}
52
53 <p class="hero-actions">
54 <a class="btn btn-primary btn-large" href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html">
55 Show me the manual
56 </a>
57 <a class="btn btn-large" href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster">
58 I want to contribute
59 </a>
60 </p>
61
62 {% endif %}
63 </div> 50 </div>
64 <div class="span6"> 51 <div class="span6">
65 {% if MANAGED %} 52 {% if MANAGED %}
@@ -70,26 +57,6 @@
70 </div> 57 </div>
71 </div> 58 </div>
72 </div> 59 </div>
73
74 {% if not MANAGED %}
75 <!-- Empty - no data in database -->
76 <div class="page-header top-air">
77 <h1>
78 All builds
79 </h1>
80 </div>
81 <div class="alert alert-info lead">
82 Toaster has not recorded any builds yet. Go build something with
83 <a href="http://www.yoctoproject.org/docs/current/yocto-project-qs/yocto-project-qs.html#test-run">
84 Knotty
85 </a>
86 or
87 <a href="https://www.yoctoproject.org/documentation/hob-manual">
88 Hob
89 </a>
90 </div>
91 {% endif %}
92
93 </div> 60 </div>
94 61
95{% endblock %} 62{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
index 7e84e4134d..d37b694f3d 100644
--- a/bitbake/lib/toaster/toastergui/templates/mrb_section.html
+++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
@@ -43,19 +43,35 @@
43 </div> 43 </div>
44 {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} 44 {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
45 <div class="span2 lead"> 45 <div class="span2 lead">
46 {% if build.errors_no %} 46 {% if build.errors.count %}
47 <i class="icon-minus-sign red"></i> <a href="{%url 'builddashboard' build.pk%}#errors" class="error">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> 47 <i class="icon-minus-sign red"></i> <a href="{%url 'builddashboard' build.pk%}#errors" class="error">{{build.errors.count}} error{{build.errors.count|pluralize}}</a>
48 {% endif %} 48 {% endif %}
49 </div> 49 </div>
50 <div class="span2 lead"> 50 <div class="span2 lead">
51 {% if build.warnings_no %} 51 {% if build.warnings.count %}
52 <i class="icon-warning-sign yellow"></i> <a href="{%url 'builddashboard' build.pk%}#warnings" class="warning">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a> 52 <i class="icon-warning-sign yellow"></i> <a href="{%url 'builddashboard' build.pk%}#warnings" class="warning">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a>
53 {% endif %} 53 {% endif %}
54 </div> 54 </div>
55 <div class="lead "> 55 <div class="lead ">
56 <span class="lead{%if not MANAGED or not build.project%} pull-right{%endif%}"> 56 <span class="lead">
57 Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> 57 Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent_seconds|sectohms }}</a>
58 </span> 58 </span>
59 <button class="btn
60 {% if build.outcome == build.SUCCEEDED %}
61 btn-success
62 {% elif build.outcome == build.FAILED %}
63 btn-danger
64 {% else %}
65 btn-info
66 {%endif%}
67 pull-right"
68 onclick='scheduleBuild({% url 'projectbuilds' build.project.id as bpi %}{{bpi|json}},
69 {{build.project.name|json}},
70 {% url 'project' build.project.id as bpurl %}{{bpurl|json}},
71 {{build.target_set.all|get_tasks|json}})'>
72
73 Run again
74 </button>
59 </div> 75 </div>
60 {%endif%} 76 {%endif%}
61 {%if build.outcome == build.IN_PROGRESS %} 77 {%if build.outcome == build.IN_PROGRESS %}
@@ -77,6 +93,7 @@
77function scheduleBuild(url, projectName, projectUrl, buildlist) { 93function scheduleBuild(url, projectName, projectUrl, buildlist) {
78 console.log("scheduleBuild"); 94 console.log("scheduleBuild");
79 libtoaster.startABuild(url, null, buildlist.join(" "), function(){ 95 libtoaster.startABuild(url, null, buildlist.join(" "), function(){
96 console.log("reloading page");
80 window.location.reload(); 97 window.location.reload();
81 }, null); 98 }, null);
82} 99}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
index e2ec75d157..a24bc8e436 100644
--- a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
+++ b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
@@ -136,13 +136,6 @@
136 136
137 <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd> 137 <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd>
138 138
139 {% if not MANAGED or not build.project %}
140 <dt>
141 Layer directory
142 <i class="icon-question-sign get-help" title="Path to the layer providing the recipe that builds this package"></i>
143 </dt>
144 <dd><code>{{package.recipe.layer_version.local_path}}</code></dd>
145 {% endif %}
146 </dl> 139 </dl>
147 </div> <!-- row4 well --> 140 </div> <!-- row4 well -->
148 {% endblock twocolumns %} 141 {% endblock twocolumns %}
diff --git a/bitbake/lib/toaster/toastergui/templates/projectbuilds.html b/bitbake/lib/toaster/toastergui/templates/projectbuilds.html
index 896c3b5af7..ac87d8c166 100644
--- a/bitbake/lib/toaster/toastergui/templates/projectbuilds.html
+++ b/bitbake/lib/toaster/toastergui/templates/projectbuilds.html
@@ -79,25 +79,20 @@
79 {% query build.task_build outcome=4 order__gt=0 as exectask%} 79 {% query build.task_build outcome=4 order__gt=0 as exectask%}
80 {% if exectask.count == 1 %} 80 {% if exectask.count == 1 %}
81 <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a> 81 <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a>
82 {% if MANAGED and build.project %}
83 <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}"> 82 <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}">
84 <i class="icon-download-alt" title="" data-original-title="Download task log file"></i> 83 <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
85 </a> 84 </a>
86 {% endif %}
87 {% elif exectask.count > 1%} 85 {% elif exectask.count > 1%}
88 <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a> 86 <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a>
89 {%endif%} 87 {%endif%}
90 </td> 88 </td>
91 <td class="errors_no"> 89 <td class="errors.count">
92 {% if build.errors_no %} 90 {% if build.errors.count %}
93 <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> 91 <a class="errors.count error" href="{% url "builddashboard" build.id %}#errors">{{build.errors.count}} error{{build.errors.count|pluralize}}</a>
94 {%endif%} 92 {%endif%}
95 </td> 93 </td>
96 <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> 94 <td class="warnings.count">{% 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>
97 <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td> 95 <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent_seconds|sectohms}}</a></td>
98 {% if not MANAGED or not build.project %}
99 <td class="log">{{build.cooker_log_path}}</td>
100 {% endif %}
101 <td class="output"> 96 <td class="output">
102 {% if build.outcome == build.SUCCEEDED %} 97 {% if build.outcome == build.SUCCEEDED %}
103 <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a> 98 <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
@@ -113,23 +108,23 @@
113 <tr class="data"> 108 <tr class="data">
114 <td class="outcome">{% if br.state == br.REQ_FAILED %}<i class="icon-minus-sign error"></i>{%else%}FIXME_build_request_state{%endif%}</td> 109 <td class="outcome">{% if br.state == br.REQ_FAILED %}<i class="icon-minus-sign error"></i>{%else%}FIXME_build_request_state{%endif%}</td>
115 <td class="target"> 110 <td class="target">
116 <a href="{% url "buildrequestdetails" br.project.id br.id %}"><span data-toggle="tooltip" {%if br.brtarget_set.all.count > 1%}title="Targets: {%for target in br.brtarget_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{br.brtarget_set.all.0.target}} {%if br.brtarget_set.all.count > 1%}(+ {{br.brtarget_set.all.count|add:"-1"}}){%endif%} </span></a> 111 <a href="{% url "builddashboard" br.id %}"><span data-toggle="tooltip" {%if br.brtarget_set.all.count > 1%}title="Targets: {%for target in br.brtarget_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{br.brtarget_set.all.0.target}} {%if br.brtarget_set.all.count > 1%}(+ {{br.brtarget_set.all.count|add:"-1"}}){%endif%} </span></a>
117 </td> 112 </td>
118 <td class="machine"> 113 <td class="machine">
119 <a href="{% url "buildrequestdetails" br.project.id br.id %}">{{br.machine}}</a> 114 <a href="{% url "builddashboard" br.id %}">{{br.machine}}</a>
120 </td> 115 </td>
121 <td class="started_on"> 116 <td class="started_on">
122 <a href="{% url "buildrequestdetails" br.project.id br.id %}">{{br.created|date:"d/m/y H:i"}}</a> 117 <a href="{% url "builddashboard" br.id %}">{{br.created|date:"d/m/y H:i"}}</a>
123 </td> 118 </td>
124 <td class="completed_on"> 119 <td class="completed_on">
125 <a href="{% url "buildrequestdetails" br.project.id br.id %}">{{br.updated|date:"d/m/y H:i"}}</a> 120 <a href="{% url "builddashboard" br.id %}">{{br.updated|date:"d/m/y H:i"}}</a>
126 </td> 121 </td>
127 <td class="failed_tasks error"> 122 <td class="failed_tasks error">
128 </td> 123 </td>
129 <td class="errors_no"> 124 <td class="errors.count">
130 <a class="errors_no error" href="{% url "buildrequestdetails" br.project.id br.id %}#errors">{{br.brerror_set.all.count}} error{{br.brerror_set.all.count|pluralize}}</a> 125 <a class="errors.count error" href="{% url "builddashboard" br.id %}#errors">{{br.brerror_set.all.count}} error{{br.brerror_set.all.count|pluralize}}</a>
131 </td> 126 </td>
132 <td class="warnings_no"> 127 <td class="warnings.count">
133 </td> 128 </td>
134 <td class="time"> 129 <td class="time">
135 {{br.timespent.total_seconds|sectohms}} 130 {{br.timespent.total_seconds|sectohms}}
diff --git a/bitbake/lib/toaster/toastergui/templates/projects.html b/bitbake/lib/toaster/toastergui/templates/projects.html
index 9c4346c45a..e6519530ef 100644
--- a/bitbake/lib/toaster/toastergui/templates/projects.html
+++ b/bitbake/lib/toaster/toastergui/templates/projects.html
@@ -26,7 +26,10 @@
26 <div class="row-fluid"> 26 <div class="row-fluid">
27 <div class="alert"> 27 <div class="alert">
28 <form class="no-results input-append" id="searchform"> 28 <form class="no-results input-append" id="searchform">
29 <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %} 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 %}
30 <button class="btn" type="submit" value="Search">Search</button> 33 <button class="btn" type="submit" value="Search">Search</button>
31 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all projects</button> 34 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all projects</button>
32 </form> 35 </form>
@@ -58,8 +61,8 @@
58 <td><a href="{% url 'projectbuilds' o.id %}">{{o.get_number_of_builds}}</a></td> 61 <td><a href="{% url 'projectbuilds' o.id %}">{{o.get_number_of_builds}}</a></td>
59 <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> 62 <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>
60 <td class="ltarget"><a href="{% url "builddashboard" o.get_last_build_id %}">{{o.get_last_target}} </a></td> 63 <td class="ltarget"><a href="{% url "builddashboard" o.get_last_build_id %}">{{o.get_last_target}} </a></td>
61 <td class="lerrors">{% if o.get_last_errors %}<a class="errors_no error" href="{% url "builddashboard" o.get_last_build_id %}#errors">{{o.get_last_errors}} error{{o.get_last_errors|pluralize}}</a>{%endif%}</td> 64 <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>
62 <td class="lwarnings">{% if o.get_last_warnings %}<a class="warnings_no warning" href="{% url "builddashboard" o.get_last_build_id %}#warnings">{{o.get_last_warnings}} warning{{o.get_last_warnings|pluralize}}</a>{%endif%}</td> 65 <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>
63 <td class="limagefiles"> 66 <td class="limagefiles">
64 {% if o.get_last_outcome == build_SUCCEEDED %} 67 {% if o.get_last_outcome == build_SUCCEEDED %}
65 <a href="{%url "builddashboard" o.get_last_build_id %}#images">{{fstypes|get_dict_value:o.id}}</a> 68 <a href="{%url "builddashboard" o.get_last_build_id %}#images">{{fstypes|get_dict_value:o.id}}</a>
diff --git a/bitbake/lib/toaster/toastergui/templates/recipe.html b/bitbake/lib/toaster/toastergui/templates/recipe.html
index dd8753d7fc..b5e4192d6b 100644
--- a/bitbake/lib/toaster/toastergui/templates/recipe.html
+++ b/bitbake/lib/toaster/toastergui/templates/recipe.html
@@ -53,13 +53,6 @@
53 </dt> 53 </dt>
54 <dd>{{layer.name}}</dd> 54 <dd>{{layer.name}}</dd>
55 55
56 {% if not MANAGED or not build.project %}
57 <dt>
58 <i class="icon-question-sign get-help" title="Path to the layer providing the recipe"></i>
59 Layer directory
60 </dt>
61 <dd><code>{{object.layer_version.local_path}}</code></dd>
62 {% endif %}
63 <dt> 56 <dt>
64 <i class="icon-question-sign get-help" title="Path to the recipe .bb file"></i> 57 <i class="icon-question-sign get-help" title="Path to the recipe .bb file"></i>
65 Recipe file 58 Recipe file
@@ -126,7 +119,7 @@
126 119
127 <td> 120 <td>
128 <a {{ task|task_color }} href="{% url "task" build.pk task.pk %}">{{task.get_outcome_display}} </a> 121 <a {{ task|task_color }} href="{% url "task" build.pk task.pk %}">{{task.get_outcome_display}} </a>
129 {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %} 122 {% if task.outcome = task.OUTCOME_FAILED %}
130 <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}"> 123 <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
131 <i class="icon-download-alt" title="Download task log file"></i> 124 <i class="icon-download-alt" title="Download task log file"></i>
132 </a> 125 </a>
diff --git a/bitbake/lib/toaster/toastergui/templates/recipes.html b/bitbake/lib/toaster/toastergui/templates/recipes.html
index 8d4494e7ef..5cdac437c4 100644
--- a/bitbake/lib/toaster/toastergui/templates/recipes.html
+++ b/bitbake/lib/toaster/toastergui/templates/recipes.html
@@ -28,7 +28,7 @@
28 <div class="row-fluid"> 28 <div class="row-fluid">
29 <div class="alert"> 29 <div class="alert">
30 <form class="no-results input-append" id="searchform"> 30 <form class="no-results input-append" id="searchform">
31 <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %} 31 <input id="search" name="search" class="input-xxlarge" type="text" value="{%if request.GET.search%}{{request.GET.search}}{%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 %}
32 <button class="btn" type="submit" value="Search">Search</button> 32 <button class="btn" type="submit" value="Search">Search</button>
33 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all recipes</button> 33 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all recipes</button>
34 </form> 34 </form>
@@ -102,11 +102,6 @@
102 {{recipe.layer_version.commit|truncatechars:13}} 102 {{recipe.layer_version.commit|truncatechars:13}}
103 </a> 103 </a>
104 </td> 104 </td>
105
106 {% if not MANAGED or not build.project %}
107 <!-- Layer directory -->
108 <td class="layer_version__local_path">{{recipe.layer_version.local_path}}</td>
109 {% endif %}
110 </tr> 105 </tr>
111 106
112 {% endfor %} 107 {% endfor %}
diff --git a/bitbake/lib/toaster/toastergui/templates/runagain.html b/bitbake/lib/toaster/toastergui/templates/runagain.html
deleted file mode 100644
index b4ba5fbf15..0000000000
--- a/bitbake/lib/toaster/toastergui/templates/runagain.html
+++ /dev/null
@@ -1,7 +0,0 @@
1{% load projecttags %}
2onclick='scheduleBuild(
3 {% url 'projectbuilds' buildrequest.project.id as bpi %}{{bpi|json}},
4 {{buildrequest.project.name|json}},
5 {% url 'project' buildrequest.project.id as bpurl %}{{bpurl|json}},
6 {{buildrequest.brtarget_set.all|get_tasks|json}})
7'>Run again
diff --git a/bitbake/lib/toaster/toastergui/templates/target.html b/bitbake/lib/toaster/toastergui/templates/target.html
index e7febaf22a..fa59f4eeba 100644
--- a/bitbake/lib/toaster/toastergui/templates/target.html
+++ b/bitbake/lib/toaster/toastergui/templates/target.html
@@ -152,11 +152,6 @@
152 {{package.recipe.layer_version.commit|truncatechars:13}} 152 {{package.recipe.layer_version.commit|truncatechars:13}}
153 </a> 153 </a>
154 </td> 154 </td>
155 {% if not MANAGED or not build.project %}
156 <td class="layer_directory">
157 {{ package.recipe.layer_version.local_path }}
158 </td>
159 {% endif %}
160 </tr> 155 </tr>
161 {% endfor %} 156 {% endfor %}
162 157
diff --git a/bitbake/lib/toaster/toastergui/templates/task.html b/bitbake/lib/toaster/toastergui/templates/task.html
index 6e06ddfa31..635098a024 100644
--- a/bitbake/lib/toaster/toastergui/templates/task.html
+++ b/bitbake/lib/toaster/toastergui/templates/task.html
@@ -23,18 +23,7 @@
23{%if task.task_executed %} 23{%if task.task_executed %}
24 {# executed tasks outcome #} 24 {# executed tasks outcome #}
25 {% if task.logfile %} 25 {% if task.logfile %}
26 {% if MANAGED and build.project %}
27 <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download task log</a> 26 <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download task log</a>
28 {% else %}
29 <dl class="dl-horizontal">
30 <dt>
31 <i class="icon-question-sign get-help" title="Path the task log file"></i> Log file
32 </dt>
33 <dd>
34 <code>{{task.logfile}}</code>
35 </dd>
36 </dl>
37 {% endif %}
38 {% endif %} 27 {% endif %}
39 {# show stack trace for failed task #} 28 {# show stack trace for failed task #}
40 {% if task.outcome == task.OUTCOME_FAILED and log_head %} 29 {% if task.outcome == task.OUTCOME_FAILED and log_head %}
@@ -130,22 +119,12 @@
130 </dd> 119 </dd>
131 </dl> 120 </dl>
132 {%elif task.outcome == task.OUTCOME_CACHED%} 121 {%elif task.outcome == task.OUTCOME_CACHED%}
133 {% if MANAGED and build.project %}
134 {% for t in task.get_related_setscene %} 122 {% for t in task.get_related_setscene %}
135 {% if forloop.last %} 123 {% if forloop.last %}
136 <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" t.pk %}" style="margin:15px;">Download task log</a> 124 <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" t.pk %}" style="margin:15px;">Download task log</a>
137 {% endif %} 125 {% endif %}
138 {% endfor %} 126 {% endfor %}
139 {% else %} 127
140 <dl class="dl-horizontal">
141 <dt>
142 <i class="icon-question-sign get-help" title="Path the task log file"></i> Log file
143 </dt>
144 <dd>
145 <code>{% for t in task.get_related_setscene %} {{t.logfile}} {% endfor %}</code>
146 </dd>
147 </dl>
148 {% endif %}
149 {%elif task.outcome == task.OUTCOME_EMPTY%} 128 {%elif task.outcome == task.OUTCOME_EMPTY%}
150 <div class="alert alert-info details"> 129 <div class="alert alert-info details">
151 This task is empty because it has the <code>noexec</code> flag set to <code>1</code>, or the task function is empty 130 This task is empty because it has the <code>noexec</code> flag set to <code>1</code>, or the task function is empty
@@ -200,20 +179,7 @@
200 <strong>Failed</strong> to restore output from sstate cache. The file was found but could not be unpacked. 179 <strong>Failed</strong> to restore output from sstate cache. The file was found but could not be unpacked.
201 </div> 180 </div>
202 <dl class="dl-horizontal"> 181 <dl class="dl-horizontal">
203 {% if MANAGED and build.project %}
204 <a href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download log</a> 182 <a href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download log</a>
205 {% else %}
206 <dt>
207 <i class="icon-question-sign get-help" title="Path to the cache attempt log file"></i>
208 Log file
209 </dt>
210 <dd><code>{{task.logfile}}</code></dd>
211 <dt>
212 <i class="icon-question-sign get-help" title="How long it took the cache attempt to finish in seconds"></i>
213 Time (secs)
214 </dt>
215 <dd>{{task.elapsed_time|format_none_and_zero}}</dd>
216 {% endif %}
217 </dl> 183 </dl>
218 <div class="alert alert-info"> 184 <div class="alert alert-info">
219 Running the real task instead. 185 Running the real task instead.
diff --git a/bitbake/lib/toaster/toastergui/templates/tasks.html b/bitbake/lib/toaster/toastergui/templates/tasks.html
index 32c0552360..b18b5c7c46 100644
--- a/bitbake/lib/toaster/toastergui/templates/tasks.html
+++ b/bitbake/lib/toaster/toastergui/templates/tasks.html
@@ -93,7 +93,7 @@
93 </td> 93 </td>
94 <td class="outcome"> 94 <td class="outcome">
95 <a href="{%url "task" build.pk task.pk%}">{{task.get_outcome_display}} </a> 95 <a href="{%url "task" build.pk task.pk%}">{{task.get_outcome_display}} </a>
96 {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %} 96 {% if task.outcome = task.OUTCOME_FAILED %}
97 <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}"> 97 <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
98 <i class="icon-download-alt" title="Download task log file"></i> 98 <i class="icon-download-alt" title="Download task log file"></i>
99 </a> 99 </a>
@@ -113,11 +113,6 @@
113 {{task.disk_io|format_none_and_zero}} 113 {{task.disk_io|format_none_and_zero}}
114 </td> 114 </td>
115 115
116 {% if not MANAGED or not build.project %}
117 <td class="task_log">
118 {{task.logfile}}
119 </td>
120 {% endif %}
121 </tr> 116 </tr>
122 {% endfor %} 117 {% endfor %}
123 118
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index 681f06787a..feb15139fb 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -131,9 +131,6 @@ urlpatterns = patterns('toastergui.views',
131 url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'), 131 url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'),
132 url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'), 132 url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'),
133 133
134 # dashboard for failed build requests
135 url(r'^project/(?P<pid>\d+)/buildrequest/(?P<bid>\d+)$', 'buildrequestdetails', name='buildrequestdetails'),
136
137 # default redirection 134 # default redirection
138 url(r'^$', RedirectView.as_view( url= 'landing')), 135 url(r'^$', RedirectView.as_view( url= 'landing')),
139) 136)
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 00b1387d63..8c6f9fa84f 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -21,7 +21,7 @@
21 21
22import operator,re 22import operator,re
23 23
24from django.db.models import Q, Sum, Count, Max 24from django.db.models import F, Q, Sum, Count, Max
25from django.db import IntegrityError 25from django.db import IntegrityError
26from django.shortcuts import render, redirect 26from django.shortcuts import render, redirect
27from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable 27from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
@@ -81,15 +81,15 @@ def _project_recent_build_list(prj):
81 "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))), 81 "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))),
82 "updated": x.completed_on.strftime('%s')+"000", 82 "updated": x.completed_on.strftime('%s')+"000",
83 "command_time": (x.completed_on - x.started_on).total_seconds(), 83 "command_time": (x.completed_on - x.started_on).total_seconds(),
84 "br_page_url": reverse('buildrequestdetails', args=(x.project.id, x.pk) ), 84 "br_page_url": reverse('builddashboard', args=(x.pk,) ),
85 "build" : map( lambda y: {"id": y.pk, 85 "build" : map( lambda y: {"id": y.pk,
86 "status": y.get_outcome_display(), 86 "status": y.get_outcome_display(),
87 "completed_on" : y.completed_on.strftime('%s')+"000", 87 "completed_on" : y.completed_on.strftime('%s')+"000",
88 "build_time" : (y.completed_on - y.started_on).total_seconds(), 88 "build_time" : (y.completed_on - y.started_on).total_seconds(),
89 "build_page_url" : reverse('builddashboard', args=(y.pk,)), 89 "build_page_url" : reverse('builddashboard', args=(y.pk,)),
90 'build_time_page_url': reverse('buildtime', args=(y.pk,)), 90 'build_time_page_url': reverse('buildtime', args=(y.pk,)),
91 "errors": y.errors_no, 91 "errors": y.errors.count(),
92 "warnings": y.warnings_no, 92 "warnings": y.warnings.count(),
93 "completeper": y.completeper() if y.outcome == Build.IN_PROGRESS else "0", 93 "completeper": y.completeper() if y.outcome == Build.IN_PROGRESS else "0",
94 "eta": y.eta().strftime('%s')+"000" if y.outcome == Build.IN_PROGRESS else "0", 94 "eta": y.eta().strftime('%s')+"000" if y.outcome == Build.IN_PROGRESS else "0",
95 }, [x]), 95 }, [x]),
@@ -1906,7 +1906,7 @@ if True:
1906 (filter_string, search_term, ordering_string) = _search_tuple(request, Build) 1906 (filter_string, search_term, ordering_string) = _search_tuple(request, Build)
1907 # post-process any date range filters 1907 # post-process any date range filters
1908 filter_string,daterange_selected = _modify_date_range_filter(filter_string) 1908 filter_string,daterange_selected = _modify_date_range_filter(filter_string)
1909 queryset_all = queryset_all.select_related("project") 1909 queryset_all = queryset_all.select_related("project").annotate(errors_no = Count('logmessage', only=Q(logmessage__level=LogMessage.ERROR)|Q(logmessage__level=LogMessage.EXCEPTION))).annotate(warnings_no = Count('logmessage', only=Q(logmessage__level=LogMessage.WARNING))).extra(select={'timespent':'completed_on - started_on'})
1910 queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on') 1910 queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on')
1911 queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on') 1911 queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on')
1912 1912
@@ -2841,10 +2841,3 @@ if True:
2841 2841
2842 _set_parameters_values(pagesize, orderby, request) 2842 _set_parameters_values(pagesize, orderby, request)
2843 return context 2843 return context
2844
2845 @_template_renderer("buildrequestdetails.html")
2846 def buildrequestdetails(request, pid, bid):
2847 context = {
2848 'buildrequest' : Build.objects.get(pk = bid, project_id = pid).buildrequest
2849 }
2850 return context