Skip to contentSkip to conversation

toaster patchset

PATCH In review Alex DAMIAN 2 participants 25 messages Jun 25, 2015 – Jun 29, 2015

lore
Share & tools
lore
#0 lore raw

cover toaster patchset

From: Alexandru DAMIAN <[email protected]>

This toaster patchset brings in filters for new toaster tables, removes the differences between managed and analysis modes in favour of project types, and more minor fixes.

Can you please cherry-pick ?

Thank you,
Alex

The following changes since commit 32166ac3c85ff3c04081580ae76bd63590d6ff3e:

runqueue: Sanity check BB_NUMBER_THREADS (2015-06-19 22:43:48 +0100)

are available in the git repository at:

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

Alexandru DAMIAN (16):
toastergui: fix angular error
toaster: improve the buildenvironment API
toastergui: enable strict variable checking
toaster: fixing undefined variables
toaster: remove MANAGED references
toaster: remove BuildRequest references
toaster: refactor the builds pages
toaster: fill in build data from buildrequest
toaster: fixes after replacing BuildRequest with Build
toaster: add django-aggregate-if
toaster: bring django-aggregate-if into the project
toaster: refactor build model
toastergui: select project types
toaster: delete multiple builds
toasterui: verify variable before usage
toasterui: fixes after html5 compliance testing

Michael Wood (7):
toaster: Enable toastertable cache
toaster: toastertable Pass up the kwargs for setup_filter
toaster: table.js fix filter visual indicator and interaction
toaster: Restore 'in project' filters to main tables
toaster: bldcontrol Ignore toasterconf files in own directories
toaster: split orm app into it's own module and app
toaster: Add url pattern for backward compatibility

 lib/bb/ui/buildinfohelper.py                       |  73 ++-
 lib/bb/ui/toasterui.py                             |  27 +-
 lib/toaster/bldcollector/__init__.py               |   0
 lib/toaster/{orm => bldcollector}/admin.py         |   3 +-
 lib/toaster/{orm => bldcollector}/urls.py          |   3 +-
 lib/toaster/{orm => bldcollector}/views.py         |   0
 lib/toaster/bldcontrol/bbcontroller.py             |   3 +
 lib/toaster/bldcontrol/localhostbecontroller.py    |  24 +-
 .../management/commands/checksettings.py           |   2 +
 .../bldcontrol/management/commands/runbuilds.py    |  69 ++-
 lib/toaster/bldcontrol/models.py                   |   3 +
 lib/toaster/bldcontrol/sshbecontroller.py          |  21 +
 .../contrib/django-aggregate-if-master/.gitignore  |  10 +
 .../contrib/django-aggregate-if-master/.travis.yml |  50 ++
 .../contrib/django-aggregate-if-master/LICENSE     |  21 +
 .../contrib/django-aggregate-if-master/README.rst  | 156 +++++
 .../django-aggregate-if-master/aggregate_if.py     | 164 ++++++
 .../contrib/django-aggregate-if-master/runtests.py |  48 ++
 .../contrib/django-aggregate-if-master/setup.py    |  33 ++
 .../contrib/django-aggregate-if-master/tox.ini     | 198 +++++++
 ...ect__chg_field_project_bitbake_version__chg_.py |   5 +-
 ...k__add_field_layer_version_local_path__del_f.py | 343 +++++++++++
 ...ings_no__del_field_build_errors_no__del_fiel.py | 353 ++++++++++++
 lib/toaster/orm/models.py                          |  67 ++-
 lib/toaster/toastergui/static/js/base.js           |   2 +-
 lib/toaster/toastergui/static/js/projectapp.js     |  20 +-
 lib/toaster/toastergui/static/js/table.js          |  59 +-
 lib/toaster/toastergui/tables.py                   |  75 ++-
 lib/toaster/toastergui/templates/base.html         |  20 +-
 .../toastergui/templates/basebuilddetailpage.html  |   4 +-
 .../toastergui/templates/basebuildpage.html        |   7 +-
 .../toastergui/templates/basetable_top.html        |  11 +-
 .../templates/basetable_top_buildprojects.html     |   2 -
 .../templates/basetable_top_projectbuilds.html     |   2 -
 lib/toaster/toastergui/templates/bpackage.html     |   3 -
 .../toastergui/templates/builddashboard.html       |  39 +-
 .../templates/{build.html => builds.html}          |  35 +-
 .../toastergui/templates/configuration.html        |   6 -
 lib/toaster/toastergui/templates/configvars.html   |   6 +-
 .../toastergui/templates/detail_search_header.html |   2 +-
 .../toastergui/templates/detail_sorted_header.html |   2 +-
 .../toastergui/templates/filtersnippet.html        |   4 +-
 .../templates/generic-toastertable-page.html       |   2 +
 lib/toaster/toastergui/templates/importlayer.html  |  15 +-
 lib/toaster/toastergui/templates/landing.html      |  37 +-
 .../toastergui/templates/managed_builds.html       | 167 ------
 .../toastergui/templates/managed_mrb_section.html  | 193 -------
 lib/toaster/toastergui/templates/mrb_section.html  |  70 ++-
 lib/toaster/toastergui/templates/newproject.html   |  99 ++--
 .../toastergui/templates/package_detail_base.html  |   7 -
 lib/toaster/toastergui/templates/project.html      |  39 +-
 .../toastergui/templates/projectbuilds.html        |  30 +-
 lib/toaster/toastergui/templates/projects.html     |  27 +-
 lib/toaster/toastergui/templates/recipe.html       |   9 +-
 lib/toaster/toastergui/templates/recipes.html      |   7 +-
 lib/toaster/toastergui/templates/runagain.html     |   7 -
 lib/toaster/toastergui/templates/target.html       |   7 +-
 lib/toaster/toastergui/templates/task.html         |  36 +-
 lib/toaster/toastergui/templates/tasks.html        |   7 +-
 .../toastergui/templates/toastertable-simple.html  |   4 +-
 lib/toaster/toastergui/templates/toastertable.html |   4 +-
 lib/toaster/toastergui/urls.py                     |   3 -
 lib/toaster/toastergui/views.py                    | 633 +++++----------------
 lib/toaster/toastergui/widgets.py                  |  19 +-
 .../toastermain/management/commands/builddelete.py |  56 +-
 lib/toaster/toastermain/settings.py                |  18 +-
 lib/toaster/toastermain/urls.py                    |   4 +
 67 files changed, 2191 insertions(+), 1284 deletions(-)
 create mode 100644 lib/toaster/bldcollector/__init__.py
 rename lib/toaster/{orm => bldcollector}/admin.py (92%)
 rename lib/toaster/{orm => bldcollector}/urls.py (95%)
 rename lib/toaster/{orm => bldcollector}/views.py (100%)
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/.gitignore
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/.travis.yml
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/LICENSE
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/README.rst
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/aggregate_if.py
 create mode 100755 lib/toaster/contrib/django-aggregate-if-master/runtests.py
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/setup.py
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/tox.ini
 create mode 100644 lib/toaster/orm/migrations/0022_auto__add_field_target_task__add_field_layer_version_local_path__del_f.py
 create mode 100644 lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py
 rename lib/toaster/toastergui/templates/{build.html => builds.html} (75%)
 delete mode 100644 lib/toaster/toastergui/templates/managed_builds.html
 delete mode 100644 lib/toaster/toastergui/templates/managed_mrb_section.html
 delete mode 100644 lib/toaster/toastergui/templates/runagain.html
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/23 toastergui: fix angular error

From: Alexandru DAMIAN <[email protected]>

Due to invalid identification of builds in the array update code (by id and status), we could end up with multiple entries sharing the same primary id, visible in the UI as an angular error.

We modify the code to identify the builds exclusively by id.

[YOCTO #7611]

---
 lib/toaster/toastergui/static/js/projectapp.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/toaster/toastergui/static/js/projectapp.js +1 -1
index 44e244d..b2e65c5 100644
@@ -341,7 +341,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                     var toDelete = [];
                     // step 1 - delete entries not found
                     $scope.builds.forEach(function (elem) {
-                        if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id && elemX.status == elem.status; })) {
+                        if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id; })) {
                             toDelete.push(elem);
                         }
                     });
Signature · 1 line
1.9.1
#2 lore raw

PATCH 2/23 toaster: improve the buildenvironment API

From: Alexandru DAMIAN <[email protected]>

We improve the buildenvironment API by reducing it to a single
command: triggerBuild.

This command is specifically implemented in each BE controller type, so the runbuilds management command is only concerned with scheduling the next build, and not with the details of how a build is actually started.

---
 lib/toaster/bldcontrol/bbcontroller.py             |  3 +++
 lib/toaster/bldcontrol/localhostbecontroller.py    | 22 ++++++++++++++++
 .../bldcontrol/management/commands/runbuilds.py    | 30 +++++-----------------
 lib/toaster/bldcontrol/sshbecontroller.py          | 21 +++++++++++++++
 4 files changed, 53 insertions(+), 23 deletions(-)
lib/toaster/bldcontrol/bbcontroller.py +3 -0
index 42675d3..9dd01e0 100644
@@ -190,6 +190,9 @@ class BuildEnvironmentController(object):
         """
         raise Exception("Must override BE release")
 
+    def triggerBuild(self, bitbake, layers, variables, targets):
+        raise Exception("Must override BE release")
+
 class ShellCmdException(Exception):
     pass
 
lib/toaster/bldcontrol/localhostbecontroller.py +22 -0
index bc3566a..d0f8632 100644
@@ -317,3 +317,25 @@ class LocalhostBEController(BuildEnvironmentController):
         import shutil
         shutil.rmtree(os.path.join(self.be.sourcedir, "build"))
         assert not os.path.exists(self.be.builddir)
+
+
+    def triggerBuild(self, bitbake, layers, variables, targets):
+        # set up the buid environment with the needed layers
+        self.setLayers(bitbake, layers)
+        self.writeConfFile("conf/toaster-pre.conf", )
+        self.writeConfFile("conf/toaster.conf", raw = "INHERIT+=\"toaster buildhistory\"")
+
+        # get the bb server running with the build req id and build env id
+        bbctrl = self.getBBController()
+
+        # trigger the build command
+        task = reduce(lambda x, y: x if len(y)== 0 else y, map(lambda y: y.task, targets))
+        if len(task) == 0:
+            task = None
+
+        bbctrl.build(list(map(lambda x:x.target, targets)), task)
+
+        logger.debug("localhostbecontroller: Build launched, exiting. Follow build logs at %s/toaster_ui.log" % self.be.builddir)
+
+        # disconnect from the server
+        bbctrl.disconnect()
lib/toaster/bldcontrol/management/commands/runbuilds.py +7 -23
index 808318f..920d9ef 100644
@@ -50,33 +50,16 @@ class Command(NoArgsCommand):
 
             # write the build identification variable
             BRVariable.objects.create(req = br, name="TOASTER_BRBE", value="%d:%d" % (br.pk, bec.be.pk))
+
             # let the build request know where it is being executed
             br.environment = bec.be
             br.save()
 
-            # set up the buid environment with the needed layers
-            bec.setLayers(br.brbitbake_set.all(), br.brlayer_set.all())
-            bec.writeConfFile("conf/toaster-pre.conf", br.brvariable_set.all())
-            bec.writeConfFile("conf/toaster.conf", raw = "INHERIT+=\"toaster buildhistory\"")
-
-            # get the bb server running with the build req id and build env id
-            bbctrl = bec.getBBController()
-
-            # trigger the build command
-            task = reduce(lambda x, y: x if len(y)== 0 else y, map(lambda y: y.task, br.brtarget_set.all()))
-            if len(task) == 0:
-                task = None
-            bbctrl.build(list(map(lambda x:x.target, br.brtarget_set.all())), task)
-
-            logger.debug("runbuilds: Build launched, exiting. Follow build logs at %s/toaster_ui.log" % bec.be.builddir)
-            # disconnect from the server
-            bbctrl.disconnect()
-
-            # cleanup to be performed by toaster when the deed is done
-
+            # this triggers an async build
+            bec.triggerBuild(br.brbitbake_set.all(), br.brlayer_set.all(), br.brvariable_set.all(), br.brtarget_set.all())
 
         except Exception as e:
-            logger.error("runbuilds: Error executing shell command %s" % e)
+            logger.error("runbuilds: Error launching build %s" % e)
             traceback.print_exc(e)
             if "[Errno 111] Connection refused" in str(e):
                 # Connection refused, read toaster_server.out
@@ -124,8 +107,9 @@ class Command(NoArgsCommand):
     def cleanup(self):
         from django.utils import timezone
         from datetime import timedelta
-        # environments locked for more than 30 seconds - they should be unlocked
-        BuildEnvironment.objects.filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
+        # DISABLED environments locked for more than 30 seconds - they should be unlocked
+        #BuildEnvironment.objects.filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
+        pass
 
 
     def handle_noargs(self, **options):
lib/toaster/bldcontrol/sshbecontroller.py +21 -0
index 29ed0a7..8ef434b 100644
@@ -156,3 +156,24 @@ class SSHBEController(BuildEnvironmentController):
         import shutil
         shutil.rmtree(os.path.join(self.be.sourcedir, "build"))
         assert not self._pathexists(self.be.builddir)
+
+    def triggerBuild(self, bitbake, layers, variables, targets):
+        # set up the buid environment with the needed layers
+        self.setLayers(bitbake, layers)
+        self.writeConfFile("conf/toaster-pre.conf", )
+        self.writeConfFile("conf/toaster.conf", raw = "INHERIT+=\"toaster buildhistory\"")
+
+        # get the bb server running with the build req id and build env id
+        bbctrl = self.getBBController()
+
+        # trigger the build command
+        task = reduce(lambda x, y: x if len(y)== 0 else y, map(lambda y: y.task, targets))
+        if len(task) == 0:
+            task = None
+
+        bbctrl.build(list(map(lambda x:x.target, targets)), task)
+
+        logger.debug("localhostbecontroller: Build launched, exiting. Follow build logs at %s/toaster_ui.log" % self.be.builddir)
+
+        # disconnect from the server
+        bbctrl.disconnect()
Signature · 1 line
1.9.1
#3 lore raw

PATCH 3/23 toastergui: enable strict variable checking

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

In order to make sure we don't use undefined variables in the templates, we enforce strict variable checking in the templating engine.

---
 lib/toaster/toastermain/settings.py | 7 +++++++
 1 file changed, 7 insertions(+)
lib/toaster/toastermain/settings.py +7 -0
index 3c7cb3b..141ad08 100644
@@ -386,3 +386,10 @@ connection_created.connect(activate_synchronous_off)
 #
 
 
+class InvalidString(str):
+    def __mod__(self, other):
+        from django.template.base import TemplateSyntaxError
+        raise TemplateSyntaxError(
+            "Undefined variable or unknown value for: \"%s\"" % other)
+
+TEMPLATE_STRING_IF_INVALID = InvalidString("%s")
Signature · 1 line
1.9.1
#4 lore raw

PATCH 4/23 toaster: fixing undefined variables

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This patchset fixes usage of undefined variables in the base page.

---
 lib/toaster/toastergui/templates/base.html          | 11 +++++++----
 lib/toaster/toastergui/templates/basetable_top.html | 11 ++++++++---
 lib/toaster/toastergui/templates/filtersnippet.html |  2 +-
 3 files changed, 16 insertions(+), 8 deletions(-)
lib/toaster/toastergui/templates/base.html +7 -4
index 9f19c03..3f3253d 100644
@@ -29,17 +29,18 @@
 {% endif %}
 <script>
   libtoaster.ctx = {
-    projectId : {{project.id|default:'undefined'}},
     jsUrl : "{% static 'js/' %}",
     htmlUrl : "{% static 'html/' %}",
     projectsUrl : "{% url 'all-projects' %}",
     {% if project.id %}
+      projectId : {{project.id}},
       projectPageUrl : {% url 'project' project.id as purl%}{{purl|json}},
       projectName : {{project.name|json}},
       projectTargetsUrl: {% url 'projectavailabletargets' project.id as paturl%}{{paturl|json}},
       projectBuildsUrl: {% url 'projectbuilds' project.id as pburl %}{{pburl|json}},
       projectId : {{project.id}},
     {% else %}
+      projectId : undefined,
       projectPageUrl : undefined,
       projectName : undefined,
       projectId : undefined,
@@ -101,8 +102,10 @@
                   <h3>New build</h3>
                   <h6>Project:</h6>
                   <span id="project">
-                    <a class="lead" href="{% if project.id %}{% url 'project' project.id %}{% endif %}">{{project.name}}</a>
-                    <i class="icon-pencil"></i>
+                    {% if project.id %}
+                      <a class="lead" href="{% url 'project' project.id %}">{{project.name}}</a>
+                      <i class="icon-pencil"></i>
+                    {% endif %}
                   </span>
                   <form id="change-project-form" style="display:none;">
                     <div class="input-append">
@@ -122,7 +125,7 @@
                     <form>
                       <input type="text" class="input-xlarge" id="build-target-input" placeholder="Type a recipe name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" disabled/>
                       <div>
-                        <button class="btn btn-primary" id="build-button" data-project-id="{{project.id}}" disabled>Build</button>
+                        <button class="btn btn-primary" id="build-button" disabled>Build</button>
                       </div>
                     </form>
                   </li>
lib/toaster/toastergui/templates/basetable_top.html +8 -3
index fcd2f03..8dd56ed 100644
@@ -162,7 +162,7 @@
 <div class="navbar">
     <div class="navbar-inner">
         <form class="navbar-search input-append pull-left" id="searchform">
-            <input class="input-xxlarge" id="search" name="search" type="text" placeholder="Search {%if object_search_display %}{{object_search_display}}{%else%}{{objectname}}{%endif%}" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{%endif%}
+            <input class="input-xxlarge" id="search" name="search" type="text" placeholder="Search {%if object_search_display %}{{object_search_display}}{%else%}{{objectname}}{%endif%}" value="{%if request.GET.search %}{{request.GET.search}}{% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{%endif%}
             <input type="hidden" name="orderby" value="{{request.GET.orderby}}">
             <input type="hidden" name="page" value="1">
             <button class="btn" type="submit" value="Search">Search</button>
@@ -191,7 +191,12 @@
                                        onclick="showhideTableColumn(
                                            $(this).attr('id'),
                                            $(this).is(':checked'),
-                                           '{{i.orderkey}}' )"
+                                           {% if i.ordericon %}
+                                              '{{i.orderkey}}'
+                                           {% else %}
+                                              undefined
+                                           {% endif %}
+                                       )"
                                    {%else%}
                                        checked disabled
                                    {% endif %}/>   {{i.name}}
@@ -221,7 +226,7 @@
     <thead>
         <!-- Table header row; generated from "tablecols" entry in the context dict -->
         <tr>
-            {% for tc in tablecols %}<th class="{{tc.dclass}} {{tc.clclass}}">
+            {% for tc in tablecols %}<th class="{%if tc.dclass%}{{tc.dclass}}{%endif%} {% if tc.clclass %}{{tc.clclass}}{% endif %}">
                 {%if tc.qhelp%}<i class="icon-question-sign get-help" title="{{tc.qhelp}}"></i>{%endif%}
                 {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })">{{tc.name}}</a>{%else%}<span class="muted">{{tc.name}}</span>{%endif%}
                 {%if tc.ordericon%} <i class="icon-caret-{{tc.ordericon}}"></i>{%endif%}
lib/toaster/toastergui/templates/filtersnippet.html +1 -1
index f624d88..56e2b21 100644
@@ -2,7 +2,7 @@
 <!-- '{{f.class}}' filter -->
 {% with f.class as  key %}
 <form id="filter_{{f.class}}" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
-        <input type="hidden" name="search" value="{{request.GET.search}}"/>
+        <input type="hidden" name="search" value="{%if request.GET.search %}{{request.GET.search}}{%endif%}"/>
         <div class="modal-header">
             <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
             {% if search_term %}
Signature · 1 line
1.9.1
#5 lore raw

PATCH 5/23 toaster: remove MANAGED references

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

We conflate the managed and analysis modes by deleting alternative code paths, favouring the MANAGED mode, always considering the MANAGED variable True.

---
 lib/toaster/orm/models.py                          |   4 +-
 lib/toaster/toastergui/templates/base.html         |   9 +-
 .../toastergui/templates/basebuilddetailpage.html  |   4 +-
 .../toastergui/templates/basebuildpage.html        |   6 +-
 .../templates/basetable_top_buildprojects.html     |   2 -
 .../templates/basetable_top_projectbuilds.html     |   2 -
 lib/toaster/toastergui/templates/bpackage.html     |   3 -
 lib/toaster/toastergui/templates/build.html        |   8 --
 .../toastergui/templates/builddashboard.html       |  16 ----
 lib/toaster/toastergui/views.py                    | 103 +--------------------
 10 files changed, 8 insertions(+), 149 deletions(-)
lib/toaster/orm/models.py +1 -3
index 8819450..422f2bf 100644
@@ -288,9 +288,7 @@ class BuildArtifact(models.Model):
 
 
     def is_available(self):
-        if settings.MANAGED and build.project is not None:
-            return build.buildrequest.environment.has_artifact(file_path)
-        return False
+        return build.buildrequest.environment.has_artifact(file_path)
 
 class ProjectTarget(models.Model):
     project = models.ForeignKey(Project)
lib/toaster/toastergui/templates/base.html +1 -8
index 3f3253d..7430338 100644
@@ -48,7 +48,6 @@
   };
 </script>
 <script src="{% static 'js/base.js' %}"></script>
-{%if MANAGED %}
 <script>
   $(document).ready(function () {
     /* Vars needed for base.js */
@@ -59,10 +58,6 @@
     basePageInit(ctx);
   });
 </script>
-{% endif %}
-<script>
-
-</script>
 
 {% block extraheadcontent %}
 {% endblock %}
@@ -80,14 +75,13 @@
             <span class="brand">
                 <a href="/">Toaster</a>
                 {% if DEBUG %}
-                    <i class="icon-info-sign" title="<strong>Toaster version information</strong>" data-content="<dl><dt>Branch</dt><dd>{{TOASTER_BRANCH}}</dd><dt>Revision</dt><dd>{{TOASTER_REVISION}}</dd><dt>Mode</dt><dd>{%if MANAGED%}Build{%else%}Analysis{%endif%}</dd></dl>"></i>
+                    <i class="icon-info-sign" title="<strong>Toaster version information</strong>" data-content="<dl><dt>Branch</dt><dd>{{TOASTER_BRANCH}}</dd><dt>Revision</dt><dd>{{TOASTER_REVISION}}</dd></dl>"></i>
                 {% endif %}
             </span>
             <a class="pull-right manual" target="_blank" href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html">
                 <i class="icon-book"></i>
                 Toaster manual
             </a>
-            {%if MANAGED %}
             <div class="btn-group pull-right">
                   <a class="btn" id="new-project-button" href="{% url 'newproject' %}">New project</a>
             </div>
@@ -132,7 +126,6 @@
               </ul>
             </div>
 
-            {%endif%}
 
     </div>
 </div>
lib/toaster/toastergui/templates/basebuilddetailpage.html +1 -3
index c8e217e..d324c90 100644
@@ -7,10 +7,8 @@
     <div class="section">
         <ul class="breadcrumb" id="breadcrumb">
             <li><a href="{% url 'all-builds' %}">All builds</a></li>
-      {% if MANAGED and build.project %}
             <li><a href="{% url 'project' build.project.id %}">{{build.project.name}}</a></li>
-      {%endif%}
-            <li><a href="{%url 'builddashboard' build.pk%}">{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%}{%if not MANAGED %}{{build.machine}}{%endif%} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
+            <li><a href="{%url 'builddashboard' build.pk%}">{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
             {% block localbreadcrumb %}{% endblock %}
         </ul>
         <script>
lib/toaster/toastergui/templates/basebuildpage.html +2 -4
index c03f1b4..b7a4dd2 100644
@@ -8,14 +8,12 @@
 <!-- Breadcrumbs -->
     <div class="section">
         <ul class="breadcrumb" id="breadcrumb">
-              <li><a href="{% url 'all-builds' %}">All builds</a></li>
-          {% if MANAGED and build.project %}
+            <li><a href="{% url 'all-builds' %}">All builds</a></li>
             <li><a href="{% url 'project' build.project.id %}">{{build.project.name}}</a></li>
-          {%endif%}
             <li>
             {% block parentbreadcrumb %}
             <a href="{%url 'builddashboard' build.pk%}">
-                {{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {%if not MANAGED %}{{build.machine}}{% endif %} ({{build.completed_on|date:"d/m/y H:i"}})
+                {{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} ({{build.completed_on|date:"d/m/y H:i"}})
             </a>
             {% endblock %}
             </li>
lib/toaster/toastergui/templates/basetable_top_buildprojects.html +0 -2
index d517179..7b19f4b 100644
@@ -1,7 +1,6 @@
 {% extends "basetable_top.html" %}
 
 {%block custombuttons %}
-{% if MANAGED %}
   <div class="btn-group builds-projects">
     <button class="btn dropdown-toggle" data-toggle="dropdown">
         <span class="selection">Show all builds</span>
@@ -12,5 +11,4 @@
         <li><a href="{% url 'all-projects'%}">Show all projects</a></li>
     </ul>
   </div>
-{% endif %}
 {%endblock%}
lib/toaster/toastergui/templates/basetable_top_projectbuilds.html +0 -2
index bfefff5..f5b01c8 100644
@@ -1,7 +1,6 @@
 {% extends "basetable_top.html" %}
 
 {%block custombuttons %}
-{% if MANAGED %}
   <div class="btn-group builds-projects">
     <button class="btn dropdown-toggle" data-toggle="dropdown">
         <span class="selection">Show all projects</span>
@@ -12,5 +11,4 @@
         <li><a href="{% url 'all-projects'%}">Show all projects</a></li>
     </ul>
   </div>
-{% endif %}
 {%endblock%}
lib/toaster/toastergui/templates/bpackage.html +0 -3
index 1c47354..d775fec 100644
@@ -88,9 +88,6 @@
                 </a>
             </td>
             <!-- Layer directory -->
-            {% if not MANAGED or not build.project %}
-                <td class="recipe__layer_version__local_path">{{package.recipe.layer_version.local_path}}</td>
-            {% endif %}
         {%else%}
             <td class="recipe__name"></td>
             <td class="recipe__version"></td>
lib/toaster/toastergui/templates/build.html +0 -8
index f7ad2f4..f0b5ea5 100644
@@ -68,11 +68,9 @@
                 {% query build.task_build outcome=4 order__gt=0 as exectask%}
                     {% if exectask.count == 1 %}
                         <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a>
-                      {% if MANAGED and build.project %}
                         <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}">
                             <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
                         </a>
-                      {% endif %}
                     {% elif exectask.count > 1%}
                         <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a>
                     {%endif%}
@@ -84,21 +82,15 @@
             </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>
             <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td>
-            {% if not MANAGED or not build.project %}
-                <td class="log">{{build.cooker_log_path}}</td>
-            {% endif %}
             <td class="output">
               {% if build.outcome == build.SUCCEEDED %}
               <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
               {% endif %}
             </td>
-   {% if MANAGED %}
-            <td class="project">
             {% if build.project %}
                 <a href="{% url 'project' build.project.id %}">{{build.project.name}}</a>
             {% endif %}
             </td>
-   {% endif %}
         </tr>
 
         {% endfor %}
lib/toaster/toastergui/templates/builddashboard.html +0 -16
index ad497e6..47b8d7a 100644
@@ -37,9 +37,7 @@
     <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>
-      {% if MANAGED and build.project %}
             <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%else%}btn-danger{%endif%} pull-right log" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a>
-      {% endif %}
             </span>
 {%endif%}
     </div>
@@ -117,19 +115,11 @@
             <dt>
                 <i class="icon-question-sign get-help" title="The location in disk of the license manifest, a document listing all packages installed in your image and their licenses"></i>
 
-            {% if MANAGED and build.project %}
                 License manifest
-            {% else %}
-                <a href="{% url 'targetpkg' build.pk target.target.pk %}">License manifest</a>
-            {% endif %}
             </dt>
-            {% if MANAGED and build.project %}
             <dd>
                 <a href="{% url 'targetpkg' build.pk target.target.pk %}">View in Toaster</a> |
                 <a href="{% url 'build_artifact' build.pk 'licensemanifest' target.target.pk %}">Download</a></dd>
-            {% else %}
-            <dd><code>{{target.target.license_manifest_path}}</code></dd>
-            {% endif %}
             <dt>
                 <i class="icon-question-sign get-help" title="Image files are stored in <code>/build/tmp/deploy/images/</code>"></i>
                 Image files
@@ -170,13 +160,9 @@
                 Other artifacts</dt>
             <dd><div>
               {% for ba in build.buildartifact_set.all|dictsort:"file_name" %}
-                {% if MANAGED and build.project %}
                 <a href="{%url 'build_artifact' build.id 'buildartifact' ba.id %}">
-                {% endif %}
                     {{ba.get_local_file_name}}
-                {% if MANAGED and build.project %}
                 </a>
-                {% endif %}
 
                 ({{ba.file_size|filtered_filesizeformat}}) <br/>
               {% endfor %}
@@ -211,11 +197,9 @@
                         <span class="task-name">{{exectask.0.task_name}}</span>
                     </a>
 
-                      {% if MANAGED and build.project %}
                         <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}">
                             <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
                         </a>
-                      {% endif %}
 
                 {% elif exectask.count > 1%}
                     <a class="error" href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}}</a>
lib/toaster/toastergui/views.py +3 -100

149 lines not on this page · raw message

Signature · 1 line
1.9.1
#6 lore raw

PATCH 6/23 toaster: remove BuildRequest references

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

In the toastergui application we should not display implementation details about how the builds are run. This patch removes the references to BuildRequest on the majority of the views (except Builds page itself, as that is more complicated).

---
 .../toastergui/templates/basebuildpage.html        |  1 +
 lib/toaster/toastergui/templates/configvars.html   |  4 +-
 lib/toaster/toastergui/views.py                    | 66 +++++++++-------------
 3 files changed, 30 insertions(+), 41 deletions(-)
lib/toaster/toastergui/templates/basebuildpage.html +1 -0
index b7a4dd2..105ad85 100644
@@ -24,6 +24,7 @@
             $('#breadcrumb > li').append("<span class=\"divider\">→</span>");
             $('#breadcrumb > li:last').addClass("active");
             $('#breadcrumb > li:last > span').remove();
+	    console.log("done");
         });
         </script>
     </div>
lib/toaster/toastergui/templates/configvars.html +2 -2
index cbe3c68..8957673 100644
@@ -56,7 +56,7 @@
         <td class="file"><a data-toggle="modal" href="#variable-{{variable.pk}}">
             {% if variable.vhistory.all %}
                 {% for path in variable.vhistory.all|filter_setin_files:file_filter %}
-                    {{path|cut_path_prefix:dirstostrip}}<br/>
+                    {{path}}<br/>
                 {% endfor %}
             {% endif %}
         </a></td>
@@ -117,7 +117,7 @@
                 <tbody>
                     {% for vh in variable.vhistory.all %}
                     <tr>
-                        <td>{{forloop.counter}}</td><td>{{vh.file_name|cut_path_prefix:dirstostrip}}</td><td>{{vh.operation}}</td><td>{{vh.line_number}}</td>
+                        <td>{{forloop.counter}}</td><td>{{vh.file_name}}</td><td>{{vh.operation}}</td><td>{{vh.line_number}}</td>
                     </tr>
                     {%endfor%}
                 </tbody>
lib/toaster/toastergui/views.py +27 -39

132 lines not on this page · raw message

Signature · 1 line
1.9.1
#7 lore raw

PATCH 7/23 toaster: refactor the builds pages

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

Taking out the managed mode-specific bits in build-related pages, as there is always only one mode available.

Also refactors the build pages in order to always display Build objects instead of BuildRequest objects.

---
 lib/toaster/toastergui/static/js/projectapp.js     |  14 +-
 .../templates/{build.html => builds.html}          |   7 +-
 .../toastergui/templates/managed_builds.html       | 167 --------
 .../toastergui/templates/managed_mrb_section.html  | 193 ---------
 lib/toaster/toastergui/templates/mrb_section.html  |  41 +-
 lib/toaster/toastergui/templates/project.html      |  40 +-
 .../toastergui/templates/projectbuilds.html        |   1 -
 lib/toaster/toastergui/templates/projects.html     |  22 +-
 lib/toaster/toastergui/urls.py                     |   2 +-
 lib/toaster/toastergui/views.py                    | 437 +++++----------------
 10 files changed, 175 insertions(+), 749 deletions(-)
 rename lib/toaster/toastergui/templates/{build.html => builds.html} (97%)
 delete mode 100644 lib/toaster/toastergui/templates/managed_builds.html
 delete mode 100644 lib/toaster/toastergui/templates/managed_mrb_section.html
lib/toaster/toastergui/static/js/projectapp.js +9 -5
index b2e65c5..40e2e1f 100644
@@ -429,13 +429,17 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
      */
 
     $scope.validateData = function () {
-        if ($scope.layers.length === 0) {
+        if ($scope.project.release) {
+            if ($scope.layers.length === 0) {
             $scope.layeralert = $scope.displayAlert($scope.zone1alerts, "You need to add some layers to this project. <a href=\""+$scope.urls.layers+"\">View all layers available in Toaster</a> or <a href=\""+$scope.urls.importlayer+"\">import a layer</a>");
-        } else {
-            if ($scope.layeralert !== undefined) {
-                $scope.layeralert.close();
-                $scope.layeralert = undefined;
+            } else {
+                if ($scope.layeralert !== undefined) {
+                    $scope.layeralert.close();
+                    $scope.layeralert = undefined;
+                }
             }
+        } else {
+            $scope.layeralert = $scope.displayAlert($scope.zone1alerts, "This project is not set to run builds.");
         }
     };
 
lib/toaster/toastergui/templates/builds.html renamed from lib/toaster/toastergui/templates/build.html +4 -3
similarity index 97%
rename from lib/toaster/toastergui/templates/build.html
rename to lib/toaster/toastergui/templates/builds.html
index f0b5ea5..e9211af 100644
@@ -14,13 +14,15 @@
 
 {% block pagecontent %}
 
+{% if last_date_from and last_date_to %}
 <script>
-    // intiialize the date range controls
+    // initialize the date range controls
     $(document).ready(function () {
         date_init('started_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_started_on}}','{{dateMax_started_on}}','{{daterange_selected}}');
         date_init('completed_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_completed_on}}','{{dateMax_completed_on}}','{{daterange_selected}}');
     });
 </script>
+{%endif%} {# last_date_from and last_date_to #}
 
 <div class="row-fluid">
 
@@ -87,9 +89,8 @@
               <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
               {% endif %}
             </td>
-            {% if build.project %}
+	    <td>
                 <a href="{% url 'project' build.project.id %}">{{build.project.name}}</a>
-            {% endif %}
             </td>
         </tr>
 
lib/toaster/toastergui/templates/managed_builds.html deleted +0 -167

167 lines not on this page · raw message

lib/toaster/toastergui/templates/managed_mrb_section.html deleted +0 -193

193 lines not on this page · raw message

lib/toaster/toastergui/templates/mrb_section.html +36 -5

59 lines not on this page · raw message

lib/toaster/toastergui/templates/project.html +8 -32
index bca703a..0f6a77b 100644
@@ -124,7 +124,7 @@ vim: expandtab tabstop=2
   <div class="well">
     <form class="build-form" data-ng-submit="buildNamedTarget()">
       <div class="input-append controls">
-        <input type="text" class="huge input-xxlarge" placeholder="Type the recipe(s) you want to build" autocomplete="off" data-ng-model="targetName" data-typeahead="a.name for a in getRecipesAutocompleteSuggestions($viewValue)" data-typeahead-template-url="recipes_suggestion_details" data-ng-disabled="!layers.length"/>
+        <input type="text" class="huge input-xxlarge" placeholder="Type the recipe(s) you want to build" autocomplete="off" data-ng-model="targetName" data-typeahead="a.name for a in getRecipesAutocompleteSuggestions($viewValue)" data-typeahead-template-url="recipes_suggestion_details" data-ng-disabled="!project.release || !layers.length"/>
         <button type="submit" class="btn btn-large btn-primary" data-ng-disabled="!targetName.length">
         Build
         </button>
@@ -145,11 +145,11 @@ vim: expandtab tabstop=2
 
   <a id="buildslist"></a>
   <h2 class="air" data-ng-if="builds.length">Latest builds</h2>
-  <div class="animate-repeat alert"  data-ng-repeat="b in builds track by b.id" data-ng-class="{'queued':'alert-info', 'deleted':'alert-info', 'in progress': 'alert-info', 'failed':'alert-error', 'completed':{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.build[0].status]}[b.status]">
+  <div class="animate-repeat alert"  data-ng-repeat="b in builds track by b.id" data-ng-class="{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.status]">
     <div class="row-fluid">
         <switch data-ng-switch="b.status">
 
-          <case data-ng-switch-when="failed">
+          <case data-ng-switch-when="Failed">
             <div class="lead span3">
               <a data-ng-class="{'succeeded': 'success', 'failed': 'error'}[b.status]" href="{[b.br_page_url]}">
                 <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>
@@ -182,32 +182,8 @@ vim: expandtab tabstop=2
             </div>
           </case>
 
-          <case data-ng-switch-when="queued">
-            <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>   </div>
-            <div class="span4 lead" >Build queued
-              <i title="This build will start as soon as a build server is available" class="icon-question-sign get-help get-help-blue heading-help" data-toggle="tooltip"></i>
-            </div>
-            <button class="btn pull-right btn-info" data-ng-click="buildCancel(b)">Cancel</button>
-          </case>
-
-          <case data-ng-switch-when="created">
-            <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>   </div>
-            <div class="span4">
-              <span class="lead">Creating build</span>
-            </div>
-            <button class="btn pull-right btn-info" data-ng-click="buildCancel(b)">Cancel</button>
-          </case>
-
-          <case data-ng-switch-when="deleted">
-            <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>   </div>
-            <div class="span4" id="{[b.id]}-deleted" >
-              <span class="lead">Build cancelled</span>
-            </div>
-            <button class="btn pull-right btn-info" data-ng-click="buildDelete(b)">Close</button>
-          </case>
-
 
-          <case data-ng-switch-when="in progress">
+          <case data-ng-switch-when="In Progress">
             <switch data-ng-switch="b.build.length">
               <case data-ng-switch-when="0">
                 <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>   </div>
@@ -227,7 +203,7 @@ vim: expandtab tabstop=2
           </case>
 
 
-          <case data-ng-switch-when="completed">
+          <case data-ng-switch-when="Succeeded">
             <div class="lead span3">
               <a data-ng-class="{'Succeeded': 'success', 'Failed': 'error'}[b.build[0].status]" href="{[b.build[0].build_page_url]}">
                 <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>
@@ -293,7 +269,7 @@ vim: expandtab tabstop=2
         Layers <span class="muted counter">({[layers.length]})</span>
         <i class="icon-question-sign get-help heading-help" title="Bitbake reads metadata files from 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" data-ng-if="!layers.length">
+      <div class="alert" data-ng-if="project.release && !layers.length">
         <b>You need to add some layers </b>
         <p>
         You can:
@@ -307,7 +283,7 @@ vim: expandtab tabstop=2
       </div>
       <form data-ng-submit="layerAdd()">
         <div class="input-append">
-          <input type="text" class="input-xlarge" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" data-ng-model="layerAddName" data-typeahead="e for e in getLayersAutocompleteSuggestions($viewValue)" data-typeahead-template-url="layers_suggestion_details" data-typeahead-on-select="onLayerSelect($item, $model, $label)" data-typeahead-editable="false" data-ng-class="{ 'has-error': layerAddName.$invalid }" />
+          <input type="text" class="input-xlarge" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" data-ng-model="layerAddName" data-typeahead="e for e in getLayersAutocompleteSuggestions($viewValue)" data-typeahead-template-url="layers_suggestion_details" data-typeahead-on-select="onLayerSelect($item, $model, $label)" data-typeahead-editable="false" data-ng-class="{ 'has-error': layerAddName.$invalid }" data-ng-disabled="!project.release" />
           <input type="submit" id="add-layer" class="btn" value="Add" data-ng-disabled="!layerAddName.length"/>
         </div>
         {% csrf_token %}
@@ -334,7 +310,7 @@ vim: expandtab tabstop=2
       </h3>
         <form data-ng-submit="buildNamedTarget()">
           <div class="input-append">
-            <input type="text" class="input-xlarge" placeholder="Type the recipe(s) you want to build" autocomplete="off" data-minLength="1"  data-ng-model="targetName1" data-typeahead="a.name for a in getRecipesAutocompleteSuggestions($viewValue)" data-typeahead-template-url="recipes_suggestion_details" data-ng-disabled="!layers.length">
+            <input type="text" class="input-xlarge" placeholder="Type the recipe(s) you want to build" autocomplete="off" data-minLength="1"  data-ng-model="targetName1" data-typeahead="a.name for a in getRecipesAutocompleteSuggestions($viewValue)" data-typeahead-template-url="recipes_suggestion_details" data-ng-disabled="!project.release || !layers.length">
             <button type="submit" class="btn btn-primary" data-ng-disabled="!targetName1.length">
               Build </button>
           </div>
lib/toaster/toastergui/templates/projectbuilds.html +0 -1
index 18b2495..896c3b5 100644
@@ -105,7 +105,6 @@
             </td>
         </tr>
 
-
               {%endwith%}
       {% else %} {# we don't have a build for this build request, mask the data with build request data #}
 
lib/toaster/toastergui/templates/projects.html +14 -8
index 2334008..9c4346c 100644
@@ -7,7 +7,7 @@
 {% block pagecontent %}
 
 
-  {% include "managed_mrb_section.html" %}
+  {% include "mrb_section.html" %}
 
 
   <div class="page-header top-air">
@@ -39,7 +39,13 @@
     <tr class="data">
       <td><a href="{% url 'project' o.id %}">{{o.name}}</a></td>
       <td class="updated"><a href="{% url 'project' o.id %}">{{o.updated|date:"d/m/y H:i"}}</a></td>
-      <td><a href="{% url 'project' o.id %}#project-details">{{o.release.name}}</a></td>
+      <td>
+        {% if o.release %}
+            <a href="{% url 'project' o.id %}#project-details">{{o.release.name}}</a>
+        {% else %}
+            No release available
+        {% endif %}
+      </td>
       <td><a href="{% url 'project' o.id %}#machine-distro">{{o.get_current_machine_name}}</a></td>
       {% if o.get_number_of_builds == 0 %}
       <td class="muted">{{o.get_number_of_builds}}</td>
@@ -52,13 +58,13 @@
       <td><a href="{% url 'projectbuilds' o.id %}">{{o.get_number_of_builds}}</a></td>
       <td class="loutcome"><a href="{% url "builddashboard" o.get_last_build_id %}">{%if o.get_last_outcome == build_SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif o.get_last_outcome == build_FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td>
       <td class="ltarget"><a href="{% url "builddashboard" o.get_last_build_id %}">{{o.get_last_target}} </a></td>
-	  <td class="lerrors">{% if o.get_last_errors %}<a class="errors_no error" href="{% url "builddashboard" o.get_last_build_id %}#errors">{{o.get_last_errors}} error{{o.get_last_errors|pluralize}}</a>{%endif%}</td>
-	  <td class="lwarnings">{% if o.get_last_warnings %}<a class="warnings_no warning" href="{% url "builddashboard" o.get_last_build_id %}#warnings">{{o.get_last_warnings}} warning{{o.get_last_warnings|pluralize}}</a>{%endif%}</td>
+      <td class="lerrors">{% if o.get_last_errors %}<a class="errors_no error" href="{% url "builddashboard" o.get_last_build_id %}#errors">{{o.get_last_errors}} error{{o.get_last_errors|pluralize}}</a>{%endif%}</td>
+      <td class="lwarnings">{% if o.get_last_warnings %}<a class="warnings_no warning" href="{% url "builddashboard" o.get_last_build_id %}#warnings">{{o.get_last_warnings}} warning{{o.get_last_warnings|pluralize}}</a>{%endif%}</td>
       <td class="limagefiles">
-	    {% if o.get_last_outcome == build_SUCCEEDED %}
-	    <a href="{%url "builddashboard" o.get_last_build_id %}#images">{{fstypes|get_dict_value:o.id}}</a>
-	    {% endif %}
-	  </td>
+        {% if o.get_last_outcome == build_SUCCEEDED %}
+        <a href="{%url "builddashboard" o.get_last_build_id %}#images">{{fstypes|get_dict_value:o.id}}</a>
+        {% endif %}
+      </td>
 
       {% endif %}
     </tr>
lib/toaster/toastergui/urls.py +1 -1
index bd3eb40..681f067 100644
@@ -132,7 +132,7 @@ urlpatterns = patterns('toastergui.views',
         url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'),
 
         # dashboard for failed build requests
-        url(r'^project/(?P<pid>\d+)/buildrequest/(?P<brid>\d+)$', 'buildrequestdetails', name='buildrequestdetails'),
+        url(r'^project/(?P<pid>\d+)/buildrequest/(?P<bid>\d+)$', 'buildrequestdetails', name='buildrequestdetails'),
 
         # default redirection
         url(r'^$', RedirectView.as_view( url= 'landing')),
lib/toaster/toastergui/views.py +103 -334

603 lines not on this page · raw message

Signature · 1 line
1.9.1
#8 lore raw

PATCH 8/23 toaster: fill in build data from buildrequest

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This patch adds logic to complete changing the interface from showing BuildRequests to showing Build data.

The BuildRequest data is now transformed in Build data with proper Toaster exceptions being recorded instead of listing problems during startup as build errors.

---
 lib/bb/ui/buildinfohelper.py                       | 16 ++++++++++-
 .../bldcontrol/management/commands/runbuilds.py    | 32 +++++++++++++++++++++-
 lib/toaster/orm/models.py                          | 28 +++++++++++++++++--
 lib/toaster/toastergui/templates/project.html      | 15 +++++++---
 lib/toaster/toastergui/views.py                    |  4 +--
 5 files changed, 84 insertions(+), 11 deletions(-)
lib/bb/ui/buildinfohelper.py +15 -1
index 3ea842c..8b63f70 100644
@@ -133,7 +133,21 @@ class ORMWrapper(object):
             logger.debug(1, "buildinfohelper: project is not specified, defaulting to %s" % prj)
 
 
-        build = Build.objects.create(
+        if buildrequest is not None:
+            build = buildrequest.build
+            build.machine=build_info['machine'],
+            build.distro=build_info['distro'],
+            build.distro_version=build_info['distro_version'],
+            build.completed_on=build_info['started_on'],
+            build.cooker_log_path=build_info['cooker_log_path'],
+            build.build_name=build_info['build_name'],
+            build.bitbake_version=build_info['bitbake_version']
+            build.save()
+
+            build.target_set.delete()
+
+        else:
+            build = Build.objects.create(
                                     project = prj,
                                     machine=build_info['machine'],
                                     distro=build_info['distro'],
lib/toaster/bldcontrol/management/commands/runbuilds.py +31 -1
index 920d9ef..da7d4af 100644
@@ -1,6 +1,6 @@
 from django.core.management.base import NoArgsCommand, CommandError
 from django.db import transaction
-from orm.models import Build, ToasterSetting
+from orm.models import Build, ToasterSetting, LogMessage, Target
 from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException, BuildSetupException
 from bldcontrol.models import BuildRequest, BuildEnvironment, BRError, BRVariable
 import os
@@ -109,6 +109,36 @@ class Command(NoArgsCommand):
         from datetime import timedelta
         # DISABLED environments locked for more than 30 seconds - they should be unlocked
         #BuildEnvironment.objects.filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
+
+
+        # update all Builds that failed to start
+
+        for br in BuildRequest.objects.filter(state = BuildRequest.REQ_FAILED):
+            br.build.outcome = Build.FAILED
+            # transpose the launch errors in ToasterExceptions
+            for brerror in br.brerror_set.all():
+                LogMessage.objects.create(build = br.build, level = LogMessage.EXCEPTION, message = brerror.errmsg)
+            br.build.save()
+
+
+
+        # update all BuildRequests without a build created
+        for br in BuildRequest.objects.filter(build = None):
+            br.build = Build.objects.create(project = br.project, completed_on = br.updated, started_on = br.created)
+            br.build.outcome = Build.REQ_FAILED
+            try:
+                br.build.machine = br.brvariable_set.get(name='MACHINE').value
+            except BRVariable.DoesNotExist:
+                pass
+            br.save()
+            # transpose target information
+            for brtarget in br.brtarget_set.all():
+                Target.objects.create(build = br.build, target= brtarget.target)
+            # transpose the launch errors in ToasterExceptions
+            for brerror in br.brerror_set.all():
+                LogMessage.objects.create(build = br.build, level = LogMessage.EXCEPTION, message = brerror.errmsg)
+
+            br.build.save()
         pass
 
 
lib/toaster/orm/models.py +25 -3
index 422f2bf..d97eadb 100644
@@ -201,16 +201,32 @@ class Project(models.Model):
                 commit = l.layercommit.get_vcs_reference()
                 print("ii Building layer ", l.layercommit.layer.name, " at vcs point ", commit)
                 BRLayer.objects.create(req = br, name = l.layercommit.layer.name, giturl = l.layercommit.layer.vcs_url, commit = commit, dirpath = l.layercommit.dirpath)
+
+            br.state = BuildRequest.REQ_QUEUED
+            now = timezone.now()
+            br.build = Build.objects.create(project = self,
+                                completed_on=now,
+                                started_on=now,
+                                )
             for t in self.projecttarget_set.all():
                 BRTarget.objects.create(req = br, target = t.target, task = t.task)
+                Target.objects.create(build = br.build, target = t.target)
+
             for v in self.projectvariable_set.all():
                 BRVariable.objects.create(req = br, name = v.name, value = v.value)
 
-            br.state = BuildRequest.REQ_QUEUED
+
+            try:
+                br.build.machine = self.projectvariable_set.get(name = 'MACHINE').value
+                br.build.save()
+            except ProjectVariable.DoesNotExist:
+                pass
             br.save()
         except Exception as e:
             br.delete()
-            raise e
+            import sys
+            et, ei, tb = sys.exc_info()
+            raise type(e), e, tb
         return br
 
 class Build(models.Model):
@@ -250,7 +266,6 @@ class Build(models.Model):
         return completeper
 
     def eta(self):
-        from django.utils import timezone
         eta = timezone.now()
         completeper = self.completeper()
         if self.completeper() > 0:
@@ -266,6 +281,12 @@ class Build(models.Model):
     def toaster_exceptions(self):
         return self.logmessage_set.filter(level=LogMessage.EXCEPTION)
 
+
+    def get_current_status(self):
+        if self.outcome == Build.IN_PROGRESS and self.build_name == "":
+            return "Queued"
+        return self.get_outcome_display()
+
     def __str__(self):
         return "%d %s %s" % (self.id, self.project, ",".join([t.target for t in self.target_set.all()]))
 
@@ -299,6 +320,7 @@ class Target(models.Model):
     search_allowed_fields = ['target', 'file_name']
     build = models.ForeignKey(Build)
     target = models.CharField(max_length=100)
+    task = models.CharField(max_length=100, null=True)
     is_image = models.BooleanField(default = False)
     image_size = models.IntegerField(default=0)
     license_manifest_path = models.CharField(max_length=500, null=True)
lib/toaster/toastergui/templates/project.html +11 -4
index 0f6a77b..1a8991f 100644
@@ -114,7 +114,7 @@ vim: expandtab tabstop=2
 
   <script type="text/ng-template" id="target_display">
       <div data-ng-switch on="t.task.length">
-        <div data-ng-switch-when="0">{[t.target]}</div>
+        <div data-ng-switch-when="undefined">{[t.target]}</div>
         <div data-ng-switch-default>{[t.target]}:{[t.task]}</div>
       </div>
   </script>
@@ -145,13 +145,13 @@ vim: expandtab tabstop=2
 
   <a id="buildslist"></a>
   <h2 class="air" data-ng-if="builds.length">Latest builds</h2>
-  <div class="animate-repeat alert"  data-ng-repeat="b in builds track by b.id" data-ng-class="{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.status]">
+  <div class="animate-repeat alert"  data-ng-repeat="b in builds track by b.id" data-ng-class="{'Queued':'alert-info', 'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.status]">
     <div class="row-fluid">
         <switch data-ng-switch="b.status">
 
           <case data-ng-switch-when="Failed">
             <div class="lead span3">
-              <a data-ng-class="{'succeeded': 'success', 'failed': 'error'}[b.status]" href="{[b.br_page_url]}">
+              <a data-ng-class="{'Succeeded': 'success', 'Failed': 'error'}[b.status]" href="{[b.br_page_url]}">
                 <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>
               </a>
             </div>
@@ -176,12 +176,19 @@ vim: expandtab tabstop=2
               <!-- we don't have warnings in this case -->
             </div>
             <div> <span class="lead">Build time: {[b.command_time|timediff]}</span>
-                <button class="btn pull-right" data-ng-class="{'succeeded':  'btn-success', 'failed': 'btn-danger'}[b.status]"
+                <button class="btn pull-right" data-ng-class="{'Succeeded':  'btn-success', 'Failed': 'btn-danger'}[b.status]"
                     data-ng-click="buildExistingTarget(b.targets)">Run again</button>
 
             </div>
           </case>
 
+          <case data-ng-switch-when="Queued">
+            <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>   </div>
+            <div class="span4 lead" >Build queued
+              <i title="This build will start as soon as a build server is available" class="icon-question-sign get-help get-help-blue heading-help" data-toggle="tooltip"></i>
+            </div>
+            <button class="btn pull-right btn-info" data-ng-click="buildCancel(b)">Cancel</button>
+          </case>
 
           <case data-ng-switch-when="In Progress">
             <switch data-ng-switch="b.build.length">
lib/toaster/toastergui/views.py +2 -2
index 0324d17..2336ae3 100755
@@ -74,8 +74,8 @@ def _project_recent_build_list(prj):
     for x in _get_latest_builds(prj):
         d = {
             "id":  x.pk,
-            "targets" : map(lambda y: {"target": y.target, "task": None }, x.target_set.all()), # TODO: create the task entry in the Target table
-            "status": x.get_outcome_display(),
+            "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.target_set.all()), # TODO: create the task entry in the Target table
+            "status": x.get_current_status(),
             "errors": map(lambda y: {"type": y.lineno, "msg": y.message, "tb": y.pathname}, x.logmessage_set.filter(level__gte=LogMessage.WARNING)),
             "updated": x.completed_on.strftime('%s')+"000",
             "command_time": (x.completed_on - x.started_on).total_seconds(),
Signature · 1 line
1.9.1
#9 lore raw

PATCH 9/23 toaster: fixes after replacing BuildRequest with Build

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This is a set of fixes that repair the interface after we switched from displaying BuildRequest data to Build data in the formerly "managed" mode.

---
 lib/bb/ui/toasterui.py                             |  24 +-
 lib/toaster/bldcontrol/localhostbecontroller.py    |   2 +-
 .../bldcontrol/management/commands/runbuilds.py    |   7 +-
 lib/toaster/bldcontrol/models.py                   |   3 +
 ...ect__chg_field_project_bitbake_version__chg_.py |   5 +-
 ...k__add_field_layer_version_local_path__del_f.py | 343 +++++++++++++++++++++
 lib/toaster/orm/models.py                          |   8 +-
 lib/toaster/toastergui/static/js/projectapp.js     |   4 +-
 lib/toaster/toastergui/templates/project.html      |   4 +-
 lib/toaster/toastergui/views.py                    |   6 +-
 10 files changed, 378 insertions(+), 28 deletions(-)
 create mode 100644 lib/toaster/orm/migrations/0022_auto__add_field_target_task__add_field_layer_version_local_path__del_f.py
lib/bb/ui/toasterui.py +10 -14
index 3054048..9c59fd0 100644
@@ -43,7 +43,7 @@ import xmlrpclib
 
 featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeatures.SEND_DEPENDS_TREE, bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING, bb.cooker.CookerFeatures.SEND_SANITYEVENTS]
 
-logger = logging.getLogger("BitBake")
+logger = logging.getLogger("ToasterLogger")
 interactive = sys.stdout.isatty()
 
 
@@ -66,7 +66,6 @@ def _log_settings_from_server(server):
 
 
 def main(server, eventHandler, params ):
-
     helper = uihelper.BBUIHelper()
 
     console = logging.StreamHandler(sys.stdout)
@@ -235,12 +234,18 @@ def main(server, eventHandler, params ):
             if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)):
                 continue
 
-            if isinstance(event, (bb.event.BuildCompleted)):
+            if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)):
+
+                if (isinstance(event, bb.command.CommandFailed)):
+                    errors += 1
+                    errorcode = 1
+                    logger.error("Command execution failed: %s", event.error)
+
                 # update the build info helper on BuildCompleted, not on CommandXXX
                 buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
                 buildinfohelper.close(errorcode)
                 # mark the log output; controllers may kill the toasterUI after seeing this log
-                logger.info("ToasterUI build done")
+                logger.info("ToasterUI build done 1, brbe: %s" % buildinfohelper.brbe )
 
                 # we start a new build info
                 if buildinfohelper.brbe is not None:
@@ -254,22 +259,13 @@ def main(server, eventHandler, params ):
                     taskfailures = []
                     buildinfohelper = BuildInfoHelper(server, build_history_enabled)
 
+                logger.info("ToasterUI build done 2")
                 continue
 
             if isinstance(event, (bb.command.CommandCompleted,
                                   bb.command.CommandFailed,
                                   bb.command.CommandExit)):
                 errorcode = 0
-                if (isinstance(event, bb.command.CommandFailed)):
-                    event.levelno = format.ERROR
-                    event.msg = "Command Failed " + event.error
-                    event.pathname = ""
-                    event.lineno = 0
-                    buildinfohelper.store_log_event(event)
-                    errors += 1
-                    errorcode = 1
-                    logger.error("Command execution failed: %s", event.error)
-
 
                 continue
 
lib/toaster/bldcontrol/localhostbecontroller.py +1 -1
index d0f8632..ad0a561 100644
@@ -322,7 +322,7 @@ class LocalhostBEController(BuildEnvironmentController):
     def triggerBuild(self, bitbake, layers, variables, targets):
         # set up the buid environment with the needed layers
         self.setLayers(bitbake, layers)
-        self.writeConfFile("conf/toaster-pre.conf", )
+        self.writeConfFile("conf/toaster-pre.conf", variables)
         self.writeConfFile("conf/toaster.conf", raw = "INHERIT+=\"toaster buildhistory\"")
 
         # get the bb server running with the build req id and build env id
lib/toaster/bldcontrol/management/commands/runbuilds.py +4 -3
index da7d4af..bcf3b04 100644
@@ -6,7 +6,7 @@ from bldcontrol.models import BuildRequest, BuildEnvironment, BRError, BRVariabl
 import os
 import logging
 
-logger = logging.getLogger("toaster")
+logger = logging.getLogger("ToasterScheduler")
 
 class Command(NoArgsCommand):
     args    = ""
@@ -35,7 +35,7 @@ class Command(NoArgsCommand):
                 # select the build environment and the request to build
                 br = self._selectBuildRequest()
             except IndexError as e:
-                # logger.debug("runbuilds: No build request")
+                #logger.debug("runbuilds: No build request")
                 return
             try:
                 bec = self._selectBuildEnvironment()
@@ -113,10 +113,11 @@ class Command(NoArgsCommand):
 
         # update all Builds that failed to start
 
-        for br in BuildRequest.objects.filter(state = BuildRequest.REQ_FAILED):
+        for br in BuildRequest.objects.filter(state = BuildRequest.REQ_FAILED, build__outcome = Build.IN_PROGRESS):
             br.build.outcome = Build.FAILED
             # transpose the launch errors in ToasterExceptions
             for brerror in br.brerror_set.all():
+                logger.debug("Saving error %s" % brerror)
                 LogMessage.objects.create(build = br.build, level = LogMessage.EXCEPTION, message = brerror.errmsg)
             br.build.save()
 
lib/toaster/bldcontrol/models.py +3 -0
index b789446..6f40866 100644
@@ -159,3 +159,6 @@ class BRError(models.Model):
     errtype     = models.CharField(max_length=100)
     errmsg      = models.TextField()
     traceback   = models.TextField()
+
+    def __str__(self):
+        return "%s (%s)" % (self.errmsg, self.req)
lib/toaster/orm/migrations/0021_auto__chg_field_build_project__chg_field_project_bitbake_version__chg_.py +3 -2
index b82cc8d..924a5c4 100644
@@ -105,7 +105,6 @@ class Migration(SchemaMigration):
             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'}),
@@ -124,6 +123,7 @@ class Migration(SchemaMigration):
             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'}),
+            'local_path': ('django.db.models.fields.FilePathField', [], {'default': "'/'", 'max_length': '1024'}),
             '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'}),
@@ -229,7 +229,7 @@ class Migration(SchemaMigration):
             'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
         },
         u'orm.recipe': {
-            'Meta': {'unique_together': "(('layer_version', 'file_path'),)", 'object_name': 'Recipe'},
+            'Meta': {'unique_together': "(('layer_version', 'file_path', 'pathflags'),)", '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'}),
@@ -239,6 +239,7 @@ class Migration(SchemaMigration):
             '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'}),
+            'pathflags': ('django.db.models.fields.CharField', [], {'max_length': '200', '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'}),
lib/toaster/orm/migrations/0022_auto__add_field_target_task__add_field_layer_version_local_path__del_f.py new file +343 -0

343 lines not on this page · raw message

lib/toaster/orm/models.py +6 -2
index d97eadb..e93629b 100644
@@ -283,8 +283,9 @@ class Build(models.Model):
 
 
     def get_current_status(self):
-        if self.outcome == Build.IN_PROGRESS and self.build_name == "":
-            return "Queued"
+        from bldcontrol.models import BuildRequest
+        if self.outcome == Build.IN_PROGRESS and self.buildrequest.state != BuildRequest.REQ_INPROGRESS:
+            return self.buildrequest.get_state_display()
         return self.get_outcome_display()
 
     def __str__(self):
@@ -1168,6 +1169,9 @@ class LogMessage(models.Model):
     pathname = models.FilePathField(max_length=255, blank=True)
     lineno = models.IntegerField(null=True)
 
+    def __str__(self):
+        return "%s %s %s" % (self.get_level_display(), self.message, self.build)
+
 def invalidate_cache(**kwargs):
     from django.core.cache import cache
     try:
lib/toaster/toastergui/static/js/projectapp.js +2 -2
index 40e2e1f..ea44bf3 100644
@@ -132,8 +132,8 @@ projectApp.filter('timediff', function() {
         var seconds = parseInt(input);
         var minutes = Math.floor(seconds / 60);
         seconds = seconds - minutes * 60;
-        var hours = Math.floor(seconds / 3600);
-        seconds = seconds - hours * 3600;
+        var hours = Math.floor(minutes / 60);
+        minutes = minutes - hours * 60;
         return pad(hours) + ":" + pad(minutes) + ":" + pad(seconds);
     };
 });
lib/toaster/toastergui/templates/project.html +2 -2
index 1a8991f..b5d97cb 100644
@@ -145,7 +145,7 @@ vim: expandtab tabstop=2
 
   <a id="buildslist"></a>
   <h2 class="air" data-ng-if="builds.length">Latest builds</h2>
-  <div class="animate-repeat alert"  data-ng-repeat="b in builds track by b.id" data-ng-class="{'Queued':'alert-info', 'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.status]">
+  <div class="animate-repeat alert"  data-ng-repeat="b in builds track by b.id" data-ng-class="{'queued':'alert-info', 'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.status]">
     <div class="row-fluid">
         <switch data-ng-switch="b.status">
 
@@ -182,7 +182,7 @@ vim: expandtab tabstop=2
             </div>
           </case>
 
-          <case data-ng-switch-when="Queued">
+          <case data-ng-switch-when="queued">
             <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span>   </div>
             <div class="span4 lead" >Build queued
               <i title="This build will start as soon as a build server is available" class="icon-question-sign get-help get-help-blue heading-help" data-toggle="tooltip"></i>
lib/toaster/toastergui/views.py +4 -2
index 2336ae3..00b1387 100755
@@ -64,7 +64,9 @@ def _get_latest_builds(prj=None):
     if prj is not None:
         queryset = queryset.filter(project = prj)
 
-    return itertools.chain(queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-pk")[:3], queryset.filter(outcome=Build.IN_PROGRESS).order_by("-pk"))
+    return itertools.chain(
+        queryset.filter(outcome=Build.IN_PROGRESS).order_by("-pk"),
+        queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-pk")[:3] )
 
 
 # a JSON-able dict of recent builds; for use in the Project page, xhr_ updates,  and other places, as needed
@@ -76,7 +78,7 @@ def _project_recent_build_list(prj):
             "id":  x.pk,
             "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.target_set.all()), # TODO: create the task entry in the Target table
             "status": x.get_current_status(),
-            "errors": map(lambda y: {"type": y.lineno, "msg": y.message, "tb": y.pathname}, x.logmessage_set.filter(level__gte=LogMessage.WARNING)),
+            "errors": map(lambda y: {"type": y.lineno, "msg": y.message, "tb": y.pathname}, (x.logmessage_set.filter(level__gte=LogMessage.WARNING)|x.logmessage_set.filter(level=LogMessage.EXCEPTION))),
             "updated": x.completed_on.strftime('%s')+"000",
             "command_time": (x.completed_on - x.started_on).total_seconds(),
             "br_page_url": reverse('buildrequestdetails', args=(x.project.id, x.pk) ),
Signature · 1 line
1.9.1
#10 lore raw

PATCH 10/23 toaster: add django-aggregate-if

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

Import library that provides conditional aggregates in Django. The tests are removed as they conflict with the Django startup.

The sources are
https://github.com/henriquebastos/django-aggregate-if

Licence is MIT

---
 .../contrib/django-aggregate-if-master/.gitignore  |  10 ++
 .../contrib/django-aggregate-if-master/.travis.yml |  50 ++++++
 .../contrib/django-aggregate-if-master/LICENSE     |  21 +++
 .../contrib/django-aggregate-if-master/README.rst  | 156 ++++++++++++++++
 .../django-aggregate-if-master/aggregate_if.py     | 164 +++++++++++++++++
 .../contrib/django-aggregate-if-master/runtests.py |  48 +++++
 .../contrib/django-aggregate-if-master/setup.py    |  33 ++++
 .../contrib/django-aggregate-if-master/tox.ini     | 198 +++++++++++++++++++++
 8 files changed, 680 insertions(+)
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/.gitignore
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/.travis.yml
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/LICENSE
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/README.rst
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/aggregate_if.py
 create mode 100755 lib/toaster/contrib/django-aggregate-if-master/runtests.py
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/setup.py
 create mode 100644 lib/toaster/contrib/django-aggregate-if-master/tox.ini
lib/toaster/contrib/django-aggregate-if-master/.gitignore new file +10 -0
new file mode 100644
index 0000000..c45652d
@@ -0,0 +1,10 @@
+*.pyc
+*.swp
+*.swo
+*.kpf
+*.egg-info/
+.idea
+.tox
+tmp/
+dist/
+.DS_Store
lib/toaster/contrib/django-aggregate-if-master/.travis.yml new file +50 -0

50 lines not on this page · raw message

lib/toaster/contrib/django-aggregate-if-master/LICENSE new file +21 -0
new file mode 100644
index 0000000..6b7c3b1
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2012 Henrique Bastos
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
lib/toaster/contrib/django-aggregate-if-master/README.rst new file +156 -0

156 lines not on this page · raw message

lib/toaster/contrib/django-aggregate-if-master/aggregate_if.py new file +164 -0

164 lines not on this page · raw message

lib/toaster/contrib/django-aggregate-if-master/runtests.py new file +48 -0

48 lines not on this page · raw message

lib/toaster/contrib/django-aggregate-if-master/setup.py new file +33 -0
new file mode 100644
index 0000000..aed3db1
@@ -0,0 +1,33 @@
+# coding: utf-8
+from setuptools import setup
+import os
+
+
+setup(name='django-aggregate-if',
+      version='0.5',
+      description='Conditional aggregates for Django, just like the famous SumIf in Excel.',
+      long_description=open(os.path.join(os.path.dirname(__file__), "README.rst")).read(),
+      author="Henrique Bastos", author_email="[email protected]",
+      license="MIT",
+      py_modules=['aggregate_if'],
+      install_requires=[
+          'six>=1.6.1',
+      ],
+      zip_safe=False,
+      platforms='any',
+      include_package_data=True,
+      classifiers=[
+          'Development Status :: 5 - Production/Stable',
+          'Framework :: Django',
+          'Intended Audience :: Developers',
+          'License :: OSI Approved :: MIT License',
+          'Natural Language :: English',
+          'Operating System :: OS Independent',
+          'Programming Language :: Python',
+          'Programming Language :: Python :: 2.7',
+          'Programming Language :: Python :: 3',
+          'Topic :: Database',
+          'Topic :: Software Development :: Libraries',
+      ],
+      url='http://github.com/henriquebastos/django-aggregate-if/',
+)
lib/toaster/contrib/django-aggregate-if-master/tox.ini new file +198 -0

198 lines not on this page · raw message

Signature · 1 line
1.9.1
#11 lore raw

PATCH 11/23 toaster: bring django-aggregate-if into the project

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

We bring the django-aggregate-if module (with minor changes to import) into the project.

---
 lib/toaster/contrib/django-aggregate-if-master/aggregate_if.py | 2 +-
 lib/toaster/toastermain/settings.py                            | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)
lib/toaster/contrib/django-aggregate-if-master/aggregate_if.py +1 -1
index 4ea9e8c..d5f3427 100644
@@ -10,7 +10,7 @@ This code was based on the work of others found on the internet:
 4. https://groups.google.com/forum/?fromgroups=#!topic/django-users/vVprMpsAnPo
 '''
 from __future__ import unicode_literals
-import six
+from django.utils import six
 import django
 from django.db.models.aggregates import Aggregate as DjangoAggregate
 from django.db.models.sql.aggregates import Aggregate as DjangoSqlAggregate
lib/toaster/toastermain/settings.py +9 -0
index 141ad08..60e80de 100644
@@ -393,3 +393,12 @@ class InvalidString(str):
             "Undefined variable or unknown value for: \"%s\"" % other)
 
 TEMPLATE_STRING_IF_INVALID = InvalidString("%s")
+
+import sys
+sys.path.append(
+    os.path.join(
+    os.path.join(
+        os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
+            "contrib"),
+            "django-aggregate-if-master")
+    )
Signature · 1 line
1.9.1
#12 lore raw

PATCH 12/23 toaster: refactor build model

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

We remove the "timespent", "errors_no" and "warnings_no" fields in favor of computing the needed values at runtime. This prevents inconsistencies in the UI.

Also removeing all references to BuildRequests from the interface - all build details now display in the build dashboard.

Minor fixes related to data logging.

---
 lib/bb/ui/buildinfohelper.py                       |  70 ++--
 lib/bb/ui/toasterui.py                             |   3 +
 lib/toaster/bldcontrol/localhostbecontroller.py    |   2 +-
 .../bldcontrol/management/commands/runbuilds.py    |  10 +-
 ...ings_no__del_field_build_errors_no__del_fiel.py | 353 +++++++++++++++++++++
 lib/toaster/orm/models.py                          |  19 +-
 .../toastergui/templates/builddashboard.html       |  23 +-
 lib/toaster/toastergui/templates/builds.html       |  22 +-
 .../toastergui/templates/configuration.html        |   6 -
 .../toastergui/templates/filtersnippet.html        |   2 +
 lib/toaster/toastergui/templates/landing.html      |  37 +--
 lib/toaster/toastergui/templates/mrb_section.html  |  29 +-
 .../toastergui/templates/package_detail_base.html  |   7 -
 .../toastergui/templates/projectbuilds.html        |  29 +-
 lib/toaster/toastergui/templates/projects.html     |   9 +-
 lib/toaster/toastergui/templates/recipe.html       |   9 +-
 lib/toaster/toastergui/templates/recipes.html      |   7 +-
 lib/toaster/toastergui/templates/runagain.html     |   7 -
 lib/toaster/toastergui/templates/target.html       |   5 -
 lib/toaster/toastergui/templates/task.html         |  36 +--
 lib/toaster/toastergui/templates/tasks.html        |   7 +-
 lib/toaster/toastergui/urls.py                     |   3 -
 lib/toaster/toastergui/views.py                    |  17 +-
 23 files changed, 503 insertions(+), 209 deletions(-)
 create mode 100644 lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py
 delete mode 100644 lib/toaster/toastergui/templates/runagain.html
lib/bb/ui/buildinfohelper.py +47 -23
index 8b63f70..63976b5 100644
@@ -16,7 +16,6 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-import datetime
 import sys
 import bb
 import re
@@ -24,6 +23,7 @@ import ast
 
 os.environ["DJANGO_SETTINGS_MODULE"] = "toaster.toastermain.settings"
 
+from django.utils import timezone
 import toaster.toastermain.settings as toaster_django_settings
 from toaster.orm.models import Build, Task, Recipe, Layer_Version, Layer, Target, LogMessage, HelpText
 from toaster.orm.models import Target_Image_File, BuildArtifact
@@ -41,7 +41,7 @@ import logging
 
 from django.db import transaction, connection
 
-logger = logging.getLogger("BitBake")
+logger = logging.getLogger("ToasterLogger")
 
 
 class NotExisting(Exception):
@@ -135,16 +135,18 @@ class ORMWrapper(object):
 
         if buildrequest is not None:
             build = buildrequest.build
-            build.machine=build_info['machine'],
-            build.distro=build_info['distro'],
-            build.distro_version=build_info['distro_version'],
-            build.completed_on=build_info['started_on'],
-            build.cooker_log_path=build_info['cooker_log_path'],
-            build.build_name=build_info['build_name'],
+            logger.info("Updating existing build, with %s" % build_info)
+            build.machine=build_info['machine']
+            build.distro=build_info['distro']
+            build.distro_version=build_info['distro_version']
+            started_on=build_info['started_on']
+            completed_on=build_info['started_on']
+            build.cooker_log_path=build_info['cooker_log_path']
+            build.build_name=build_info['build_name']
             build.bitbake_version=build_info['bitbake_version']
             build.save()
 
-            build.target_set.delete()
+            Target.objects.filter(build = build).delete()
 
         else:
             build = Build.objects.create(
@@ -188,10 +190,7 @@ class ORMWrapper(object):
         if errors or taskfailures:
             outcome = Build.FAILED
 
-        build.completed_on = datetime.datetime.now()
-        build.timespent = int((build.completed_on - build.started_on).total_seconds())
-        build.errors_no = errors
-        build.warnings_no = warnings
+        build.completed_on = timezone.now()
         build.outcome = outcome
         build.save()
 
@@ -687,8 +686,8 @@ class BuildInfoHelper(object):
         build_info['machine'] = self.server.runCommand(["getVariable", "MACHINE"])[0]
         build_info['distro'] = self.server.runCommand(["getVariable", "DISTRO"])[0]
         build_info['distro_version'] = self.server.runCommand(["getVariable", "DISTRO_VERSION"])[0]
-        build_info['started_on'] = datetime.datetime.now()
-        build_info['completed_on'] = datetime.datetime.now()
+        build_info['started_on'] = timezone.now()
+        build_info['completed_on'] = timezone.now()
         build_info['cooker_log_path'] = self.server.runCommand(["getVariable", "BB_CONSOLELOG"])[0]
         build_info['build_name'] = self.server.runCommand(["getVariable", "BUILDNAME"])[0]
         build_info['bitbake_version'] = self.server.runCommand(["getVariable", "BB_VERSION"])[0]
@@ -857,6 +856,30 @@ class BuildInfoHelper(object):
 
         # Save build configuration
         data = self.server.runCommand(["getAllKeysWithFlags", ["doc", "func"]])[0]
+
+        # convert the paths from absolute to relative to either the build directory or layer checkouts
+        path_prefixes = []
+
+        br_id, be_id = self.brbe.split(":")
+        from bldcontrol.models import BuildEnvironment, BuildRequest
+        be = BuildEnvironment.objects.get(pk = be_id)
+        path_prefixes.append(be.builddir)
+
+        for layer in sorted(self.orm_wrapper.layer_version_objects, key = lambda x:len(x.local_path), reverse=True):
+            path_prefixes.append(layer.local_path)
+
+        # we strip the prefixes
+        for k in data:
+            if not bool(data[k]['func']):
+                for vh in data[k]['history']:
+                    if not 'documentation.conf' in vh['file']:
+                        abs_file_name = vh['file']
+                        for pp in path_prefixes:
+                            if abs_file_name.startswith(pp + "/"):
+                                vh['file']=abs_file_name[len(pp + "/"):]
+                                break
+
+        # save the variables
         self.orm_wrapper.save_build_variables(build_obj, data)
 
         return self.brbe
@@ -1031,7 +1054,7 @@ class BuildInfoHelper(object):
             mevent.taskhash = taskhash
             task_information = self._get_task_information(mevent,recipe)
 
-            task_information['start_time'] = datetime.datetime.now()
+            task_information['start_time'] = timezone.now()
             task_information['outcome'] = Task.OUTCOME_NA
             task_information['sstate_checksum'] = taskhash
             task_information['sstate_result'] = Task.SSTATE_MISS
@@ -1206,6 +1229,7 @@ class BuildInfoHelper(object):
                             )
 
     def _store_build_done(self, errorcode):
+        logger.info("Build exited with errorcode %d", errorcode)
         br_id, be_id = self.brbe.split(":")
         from bldcontrol.models import BuildEnvironment, BuildRequest
         be = BuildEnvironment.objects.get(pk = be_id)
@@ -1225,7 +1249,7 @@ class BuildInfoHelper(object):
         mockevent.levelno = format.ERROR
         mockevent.msg = text
         mockevent.pathname = '-- None'
-        mockevent.lineno = -1
+        mockevent.lineno = LogMessage.ERROR
         self.store_log_event(mockevent)
 
     def store_log_exception(self, text, backtrace = ""):
@@ -1249,13 +1273,12 @@ class BuildInfoHelper(object):
                 if not 'backlog' in self.internal_state:
                     self.internal_state['backlog'] = []
                 self.internal_state['backlog'].append(event)
-            else:   # we're under Toaster control, post the errors to the build request
+                return
+            else:   # we're under Toaster control, the build is already created
                 from bldcontrol.models import BuildRequest, BRError
                 br, be = self.brbe.split(":")
                 buildrequest = BuildRequest.objects.get(pk = br)
-                brerror = BRError.objects.create(req = buildrequest, errtype="build", errmsg = event.msg)
-
-            return
+                self.internal_state['build'] = buildrequest.build
 
         if 'build' in self.internal_state and 'backlog' in self.internal_state:
             # if we have a backlog of events, do our best to save them here
@@ -1273,14 +1296,15 @@ 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
+        elif event.levelno == -2:   # toaster self-logging
+            log_information['level'] = -2
         else:
             log_information['level'] = LogMessage.INFO
 
         log_information['message'] = event.msg
         log_information['pathname'] = event.pathname
         log_information['lineno'] = event.lineno
+        logger.info("Logging error 2: %s" % log_information)
         self.orm_wrapper.create_logmessage(log_information)
 
     def close(self, errorcode):
lib/bb/ui/toasterui.py +3 -0
index 9c59fd0..28fdd82 100644
@@ -140,6 +140,9 @@ def main(server, eventHandler, params ):
                 continue
 
             if isinstance(event, logging.LogRecord):
+                if event.levelno == -1:
+                    event.levelno = format.ERROR
+
                 buildinfohelper.store_log_event(event)
                 if event.levelno >= format.ERROR:
                     errors = errors + 1
lib/toaster/bldcontrol/localhostbecontroller.py +1 -1
index ad0a561..3e16837 100644
@@ -113,7 +113,7 @@ class LocalhostBEController(BuildEnvironmentController):
         # 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:
+            with open(toaster_ui_log_filepath, "w") as f:
                 f.seek(0, 2)    # jump to the end
                 toaster_ui_log_filelength = f.tell()
 
lib/toaster/bldcontrol/management/commands/runbuilds.py +7 -3
index bcf3b04..33cc94e 100644
@@ -107,20 +107,24 @@ class Command(NoArgsCommand):
     def cleanup(self):
         from django.utils import timezone
         from datetime import timedelta
-        # DISABLED environments locked for more than 30 seconds - they should be unlocked
-        #BuildEnvironment.objects.filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
+        # environments locked for more than 30 seconds - they should be unlocked
+        BuildEnvironment.objects.filter(buildrequest__state__in=[BuildRequest.REQ_FAILED, BuildRequest.REQ_COMPLETED]).filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
 
 
         # update all Builds that failed to start
 
         for br in BuildRequest.objects.filter(state = BuildRequest.REQ_FAILED, build__outcome = Build.IN_PROGRESS):
-            br.build.outcome = Build.FAILED
             # transpose the launch errors in ToasterExceptions
+            br.build.outcome = Build.FAILED
             for brerror in br.brerror_set.all():
                 logger.debug("Saving error %s" % brerror)
                 LogMessage.objects.create(build = br.build, level = LogMessage.EXCEPTION, message = brerror.errmsg)
             br.build.save()
 
+            # we don't have a true build object here; hence, toasterui didn't have a change to release the BE lock
+            br.environment.lock = BuildEnvironment.LOCK_FREE
+            br.environment.save()
+
 
 
         # update all BuildRequests without a build created
lib/toaster/orm/migrations/0023_auto__del_field_build_warnings_no__del_field_build_errors_no__del_fiel.py new file +353 -0

354 lines not on this page · raw message

lib/toaster/orm/models.py +13 -6
index e93629b..077c94d 100644
@@ -147,7 +147,7 @@ class Project(models.Model):
         if (-1 == build_id):
             return( 0 )
         try:
-            return Build.objects.filter(id = build_id)[ 0 ].errors_no
+            return Build.objects.filter(id = build_id)[ 0 ].errors.count()
         except (Build.DoesNotExist,IndexError):
             return( "not_found" )
 
@@ -156,7 +156,7 @@ class Project(models.Model):
         if (-1 == build_id):
             return( 0 )
         try:
-            return Build.objects.filter(id = build_id)[ 0 ].warnings_no
+            return Build.objects.filter(id = build_id)[ 0 ].warnings.count()
         except (Build.DoesNotExist,IndexError):
             return( "not_found" )
 
@@ -248,10 +248,7 @@ class Build(models.Model):
     distro_version = models.CharField(max_length=100)
     started_on = models.DateTimeField()
     completed_on = models.DateTimeField()
-    timespent = models.IntegerField(default=0)
     outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS)
-    errors_no = models.IntegerField(default=0)
-    warnings_no = models.IntegerField(default=0)
     cooker_log_path = models.CharField(max_length=500)
     build_name = models.CharField(max_length=100)
     bitbake_version = models.CharField(max_length=50)
@@ -281,6 +278,17 @@ class Build(models.Model):
     def toaster_exceptions(self):
         return self.logmessage_set.filter(level=LogMessage.EXCEPTION)
 
+    @property
+    def errors(self):
+        return (self.logmessage_set.filter(level=LogMessage.ERROR)|self.logmessage_set.filter(level=LogMessage.EXCEPTION))
+
+    @property
+    def warnings(self):
+        return self.logmessage_set.filter(level=LogMessage.WARNING)
+
+    @property
+    def timespent_seconds(self):
+        return (self.completed_on - self.started_on).total_seconds()
 
     def get_current_status(self):
         from bldcontrol.models import BuildRequest
@@ -298,7 +306,6 @@ class BuildArtifact(models.Model):
     file_name = models.FilePathField()
     file_size = models.IntegerField()
 
-
     def get_local_file_name(self):
         try:
             deploydir = Variable.objects.get(build = self.build, variable_name="DEPLOY_DIR").variable_value
lib/toaster/toastergui/templates/builddashboard.html +12 -11
index 47b8d7a..bab8e38 100644
@@ -23,22 +23,23 @@
               </strong> on
             {{build.completed_on|date:"d/m/y H:i"}}
 </span>
-{% if  build.warnings_no or build.errors_no %}
+{% if  build.warnings.count or build.errors.count %}
 &nbsp;with
 {% endif %}
 {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
-{% if  build.errors_no %}
-     <span > <i class="icon-minus-sign red"></i><strong><a href="#errors" class="error show-errors"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span>
+{% if  build.errors.count %}
+     <span > <i class="icon-minus-sign red"></i><strong><a href="#errors" class="error show-errors"> {{build.errors.count}} error{{build.errors.count|pluralize}}</a></strong></span>
 {% endif %}
-{% if  build.warnings_no %}
-{% if  build.errors_no %}
+{% if  build.warnings.count %}
+{% if  build.errors.count %}
     and
 {% 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>
+    <span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning show-warnings"> {{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a></strong></span>
 {% endif %}
-            <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a>
+            <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent_seconds|sectohms }}</a>
             <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%else%}btn-danger{%endif%} pull-right log" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a>
             </span>
+
 {%endif%}
     </div>
     {% if build.toaster_exceptions.count > 0 %}
@@ -52,14 +53,14 @@
   </div>
 </div>
 
-{% if build.errors_no %}
+{% if build.errors.count %}
 <div class="accordion span10 pull-right" id="errors">
   <div class="accordion-group">
     <div class="accordion-heading">
             <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}}
+           {{build.errors.count}} error{{build.errors.count|pluralize}}
          </h2>
       </a>
     </div>
@@ -241,14 +242,14 @@
     </div>
 </div>
 
-{% if build.warnings_no %}
+{% if build.warnings.count %}
 <div class="accordion span10 pull-right" id="warnings">
   <div class="accordion-group">
     <div class="accordion-heading">
       <a class="accordion-toggle warning toggle-warnings">
         <h2 id="warning-toggle">
           <i class="icon-warning-sign"></i>
-          {{build.warnings_no}} warning{{build.warnings_no|pluralize}}
+          {{build.warnings.count}} warning{{build.warnings.count|pluralize}}
         </h2>
       </a>
     </div>
lib/toaster/toastergui/templates/builds.html +13 -9
index e9211af..00d1d4e 100644
@@ -46,7 +46,11 @@
     <div class="row-fluid">
       <div class="alert">
         <form class="no-results input-append" id="searchform">
-            <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+            <input id="search" name="search" class="input-xxlarge" type="text" value="
+            {% if request.GET.search %}
+                {{request.GET.search}}
+        {% endif %}"/>
+            {% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
             <button class="btn" type="submit" value="Search">Search</button>
             <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all builds</button>
         </form>
@@ -60,8 +64,8 @@
         {% 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> &nbsp;
-	    </td>
+        <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>
@@ -77,19 +81,19 @@
                         <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a>
                     {%endif%}
             </td>
-            <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>
+            <td class="errors.count">
+                {% if  build.errors.count %}
+                    <a class="errors.count error" href="{% url "builddashboard" build.id %}#errors">{{build.errors.count}} error{{build.errors.count|pluralize}}</a>
                 {%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>
-            <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td>
+            <td class="warnings.count">{% if  build.warnings.count %}<a class="warnings.count warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a>{%endif%}</td>
+            <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent_seconds|sectohms}}</a></td>
             <td class="output">
               {% if build.outcome == build.SUCCEEDED %}
               <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
               {% endif %}
             </td>
-	    <td>
+        <td>
                 <a href="{% url 'project' build.project.id %}">{{build.project.name}}</a>
             </td>
         </tr>
lib/toaster/toastergui/templates/configuration.html +0 -6
index 2aa1ae1..3e48991 100644
@@ -50,9 +50,6 @@
           <th>Layer</th>
           <th>Layer branch</th>
           <th>Layer commit</th>
-          {% if not MANAGED or not build.project %}
-              <th>Layer directory</th>
-          {% endif %}
         </tr>
       </thead>
       <tbody>{% for lv in build.layer_version_build.all|dictsort:"layer.name" %}
@@ -63,9 +60,6 @@
                 <li>{{lv.commit}}</li> </ul>">
                     {{lv.commit|truncatechars:13}}
                 </a></td>
-          {% if not MANAGED or not build.project %}
-            <td>{{lv.local_path}}</td>
-          {% endif %}
         </tr>{% endfor %}
       </tbody>
     </table>
lib/toaster/toastergui/templates/filtersnippet.html +2 -0
index 56e2b21..1101aa8 100644
@@ -40,8 +40,10 @@
                 {% endif %}
             {% endfor %}
         <!-- daterange persistence -->
+        {% if last_date_from and last_date_to %}
         <input type="hidden" id="last_date_from_{{key}}" name="last_date_from" value="{{last_date_from}}"/>
         <input type="hidden" id="last_date_to_{{key}}" name="last_date_to"   value="{{last_date_to}}"/>
+        {% endif %}
         </div>
         <div class="modal-footer">
             <button type="submit" class="btn btn-primary" data-key="{{key}}">Apply</button>
lib/toaster/toastergui/templates/landing.html +2 -35
index 4af849c..15cac47 100644
@@ -9,7 +9,7 @@
   <div class="container-fluid">
    <div class="row-fluid">
     <!-- Empty - no data in database -->
-    <div class="hero-unit span12 {%if MANAGED%}well-transparent{%endif%}">
+    <div class="hero-unit span12 well-transparent">
      <div class="row-fluid">
       <div class="span6">
        <h1>
@@ -17,7 +17,6 @@
        </h1>
        <p>A web interface to <a href="http://www.openembedded.org">OpenEmbedded</a> and <a href="http://www.yoctoproject.org/tools-resources/projects/bitbake">BitBake</a>, the <a href="http://www.yoctoproject.org">Yocto Project</a> build system.</p>
 
-	{% if MANAGED %}
 
 		{% if lvs_nos %}
 		    <p class="hero-actions">
@@ -37,7 +36,7 @@
 			        </li>
 			    </ul>
 		    </div>
-        {% endif %}
+	        {% endif %}
 
         <ul class="unstyled">
             <li>
@@ -48,18 +47,6 @@
             </li>
         </ul>
 
-        {% else %}
-
-        <p class="hero-actions">
-            <a class="btn btn-primary btn-large" href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html">
-                Show me the manual
-            </a>
-            <a class="btn btn-large" href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster">
-                I want to contribute
-	        </a>
-	    </p>
-
-	    {% endif %}
       </div>
       <div class="span6">
         {% if MANAGED %}
@@ -70,26 +57,6 @@
       </div>
      </div>
     </div>
-
-   {% if not MANAGED %}
-    <!-- Empty - no data in database -->
-    <div class="page-header top-air">
-     <h1>
-      All builds
-     </h1>
-    </div>
-    <div class="alert alert-info lead">
-     Toaster has not recorded any builds yet. Go build something with
-     <a href="http://www.yoctoproject.org/docs/current/yocto-project-qs/yocto-project-qs.html#test-run">
-      Knotty
-     </a>
-     or
-     <a href="https://www.yoctoproject.org/documentation/hob-manual">
-      Hob
-     </a>
-    </div>
-   {% endif %}
-
    </div>
 
 {% endblock %}
lib/toaster/toastergui/templates/mrb_section.html +23 -6
index 7e84e41..d37b694 100644
@@ -43,19 +43,35 @@
             </div>
     {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
             <div class="span2 lead">
-      {% if  build.errors_no %}
-                <i class="icon-minus-sign red"></i> <a href="{%url 'builddashboard' build.pk%}#errors" class="error">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>
+      {% if  build.errors.count %}
+                <i class="icon-minus-sign red"></i> <a href="{%url 'builddashboard' build.pk%}#errors" class="error">{{build.errors.count}} error{{build.errors.count|pluralize}}</a>
       {% endif %}
             </div>
             <div class="span2 lead">
-      {% if  build.warnings_no %}
-                <i class="icon-warning-sign yellow"></i> <a href="{%url 'builddashboard' build.pk%}#warnings" class="warning">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>
+      {% if  build.warnings.count %}
+                <i class="icon-warning-sign yellow"></i> <a href="{%url 'builddashboard' build.pk%}#warnings" class="warning">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a>
       {% endif %}
             </div>
             <div class="lead ">
-              <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 class="lead">
+                Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent_seconds|sectohms }}</a>
               </span>
+              <button 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 'projectbuilds' build.project.id as bpi %}{{bpi|json}},
+                    {{build.project.name|json}},
+                    {% url 'project' build.project.id as bpurl %}{{bpurl|json}},
+                    {{build.target_set.all|get_tasks|json}})'>
+
+                    Run again
+              </button>
             </div>
     {%endif%}
     {%if build.outcome == build.IN_PROGRESS %}
@@ -77,6 +93,7 @@
 function scheduleBuild(url, projectName, projectUrl, buildlist) {
   console.log("scheduleBuild");
   libtoaster.startABuild(url, null, buildlist.join(" "), function(){
+    console.log("reloading page");
     window.location.reload();
   }, null);
 }
lib/toaster/toastergui/templates/package_detail_base.html +0 -7
index e2ec75d..a24bc8e 100644
@@ -136,13 +136,6 @@
 
             <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd>
 
-          {% if not MANAGED or not build.project %}
-            <dt>
-                Layer directory
-                <i class="icon-question-sign get-help" title="Path to the layer providing the recipe that builds this package"></i>
-            </dt>
-            <dd><code>{{package.recipe.layer_version.local_path}}</code></dd>
-          {% endif %}
         </dl>
     </div> <!-- row4 well -->
     {% endblock twocolumns %}
lib/toaster/toastergui/templates/projectbuilds.html +12 -17
index 896c3b5..ac87d8c 100644
@@ -79,25 +79,20 @@
                 {% query build.task_build outcome=4 order__gt=0 as exectask%}
                     {% if exectask.count == 1 %}
                         <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a>
-                      {% if MANAGED and build.project %}
                         <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}">
                             <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
                         </a>
-                      {% endif %}
                     {% elif exectask.count > 1%}
                         <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a>
                     {%endif%}
             </td>
-            <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>
+            <td class="errors.count">
+                {% if  build.errors.count %}
+                    <a class="errors.count error" href="{% url "builddashboard" build.id %}#errors">{{build.errors.count}} error{{build.errors.count|pluralize}}</a>
                 {%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>
-            <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td>
-            {% if not MANAGED or not build.project %}
-                <td class="log">{{build.cooker_log_path}}</td>
-            {% endif %}
+            <td class="warnings.count">{% if  build.warnings.count %}<a class="warnings.count warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a>{%endif%}</td>
+            <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent_seconds|sectohms}}</a></td>
             <td class="output">
               {% if build.outcome == build.SUCCEEDED %}
               <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
@@ -113,23 +108,23 @@
         <tr class="data">
             <td class="outcome">{% if br.state == br.REQ_FAILED %}<i class="icon-minus-sign error"></i>{%else%}FIXME_build_request_state{%endif%}</td>
             <td class="target">
-                <a href="{% url "buildrequestdetails" br.project.id br.id %}"><span data-toggle="tooltip" {%if br.brtarget_set.all.count > 1%}title="Targets: {%for target in br.brtarget_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{br.brtarget_set.all.0.target}} {%if br.brtarget_set.all.count > 1%}(+ {{br.brtarget_set.all.count|add:"-1"}}){%endif%} </span></a>
+                <a href="{% url "builddashboard" br.id %}"><span data-toggle="tooltip" {%if br.brtarget_set.all.count > 1%}title="Targets: {%for target in br.brtarget_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{br.brtarget_set.all.0.target}} {%if br.brtarget_set.all.count > 1%}(+ {{br.brtarget_set.all.count|add:"-1"}}){%endif%} </span></a>
             </td>
             <td class="machine">
-                <a href="{% url "buildrequestdetails" br.project.id br.id %}">{{br.machine}}</a>
+                <a href="{% url "builddashboard" br.id %}">{{br.machine}}</a>
             </td>
             <td class="started_on">
-                <a href="{% url "buildrequestdetails" br.project.id br.id %}">{{br.created|date:"d/m/y H:i"}}</a>
+                <a href="{% url "builddashboard" br.id %}">{{br.created|date:"d/m/y H:i"}}</a>
             </td>
             <td class="completed_on">
-                <a href="{% url "buildrequestdetails" br.project.id br.id %}">{{br.updated|date:"d/m/y H:i"}}</a>
+                <a href="{% url "builddashboard" br.id %}">{{br.updated|date:"d/m/y H:i"}}</a>
             </td>
             <td class="failed_tasks error">
             </td>
-            <td class="errors_no">
-        <a class="errors_no error" href="{% url "buildrequestdetails" br.project.id br.id %}#errors">{{br.brerror_set.all.count}} error{{br.brerror_set.all.count|pluralize}}</a>
+            <td class="errors.count">
+        <a class="errors.count error" href="{% url "builddashboard" br.id %}#errors">{{br.brerror_set.all.count}} error{{br.brerror_set.all.count|pluralize}}</a>
             </td>
-            <td class="warnings_no">
+            <td class="warnings.count">
             </td>
             <td class="time">
                 {{br.timespent.total_seconds|sectohms}}
lib/toaster/toastergui/templates/projects.html +6 -3
index 9c4346c..e651953 100644
@@ -26,7 +26,10 @@
     <div class="row-fluid">
       <div class="alert">
         <form class="no-results input-append" id="searchform">
-            <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+            <input id="search" name="search" class="input-xxlarge" type="text" value="
+                {% if request.GET.search %}
+                    {{request.GET.search}}
+                {% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
             <button class="btn" type="submit" value="Search">Search</button>
             <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all projects</button>
         </form>
@@ -58,8 +61,8 @@
       <td><a href="{% url 'projectbuilds' o.id %}">{{o.get_number_of_builds}}</a></td>
       <td class="loutcome"><a href="{% url "builddashboard" o.get_last_build_id %}">{%if o.get_last_outcome == build_SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif o.get_last_outcome == build_FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td>
       <td class="ltarget"><a href="{% url "builddashboard" o.get_last_build_id %}">{{o.get_last_target}} </a></td>
-      <td class="lerrors">{% if o.get_last_errors %}<a class="errors_no error" href="{% url "builddashboard" o.get_last_build_id %}#errors">{{o.get_last_errors}} error{{o.get_last_errors|pluralize}}</a>{%endif%}</td>
-      <td class="lwarnings">{% if o.get_last_warnings %}<a class="warnings_no warning" href="{% url "builddashboard" o.get_last_build_id %}#warnings">{{o.get_last_warnings}} warning{{o.get_last_warnings|pluralize}}</a>{%endif%}</td>
+      <td class="lerrors">{% if o.get_last_errors %}<a class="errors.count error" href="{% url "builddashboard" o.get_last_build_id %}#errors">{{o.get_last_errors}} error{{o.get_last_errors|pluralize}}</a>{%endif%}</td>
+      <td class="lwarnings">{% if o.get_last_warnings %}<a class="warnings.count warning" href="{% url "builddashboard" o.get_last_build_id %}#warnings">{{o.get_last_warnings}} warning{{o.get_last_warnings|pluralize}}</a>{%endif%}</td>
       <td class="limagefiles">
         {% if o.get_last_outcome == build_SUCCEEDED %}
         <a href="{%url "builddashboard" o.get_last_build_id %}#images">{{fstypes|get_dict_value:o.id}}</a>
lib/toaster/toastergui/templates/recipe.html +1 -8
index dd8753d..b5e4192 100644
@@ -53,13 +53,6 @@
                 </dt>
                 <dd>{{layer.name}}</dd>
 
-          {% if not MANAGED or not build.project %}
-                <dt>
-                    <i class="icon-question-sign get-help" title="Path to the layer providing the recipe"></i>
-                    Layer directory
-                </dt>
-                <dd><code>{{object.layer_version.local_path}}</code></dd>
-          {% endif %}
                 <dt>
                     <i class="icon-question-sign get-help" title="Path to the recipe .bb file"></i>
                     Recipe file
@@ -126,7 +119,7 @@
 
                     <td>
                         <a {{ task|task_color }} href="{% url "task" build.pk task.pk %}">{{task.get_outcome_display}} </a>
-                        {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %}
+                        {% if task.outcome = task.OUTCOME_FAILED %}
                             <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
                                 <i class="icon-download-alt" title="Download task log file"></i>
                             </a>
lib/toaster/toastergui/templates/recipes.html +1 -6
index 8d4494e..5cdac43 100644
@@ -28,7 +28,7 @@
   <div class="row-fluid">
       <div class="alert">
         <form class="no-results input-append" id="searchform">
-            <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+            <input id="search" name="search" class="input-xxlarge" type="text" value="{%if request.GET.search%}{{request.GET.search}}{%endif%}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
             <button class="btn" type="submit" value="Search">Search</button>
             <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all recipes</button>
         </form>
@@ -102,11 +102,6 @@
                 {{recipe.layer_version.commit|truncatechars:13}}
             </a>
         </td>
-
-        {% if not MANAGED or not build.project %}
-            <!-- Layer directory -->
-            <td class="layer_version__local_path">{{recipe.layer_version.local_path}}</td>
-        {% endif %}
     </tr>
 
     {% endfor %}
lib/toaster/toastergui/templates/runagain.html deleted +0 -7
deleted file mode 100644
index b4ba5fb..0000000
@@ -1,7 +0,0 @@
-{% load projecttags %}
-onclick='scheduleBuild(
-    {% url 'projectbuilds' buildrequest.project.id as bpi %}{{bpi|json}},
-    {{buildrequest.project.name|json}},
-    {% url 'project' buildrequest.project.id as bpurl %}{{bpurl|json}},
-    {{buildrequest.brtarget_set.all|get_tasks|json}})
-'>Run again
lib/toaster/toastergui/templates/target.html +0 -5
index e7febaf..fa59f4e 100644
@@ -152,11 +152,6 @@
                 {{package.recipe.layer_version.commit|truncatechars:13}}
             </a>
         </td>
-        {% if not MANAGED or not build.project %}
-            <td class="layer_directory">
-                {{ package.recipe.layer_version.local_path }}
-            </td>
-        {% endif %}
     </tr>
     {% endfor %}
 
lib/toaster/toastergui/templates/task.html +1 -35
index 6e06ddf..635098a 100644
@@ -23,18 +23,7 @@
 {%if task.task_executed %}
     {# executed tasks outcome #}
     {% if task.logfile %}
-      {% if MANAGED and build.project %}
             <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download task log</a>
-      {% else %}
-       <dl class="dl-horizontal">
-        <dt>
-            <i class="icon-question-sign get-help" title="Path the task log file"></i> Log file
-        </dt>
-        <dd>
-             <code>{{task.logfile}}</code>
-        </dd>
-       </dl>
-      {% endif %}
     {% endif %}
         {# show stack trace for failed task #}
         {% if task.outcome == task.OUTCOME_FAILED and log_head %}
@@ -130,22 +119,12 @@
             </dd>
         </dl>
     {%elif task.outcome == task.OUTCOME_CACHED%}
-        {% if MANAGED and build.project %}
             {% for t in task.get_related_setscene %}
                 {% if forloop.last %}
                     <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" t.pk %}" style="margin:15px;">Download task log</a>
                 {% endif %}
             {% endfor %}
-        {% else %}
-        <dl class="dl-horizontal">
-            <dt>
-                <i class="icon-question-sign get-help" title="Path the task log file"></i> Log file
-            </dt>
-            <dd>
-                <code>{% for t in task.get_related_setscene %} {{t.logfile}} {% endfor %}</code>
-            </dd>
-        </dl>
-        {% endif %}
+
     {%elif task.outcome == task.OUTCOME_EMPTY%}
         <div class="alert alert-info details">
             This task is empty because it has the <code>noexec</code> flag set to <code>1</code>, or the task function is empty
@@ -200,20 +179,7 @@
             <strong>Failed</strong> to restore output from sstate cache. The file was found but could not be unpacked.
         </div>
         <dl class="dl-horizontal">
-          {% if MANAGED and build.project %}
             <a href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download log</a>
-          {% else %}
-            <dt>
-                <i class="icon-question-sign get-help" title="Path to the cache attempt log file"></i>
-                Log file
-            </dt>
-            <dd><code>{{task.logfile}}</code></dd>
-            <dt>
-                <i class="icon-question-sign get-help" title="How long it took the cache attempt to finish in seconds"></i>
-                Time (secs)
-            </dt>
-            <dd>{{task.elapsed_time|format_none_and_zero}}</dd>
-          {% endif %}
         </dl>
         <div class="alert alert-info">
             Running the real task instead.
lib/toaster/toastergui/templates/tasks.html +1 -6
index 32c0552..b18b5c7 100644
@@ -93,7 +93,7 @@
             </td>
             <td class="outcome">
                 <a href="{%url "task" build.pk task.pk%}">{{task.get_outcome_display}} </a>
-                {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %}
+                {% if task.outcome = task.OUTCOME_FAILED %}
                     <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
                         <i class="icon-download-alt" title="Download task log file"></i>
                     </a>
@@ -113,11 +113,6 @@
                 {{task.disk_io|format_none_and_zero}}
             </td>
 
-        {% if not MANAGED or not build.project %}
-            <td class="task_log">
-                {{task.logfile}}
-            </td>
-        {% endif %}
         </tr>
     {% endfor %}
 
lib/toaster/toastergui/urls.py +0 -3
index 681f067..feb1513 100644
@@ -131,9 +131,6 @@ urlpatterns = patterns('toastergui.views',
         url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'),
         url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'),
 
-        # dashboard for failed build requests
-        url(r'^project/(?P<pid>\d+)/buildrequest/(?P<bid>\d+)$', 'buildrequestdetails', name='buildrequestdetails'),
-
         # default redirection
         url(r'^$', RedirectView.as_view( url= 'landing')),
 )
lib/toaster/toastergui/views.py +5 -12
index 00b1387..8c6f9fa 100755
@@ -21,7 +21,7 @@
 
 import operator,re
 
-from django.db.models import Q, Sum, Count, Max
+from django.db.models import F, Q, Sum, Count, Max
 from django.db import IntegrityError
 from django.shortcuts import render, redirect
 from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
@@ -81,15 +81,15 @@ def _project_recent_build_list(prj):
             "errors": map(lambda y: {"type": y.lineno, "msg": y.message, "tb": y.pathname}, (x.logmessage_set.filter(level__gte=LogMessage.WARNING)|x.logmessage_set.filter(level=LogMessage.EXCEPTION))),
             "updated": x.completed_on.strftime('%s')+"000",
             "command_time": (x.completed_on - x.started_on).total_seconds(),
-            "br_page_url": reverse('buildrequestdetails', args=(x.project.id, x.pk) ),
+            "br_page_url": reverse('builddashboard', args=(x.pk,) ),
             "build" : map( lambda y: {"id": y.pk,
                         "status": y.get_outcome_display(),
                         "completed_on" : y.completed_on.strftime('%s')+"000",
                         "build_time" : (y.completed_on - y.started_on).total_seconds(),
                         "build_page_url" : reverse('builddashboard', args=(y.pk,)),
                         'build_time_page_url': reverse('buildtime', args=(y.pk,)),
-                        "errors": y.errors_no,
-                        "warnings": y.warnings_no,
+                        "errors": y.errors.count(),
+                        "warnings": y.warnings.count(),
                         "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",
                         }, [x]),
@@ -1906,7 +1906,7 @@ if True:
         (filter_string, search_term, ordering_string) = _search_tuple(request, Build)
         # post-process any date range filters
         filter_string,daterange_selected = _modify_date_range_filter(filter_string)
-        queryset_all = queryset_all.select_related("project")
+        queryset_all = queryset_all.select_related("project").annotate(errors_no = Count('logmessage', only=Q(logmessage__level=LogMessage.ERROR)|Q(logmessage__level=LogMessage.EXCEPTION))).annotate(warnings_no = Count('logmessage', only=Q(logmessage__level=LogMessage.WARNING))).extra(select={'timespent':'completed_on - started_on'})
         queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on')
         queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on')
 
@@ -2841,10 +2841,3 @@ if True:
 
         _set_parameters_values(pagesize, orderby, request)
         return context
-
-    @_template_renderer("buildrequestdetails.html")
-    def buildrequestdetails(request, pid, bid):
-        context = {
-            'buildrequest' : Build.objects.get(pk = bid, project_id = pid).buildrequest
-        }
-        return context
Signature · 1 line
1.9.1
#13 lore raw

PATCH 13/23 toastergui: select project types

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This brings in project types in the New Project page.

The "analisys" projects are the projects with no "release" set, and have read-only properties in the project page.

---
 lib/toaster/orm/models.py                        |  8 +-
 lib/toaster/toastergui/templates/newproject.html | 99 +++++++++++++++---------
 lib/toaster/toastergui/views.py                  | 11 ++-
 3 files changed, 80 insertions(+), 38 deletions(-)
lib/toaster/orm/models.py +7 -1
index 077c94d..8488aa4 100644
@@ -57,7 +57,11 @@ class ToasterSetting(models.Model):
 
 class ProjectManager(models.Manager):
     def create_project(self, name, release):
-        prj = self.model(name = name, bitbake_version = release.bitbake_version, release = release)
+        if release is not None:
+            prj = self.model(name = name, bitbake_version = release.bitbake_version, release = release)
+        else:
+            prj = self.model(name = name, bitbake_version = None, release = None)
+
         prj.save()
 
         for defaultconf in ToasterSetting.objects.filter(name__startswith="DEFCONF_"):
@@ -66,6 +70,8 @@ class ProjectManager(models.Manager):
                 name = name,
                 value = defaultconf.value)
 
+        if release is None:
+            return prj
 
         for rdl in release.releasedefaultlayer_set.all():
             try:
lib/toaster/toastergui/templates/newproject.html +64 -35

130 lines not on this page · raw message

lib/toaster/toastergui/views.py +9 -2
index 8c6f9fa..1a504b8 100755
@@ -2104,8 +2104,11 @@ if True:
             # render new project page
             return render(request, template, context)
         elif request.method == "POST":
-            mandatory_fields = ['projectname', 'projectversion']
+            mandatory_fields = ['projectname', 'ptype']
             try:
+                ptype = request.POST.get('ptype')
+                if ptype == "build":
+                    mandatory_fields.append('projectversion')
                 # make sure we have values for all mandatory_fields
                 if reduce( lambda x, y: x or y, map(lambda x: len(request.POST.get(x, '')) == 0, mandatory_fields)):
                 # set alert for missing fields
@@ -2121,7 +2124,11 @@ if True:
                     login(request, user)
 
                 #  save the project
-                prj = Project.objects.create_project(name = request.POST['projectname'], release = Release.objects.get(pk = request.POST['projectversion']))
+                release = Release.objects.get(pk = request.POST.get('projectversion', None ))
+                if ptype == "analysis":
+                    release = None
+
+                prj = Project.objects.create_project(name = request.POST['projectname'], release = release)
                 prj.user_id = request.user.pk
                 prj.save()
                 return redirect(reverse(project, args=(prj.pk,)) + "#/newproject")
Signature · 1 line
1.9.1
#14 lore raw

PATCH 14/23 toaster: delete multiple builds

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This patch fixes the build deletion on unmigrated databases, and enhances it to delete multiple builds in a single run.

[YOCTO #7726]

---
 lib/toaster/toastergui/views.py                    |  4 +-
 .../toastermain/management/commands/builddelete.py | 56 ++++++++++++++--------
 2 files changed, 38 insertions(+), 22 deletions(-)
lib/toaster/toastergui/views.py +2 -2
index 1a504b8..ec65903 100755
@@ -64,9 +64,9 @@ def _get_latest_builds(prj=None):
     if prj is not None:
         queryset = queryset.filter(project = prj)
 
-    return itertools.chain(
+    return list(itertools.chain(
         queryset.filter(outcome=Build.IN_PROGRESS).order_by("-pk"),
-        queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-pk")[:3] )
+        queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-pk")[:3] ))
 
 
 # a JSON-able dict of recent builds; for use in the Project page, xhr_ updates,  and other places, as needed
lib/toaster/toastermain/management/commands/builddelete.py +36 -20

69 lines not on this page · raw message

Signature · 1 line
1.9.1
#15 lore raw

PATCH 15/23 toasterui: verify variable before usage

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This patch verifies that BRBE is set before trying to use it to read the checkout paths. This is needed for builds ran outside Toaster control.

---
 lib/bb/ui/buildinfohelper.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
lib/bb/ui/buildinfohelper.py +5 -4
index 63976b5..cce6da5 100644
@@ -860,10 +860,11 @@ class BuildInfoHelper(object):
         # convert the paths from absolute to relative to either the build directory or layer checkouts
         path_prefixes = []
 
-        br_id, be_id = self.brbe.split(":")
-        from bldcontrol.models import BuildEnvironment, BuildRequest
-        be = BuildEnvironment.objects.get(pk = be_id)
-        path_prefixes.append(be.builddir)
+        if self.brbe is not None:
+            br_id, be_id = self.brbe.split(":")
+            from bldcontrol.models import BuildEnvironment, BuildRequest
+            be = BuildEnvironment.objects.get(pk = be_id)
+            path_prefixes.append(be.builddir)
 
         for layer in sorted(self.orm_wrapper.layer_version_objects, key = lambda x:len(x.local_path), reverse=True):
             path_prefixes.append(layer.local_path)
Signature · 1 line
1.9.1
#16 lore raw

PATCH 16/23 toasterui: fixes after html5 compliance testing

In reply to Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This patch brings fixes for issues highlighted by
HTML5 compliance testing.

---
 lib/toaster/orm/models.py                                 |  4 +++-
 lib/toaster/toastergui/static/js/base.js                  |  2 +-
 lib/toaster/toastergui/templates/configvars.html          |  2 +-
 .../toastergui/templates/detail_search_header.html        |  2 +-
 .../toastergui/templates/detail_sorted_header.html        |  2 +-
 .../toastergui/templates/generic-toastertable-page.html   |  2 ++
 lib/toaster/toastergui/templates/importlayer.html         | 15 +++++++++++++--
 lib/toaster/toastergui/templates/target.html              |  2 +-
 lib/toaster/toastergui/templates/toastertable-simple.html |  4 ++--
 lib/toaster/toastergui/templates/toastertable.html        |  4 ++--
 lib/toaster/toastergui/views.py                           | 11 ++++++-----
 11 files changed, 33 insertions(+), 17 deletions(-)
lib/toaster/orm/models.py +3 -1
index 8488aa4..7e8ab16 100644
@@ -180,7 +180,9 @@ class Project(models.Model):
         if release == None:
             release = self.release
         # layers on the same branch or layers specifically set for this project
-        queryset = Layer_Version.objects.filter((Q(up_branch__name = release.branch_name) & Q(project = None)) | Q(project = self) | Q(build__project = self))
+        queryset = Layer_Version.objects.filter(Q(project = self) | Q(build__project = self))
+        if release is not None:
+            queryset = queryset.filter(Q(up_branch__name = release.branch_name) & Q(project = None))
         if layer_name is not None:
             # we select only a layer name
             queryset = queryset.filter(layer__name = layer_name)
lib/toaster/toastergui/static/js/base.js +1 -1
index d079f23..f1711c1 100644
@@ -39,7 +39,7 @@ function basePageInit(ctx) {
 
     libtoaster.getProjectInfo(selectedProject.projectPageUrl,
       function (data) {
-        if (data.machine.name === undefined || data.layers.length === 0) {
+        if (data.machine === null || data.machine.name === undefined || data.layers.length === 0) {
           /* we can't build anything with out a machine and some layers */
           $("#new-build-button #targets-form").hide();
           $("#new-build-button .alert").show();
lib/toaster/toastergui/templates/configvars.html +1 -1
index 8957673..8a572ae 100644
@@ -39,7 +39,7 @@
   <div class="row-fluid">
       <div class="alert">
         <form class="no-results input-append" id="searchform">
-            <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+            <input id="search" name="search" class="input-xxlarge" type="text" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
             <button class="btn" type="submit" value="Search">Search</button>
             <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all variables</button>
         </form>
lib/toaster/toastergui/templates/detail_search_header.html +1 -1
index ca8e158..7bea3f4 100644
@@ -28,7 +28,7 @@ $(document).ready(function() {
     <form id="searchform" class="navbar-search input-append pull-left">
   {% endif %}
 
-      <input id="search" class="input-xlarge" type="text" placeholder="Search {{search_what}}" name="search" value="{{request.GET.search}}">
+      <input id="search" class="input-xlarge" type="text" placeholder="Search {{search_what}}" name="search" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}">
       <input type="hidden" value="name:+" name="orderby">
       <input type="hidden" value="l" name="page">
   {% if request.GET.search %}
lib/toaster/toastergui/templates/detail_sorted_header.html +1 -1
index 5214444..6ce292e 100644
@@ -9,7 +9,7 @@
     <thead>
         <!-- Table header row; generated from "tablecols" entry in the context dict -->
         <tr>
-            {% for tc in tablecols %}<th class="{{tc.dclass}} {{tc.clclass}}">
+            {% for tc in tablecols %}<th class="{%if tc.dclass%}{{tc.dclass}}{% endif %} {%if tc.class %}{{tc.clclass}}{% endif %}">
                 {%if tc.qhelp%}<i class="icon-question-sign get-help" title="{{tc.qhelp}}"></i>{%endif%}
                 {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })">{{tc.name}}</a>{%else%}<span class="muted">{{tc.name}}</span>{%endif%}
                 {%if tc.ordericon%} <i class="icon-caret-{{tc.ordericon}}"></i>{%endif%}
lib/toaster/toastergui/templates/generic-toastertable-page.html +2 -0
index d7ad2e7..78e942c 100644
@@ -11,7 +11,9 @@
 {% block projectinfomain %}
 <div class="page-header">
   <h1>{{title}} (<span class="table-count-{{table_name}}"></span>)
+    {% if project.release %}
     <i class="icon-question-sign get-help heading-help" title="This page lists {{title}} compatible with the release selected for this project, which is {{project.release.description}}"></i>
+    {% endif %}
   </h1>
 </div>
 <div id="zone1alerts" style="display:none">
lib/toaster/toastergui/templates/importlayer.html +13 -2
index 498a204..6a5d412d 100644
@@ -9,6 +9,7 @@
 
 {% block projectinfomain %}
 
+        {% if project and project.release %}
                   <script src="{% static 'js/layerDepsModal.js' %}"></script>
                   <script src="{% static 'js/importlayer.js' %}"></script>
                   <script>
@@ -31,9 +32,7 @@
                 </div>
 
                 <form>
-        {% if project %}
                     <span class="help-block" style="padding-left:19px;">The layer you are importing must be compatible with <strong>{{project.release.description}}</strong>, which is the release you are using in this project.</span>
-          {% endif %}
                    <fieldset class="air">
                       <legend>Layer repository information</legend>
                       <div class="alert alert-error" id="import-error" style="display:none">
@@ -131,4 +130,16 @@
                   </div>
                   </form>
 
+          {% else %} {#project and project release#}
+                <div class="page-header">
+                    <h1>Import layer</h1>
+                </div>
+                      <div class="alert alert-info" id="import-error" >
+                        <h3>Unsupported project type</h3>
+                        <p>This project does not support importing layers.</p>
+                        <ul></ul>
+                      </div>
+
+          {% endif %}
+
 {% endblock %}
lib/toaster/toastergui/templates/target.html +1 -1
index fa59f4e..65e6c4a 100644
@@ -53,7 +53,7 @@
     <div class="row-fluid">
         <div class="alert">
             <form class="no-results input-append" id="searchform">
-                <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+                <input id="search" name="search" class="input-xxlarge" type="text" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
                 <button class="btn" type="submit" value="Search">Search</button>
                 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all packages</button>
             </form>
lib/toaster/toastergui/templates/toastertable-simple.html +2 -2
index ea7b38e..212318b 100644
@@ -29,7 +29,7 @@
 <div class="row-fluid" id="no-results-{{table_name}}" style="display:none">
   <div class="alert">
     <form class="no-results input-append">
-      <input class="input-xlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+      <input class="input-xlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>
       <a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
         <i class="icon-remove"></i>
       </a>
@@ -44,7 +44,7 @@
   <div class="row-fluid" id="table-chrome-{{table_name}}">
       <div class="navbar-search input-append pull-left">
 
-        <input class="input-xlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+        <input class="input-xlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>
         <a href="#" style="display:none" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
           <i class="icon-remove"></i>
         </a>
lib/toaster/toastergui/templates/toastertable.html +2 -2
index c7c7a84..0473116 100644
@@ -29,7 +29,7 @@
 <div class="row-fluid" id="no-results-{{table_name}}" style="display:none">
   <div class="alert">
     <form class="no-results input-append">
-      <input class="input-xxlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+      <input class="input-xxlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{%if request.GET.search %}{{request.GET.search}}{%endif%}"/>
       <a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
         <i class="icon-remove"></i>
       </a>
@@ -46,7 +46,7 @@
     <div class="navbar-inner">
       <div class="navbar-search input-append pull-left">
 
-        <input class="input-xxlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+        <input class="input-xxlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{%if request.GET.search%}{{request.GET.search}}{%endif%}"/>
         <a href="#" style="display:none" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
           <i class="icon-remove"></i>
         </a>
lib/toaster/toastergui/views.py +6 -5
index ec65903..82650d0 100755
@@ -165,8 +165,8 @@ def _lv_to_dict(prj, x = None):
 
     return {"id": x.pk,
             "name": x.layer.name,
-            "tooltip": x.layer.vcs_url+" | "+x.get_vcs_reference(),
-            "detail": "(" + x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.get_vcs_reference()+")"),
+            "tooltip": "%s | %s" % (x.layer.vcs_url,x.get_vcs_reference()),
+            "detail": "(%s" % x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.get_vcs_reference()+")"),
             "giturl": x.layer.vcs_url,
             "layerdetailurl" : reverse('layerdetails', args=(prj.id,x.pk)),
             "revision" : x.get_vcs_reference(),
@@ -559,10 +559,10 @@ def task( request, build_id, task_id ):
     uri_list= [ ]
     variables = Variable.objects.filter(build=build_id)
     v=variables.filter(variable_name='SSTATE_DIR')
-    if v.count > 0:
+    if v.count() > 0:
         uri_list.append(v[0].variable_value)
     v=variables.filter(variable_name='SSTATE_MIRRORS')
-    if (v.count > 0):
+    if (v.count() > 0):
         for mirror in v[0].variable_value.split('\\n'):
             s=re.sub('.* ','',mirror.strip(' \t\n\r'))
             if len(s): uri_list.append(s)
@@ -2124,9 +2124,10 @@ if True:
                     login(request, user)
 
                 #  save the project
-                release = Release.objects.get(pk = request.POST.get('projectversion', None ))
                 if ptype == "analysis":
                     release = None
+                else:
+                    release = Release.objects.get(pk = request.POST.get('projectversion', None ))
 
                 prj = Project.objects.create_project(name = request.POST['projectname'], release = release)
                 prj.user_id = request.user.pk
Signature · 1 line
1.9.1
#17 lore raw

Re: [PATCH 16/23] toasterui: fixes after html5 compliance testing

Quoted 227 lines · Alex DAMIAN

From: Alexandru DAMIAN <[email protected]>

This patch brings fixes for issues highlighted by
HTML5 compliance testing.

---
  lib/toaster/orm/models.py                                 |  4 +++-
  lib/toaster/toastergui/static/js/base.js                  |  2 +-
  lib/toaster/toastergui/templates/configvars.html          |  2 +-
  .../toastergui/templates/detail_search_header.html        |  2 +-
  .../toastergui/templates/detail_sorted_header.html        |  2 +-
  .../toastergui/templates/generic-toastertable-page.html   |  2 ++
  lib/toaster/toastergui/templates/importlayer.html         | 15 +++++++++++++--
  lib/toaster/toastergui/templates/target.html              |  2 +-
  lib/toaster/toastergui/templates/toastertable-simple.html |  4 ++--
  lib/toaster/toastergui/templates/toastertable.html        |  4 ++--
  lib/toaster/toastergui/views.py                           | 11 ++++++-----
  11 files changed, 33 insertions(+), 17 deletions(-)
lib/toaster/orm/models.py +3 -1
index 8488aa4..7e8ab16 100644
@@ -180,7 +180,9 @@ class Project(models.Model):
          if release == None:
              release = self.release
          # layers on the same branch or layers specifically set for this project
-        queryset = Layer_Version.objects.filter((Q(up_branch__name = release.branch_name) & Q(project = None)) | Q(project = self) | Q(build__project = self))
+        queryset = Layer_Version.objects.filter(Q(project = self) | Q(build__project = self))
+        if release is not None:
+            queryset = queryset.filter(Q(up_branch__name = release.branch_name) & Q(project = None))
          if layer_name is not None:
              # we select only a layer name
              queryset = queryset.filter(layer__name = layer_name)
lib/toaster/toastergui/static/js/base.js +1 -1
index d079f23..f1711c1 100644
@@ -39,7 +39,7 @@ function basePageInit(ctx) {
 
      libtoaster.getProjectInfo(selectedProject.projectPageUrl,
        function (data) {
-        if (data.machine.name === undefined || data.layers.length === 0) {
+        if (data.machine === null || data.machine.name === undefined || data.layers.length === 0) {
            /* we can't build anything with out a machine and some layers */
            $("#new-build-button #targets-form").hide();
            $("#new-build-button .alert").show();
lib/toaster/toastergui/templates/configvars.html +1 -1
index 8957673..8a572ae 100644
@@ -39,7 +39,7 @@
    <div class="row-fluid">
        <div class="alert">
          <form class="no-results input-append" id="searchform">
-            <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+            <input id="search" name="search" class="input-xxlarge" type="text" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
              <button class="btn" type="submit" value="Search">Search</button>
              <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all variables</button>
          </form>
lib/toaster/toastergui/templates/detail_search_header.html +1 -1
index ca8e158..7bea3f4 100644
@@ -28,7 +28,7 @@ $(document).ready(function() {
      <form id="searchform" class="navbar-search input-append pull-left">
    {% endif %}
 
-      <input id="search" class="input-xlarge" type="text" placeholder="Search {{search_what}}" name="search" value="{{request.GET.search}}">
+      <input id="search" class="input-xlarge" type="text" placeholder="Search {{search_what}}" name="search" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}">
        <input type="hidden" value="name:+" name="orderby">
        <input type="hidden" value="l" name="page">
    {% if request.GET.search %}
lib/toaster/toastergui/templates/detail_sorted_header.html +1 -1
index 5214444..6ce292e 100644
@@ -9,7 +9,7 @@
      <thead>
          <!-- Table header row; generated from "tablecols" entry in the context dict -->
          <tr>
-            {% for tc in tablecols %}<th class="{{tc.dclass}} {{tc.clclass}}">
+            {% for tc in tablecols %}<th class="{%if tc.dclass%}{{tc.dclass}}{% endif %} {%if tc.class %}{{tc.clclass}}{% endif %}">
                  {%if tc.qhelp%}<i class="icon-question-sign get-help" title="{{tc.qhelp}}"></i>{%endif%}
                  {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })">{{tc.name}}</a>{%else%}<span class="muted">{{tc.name}}</span>{%endif%}
                  {%if tc.ordericon%} <i class="icon-caret-{{tc.ordericon}}"></i>{%endif%}
lib/toaster/toastergui/templates/generic-toastertable-page.html +2 -0
index d7ad2e7..78e942c 100644
@@ -11,7 +11,9 @@
  {% block projectinfomain %}
  <div class="page-header">
    <h1>{{title}} (<span class="table-count-{{table_name}}"></span>)
+    {% if project.release %}
      <i class="icon-question-sign get-help heading-help" title="This page lists {{title}} compatible with the release selected for this project, which is {{project.release.description}}"></i>
+    {% endif %}
    </h1>
  </div>
  <div id="zone1alerts" style="display:none">
lib/toaster/toastergui/templates/importlayer.html +13 -2
index 498a204..6a5d412d 100644
@@ -9,6 +9,7 @@
 
  {% block projectinfomain %}
 
+        {% if project and project.release %}
                    <script src="{% static 'js/layerDepsModal.js' %}"></script>
                    <script src="{% static 'js/importlayer.js' %}"></script>
                    <script>
@@ -31,9 +32,7 @@
                  </div>
 
                  <form>
-        {% if project %}
                      <span class="help-block" style="padding-left:19px;">The layer you are importing must be compatible with <strong>{{project.release.description}}</strong>, which is the release you are using in this project.</span>
-          {% endif %}
                     <fieldset class="air">
                        <legend>Layer repository information</legend>
                        <div class="alert alert-error" id="import-error" style="display:none">
@@ -131,4 +130,16 @@
                    </div>
                    </form>
 
+          {% else %} {#project and project release#}
+                <div class="page-header">
+                    <h1>Import layer</h1>
+                </div>
+                      <div class="alert alert-info" id="import-error" >
+                        <h3>Unsupported project type</h3>
+                        <p>This project does not support importing layers.</p>
+                        <ul></ul>
+                      </div>
+
+          {% endif %}
+
  {% endblock %}
lib/toaster/toastergui/templates/target.html +1 -1
index fa59f4e..65e6c4a 100644
@@ -53,7 +53,7 @@
      <div class="row-fluid">
          <div class="alert">
              <form class="no-results input-append" id="searchform">
-                <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
+                <input id="search" name="search" class="input-xxlarge" type="text" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
                  <button class="btn" type="submit" value="Search">Search</button>
                  <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all packages</button>
              </form>
lib/toaster/toastergui/templates/toastertable-simple.html +2 -2
index ea7b38e..212318b 100644
@@ -29,7 +29,7 @@
  <div class="row-fluid" id="no-results-{{table_name}}" style="display:none">
    <div class="alert">
      <form class="no-results input-append">
-      <input class="input-xlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+      <input class="input-xlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>
        <a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
          <i class="icon-remove"></i>
        </a>
@@ -44,7 +44,7 @@
    <div class="row-fluid" id="table-chrome-{{table_name}}">
        <div class="navbar-search input-append pull-left">
 
-        <input class="input-xlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+        <input class="input-xlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>
          <a href="#" style="display:none" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
            <i class="icon-remove"></i>
          </a>
lib/toaster/toastergui/templates/toastertable.html +2 -2
index c7c7a84..0473116 100644
@@ -29,7 +29,7 @@
  <div class="row-fluid" id="no-results-{{table_name}}" style="display:none">
    <div class="alert">
      <form class="no-results input-append">
-      <input class="input-xxlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+      <input class="input-xxlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{%if request.GET.search %}{{request.GET.search}}{%endif%}"/>
        <a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
          <i class="icon-remove"></i>
        </a>
@@ -46,7 +46,7 @@
      <div class="navbar-inner">
        <div class="navbar-search input-append pull-left">
 
-        <input class="input-xxlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
+        <input class="input-xxlarge" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{%if request.GET.search%}{{request.GET.search}}{%endif%}"/>
          <a href="#" style="display:none" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
            <i class="icon-remove"></i>
          </a>
lib/toaster/toastergui/views.py +4 -4
index ec65903..82650d0 100755
@@ -165,8 +165,8 @@ def _lv_to_dict(prj, x = None):
 
      return {"id": x.pk,
              "name": x.layer.name,
-            "tooltip": x.layer.vcs_url+" | "+x.get_vcs_reference(),
-            "detail": "(" + x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.get_vcs_reference()+")"),
+            "tooltip": "%s | %s" % (x.layer.vcs_url,x.get_vcs_reference()),
+            "detail": "(%s" % x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.get_vcs_reference()+")"),
              "giturl": x.layer.vcs_url,
              "layerdetailurl" : reverse('layerdetails', args=(prj.id,x.pk)),
              "revision" : x.get_vcs_reference(),
@@ -559,10 +559,10 @@ def task( request, build_id, task_id ):
      uri_list= [ ]
      variables = Variable.objects.filter(build=build_id)
      v=variables.filter(variable_name='SSTATE_DIR')
-    if v.count > 0:
+    if v.count() > 0:
          uri_list.append(v[0].variable_value)
      v=variables.filter(variable_name='SSTATE_MIRRORS')
-    if (v.count > 0):
+    if (v.count() > 0):
          for mirror in v[0].variable_value.split('\\n'):
              s=re.sub('.* ','',mirror.strip(' \t\n\r'))
              if len(s): uri_list.append(s)
@@ -2124,9 +2124,10 @@ if True:
                      login(request, user)

lib/toaster/toastergui/views.py if True: · line 2133

Quoted 10 lines
lib/toaster/toastergui/views.py +2 -1
 
                  #  save the project
-                release = Release.objects.get(pk = request.POST.get('projectversion', None ))
                  if ptype == "analysis":
                      release = None
+                else:
+                    release = Release.objects.get(pk = request.POST.get('projectversion', None ))
 
                  prj = Project.objects.create_project(name = request.POST['projectname'], release = release)
                  prj.user_id = request.user.pk

Note: This patch as far as I can see wasn't submitted for review on the Toaster mailing list. It currently breaks Toaster.

As this touches things which should not have been in this patch; js, template changes, views and orm/models.py we can't revert it as it will break other things. I will try to roll a patch which reverts part of this patch.

#18 lore raw

PATCH 17/23 toaster: Enable toastertable cache

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

Enable the cache and fix warning on the toastertable cache which happens on the memcache backend "CacheKeyWarning: Cache key contains characters that will cause errors if used with memcached"

---
 lib/toaster/toastergui/widgets.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
lib/toaster/toastergui/widgets.py +5 -2
index f5a1b3e..e257c70 100644
@@ -36,6 +36,7 @@ import types
 import json
 import collections
 import operator
+import re
 
 from toastergui.views import objtojson
 
@@ -251,10 +252,12 @@ class ToasterTable(TemplateView):
         for key, val in kwargs.iteritems():
             cache_name = cache_name + str(key) + str(val)
 
+        # No special chars allowed in the cache name
+        cache_name = re.sub(r'[^A-Za-z0-9]', "", cache_name)
         data = cache.get(cache_name)
 
-        #if data:
-        #    return data
+        if data:
+            return data
 
         self.setup_columns(**kwargs)
 
Signature · 1 line
1.9.1
#19 lore raw

PATCH 18/23 toaster: toastertable Pass up the kwargs for setup_filter

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

This allows us to setup_filter in tables using args such as the current project.

---
 lib/toaster/toastergui/widgets.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
lib/toaster/toastergui/widgets.py +6 -6
index e257c70..5f6b47b 100644
@@ -72,7 +72,7 @@ class ToasterTable(TemplateView):
 
             cmd = request.GET.get('cmd', None)
             if cmd and 'filterinfo' in cmd:
-                data = self.get_filter_info(request)
+                data = self.get_filter_info(request, **kwargs)
             else:
                 # If no cmd is specified we give you the table data
                 data = self.get_data(request, **kwargs)
@@ -81,10 +81,10 @@ class ToasterTable(TemplateView):
 
         return super(ToasterTable, self).get(request, *args, **kwargs)
 
-    def get_filter_info(self, request):
+    def get_filter_info(self, request, **kwargs):
         data = None
 
-        self.setup_filters()
+        self.setup_filters(**kwargs)
 
         search = request.GET.get("search", None)
         if search:
@@ -194,8 +194,8 @@ class ToasterTable(TemplateView):
 
         return template.render(context)
 
-    def apply_filter(self, filters):
-        self.setup_filters()
+    def apply_filter(self, filters, **kwargs):
+        self.setup_filters(**kwargs)
 
         try:
             filter_name, filter_action = filters.split(':')
@@ -264,7 +264,7 @@ class ToasterTable(TemplateView):
         if search:
             self.apply_search(search)
         if filters:
-            self.apply_filter(filters)
+            self.apply_filter(filters, **kwargs)
         if orderby:
             self.apply_orderby(orderby)
 
Signature · 1 line
1.9.1
#20 lore raw

PATCH 19/23 toaster: table.js fix filter visual indicator and interaction

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

- Fix the id of the filter modal dialog.
- Fix the visual indicator toggle button
- Add check to see if the number of items to filter on is !=0 if it is then don't allow applying this filter.

---
 lib/toaster/toastergui/static/js/table.js | 59 +++++++++++++++++++++++--------
 1 file changed, 44 insertions(+), 15 deletions(-)
lib/toaster/toastergui/static/js/table.js +44 -15
index 1072c75..d06a3f5 100644
@@ -261,23 +261,14 @@ function tableInit(ctx){
         var filterBtn = $('<a href="#" role="button" class="pull-right btn btn-mini" data-toggle="modal"><i class="icon-filter filtered"></i></a>');
 
         filterBtn.data('filter-name', col.filter_name);
+        filterBtn.prop('id', col.filter_name);
         filterBtn.click(filterOpenClicked);
 
         /* If we're currently being filtered setup the visial indicator */
         if (tableParams.filter &&
             tableParams.filter.match('^'+col.filter_name)) {
 
-            filterBtn.addClass("btn-primary");
-
-            filterBtn.tooltip({
-                html: true,
-                title: '<button class="btn btn-small btn-primary" onClick=\'$("#clear-filter-btn").click();\'>Clear filter</button>',
-                placement: 'bottom',
-                delay: {
-                  hide: 1500,
-                  show: 400,
-                },
-            });
+            filterBtnActive(filterBtn, true);
         }
         header.append(filterBtn);
       }
@@ -310,6 +301,26 @@ function tableInit(ctx){
     tableChromeDone = true;
   }
 
+  /* Toggles the active state of the filter button */
+  function filterBtnActive(filterBtn, active){
+    if (active) {
+      filterBtn.addClass("btn-primary");
+
+      filterBtn.tooltip({
+          html: true,
+          title: '<button class="btn btn-small btn-primary" onClick=\'$("#clear-filter-btn-'+ ctx.tableName +'").click();\'>Clear filter</button>',
+          placement: 'bottom',
+          delay: {
+            hide: 1500,
+            show: 400,
+          },
+      });
+    } else {
+      filterBtn.removeClass("btn-primary");
+      filterBtn.tooltip('destroy');
+    }
+  }
+
   /* Display or hide table columns based on the cookie preference or defaults */
   function loadColumnsPreference(){
     var cookie_data = $.cookie("cols");
@@ -427,6 +438,10 @@ function tableInit(ctx){
 
             var radioInput = action.children("input");
 
+            if (Number(filterAction.count) == 0){
+              radioInput.attr("disabled", "disabled");
+            }
+
             action.children(".filter-title").text(actionTitle);
 
             radioInput.val(filterName + ':' + filterAction.name);
@@ -475,7 +490,13 @@ function tableInit(ctx){
 
     tableParams.page = 1;
     tableParams.search = searchTerm;
-    tableParams.filter = null;
+
+    /* If a filter was active we remove it */
+    if (tableParams.filter) {
+      var filterBtn = $("#" + tableParams.filter.split(":")[0]);
+      filterBtnActive(filterBtn, false);
+      tableParams.filter = null;
+    }
 
     loadData(tableParams);
 
@@ -504,6 +525,9 @@ function tableInit(ctx){
   });
 
   $("#clear-filter-btn-"+ctx.tableName).click(function(){
+    var filterBtn = $("#" + tableParams.filter.split(":")[0]);
+    filterBtnActive(filterBtn, false);
+
     tableParams.filter = null;
     loadData(tableParams);
   });
@@ -513,13 +537,18 @@ function tableInit(ctx){
 
     tableParams.filter = $(this).find("input[type='radio']:checked").val();
 
+    var filterBtn = $("#" + tableParams.filter.split(":")[0]);
+
     /* All === remove filter */
-    if (tableParams.filter.match(":all$"))
+    if (tableParams.filter.match(":all$")) {
       tableParams.filter = null;
+      filterBtnActive(filterBtn, false);
+    } else {
+      filterBtnActive(filterBtn, true);
+    }
 
     loadData(tableParams);
 
-
-    $('#filter-modal').modal('hide');
+    $(this).parent().modal('hide');
   });
 }
Signature · 1 line
1.9.1
#21 lore raw

PATCH 20/23 toaster: Restore 'in project' filters to main tables

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

Restores the previously removed filters from recipes, machines and layers table. These filters allow filtering down the results to just displaying the current added layers, machines or recipes in the project.

[YOCTO #7851]

---
 lib/toaster/toastergui/tables.py | 75 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 2 deletions(-)
lib/toaster/toastergui/tables.py +73 -2
index 43b81a3..146a8dd 100644
@@ -26,6 +26,24 @@ from django.conf.urls import url
 from django.core.urlresolvers import reverse
 from django.views.generic import TemplateView
 
+
+class ProjectFiltersMixin(object):
+    """Common mixin for recipe, machine in project filters"""
+
+    def filter_in_project(self, count_only=False):
+        query = self.queryset.filter(layer_version__in=self.project_layers)
+        if count_only:
+            return query.count()
+
+        self.queryset = query
+
+    def filter_not_in_project(self, count_only=False):
+        query = self.queryset.exclude(layer_version__in=self.project_layers)
+        if count_only:
+            return query.count()
+
+        self.queryset = query
+
 class LayersTable(ToasterTable):
     """Table of layers in Toaster"""
 
@@ -37,12 +55,40 @@ class LayersTable(ToasterTable):
         context = super(LayersTable, self).get_context_data(**kwargs)
 
         project = Project.objects.get(pk=kwargs['pid'])
+
         context['project'] = project
         context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=project))
 
         return context
 
 
+    def setup_filters(self, *args, **kwargs):
+        project = Project.objects.get(pk=kwargs['pid'])
+        self.project_layers = ProjectLayer.objects.filter(project=project)
+
+
+        self.add_filter(title="Filter by project layers",
+                        name="in_current_project",
+                        filter_actions=[
+                            self.make_filter_action("in_project", "Layers added to this project", self.filter_in_project),
+                            self.make_filter_action("not_in_project", "Layers not added to this project", self.filter_not_in_project)
+                        ])
+
+    def filter_in_project(self, count_only=False):
+        query = self.queryset.filter(projectlayer__in=self.project_layers)
+        if count_only:
+            return query.count()
+
+        self.queryset = query
+
+    def filter_not_in_project(self, count_only=False):
+        query = self.queryset.exclude(projectlayer__in=self.project_layers)
+        if count_only:
+            return query.count()
+
+        self.queryset = query
+
+
     def setup_queryset(self, *args, **kwargs):
         prj = Project.objects.get(pk = kwargs['pid'])
         compatible_layers = prj.compatible_layerversions()
@@ -140,6 +186,7 @@ class LayersTable(ToasterTable):
         self.add_column(title="Add | Delete",
                         help_text="Add or delete layers to / from your project",
                         hideable=False,
+                        filter_name="in_current_project",
                         static_data_name="add-del-layers",
                         static_data_template='{% include "layer_btn.html" %}')
 
@@ -169,7 +216,7 @@ class LayerDetails(ToasterTemplateView):
         return context
 
 
-class MachinesTable(ToasterTable):
+class MachinesTable(ToasterTable, ProjectFiltersMixin):
     """Table of Machines in Toaster"""
 
     def __init__(self, *args, **kwargs):
@@ -183,6 +230,16 @@ class MachinesTable(ToasterTable):
         context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project']))
         return context
 
+    def setup_filters(self, *args, **kwargs):
+        project = Project.objects.get(pk=kwargs['pid'])
+        self.project_layers = project.projectlayer_equivalent_set()
+
+        self.add_filter(title="Filter by project machines",
+                        name="in_current_project",
+                        filter_actions=[
+                            self.make_filter_action("in_project", "Machines provided by layers added to this project", self.filter_in_project),
+                            self.make_filter_action("not_in_project", "Machines provided by layers not added to this project", self.filter_not_in_project)
+                        ])
 
     def setup_queryset(self, *args, **kwargs):
         prj = Project.objects.get(pk = kwargs['pid'])
@@ -226,6 +283,7 @@ class MachinesTable(ToasterTable):
         self.add_column(title="Select",
                         help_text="Sets the selected machine as the project machine. You can only have one machine per project",
                         hideable=False,
+                        filter_name="in_current_project",
                         static_data_name="add-del-layers",
                         static_data_template='{% include "machine_btn.html" %}')
 
@@ -264,7 +322,7 @@ class LayerMachinesTable(MachinesTable):
                         static_data_template=select_btn_template)
 
 
-class RecipesTable(ToasterTable):
+class RecipesTable(ToasterTable, ProjectFiltersMixin):
     """Table of Recipes in Toaster"""
 
     def __init__(self, *args, **kwargs):
@@ -282,6 +340,17 @@ class RecipesTable(ToasterTable):
 
         return context
 
+    def setup_filters(self, *args, **kwargs):
+        project = Project.objects.get(pk=kwargs['pid'])
+        self.project_layers = project.projectlayer_equivalent_set()
+
+        self.add_filter(title="Filter by project recipes",
+                        name="in_current_project",
+                        filter_actions=[
+                            self.make_filter_action("in_project", "Recipes provided by layers added to this project", self.filter_in_project),
+                            self.make_filter_action("not_in_project", "Recipes provided by layers not added to this project", self.filter_not_in_project)
+                        ])
+
 
     def setup_queryset(self, *args, **kwargs):
         prj = Project.objects.get(pk = kwargs['pid'])
@@ -318,6 +387,7 @@ class RecipesTable(ToasterTable):
 
         self.add_column(title="Recipe file",
                         help_text="Path to the recipe .bb file",
+                        hidden=True,
                         static_data_name="recipe-file",
                         static_data_template=recipe_file_template)
 
@@ -348,6 +418,7 @@ class RecipesTable(ToasterTable):
         self.add_column(title="Build",
                         help_text="Add or delete recipes to and from your project",
                         hideable=False,
+                        filter_name="in_current_project",
                         static_data_name="add-del-layers",
                         static_data_template='{% include "recipe_btn.html" %}')
 
Signature · 1 line
1.9.1
#22 lore raw

PATCH 21/23 toaster: bldcontrol Ignore toasterconf files in own directories

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

If toaster has previously cloned poky or a layer with a toasterconf file we don't want this to be picked up as a choice as these clones are "internal" to toaster and may have undesired effects on toaster's setup.

[YOCTO #7741]

---
 lib/toaster/bldcontrol/management/commands/checksettings.py | 2 ++
 1 file changed, 2 insertions(+)
lib/toaster/bldcontrol/management/commands/checksettings.py +2 -0
index 3c52446..3002e4c 100644
@@ -166,6 +166,8 @@ class Command(NoArgsCommand):
                             conffilepath, error = subprocess.Popen('bash -c ". '+os.path.join(dirname, ".templateconf")+'; echo \"\$TEMPLATECONF\""', shell=True, stdout=subprocess.PIPE).communicate()
                             conffilepath = os.path.join(conffilepath.strip(), "toasterconf.json")
                             candidatefilepath = os.path.join(dirname, conffilepath)
+                            if "toaster_cloned" in candidatefilepath:
+                                continue
                             if os.path.exists(candidatefilepath):
                                 config_files.append(candidatefilepath)
 
Signature · 1 line
1.9.1
#23 lore raw

PATCH 22/23 toaster: split orm app into it's own module and app

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

The orm application was also the django application to collect the build information. Splitting this module up into it's functional parts. orm for the data module and bldcollector for build collection data.

---
 lib/toaster/bldcollector/__init__.py       | 0
 lib/toaster/{orm => bldcollector}/admin.py | 3 +--
 lib/toaster/{orm => bldcollector}/urls.py  | 3 +--
 lib/toaster/{orm => bldcollector}/views.py | 0
 lib/toaster/toastermain/settings.py        | 2 +-
 5 files changed, 3 insertions(+), 5 deletions(-)
 create mode 100644 lib/toaster/bldcollector/__init__.py
 rename lib/toaster/{orm => bldcollector}/admin.py (92%)
 rename lib/toaster/{orm => bldcollector}/urls.py (95%)
 rename lib/toaster/{orm => bldcollector}/views.py (100%)
lib/toaster/bldcollector/__init__.py new file +0 -0
new file mode 100644
index 0000000..e69de29
lib/toaster/bldcollector/admin.py renamed from lib/toaster/orm/admin.py +1 -2
similarity index 92%
rename from lib/toaster/orm/admin.py
rename to lib/toaster/bldcollector/admin.py
index 706e517..c1f85d7 100644
@@ -1,6 +1,6 @@
 from django.contrib import admin
 from django.contrib.admin.filters import RelatedFieldListFilter
-from .models import BitbakeVersion, Release, LayerSource, ToasterSetting
+from orm.models import BitbakeVersion, Release, LayerSource, ToasterSetting
 from django.forms.widgets import Textarea
 from django import forms
 import django.db.models as models
@@ -31,4 +31,3 @@ admin.site.register(LayerSource, LayerSourceAdmin)
 admin.site.register(BitbakeVersion, BitbakeVersionAdmin)
 admin.site.register(Release, ReleaseAdmin)
 admin.site.register(ToasterSetting, ToasterSettingAdmin)
-
lib/toaster/bldcollector/urls.py renamed from lib/toaster/orm/urls.py +1 -2
similarity index 95%
rename from lib/toaster/orm/urls.py
rename to lib/toaster/bldcollector/urls.py
index 961bc19..144387b 100644
@@ -20,8 +20,7 @@
 from django.conf.urls import patterns, include, url
 from django.views.generic import RedirectView
 
-urlpatterns = patterns('orm.views',
+urlpatterns = patterns('bldcollector.views',
         # landing point for pushing a bitbake_eventlog.json file to this toaster instace
         url(r'^eventfile$', 'eventfile', name='eventfile'),
         )
-
lib/toaster/bldcollector/views.py renamed from lib/toaster/orm/views.py +0 -0
similarity index 100%
rename from lib/toaster/orm/views.py
rename to lib/toaster/bldcollector/views.py
lib/toaster/toastermain/settings.py +1 -1
index 60e80de..c72a904 100644
@@ -268,7 +268,7 @@ INSTALLED_APPS = (
     # Uncomment the next line to enable admin documentation:
     # 'django.contrib.admindocs',
     'django.contrib.humanize',
-    'orm',
+    'bldcollector',
     'toastermain',
     'south',
 )
Signature · 1 line
1.9.1
#24 lore raw

PATCH 23/23 toaster: Add url pattern for backward compatibility

In reply to Alex DAMIAN

From: Michael Wood <[email protected]>

This adds an url to match the old orm application.

---
 lib/toaster/toastermain/urls.py | 4 ++++
 1 file changed, 4 insertions(+)
lib/toaster/toastermain/urls.py +4 -0
index 26ad3a2..521588a 100644
@@ -40,6 +40,10 @@ urlpatterns = patterns('',
     # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
 
+    # This is here to maintain backward compatibility and will be deprecated
+    # in the future.
+    url(r'^orm/eventfile$', 'bldcollector.views.eventfile'),
+
     # if no application is selected, we have the magic toastergui app here
     url(r'^$', never_cache(RedirectView.as_view(url='/toastergui/'))),
 )
Signature · 1 line
1.9.1