diff options
12 files changed, 473 insertions, 47 deletions
diff --git a/bitbake/lib/bb/ui/buildinfohelper.py b/bitbake/lib/bb/ui/buildinfohelper.py index b90e915a1a..3b4d7c9c10 100644 --- a/bitbake/lib/bb/ui/buildinfohelper.py +++ b/bitbake/lib/bb/ui/buildinfohelper.py | |||
@@ -75,6 +75,7 @@ class ORMWrapper(object): | |||
75 | outcome = Build.FAILED | 75 | outcome = Build.FAILED |
76 | 76 | ||
77 | build.completed_on = datetime.datetime.now() | 77 | build.completed_on = datetime.datetime.now() |
78 | build.timespent = int((build.completed_on - build.started_on).total_seconds()) | ||
78 | build.errors_no = errors | 79 | build.errors_no = errors |
79 | build.warnings_no = warnings | 80 | build.warnings_no = warnings |
80 | build.outcome = outcome | 81 | build.outcome = outcome |
@@ -387,7 +388,7 @@ class BuildInfoHelper(object): | |||
387 | for i in string.split(): | 388 | for i in string.split(): |
388 | if i not in ret: | 389 | if i not in ret: |
389 | ret.append(i) | 390 | ret.append(i) |
390 | return " ".join(ret) | 391 | return " ".join(sorted(ret)) |
391 | 392 | ||
392 | 393 | ||
393 | ################################ | 394 | ################################ |
diff --git a/bitbake/lib/toaster/orm/migrations/0002_auto__add_field_build_timespent.py b/bitbake/lib/toaster/orm/migrations/0002_auto__add_field_build_timespent.py new file mode 100644 index 0000000000..c01b50ae7d --- /dev/null +++ b/bitbake/lib/toaster/orm/migrations/0002_auto__add_field_build_timespent.py | |||
@@ -0,0 +1,180 @@ | |||
1 | # -*- coding: utf-8 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import SchemaMigration | ||
5 | from django.db import models | ||
6 | |||
7 | |||
8 | class Migration(SchemaMigration): | ||
9 | |||
10 | def forwards(self, orm): | ||
11 | # Adding field 'Build.timespent' | ||
12 | db.add_column(u'orm_build', 'timespent', | ||
13 | self.gf('django.db.models.fields.IntegerField')(default=0), | ||
14 | keep_default=False) | ||
15 | |||
16 | |||
17 | def backwards(self, orm): | ||
18 | # Deleting field 'Build.timespent' | ||
19 | db.delete_column(u'orm_build', 'timespent') | ||
20 | |||
21 | |||
22 | models = { | ||
23 | u'orm.build': { | ||
24 | 'Meta': {'object_name': 'Build'}, | ||
25 | 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}), | ||
26 | 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
27 | 'completed_on': ('django.db.models.fields.DateTimeField', [], {}), | ||
28 | 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}), | ||
29 | 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
30 | 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
31 | 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
32 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
33 | 'image_fstypes': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
34 | 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
35 | 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}), | ||
36 | 'started_on': ('django.db.models.fields.DateTimeField', [], {}), | ||
37 | 'timespent': ('django.db.models.fields.IntegerField', [], {}), | ||
38 | 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}) | ||
39 | }, | ||
40 | u'orm.layer': { | ||
41 | 'Meta': {'object_name': 'Layer'}, | ||
42 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
43 | 'layer_index_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), | ||
44 | 'local_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}), | ||
45 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
46 | }, | ||
47 | u'orm.layer_version': { | ||
48 | 'Meta': {'object_name': 'Layer_Version'}, | ||
49 | 'branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}), | ||
50 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_build'", 'to': u"orm['orm.Build']"}), | ||
51 | 'commit': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
52 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
53 | 'layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_layer'", 'to': u"orm['orm.Layer']"}), | ||
54 | 'priority': ('django.db.models.fields.IntegerField', [], {}) | ||
55 | }, | ||
56 | u'orm.logmessage': { | ||
57 | 'Meta': {'object_name': 'LogMessage'}, | ||
58 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}), | ||
59 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
60 | 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
61 | 'lineno': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
62 | 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}), | ||
63 | 'pathname': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}) | ||
64 | }, | ||
65 | u'orm.package': { | ||
66 | 'Meta': {'object_name': 'Package'}, | ||
67 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}), | ||
68 | 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), | ||
69 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
70 | 'installed_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
71 | 'license': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), | ||
72 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
73 | 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Recipe']", 'null': 'True'}), | ||
74 | 'revision': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), | ||
75 | 'section': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), | ||
76 | 'size': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
77 | 'summary': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), | ||
78 | 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}) | ||
79 | }, | ||
80 | u'orm.package_dependency': { | ||
81 | 'Meta': {'object_name': 'Package_Dependency'}, | ||
82 | 'dep_type': ('django.db.models.fields.IntegerField', [], {}), | ||
83 | 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_target'", 'to': u"orm['orm.Package']"}), | ||
84 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
85 | 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_source'", 'to': u"orm['orm.Package']"}), | ||
86 | 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']", 'null': 'True'}) | ||
87 | }, | ||
88 | u'orm.package_file': { | ||
89 | 'Meta': {'object_name': 'Package_File'}, | ||
90 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
91 | 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildfilelist_package'", 'to': u"orm['orm.Package']"}), | ||
92 | 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}), | ||
93 | 'size': ('django.db.models.fields.IntegerField', [], {}) | ||
94 | }, | ||
95 | u'orm.recipe': { | ||
96 | 'Meta': {'object_name': 'Recipe'}, | ||
97 | 'bugtracker': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), | ||
98 | 'description': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
99 | 'file_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}), | ||
100 | 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), | ||
101 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
102 | 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recipe_layer_version'", 'to': u"orm['orm.Layer_Version']"}), | ||
103 | 'license': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), | ||
104 | 'licensing_info': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
105 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
106 | 'section': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
107 | 'summary': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
108 | 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}) | ||
109 | }, | ||
110 | u'orm.recipe_dependency': { | ||
111 | 'Meta': {'object_name': 'Recipe_Dependency'}, | ||
112 | 'dep_type': ('django.db.models.fields.IntegerField', [], {}), | ||
113 | 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_depends'", 'to': u"orm['orm.Recipe']"}), | ||
114 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
115 | 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_recipe'", 'to': u"orm['orm.Recipe']"}) | ||
116 | }, | ||
117 | u'orm.target': { | ||
118 | 'Meta': {'object_name': 'Target'}, | ||
119 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}), | ||
120 | 'file_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
121 | 'file_size': ('django.db.models.fields.IntegerField', [], {}), | ||
122 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
123 | 'is_image': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
124 | 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
125 | }, | ||
126 | u'orm.target_installed_package': { | ||
127 | 'Meta': {'object_name': 'Target_Installed_Package'}, | ||
128 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
129 | 'package': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Package']"}), | ||
130 | 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"}) | ||
131 | }, | ||
132 | u'orm.task': { | ||
133 | 'Meta': {'ordering': "('order', 'recipe')", 'object_name': 'Task'}, | ||
134 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_build'", 'to': u"orm['orm.Build']"}), | ||
135 | 'cpu_usage': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '6', 'decimal_places': '2'}), | ||
136 | 'disk_io': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
137 | 'elapsed_time': ('django.db.models.fields.CharField', [], {'default': '0', 'max_length': '50'}), | ||
138 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
139 | 'line_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
140 | 'logfile': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}), | ||
141 | 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}), | ||
142 | 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
143 | 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '5'}), | ||
144 | 'path_to_sstate_obj': ('django.db.models.fields.FilePathField', [], {'max_length': '500', 'blank': 'True'}), | ||
145 | 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'build_recipe'", 'to': u"orm['orm.Recipe']"}), | ||
146 | 'script_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
147 | 'source_url': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}), | ||
148 | 'sstate_checksum': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
149 | 'sstate_result': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
150 | 'task_executed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
151 | 'task_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
152 | 'work_directory': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}) | ||
153 | }, | ||
154 | u'orm.task_dependency': { | ||
155 | 'Meta': {'object_name': 'Task_Dependency'}, | ||
156 | 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_depends'", 'to': u"orm['orm.Task']"}), | ||
157 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
158 | 'task': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_task'", 'to': u"orm['orm.Task']"}) | ||
159 | }, | ||
160 | u'orm.variable': { | ||
161 | 'Meta': {'object_name': 'Variable'}, | ||
162 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variable_build'", 'to': u"orm['orm.Build']"}), | ||
163 | 'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
164 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
165 | 'human_readable_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), | ||
166 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
167 | 'variable_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
168 | 'variable_value': ('django.db.models.fields.TextField', [], {'blank': 'True'}) | ||
169 | }, | ||
170 | u'orm.variablehistory': { | ||
171 | 'Meta': {'object_name': 'VariableHistory'}, | ||
172 | 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}), | ||
173 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
174 | 'line_number': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
175 | 'operation': ('django.db.models.fields.CharField', [], {'max_length': '16'}), | ||
176 | 'variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vhistory'", 'to': u"orm['orm.Variable']"}) | ||
177 | } | ||
178 | } | ||
179 | |||
180 | complete_apps = ['orm'] \ No newline at end of file | ||
diff --git a/bitbake/lib/toaster/orm/migrations/0003_timespent.py b/bitbake/lib/toaster/orm/migrations/0003_timespent.py new file mode 100644 index 0000000000..9600f9e296 --- /dev/null +++ b/bitbake/lib/toaster/orm/migrations/0003_timespent.py | |||
@@ -0,0 +1,182 @@ | |||
1 | # -*- coding: utf-8 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import DataMigration | ||
5 | from django.db import models | ||
6 | |||
7 | class Migration(DataMigration): | ||
8 | |||
9 | def forwards(self, orm): | ||
10 | "Write your forwards methods here." | ||
11 | # Note: Don't use "from appname.models import ModelName". | ||
12 | # Use orm.ModelName to refer to models in this application, | ||
13 | # and orm['appname.ModelName'] for models in other applications. | ||
14 | |||
15 | for build in orm.Build.objects.all(): | ||
16 | build.timespent = int((build.completed_on - build.started_on).total_seconds()) | ||
17 | build.save() | ||
18 | |||
19 | def backwards(self, orm): | ||
20 | "Write your backwards methods here." | ||
21 | raise RuntimeError("Cannot reverse this migration.") | ||
22 | |||
23 | models = { | ||
24 | u'orm.build': { | ||
25 | 'Meta': {'object_name': 'Build'}, | ||
26 | 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}), | ||
27 | 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
28 | 'completed_on': ('django.db.models.fields.DateTimeField', [], {}), | ||
29 | 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}), | ||
30 | 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
31 | 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
32 | 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
33 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
34 | 'image_fstypes': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
35 | 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
36 | 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}), | ||
37 | 'started_on': ('django.db.models.fields.DateTimeField', [], {}), | ||
38 | 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
39 | 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}) | ||
40 | }, | ||
41 | u'orm.layer': { | ||
42 | 'Meta': {'object_name': 'Layer'}, | ||
43 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
44 | 'layer_index_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), | ||
45 | 'local_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}), | ||
46 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
47 | }, | ||
48 | u'orm.layer_version': { | ||
49 | 'Meta': {'object_name': 'Layer_Version'}, | ||
50 | 'branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}), | ||
51 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_build'", 'to': u"orm['orm.Build']"}), | ||
52 | 'commit': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
53 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
54 | 'layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_layer'", 'to': u"orm['orm.Layer']"}), | ||
55 | 'priority': ('django.db.models.fields.IntegerField', [], {}) | ||
56 | }, | ||
57 | u'orm.logmessage': { | ||
58 | 'Meta': {'object_name': 'LogMessage'}, | ||
59 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}), | ||
60 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
61 | 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
62 | 'lineno': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
63 | 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}), | ||
64 | 'pathname': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}) | ||
65 | }, | ||
66 | u'orm.package': { | ||
67 | 'Meta': {'object_name': 'Package'}, | ||
68 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}), | ||
69 | 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), | ||
70 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
71 | 'installed_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
72 | 'license': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), | ||
73 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
74 | 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Recipe']", 'null': 'True'}), | ||
75 | 'revision': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), | ||
76 | 'section': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), | ||
77 | 'size': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
78 | 'summary': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), | ||
79 | 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}) | ||
80 | }, | ||
81 | u'orm.package_dependency': { | ||
82 | 'Meta': {'object_name': 'Package_Dependency'}, | ||
83 | 'dep_type': ('django.db.models.fields.IntegerField', [], {}), | ||
84 | 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_target'", 'to': u"orm['orm.Package']"}), | ||
85 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
86 | 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_source'", 'to': u"orm['orm.Package']"}), | ||
87 | 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']", 'null': 'True'}) | ||
88 | }, | ||
89 | u'orm.package_file': { | ||
90 | 'Meta': {'object_name': 'Package_File'}, | ||
91 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
92 | 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildfilelist_package'", 'to': u"orm['orm.Package']"}), | ||
93 | 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}), | ||
94 | 'size': ('django.db.models.fields.IntegerField', [], {}) | ||
95 | }, | ||
96 | u'orm.recipe': { | ||
97 | 'Meta': {'object_name': 'Recipe'}, | ||
98 | 'bugtracker': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), | ||
99 | 'description': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
100 | 'file_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}), | ||
101 | 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), | ||
102 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
103 | 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recipe_layer_version'", 'to': u"orm['orm.Layer_Version']"}), | ||
104 | 'license': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), | ||
105 | 'licensing_info': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
106 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
107 | 'section': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
108 | 'summary': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
109 | 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}) | ||
110 | }, | ||
111 | u'orm.recipe_dependency': { | ||
112 | 'Meta': {'object_name': 'Recipe_Dependency'}, | ||
113 | 'dep_type': ('django.db.models.fields.IntegerField', [], {}), | ||
114 | 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_depends'", 'to': u"orm['orm.Recipe']"}), | ||
115 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
116 | 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_recipe'", 'to': u"orm['orm.Recipe']"}) | ||
117 | }, | ||
118 | u'orm.target': { | ||
119 | 'Meta': {'object_name': 'Target'}, | ||
120 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}), | ||
121 | 'file_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
122 | 'file_size': ('django.db.models.fields.IntegerField', [], {}), | ||
123 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
124 | 'is_image': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
125 | 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
126 | }, | ||
127 | u'orm.target_installed_package': { | ||
128 | 'Meta': {'object_name': 'Target_Installed_Package'}, | ||
129 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
130 | 'package': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Package']"}), | ||
131 | 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"}) | ||
132 | }, | ||
133 | u'orm.task': { | ||
134 | 'Meta': {'ordering': "('order', 'recipe')", 'object_name': 'Task'}, | ||
135 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_build'", 'to': u"orm['orm.Build']"}), | ||
136 | 'cpu_usage': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '6', 'decimal_places': '2'}), | ||
137 | 'disk_io': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
138 | 'elapsed_time': ('django.db.models.fields.CharField', [], {'default': '0', 'max_length': '50'}), | ||
139 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
140 | 'line_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
141 | 'logfile': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}), | ||
142 | 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}), | ||
143 | 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
144 | 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '5'}), | ||
145 | 'path_to_sstate_obj': ('django.db.models.fields.FilePathField', [], {'max_length': '500', 'blank': 'True'}), | ||
146 | 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'build_recipe'", 'to': u"orm['orm.Recipe']"}), | ||
147 | 'script_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
148 | 'source_url': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}), | ||
149 | 'sstate_checksum': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), | ||
150 | 'sstate_result': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
151 | 'task_executed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
152 | 'task_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
153 | 'work_directory': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}) | ||
154 | }, | ||
155 | u'orm.task_dependency': { | ||
156 | 'Meta': {'object_name': 'Task_Dependency'}, | ||
157 | 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_depends'", 'to': u"orm['orm.Task']"}), | ||
158 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
159 | 'task': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_task'", 'to': u"orm['orm.Task']"}) | ||
160 | }, | ||
161 | u'orm.variable': { | ||
162 | 'Meta': {'object_name': 'Variable'}, | ||
163 | 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variable_build'", 'to': u"orm['orm.Build']"}), | ||
164 | 'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
165 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
166 | 'human_readable_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), | ||
167 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
168 | 'variable_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
169 | 'variable_value': ('django.db.models.fields.TextField', [], {'blank': 'True'}) | ||
170 | }, | ||
171 | u'orm.variablehistory': { | ||
172 | 'Meta': {'object_name': 'VariableHistory'}, | ||
173 | 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}), | ||
174 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
175 | 'line_number': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), | ||
176 | 'operation': ('django.db.models.fields.CharField', [], {'max_length': '16'}), | ||
177 | 'variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vhistory'", 'to': u"orm['orm.Variable']"}) | ||
178 | } | ||
179 | } | ||
180 | |||
181 | complete_apps = ['orm'] | ||
182 | symmetrical = True | ||
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index 3a4f2fb884..81dae48e10 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
@@ -43,6 +43,7 @@ class Build(models.Model): | |||
43 | distro_version = models.CharField(max_length=100) | 43 | distro_version = models.CharField(max_length=100) |
44 | started_on = models.DateTimeField() | 44 | started_on = models.DateTimeField() |
45 | completed_on = models.DateTimeField() | 45 | completed_on = models.DateTimeField() |
46 | timespent = models.IntegerField(default=0) | ||
46 | outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS) | 47 | outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS) |
47 | errors_no = models.IntegerField(default=0) | 48 | errors_no = models.IntegerField(default=0) |
48 | warnings_no = models.IntegerField(default=0) | 49 | warnings_no = models.IntegerField(default=0) |
@@ -231,7 +232,7 @@ class Layer_Version(models.Model): | |||
231 | 232 | ||
232 | class Variable(models.Model): | 233 | class Variable(models.Model): |
233 | search_allowed_fields = ['variable_name', 'variable_value', | 234 | search_allowed_fields = ['variable_name', 'variable_value', |
234 | 'variablehistory__file_name', "description"] | 235 | 'vhistory__file_name', "description"] |
235 | build = models.ForeignKey(Build, related_name='variable_build') | 236 | build = models.ForeignKey(Build, related_name='variable_build') |
236 | variable_name = models.CharField(max_length=100) | 237 | variable_name = models.CharField(max_length=100) |
237 | variable_value = models.TextField(blank=True) | 238 | variable_value = models.TextField(blank=True) |
diff --git a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html index 7d2a1f388e..c85faf9f6a 100644 --- a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html +++ b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html | |||
@@ -8,7 +8,7 @@ | |||
8 | <div class="section"> | 8 | <div class="section"> |
9 | <ul class="breadcrumb" id="breadcrumb"> | 9 | <ul class="breadcrumb" id="breadcrumb"> |
10 | <li><a href="{% url 'all-builds' %}">All builds</a></li> | 10 | <li><a href="{% url 'all-builds' %}">All builds</a></li> |
11 | <li><a href="{%url 'builddashboard' build.pk%}">{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|naturaltime}})</a></li> | 11 | <li><a href="{%url 'builddashboard' build.pk%}">{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})</a></li> |
12 | {% block localbreadcrumb %}{% endblock %} | 12 | {% block localbreadcrumb %}{% endblock %} |
13 | </ul> | 13 | </ul> |
14 | <script> | 14 | <script> |
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html index 3e4b0cc5a4..8f81472723 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html | |||
@@ -38,6 +38,21 @@ | |||
38 | <script> | 38 | <script> |
39 | $(document).ready(function() { | 39 | $(document).ready(function() { |
40 | 40 | ||
41 | // we load cookies for the column display | ||
42 | save = $.cookie('_displaycols_{{objectname}}'); | ||
43 | setting = save.split(';'); | ||
44 | for ( i = 0; i < setting.length; i++) { | ||
45 | if (setting[i].length > 0) { | ||
46 | [id, v] = setting[i].split(':'); | ||
47 | if (v == 'true') { | ||
48 | $('.chbxtoggle#'+id).prop('checked', true); | ||
49 | } | ||
50 | else { | ||
51 | $('.chbxtoggle#'+id).prop('checked', false); | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | |||
41 | $('.chbxtoggle').each(function () { | 56 | $('.chbxtoggle').each(function () { |
42 | showhideTableColumn($(this).attr('id'), $(this).is(':checked')) | 57 | showhideTableColumn($(this).attr('id'), $(this).is(':checked')) |
43 | }); | 58 | }); |
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_top.html b/bitbake/lib/toaster/toastergui/templates/basetable_top.html index 34e0cd7210..b8d5c382c7 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_top.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_top.html | |||
@@ -1,8 +1,15 @@ | |||
1 | {% load projecttags %} | ||
1 | <!-- component to display a generic table --> | 2 | <!-- component to display a generic table --> |
2 | <script> | 3 | <script> |
3 | function showhideTableColumn(clname, sh) { | 4 | function showhideTableColumn(clname, sh) { |
4 | if (sh) $('.' + clname).show(); | 5 | if (sh) $('.' + clname).show(100); |
5 | else $('.' + clname).hide(); | 6 | else $('.' + clname).hide(100); |
7 | |||
8 | // save cookie for all checkboxes | ||
9 | save = ''; | ||
10 | $('.chbxtoggle').each(function() { if ($(this).attr('id') != undefined) { save += ';' + $(this).attr('id') +':'+ $(this).is(':checked')} }) | ||
11 | $.cookie('_displaycols_{{objectname}}', save); | ||
12 | save = ''; | ||
6 | } | 13 | } |
7 | 14 | ||
8 | 15 | ||
@@ -22,8 +29,11 @@ | |||
22 | <!-- control header --> | 29 | <!-- control header --> |
23 | <div class="navbar"> | 30 | <div class="navbar"> |
24 | <div class="navbar-inner"> | 31 | <div class="navbar-inner"> |
25 | <form class="navbar-search input-append pull-left" > | 32 | <form class="navbar-search input-append pull-left" id="searchform"> |
26 | <input class="input-xxlarge" name="search" type="text" placeholder="Search {{objectname}}" value="{{request.GET.search}}"/> | 33 | <div class="input-append" style="padding-right:1em"> |
34 | <input class="input-xxlarge" id="search" name="search" type="text" placeholder="Search {{objectname}}" value="{{request.GET.search}}"/><a href="javascript:$('#search').val('');searchform.submit()" class="add-on"><i class="icon-remove"></i></a> | ||
35 | </div> | ||
36 | <input type="hidden" name="orderby" value="{{request.GET.orderby}}"> | ||
27 | <input class="btn" type="submit" value="Search"/> | 37 | <input class="btn" type="submit" value="Search"/> |
28 | </form> | 38 | </form> |
29 | <div class="pull-right"> | 39 | <div class="pull-right"> |
@@ -32,7 +42,10 @@ | |||
32 | <button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns | 42 | <button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns |
33 | <span class="caret"></span> | 43 | <span class="caret"></span> |
34 | </button> | 44 | </button> |
35 | <ul class="dropdown-menu">{% for i in tablecols %} | 45 | <!-- |
46 | {{tablecols|sortcols}} | ||
47 | --> | ||
48 | <ul class="dropdown-menu">{% for i in tablecols|sortcols %} | ||
36 | <li> | 49 | <li> |
37 | <label class="checkbox"> | 50 | <label class="checkbox"> |
38 | <input type="checkbox" class="chbxtoggle" {% if i.clclass %}id="{{i.clclass}}" value="ct{{i.name}}" {% if not i.hidden %}checked="checked"{%endif%} onchange="showhideTableColumn($(this).attr('id'), $(this).is(':checked'))" {%else%} checked disabled{% endif %}/> {{i.name}} | 51 | <input type="checkbox" class="chbxtoggle" {% if i.clclass %}id="{{i.clclass}}" value="ct{{i.name}}" {% if not i.hidden %}checked="checked"{%endif%} onchange="showhideTableColumn($(this).attr('id'), $(this).is(':checked'))" {%else%} checked disabled{% endif %}/> {{i.name}} |
diff --git a/bitbake/lib/toaster/toastergui/templates/build.html b/bitbake/lib/toaster/toastergui/templates/build.html index eb7e03c951..a15702463b 100644 --- a/bitbake/lib/toaster/toastergui/templates/build.html +++ b/bitbake/lib/toaster/toastergui/templates/build.html | |||
@@ -18,9 +18,13 @@ | |||
18 | <div class="row-fluid"> | 18 | <div class="row-fluid"> |
19 | <div class="lead span5"> | 19 | <div class="lead span5"> |
20 | {%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%} | 20 | {%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%} |
21 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
21 | <a href="{%url 'builddashboard' build.pk%}"> | 22 | <a href="{%url 'builddashboard' build.pk%}"> |
23 | {% endif %} | ||
22 | <span data-toggle="tooltip" {%if build.target_set.all.count > 1%}title="Targets: {%for target in build.target_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|naturaltime}})</span> | 24 | <span data-toggle="tooltip" {%if build.target_set.all.count > 1%}title="Targets: {%for target in build.target_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|naturaltime}})</span> |
25 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
23 | </a> | 26 | </a> |
27 | {% endif %} | ||
24 | </div> | 28 | </div> |
25 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | 29 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} |
26 | <div class="span2 lead"> | 30 | <div class="span2 lead"> |
@@ -34,7 +38,7 @@ | |||
34 | {% endif %} | 38 | {% endif %} |
35 | </div> | 39 | </div> |
36 | <div class="lead pull-right"> | 40 | <div class="lead pull-right"> |
37 | Build time: <a href="build-time.html">{{ build|timespent }}</a> | 41 | Build time: <a href="build-time.html">{{ build.timespent|sectohms }}</a> |
38 | </div> | 42 | </div> |
39 | {%endif%}{%if build.outcome == build.IN_PROGRESS %} | 43 | {%endif%}{%if build.outcome == build.IN_PROGRESS %} |
40 | <div class="span4"> | 44 | <div class="span4"> |
@@ -81,14 +85,14 @@ | |||
81 | {% for build in objects %} | 85 | {% for build in objects %} |
82 | <tr class="data"> | 86 | <tr class="data"> |
83 | <td class="outcome"><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></td> | 87 | <td class="outcome"><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></td> |
84 | <td class="target">{% for t in build.target_set.all %}{%if t.is_image %}<a href="{% url "target" build.id t.id %}">{% endif %}{{t.target}}{% if t.is_image %}</a>{% endif %}<br/>{% endfor %}</td> | 88 | <td class="target">{% for t in build.target_set.all %}{%if t.is_image %}<a href="{% url "builddashboard" build.id %}">{% endif %}{{t.target}}{% if t.is_image %}</a>{% endif %}<br/>{% endfor %}</td> |
85 | <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> | 89 | <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> |
86 | <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on}}</a></td> | 90 | <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> |
87 | <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on}}</a></td> | 91 | <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on|date:"d/m/y H:i"}}</a></td> |
88 | <td class="failed_tasks">{% query build.task_build outcome=4 order__gt=0 as exectask%}{% if exectask.count == 1 %}{{exectask.0.recipe.name}}.{{exectask.0.task_name}}{% elif exectask.count > 1%}{{exectask.count}}{%endif%}</td> | 92 | <td class="failed_tasks error">{% query build.task_build outcome=4 order__gt=0 as exectask%}{% if exectask.count == 1 %}{{exectask.0.recipe.name}}.{{exectask.0.task_name}}{% elif exectask.count > 1%}{{exectask.count}}{%endif%}</td> |
89 | <td class="errors_no">{% if build.errors_no %}<a class="errors_no" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>{%endif%}</td> | 93 | <td class="errors_no">{% if build.errors_no %}<a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>{%endif%}</td> |
90 | <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> | 94 | <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> |
91 | <td class="time"><a href="{% url "buildtime" build.id %}">{{build|timespent}}</a></td> | 95 | <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td> |
92 | <td class="log">{{build.cooker_log_path}}</td> | 96 | <td class="log">{{build.cooker_log_path}}</td> |
93 | <td class="output">{% if build.outcome == 0 %}{% for t in build.target_set.all %}{% if t.is_image %}<a href="{%url "builddashboard" build.id%}#images">{{build.image_fstypes}}</a>{% endif %}{% endfor %}{% endif %}</td> | 97 | <td class="output">{% if build.outcome == 0 %}{% for t in build.target_set.all %}{% if t.is_image %}<a href="{%url "builddashboard" build.id%}#images">{{build.image_fstypes}}</a>{% endif %}{% endfor %}{% endif %}</td> |
94 | </tr> | 98 | </tr> |
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html index 3b184372bf..b6506c73d0 100644 --- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html +++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html | |||
@@ -17,13 +17,13 @@ | |||
17 | <div class="row-fluid span10 pull-right"> | 17 | <div class="row-fluid span10 pull-right"> |
18 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> | 18 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> |
19 | <div class="row-fluid lead"> | 19 | <div class="row-fluid lead"> |
20 | <span class="pull-left"><strong>{%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%}</strong> {{build.completed_on|naturaltime}} with </span>{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}{% if build.errors_no %} | 20 | <span class="pull-left"><strong>{%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%}</strong> {{build.completed_on|date:"d/m/y H:i"}} with </span>{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}{% if build.errors_no %} |
21 | <span class="span2"><i class="icon-minus-sign red"></i><strong><a href="{%url 'builddashboard' build.pk%}" class="error"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span> | 21 | <span class="span2"><i class="icon-minus-sign red"></i><strong><a href="{%url 'builddashboard' build.pk%}" class="error"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span> |
22 | {% endif %} | 22 | {% endif %} |
23 | {% if build.warnings_no %} | 23 | {% if build.warnings_no %} |
24 | <span class="span2"><i class="icon-warning-sign yellow"></i><strong><a href="{%url 'builddashboard' build.pk%}" class="warning"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span> | 24 | <span class="span2"><i class="icon-warning-sign yellow"></i><strong><a href="{%url 'builddashboard' build.pk%}" class="warning"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span> |
25 | {% endif %} | 25 | {% endif %} |
26 | <span class="pull-right">Build time: <a href="build-time.html">{{ build|timespent }}</a></span> | 26 | <span class="pull-right">Build time: <a href="build-time.html">{{ build.timespent|sectohms }}</a></span> |
27 | {%endif%} | 27 | {%endif%} |
28 | </div> | 28 | </div> |
29 | </div> | 29 | </div> |
diff --git a/bitbake/lib/toaster/toastergui/templates/configvars.html b/bitbake/lib/toaster/toastergui/templates/configvars.html index 8ce04b883d..ae45119f39 100644 --- a/bitbake/lib/toaster/toastergui/templates/configvars.html +++ b/bitbake/lib/toaster/toastergui/templates/configvars.html | |||
@@ -27,7 +27,7 @@ | |||
27 | <tr class="data"> | 27 | <tr class="data"> |
28 | <td class="variable">{{variable.variable_name}}</td> | 28 | <td class="variable">{{variable.variable_name}}</td> |
29 | <td class="variable_value">{{variable.variable_value}}</td> | 29 | <td class="variable_value">{{variable.variable_value}}</td> |
30 | <td class="file">{% for vh in variable.variablehistory_set.all %}{{vh.operation}} in {{vh.file_name}}:{{vh.line_number}}<br/>{%endfor%}</td> | 30 | <td class="file">{% for vh in variable.vhistory_set.all %}{{vh.operation}} in {{vh.file_name}}:{{vh.line_number}}<br/>{%endfor%}</td> |
31 | <td class="description">{% if variable.description %}{{variable.description}}{% endif %}</td> | 31 | <td class="description">{% if variable.description %}{{variable.description}}{% endif %}</td> |
32 | </tr> | 32 | </tr> |
33 | {% endfor %} | 33 | {% endfor %} |
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py index 24639477f6..d57a0598f9 100644 --- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py +++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py | |||
@@ -29,10 +29,14 @@ register = template.Library() | |||
29 | def time_difference(start_time, end_time): | 29 | def time_difference(start_time, end_time): |
30 | return end_time - start_time | 30 | return end_time - start_time |
31 | 31 | ||
32 | @register.filter(name = 'timespent') | 32 | @register.filter(name = 'sectohms') |
33 | def timespent(build_object): | 33 | def sectohms(time): |
34 | tdsec = (build_object.completed_on - build_object.started_on).total_seconds() | 34 | try: |
35 | return "%02d:%02d:%02d" % (int(tdsec/3600), int((tdsec - tdsec/ 3600)/ 60), int(tdsec) % 60) | 35 | tdsec = int(time) |
36 | except ValueError: | ||
37 | tdsec = 0 | ||
38 | hours = int(tdsec / 3600) | ||
39 | return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60) | ||
36 | 40 | ||
37 | @register.assignment_tag | 41 | @register.assignment_tag |
38 | def query(qs, **kwargs): | 42 | def query(qs, **kwargs): |
@@ -57,3 +61,8 @@ def multiply(value, arg): | |||
57 | @register.assignment_tag | 61 | @register.assignment_tag |
58 | def datecompute(delta, start = timezone.now()): | 62 | def datecompute(delta, start = timezone.now()): |
59 | return start + timedelta(delta) | 63 | return start + timedelta(delta) |
64 | |||
65 | |||
66 | @register.filter(name = 'sortcols') | ||
67 | def sortcols(tablecols): | ||
68 | return sorted(tablecols, key = lambda t: t['name']) | ||
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index a123eb5095..d54c66be81 100644 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
@@ -103,8 +103,11 @@ def _get_filtering_query(filter_string): | |||
103 | querydict = dict(zip(keys, values)) | 103 | querydict = dict(zip(keys, values)) |
104 | return reduce(lambda x, y: x & y, map(lambda x: __get_q_for_val(k, querydict[k]),[k for k in querydict])) | 104 | return reduce(lambda x, y: x & y, map(lambda x: __get_q_for_val(k, querydict[k]),[k for k in querydict])) |
105 | 105 | ||
106 | def _get_toggle_order(request, orderkey): | 106 | def _get_toggle_order(request, orderkey, reverse = False): |
107 | return "%s:-" % orderkey if request.GET.get('orderby', "") == "%s:+" % orderkey else "%s:+" % orderkey | 107 | if reverse: |
108 | return "%s:+" % orderkey if request.GET.get('orderby', "") == "%s:-" % orderkey else "%s:-" % orderkey | ||
109 | else: | ||
110 | return "%s:-" % orderkey if request.GET.get('orderby', "") == "%s:+" % orderkey else "%s:+" % orderkey | ||
108 | 111 | ||
109 | # we check that the input comes in a valid form that we can recognize | 112 | # we check that the input comes in a valid form that we can recognize |
110 | def _validate_input(input, model): | 113 | def _validate_input(input, model): |
@@ -163,12 +166,12 @@ def _search_tuple(request, model): | |||
163 | 166 | ||
164 | 167 | ||
165 | # returns a lazy-evaluated queryset for a filter/search/order combination | 168 | # returns a lazy-evaluated queryset for a filter/search/order combination |
166 | def _get_queryset(model, filter_string, search_term, ordering_string): | 169 | def _get_queryset(model, queryset, filter_string, search_term, ordering_string): |
167 | if filter_string: | 170 | if filter_string: |
168 | filter_query = _get_filtering_query(filter_string) | 171 | filter_query = _get_filtering_query(filter_string) |
169 | queryset = model.objects.filter(filter_query) | 172 | queryset = queryset.filter(filter_query) |
170 | else: | 173 | else: |
171 | queryset = model.objects.all() | 174 | queryset = queryset.all() |
172 | 175 | ||
173 | if search_term: | 176 | if search_term: |
174 | queryset = _get_search_results(search_term, queryset, model) | 177 | queryset = _get_search_results(search_term, queryset, model) |
@@ -196,16 +199,21 @@ def builds(request): | |||
196 | # boilerplate code that takes a request for an object type and returns a queryset | 199 | # boilerplate code that takes a request for an object type and returns a queryset |
197 | # for that object type. copypasta for all needed table searches | 200 | # for that object type. copypasta for all needed table searches |
198 | (filter_string, search_term, ordering_string) = _search_tuple(request, Build) | 201 | (filter_string, search_term, ordering_string) = _search_tuple(request, Build) |
199 | queryset = _get_queryset(Build, filter_string, search_term, ordering_string) | 202 | queryset = Build.objects.exclude(outcome = Build.IN_PROGRESS) |
203 | queryset = _get_queryset(Build, queryset, filter_string, search_term, ordering_string) | ||
200 | 204 | ||
201 | # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display | 205 | # retrieve the objects that will be displayed in the table; builds a paginator and gets a page range to display |
202 | build_info = _build_page_range(Paginator(queryset.exclude(outcome = Build.IN_PROGRESS), request.GET.get('count', 10)),request.GET.get('page', 1)) | 206 | build_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1)) |
203 | 207 | ||
204 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | 208 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) |
205 | build_mru = Build.objects.filter(completed_on__gte=(timezone.now()-timedelta(hours=24))).order_by("-started_on")[:3] | 209 | build_mru = Build.objects.filter(completed_on__gte=(timezone.now()-timedelta(hours=24))).order_by("-started_on")[:3] |
206 | for b in [ x for x in build_mru if x.outcome == Build.IN_PROGRESS ]: | 210 | for b in [ x for x in build_mru if x.outcome == Build.IN_PROGRESS ]: |
207 | tf = Task.objects.filter(build = b) | 211 | tf = Task.objects.filter(build = b) |
208 | b.completeper = tf.exclude(order__isnull=True).count()*100/tf.count() | 212 | tfc = tf.count() |
213 | if tfc > 0: | ||
214 | b.completeper = tf.exclude(order__isnull=True).count()*100/tf.count() | ||
215 | else: | ||
216 | b.completeper = 0 | ||
209 | b.eta = timezone.now() | 217 | b.eta = timezone.now() |
210 | if b.completeper > 0: | 218 | if b.completeper > 0: |
211 | b.eta += ((timezone.now() - b.started_on)*100/b.completeper) | 219 | b.eta += ((timezone.now() - b.started_on)*100/b.completeper) |
@@ -218,6 +226,7 @@ def builds(request): | |||
218 | 'mru' : build_mru, | 226 | 'mru' : build_mru, |
219 | # TODO: common objects for all table views, adapt as needed | 227 | # TODO: common objects for all table views, adapt as needed |
220 | 'objects' : build_info, | 228 | 'objects' : build_info, |
229 | 'objectname' : "builds", | ||
221 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns | 230 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns |
222 | 'tablecols' : [ | 231 | 'tablecols' : [ |
223 | {'name': 'Outcome ', # column with a single filter | 232 | {'name': 'Outcome ', # column with a single filter |
@@ -239,10 +248,13 @@ def builds(request): | |||
239 | }, | 248 | }, |
240 | {'name': 'Machine ', | 249 | {'name': 'Machine ', |
241 | 'qhelp': "The machine is the hardware for which you are building", | 250 | 'qhelp': "The machine is the hardware for which you are building", |
242 | 'dclass': 'span3'}, # a slightly wider column | 251 | 'orderfield': _get_toggle_order(request, "machine"), |
252 | 'dclass': 'span3' | ||
253 | }, # a slightly wider column | ||
243 | {'name': 'Started on ', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column | 254 | {'name': 'Started on ', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column |
244 | 'qhelp': "The date and time you started the build", | 255 | 'qhelp': "The date and time you started the build", |
245 | 'filter' : {'class' : 'started_on', 'label': 'Show only builds started', 'options' : { | 256 | 'orderfield': _get_toggle_order(request, "started_on", True), |
257 | 'filter' : {'class' : 'started_on', 'label': 'Show only builds started', 'options' : { | ||
246 | 'Today' : 'started_on__gte:'+timezone.now().strftime("%Y-%m-%d"), | 258 | 'Today' : 'started_on__gte:'+timezone.now().strftime("%Y-%m-%d"), |
247 | 'Yesterday' : 'started_on__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), | 259 | 'Yesterday' : 'started_on__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), |
248 | 'Within one week' : 'started_on__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), | 260 | 'Within one week' : 'started_on__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), |
@@ -250,7 +262,7 @@ def builds(request): | |||
250 | }, | 262 | }, |
251 | {'name': 'Completed on ', | 263 | {'name': 'Completed on ', |
252 | 'qhelp': "The date and time the build finished", | 264 | 'qhelp': "The date and time the build finished", |
253 | 'orderfield': _get_toggle_order(request, "completed_on"), | 265 | 'orderfield': _get_toggle_order(request, "completed_on", True), |
254 | 'filter' : {'class' : 'completed_on', 'label': 'Show only builds completed', 'options' : { | 266 | 'filter' : {'class' : 'completed_on', 'label': 'Show only builds completed', 'options' : { |
255 | 'Today' : 'completed_on__gte:'+timezone.now().strftime("%Y-%m-%d"), | 267 | 'Today' : 'completed_on__gte:'+timezone.now().strftime("%Y-%m-%d"), |
256 | 'Yesterday' : 'completed_on__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), | 268 | 'Yesterday' : 'completed_on__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), |
@@ -266,7 +278,7 @@ def builds(request): | |||
266 | }, | 278 | }, |
267 | {'name': 'Errors ', 'clclass': 'errors_no', | 279 | {'name': 'Errors ', 'clclass': 'errors_no', |
268 | 'qhelp': "How many errors were encountered during the build (if any)", | 280 | 'qhelp': "How many errors were encountered during the build (if any)", |
269 | 'orderfield': _get_toggle_order(request, "errors_no"), | 281 | 'orderfield': _get_toggle_order(request, "errors_no", True), |
270 | 'filter' : {'class' : 'errors_no', 'label': 'Show only ', 'options' : { | 282 | 'filter' : {'class' : 'errors_no', 'label': 'Show only ', 'options' : { |
271 | 'Builds with errors' : 'errors_no__gte:1', | 283 | 'Builds with errors' : 'errors_no__gte:1', |
272 | 'Builds without errors' : 'errors_no:0', | 284 | 'Builds without errors' : 'errors_no:0', |
@@ -274,20 +286,25 @@ def builds(request): | |||
274 | }, | 286 | }, |
275 | {'name': 'Warnings', 'clclass': 'warnings_no', | 287 | {'name': 'Warnings', 'clclass': 'warnings_no', |
276 | 'qhelp': "How many warnigns were encountered during the build (if any)", | 288 | 'qhelp': "How many warnigns were encountered during the build (if any)", |
277 | 'orderfield': _get_toggle_order(request, "warnings_no"), | 289 | 'orderfield': _get_toggle_order(request, "warnings_no", True), |
278 | 'filter' : {'class' : 'warnings_no', 'label': 'Show only ', 'options' : { | 290 | 'filter' : {'class' : 'warnings_no', 'label': 'Show only ', 'options' : { |
279 | 'Builds with warnings' : 'warnings_no__gte:1', | 291 | 'Builds with warnings' : 'warnings_no__gte:1', |
280 | 'Builds without warnings' : 'warnings_no:0', | 292 | 'Builds without warnings' : 'warnings_no:0', |
281 | }} | 293 | }} |
282 | }, | 294 | }, |
283 | {'name': 'Time ', 'clclass': 'time', 'hidden' : 1, | 295 | {'name': 'Time ', 'clclass': 'time', 'hidden' : 1, |
284 | 'qhelp': "How long it took the build to finish",}, | 296 | 'qhelp': "How long it took the build to finish", |
297 | 'orderfield': _get_toggle_order(request, "timespent", True), | ||
298 | }, | ||
285 | {'name': 'Log', | 299 | {'name': 'Log', |
286 | 'dclass': "span4", | 300 | 'dclass': "span4", |
287 | 'qhelp': "The location in disk of the build main log file", | 301 | 'qhelp': "The location in disk of the build main log file", |
288 | 'clclass': 'log', 'hidden': 1}, | 302 | 'clclass': 'log', 'hidden': 1 |
303 | }, | ||
289 | {'name': 'Output', 'clclass': 'output', | 304 | {'name': 'Output', 'clclass': 'output', |
290 | 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory"}, | 305 | 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory", |
306 | 'orderfield': _get_toggle_order(request, "image_fstypes") | ||
307 | }, | ||
291 | ] | 308 | ] |
292 | } | 309 | } |
293 | 310 | ||
@@ -368,9 +385,10 @@ def tasks(request, build_id): | |||
368 | if retval: | 385 | if retval: |
369 | return _redirect_parameters( 'tasks', request.GET, mandatory_parameters, build_id = build_id) | 386 | return _redirect_parameters( 'tasks', request.GET, mandatory_parameters, build_id = build_id) |
370 | (filter_string, search_term, ordering_string) = _search_tuple(request, Task) | 387 | (filter_string, search_term, ordering_string) = _search_tuple(request, Task) |
371 | queryset = _get_queryset(Task, filter_string, search_term, ordering_string) | 388 | queryset = Task.objects.filter(build=build_id, order__gt=0) |
389 | queryset = _get_queryset(Task, queryset, filter_string, search_term, ordering_string) | ||
372 | 390 | ||
373 | tasks = _build_page_range(Paginator(queryset.filter(build=build_id, order__gt=0), request.GET.get('count', 100)),request.GET.get('page', 1)) | 391 | tasks = _build_page_range(Paginator(queryset, request.GET.get('count', 100)),request.GET.get('page', 1)) |
374 | 392 | ||
375 | for t in tasks: | 393 | for t in tasks: |
376 | if t.outcome == Task.OUTCOME_COVERED: | 394 | if t.outcome == Task.OUTCOME_COVERED: |
@@ -387,9 +405,10 @@ def recipes(request, build_id): | |||
387 | if retval: | 405 | if retval: |
388 | return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id) | 406 | return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id) |
389 | (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe) | 407 | (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe) |
390 | queryset = _get_queryset(Recipe, filter_string, search_term, ordering_string) | 408 | queryset = Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)) |
409 | queryset = _get_queryset(Recipe, queryset, filter_string, search_term, ordering_string) | ||
391 | 410 | ||
392 | recipes = _build_page_range(Paginator(queryset.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)), request.GET.get('count', 100)),request.GET.get('page', 1)) | 411 | recipes = _build_page_range(Paginator(queryset, request.GET.get('count', 100)),request.GET.get('page', 1)) |
393 | 412 | ||
394 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes, } | 413 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes, } |
395 | 414 | ||
@@ -410,9 +429,10 @@ def configvars(request, build_id): | |||
410 | return _redirect_parameters( 'configvars', request.GET, mandatory_parameters, build_id = build_id) | 429 | return _redirect_parameters( 'configvars', request.GET, mandatory_parameters, build_id = build_id) |
411 | 430 | ||
412 | (filter_string, search_term, ordering_string) = _search_tuple(request, Variable) | 431 | (filter_string, search_term, ordering_string) = _search_tuple(request, Variable) |
413 | queryset = _get_queryset(Variable, filter_string, search_term, ordering_string) | 432 | queryset = Variable.objects.filter(build=build_id) |
433 | queryset = _get_queryset(Variable, queryset, filter_string, search_term, ordering_string) | ||
414 | 434 | ||
415 | variables = _build_page_range(Paginator(queryset.filter(build=build_id), request.GET.get('count', 50)), request.GET.get('page', 1)) | 435 | variables = _build_page_range(Paginator(queryset, request.GET.get('count', 50)), request.GET.get('page', 1)) |
416 | 436 | ||
417 | context = { | 437 | context = { |
418 | 'build': Build.objects.filter(pk=build_id)[0], | 438 | 'build': Build.objects.filter(pk=build_id)[0], |
@@ -492,9 +512,10 @@ def bpackage(request, build_id): | |||
492 | if retval: | 512 | if retval: |
493 | return _redirect_parameters( 'packages', request.GET, mandatory_parameters, build_id = build_id) | 513 | return _redirect_parameters( 'packages', request.GET, mandatory_parameters, build_id = build_id) |
494 | (filter_string, search_term, ordering_string) = _search_tuple(request, Package) | 514 | (filter_string, search_term, ordering_string) = _search_tuple(request, Package) |
495 | queryset = _get_queryset(Package, filter_string, search_term, ordering_string) | 515 | queryset = Package.objects.filter(build = build_id) |
516 | queryset = _get_queryset(Package, queryset, filter_string, search_term, ordering_string) | ||
496 | 517 | ||
497 | packages = _build_page_range(Paginator(queryset.filter(build = build_id), request.GET.get('count', 100)),request.GET.get('page', 1)) | 518 | packages = _build_page_range(Paginator(queryset, request.GET.get('count', 100)),request.GET.get('page', 1)) |
498 | 519 | ||
499 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages} | 520 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages} |
500 | return render(request, template, context) | 521 | return render(request, template, context) |