Openembedded Bitbake Development
 help / color / mirror / Atom feed
* [PATCH 01/14] toaster: use http proxies to fetch data
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 02/14] toaster: base Only show New Build button when there are > 0 projects Alex DAMIAN
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

Under some network configurations http proxies are used
for Internet access. This patch makes Toaster obey
the http_proxy environment variable when fetching
information from layer indexes.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/orm/models.py | 45 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index c90e047..99cc695 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -599,24 +599,41 @@ class LayerIndexLayerSource(LayerSource):
         assert self.apiurl is not None
         from django.db import IntegrityError
 
+        import httplib, urlparse, json
+        import os
+        proxy_settings = os.environ.get("http_proxy", None)
+
         def _get_json_response(apiurl = self.apiurl):
-            import httplib, urlparse, json
-            parsedurl = urlparse.urlparse(apiurl)
-            try:
-                (host, port) = parsedurl.netloc.split(":")
-            except ValueError:
-                host = parsedurl.netloc
-                port = None
+            conn = None
+            _parsedurl = urlparse.urlparse(apiurl)
+            path = _parsedurl.path
+            query = _parsedurl.query
+            def parse_url(url):
+                parsedurl = urlparse.urlparse(url)
+                try:
+                    (host, port) = parsedurl.netloc.split(":")
+                except ValueError:
+                    host = parsedurl.netloc
+                    port = None
+
+                if port is None:
+                    port = 80
+                else:
+                    port = int(port)
+                return (host, port)
 
-            if port is None:
-                port = 80
+            if proxy_settings is None:
+                host, port = parse_url(apiurl)
+                conn = httplib.HTTPConnection(host, port)
+                conn.request("GET", path + "?" + query)
             else:
-                port = int(port)
-            conn = httplib.HTTPConnection(host, port)
-            conn.request("GET", parsedurl.path + "?" + parsedurl.query)
+                host, port = parse_url(proxy_settings)
+                conn = httplib.HTTPConnection(host, port)
+                conn.request("GET", apiurl)
+
             r = conn.getresponse()
             if r.status != 200:
-                raise Exception("Failed to read " + parsedurl.path + ": %d %s" % (r.status, r.reason))
+                raise Exception("Failed to read " + path + ": %d %s" % (r.status, r.reason))
             return json.loads(r.read())
 
         # verify we can get the basic api
@@ -624,6 +641,8 @@ class LayerIndexLayerSource(LayerSource):
             apilinks = _get_json_response()
         except Exception as e:
             import traceback
+            if proxy_settings is not None:
+                print "EE: Using proxy ", proxy_settings
             print "EE: could not connect to %s, skipping update: %s\n%s" % (self.apiurl, e, traceback.format_exc(e))
             return
 
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 02/14] toaster: base Only show New Build button when there are > 0 projects
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 01/14] toaster: use http proxies to fetch data Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 03/14] toastergui: update layer search criteria Alex DAMIAN
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel

From: Michael Wood <michael.g.wood@intel.com>

Only show new build button if we have defined at least one project as we
can't select a project to build against if there are no projects created
yet.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/toastergui/static/js/base.js   | 13 +++++++++----
 lib/toaster/toastergui/templates/base.html |  1 +
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/lib/toaster/toastergui/static/js/base.js b/lib/toaster/toastergui/static/js/base.js
index 864130d..fac59e6 100644
--- a/lib/toaster/toastergui/static/js/base.js
+++ b/lib/toaster/toastergui/static/js/base.js
@@ -3,10 +3,12 @@
 function basePageInit (ctx) {
 
   var newBuildButton = $("#new-build-button");
-  /* Hide the button if we're on the project,newproject or importlyaer page */
-  if (ctx.currentUrl.search('newproject|project/\\d/$|importlayer/$') > 0){
-    newBuildButton.hide();
-    return;
+  /* Hide the button if we're on the project,newproject or importlyaer page
+   * or if there are no projects yet defined
+   */
+  if (ctx.numProjects == 0 || ctx.currentUrl.search('newproject|project/\\d/$|importlayer/$') > 0){
+      newBuildButton.hide();
+      return;
   }
 
 
@@ -17,6 +19,9 @@ function basePageInit (ctx) {
 
 
   function _checkProjectBuildable(){
+    if (ctx.projectId == undefined)
+      return;
+
     libtoaster.getProjectInfo(ctx.projectInfoUrl, ctx.projectId,
       function(data){
         if (data.machine.name == undefined || data.layers.length == 0) {
diff --git a/lib/toaster/toastergui/templates/base.html b/lib/toaster/toastergui/templates/base.html
index 734d2ad..f457b91 100644
--- a/lib/toaster/toastergui/templates/base.html
+++ b/lib/toaster/toastergui/templates/base.html
@@ -31,6 +31,7 @@
     ctx.projectBuildUrl = "{% url 'xhr_build' %}";
     ctx.projectPageUrl = "{% url 'project' %}";
     ctx.projectInfoUrl = "{% url 'xhr_projectinfo' %}";
+    ctx.numProjects = {{projects|length}};
     {% if project %}
       ctx.projectId = {{project.id}};
     {% endif %}
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 03/14] toastergui: update layer search criteria
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 01/14] toaster: use http proxies to fetch data Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 02/14] toaster: base Only show New Build button when there are > 0 projects Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 04/14] toastergui: do not show project info in interactive mode Alex DAMIAN
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

In order to accomodate the designs around imported layer,
we add a "project" field for in the layer versions.

The field must be set if and only if the layer is manually
imported in the project. This will prevent information leakage
between different projects.

The views have been updated to perform relevant layer queries
in a single location.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 .../0018_auto__add_field_layer_version_project.py  | 331 +++++++++++++++++++++
 lib/toaster/orm/models.py                          |   4 +-
 lib/toaster/toastergui/views.py                    |  59 ++--
 3 files changed, 371 insertions(+), 23 deletions(-)
 create mode 100644 lib/toaster/orm/migrations/0018_auto__add_field_layer_version_project.py

diff --git a/lib/toaster/orm/migrations/0018_auto__add_field_layer_version_project.py b/lib/toaster/orm/migrations/0018_auto__add_field_layer_version_project.py
new file mode 100644
index 0000000..7284bb8
--- /dev/null
+++ b/lib/toaster/orm/migrations/0018_auto__add_field_layer_version_project.py
@@ -0,0 +1,331 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'Layer_Version.project'
+        db.add_column(u'orm_layer_version', 'project',
+                      self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['orm.Project'], null=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Layer_Version.project'
+        db.delete_column(u'orm_layer_version', 'project_id')
+
+
+    models = {
+        u'orm.bitbakeversion': {
+            'Meta': {'object_name': 'BitbakeVersion'},
+            'branch': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'giturl': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
+        },
+        u'orm.branch': {
+            'Meta': {'unique_together': "(('layer_source', 'name'), ('layer_source', 'up_id'))", 'object_name': 'Branch'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'True', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
+            'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
+        },
+        u'orm.build': {
+            'Meta': {'object_name': 'Build'},
+            'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
+            'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
+            'started_on': ('django.db.models.fields.DateTimeField', [], {}),
+            'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+        },
+        u'orm.helptext': {
+            'Meta': {'object_name': 'HelpText'},
+            'area': ('django.db.models.fields.IntegerField', [], {}),
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'helptext_build'", 'to': u"orm['orm.Build']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        u'orm.layer': {
+            'Meta': {'unique_together': "(('layer_source', 'up_id'), ('layer_source', 'name'))", 'object_name': 'Layer'},
+            'description': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_index_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
+            'local_path': ('django.db.models.fields.FilePathField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'summary': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
+            'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
+            'vcs_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
+            'vcs_web_file_base_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
+            'vcs_web_tree_base_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
+            'vcs_web_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'})
+        },
+        u'orm.layer_version': {
+            'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'Layer_Version'},
+            'branch': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'layer_version_build'", 'null': 'True', 'to': u"orm['orm.Build']"}),
+            'commit': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'dirpath': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_layer'", 'to': u"orm['orm.Layer']"}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
+            'priority': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.Project']", 'null': 'True'}),
+            'up_branch': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.Branch']", 'null': 'True'}),
+            'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
+        },
+        u'orm.layersource': {
+            'Meta': {'unique_together': "(('sourcetype', 'apiurl'),)", 'object_name': 'LayerSource'},
+            'apiurl': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '63'}),
+            'sourcetype': ('django.db.models.fields.IntegerField', [], {})
+        },
+        u'orm.layerversiondependency': {
+            'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'LayerVersionDependency'},
+            'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependees'", 'to': u"orm['orm.Layer_Version']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
+            'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependencies'", 'to': u"orm['orm.Layer_Version']"}),
+            'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
+        },
+        u'orm.logmessage': {
+            'Meta': {'object_name': 'LogMessage'},
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'lineno': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}),
+            'pathname': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
+            'task': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Task']", 'null': 'True', 'blank': 'True'})
+        },
+        u'orm.machine': {
+            'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'Machine'},
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
+            'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Layer_Version']"}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
+        },
+        u'orm.package': {
+            'Meta': {'object_name': 'Package'},
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'installed_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
+            'installed_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'license': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'recipe': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Recipe']", 'null': 'True'}),
+            'revision': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
+            'section': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
+            'size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        u'orm.package_dependency': {
+            'Meta': {'object_name': 'Package_Dependency'},
+            'dep_type': ('django.db.models.fields.IntegerField', [], {}),
+            'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_target'", 'to': u"orm['orm.Package']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_source'", 'to': u"orm['orm.Package']"}),
+            'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']", 'null': 'True'})
+        },
+        u'orm.package_file': {
+            'Meta': {'object_name': 'Package_File'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildfilelist_package'", 'to': u"orm['orm.Package']"}),
+            'path': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
+            'size': ('django.db.models.fields.IntegerField', [], {})
+        },
+        u'orm.project': {
+            'Meta': {'object_name': 'Project'},
+            'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"}),
+            'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
+            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
+        },
+        u'orm.projectlayer': {
+            'Meta': {'unique_together': "(('project', 'layercommit'),)", 'object_name': 'ProjectLayer'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layercommit': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Layer_Version']", 'null': 'True'}),
+            'optional': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"})
+        },
+        u'orm.projecttarget': {
+            'Meta': {'object_name': 'ProjectTarget'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
+            'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        u'orm.projectvariable': {
+            'Meta': {'object_name': 'ProjectVariable'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
+            'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        u'orm.recipe': {
+            'Meta': {'unique_together': "(('layer_version', 'file_path'),)", 'object_name': 'Recipe'},
+            'bugtracker': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'file_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}),
+            'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
+            'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recipe_layer_version'", 'to': u"orm['orm.Layer_Version']"}),
+            'license': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+            'section': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+            'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
+            'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        u'orm.recipe_dependency': {
+            'Meta': {'object_name': 'Recipe_Dependency'},
+            'dep_type': ('django.db.models.fields.IntegerField', [], {}),
+            'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_depends'", 'to': u"orm['orm.Recipe']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_recipe'", 'to': u"orm['orm.Recipe']"})
+        },
+        u'orm.release': {
+            'Meta': {'object_name': 'Release'},
+            'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
+            'branch_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50'}),
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'helptext': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
+        },
+        u'orm.releasedefaultlayer': {
+            'Meta': {'object_name': 'ReleaseDefaultLayer'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
+            'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"})
+        },
+        u'orm.releaselayersourcepriority': {
+            'Meta': {'unique_together': "(('release', 'layer_source'),)", 'object_name': 'ReleaseLayerSourcePriority'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.LayerSource']"}),
+            'priority': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"})
+        },
+        u'orm.target': {
+            'Meta': {'object_name': 'Target'},
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'is_image': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'license_manifest_path': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
+            'target': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'orm.target_file': {
+            'Meta': {'object_name': 'Target_File'},
+            'directory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'directory_set'", 'null': 'True', 'to': u"orm['orm.Target_File']"}),
+            'group': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'inodetype': ('django.db.models.fields.IntegerField', [], {}),
+            'owner': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'path': ('django.db.models.fields.FilePathField', [], {'max_length': '100'}),
+            'permission': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+            'size': ('django.db.models.fields.IntegerField', [], {}),
+            'sym_target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'symlink_set'", 'null': 'True', 'to': u"orm['orm.Target_File']"}),
+            'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
+        },
+        u'orm.target_image_file': {
+            'Meta': {'object_name': 'Target_Image_File'},
+            'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '254'}),
+            'file_size': ('django.db.models.fields.IntegerField', [], {}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
+        },
+        u'orm.target_installed_package': {
+            'Meta': {'object_name': 'Target_Installed_Package'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildtargetlist_package'", 'to': u"orm['orm.Package']"}),
+            'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
+        },
+        u'orm.task': {
+            'Meta': {'ordering': "('order', 'recipe')", 'unique_together': "(('build', 'recipe', 'task_name'),)", 'object_name': 'Task'},
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_build'", 'to': u"orm['orm.Build']"}),
+            'cpu_usage': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '6', 'decimal_places': '2'}),
+            'disk_io': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'elapsed_time': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '6', 'decimal_places': '2'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'line_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'logfile': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
+            'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}),
+            'order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'outcome': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
+            'path_to_sstate_obj': ('django.db.models.fields.FilePathField', [], {'max_length': '500', 'blank': 'True'}),
+            'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'build_recipe'", 'to': u"orm['orm.Recipe']"}),
+            'script_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'source_url': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
+            'sstate_checksum': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+            'sstate_result': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'task_executed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'task_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'work_directory': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'})
+        },
+        u'orm.task_dependency': {
+            'Meta': {'object_name': 'Task_Dependency'},
+            'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_depends'", 'to': u"orm['orm.Task']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'task': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_task'", 'to': u"orm['orm.Task']"})
+        },
+        u'orm.toastersetting': {
+            'Meta': {'object_name': 'ToasterSetting'},
+            'helptext': ('django.db.models.fields.TextField', [], {}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '63'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'orm.variable': {
+            'Meta': {'object_name': 'Variable'},
+            'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variable_build'", 'to': u"orm['orm.Build']"}),
+            'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'human_readable_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'variable_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'variable_value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        u'orm.variablehistory': {
+            'Meta': {'object_name': 'VariableHistory'},
+            'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'line_number': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'operation': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+            'value': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vhistory'", 'to': u"orm['orm.Variable']"})
+        }
+    }
+
+    complete_apps = ['orm']
\ No newline at end of file
diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 99cc695..364b215 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -843,6 +843,8 @@ class Layer_Version(models.Model):
     dirpath = models.CharField(max_length=255, null = True, default = None)          # LayerBranch.vcs_subdir
     priority = models.IntegerField(default = 0)         # if -1, this is a default layer
 
+    project = models.ForeignKey('Project', null = True, default = None)   # Set if this layer is project-specific; always set for imported layers, and project-set branches
+
     # code lifted, with adaptations, from the layerindex-web application https://git.yoctoproject.org/cgit/cgit.cgi/layerindex-web/
     def _handle_url_path(self, base_url, path):
         import re
@@ -902,7 +904,7 @@ class Layer_Version(models.Model):
         return sorted(
                 Layer_Version.objects.filter( layer__name = self.layer.name, up_branch__name = self.up_branch.name ),
                 key = lambda x: _get_ls_priority(x.layer_source),
-                reverse = False)
+                reverse = True)
 
 
     def __unicode__(self):
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index a0dcf87..11c373a 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1935,7 +1935,21 @@ if toastermain.settings.MANAGED:
 
         raise Exception("Invalid HTTP method for this page")
 
+    # returns a queryset of compatible layers for a project
+    def _compatible_layerversions_for_project(prj, release = None, layer_name = None):
+        if release == None:
+            release = prj.release
+        # layers on the same branch or layers specifically set for this project
+        return Layer_Version.objects.filter((Q(up_branch__name = release.branch_name) & Q(project = None)) | Q(project = prj))
 
+
+    # returns the equivalence group for all the layers currently set in the project
+    def _project_equivalent_layerversions(prj):
+        return reduce(lambda x, y: list(x) + list(y),
+                    # take all equivalent layers for each entry
+                    map(lambda x: x.layercommit.get_equivalents_wpriority(prj), prj.projectlayer_set.all()) , [])
+
+    # returns a list for most recent builds; for use in the Project page, xhr_ updates,  and other places, as needed
     def _project_recent_build_list(prj):
         return map(lambda x: {
                 "id":  x.pk,
@@ -2101,7 +2115,7 @@ if toastermain.settings.MANAGED:
                 for i in prj.projectlayer_set.all():
                     # find and add a similarly-named layer on the new branch
                     try:
-                        lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__name = prj.release.branch_name)[0].get_equivalents_wpriority(prj)[0]
+                        lv = _compatible_layerversions_for_project(prj).filter(layer__name = i.layer.name).get_equivalents_wpriority(prj)[0]
                         ProjectLayer.objects.get_or_create(project = prj, layercommit = lv)
                     except IndexError:
                         pass
@@ -2140,30 +2154,32 @@ if toastermain.settings.MANAGED:
 			else:
 				raise Exception("No valid project selected")
 
-            # returns layers for current project release that are not in the project set
+
+            def _lv_to_dict(x):
+                return {"id": x.pk, "name": x.layer.name, 
+                        "detail": "(" + x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.up_branch.name+")"),
+                        "giturl": x.layer.vcs_url, "layerdetailurl" : reverse('layerdetails', args=(x.pk,))}
+
+
+            # returns layers for current project release that are not in the project set, matching the name
             if request.GET['type'] == "layers":
-                queryset_all = Layer_Version.objects.filter(layer__name__icontains=request.GET.get('value',''))
-                queryset_all = queryset_all.filter(up_branch__name= prj.release.branch_name).exclude(pk__in = [x.id for x in reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), prj.projectlayer_set.all()))])
+                queryset_all = _compatible_layerversions_for_project(prj).filter(layer__name__icontains=request.GET.get('value',''))
+
+                queryset_all = queryset_all.exclude(pk__in = [x.id for x in _project_equivalent_layerversions(prj)])
 
                 queryset_all = set([x.get_equivalents_wpriority(prj)[0] for x in queryset_all[:8]])
 
-                return HttpResponse(jsonfilter( { "error":"ok",
-                    "list" : map( lambda x: {"id": x.pk, "name": "%s" % (x.layer.name, ), "detail": "(" + x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.up_branch.name+")")},
-                            queryset_all)
-                    }), content_type = "application/json")
+                return HttpResponse(jsonfilter( { "error":"ok",  "list" : map( _lv_to_dict, queryset_all) }), content_type = "application/json")
 
 
             # returns layer dependencies for a layer, excluding current project layers
             if request.GET['type'] == "layerdeps":
                 queryset_all = LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])
-                queryset_all = queryset_all.exclude(depends_on__in = reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), prj.projectlayer_set.all())))
+                queryset_all = queryset_all.exclude(depends_on__in = _project_equivalent_layerversions(prj))
                 queryset_all.order_by("-up_id");
 
                 return HttpResponse(jsonfilter( { "error":"ok",
-                    "list" : map(
-                        lambda x: {"id": x.pk, "name": x.layer.name, "detail": "(" + x.layer.layer_source.name + (")" if x.up_branch == None else " | "+x.up_branch.name+")"),
-                                   "giturl": x.layer.vcs_url, "layerdetailurl" : reverse('layerdetails', args=(x.pk,))},
-                        map(lambda x: x.depends_on.get_equivalents_wpriority(prj)[0], queryset_all))
+                    "list" : map( _lv_to_dict,  map(lambda x: x.depends_on.get_equivalents_wpriority(prj)[0], queryset_all))
                     }), content_type = "application/json")
 
 
@@ -2174,20 +2190,20 @@ if toastermain.settings.MANAGED:
 
                 retval = []
                 for i in prj.projectlayer_set.all():
-                    lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__name = Release.objects.get(pk=request.GET['value']).branch_name)
-                    if lv.count() < 1:     # there is no layer_version with the new release id, and the same name
+                    lv = _compatible_layerversions_for_project(prj, release = Release.objects.get(pk=request.GET['value']))
+                    # there is no layer_version with the new release id, and the same name
+                    if lv.count() < 1:
                         retval.append(i)
 
                 return HttpResponse(jsonfilter( {"error":"ok",
-                    "list": map(
-                        lambda x: {"id": x.layercommit.pk, "name": x.layercommit.layer.name, "detail": "(" + x.layercommit.layer.layer_source.name + (")" if x.layercommit.up_branch == None else " | "+x.layercommit.up_branch.name+")")},
-                        retval) }), content_type = "application/json")
+                    "list" : map( _lv_to_dict,  map(lambda x: x.layercommit, retval ))
+                    }), content_type = "application/json")
 
 
             # returns targets provided by current project layers
             if request.GET['type'] == "targets":
                 queryset_all = Recipe.objects.all()
-                queryset_all = queryset_all.filter(layer_version__in = reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), ProjectLayer.objects.filter(project = prj))))
+                queryset_all = queryset_all.filter(layer_version__in = reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), prj.projectlayer_set.all()), []))
                 return HttpResponse(jsonfilter({ "error":"ok",
                     "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name+ (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")},
                         queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]),
@@ -2243,10 +2259,9 @@ if toastermain.settings.MANAGED:
         # for that object type. copypasta for all needed table searches
         (filter_string, search_term, ordering_string) = _search_tuple(request, Layer_Version)
 
-        queryset_all = Layer_Version.objects.all()
-
         prj = Project.objects.get(pk = request.session['project_id'])
-        queryset_all = queryset_all.filter(up_branch__name = prj.release.branch_name)
+
+        queryset_all = _compatible_layerversions_for_project(prj)
 
         queryset_all = _get_queryset(Layer_Version, queryset_all, filter_string, search_term, ordering_string, '-layer__name')
 
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 04/14] toastergui: do not show project info in interactive mode
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (2 preceding siblings ...)
  2014-11-27 17:07 ` [PATCH 03/14] toastergui: update layer search criteria Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 05/14] toaster: display Toaster exceptions and other fixes Alex DAMIAN
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

The most recent builds section showed the project name and the Run Again
buttons regardless whenever the Toaster was in interactive or managed
modes. These widgets have no meaning in interactive mode, and this
patch disables the widgets if toaster is not running in Managed mode.

[YOCTO #6776]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/templates/mrb_section.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/toaster/toastergui/templates/mrb_section.html b/lib/toaster/toastergui/templates/mrb_section.html
index 586c47b..4237980 100644
--- a/lib/toaster/toastergui/templates/mrb_section.html
+++ b/lib/toaster/toastergui/templates/mrb_section.html
@@ -13,7 +13,7 @@
   <div id="latest-builds">
   {% for build in mru %}
     <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}" style="padding-top: 0;">
-    {% if build.project %}
+    {% if MANAGED and build.project %}
        <span class="label {%if build.outcome == build.SUCCEEDED%}label-success{%elif build.outcome == build.FAILED%}label-danger{%else%}label-info{%endif%}" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;"> {{build.project.name}} </span>
     {% endif %}
 
@@ -40,10 +40,10 @@
       {% endif %}
             </div>
             <div class="lead ">
-              <span class="lead{%if not build.project%} pull-right{%endif%}">
+              <span class="lead{%if not MANAGED or not build.project%} pull-right{%endif%}">
                 Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a>
               </span>
-          {% if build.project %}
+          {% if MANAGED and build.project %}
               <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%elif build.outcome == build.FAILED%}btn-danger{%else%}btn-info{%endif%} pull-right" onclick="scheduleBuild({% url 'xhr_projectbuild' build.project.id as bpi%}{{bpi|json}}, {{build.project.name|json}}, {{build.get_sorted_target_list|mapselect:'target'|json}})">Run again</a>
           {% endif %}
             </div>
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 05/14] toaster: display Toaster exceptions and other fixes
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (3 preceding siblings ...)
  2014-11-27 17:07 ` [PATCH 04/14] toastergui: do not show project info in interactive mode Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 06/14] toasterui: fix layer identification for managed builds Alex DAMIAN
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

Changing ToasterUI to log toaster exceptions on a different level than
build errors.

Updating the build dashboard to show Toaster exceptions.

We add extra logging to console for exceptions.

Fixed a problem where packages database entries were created instead of
being looked up in the database, conficting with entries created to
satisfy dependency information.

Toaster now checks for invalid states at startup and performs needed
cleanups.

Removed loading reference to jquery-ui.min.css as we do not have this
file.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/bb/ui/buildinfohelper.py                       | 15 ++++++++--
 lib/bb/ui/toasterui.py                             |  7 +++--
 .../management/commands/checksettings.py           |  8 +++++
 lib/toaster/orm/models.py                          |  9 +++++-
 lib/toaster/toastergui/static/js/libtoaster.js     |  7 +++++
 lib/toaster/toastergui/templates/base.html         |  2 +-
 .../toastergui/templates/builddashboard.html       | 35 ++++++++++++++++++++++
 lib/toaster/toastergui/views.py                    |  2 +-
 8 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/lib/bb/ui/buildinfohelper.py b/lib/bb/ui/buildinfohelper.py
index a907a03..a3401ce 100644
--- a/lib/bb/ui/buildinfohelper.py
+++ b/lib/bb/ui/buildinfohelper.py
@@ -381,7 +381,7 @@ class ORMWrapper(object):
                 searchname = pkgpnmap[p]['OPKGN']
 
             packagedict[p]['object'], created = Package.objects.get_or_create( build = build_obj, name = searchname )
-            if created or package[p]['object'].size == -1:    # save the data anyway we can, not just if it was not created here; bug [YOCTO #6887]
+            if created or packagedict[p]['object'].size == -1:    # save the data anyway we can, not just if it was not created here; bug [YOCTO #6887]
                 # fill in everything we can from the runtime-reverse package data
                 try:
                     packagedict[p]['object'].recipe = recipes[pkgpnmap[p]['PN']]
@@ -462,7 +462,7 @@ class ORMWrapper(object):
         if 'OPKGN' in package_info.keys():
             pname = package_info['OPKGN']
 
-        bp_object = Package.objects.create( build = build_obj,
+        bp_object, created = Package.objects.get_or_create( build = build_obj,
                                        name = pname )
 
         bp_object.installed_name = package_info['PKG']
@@ -1043,6 +1043,15 @@ class BuildInfoHelper(object):
         mockevent.lineno = -1
         self.store_log_event(mockevent)
 
+    def store_log_exception(self, text, backtrace = ""):
+        mockevent = MockEvent()
+        mockevent.levelno = -1
+        mockevent.msg = text
+        mockevent.pathname = backtrace
+        mockevent.lineno = -1
+        self.store_log_event(mockevent)
+
+
     def store_log_event(self, event):
         if event.levelno < format.WARNING:
             return
@@ -1078,6 +1087,8 @@ class BuildInfoHelper(object):
             log_information['level'] = LogMessage.ERROR
         elif event.levelno == format.WARNING:
             log_information['level'] = LogMessage.WARNING
+        elif event.levelno == -1:   # toaster self-logging
+            log_information['level'] = -1
         else:
             log_information['level'] = LogMessage.INFO
 
diff --git a/lib/bb/ui/toasterui.py b/lib/bb/ui/toasterui.py
index b9e8029..9bd04df 100644
--- a/lib/bb/ui/toasterui.py
+++ b/lib/bb/ui/toasterui.py
@@ -299,12 +299,13 @@ def main(server, eventHandler, params ):
             logger.error(e)
             import traceback
             exception_data = traceback.format_exc()
+            print(exception_data)
 
             # save them to database, if possible; if it fails, we already logged to console.
             try:
-                buildinfohelper.store_log_error("%s\n%s" % (str(e), exception_data))
-            except Exception:
-                pass
+                buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data))
+            except Exception as ce:
+                print("CRITICAL: failed to to save toaster exception to the database: %s" % str(ce))
 
             pass
 
diff --git a/lib/toaster/bldcontrol/management/commands/checksettings.py b/lib/toaster/bldcontrol/management/commands/checksettings.py
index cd604eb..96d2d51 100644
--- a/lib/toaster/bldcontrol/management/commands/checksettings.py
+++ b/lib/toaster/bldcontrol/management/commands/checksettings.py
@@ -139,4 +139,12 @@ class Command(NoArgsCommand):
             ToasterSetting.objects.filter(name = 'DEFAULT_RELEASE').delete()
             ToasterSetting.objects.get_or_create(name = 'DEFAULT_RELEASE', value = '')
 
+        # we are just starting up. we must not have any builds in progress, or build environments taken
+        for b in BuildRequest.objects.filter(state = BuildRequest.REQ_INPROGRESS):
+            BRError.objects.create(req = b, errtype = "toaster", errmsg = "Toaster found this build IN PROGRESS while Toaster started up. This is an inconsistent state, and the build was marked as failed")
+
+        BuildRequest.objects.filter(state = BuildRequest.REQ_INPROGRESS).update(state = BuildRequest.REQ_FAILED)
+
+        BuildEnvironment.objects.update(lock = BuildEnvironment.LOCK_FREE)
+
         return 0
diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 364b215..34d3754 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -178,6 +178,11 @@ class Build(models.Model):
         tgts = Target.objects.filter(build_id = self.id).order_by( 'target' );
         return( tgts );
 
+    @property
+    def toaster_exceptions(self):
+        return self.logmessage_set.filter(level=LogMessage.EXCEPTION)
+
+
 class ProjectTarget(models.Model):
     project = models.ForeignKey(Project)
     target = models.CharField(max_length=100)
@@ -966,13 +971,15 @@ class HelpText(models.Model):
     text = models.TextField()
 
 class LogMessage(models.Model):
+    EXCEPTION = -1      # used to signal self-toaster-exceptions
     INFO = 0
     WARNING = 1
     ERROR = 2
 
     LOG_LEVEL = ( (INFO, "info"),
             (WARNING, "warn"),
-            (ERROR, "error") )
+            (ERROR, "error"),
+            (EXCEPTION, "toaster exception"))
 
     build = models.ForeignKey(Build)
     task  = models.ForeignKey(Task, blank = True, null=True)
diff --git a/lib/toaster/toastergui/static/js/libtoaster.js b/lib/toaster/toastergui/static/js/libtoaster.js
index 4983ef6..8e76ecb 100644
--- a/lib/toaster/toastergui/static/js/libtoaster.js
+++ b/lib/toaster/toastergui/static/js/libtoaster.js
@@ -252,6 +252,13 @@ $(document).ready(function() {
     $('.toggle-warnings').click(function() {
         $('#collapse-warnings').toggleClass('in');
     });
+    $('.show-exceptions').click(function() {
+        $('#collapse-exceptions').addClass('in');
+    });
+    $('.toggle-exceptions').click(function() {
+        $('#collapse-exceptions').toggleClass('in');
+    });
+
     //show warnings section when requested from the previous page
     if (location.href.search('#warnings') > -1) {
         $('#collapse-warnings').addClass('in');
diff --git a/lib/toaster/toastergui/templates/base.html b/lib/toaster/toastergui/templates/base.html
index f457b91..8170a3d 100644
--- a/lib/toaster/toastergui/templates/base.html
+++ b/lib/toaster/toastergui/templates/base.html
@@ -8,7 +8,7 @@
 <link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}" type='text/css'>
 <link rel="stylesheet" href="{% static 'css/prettify.css' %}" type='text/css'>
 <link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'>
-<link rel="stylesheet" href="assets/css/jquery-ui-1.10.3.custom.min.css" type='text/css'>
+
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
 <script src="{% static 'js/jquery-2.0.3.min.js' %}">
diff --git a/lib/toaster/toastergui/templates/builddashboard.html b/lib/toaster/toastergui/templates/builddashboard.html
index 2aa7b6b..e682094 100644
--- a/lib/toaster/toastergui/templates/builddashboard.html
+++ b/lib/toaster/toastergui/templates/builddashboard.html
@@ -39,6 +39,14 @@
             <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a></span>
 {%endif%}
     </div>
+    {% if build.toaster_exceptions.count > 0 %}
+    <div class="row">
+        <small class="pull-right">
+		<i class="icon-question-sign get-help get-help-blue" title="" data-original-title="Toaster exceptions do not affect your build: only the operation of Toaster"></i>
+		<a class="show-exceptions" href="#exceptions">Toaster threw {{build.toaster_exceptions.count}} exception{{build.toaster_exceptions.count|pluralize}}</a>
+	</small>
+    </div>
+    {% endif %}
   </div>
 </div>
 
@@ -223,6 +231,33 @@
 </div>
 {% endif %}
 
+
+{% if build.toaster_exceptions.count > 0 %}
+<div class="accordion span10 pull-right" id="exceptions">
+  <div class="accordion-group">
+    <div class="accordion-heading">
+      <a class="accordion-toggle exception toggle-exceptions">
+        <h2 id="exception-toggle">
+          <i class="icon-warning-sign"></i>
+          {{build.toaster_exceptions.count}} Toaster exception{{build.toaster_exceptions.count|pluralize}}
+        </h2>
+      </a>
+    </div>
+    <div class="accordion-body collapse" id="collapse-exceptions">
+      <div class="accordion-inner">
+        <div class="span10">
+          {% for exception in build.toaster_exceptions %}
+            <div class="alert alert-exception">
+              <pre>{{exception.message}}</pre>
+            </div>
+          {% endfor %}
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+{% endif %}
+
 <script type="text/javascript">
     $(document).ready(function() {
         //show warnings section when requested from the previous page
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 11c373a..b13f3e8 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -461,7 +461,7 @@ def builddashboard( request, build_id ):
     template = "builddashboard.html"
     if Build.objects.filter( pk=build_id ).count( ) == 0 :
         return redirect( builds )
-    build = Build.objects.filter( pk = build_id )[ 0 ];
+    build = Build.objects.get( pk = build_id );
     layerVersionId = Layer_Version.objects.filter( build = build_id );
     recipeCount = Recipe.objects.filter( layer_version__id__in = layerVersionId ).count( );
     tgts = Target.objects.filter( build_id = build_id ).order_by( 'target' );
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 06/14] toasterui: fix layer identification for managed builds
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (4 preceding siblings ...)
  2014-11-27 17:07 ` [PATCH 05/14] toaster: display Toaster exceptions and other fixes Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 07/14] toaster: fix loadconf path calculation Alex DAMIAN
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

If we have a managed build, we match the layers used for build
with the layers configured for project, as we know where the layers
are coming from

[YOCTO #6962]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/bb/ui/buildinfohelper.py | 38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/lib/bb/ui/buildinfohelper.py b/lib/bb/ui/buildinfohelper.py
index a3401ce..e428e4c 100644
--- a/lib/bb/ui/buildinfohelper.py
+++ b/lib/bb/ui/buildinfohelper.py
@@ -117,15 +117,14 @@ class ORMWrapper(object):
 
         if brbe is not None:
             from bldcontrol.models import BuildEnvironment, BuildRequest
-            try:
-                br, be = brbe.split(":")
-                buildrequest = BuildRequest.objects.get(pk = br)
-                buildrequest.build = build
-                buildrequest.save()
-                build.project_id = buildrequest.project_id
-                build.save()
-            except BuildRequest.DoesNotExist:
-                pass
+            br, be = brbe.split(":")
+
+            buildrequest = BuildRequest.objects.get(pk = br)
+            buildrequest.build = build
+            buildrequest.save()
+
+            build.project_id = buildrequest.project_id
+            build.save()
         return build
 
     def create_target_objects(self, target_info):
@@ -250,17 +249,30 @@ class ORMWrapper(object):
 
         return layer_version_object
 
-    def get_update_layer_object(self, layer_information):
+    def get_update_layer_object(self, layer_information, brbe):
         assert 'name' in layer_information
         assert 'local_path' in layer_information
         assert 'layer_index_url' in layer_information
 
-        layer_object, created = Layer.objects.get_or_create(
+        if brbe is None:
+            layer_object, created = Layer.objects.get_or_create(
                                 name=layer_information['name'],
                                 local_path=layer_information['local_path'],
                                 layer_index_url=layer_information['layer_index_url'])
+            return layer_object
+        else:
+            # we are under managed mode; we must match the layer used in the Project Layer
+            from bldcontrol.models import BuildEnvironment, BuildRequest
+            br, be = brbe.split(":")
+
+            buildrequest = BuildRequest.objects.get(pk = br)
+
+            # we might have a race condition here, as the project layers may change between the build trigger and the actual build execution
+            # but we can only match on the layer name, so the worst thing can happen is a mis-identification of the layer, not a total failure
+            layer_object = buildrequest.project.projectlayer_set.get(layercommit__layer__name=layer_information['name']).layercommit.layer
+
+            return layer_object
 
-        return layer_object
 
     def save_target_file_information(self, build_obj, target_obj, filedata):
         assert isinstance(build_obj, Build)
@@ -689,7 +701,7 @@ class BuildInfoHelper(object):
         layerinfos = event._localdata
         self.internal_state['lvs'] = {}
         for layer in layerinfos:
-            self.internal_state['lvs'][self.orm_wrapper.get_update_layer_object(layerinfos[layer])] = layerinfos[layer]['version']
+            self.internal_state['lvs'][self.orm_wrapper.get_update_layer_object(layerinfos[layer], self.brbe)] = layerinfos[layer]['version']
 
 
     def store_started_build(self, event):
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 07/14] toaster: fix loadconf path calculation
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (5 preceding siblings ...)
  2014-11-27 17:07 ` [PATCH 06/14] toasterui: fix layer identification for managed builds Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 08/14] toastergui: new project page Alex DAMIAN
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

Fixing the path calculation for local layer sources, as the
path need to be absolute.

Added tests for pieces of code.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 .../bldcontrol/management/commands/loadconf.py     | 42 +++++++++++++---------
 lib/toaster/bldcontrol/tests.py                    | 19 ++++++++++
 2 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/lib/toaster/bldcontrol/management/commands/loadconf.py b/lib/toaster/bldcontrol/management/commands/loadconf.py
index 6e1f97a..2257a71 100644
--- a/lib/toaster/bldcontrol/management/commands/loadconf.py
+++ b/lib/toaster/bldcontrol/management/commands/loadconf.py
@@ -5,20 +5,29 @@ import os
 
 from checksettings import DN
 
+def _reduce_canon_path(path):
+    components = []
+    for c in path.split("/"):
+        if c == "..":
+            del components[-1]
+        elif c == ".":
+            pass
+        else:
+            components.append(c)
+    if len(components) < 2:
+        components.append('')
+    return "/".join(components)
+
+def _get_id_for_sourcetype(s):
+    for i in LayerSource.SOURCE_TYPE:
+        if s == i[1]:
+            return i[0]
+    raise Exception("Could not find definition for sourcetype " + s)
+
 class Command(BaseCommand):
     help = "Loads a toasterconf.json file in the database"
     args = "filepath"
 
-    def _reduce_canon_path(self, path):
-        components = []
-        for c in path.split("/"):
-            if c == "..":
-                del components[-1]
-            elif c == ".":
-                pass
-            else:
-                components.append(c)
-        return "/".join(components)
 
 
     def _import_layer_config(self, filepath):
@@ -71,16 +80,13 @@ class Command(BaseCommand):
             assert 'name' in lsi
             assert 'branches' in lsi
 
-            def _get_id_for_sourcetype(s):
-                for i in LayerSource.SOURCE_TYPE:
-                    if s == i[1]:
-                        return i[0]
-                raise Exception("Could not find definition for sourcetype " + s)
 
             if _get_id_for_sourcetype(lsi['sourcetype']) == LayerSource.TYPE_LAYERINDEX or lsi['apiurl'].startswith("/"):
                 apiurl = lsi['apiurl']
             else:
-                apiurl = self._reduce_canon_path(os.path.join(DN(filepath), lsi['apiurl']))
+                apiurl = _reduce_canon_path(os.path.join(DN(os.path.abspath(filepath)), lsi['apiurl']))
+
+            assert ((_get_id_for_sourcetype(lsi['sourcetype']) == LayerSource.TYPE_LAYERINDEX) or apiurl.startswith("/")), (lsi['sourcetype'],apiurl)
 
             try:
                 ls = LayerSource.objects.get(sourcetype = _get_id_for_sourcetype(lsi['sourcetype']), apiurl = apiurl)
@@ -102,7 +108,7 @@ class Command(BaseCommand):
                     if layerinfo['local_path'].startswith("/"):
                         lo.local_path = layerinfo['local_path']
                     else:
-                        lo.local_path = self._reduce_canon_path(os.path.join(DN(DN(DN(filepath))), layerinfo['local_path']))
+                        lo.local_path = _reduce_canon_path(os.path.join(ls.apiurl, layerinfo['local_path']))
 
                     if not os.path.exists(lo.local_path):
                         raise Exception("Local layer path %s must exists." % lo.local_path)
@@ -110,6 +116,8 @@ class Command(BaseCommand):
                     lo.vcs_url = layerinfo['vcs_url']
                     if layerinfo['vcs_url'].startswith("remote:"):
                         lo.vcs_url = _read_git_url_from_local_repository(layerinfo['vcs_url'])
+                    else:
+                        lo.vcs_url = layerinfo['vcs_url']
 
                     if 'layer_index_url' in layerinfo:
                         lo.layer_index_url = layerinfo['layer_index_url']
diff --git a/lib/toaster/bldcontrol/tests.py b/lib/toaster/bldcontrol/tests.py
index 37d6524..5a9d1df 100644
--- a/lib/toaster/bldcontrol/tests.py
+++ b/lib/toaster/bldcontrol/tests.py
@@ -141,3 +141,22 @@ class RunBuildsCommandTests(TestCase):
         self.assertTrue(br.state == BuildRequest.REQ_INPROGRESS, "Request is not updated")
         # no more selections possible here
         self.assertRaises(IndexError, command._selectBuildRequest)
+
+
+class UtilityTests(TestCase):
+    def test_reduce_path(self):
+        from bldcontrol.management.commands.loadconf import _reduce_canon_path, _get_id_for_sourcetype
+
+        self.assertTrue( _reduce_canon_path("/") == "/")
+        self.assertTrue( _reduce_canon_path("/home/..") == "/")
+        self.assertTrue( _reduce_canon_path("/home/../ana") == "/ana")
+        self.assertTrue( _reduce_canon_path("/home/../ana/..") == "/")
+        self.assertTrue( _reduce_canon_path("/home/ana/mihai/../maria") == "/home/ana/maria")
+
+    def test_get_id_for_sorucetype(self):
+        from bldcontrol.management.commands.loadconf import _reduce_canon_path, _get_id_for_sourcetype
+        self.assertTrue( _get_id_for_sourcetype("layerindex") == 1)
+        self.assertTrue( _get_id_for_sourcetype("local") == 0)
+        self.assertTrue( _get_id_for_sourcetype("imported") == 2)
+        with self.assertRaises(Exception):
+            _get_id_for_sourcetype("unknown")
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 00/14] please pull toaster patchset
@ 2014-11-27 17:07 Alex DAMIAN
  2014-11-27 17:07 ` [PATCH 01/14] toaster: use http proxies to fetch data Alex DAMIAN
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN, Belen Barros Pena

From: Alexandru DAMIAN <alexandru.damian@intel.com>

Hi,

This is a toaster patchset consisting of new features (New Project page), and bug fixes
in toasterui data gathering, better layer identification, ability to use http_proxy
to fetch data, and other fixes.

This patch has been reviewed on "toaster/master" poky contrib.

Can you please pull at your convenience ?

Cheers,
Alex

The following changes since commit 27023ce2d264ce05008ef9af33982b054c6a87b5:

  toaster: do not show target if target name is empty (2014-11-20 15:43:57 +0000)

are available in the git repository at:

  git://git.yoctoproject.org/poky-contrib adamian/20141127-submission-bb
  http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=adamian/20141127-submission-bb

Alexandru DAMIAN (8):
  toaster: use http proxies to fetch data
  toastergui: update layer search criteria
  toastergui: do not show project info in interactive mode
  toaster: display Toaster exceptions and other fixes
  toasterui: fix layer identification for managed builds
  toaster: fix loadconf path calculation
  toastergui: new project page
  toasterui: Compatibility patch for daisy and dizzy

Belen Barros Pena (5):
  toaster: fix errors and warnings display
  toaster: make 'latest builds' section consistent across pages
  toaster: fix padding of build notifications
  toaster: release name consistency
  toaster: remove the word 'project' from layers and machine

Michael Wood (1):
  toaster: base Only show New Build button when there are > 0 projects

 lib/bb/ui/buildinfohelper.py                       |  96 ++++--
 lib/bb/ui/toasterui.py                             |   8 +-
 .../management/commands/checksettings.py           |   8 +
 .../bldcontrol/management/commands/loadconf.py     |  42 +--
 lib/toaster/bldcontrol/tests.py                    |  19 ++
 .../0018_auto__add_field_layer_version_project.py  | 331 +++++++++++++++++++++
 lib/toaster/orm/models.py                          |  58 +++-
 lib/toaster/toastergui/static/css/default.css      |   4 +
 lib/toaster/toastergui/static/js/base.js           |  13 +-
 lib/toaster/toastergui/static/js/libtoaster.js     |   7 +
 lib/toaster/toastergui/templates/base.html         |   5 +-
 .../toastergui/templates/builddashboard.html       |  35 +++
 lib/toaster/toastergui/templates/layers.html       |   9 +-
 lib/toaster/toastergui/templates/mrb_section.html  |  25 +-
 lib/toaster/toastergui/templates/newproject.html   | 116 ++++++--
 lib/toaster/toastergui/templates/project.html      |  28 +-
 lib/toaster/toastergui/templatetags/projecttags.py |   8 +
 lib/toaster/toastergui/views.py                    |  70 +++--
 18 files changed, 736 insertions(+), 146 deletions(-)
 create mode 100644 lib/toaster/orm/migrations/0018_auto__add_field_layer_version_project.py

-- 
1.9.1



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 08/14] toastergui: new project page
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (6 preceding siblings ...)
  2014-11-27 17:07 ` [PATCH 07/14] toaster: fix loadconf path calculation Alex DAMIAN
@ 2014-11-27 17:07 ` Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 09/14] toaster: fix errors and warnings display Alex DAMIAN
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:07 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

Patch that brings in to new project page according to specifications.

[YOCTO #6596]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/templates/base.html       |   2 +-
 lib/toaster/toastergui/templates/newproject.html | 116 +++++++++++++++++------
 lib/toaster/toastergui/views.py                  |   7 +-
 3 files changed, 92 insertions(+), 33 deletions(-)

diff --git a/lib/toaster/toastergui/templates/base.html b/lib/toaster/toastergui/templates/base.html
index 8170a3d..594c495 100644
--- a/lib/toaster/toastergui/templates/base.html
+++ b/lib/toaster/toastergui/templates/base.html
@@ -60,7 +60,7 @@
             </a>
             {%if MANAGED %}
             <div class="btn-group pull-right">
-              <a class="btn" href="{% url 'newproject' %}">New project</a>
+                  <a class="btn" id="new-project-button" href="{% url 'newproject' %}">New project</a>
             </div>
             <!-- New build popover -->
             <div class="btn-group pull-right" id="new-build-button">
diff --git a/lib/toaster/toastergui/templates/newproject.html b/lib/toaster/toastergui/templates/newproject.html
index 43c4e28..5a5e1e6 100644
--- a/lib/toaster/toastergui/templates/newproject.html
+++ b/lib/toaster/toastergui/templates/newproject.html
@@ -3,35 +3,91 @@
 {% load humanize %}
 {% block pagecontent %}
 <div class="row-fluid">
-				<div class="span6">
-				<div class="page-header">
-					<h1>Create a new project</h1>
-				</div>
-				<div class="container-fluid">
-		{% if alert %}
-			<div class="alert alert-error row-fluid" role="alert">{{alert}}</div>
-		{% endif %}
-				</div>
-					<form method="POST">{% csrf_token %}
-						<fieldset>
-							<label>Project name <span class="muted">(required)</span></label>
-							<input type="text" class="input-xlarge" required name="projectname" value="{{projectname}}">
-							<label class="project-form">
-								Yocto Project version
-								<i class="icon-question-sign get-help" title="This sets the branch for the Yocto Project core layers (meta, meta-yocto and meta-yocto-bsp), and for the layers you use from the OpenEmbedded Metadata Index"></i>
-							</label>
-							<select name="projectversion" id="projectversion">
-	{% for release in releases %}
-		<option value="{{release.id}}"{%if projectversion == release.id %} selected{%endif%}>{{release.name}} ({{release.description}})</option>
-	{% endfor %}
-							</select>
-						</fieldset>
+    <div class="page-header">
+          <h1>Create a new project</h1>
+        </div>
+        <div class="container-fluid">
+    {% if alert %}
+      <div class="alert alert-error row-fluid" role="alert">{{alert}}</div>
+    {% endif %}
+        </div>
+    {% if releases.count > 0 %}
+        <form method="POST">{% csrf_token %}
+            <fieldset>
+              <label>Project name <span class="muted">(required)</span></label>
+              <input type="text" class="input-xlarge" required id="new-project-name" name="projectname">
+       {% if releases.count > 1 %}
+              <label class="project-form">
+                Release version
+                <i class="icon-question-sign get-help" title="The version of the build system you want to use"></i>
+              </label>
+              <select name="projectversion" id="projectversion">
+  {% for release in releases %}
+    <option value="{{release.id}}"{%if projectversion == release.id %} selected{%endif%}>{{release.description}} ({{release.name}})</option>
+  {% endfor %}
+              </select>
+  {% for release in releases %}
+    <div class="row-fluid helptext" id="description-{{release.id}}" style="display: none">
+        <span class="help-block span5">{{release.helptext|safe}}</span>
+    </div>
+  {% endfor %}
+       {% else %}
+    <input type="hidden" name="projectversion" value="{{releases.0.id}}"/>
+       {% endif %}
+            </fieldset>
 
-						<div class="form-actions">
-							<input type="submit" class="btn btn-primary btn-large" value="Create project"/>
-						</div>
-					</form>
-				</div>
-			</div>
-		</div>
+            <div class="form-actions">
+              <input type="submit" class="btn btn-primary btn-large" value="Create project"></input>
+              <span class="help-inline" style="vertical-align:middle;">To create a project, you need to enter a project name</span>
+            </div>
+        </form>
+    {% else %}
+    <br/>
+    <div class="alert alert-warning row-fluid span6">
+    <h3>No releases configured</h3>
+    <p>
+    It looks like Toaster releases have not been configured properly. Contact the person who set up Toaster, and tell them about it.
+    </p>
+    <p>
+    If you are the Toaster administrator, we are sorry: setting up Toaster is not easy.
+    <ul>
+    <li><a href="{% url 'admin:orm_release_changelist' %}">Log in to the Django administration interface</a> and check  the "Releases" section.</li>
+    <li>Check out the <a href="https://wiki.yoctoproject.org/wiki/Setting_up_a_hosted_managed_mode_for_Toaster#Releases">documentation about configuring releases</a></li>
+    </ul>
+    </p>
+    </div>
+    {% endif %}
+
+    </div>
+    <script type="text/javascript">
+        $(document).ready(function () {
+            // hide the new project button
+            $("#new-project-button").hide();
+            $('.btn-primary').attr('disabled', 'disabled');
+
+            // enable submit button when all required fields are populated
+            $("input#new-project-name").keyup(function() {
+                if ($("input#new-project-name").val().length > 0 ){
+                    $('.btn-primary').removeAttr('disabled');
+                    $(".help-inline").css('visibility','hidden');
+                }
+                else {
+                    $('.btn-primary').attr('disabled', 'disabled');
+                    $(".help-inline").css('visibility','visible');
+                }
+            });
+
+            // show relevant help text for the selected release
+            var selected_release = $('select').val();
+            $("#description-" + selected_release).show();
+
+
+			$('select').change(function(){
+				var new_release = $('select').val();
+                $(".helptext").hide();
+				$('#description-' + new_release).fadeIn();
+			});
+        })
+    </script>
+</div>
 {% endblock %}
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index b13f3e8..49a7769 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1894,9 +1894,12 @@ if toastermain.settings.MANAGED:
             'email': request.user.email if request.user.is_authenticated() else '',
             'username': request.user.username if request.user.is_authenticated() else '',
             'releases': Release.objects.order_by("id"),
-            'defaultbranch': ToasterSetting.objects.get(name = "DEFAULT_RELEASE").value,
         }
 
+        try:
+            context['defaultbranch'] = ToasterSetting.objects.get(name = "DEFAULT_RELEASE").value
+        except ToasterSetting.DoesNotExist:
+            pass
 
         if request.method == "GET":
             # render new project page
@@ -2156,7 +2159,7 @@ if toastermain.settings.MANAGED:
 
 
             def _lv_to_dict(x):
-                return {"id": x.pk, "name": x.layer.name, 
+                return {"id": x.pk, "name": x.layer.name,
                         "detail": "(" + x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.up_branch.name+")"),
                         "giturl": x.layer.vcs_url, "layerdetailurl" : reverse('layerdetails', args=(x.pk,))}
 
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 09/14] toaster: fix errors and warnings display
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (7 preceding siblings ...)
  2014-11-27 17:07 ` [PATCH 08/14] toastergui: new project page Alex DAMIAN
@ 2014-11-27 17:08 ` Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 10/14] toaster: make 'latest builds' section consistent across pages Alex DAMIAN
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:08 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN, Belen Barros Pena

From: Belen Barros Pena <belen.barros.pena@linux.intel.com>

In the 'Latest builds' section of the project page,
show number of errors and number of warnings as we
show them in the all builds page.

Signed-off-by: Belen Barros Pena <belen.barros.pena@linux.intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/templates/project.html | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/lib/toaster/toastergui/templates/project.html b/lib/toaster/toastergui/templates/project.html
index 18a52bf..0b2821c 100644
--- a/lib/toaster/toastergui/templates/project.html
+++ b/lib/toaster/toastergui/templates/project.html
@@ -178,8 +178,24 @@ vim: expandtab tabstop=2
                  {[b.build[0].completed_on|date:'dd/MM/yy HH:mm']}
               </ngif>
             </div>
-            <div class="span2"><span><a href="{[b.build[0].build_page_url]}#errors" class="lead error" ng-if="b.build[0].errors">{[b.build[0].errors]}</a></span></div>
-            <div class="span2"><span><a href="{[b.build[0].build_page_url]}#warnings" class="lead warning" ng-if="b.build[0].warnings">{[b.build[0].warnings]}</a></span></div>
+            <div class="span2">
+              <ngif ng-if="b.build[0].errors">
+                <span>
+                  <i class="icon-minus-sign red lead"></i>
+                  <a href="{[b.build[0].build_page_url]}#errors" class="lead error">{[b.build[0].errors]}
+                  <ng-pluralize count="b.build[0].errors" when="{'1':'error','other':'errors'}"></ng-pluralize></a>
+                </span>
+              </ngif>
+            </div>
+            <div class="span2">
+              <ngif ng-if="b.build[0].warnings">
+                <span>
+                  <i class="icon-warning-sign yellow lead"></i>
+                  <a href="{[b.build[0].build_page_url]}#warnings" class="lead warning">{[b.build[0].warnings]}
+                  <ng-pluralize count="b.build[0].warnings" when="{'1':'warning','other':'warnings'}"></ng-pluralize></a>
+                </span>
+              </ngif>
+            </div>
             <div> <span class="lead">Build time: <a href="{[b.build[0].build_time_page_url]}">{[b.build[0].build_time|timediff]}</a></span>
                 <button class="btn pull-right" ng-class="{'Succeeded':  'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]"
                     ng-click="targetExistingBuild(b.targets)">Run again</button>
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 10/14] toaster: make 'latest builds' section consistent across pages
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (8 preceding siblings ...)
  2014-11-27 17:08 ` [PATCH 09/14] toaster: fix errors and warnings display Alex DAMIAN
@ 2014-11-27 17:08 ` Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 11/14] toaster: fix padding of build notifications Alex DAMIAN
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:08 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN, Belen Barros Pena

From: Belen Barros Pena <belen.barros.pena@linux.intel.com>

Make sure that the 'latest builds' sections in the all builds
page and the project page are identical:

* no icon to represent build outcome
* remove machine name
* show date only when the build is more than 24 hours old
* same date and time format

Signed-off-by: Belen Barros Pena <belen.barros.pena@linux.intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/templates/mrb_section.html  | 15 +++++++++++----
 lib/toaster/toastergui/templatetags/projecttags.py |  8 ++++++++
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/lib/toaster/toastergui/templates/mrb_section.html b/lib/toaster/toastergui/templates/mrb_section.html
index 4237980..33afb7b 100644
--- a/lib/toaster/toastergui/templates/mrb_section.html
+++ b/lib/toaster/toastergui/templates/mrb_section.html
@@ -7,7 +7,7 @@
 
   <div class="page-header top-air">
       <h1>
-          Latest Builds
+          Latest builds
        </h1>
   </div>
   <div id="latest-builds">
@@ -18,16 +18,23 @@
     {% endif %}
 
         <div class="row-fluid">
-            <div class="span4 lead">
-                {%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%}
+            <div class="span3 lead">
     {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
                 <a href="{%url 'builddashboard' build.pk%}" class="{%if build.outcome == build.SUCCEEDED %}success{%else%}error{%endif%}">
     {% endif %}
-                <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>
+                <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%}
+		        </span>
     {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
                 </a>
     {% endif %}
             </div>
+            <div class="span2 lead">
+                {% if build.completed_on|format_build_date  %}
+                    {{ build.completed_on|date:'d/m/y H:i' }}
+                {% else %}
+                    {{ build.completed_on|date:'H:i' }}
+                {% endif %}
+            </div>
     {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
             <div class="span2 lead">
       {% if  build.errors_no %}
diff --git a/lib/toaster/toastergui/templatetags/projecttags.py b/lib/toaster/toastergui/templatetags/projecttags.py
index 99fd4cf..f564edf 100644
--- a/lib/toaster/toastergui/templatetags/projecttags.py
+++ b/lib/toaster/toastergui/templatetags/projecttags.py
@@ -268,3 +268,11 @@ def get_dict_value(dictionary, key):
         return dictionary[key]
     except (KeyError, IndexError):
         return ''
+
+@register.filter
+def format_build_date(completed_on):
+    now = timezone.now()
+    delta = now - completed_on
+
+    if delta.days >= 1:
+        return True
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 11/14] toaster: fix padding of build notifications
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (9 preceding siblings ...)
  2014-11-27 17:08 ` [PATCH 10/14] toaster: make 'latest builds' section consistent across pages Alex DAMIAN
@ 2014-11-27 17:08 ` Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 12/14] toasterui: Compatibility patch for daisy and dizzy Alex DAMIAN
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:08 UTC (permalink / raw)
  To: bitbake-devel

From: Belen Barros Pena <belen.barros.pena@intel.com>

In managed mode, we show the name of the project in the build
notifications of the all builds page. The way we show the
project requires modifying the default padding of the .alert
class. This patch makes sure the padding modification is
only applied in managed mode, i.e., when the project name
needs to be shown.

Signed-off-by: Belen Barros Pena <belen.barros.pena@intel.com>
---
 lib/toaster/toastergui/static/css/default.css     | 4 ++++
 lib/toaster/toastergui/templates/mrb_section.html | 4 ++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/lib/toaster/toastergui/static/css/default.css b/lib/toaster/toastergui/static/css/default.css
index dcb8e34..199c753 100644
--- a/lib/toaster/toastergui/static/css/default.css
+++ b/lib/toaster/toastergui/static/css/default.css
@@ -136,6 +136,10 @@ select { width: auto; }
 .new-build .alert { margin-top: 10px; }
 .new-build .alert p { margin-top: 10px; }
 
+/* styles for showing the project name in build mode */
+.project-name { padding-top: 0; }
+.project-name .label { font-weight: normal; margin-bottom: 5px; margin-left: -15px; padding: 5px; }
+
 /* Remove bottom margin for forms inside modal dialogs */
 #dependencies_modal_form { margin-bottom: 0px; }
 
diff --git a/lib/toaster/toastergui/templates/mrb_section.html b/lib/toaster/toastergui/templates/mrb_section.html
index 33afb7b..73031e2 100644
--- a/lib/toaster/toastergui/templates/mrb_section.html
+++ b/lib/toaster/toastergui/templates/mrb_section.html
@@ -12,9 +12,9 @@
   </div>
   <div id="latest-builds">
   {% for build in mru %}
-    <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}" style="padding-top: 0;">
+    <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%} {% if MANAGED and build.project %}project-name{% endif %} ">
     {% if MANAGED and build.project %}
-       <span class="label {%if build.outcome == build.SUCCEEDED%}label-success{%elif build.outcome == build.FAILED%}label-danger{%else%}label-info{%endif%}" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;"> {{build.project.name}} </span>
+       <span class="label {%if build.outcome == build.SUCCEEDED%}label-success{%elif build.outcome == build.FAILED%}label-danger{%else%}label-info{%endif%}"> {{build.project.name}} </span>
     {% endif %}
 
         <div class="row-fluid">
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 12/14] toasterui: Compatibility patch for daisy and dizzy
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (10 preceding siblings ...)
  2014-11-27 17:08 ` [PATCH 11/14] toaster: fix padding of build notifications Alex DAMIAN
@ 2014-11-27 17:08 ` Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 13/14] toaster: release name consistency Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 14/14] toaster: remove the word 'project' from layers and machine Alex DAMIAN
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:08 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

This patch brings in changes that allow a toasterUI coming in
from 'master' branch to record data from a 'daisy' or 'dizzy'
bitbake server.

This is needed to allow Toaster to record builds running
on older branch releases.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/bb/ui/buildinfohelper.py | 43 ++++++++++++++++++++++++++-----------------
 lib/bb/ui/toasterui.py       |  3 +--
 2 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/lib/bb/ui/buildinfohelper.py b/lib/bb/ui/buildinfohelper.py
index e428e4c..9aa8fe3 100644
--- a/lib/bb/ui/buildinfohelper.py
+++ b/lib/bb/ui/buildinfohelper.py
@@ -695,10 +695,19 @@ class BuildInfoHelper(object):
 
     ################################
     ## external available methods to store information
+    @staticmethod
+    def _get_data_from_event(event):
+        evdata = None
+        if '_localdata' in vars(event):
+            evdata = event._localdata
+        elif 'data' in vars(event):
+            evdata = event.data
+        else:
+            raise Exception("Event with neither _localdata or data properties")
+        return evdata
 
     def store_layer_info(self, event):
-        assert '_localdata' in vars(event)
-        layerinfos = event._localdata
+        layerinfos = BuildInfoHelper._get_data_from_event(event)
         self.internal_state['lvs'] = {}
         for layer in layerinfos:
             self.internal_state['lvs'][self.orm_wrapper.get_update_layer_object(layerinfos[layer], self.brbe)] = layerinfos[layer]['version']
@@ -732,15 +741,16 @@ class BuildInfoHelper(object):
         return self.brbe
 
 
-
     def update_target_image_file(self, event):
         image_fstypes = self.server.runCommand(["getVariable", "IMAGE_FSTYPES"])[0]
+        evdata = BuildInfoHelper._get_data_from_event(event)
+
         for t in self.internal_state['targets']:
             if t.is_image == True:
-                output_files = list(event._localdata.viewkeys())
+                output_files = list(evdata.viewkeys())
                 for output in output_files:
                     if t.target in output and output.split('.rootfs.')[1] in image_fstypes:
-                        self.orm_wrapper.save_target_image_file_information(t, output, event._localdata[output])
+                        self.orm_wrapper.save_target_image_file_information(t, output, evdata[output])
 
     def update_build_information(self, event, errors, warnings, taskfailures):
         if 'build' in self.internal_state:
@@ -748,8 +758,8 @@ class BuildInfoHelper(object):
 
 
     def store_license_manifest_path(self, event):
-        deploy_dir = event._localdata['deploy_dir']
-        image_name =  event._localdata['image_name']
+        deploy_dir = BuildInfoHelper._get_data_from_event(event)['deploy_dir']
+        image_name = BuildInfoHelper._get_data_from_event(event)['image_name']
         path = deploy_dir + "/licenses/" + image_name + "/"
         for target in self.internal_state['targets']:
             if target.target in image_name:
@@ -797,7 +807,7 @@ class BuildInfoHelper(object):
 
 
     def store_tasks_stats(self, event):
-        for (taskfile, taskname, taskstats, recipename) in event._localdata:
+        for (taskfile, taskname, taskstats, recipename) in BuildInfoHelper._get_data_from_event(event):
             localfilepath = taskfile.split(":")[-1]
             assert localfilepath.startswith("/")
 
@@ -812,7 +822,8 @@ class BuildInfoHelper(object):
             task_information['task_name'] = taskname
             task_information['cpu_usage'] = taskstats['cpu_usage']
             task_information['disk_io'] = taskstats['disk_io']
-            task_information['elapsed_time'] = taskstats['elapsed_time']
+            if 'elapsed_time' in taskstats:
+                task_information['elapsed_time'] = taskstats['elapsed_time']
             task_obj = self.orm_wrapper.get_update_task_object(task_information, True)  # must exist
 
     def update_and_store_task(self, event):
@@ -870,7 +881,7 @@ class BuildInfoHelper(object):
 
 
     def store_missed_state_tasks(self, event):
-        for (fn, taskname, taskhash, sstatefile) in event._localdata['missed']:
+        for (fn, taskname, taskhash, sstatefile) in BuildInfoHelper._get_data_from_event(event)['missed']:
 
             identifier = fn + taskname + "_setscene"
             recipe_information = self._get_recipe_information_from_taskfile(fn)
@@ -888,7 +899,7 @@ class BuildInfoHelper(object):
 
             self.orm_wrapper.get_update_task_object(task_information)
 
-        for (fn, taskname, taskhash, sstatefile) in event._localdata['found']:
+        for (fn, taskname, taskhash, sstatefile) in BuildInfoHelper._get_data_from_event(event)['found']:
 
             identifier = fn + taskname + "_setscene"
             recipe_information = self._get_recipe_information_from_taskfile(fn)
@@ -904,15 +915,14 @@ class BuildInfoHelper(object):
 
 
     def store_target_package_data(self, event):
-        assert '_localdata' in vars(event)
         # for all image targets
         for target in self.internal_state['targets']:
             if target.is_image:
                 try:
-                    pkgdata = event._localdata['pkgdata']
-                    imgdata = event._localdata['imgdata'][target.target]
+                    pkgdata = BuildInfoHelper._get_data_from_event(event)['pkgdata']
+                    imgdata = BuildInfoHelper._get_data_from_event(event)['imgdata'][target.target]
                     self.orm_wrapper.save_target_package_information(self.internal_state['build'], target, imgdata, pkgdata, self.internal_state['recipes'])
-                    filedata = event._localdata['filedata'][target.target]
+                    filedata = BuildInfoHelper._get_data_from_event(event)['filedata'][target.target]
                     self.orm_wrapper.save_target_file_information(self.internal_state['build'], target, filedata)
                 except KeyError:
                     # we must have not got the data for this image, nothing to save
@@ -1026,8 +1036,7 @@ class BuildInfoHelper(object):
 
 
     def store_build_package_information(self, event):
-        assert '_localdata' in vars(event)
-        package_info = event._localdata
+        package_info = BuildInfoHelper._get_data_from_event(event)
         self.orm_wrapper.save_build_package_information(self.internal_state['build'],
                             package_info,
                             self.internal_state['recipes'],
diff --git a/lib/bb/ui/toasterui.py b/lib/bb/ui/toasterui.py
index 9bd04df..3a6104b 100644
--- a/lib/bb/ui/toasterui.py
+++ b/lib/bb/ui/toasterui.py
@@ -296,10 +296,9 @@ def main(server, eventHandler, params ):
             pass
         except Exception as e:
             # print errors to log
-            logger.error(e)
             import traceback
             exception_data = traceback.format_exc()
-            print(exception_data)
+            logger.error("%s\n%s" % (e, exception_data))
 
             # save them to database, if possible; if it fails, we already logged to console.
             try:
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 13/14] toaster: release name consistency
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (11 preceding siblings ...)
  2014-11-27 17:08 ` [PATCH 12/14] toasterui: Compatibility patch for daisy and dizzy Alex DAMIAN
@ 2014-11-27 17:08 ` Alex DAMIAN
  2014-11-27 17:08 ` [PATCH 14/14] toaster: remove the word 'project' from layers and machine Alex DAMIAN
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:08 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Belen Barros Pena

From: Belen Barros Pena <belen.barros.pena@linux.intel.com>

Small changes to the project, new project and all layers
pages to ensure consitency in release naming across the
interface.

The changes are:

* In the new project page, change the label 'release version' to
'release'

* In the new project page, sort the releases in the dropdown menu
in ascending alphabetical order

* In the new project page, remove the release name that was
showing between brackets after the release description in the
dropdown menu

* In the project page, make sure the release information
shows the release description field instead of the release name,
to keep consistency with the new project page

* In the all layers page, provide some help text for the branch 'HEAD'

Signed-off-by: Belen Barros Pena <belen.barros.pena@linux.intel.com>
---
 lib/toaster/toastergui/templates/layers.html     | 9 ++++++++-
 lib/toaster/toastergui/templates/newproject.html | 4 ++--
 lib/toaster/toastergui/templates/project.html    | 4 ++--
 lib/toaster/toastergui/views.py                  | 4 ++--
 4 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/lib/toaster/toastergui/templates/layers.html b/lib/toaster/toastergui/templates/layers.html
index 4e92332..ced54c2 100644
--- a/lib/toaster/toastergui/templates/layers.html
+++ b/lib/toaster/toastergui/templates/layers.html
@@ -52,7 +52,14 @@
             <a target="_blank" href="{{ o.get_vcs_dirpath_link_url }}"><i class="icon-share get-info"></i></a>
                 {% endif %}
         </td>
-            <td class="branch">{% if o.branch %}{{o.branch}}{% else %}{{o.up_branch.name}}{% endif %}</td>
+            <td class="branch">
+                {% if o.branch %}
+                    {{o.branch}}
+                {% else %}
+                    {{o.up_branch.name}}
+                    <i class="icon-question-sign get-help hover-help" title="Your builds will use the tip of the branch you have cloned or downloaded to your computer, so nothing will be fetched"></i>
+                {% endif %}
+            </td>
             <td class="dependencies">
         {% with ods=o.dependencies.all%}
             {% if ods.count %}
diff --git a/lib/toaster/toastergui/templates/newproject.html b/lib/toaster/toastergui/templates/newproject.html
index 5a5e1e6..512a8fa 100644
--- a/lib/toaster/toastergui/templates/newproject.html
+++ b/lib/toaster/toastergui/templates/newproject.html
@@ -18,12 +18,12 @@
               <input type="text" class="input-xlarge" required id="new-project-name" name="projectname">
        {% if releases.count > 1 %}
               <label class="project-form">
-                Release version
+                Release
                 <i class="icon-question-sign get-help" title="The version of the build system you want to use"></i>
               </label>
               <select name="projectversion" id="projectversion">
   {% for release in releases %}
-    <option value="{{release.id}}"{%if projectversion == release.id %} selected{%endif%}>{{release.description}} ({{release.name}})</option>
+    <option value="{{release.id}}"{%if projectversion == release.id %} selected{%endif%}>{{release.description}}</option>
   {% endfor %}
               </select>
   {% for release in releases %}
diff --git a/lib/toaster/toastergui/templates/project.html b/lib/toaster/toastergui/templates/project.html
index 0b2821c..fdfc3af 100644
--- a/lib/toaster/toastergui/templates/project.html
+++ b/lib/toaster/toastergui/templates/project.html
@@ -350,13 +350,13 @@ vim: expandtab tabstop=2
       <i class="icon-question-sign get-help heading-help" title="The version of the build system you want to use"></i>
     </h3>
     <p class="lead" id="change-project-version-opposite">
-      <span id="project-version">{[project.release.name]}</span>
+      <span id="project-version">{[project.release.desc]}</span>
       <i id="change-version" class="icon-pencil" ng-click="toggle('#change-project-version')" ></i>
     </p>
     <div class="div-inline" id="change-project-version" style="display:none;">
       <form ng-submit="test('#change-project-version')" class="input-append">
         <select id="select-version" ng-model="projectVersion">
-          <option ng-repeat="r in releases" value="{[r.id]}" ng-selected="r.id == project.release.id">{[r.name]}</option>
+          <option ng-repeat="r in releases" value="{[r.id]}" ng-selected="r.id == project.release.id">{[r.description]}</option>
         </select>
         <input type="submit" class="btn" style="margin-left:5px;" value="Save" ng-disabled="project.release.id == projectVersion"/>
         <input type="reset"  class="btn btn-link" value="Cancel" ng-click="toggle('#change-project-version')" ng-disabled="project.release.id == projectVersion"/>
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 49a7769..8301f6c 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1893,7 +1893,7 @@ if toastermain.settings.MANAGED:
         context = {
             'email': request.user.email if request.user.is_authenticated() else '',
             'username': request.user.username if request.user.is_authenticated() else '',
-            'releases': Release.objects.order_by("id"),
+            'releases': Release.objects.order_by("description"),
         }
 
         try:
@@ -2016,7 +2016,7 @@ if toastermain.settings.MANAGED:
                     prj.projectlayer_set.all().order_by("id")),
             "targets" : map(lambda x: {"target" : x.target, "task" : x.task, "pk": x.pk}, prj.projecttarget_set.all()),
             "freqtargets": freqtargets,
-            "releases": map(lambda x: {"id": x.pk, "name": x.name}, Release.objects.all()),
+            "releases": map(lambda x: {"id": x.pk, "name": x.name, "description":x.description}, Release.objects.all()),
         }
         try:
             context["machine"] = {"name": prj.projectvariable_set.get(name="MACHINE").value}
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 14/14] toaster: remove the word 'project' from layers and machine
  2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
                   ` (12 preceding siblings ...)
  2014-11-27 17:08 ` [PATCH 13/14] toaster: release name consistency Alex DAMIAN
@ 2014-11-27 17:08 ` Alex DAMIAN
  13 siblings, 0 replies; 15+ messages in thread
From: Alex DAMIAN @ 2014-11-27 17:08 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Belen Barros Pena

From: Belen Barros Pena <belen.barros.pena@linux.intel.com>

Remove the word 'project' from the 'Layers' and 'Machine'
sections of the project page, following feedback from the
QA team, who suggested that the word 'project'
raised questions regarding the scope of the configuration,

Signed-off-by: Belen Barros Pena <belen.barros.pena@linux.intel.com>
---
 lib/toaster/toastergui/templates/project.html | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/toaster/toastergui/templates/project.html b/lib/toaster/toastergui/templates/project.html
index fdfc3af..113e382 100644
--- a/lib/toaster/toastergui/templates/project.html
+++ b/lib/toaster/toastergui/templates/project.html
@@ -227,7 +227,7 @@ vim: expandtab tabstop=2
     <!-- project layers -->
     <div id="layer-container" class="well well-transparent span4">
       <h3>
-        Project layers <span class="muted counter">({[layers.length]})</span>
+        Layers <span class="muted counter">({[layers.length]})</span>
         <i class="icon-question-sign get-help heading-help" title="OpenEmbedded organises metadata into modules called 'layers'. Layers allow you to isolate different types of customizations from each other. <a href='http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers' target='_blank'>More on layers</a>"></i>
       </h3>
       <div class="alert" ng-if="!layers.length">
@@ -292,7 +292,7 @@ vim: expandtab tabstop=2
     <!-- project configuration -->
     <div id="machine-distro" class="well well-transparent span4">
       <h3>
-        Project machine
+        Machine
         <i class="icon-question-sign get-help heading-help" title="The machine is the hardware for which you want to build. You can only set one machine per project"></i>
       </h3>
       <p class="lead" id="select-machine-opposite">
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2014-11-27 17:08 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-27 17:07 [PATCH 00/14] please pull toaster patchset Alex DAMIAN
2014-11-27 17:07 ` [PATCH 01/14] toaster: use http proxies to fetch data Alex DAMIAN
2014-11-27 17:07 ` [PATCH 02/14] toaster: base Only show New Build button when there are > 0 projects Alex DAMIAN
2014-11-27 17:07 ` [PATCH 03/14] toastergui: update layer search criteria Alex DAMIAN
2014-11-27 17:07 ` [PATCH 04/14] toastergui: do not show project info in interactive mode Alex DAMIAN
2014-11-27 17:07 ` [PATCH 05/14] toaster: display Toaster exceptions and other fixes Alex DAMIAN
2014-11-27 17:07 ` [PATCH 06/14] toasterui: fix layer identification for managed builds Alex DAMIAN
2014-11-27 17:07 ` [PATCH 07/14] toaster: fix loadconf path calculation Alex DAMIAN
2014-11-27 17:07 ` [PATCH 08/14] toastergui: new project page Alex DAMIAN
2014-11-27 17:08 ` [PATCH 09/14] toaster: fix errors and warnings display Alex DAMIAN
2014-11-27 17:08 ` [PATCH 10/14] toaster: make 'latest builds' section consistent across pages Alex DAMIAN
2014-11-27 17:08 ` [PATCH 11/14] toaster: fix padding of build notifications Alex DAMIAN
2014-11-27 17:08 ` [PATCH 12/14] toasterui: Compatibility patch for daisy and dizzy Alex DAMIAN
2014-11-27 17:08 ` [PATCH 13/14] toaster: release name consistency Alex DAMIAN
2014-11-27 17:08 ` [PATCH 14/14] toaster: remove the word 'project' from layers and machine Alex DAMIAN

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox