All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/10] toaster: bitbake cooker log saving and downloading
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
@ 2015-02-18 19:10 ` Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 02/10] toaster: properly detect starting in rolling log file Alex DAMIAN
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:10 UTC (permalink / raw)
  To: bitbake-devel

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

This patch brings in cooker log saving and proper download links.

* toasterui will now write the cooker log file if running in managed
mode
* the BuildRequest has a new state, REQ_ARCHIVE, indicating that the
build is completed, and the artifacts are ready to be grabbed
* the runbuild test execution commands will gather needed artifacts,
and save them to a storage directory selected during Toaster setup.
* the build dashboard, project builds and all builds pages have
permanent links for the cooker log

[YOCTO #7220]
[YOCTO #7206]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/bb/ui/buildinfohelper.py                       |   3 +-
 lib/bb/ui/toasterui.py                             |  29 ++++-
 .../management/commands/checksettings.py           |  17 +++
 .../bldcontrol/management/commands/runbuilds.py    |  29 ++++-
 .../bldcontrol/migrations/0008_brarchive.py        | 138 +++++++++++++++++++++
 lib/toaster/bldcontrol/models.py                   |   2 +
 lib/toaster/toastergui/templates/build.html        |   9 +-
 .../toastergui/templates/builddashboard.html       |  11 +-
 .../toastergui/templates/managed_builds.html       |   9 +-
 .../toastergui/templates/projectbuilds.html        |  14 ++-
 .../toastergui/templates/unavailable_artifact.html |  17 +++
 lib/toaster/toastergui/views.py                    |  94 +++++++++++---
 lib/toaster/toastermain/urls.py                    |   6 +-
 13 files changed, 335 insertions(+), 43 deletions(-)
 create mode 100644 lib/toaster/bldcontrol/migrations/0008_brarchive.py
 create mode 100644 lib/toaster/toastergui/templates/unavailable_artifact.html

diff --git a/lib/bb/ui/buildinfohelper.py b/lib/bb/ui/buildinfohelper.py
index 491fd15..1096ccf 100644
--- a/lib/bb/ui/buildinfohelper.py
+++ b/lib/bb/ui/buildinfohelper.py
@@ -1114,7 +1114,8 @@ class BuildInfoHelper(object):
         be.save()
         br = BuildRequest.objects.get(pk = br_id)
         if errorcode == 0:
-            br.state = BuildRequest.REQ_COMPLETED
+            # request archival of the project artifacts
+            br.state = BuildRequest.REQ_ARCHIVE
         else:
             br.state = BuildRequest.REQ_FAILED
         br.save()
diff --git a/lib/bb/ui/toasterui.py b/lib/bb/ui/toasterui.py
index a85ad5a..df9f362 100644
--- a/lib/bb/ui/toasterui.py
+++ b/lib/bb/ui/toasterui.py
@@ -58,7 +58,12 @@ def _log_settings_from_server(server):
     if error:
         logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
         raise BaseException(error)
-    return includelogs, loglines
+    consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
+    if error:
+        logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
+        raise BaseException(error)
+    return includelogs, loglines, consolelogfile
+
 
 def main(server, eventHandler, params ):
 
@@ -71,7 +76,7 @@ def main(server, eventHandler, params ):
     console.setFormatter(format)
     logger.addHandler(console)
 
-    includelogs, loglines = _log_settings_from_server(server)
+    includelogs, loglines, consolelogfile = _log_settings_from_server(server)
 
     # verify and warn
     build_history_enabled = True
@@ -96,6 +101,16 @@ def main(server, eventHandler, params ):
 
     buildinfohelper = BuildInfoHelper(server, build_history_enabled)
 
+    if buildinfohelper.brbe is not None and consolelogfile:
+        # if we are under managed mode we have no other UI and we need to write our own file
+        bb.utils.mkdirhier(os.path.dirname(consolelogfile))
+        conlogformat = bb.msg.BBLogFormatter(format_str)
+        consolelog = logging.FileHandler(consolelogfile)
+        bb.msg.addDefaultlogFilter(consolelog)
+        consolelog.setFormatter(conlogformat)
+        logger.addHandler(consolelog)
+
+
     while True:
         try:
             event = eventHandler.waitEvent(0.25)
@@ -115,8 +130,12 @@ def main(server, eventHandler, params ):
 
             if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
                 buildinfohelper.update_and_store_task(event)
+                logger.warn("Logfile for task %s" % event.logfile)
                 continue
 
+            if isinstance(event, bb.build.TaskBase):
+                logger.info(event._message)
+
             if isinstance(event, bb.event.LogExecTTY):
                 logger.warn(event.msg)
                 continue
@@ -162,7 +181,12 @@ def main(server, eventHandler, params ):
             if isinstance(event, bb.event.CacheLoadCompleted):
                 continue
             if isinstance(event, bb.event.MultipleProviders):
+                logger.info("multiple providers are available for %s%s (%s)", event._is_runtime and "runtime " or "",
+                            event._item,
+                            ", ".join(event._candidates))
+                logger.info("consider defining a PREFERRED_PROVIDER entry to match %s", event._item)
                 continue
+
             if isinstance(event, bb.event.NoProvider):
                 return_value = 1
                 errors = errors + 1
@@ -229,6 +253,7 @@ def main(server, eventHandler, params ):
                     buildinfohelper.store_log_event(event)
                     errors += 1
                     errorcode = 1
+                    logger.error("Command execution failed: %s", event.error)
 
                 buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
                 buildinfohelper.close(errorcode)
diff --git a/lib/toaster/bldcontrol/management/commands/checksettings.py b/lib/toaster/bldcontrol/management/commands/checksettings.py
index 5d80bc7..1ff5c92 100644
--- a/lib/toaster/bldcontrol/management/commands/checksettings.py
+++ b/lib/toaster/bldcontrol/management/commands/checksettings.py
@@ -62,6 +62,23 @@ class Command(NoArgsCommand):
 
 
     def handle(self, **options):
+        # verify that we have a settings for downloading artifacts
+        while ToasterSetting.objects.filter(name="ARTIFACTS_STORAGE_DIR").count() == 0:
+            guessedpath = os.getcwd() + "/toaster_build_artifacts/"
+            print("Toaster needs to know in which directory it can download build log files and other artifacts.\n Toaster suggests \"%s\"." % guessedpath)
+            artifacts_storage_dir = raw_input(" Press Enter to select \"%s\" or type the full path to a different directory: " % guessedpath)
+            if len(artifacts_storage_dir) == 0:
+                artifacts_storage_dir = guessedpath
+            if len(artifacts_storage_dir) > 0 and artifacts_storage_dir.startswith("/"):
+                try:
+                    os.makedirs(artifacts_storage_dir)
+                except OSError as ose:
+                    if "File exists" in str(ose):
+                        pass
+                    else:
+                        raise ose
+                ToasterSetting.objects.create(name="ARTIFACTS_STORAGE_DIR", value=artifacts_storage_dir)
+
         self.guesspath = DN(DN(DN(DN(DN(DN(DN(__file__)))))))
         # refuse to start if we have no build environments
         while BuildEnvironment.objects.count() == 0:
diff --git a/lib/toaster/bldcontrol/management/commands/runbuilds.py b/lib/toaster/bldcontrol/management/commands/runbuilds.py
index 3de582c..808318f 100644
--- a/lib/toaster/bldcontrol/management/commands/runbuilds.py
+++ b/lib/toaster/bldcontrol/management/commands/runbuilds.py
@@ -1,6 +1,6 @@
 from django.core.management.base import NoArgsCommand, CommandError
 from django.db import transaction
-from orm.models import Build
+from orm.models import Build, ToasterSetting
 from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException, BuildSetupException
 from bldcontrol.models import BuildRequest, BuildEnvironment, BRError, BRVariable
 import os
@@ -93,7 +93,33 @@ class Command(NoArgsCommand):
             bec.be.lock = BuildEnvironment.LOCK_FREE
             bec.be.save()
 
+    def archive(self):
+        ''' archives data from the builds '''
+        artifact_storage_dir = ToasterSetting.objects.get(name="ARTIFACTS_STORAGE_DIR").value
+        for br in BuildRequest.objects.filter(state = BuildRequest.REQ_ARCHIVE):
+            # save cooker log
+            if br.build == None:
+                br.state = BuildRequest.REQ_FAILED
+                br.save()
+                continue
+            build_artifact_storage_dir = os.path.join(artifact_storage_dir, "%d" % br.build.pk)
+            try:
+                os.makedirs(build_artifact_storage_dir)
+            except OSError as ose:
+                if "File exists" in str(ose):
+                    pass
+                else:
+                    raise ose
+
+            file_name = os.path.join(build_artifact_storage_dir, "cooker_log.txt")
+            try:
+                with open(file_name, "w") as f:
+                    f.write(br.environment.get_artifact(br.build.cooker_log_path).read())
+            except IOError:
+                os.unlink(file_name)
 
+            br.state = BuildRequest.REQ_COMPLETED
+            br.save()
 
     def cleanup(self):
         from django.utils import timezone
@@ -104,4 +130,5 @@ class Command(NoArgsCommand):
 
     def handle_noargs(self, **options):
         self.cleanup()
+        self.archive()
         self.schedule()
diff --git a/lib/toaster/bldcontrol/migrations/0008_brarchive.py b/lib/toaster/bldcontrol/migrations/0008_brarchive.py
new file mode 100644
index 0000000..f546960
--- /dev/null
+++ b/lib/toaster/bldcontrol/migrations/0008_brarchive.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+    # ids that cannot be imported from BuildRequest
+
+    def forwards(self, orm):
+        REQ_COMPLETED = 3
+        REQ_ARCHIVE = 6
+        "Write your forwards methods here."
+        # Note: Don't use "from appname.models import ModelName".
+        # Use orm.ModelName to refer to models in this application,
+        # and orm['appname.ModelName'] for models in other applications.
+        orm.BuildRequest.objects.filter(state=REQ_COMPLETED).update(state=REQ_ARCHIVE)
+
+    def backwards(self, orm):
+        REQ_COMPLETED = 3
+        REQ_ARCHIVE = 6
+        "Write your backwards methods here."
+        orm.BuildRequest.objects.filter(state=REQ_ARCHIVE).update(state=REQ_COMPLETED)
+
+    models = {
+        u'bldcontrol.brbitbake': {
+            'Meta': {'object_name': 'BRBitbake'},
+            'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']", 'unique': 'True'})
+        },
+        u'bldcontrol.brerror': {
+            'Meta': {'object_name': 'BRError'},
+            'errmsg': ('django.db.models.fields.TextField', [], {}),
+            'errtype': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
+            'traceback': ('django.db.models.fields.TextField', [], {})
+        },
+        u'bldcontrol.brlayer': {
+            'Meta': {'object_name': 'BRLayer'},
+            'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
+        },
+        u'bldcontrol.brtarget': {
+            'Meta': {'object_name': 'BRTarget'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
+            'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        u'bldcontrol.brvariable': {
+            'Meta': {'object_name': 'BRVariable'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
+            'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        u'bldcontrol.buildenvironment': {
+            'Meta': {'object_name': 'BuildEnvironment'},
+            'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
+            'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
+            'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
+            'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
+            'betype': ('django.db.models.fields.IntegerField', [], {}),
+            'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
+            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+        },
+        u'bldcontrol.buildrequest': {
+            'Meta': {'object_name': 'BuildRequest'},
+            'build': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['orm.Build']", 'unique': 'True', 'null': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'environment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildEnvironment']", 'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
+            'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+        },
+        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.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.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.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'})
+        }
+    }
+
+    complete_apps = ['bldcontrol']
+    symmetrical = True
diff --git a/lib/toaster/bldcontrol/models.py b/lib/toaster/bldcontrol/models.py
index dc4afca..25d94cd 100644
--- a/lib/toaster/bldcontrol/models.py
+++ b/lib/toaster/bldcontrol/models.py
@@ -94,6 +94,7 @@ class BuildRequest(models.Model):
     REQ_COMPLETED = 3
     REQ_FAILED = 4
     REQ_DELETED = 5
+    REQ_ARCHIVE = 6
 
     REQUEST_STATE = (
         (REQ_CREATED, "created"),
@@ -102,6 +103,7 @@ class BuildRequest(models.Model):
         (REQ_COMPLETED, "completed"),
         (REQ_FAILED, "failed"),
         (REQ_DELETED, "deleted"),
+        (REQ_ARCHIVE, "archive"),
     )
 
     search_allowed_fields = ("brtarget__target",)
diff --git a/lib/toaster/toastergui/templates/build.html b/lib/toaster/toastergui/templates/build.html
index e71e38f..684ec65 100644
--- a/lib/toaster/toastergui/templates/build.html
+++ b/lib/toaster/toastergui/templates/build.html
@@ -40,7 +40,9 @@
         <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work -->
         {% for build in objects %}
         <tr class="data">
-            <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td>
+            <td class="outcome">
+	    <a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a> &nbsp;
+	    </td>
             <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
             <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
             <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
@@ -61,11 +63,6 @@
             <td class="errors_no">
                 {% if  build.errors_no %}
                     <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>
-                    {% if MANAGED and build.project %}
-                        <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
-                            <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
-                        </a>
-                    {% endif %}
                 {%endif%}
             </td>
             <td class="warnings_no">{% if  build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td>
diff --git a/lib/toaster/toastergui/templates/builddashboard.html b/lib/toaster/toastergui/templates/builddashboard.html
index 2458cdb..c0898e2 100644
--- a/lib/toaster/toastergui/templates/builddashboard.html
+++ b/lib/toaster/toastergui/templates/builddashboard.html
@@ -36,7 +36,11 @@
 {% endif %}
     <span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning show-warnings"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span>
 {% endif %}
-            <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a></span>
+            <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> &nbsp;
+      {% if MANAGED and build.project %}
+            <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%else%}btn-danger{%endif%} pull-right" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a>
+      {% endif %}
+            </span>
 {%endif%}
     </div>
     {% if build.toaster_exceptions.count > 0 %}
@@ -54,10 +58,7 @@
 <div class="accordion span10 pull-right" id="errors">
   <div class="accordion-group">
     <div class="accordion-heading">
-      {% if MANAGED and build.project %}
-          <a class="btn btn-large pull-right" href="{% url 'build_artifact' build.id "cookerlog" build.id %}" style="margin:15px;">Download build log</a>
-      {% endif %}
-      <a class="accordion-toggle error toggle-errors">
+            <a class="accordion-toggle error toggle-errors">
          <h2 id="error-toggle">
            <i class="icon-minus-sign"></i>
            {{build.errors_no}} error{{build.errors_no|pluralize}}
diff --git a/lib/toaster/toastergui/templates/managed_builds.html b/lib/toaster/toastergui/templates/managed_builds.html
index 121ad07..a4db55b 100644
--- a/lib/toaster/toastergui/templates/managed_builds.html
+++ b/lib/toaster/toastergui/templates/managed_builds.html
@@ -46,7 +46,14 @@
         <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work -->
         {% for buildrequest in objects %}{% if buildrequest.build %}  {% with build=buildrequest.build %} {# if we have a build, just display it #}
         <tr class="data">
-            <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td>
+            <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a>
+	            {% if build.project %}
+                        &nbsp; <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
+                            <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
+                        </a>
+                    {% endif %}
+
+            </td>
             <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
             <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
             <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
diff --git a/lib/toaster/toastergui/templates/projectbuilds.html b/lib/toaster/toastergui/templates/projectbuilds.html
index 02d1663..afcf519 100644
--- a/lib/toaster/toastergui/templates/projectbuilds.html
+++ b/lib/toaster/toastergui/templates/projectbuilds.html
@@ -49,7 +49,14 @@
         <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work -->
         {% for br in objects %}{% if br.build %}  {% with build=br.build %} {# if we have a build, just display it #}
         <tr class="data">
-            <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td>
+            <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a>
+                   {% if build.project %}
+                        &nbsp; <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
+                            <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
+                        </a>
+                    {% endif %}
+            </td>
+
             <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
             <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
             <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
@@ -70,11 +77,6 @@
             <td class="errors_no">
                 {% if  build.errors_no %}
                     <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>
-                    {% if MANAGED and build.project %}
-                        <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
-                            <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
-                        </a>
-                    {% endif %}
                 {%endif%}
             </td>
             <td class="warnings_no">{% if  build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td>
diff --git a/lib/toaster/toastergui/templates/unavailable_artifact.html b/lib/toaster/toastergui/templates/unavailable_artifact.html
new file mode 100644
index 0000000..c93d425
--- /dev/null
+++ b/lib/toaster/toastergui/templates/unavailable_artifact.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+{% load projecttags %}
+{% load humanize %}
+{% load static %}
+
+{% block pagecontent %}
+<div class="section">
+</div>
+<div class="row-fluid">
+
+    <div class="alert alert-info">
+    <p class="lead"> The artifact you are seeking to download is not available. We are sorry. You can <a href="javascript:window.history.back()">go back</a>
+    </p>
+    </div>
+</div>
+{% endblock %}
+
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index b5ff9b1..eb323ec 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2914,9 +2914,6 @@ if toastermain.settings.MANAGED:
         if artifact_type == "imagefile":
             file_name = Target_Image_File.objects.get(target__build = b, pk = artifact_id).file_name
 
-        elif artifact_type == "cookerlog":
-            file_name = b.cooker_log_path
-
         elif artifact_type == "buildartifact":
             file_name = BuildArtifact.objects.get(build = b, pk = artifact_id).file_name
 
@@ -2935,26 +2932,87 @@ if toastermain.settings.MANAGED:
 
 
     def build_artifact(request, build_id, artifact_type, artifact_id):
-        b = Build.objects.get(pk=build_id)
-        if b.buildrequest is None or b.buildrequest.environment is None:
-            raise Exception("Artifact not available for download (missing build request or build environment)")
+        if artifact_type in ["cookerlog"]:
+            # these artifacts are saved after building, so they are on the server itself
+            def _mimetype_for_artifact(path):
+                try:
+                    import magic
+
+                    # fair warning: this is a mess; there are multiple competing and incompatible
+                    # magic modules floating around, so we try some of the most common combinations
+
+                    try:    # we try ubuntu's python-magic 5.4
+                        m = magic.open(magic.MAGIC_MIME_TYPE)
+                        m.load()
+                        return m.file(path)
+                    except AttributeError:
+                        pass
+
+                    try:    # we try python-magic 0.4.6
+                        m = magic.Magic(magic.MAGIC_MIME)
+                        return m.from_file(path)
+                    except AttributeError:
+                        pass
+
+                    try:    # we try pip filemagic 1.6
+                        m = magic.Magic(flags=magic.MAGIC_MIME_TYPE)
+                        return m.id_filename(path)
+                    except AttributeError:
+                        pass
+
+                    return "binary/octet-stream"
+                except ImportError:
+                    return "binary/octet-stream"
+            try:
+                # match code with runbuilds.Command.archive()
+                build_artifact_storage_dir = os.path.join(ToasterSetting.objects.get(name="ARTIFACTS_STORAGE_DIR").value, "%d" % int(build_id))
+                file_name = os.path.join(build_artifact_storage_dir, "cooker_log.txt")
+
+                fsock = open(file_name, "r")
+                content_type=_mimetype_for_artifact(file_name)
 
-        file_name = _file_name_for_artifact(b, artifact_type, artifact_id)
-        fsock = None
-        content_type='application/force-download'
+                response = HttpResponse(fsock, content_type = content_type)
+
+                response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_name)
+                return response
+            except IOError:
+                context = {
+                    'build' : Build.objects.get(pk = build_id),
+                }
+                return render(request, "unavailable_artifact.html", context)
 
-        if file_name is None:
-            raise Exception("Could not handle artifact %s id %s" % (artifact_type, artifact_id))
         else:
-            content_type = b.buildrequest.environment.get_artifact_type(file_name)
-            fsock = b.buildrequest.environment.get_artifact(file_name)
-            file_name = os.path.basename(file_name) # we assume that the build environment system has the same path conventions as host
+            # retrieve the artifact directly from the build environment
+            return _get_be_artifact(request, build_id, artifact_type, artifact_id)
 
-        response = HttpResponse(fsock, content_type = content_type)
 
-        # returns a file from the environment
-        response['Content-Disposition'] = 'attachment; filename=' + file_name
-        return response
+    def _get_be_artifact(request, build_id, artifact_type, artifact_id):
+        try:
+            b = Build.objects.get(pk=build_id)
+            if b.buildrequest is None or b.buildrequest.environment is None:
+                raise Exception("Artifact not available for download (missing build request or build environment)")
+
+            file_name = _file_name_for_artifact(b, artifact_type, artifact_id)
+            fsock = None
+            content_type='application/force-download'
+
+            if file_name is None:
+                raise Exception("Could not handle artifact %s id %s" % (artifact_type, artifact_id))
+            else:
+                content_type = b.buildrequest.environment.get_artifact_type(file_name)
+                fsock = b.buildrequest.environment.get_artifact(file_name)
+                file_name = os.path.basename(file_name) # we assume that the build environment system has the same path conventions as host
+
+            response = HttpResponse(fsock, content_type = content_type)
+
+            # returns a file from the environment
+            response['Content-Disposition'] = 'attachment; filename=' + file_name
+            return response
+        except IOError:
+            context = {
+                'build' : Build.objects.get(pk = build_id),
+            }
+            return render(request, "unavailable_artifact.html", context)
 
 
 
diff --git a/lib/toaster/toastermain/urls.py b/lib/toaster/toastermain/urls.py
index f66f11d..395c4e8 100644
--- a/lib/toaster/toastermain/urls.py
+++ b/lib/toaster/toastermain/urls.py
@@ -50,12 +50,12 @@ import toastermain.settings
 
 if toastermain.settings.FRESH_ENABLED:
     urlpatterns.insert(1, url(r'', include('fresh.urls')))
-    logger.info("Enabled django-fresh extension")
+    #logger.info("Enabled django-fresh extension")
 
 if toastermain.settings.DEBUG_PANEL_ENABLED:
     import debug_toolbar
     urlpatterns.insert(1, url(r'', include(debug_toolbar.urls)))
-    logger.info("Enabled django_toolbar extension")
+    #logger.info("Enabled django_toolbar extension")
 
 
 if toastermain.settings.MANAGED:
@@ -86,4 +86,4 @@ for t in os.walk(os.path.dirname(currentdir)):
             logger.warn("Module \'%s\' has a regexp conflict, was not added to the urlpatterns" % modulename)
 
 from pprint import pformat
-logger.debug("urlpatterns list %s", pformat(urlpatterns))
+#logger.debug("urlpatterns list %s", pformat(urlpatterns))
-- 
1.9.1



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

* [PATCH 02/10] toaster: properly detect starting in rolling log file
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 01/10] toaster: bitbake cooker log saving and downloading Alex DAMIAN
@ 2015-02-18 19:10 ` Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 03/10] toasterui: fix time estimation in project page Alex DAMIAN
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:10 UTC (permalink / raw)
  To: bitbake-devel

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

This patch brings in properly detection of system start in
a rolling toaster_ui log file.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/bldcontrol/localhostbecontroller.py | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/lib/toaster/bldcontrol/localhostbecontroller.py b/lib/toaster/bldcontrol/localhostbecontroller.py
index 6bd019a..25ce052 100644
--- a/lib/toaster/bldcontrol/localhostbecontroller.py
+++ b/lib/toaster/bldcontrol/localhostbecontroller.py
@@ -107,6 +107,13 @@ class LocalhostBEController(BuildEnvironmentController):
 
         logger.debug("localhostbecontroller: running the listener at %s" % own_bitbake)
 
+        toaster_ui_log_filepath = os.path.join(self.be.builddir, "toaster_ui.log")
+        # get the file length; we need to detect the _last_ start of the toaster UI, not the first
+        toaster_ui_log_filelength = 0
+        if os.path.exists(toaster_ui_log_filepath):
+            with open(toaster_ui_log_filepath, "r") as f:
+                f.seek(0, 2)    # jump to the end
+                toaster_ui_log_filelength = f.tell()
 
         cmd = "bash -c \"source %s/oe-init-build-env %s && bitbake --read conf/toaster-pre.conf --postread conf/toaster.conf --server-only -t xmlrpc -B 0.0.0.0:0 >toaster_server.log && DATABASE_URL=%s BBSERVER=0.0.0.0:-1 daemon -d -i -D %s -o toaster_ui.log -- %s --observe-only -u toasterui &\"" % (self.pokydirname, self.be.builddir,
                 self.dburl, self.be.builddir, own_bitbake)
@@ -117,10 +124,11 @@ class LocalhostBEController(BuildEnvironmentController):
                 port = i.split(" ")[-1]
                 logger.debug("localhostbecontroller: Found bitbake server port %s" % port)
 
-        def _toaster_ui_started(filepath):
+        def _toaster_ui_started(filepath, filepos = 0):
             if not os.path.exists(filepath):
                 return False
             with open(filepath, "r") as f:
+                f.seek(filepos)
                 for line in f:
                     if line.startswith("NOTE: ToasterUI waiting for events"):
                         return True
@@ -129,7 +137,7 @@ class LocalhostBEController(BuildEnvironmentController):
         retries = 0
         started = False
         while not started and retries < 10:
-            started = _toaster_ui_started(os.path.join(self.be.builddir, "toaster_ui.log"))
+            started = _toaster_ui_started(toaster_ui_log_filepath, toaster_ui_log_filelength)
             import time
             logger.debug("localhostbecontroller: Waiting bitbake server to start")
             time.sleep(0.5)
-- 
1.9.1



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

* [PATCH 03/10] toasterui: fix time estimation in project page
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 01/10] toaster: bitbake cooker log saving and downloading Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 02/10] toaster: properly detect starting in rolling log file Alex DAMIAN
@ 2015-02-18 19:10 ` Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 04/10] toasterui: UI query performance improvements Alex DAMIAN
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:10 UTC (permalink / raw)
  To: bitbake-devel

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

This patch fixes the time estimation to build completion
in project page. Additionally it fixes the Most Recent Builds
section used in various pages in managed mode, and proper
time to build estimation in all pages.

[YOCTO #7004]

Signed-off-by: Alexandru Damian <alexandru.damian@intel.com>
---
 lib/toaster/orm/models.py                          |  2 +-
 lib/toaster/toastergui/static/js/projectapp.js     | 24 +++++++++++++++++++---
 .../toastergui/templates/managed_mrb_section.html  |  3 +--
 lib/toaster/toastergui/templates/project.html      |  2 +-
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index f70c006..0f85c8f 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -194,7 +194,7 @@ class Build(models.Model):
         eta = timezone.now()
         completeper = self.completeper()
         if self.completeper() > 0:
-            eta = timezone.now() + ((timezone.now() - self.started_on)*(100-completeper)/completeper)
+            eta += ((eta - self.started_on)*100)/completeper
         return eta
 
 
diff --git a/lib/toaster/toastergui/static/js/projectapp.js b/lib/toaster/toastergui/static/js/projectapp.js
index bee3c56..4d00f40 100644
--- a/lib/toaster/toastergui/static/js/projectapp.js
+++ b/lib/toaster/toastergui/static/js/projectapp.js
@@ -136,6 +136,16 @@ projectApp.filter('timediff', function() {
     }
 });
 
+// add "time to future" eta that computes time from now to a point in the future
+projectApp.filter('toeta', function() {
+    return function(input) {
+       var crtmiliseconds = new Date().getTime();
+        diff = (parseInt(input) - crtmiliseconds ) / 1000;
+        console.log("Debug: future time ", input, "crt time", crtmiliseconds, ":", diff);
+        return diff < 0 ? 300 : diff;
+    }
+});
+
 /**
  * main controller for the project page
  */
@@ -259,7 +269,14 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                         var i = 0;
                         for (i = 0 ; i < $scope.builds.length; i ++) {
                             if ($scope.builds[i].id > elem.id) continue;
-                            if ($scope.builds[i].id == elem.id) { found=true; break;}
+                            if ($scope.builds[i].id == elem.id) {
+                                found=true;
+                                // do deep data copy
+                                for (var attr in elem) {
+                                    $scope.builds[i][attr] = elem[attr];
+                                }
+                                break;
+                            }
                             if ($scope.builds[i].id < elem.id) break;
                         }
                         if (!found) {
@@ -272,8 +289,8 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                         var found = false;
                         var i = 0;
                         for (i = 0; i < $scope.builds.length; i ++) {
-                           if ($scope.builds[i].id > elem.id) continue;
-                            if ($scope.builds[i].id == elem.id) { found=true; break;}
+                            if ($scope.builds[i].id > elem.id) continue;
+                            if ($scope.builds[i].id == elem.id) { found=true; break; }
                             if ($scope.builds[i].id < elem.id) break;
                         }
                         if (!found) {
@@ -281,6 +298,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                         }
                     });
 
+
                     $scope.fetchLayersForTargets();
                 }
                 if (_data.targets !== undefined) {
diff --git a/lib/toaster/toastergui/templates/managed_mrb_section.html b/lib/toaster/toastergui/templates/managed_mrb_section.html
index 6f31ee0..b8d087a 100644
--- a/lib/toaster/toastergui/templates/managed_mrb_section.html
+++ b/lib/toaster/toastergui/templates/managed_mrb_section.html
@@ -2,8 +2,7 @@
 {% load projecttags %}
 {% load humanize %}
 
-
-{%if len.mru > 0%}
+{%if mru|length > 0%}
   <div class="page-header top-air">
       <h1>
           Latest builds
diff --git a/lib/toaster/toastergui/templates/project.html b/lib/toaster/toastergui/templates/project.html
index 7da2361..a1cce33 100644
--- a/lib/toaster/toastergui/templates/project.html
+++ b/lib/toaster/toastergui/templates/project.html
@@ -196,7 +196,7 @@ vim: expandtab tabstop=2
                       <div style="width: {[b.build[0].completeper]}%;" class="bar"></div>
                   </div>
                 </div>
-                <div class="text-right lead">ETA: {[b.build[0].eta|date:"HH:mm:ss"]}</div>
+                <div class="text-right lead">ETA in {[b.build[0].eta|toeta|timediff]}</div>
               </case>
           </case>
 
-- 
1.9.1



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

* [PATCH 04/10] toasterui: UI query performance improvements
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (2 preceding siblings ...)
  2015-02-18 19:10 ` [PATCH 03/10] toasterui: fix time estimation in project page Alex DAMIAN
@ 2015-02-18 19:10 ` Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 05/10] toaster: get proper version string Alex DAMIAN
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:10 UTC (permalink / raw)
  To: bitbake-devel

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

We reduce the number of queries by using "select_related"
to bring in more data in a single query. Improvements in
project page refresh, recipes table and tasks table.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/orm/models.py       | 11 +++++++----
 lib/toaster/toastergui/views.py | 15 +++++++++------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 0f85c8f..54cd535 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -362,11 +362,14 @@ class Task(models.Model):
         return "Not Executed"
 
     def get_description(self):
-        helptext = HelpText.objects.filter(key=self.task_name, area=HelpText.VARIABLE, build=self.build)
+        if '_helptext' in vars(self) and self._helptext != None:
+            return self._helptext
         try:
-            return helptext[0].text
-        except IndexError:
-            return ''
+            self._helptext = HelpText.objects.get(key=self.task_name, area=HelpText.VARIABLE, build=self.build).text
+        except HelpText.DoesNotExit:
+            self._helptext = None
+
+        return self._helptext
 
     build = models.ForeignKey(Build, related_name='task_build')
     order = models.IntegerField(null=True)
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index eb323ec..a2e9206 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -75,8 +75,9 @@ def _project_recent_build_list(prj):
                         'build_time_page_url': reverse('buildtime', args=(y.pk,)),
                         "errors": y.errors_no,
                         "warnings": y.warnings_no,
-                        "completeper": y.completeper(),
-                        "eta": y.eta().strftime('%s')+"000"}, Build.objects.filter(buildrequest = x)),
+                        "completeper": y.completeper() if y.outcome == Build.IN_PROGRESS else "0",
+                        "eta": y.eta().strftime('%s')+"000" if y.outcome == Build.IN_PROGRESS else "0",
+                        }, Build.objects.filter(buildrequest = x)),
         }, list(prj.buildrequest_set.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) +
             list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3]))
 
@@ -828,6 +829,8 @@ def tasks_common(request, build_id, variant, task_anchor):
     else:
         queryset = _get_queryset(Task, queryset_all, filter_string, search_term, ordering_string, 'order')
 
+    queryset = queryset.select_related("recipe", "build")
+
     # compute the anchor's page
     if anchor:
         request.GET = request.GET.copy()
@@ -1023,14 +1026,14 @@ def recipes(request, build_id):
     if retval:
         return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id)
     (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe)
-    queryset = Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id))
+    queryset = Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)).select_related("layer_version", "layer_version__layer")
     queryset = _get_queryset(Recipe, queryset, filter_string, search_term, ordering_string, 'name')
 
     recipes = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1))
 
     # prefetch the forward and reverse recipe dependencies
     deps = { }; revs = { }
-    queryset_dependency=Recipe_Dependency.objects.filter(recipe__layer_version__build_id = build_id)
+    queryset_dependency=Recipe_Dependency.objects.filter(recipe__layer_version__build_id = build_id).select_related("depends_on", "recipe")
     for recipe in recipes:
         deplist = [ ]
         for recipe_dep in [x for x in queryset_dependency if x.recipe_id == recipe.id]:
@@ -1804,7 +1807,7 @@ if toastermain.settings.MANAGED:
         (filter_string, search_term, ordering_string) = _search_tuple(request, BuildRequest)
         # we don't display in-progress or deleted builds
         queryset_all = buildrequests.exclude(state = BuildRequest.REQ_DELETED)
-        queryset_all = queryset_all.annotate(Count('brerror'))
+        queryset_all = queryset_all.select_related("build", "build__project").annotate(Count('brerror'))
         queryset_with_search = _get_queryset(BuildRequest, queryset_all, filter_string, search_term, ordering_string, '-updated')
 
 
@@ -2179,7 +2182,7 @@ if toastermain.settings.MANAGED:
             # return all project settings
             return HttpResponse(jsonfilter( {
                 "error": "ok",
-                "layers" :  map(lambda x: {"id": x.layercommit.pk, "orderid" : x.pk, "name" : x.layercommit.layer.name, "giturl" : x.layercommit.layer.vcs_url, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all().order_by("id")),
+                "layers" :  map(lambda x: {"id": x.layercommit.pk, "orderid" : x.pk, "name" : x.layercommit.layer.name, "giturl" : x.layercommit.layer.vcs_url, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all().select_related("layer").order_by("id")),
                 "builds" : _project_recent_build_list(prj),
                 "variables": map(lambda x: (x.name, x.value), prj.projectvariable_set.all()),
                 "machine": {"name": prj.projectvariable_set.get(name="MACHINE").value},
-- 
1.9.1



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

* [PATCH 05/10] toaster: get proper version string
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (3 preceding siblings ...)
  2015-02-18 19:10 ` [PATCH 04/10] toasterui: UI query performance improvements Alex DAMIAN
@ 2015-02-18 19:10 ` Alex DAMIAN
  2015-02-18 19:11 ` [PATCH 06/10] toaster: landing page when no build module Alex DAMIAN
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:10 UTC (permalink / raw)
  To: bitbake-devel

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

This patch brings in the toaster tree commit ID in
the version string to allow users properly report their
toaster version when submitting issues.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastermain/settings.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/toaster/toastermain/settings.py b/lib/toaster/toastermain/settings.py
index b6a42c0..a7304fa 100644
--- a/lib/toaster/toastermain/settings.py
+++ b/lib/toaster/toastermain/settings.py
@@ -232,7 +232,8 @@ from os.path import dirname as DN
 SITE_ROOT=DN(DN(os.path.abspath(__file__)))
 
 import subprocess
-TOASTER_VERSION = subprocess.Popen('cd %s; git branch | grep "^* " | tr -d "* "' % SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+TOASTER_VERSION = subprocess.Popen('git branch | grep "^* " | tr -d "* "', cwd = SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+TOASTER_VERSION += " " + subprocess.Popen('git rev-parse HEAD ', cwd = SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
 
 ROOT_URLCONF = 'toastermain.urls'
 
-- 
1.9.1



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

* [PATCH 00/10] Toaster patchset
@ 2015-02-18 19:11 Alex DAMIAN
  2015-02-18 19:10 ` [PATCH 01/10] toaster: bitbake cooker log saving and downloading Alex DAMIAN
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:11 UTC (permalink / raw)
  To: bitbake-devel; +Cc: David Reyna

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

Hello,

This is a toaster patchset with bug fixes and new features. The patches
have been reviewed on the toaster mailing list. 

Can you please pull ?

Cheers,
Alex

The following changes since commit 7cfe279bf77b59d5cbd20d8a93e1d33279bebc20:

  toasterui: empty state for pages (2015-02-16 17:48:30 +0000)

are available in the git repository at:

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

Alexandru DAMIAN (4):
  toaster: bitbake cooker log saving and downloading
  toaster: properly detect starting in rolling log file
  toasterui: UI query performance improvements
  toaster: get proper version string

Alexandru Damian (1):
  toasterui: fix time estimation in project page

Belen Barros Pena (2):
  toasterui: style the Toaster version information
  toasterui: remove layer directory in managed mode

David Reyna (1):
  toaster: landing page when no build module

Michael Wood (2):
  toaster: layerdetails Don't show None type in description/summary
  toaster: importlayer Remove description input field

 lib/bb/ui/buildinfohelper.py                       |   3 +-
 lib/bb/ui/toasterui.py                             |  29 +++-
 lib/toaster/bldcontrol/localhostbecontroller.py    |  12 +-
 .../management/commands/checksettings.py           |  17 +++
 .../bldcontrol/management/commands/runbuilds.py    |  29 +++-
 .../bldcontrol/migrations/0008_brarchive.py        | 138 +++++++++++++++++
 lib/toaster/bldcontrol/models.py                   |   2 +
 lib/toaster/orm/models.py                          |  13 +-
 lib/toaster/toastergui/static/css/default.css      |  22 +--
 lib/toaster/toastergui/static/js/importlayer.js    |   1 -
 lib/toaster/toastergui/static/js/projectapp.js     |  24 ++-
 lib/toaster/toastergui/templates/base.html         |  13 +-
 lib/toaster/toastergui/templates/bpackage.html     |   4 +-
 lib/toaster/toastergui/templates/build.html        |   9 +-
 .../toastergui/templates/builddashboard.html       |  11 +-
 lib/toaster/toastergui/templates/importlayer.html  |   6 -
 .../toastergui/templates/landing_not_managed.html  |  32 ++++
 lib/toaster/toastergui/templates/layerdetails.html |   4 +-
 .../toastergui/templates/managed_builds.html       |   9 +-
 .../toastergui/templates/managed_mrb_section.html  |   3 +-
 lib/toaster/toastergui/templates/project.html      |   2 +-
 .../toastergui/templates/projectbuilds.html        |  14 +-
 .../toastergui/templates/unavailable_artifact.html |  17 +++
 lib/toaster/toastergui/views.py                    | 168 ++++++++++++++-------
 lib/toaster/toastermain/settings.py                |   3 +-
 lib/toaster/toastermain/urls.py                    |   6 +-
 26 files changed, 465 insertions(+), 126 deletions(-)
 create mode 100644 lib/toaster/bldcontrol/migrations/0008_brarchive.py
 create mode 100644 lib/toaster/toastergui/templates/landing_not_managed.html
 create mode 100644 lib/toaster/toastergui/templates/unavailable_artifact.html

-- 
1.9.1



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

* [PATCH 06/10] toaster: landing page when no build module
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (4 preceding siblings ...)
  2015-02-18 19:10 ` [PATCH 05/10] toaster: get proper version string Alex DAMIAN
@ 2015-02-18 19:11 ` Alex DAMIAN
  2015-02-18 19:11 ` [PATCH 07/10] toaster: layerdetails Don't show None type in description/summary Alex DAMIAN
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:11 UTC (permalink / raw)
  To: bitbake-devel; +Cc: David Reyna

From: David Reyna <David.Reyna@windriver.com>

Add landing page for managed build pages when build module not installed.

Some wording and whitespace changed.

[YOCTO #6483]

Signed-off-by: David Reyna <David.Reyna@windriver.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 .../toastergui/templates/landing_not_managed.html  | 32 +++++++++++++++++
 lib/toaster/toastergui/views.py                    | 42 +++++++++++-----------
 2 files changed, 53 insertions(+), 21 deletions(-)
 create mode 100644 lib/toaster/toastergui/templates/landing_not_managed.html

diff --git a/lib/toaster/toastergui/templates/landing_not_managed.html b/lib/toaster/toastergui/templates/landing_not_managed.html
new file mode 100644
index 0000000..fe56655
--- /dev/null
+++ b/lib/toaster/toastergui/templates/landing_not_managed.html
@@ -0,0 +1,32 @@
+{% extends "base.html" %}
+
+{% load static %}
+{% load projecttags %}
+{% load humanize %}
+
+{% block pagecontent %}
+
+  <div class="container-fluid">
+   <div class="row-fluid">
+    <!-- Empty - no build module -->
+    <div class="page-header top-air">
+     <h1>
+       This page only works with the Toaster 'Build' mode
+     </h1>
+    </div>
+    <div class="alert alert-info">
+     <p class="lead">
+     The 'Build' mode allows you to configure and run your Yocto Project builds from Toaster
+     <ul>
+       <li class="lead"><a href="https://wiki.yoctoproject.org/wiki/Toaster#Modes">
+       Read about the 'Build' mode
+       </a></li>
+       <li class="lead"><a href="/">
+       View your builds
+       </a></li>
+     </ul>
+     </p>
+    </div>
+   </div>
+
+{% endblock %}
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index a2e9206..70241dc 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -3290,64 +3290,64 @@ else:
 
 
     def newproject(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def project(request, pid):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_projectbuild(request, pid):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_build(request, pid):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_projectinfo(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_projectedit(request, pid):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_datatypeahead(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_configvaredit(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def importlayer(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def layers(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def layerdetails(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def targets(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def targetdetails(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def machines(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def projectconf(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def projectbuilds(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def build_artifact(request, build_id, artifact_type, artifact_id):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def projects(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_importlayer(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def xhr_updatelayer(request):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
 
     def buildrequestdetails(request, pid, brid):
-        raise Exception("page not available in interactive mode")
+        return render(request, 'landing_not_managed.html')
-- 
1.9.1



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

* [PATCH 07/10] toaster: layerdetails Don't show None type in description/summary
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (5 preceding siblings ...)
  2015-02-18 19:11 ` [PATCH 06/10] toaster: landing page when no build module Alex DAMIAN
@ 2015-02-18 19:11 ` Alex DAMIAN
  2015-02-18 19:11 ` [PATCH 08/10] toasterui: style the Toaster version information Alex DAMIAN
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:11 UTC (permalink / raw)
  To: bitbake-devel

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

When the result for the summary or description is None don't output the
result as the string version of None, use an empty value so that the
"Not set" mechanism works.

[YOCTO #7244]

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

diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 465d633..c162c8b 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -453,7 +453,7 @@
                 </dt>
                 <dd>
                   <span class="muted" style="display:none">Not set</span>
-                  <span class="current-value">{{layerversion.layer.summary}}</span>
+                  <span class="current-value">{{layerversion.layer.summary|default_if_none:''}}</span>
                   <form style="display:none; margin-bottom:20px">
                     <textarea class="span12" rows="2">{% if layerversion.layer.summary %}{{layerversion.layer.summary}}{% endif %}</textarea>
                     <button class="btn change-btn" data-layer-prop="summary" type="button">Save</button>
@@ -467,7 +467,7 @@
                 </dt>
                 <dd>
                   <span class="muted" style="display:none">Not set</span>
-                  <span class="current-value">{{layerversion.layer.description}}</span>
+                  <span class="current-value">{{layerversion.layer.description|default_if_none:''}}</span>
                   <form style="display:none; margin-bottom:20px">
                     <textarea class="span12" rows="6">{% if layerversion.layer.description %}{{layerversion.layer.description}}{% endif %}</textarea>
                     <button class="btn change-btn" data-layer-prop="description" type="button" >Save</button>
-- 
1.9.1



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

* [PATCH 08/10] toasterui: style the Toaster version information
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (6 preceding siblings ...)
  2015-02-18 19:11 ` [PATCH 07/10] toaster: layerdetails Don't show None type in description/summary Alex DAMIAN
@ 2015-02-18 19:11 ` Alex DAMIAN
  2015-02-18 19:11 ` [PATCH 09/10] toasterui: remove layer directory in managed mode Alex DAMIAN
  2015-02-18 19:11 ` [PATCH 10/10] toaster: importlayer Remove description input field Alex DAMIAN
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:11 UTC (permalink / raw)
  To: bitbake-devel

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

In debug mode, we show the Toaster version and mode in the
top bar. Display them inside a tooltip that appears when
you hover over a nice info icon to make them less conspicuous.

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

diff --git a/lib/toaster/toastergui/static/css/default.css b/lib/toaster/toastergui/static/css/default.css
index 41b73cc..86cf67a 100644
--- a/lib/toaster/toastergui/static/css/default.css
+++ b/lib/toaster/toastergui/static/css/default.css
@@ -2,24 +2,10 @@
 .logo img { height: 30px; width: auto !important; }
 .logo { padding-top: 4px !important; padding-bottom:0px !important; }
 
-/* style the version text */
-.version-text {
-	color: #AAA;
-	font-size: 0.6em;
-	display: table-footer-group;
-	padding: 0px;
-	margin: 1px 1px 1px 1px;
-}
-
-.version-brand, .version-brand:hover, a.version-brand:focus  {
-    color: #777;
-    display: block;
-    float: left;
-    font-size: 20px;
-    font-weight: 200;
-    padding: 00px 0px;
-    text-shadow: 0 1px 0 #fff;
-}
+/* style the version information */
+.brand > a { color: #777; }
+.brand > a:hover { color: #999; text-decoration: none; }
+.icon-info-sign.get-help { color: #777; font-size: 16px; margin-left: 5px;}
 
 /* Style the breadcrumb */
 .breadcrumb { display: inline-block; background-color: transparent; }
diff --git a/lib/toaster/toastergui/templates/base.html b/lib/toaster/toastergui/templates/base.html
index 6f249bc..695ca5d 100644
--- a/lib/toaster/toastergui/templates/base.html
+++ b/lib/toaster/toastergui/templates/base.html
@@ -58,13 +58,12 @@
 <div class="navbar navbar-static-top">
     <div class="navbar-inner">
             <a class="brand logo" href="#"><img src="{% static 'img/logo.png' %}" class="" alt="Yocto logo project"/></a>
-            <a class="brand" href="/">Toaster</a>
-            {% if DEBUG %}
-            <div style="display: inline;" class="version-brand">
-              <p class="version-text">version {{TOASTER_VERSION}}</p>
-              <p class="version-text">{%if MANAGED%}managed{%else%}interactive{%endif%} mode</p>
-            </div>
-            {% endif %}
+            <span class="brand">
+                <a href="/">Toaster</a>
+                {% if DEBUG %}
+                    <i class="icon-info-sign get-help heading-help" data-placement="bottom" title="Version: {{TOASTER_VERSION}} <br /> Mode: {%if MANAGED%}build{%else%}analysis{%endif%}"></i>
+                {% endif %}
+            </span>
             <a class="pull-right manual" target="_blank" href="http://www.yoctoproject.org/documentation/toaster-manual">
                 <i class="icon-book"></i>
                 Toaster manual
-- 
1.9.1



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

* [PATCH 09/10] toasterui: remove layer directory in managed mode
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (7 preceding siblings ...)
  2015-02-18 19:11 ` [PATCH 08/10] toasterui: style the Toaster version information Alex DAMIAN
@ 2015-02-18 19:11 ` Alex DAMIAN
  2015-02-18 19:11 ` [PATCH 10/10] toaster: importlayer Remove description input field Alex DAMIAN
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:11 UTC (permalink / raw)
  To: bitbake-devel

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

Removes the layer directory information from the packages
built page when in managed mode.

[YOCTO #7221]

Signed-off-by: Belen Barros Pena <belen.barros.pena@intel.com>
---
 lib/toaster/toastergui/templates/bpackage.html |  4 +++-
 lib/toaster/toastergui/views.py                | 14 ++++++++++----
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/lib/toaster/toastergui/templates/bpackage.html b/lib/toaster/toastergui/templates/bpackage.html
index 2d4948b..80229f9 100644
--- a/lib/toaster/toastergui/templates/bpackage.html
+++ b/lib/toaster/toastergui/templates/bpackage.html
@@ -88,7 +88,9 @@
                 </a>
             </td>
             <!-- Layer directory -->
-            <td class="recipe__layer_version__layer__local_path">{{package.recipe.layer_version.layer.local_path}}</td>
+            {% if not MANAGED or not build.project %}
+                <td class="recipe__layer_version__layer__local_path">{{package.recipe.layer_version.layer.local_path}}</td>
+            {% endif %}
         {%else%}
             <td class="recipe__name"></td>
             <td class="recipe__version"></td>
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 70241dc..bf148e2 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1282,9 +1282,11 @@ def bpackage(request, build_id):
 
     packages = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1))
 
+    build = Build.objects.get( pk = build_id )
+
     context = {
         'objectname': 'packages built',
-        'build': Build.objects.get(pk=build_id),
+        'build': build,
         'objects' : packages,
         'default_orderby' : 'name:+',
         'tablecols':[
@@ -1349,16 +1351,20 @@ def bpackage(request, build_id):
                 'qhelp':'The Git commit of the layer providing the recipe that builds the package',
                 'clclass': 'recipe__layer_version__layer__commit', 'hidden': 1,
             },
-            {
+            ]
+        }
+
+    if not toastermain.settings.MANAGED or build.project is None:
+
+        tc_layerDir = {
                 'name':'Layer directory',
                 'qhelp':'Path to the layer providing the recipe that builds the package',
                 'orderfield': _get_toggle_order(request, "recipe__layer_version__layer__local_path"),
                 'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__layer__local_path"),
                 'orderkey' : 'recipe__layer_version__layer__local_path',
                 'clclass': 'recipe__layer_version__layer__local_path', 'hidden': 1,
-            },
-            ]
         }
+        context['tablecols'].append(tc_layerDir)
 
     response = render(request, template, context)
     _save_parameters_cookies(response, pagesize, orderby, request)
-- 
1.9.1



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

* [PATCH 10/10] toaster: importlayer Remove description input field
  2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
                   ` (8 preceding siblings ...)
  2015-02-18 19:11 ` [PATCH 09/10] toasterui: remove layer directory in managed mode Alex DAMIAN
@ 2015-02-18 19:11 ` Alex DAMIAN
  9 siblings, 0 replies; 11+ messages in thread
From: Alex DAMIAN @ 2015-02-18 19:11 UTC (permalink / raw)
  To: bitbake-devel

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

This wasn't required or working due to a typo and adds ambiguity between
the summary and description. The correct method for changing the description
or summary is via the layerdetails page.

[YOCTO #7190]

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/toastergui/static/js/importlayer.js   | 1 -
 lib/toaster/toastergui/templates/importlayer.html | 6 ------
 lib/toaster/toastergui/views.py                   | 3 ---
 3 files changed, 10 deletions(-)

diff --git a/lib/toaster/toastergui/static/js/importlayer.js b/lib/toaster/toastergui/static/js/importlayer.js
index e782bda..9d54286 100644
--- a/lib/toaster/toastergui/static/js/importlayer.js
+++ b/lib/toaster/toastergui/static/js/importlayer.js
@@ -136,7 +136,6 @@ function importLayerPageInit (ctx) {
         name: layerNameInput.val(),
         vcs_url: vcsURLInput.val(),
         git_ref: gitRefInput.val(),
-        summary:  $("#layer-summary").val(),
         dir_path: $("#layer-subdir").val(),
         project_id: ctx.projectId,
         layer_deps: layerDepsCsv,
diff --git a/lib/toaster/toastergui/templates/importlayer.html b/lib/toaster/toastergui/templates/importlayer.html
index a4d8ee1..1196e0c 100644
--- a/lib/toaster/toastergui/templates/importlayer.html
+++ b/lib/toaster/toastergui/templates/importlayer.html
@@ -84,12 +84,6 @@
                             </div>
                           </div>
 
-                          <label class="project-form" for="layer-description">Layer description
-                            <span class="muted">(optional)</span>
-                            <span class="icon-question-sign get-help" title="A short layer explanation" />
-                          </label>
-                          <textarea id="layer-description" class="input-xxlarge"></textarea>
-
                     </fieldset>
                     <fieldset class="air">
                         <legend>
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index bf148e2..be74c10 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2422,9 +2422,6 @@ if toastermain.settings.MANAGED:
             if layer_created:
                 layer.layer_source = layer_source
                 layer.vcs_url = post_data['vcs_url']
-                if post_data.has_key('summary'):
-                    layer.summary = layer.description = post_data['summary']
-
                 layer.up_date = timezone.now()
                 layer.save()
             else:
-- 
1.9.1



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

end of thread, other threads:[~2015-02-18 19:11 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-18 19:11 [PATCH 00/10] Toaster patchset Alex DAMIAN
2015-02-18 19:10 ` [PATCH 01/10] toaster: bitbake cooker log saving and downloading Alex DAMIAN
2015-02-18 19:10 ` [PATCH 02/10] toaster: properly detect starting in rolling log file Alex DAMIAN
2015-02-18 19:10 ` [PATCH 03/10] toasterui: fix time estimation in project page Alex DAMIAN
2015-02-18 19:10 ` [PATCH 04/10] toasterui: UI query performance improvements Alex DAMIAN
2015-02-18 19:10 ` [PATCH 05/10] toaster: get proper version string Alex DAMIAN
2015-02-18 19:11 ` [PATCH 06/10] toaster: landing page when no build module Alex DAMIAN
2015-02-18 19:11 ` [PATCH 07/10] toaster: layerdetails Don't show None type in description/summary Alex DAMIAN
2015-02-18 19:11 ` [PATCH 08/10] toasterui: style the Toaster version information Alex DAMIAN
2015-02-18 19:11 ` [PATCH 09/10] toasterui: remove layer directory in managed mode Alex DAMIAN
2015-02-18 19:11 ` [PATCH 10/10] toaster: importlayer Remove description input field Alex DAMIAN

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.