Openembedded Bitbake Development
 help / color / mirror / Atom feed
* [PATCH 01/27] toastergui: remove time link for failed build requests
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 02/27] toasterui: use text() instead of html() Alex DAMIAN
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Failed build requests do not have a build time page where
you can look at the time spent on each task. Therefore,
their build time information cannot be a link to such
a page.

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

diff --git a/lib/toaster/toastergui/templates/managed_mrb_section.html b/lib/toaster/toastergui/templates/managed_mrb_section.html
index d2ffdcd..c7ae6fd 100644
--- a/lib/toaster/toastergui/templates/managed_mrb_section.html
+++ b/lib/toaster/toastergui/templates/managed_mrb_section.html
@@ -100,7 +100,7 @@
             </div>
             <div class="lead ">
               <span class="lead{%if not MANAGED or not buildrequest.project%} pull-right{%endif%}">
-                Build time: <a href="{% url 'buildrequestdetails' buildrequest.project.id buildrequest.pk %}">{{ buildrequest.get_duration|sectohms }}</a>
+                Build time: {{ buildrequest.get_duration|sectohms }}
               </span>
               <button class="btn btn-danger pull-right" onclick='scheduleBuild({% url 'xhr_projectbuild' buildrequest.project.id as bpi%}{{bpi|json}}, {{buildrequest.project.name|json}}, {{buildrequest.get_sorted_target_list|mapselect:'target'|json}})'>Run again</button>
 
-- 
1.9.1



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

* [PATCH 02/27] toasterui: use text() instead of html()
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 01/27] toastergui: remove time link for failed build requests Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 03/27] toaster: correct typo in toaster script Alex DAMIAN
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Use the text() jQuery function instead of the html()
one for security reasons.

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

diff --git a/lib/toaster/toastergui/static/js/layerdetails.js b/lib/toaster/toastergui/static/js/layerdetails.js
index 2793225..9339ae8 100644
--- a/lib/toaster/toastergui/static/js/layerdetails.js
+++ b/lib/toaster/toastergui/static/js/layerdetails.js
@@ -252,10 +252,10 @@ function layerDetailsPageInit (ctx) {
           break;
       }
 
-      alertMsg.append("You have deleted <strong>1</strong> layer from <a id=\"project-affected-name\"></a>: <span id=\"layer-affected-name\"></span>");
+      alertMsg.append("You have deleted <strong>1</strong> layer from <a id=\"project-affected-name\"></a>: <strong id=\"layer-affected-name\"></strong>");
     }
 
-    alertMsg.children("#layer-affected-name").html("<strong>" + ctx.layerVersion.name + "</strong>");
+    alertMsg.children("#layer-affected-name").text(ctx.layerVersion.name);
     alertMsg.children("#project-affected-name").text(ctx.projectName);
     alertMsg.children("#project-affected-name").attr("href", ctx.projectPageUrl);
     $("#alert-area").show();
-- 
1.9.1



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

* [PATCH 03/27] toaster: correct typo in toaster script
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 01/27] toastergui: remove time link for failed build requests Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 02/27] toasterui: use text() instead of html() Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 04/27] toastergui: fix loadconf error message Alex DAMIAN
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

A small typo slipped in the message included in
the fix for [YOCTO #6023].

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

diff --git a/bin/toaster b/bin/toaster
index 85a2575..6f7c6f0 100755
--- a/bin/toaster
+++ b/bin/toaster
@@ -242,8 +242,8 @@ if [ ${CMD} == "start" ] && [ $lock -eq 0 ]; then
 fi
 
 if [ ${CMD} == "start" ] && [ -e $BUILDDIR/.toastermain.pid ] && kill -0 `cat $BUILDDIR/.toastermain.pid`; then
-    echo "Error: bitbake appears to be dead, but the webserver is alive. Something fishy is going on." 1>&2
-    echo "Cleaning up the web server at to start a clean slate."
+    echo "Warning: bitbake appears to be dead, but the Toaster web server is running. Something fishy is going on." 1>&2
+    echo "Cleaning up the web server to start from a clean slate."
     webserverKillAll
 fi
 
-- 
1.9.1



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

* [PATCH 04/27] toastergui: fix loadconf error message
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (2 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 03/27] toaster: correct typo in toaster script Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 05/27] toaster: enable server-side caches and debug-panel Alex DAMIAN
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Toaster crashes in loadconf if it needs to raise an Exception due
to poorly formatted error message. This patch fixes the formatting

[YOCTO #7276]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/bldcontrol/management/commands/loadconf.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/toaster/bldcontrol/management/commands/loadconf.py b/lib/toaster/bldcontrol/management/commands/loadconf.py
index e2f61e4..9163e9b 100644
--- a/lib/toaster/bldcontrol/management/commands/loadconf.py
+++ b/lib/toaster/bldcontrol/management/commands/loadconf.py
@@ -59,7 +59,7 @@ class Command(BaseCommand):
                 except ValueError:
                     pass
             if url == None:
-                raise Exception("Error while looking for remote \"%s\" in \"s\"" % (remote_name, lo.local_path))
+                raise Exception("Error while looking for remote \"%s\" in \"%s\"" % (remote_name, out))
             return url
 
 
-- 
1.9.1



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

* [PATCH 05/27] toaster: enable server-side caches and debug-panel
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (3 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 04/27] toastergui: fix loadconf error message Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 06/27] toastergui: improvements in layer selection logic Alex DAMIAN
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

This patch enables the server-side caches for Django using
file cache in /tmp/ directory.

Patch enables django debug panel if available.

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

diff --git a/lib/toaster/toastermain/settings.py b/lib/toaster/toastermain/settings.py
index acc20cc..7cf9052 100644
--- a/lib/toaster/toastermain/settings.py
+++ b/lib/toaster/toastermain/settings.py
@@ -211,10 +211,25 @@ MIDDLEWARE_CLASSES = (
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.cache.UpdateCacheMiddleware',
+    'django.middleware.cache.FetchFromCacheMiddleware',
     # Uncomment the next line for simple clickjacking protection:
     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 )
 
+CACHES = {
+    #        'default': {
+    #            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+    #            'LOCATION': '127.0.0.1:11211',
+    #        },
+           'default': {
+               'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+               'LOCATION': '/tmp/django-default-cache',
+               'TIMEOUT': 5,
+            }
+          }
+
+
 from os.path import dirname as DN
 SITE_ROOT=DN(DN(os.path.abspath(__file__)))
 
@@ -252,17 +267,41 @@ INSTALLED_APPS = (
 )
 
 
+INTERNAL_IPS = ['127.0.0.1', '192.168.2.28']
+
 # Load django-fresh is TOASTER_DEVEL is set, and the module is available
 FRESH_ENABLED = False
 if os.environ.get('TOASTER_DEVEL', None) is not None:
     try:
         import fresh
-        MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ("fresh.middleware.FreshMiddleware",)
+        MIDDLEWARE_CLASSES = ("fresh.middleware.FreshMiddleware",) + MIDDLEWARE_CLASSES
         INSTALLED_APPS = INSTALLED_APPS + ('fresh',)
         FRESH_ENABLED = True
     except:
         pass
 
+DEBUG_PANEL_ENABLED = False
+if os.environ.get('TOASTER_DEVEL', None) is not None:
+    try:
+        import debug_toolbar, debug_panel
+        MIDDLEWARE_CLASSES = ('debug_panel.middleware.DebugPanelMiddleware',) + MIDDLEWARE_CLASSES
+        #MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ('debug_toolbar.middleware.DebugToolbarMiddleware',)
+        INSTALLED_APPS = INSTALLED_APPS + ('debug_toolbar','debug_panel',)
+        DEBUG_PANEL_ENABLED = True
+
+        # this cache backend will be used by django-debug-panel
+        CACHES['debug-panel'] = {
+                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+                'LOCATION': '/var/tmp/debug-panel-cache',
+                'TIMEOUT': 300,
+                'OPTIONS': {
+                    'MAX_ENTRIES': 200
+                }
+        }
+
+    except:
+        pass
+
 
 SOUTH_TESTS_MIGRATE = False
 
-- 
1.9.1



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

* [PATCH 06/27] toastergui: improvements in layer selection logic
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (4 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 05/27] toaster: enable server-side caches and debug-panel Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 07/27] toaster: enhancements for the startup sequence Alex DAMIAN
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

This patch clearers and bring fixes for the layer selection
logic in order to enable information collected during build to be used
in configuring projects, specifically targeting the recipes
learned through the building process.

The patch also adds tests to verify the layer selection logic.

[YOCTO #7189]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/bldcontrol/bbcontroller.py          |  13 ---
 lib/toaster/bldcontrol/localhostbecontroller.py |  54 +++++++---
 lib/toaster/bldcontrol/sshbecontroller.py       |   2 +-
 lib/toaster/orm/models.py                       |  23 ++++-
 lib/toaster/orm/tests.py                        | 131 +++++++++++++++++++++++-
 lib/toaster/toastergui/templates/targets.html   |  14 +--
 lib/toaster/toastergui/views.py                 |  35 +++++--
 lib/toaster/toastermain/urls.py                 |   5 +
 8 files changed, 224 insertions(+), 53 deletions(-)

diff --git a/lib/toaster/bldcontrol/bbcontroller.py b/lib/toaster/bldcontrol/bbcontroller.py
index cf3f1fd..42675d3 100644
--- a/lib/toaster/bldcontrol/bbcontroller.py
+++ b/lib/toaster/bldcontrol/bbcontroller.py
@@ -81,19 +81,6 @@ def getBuildEnvironmentController(**kwargs):
         raise Exception("FIXME: Implement BEC for type %s" % str(be.betype))
 
 
-def _get_git_clonedirectory(url, branch):
-    """ Utility that returns the last component of a git path as directory
-    """
-    import re
-    components = re.split(r'[:\.\/]', url)
-    base = components[-2] if components[-1] == "git" else components[-1]
-
-    if branch != "HEAD":
-        return "_%s_%s.toaster_cloned" % (base, branch)
-
-    return base
-
-
 class BuildEnvironmentController(object):
     """ BuildEnvironmentController (BEC) is the abstract class that defines the operations that MUST
         or SHOULD be supported by a Build Environment. It is used to establish the framework, and must
diff --git a/lib/toaster/bldcontrol/localhostbecontroller.py b/lib/toaster/bldcontrol/localhostbecontroller.py
index 47708d1..005c464 100644
--- a/lib/toaster/bldcontrol/localhostbecontroller.py
+++ b/lib/toaster/bldcontrol/localhostbecontroller.py
@@ -30,7 +30,7 @@ import subprocess
 
 from toastermain import settings
 
-from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, _get_git_clonedirectory
+from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException
 
 import logging
 logger = logging.getLogger("toaster")
@@ -54,6 +54,7 @@ class LocalhostBEController(BuildEnvironmentController):
         if cwd is None:
             cwd = self.be.sourcedir
 
+        #logger.debug("lbc_shellcmmd: (%s) %s" % (cwd, command))
         p = subprocess.Popen(command, cwd = cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (out,err) = p.communicate()
         p.wait()
@@ -62,7 +63,7 @@ class LocalhostBEController(BuildEnvironmentController):
                 err = "command: %s \n%s" % (command, out)
             else:
                 err = "command: %s \n%s" % (command, err)
-            #logger.debug("localhostbecontroller: shellcmd error %s" % err)
+            #logger.warn("localhostbecontroller: shellcmd error %s" % err)
             raise ShellCmdException(err)
         else:
             #logger.debug("localhostbecontroller: shellcmd success")
@@ -106,19 +107,12 @@ class LocalhostBEController(BuildEnvironmentController):
 
         logger.debug("localhostbecontroller: running the listener at %s" % own_bitbake)
 
-        try:
-            os.remove(os.path.join(self.be.builddir, "toaster_ui.log"))
-        except OSError as e:
-            import errno
-            if e.errno != errno.ENOENT:
-                raise
-
 
         cmd = "bash -c \"source %s/oe-init-build-env %s && bitbake --read conf/toaster-pre.conf --postread conf/toaster.conf --server-only -t xmlrpc -B 0.0.0.0:0 && DATABASE_URL=%s BBSERVER=0.0.0.0:-1 daemon -d -i -D %s -o toaster_ui.log -- %s --observe-only -u toasterui &\"" % (self.pokydirname, self.be.builddir,
                 self.dburl, self.be.builddir, own_bitbake)
-        logger.debug("fullcommand |%s| " % cmd)
         port = "-1"
-        for i in self._shellcmd(cmd).split("\n"):
+        cmdoutput = self._shellcmd(cmd)
+        for i in cmdoutput.split("\n"):
             if i.startswith("Bitbake server address"):
                 port = i.split(" ")[-1]
                 logger.debug("localhostbecontroller: Found bitbake server port %s" % port)
@@ -132,10 +126,17 @@ class LocalhostBEController(BuildEnvironmentController):
                         return True
             return False
 
-        while not _toaster_ui_started(os.path.join(self.be.builddir, "toaster_ui.log")):
+        retries = 0
+        started = False
+        while not started and retries < 10:
+            started = _toaster_ui_started(os.path.join(self.be.builddir, "toaster_ui.log"))
             import time
             logger.debug("localhostbecontroller: Waiting bitbake server to start")
             time.sleep(0.5)
+            retries += 1
+
+        if not started:
+            raise BuildSetupException("localhostbecontroller: Bitbake server did not start in 5 seconds, aborting (Error: '%s')" % (cmdoutput))
 
         logger.debug("localhostbecontroller: Started bitbake server")
 
@@ -163,6 +164,25 @@ class LocalhostBEController(BuildEnvironmentController):
         self.be.save()
         logger.debug("localhostbecontroller: Stopped bitbake server")
 
+    def getGitCloneDirectory(self, url, branch):
+        """ Utility that returns the last component of a git path as directory
+        """
+        import re
+        components = re.split(r'[:\.\/]', url)
+        base = components[-2] if components[-1] == "git" else components[-1]
+
+        if branch != "HEAD":
+            return "_%s_%s.toaster_cloned" % (base, branch)
+
+
+        # word of attention; this is a localhost-specific issue; only on the localhost we expect to have "HEAD" releases
+        # which _ALWAYS_ means the current poky checkout
+        from os.path import dirname as DN
+        local_checkout_path = DN(DN(DN(DN(DN(os.path.abspath(__file__))))))
+        #logger.debug("localhostbecontroller: using HEAD checkout in %s" % local_checkout_path)
+        return local_checkout_path
+
+
     def setLayers(self, bitbakes, layers):
         """ a word of attention: by convention, the first layer for any build will be poky! """
 
@@ -208,15 +228,17 @@ class LocalhostBEController(BuildEnvironmentController):
 
         layerlist = []
 
+
         # 3. checkout the repositories
         for giturl, commit in gitrepos.keys():
-            localdirname = os.path.join(self.be.sourcedir, _get_git_clonedirectory(giturl, commit))
+            localdirname = os.path.join(self.be.sourcedir, self.getGitCloneDirectory(giturl, commit))
             logger.debug("localhostbecontroller: giturl %s:%s checking out in current directory %s" % (giturl, commit, localdirname))
 
             # make sure our directory is a git repository
             if os.path.exists(localdirname):
-                if not giturl in self._shellcmd("git remote -v", localdirname):
-                    raise BuildSetupException("Existing git repository at %s, but with different remotes (not '%s'). Aborting." % (localdirname, giturl))
+                localremotes = self._shellcmd("git remote -v", localdirname)
+                if not giturl in localremotes:
+                    raise BuildSetupException("Existing git repository at %s, but with different remotes ('%s', expected '%s'). Toaster will not continue out of fear of damaging something." % (localdirname, ", ".join(localremotes.split("\n")), giturl))
             else:
                 if giturl in cached_layers:
                     logger.debug("localhostbecontroller git-copying %s to %s" % (cached_layers[giturl], localdirname))
@@ -230,7 +252,7 @@ class LocalhostBEController(BuildEnvironmentController):
             # branch magic name "HEAD" will inhibit checkout
             if commit != "HEAD":
                 logger.debug("localhostbecontroller: checking out commit %s to %s " % (commit, localdirname))
-                self._shellcmd("git fetch --all && git checkout \"%s\"" % commit , localdirname)
+                self._shellcmd("git fetch --all && git checkout \"%s\" && git pull --rebase" % (commit) , localdirname)
 
             # take the localdirname as poky dir if we can find the oe-init-build-env
             if self.pokydirname is None and os.path.exists(os.path.join(localdirname, "oe-init-build-env")):
diff --git a/lib/toaster/bldcontrol/sshbecontroller.py b/lib/toaster/bldcontrol/sshbecontroller.py
index be797c9..11ad08d 100644
--- a/lib/toaster/bldcontrol/sshbecontroller.py
+++ b/lib/toaster/bldcontrol/sshbecontroller.py
@@ -29,7 +29,7 @@ import subprocess
 
 from toastermain import settings
 
-from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, _get_git_clonedirectory
+from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException
 
 def DN(path):
     return "/".join(path.split("/")[0:-1])
diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 5eff955..454f369 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -103,7 +103,7 @@ 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))
+        queryset = Layer_Version.objects.filter((Q(up_branch__name = release.branch_name) & Q(project = None)) | Q(project = self) | Q(build__project = self))
         if layer_name is not None:
             # we select only a layer name
             queryset = queryset.filter(layer__name = layer_name)
@@ -952,11 +952,24 @@ class Layer_Version(models.Model):
         """ Returns an ordered layerversion list that satisfies a LayerVersionDependency using the layer name and the current Project Releases' LayerSource priority """
         def _get_ls_priority(ls):
             try:
+                # if there is no layer source, we have minus infinite priority, as we don't want this layer selected
+                if ls == None:
+                    return -10000
                 return ls.releaselayersourcepriority_set.get(release=project.release).priority
             except ReleaseLayerSourcePriority.DoesNotExist:
                 raise
+
+        # layers created for this project, or coming from a build inthe project
+        query = Q(project = project) | Q(build__project = project)
+        if self.up_branch is not None:
+            # the same up_branch name
+            query |= Q(up_branch__name=self.up_branch.name)
+        else:
+            # or we have a layer in the project that's similar to mine (See the layer.name constraint below)
+            query |= Q(projectlayer__project=project)
+
         return sorted(
-                Layer_Version.objects.filter( layer__name = self.layer.name, up_branch__name = self.up_branch.name ),
+                Layer_Version.objects.filter(layer__name = self.layer.name).filter(query).select_related('layer_source', 'layer'),
                 key = lambda x: _get_ls_priority(x.layer_source),
                 reverse = True)
 
@@ -965,10 +978,12 @@ class Layer_Version(models.Model):
             return self.commit
         if self.branch is not None and len(self.branch) > 0:
             return self.branch
-        return self.up_branch.name
+        if self.up_branch is not None:
+            return self.up_branch.name
+        raise Exception("Cannot determine the vcs_reference for layer version %s" % vars(self))
 
     def __unicode__(self):
-        return  str(self.layer) + " (" + self.commit +")"
+        return  str(self.layer) + "(%s,%s)" % (self.get_vcs_reference(), self.build.project if self.build is not None else "None")
 
     class Meta:
         unique_together = ("layer_source", "up_id")
diff --git a/lib/toaster/orm/tests.py b/lib/toaster/orm/tests.py
index b965d8e..7b1b963 100644
--- a/lib/toaster/orm/tests.py
+++ b/lib/toaster/orm/tests.py
@@ -2,6 +2,12 @@ from django.test import TestCase
 from orm.models import LocalLayerSource, LayerIndexLayerSource, ImportedLayerSource, LayerSource
 from orm.models import Branch
 
+from orm.models import Project, Build, Layer, Layer_Version, Branch, ProjectLayer
+from orm.models import Release, ReleaseLayerSourcePriority, BitbakeVersion
+
+from django.utils import timezone
+
+# tests to verify inheritance for the LayerSource proxy-inheritance classes
 class LayerSourceVerifyInheritanceSaveLoad(TestCase):
     def test_object_creation(self):
         lls = LayerSource.objects.create(name = "a1", sourcetype = LayerSource.TYPE_LOCAL, apiurl = "")
@@ -23,7 +29,7 @@ class LayerSourceVerifyInheritanceSaveLoad(TestCase):
         self.assertRaises(Exception, duplicate)
 
 
-
+# test to verify the layer source update functionality for layerindex. edit to pass the URL to a layerindex application
 class LILSUpdateTestCase(TestCase):
     def test_update(self):
         lils = LayerSource.objects.create(name = "b1", sourcetype = LayerSource.TYPE_LAYERINDEX, apiurl = "http://adamian-desk.local:8080/layerindex/api/")
@@ -34,3 +40,126 @@ class LILSUpdateTestCase(TestCase):
 
         # print vars(lils)
         #print map(lambda x: vars(x), Branch.objects.all())
+
+        # run asserts
+        self.assertTrue(lils.branch_set.all().count() > 0, "update() needs to fetch some branches")
+
+
+
+# tests to verify layer_version priority selection
+class LayerVersionEquivalenceTestCase(TestCase):
+    def setUp(self):
+        # create layer sources
+        ls = LayerSource.objects.create(name = "dummy-layersource", sourcetype = LayerSource.TYPE_LOCAL)
+
+        # create bitbake version
+        bbv = BitbakeVersion.objects.create(name="master", giturl="git://git.openembedded.org/bitbake")
+        # create release
+        release = Release.objects.create(name="default-release", bitbake_version = bbv, branch_name = "master")
+        # attach layer source to release
+        ReleaseLayerSourcePriority.objects.create(release = release, layer_source = ls, priority = 1)
+
+        # create layer attach
+        self.layer = Layer.objects.create(name="meta-testlayer", layer_source = ls)
+        # create branch
+        self.branch = Branch.objects.create(name="master", layer_source = ls)
+
+        # set a layer version for the layer on the specified branch
+        self.layerversion = Layer_Version.objects.create(layer = self.layer, layer_source = ls, up_branch = self.branch)
+
+        # create spoof layer that should not appear in the search results
+        Layer_Version.objects.create(layer = Layer.objects.create(name="meta-notvalid", layer_source = ls), layer_source = ls, up_branch = self.branch)
+
+
+        # create a project ...
+        self.project = Project.objects.create_project(name="test-project", release = release)
+        # ... and set it up with a single layer version
+        ProjectLayer.objects.create(project=  self.project, layercommit = self.layerversion)
+
+    def test_single_layersource(self):
+        # when we have a single layer version, get_equivalents_wpriority() should return a list with just this layer_version
+        equivalent_list = self.layerversion.get_equivalents_wpriority(self.project)
+        self.assertTrue(len(equivalent_list) == 1)
+        self.assertTrue(equivalent_list[0] == self.layerversion)
+
+    def test_dual_layersource(self):
+        # if we have two layers with the same name, from different layer sources, we expect both layers in, in increasing priority of the layer source
+        ls2 = LayerSource.objects.create(name = "dummy-layersource2", sourcetype = LayerSource.TYPE_LOCAL)
+
+        # assign a lower priority for the second layer source
+        Release.objects.get(name="default-release").releaselayersourcepriority_set.create(layer_source = ls2, priority = 2)
+
+        # create a new layer_version for a layer with the same name coming from the second layer source
+        self.layer2 = Layer.objects.create(name="meta-testlayer", layer_source = ls2)
+        self.layerversion2 = Layer_Version.objects.create(layer = self.layer2, layer_source = ls2, up_branch = self.branch)
+
+        # expect two layer versions, in the priority order
+        equivalent_list = self.layerversion.get_equivalents_wpriority(self.project)
+        self.assertTrue(len(equivalent_list) == 2)
+        self.assertTrue(equivalent_list[0] == self.layerversion2)
+        self.assertTrue(equivalent_list[1] == self.layerversion)
+
+    def test_build_layerversion(self):
+        # any layer version coming from the build should show up before any layer version coming from upstream
+        build = Build.objects.create(project = self.project, started_on = timezone.now(), completed_on = timezone.now())
+        self.layerversion_build = Layer_Version.objects.create(layer = self.layer, build = build, commit = "deadbeef")
+
+        # a build layerversion must be in the equivalence list for the original layerversion
+        equivalent_list = self.layerversion.get_equivalents_wpriority(self.project)
+        self.assertTrue(len(equivalent_list) == 2)
+        self.assertTrue(equivalent_list[0] == self.layerversion)
+        self.assertTrue(equivalent_list[1] == self.layerversion_build)
+
+        # getting the build layerversion equivalent list must return the same list as the original layer
+        build_equivalent_list = self.layerversion_build.get_equivalents_wpriority(self.project)
+
+        self.assertTrue(equivalent_list == build_equivalent_list, "%s is not %s" % (equivalent_list, build_equivalent_list))
+
+class ProjectLVSelectionTestCase(TestCase):
+    def setUp(self):
+        # create layer sources
+        ls = LayerSource.objects.create(name = "dummy-layersource", sourcetype = LayerSource.TYPE_LOCAL)
+
+        # create bitbake version
+        bbv = BitbakeVersion.objects.create(name="master", giturl="git://git.openembedded.org/bitbake")
+        # create release
+        release = Release.objects.create(name="default-release", bitbake_version = bbv, branch_name="master")
+        # attach layer source to release
+        ReleaseLayerSourcePriority.objects.create(release = release, layer_source = ls, priority = 1)
+
+        # create layer attach
+        self.layer = Layer.objects.create(name="meta-testlayer", layer_source = ls)
+        # create branch
+        self.branch = Branch.objects.create(name="master", layer_source = ls)
+
+        # set a layer version for the layer on the specified branch
+        self.layerversion = Layer_Version.objects.create(layer = self.layer, layer_source = ls, up_branch = self.branch)
+
+
+        # create a project ...
+        self.project = Project.objects.create_project(name="test-project", release = release)
+        # ... and set it up with a single layer version
+        ProjectLayer.objects.create(project=  self.project, layercommit = self.layerversion)
+
+    def test_single_layersource(self):
+        compatible_layerversions = self.project.compatible_layerversions()
+        self.assertTrue(len(compatible_layerversions) == 1)
+        self.assertTrue(compatible_layerversions[0] == self.layerversion)
+
+
+    def test_dual_layersource(self):
+         # if we have two layers with the same name, from different layer sources, we expect both layers in, in increasing priority of the layer source
+        ls2 = LayerSource.objects.create(name = "dummy-layersource2", sourcetype = LayerSource.TYPE_LOCAL)
+
+        # assign a lower priority for the second layer source
+        Release.objects.get(name="default-release").releaselayersourcepriority_set.create(layer_source = ls2, priority = 2)
+
+        # create a new layer_version for a layer with the same name coming from the second layer source
+        self.layer2 = Layer.objects.create(name="meta-testlayer", layer_source = ls2)
+        self.layerversion2 = Layer_Version.objects.create(layer = self.layer2, layer_source = ls2, up_branch = self.branch)
+
+         # expect two layer versions, in the priority order
+        equivalent_list = self.project.compatible_layerversions()
+        self.assertTrue(len(equivalent_list) == 2)
+        self.assertTrue(equivalent_list[0] == self.layerversion2)
+        self.assertTrue(equivalent_list[1] == self.layerversion)
diff --git a/lib/toaster/toastergui/templates/targets.html b/lib/toaster/toastergui/templates/targets.html
index 590ecb9..3038649 100644
--- a/lib/toaster/toastergui/templates/targets.html
+++ b/lib/toaster/toastergui/templates/targets.html
@@ -52,11 +52,11 @@
         </td>
         <td class="target-section">{{o.section}}</td>
         <td class="license">{{o.license}}</td>
-        <td class="layer"><a href="{% url 'layerdetails' o.layer_version.id%}">{{o.layer_version.layer.name}}</a></td>
-        <td class="source">{{o.layer_source.name}}</td>
+        <td class="layer"><a href="{% url 'layerdetails' o.preffered_layerversion.id%}">{{o.preffered_layerversion.layer.name}}</a></td>
+        <td class="source">{{o.preffered_layerversion.layer_source.name}}</td>
         <td class="branch">
-        {% if o.layer_version.up_branch %}
-            {{o.layer_version.up_branch.name}}
+        {% if o.preffered_layerversion.up_branch %}
+            {{o.preffered_layerversion.up_branch.name}}
         {% else %}
         <a class="btn"
                 data-content="<ul class='unstyled'>
@@ -66,15 +66,15 @@
             </a>
             {% endif %}
         </td>
-        <td class="add-layer" value="{{o.pk}}" layerversion_id="{{o.layer_version.pk}}">
+        <td class="add-layer" value="{{o.pk}}" layerversion_id="{{o.preffered_layerversion.pk}}">
             <div id="layer-tooltip-{{o.pk}}" style="display: none; font-size: 11px; line-height: 1.3;" class="tooltip-inner">layer was modified</div>
             <a href="{% url 'project' project.id %}#/targetbuild={{o.name}}" id="target-build-{{o.pk}}" class="btn btn-block remove-layer" style="display:none;" >
                 Build target
             </a>
-            <a id="layer-add-{{o.pk}}" class="btn btn-block" style="display:none;" href="javascript:layerAdd({{o.layer_version.pk}}, '{{o.layer_version.layer.name}}', '{%url 'layerdetails' o.layer_version.pk%}', {{o.pk}})" >
+            <a id="layer-add-{{o.pk}}" class="btn btn-block" style="display:none;" href="javascript:layerAdd({{o.preffered_layerversion.pk}}, '{{o.preffered_layerversion.layer.name}}', '{%url 'layerdetails' o.preffered_layerversion.pk%}', {{o.pk}})" >
                 <i class="icon-plus"></i>
                 Add layer
-                <i title="" class="icon-question-sign get-help" data-original-title="To build this target, you must first add the {{o.layer_version.layer.name}} layer to your project"></i>
+                <i title="" class="icon-question-sign get-help" data-original-title="To build this target, you must first add the {{o.preffered_layerversion.layer.name}} layer to your project"></i>
             </a>
         </td>
     </tr>
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 6ccbf54..7353844 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -22,7 +22,7 @@
 import operator,re
 import HTMLParser
 
-from django.db.models import Q, Sum, Count
+from django.db.models import 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
@@ -236,7 +236,7 @@ def _get_queryset(model, queryset, filter_string, search_term, ordering_string,
     if search_term:
         queryset = _get_search_results(search_term, queryset, model)
 
-    if ordering_string and queryset:
+    if ordering_string:
         column, order = ordering_string.split(':')
         if column == re.sub('-','',ordering_secondary):
             ordering_secondary=''
@@ -2046,7 +2046,7 @@ if toastermain.settings.MANAGED:
                         "url": x.layercommit.layer.layer_index_url,
                         "layerdetailurl": reverse("layerdetails", args=(x.layercommit.pk,)),
                 # This branch name is actually the release
-                        "branch" : { "name" : x.layercommit.commit, "layersource" : x.layercommit.up_branch.layer_source.name}},
+                        "branch" : { "name" : x.layercommit.commit, "layersource" : x.layercommit.up_branch.layer_source.name if x.layercommit.up_branch != None else None}},
                     prj.projectlayer_set.all().order_by("id")),
             "targets" : map(lambda x: {"target" : x.target, "task" : x.task, "pk": x.pk}, prj.projecttarget_set.all()),
             "freqtargets": freqtargets,
@@ -2243,11 +2243,11 @@ if toastermain.settings.MANAGED:
 
             # returns layer versions that provide the named targets
             if request.GET['type'] == "layers4target":
-                # we returnd ata only if the recipe can't be provided by the current project layer set
-                if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name="anki").count() for x in prj.projectlayer_equivalent_set()], 0):
+                # we return data only if the recipe can't be provided by the current project layer set
+                if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name=request.GET['value']).count() for x in prj.projectlayer_equivalent_set()], 0):
                     final_list = []
                 else:
-                    queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET.get('value', '__none__'))
+                    queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET['value'])
 
                     # exclude layers in the project
                     queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()])
@@ -2259,14 +2259,20 @@ if toastermain.settings.MANAGED:
 
             # returns targets provided by current project layers
             if request.GET['type'] == "targets":
-                queryset_all = Recipe.objects.all()
+                queryset_all = Recipe.objects.filter(name__icontains=request.GET.get('value',''))
                 layer_equivalent_set = []
                 for i in prj.projectlayer_set.all():
                     layer_equivalent_set += i.layercommit.get_equivalents_wpriority(prj)
                 queryset_all = queryset_all.filter(layer_version__in =  layer_equivalent_set)
+
+                # if we have more than one hit here (for distinct name and version), max the id it out
+                queryset_all_maxids = queryset_all.values('name').distinct().annotate(max_id=Max('id')).values_list('max_id')
+                queryset_all = queryset_all.filter(id__in = queryset_all_maxids)
+
+
                 return HttpResponse(jsonfilter({ "error":"ok",
-                    "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name+ (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")},
-                        queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]),
+                    "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name + (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")},
+                        queryset_all[:8]),
 
                     }), content_type = "application/json")
 
@@ -2663,10 +2669,17 @@ if toastermain.settings.MANAGED:
 
         queryset_with_search = _get_queryset(Recipe, queryset_all, None, search_term, ordering_string, '-name')
 
-        queryset_with_search.prefetch_related("layer_source")
+        # get unique values for 'name' and 'version', and select the maximum ID for each entry (the max id is the newest one)
+        queryset_with_search_maxids = queryset_with_search.values('name').distinct().annotate(max_id=Max('id')).values_list('max_id')
+
+        queryset_with_search = queryset_with_search.filter(id__in=queryset_with_search_maxids).select_related('layer_version', 'layer_version__layer')
+
+        objects = list(queryset_with_search)
+        for e in objects:
+            e.preffered_layerversion = e.layer_version.get_equivalents_wpriority(prj)[0]
 
         # retrieve the objects that will be displayed in the table; targets a paginator and gets a page range to display
-        target_info = _build_page_range(Paginator(queryset_with_search, request.GET.get('count', 10)),request.GET.get('page', 1))
+        target_info = _build_page_range(Paginator(objects, request.GET.get('count', 10)),request.GET.get('page', 1))
 
 
         context = {
diff --git a/lib/toaster/toastermain/urls.py b/lib/toaster/toastermain/urls.py
index a2916e2..6112067 100644
--- a/lib/toaster/toastermain/urls.py
+++ b/lib/toaster/toastermain/urls.py
@@ -48,6 +48,11 @@ import toastermain.settings
 if toastermain.settings.FRESH_ENABLED:
     urlpatterns.insert(1, url(r'', include('fresh.urls')))
 
+if toastermain.settings.DEBUG_PANEL_ENABLED:
+    import debug_toolbar
+    urlpatterns.insert(1, url(r'', include(debug_toolbar.urls)))
+
+
 if toastermain.settings.MANAGED:
     urlpatterns = [
         # Uncomment the next line to enable the admin:
-- 
1.9.1



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

* [PATCH 07/27] toaster: enhancements for the startup sequence
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (5 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 06/27] toastergui: improvements in layer selection logic Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 08/27] toaster: improve logging facilities for toaster Alex DAMIAN
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

This patch brings fixes and enhancements in the startup sequence.

- the dependency version checking is now correctly enforced when
starting in both modes
- fixed errors in looking up environment variables
- added message with 'daemon' program start location
- presenting menu for selecting config file

[YOCTO #7283]
[YOCTO #7291]
[YOCTO #7273]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 bin/toaster                                        | 37 +++++++----
 .../management/commands/checksettings.py           | 76 +++++++++++++++++-----
 2 files changed, 84 insertions(+), 29 deletions(-)

diff --git a/bin/toaster b/bin/toaster
index 6f7c6f0..c3b8633 100755
--- a/bin/toaster
+++ b/bin/toaster
@@ -126,17 +126,20 @@ function notify_chldexit() {
 }
 
 
-# Verify prerequisites
+function verify_prereq() {
+	# Verify prerequisites
 
-if ! echo "import django; print (1,) == django.VERSION[0:1] and django.VERSION[1:2][0] in (5,6)" | python 2>/dev/null | grep True >/dev/null; then
-    echo -e "This program needs Django 1.5 or 1.6. Please install with\n\npip install django==1.6"
-    return 2
-fi
+    if ! echo "import django; print (1,) == django.VERSION[0:1] and django.VERSION[1:2][0] in (5,6)" | python 2>/dev/null | grep True >/dev/null; then
+        echo -e "This program needs Django 1.5 or 1.6. Please install with\n\npip install django==1.6\n"
+        return 2
+    fi
 
-if ! echo "import south; print [0,8,4] ==  map(int,south.__version__.split(\".\"))" | python 2>/dev/null | grep True >/dev/null; then
-    echo -e "This program needs South 0.8.4. Please install with\n\npip install south==0.8.4"
-    return 2
-fi
+    if ! echo "import south; print reduce(lambda x, y: 2 if x==2 else 0 if x == 0 else y, map(lambda x: 1+cmp(x[1]-x[0],0), zip([0,8,4], map(int,south.__version__.split(\".\"))))) > 0" | python 2>/dev/null | grep True >/dev/null; then
+        echo -e "This program needs South 0.8.4. Please install with\n\npip install south==0.8.4\n"
+        return 2
+    fi
+    return 0
+}
 
 
 # read command line parameters
@@ -170,13 +173,18 @@ if [ -z "$ZSH_NAME" ] && [ `basename \"$0\"` = `basename \"$BASH_SOURCE\"` ]; th
     # We are called as standalone. We refuse to run in a build environment - we need the interactive mode for that.
     # Start just the web server, point the web browser to the interface, and start any Django services.
 
+    if ! verify_prereq; then
+        echo -e "Error: Could not verify that the needed dependencies are installed. Please use virtualenv and pip to install dependencies listed in toaster-requirements.txt" 1>&2;
+        exit 1;
+    fi
+
     if [ -n "$BUILDDIR" ]; then
-	echo -e "Error: It looks like you sourced oe-init-build-env. Toaster cannot start in build mode from an oe-core build environment. You can work around this problem by starting Toaster from a new terminal window." 1>&2;
+	echo -e "Error: It looks like you sourced oe-init-build-env. Toaster cannot start in build mode from an oe-core build environment.\n You should be starting Toaster from a new terminal window." 1>&2;
         exit 1;
     fi
 
     if [ "x`which daemon`" == "x" ]; then
-        echo -e "Failed dependency; toaster needs the 'daemon' program in order to be able to start builds'. Please install the 'daemon' program." 1>&2;
+        echo -e "Failed dependency; toaster needs the 'daemon' program in order to be able to start builds'. Please install the 'daemon' program from your distribution repositories or http://www.libslack.org/daemon/" 1>&2;
 	exit 1;
     fi
 
@@ -208,6 +216,13 @@ if [ -z "$ZSH_NAME" ] && [ `basename \"$0\"` = `basename \"$BASH_SOURCE\"` ]; th
     exit 0
 fi
 
+
+if ! verify_prereq; then
+	echo -e "Error: Could not verify that the needed dependencies are installed. Please use virtualenv and pip to install dependencies listed in toaster-requirements.txt" 1>&2;
+	return 1;
+fi
+
+
 # We make sure we're running in the current shell and in a good environment
 if [ -z "$BUILDDIR" ] || [ -z `which bitbake` ]; then
     echo "Error: Build environment is not setup or bitbake is not in path." 1>&2;
diff --git a/lib/toaster/bldcontrol/management/commands/checksettings.py b/lib/toaster/bldcontrol/management/commands/checksettings.py
index cf3c3d7..5d80bc7 100644
--- a/lib/toaster/bldcontrol/management/commands/checksettings.py
+++ b/lib/toaster/bldcontrol/management/commands/checksettings.py
@@ -78,44 +78,68 @@ class Command(NoArgsCommand):
 
         # we make sure we have builddir and sourcedir for all defined build envionments
         for be in BuildEnvironment.objects.all():
+            be.needs_import = False
             def _verify_be():
                 is_changed = False
-                print("Verifying the Build Environment. If the Build Environment is completly configured, you will be asked to configure it.")
-                if len(be.sourcedir) == 0:
+                print("Verifying the Build Environment. If the local Build Environment is not properly configured, you will be asked to configure it.")
+
+                def _update_sourcedir():
                     suggesteddir = self._get_suggested_sourcedir(be)
                     if len(suggesteddir) > 0:
-                        be.sourcedir = raw_input("\nToaster needs to know in which directory it should check out the layers that will be needed for your builds.\n Toaster suggests \"%s\". If you select this directory, a layer like \"meta-yocto\" will end up in \"%s/meta-yocto\".\n Press Enter to select \"%s\" or type the full path to a different directory: " % (suggesteddir, suggesteddir, suggesteddir))
+                        be.sourcedir = raw_input("Toaster needs to know in which directory it should check out the layers that will be needed for your builds.\n Toaster suggests \"%s\". If you select this directory, a layer like \"meta-intel\" will end up in \"%s/meta-intel\".\n Press Enter to select \"%s\" or type the full path to a different directory (must be a parent of current checkout directory): " % (suggesteddir, suggesteddir, suggesteddir))
                     else:
-                        be.sourcedir = raw_input("\nToaster needs to know in which directory it should check out the layers that will be needed for your builds. Type the full path to the directory (for example: \"%s\": " % os.environment['HOME'])
+                        be.sourcedir = raw_input("Toaster needs to know in which directory it should check out the layers that will be needed for your builds. Type the full path to the directory (for example: \"%s\": " % os.environ.get('HOME', '/tmp/'))
                     if len(be.sourcedir) == 0 and len(suggesteddir) > 0:
                         be.sourcedir = suggesteddir
-                    is_changed = True
+                    return True
+
+                if len(be.sourcedir) == 0:
+                    print "\n -- Validation: The checkout directory must be set."
+                    is_changed = _update_sourcedir()
 
                 if not be.sourcedir.startswith("/"):
-                    be.sourcedir = raw_input(" Layer sources checkout directory must be an absolute path:")
-                    is_changed = True
+                    print "\n -- Validation: The checkout directory must be set to an absolute path."
+                    is_changed = _update_sourcedir()
 
-                if len(be.builddir) == 0:
+                if not be.sourcedir in DN(__file__):
+                    print "\n -- Validation: The checkout directory must be a parent of the current checkout."
+                    is_changed = _update_sourcedir()
+
+                if is_changed:
+                    if be.betype == BuildEnvironment.TYPE_LOCAL:
+                        be.needs_import = True
+                    return True
+
+                def _update_builddir():
                     suggesteddir = self._get_suggested_builddir(be)
                     if len(suggesteddir) > 0:
-                        be.builddir = raw_input("\nToaster needs to know where is your build directory.\n The build directory is where all the artifacts created by your builds will be stored. Toaster suggests \"%s\".\n Press Enter to select \"%s\" or type the full path to a different directory: " % (suggesteddir, suggesteddir))
+                        be.builddir = raw_input("Toaster needs to know where it your build directory is located.\n The build directory is where all the artifacts created by your builds will be stored. Toaster suggests \"%s\".\n Press Enter to select \"%s\" or type the full path to a different directory: " % (suggesteddir, suggesteddir))
                     else:
-                        be.builddir = raw_input("\nToaster needs to know where is your build directory.\n The build directory is where all the artifacts created by your builds will be stored. Type the full path to the directory (for example: \" %s/build\")" % os.environment['HOME'])
+                        be.builddir = raw_input("Toaster needs to know where is your build directory.\n The build directory is where all the artifacts created by your builds will be stored. Type the full path to the directory (for example: \" %s/build\")" % os.environ.get('HOME','/tmp/'))
                     if len(be.builddir) == 0 and len(suggesteddir) > 0:
                         be.builddir = suggesteddir
-                    is_changed = True
+                    return True
+
+                if len(be.builddir) == 0:
+                    print "\n -- Validation: The build directory must be set."
+                    is_changed = _update_builddir()
 
                 if not be.builddir.startswith("/"):
-                    be.builddir = raw_input(" Build directory must be an absolute path:")
-                    is_changed = True
+                    print "\n -- Validation: The build directory must to be set to an absolute path."
+                    is_changed = _update_builddir()
 
 
                 if is_changed:
                     print "Build configuration saved"
                     be.save()
+                    return True
+
+
+                if be.needs_import:
+                    print "\nToaster can use a SINGLE predefined configuration file to set up default project settings and layer information sources.\n"
 
-                if is_changed and be.betype == BuildEnvironment.TYPE_LOCAL:
-                    print "\nToaster can use a SINGLE predefined configuration file to set up default project settings and layer information sources.\n Toaster will list now the configuration files that it found. Select Yes to use the desired configuration file."
+                    # find configuration files
+                    config_files = []
                     for dirname in self._recursive_list_directories(be.sourcedir,2):
                         if os.path.exists(os.path.join(dirname, ".templateconf")):
                             import subprocess
@@ -123,11 +147,20 @@ class Command(NoArgsCommand):
                             conffilepath = os.path.join(conffilepath.strip(), "toasterconf.json")
                             candidatefilepath = os.path.join(dirname, conffilepath)
                             if os.path.exists(candidatefilepath):
-                                i = raw_input("\n Found an preset configuration file \"%s\".\n Do you want to use it? (y/N):" % candidatefilepath)
-                                if len(i) and i.upper()[0] == 'Y':
+                                config_files.append(candidatefilepath)
+
+                    if len(config_files) > 0:
+                        print " Toaster will list now the configuration files that it found. Select the number to use the desired configuration file."
+                        for cf in config_files:
+                            print "  [%d] - %s" % (config_files.index(cf) + 1, cf)
+                        print "\n  [0] - Exit without importing any file"
+                        try:
+                                i = raw_input("\n Enter your option: ")
+                                if len(i) and (int(i) - 1 >= 0 and int(i) - 1 < len(config_files)):
+                                    print "Importing file: %s" % config_files[int(i)-1]
                                     from loadconf import Command as LoadConfigCommand
 
-                                    LoadConfigCommand()._import_layer_config(candidatefilepath)
+                                    LoadConfigCommand()._import_layer_config(config_files[int(i)-1])
                                     # we run lsupdates after config update
                                     print "Layer configuration imported. Updating information from the layer sources, please wait.\n You can re-update any time later by running bitbake/lib/toaster/manage.py lsupdates"
                                     from django.core.management import call_command
@@ -135,6 +168,13 @@ class Command(NoArgsCommand):
 
                                     # we don't look for any other config files
                                     return is_changed
+                        except Exception as e:
+                            print "Failure while trying to import the toaster config file: %s" % e
+                    else:
+                        print "\n Toaster could not find a configuration file. You need to configure Toaster manually using the web interface, or create a configuration file and use\n  bitbake/lib/toaster/managepy.py loadconf [filename]\n command to load it. You can use https://wiki.yoctoproject.org/wiki/File:Toasterconf.json.txt.patch as a starting point."
+
+
+
 
                 return is_changed
 
-- 
1.9.1



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

* [PATCH 08/27] toaster: improve logging facilities for toaster
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (6 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 07/27] toaster: enhancements for the startup sequence Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 09/27] toaster: display Toaster mode and version in debug mode Alex DAMIAN
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

This patch improves the logging facilities for toaster in order
to help diagnose bugs that happen on user machines.

The logs are stored now under "/tmp/toaster_$$" where $$ is a
PID-based unique identifier. On shutdown, toaster will automatically
erase all logs unless errors are listed in the log file.

On error, Toaster provides suggestions on what to do.

This patch includes a minor fix found as a result of logging
improvements.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 bin/toaster                                        | 41 +++++++++++++++----
 lib/bb/ui/buildinfohelper.py                       | 47 ++++++++++++++++------
 .../bldcontrol/management/commands/runbuilds.py    |  2 +-
 lib/toaster/toastergui/views.py                    |  2 +-
 lib/toaster/toastermain/settings.py                |  6 +--
 lib/toaster/toastermain/urls.py                    | 18 ++++++++-
 6 files changed, 91 insertions(+), 25 deletions(-)

diff --git a/bin/toaster b/bin/toaster
index c3b8633..04f2e99 100755
--- a/bin/toaster
+++ b/bin/toaster
@@ -69,7 +69,7 @@ function webserverStartAll()
 	fi
         if [ $retval -eq 0 ]; then
 	    echo "Starting webserver..."
-            python $BBBASEDIR/lib/toaster/manage.py runserver "0.0.0.0:$WEB_PORT" </dev/null >${BUILDDIR}/toaster_web_$$.log 2>&1 & echo $! >${BUILDDIR}/.toastermain.pid
+            python $BBBASEDIR/lib/toaster/manage.py runserver "0.0.0.0:$WEB_PORT" </dev/null >>${BUILDDIR}/toaster_web.log 2>&1 & echo $! >${BUILDDIR}/.toastermain.pid
             sleep 1
             if ! cat "${BUILDDIR}/.toastermain.pid" | xargs -I{} kill -0 {} ; then
                 retval=1
@@ -189,17 +189,43 @@ if [ -z "$ZSH_NAME" ] && [ `basename \"$0\"` = `basename \"$BASH_SOURCE\"` ]; th
     fi
 
     # Define a fake builddir where only the pid files are actually created. No real builds will take place here.
-    BUILDDIR=/tmp
+    BUILDDIR=/tmp/toaster_$$
+    if [ -d "$BUILDDIR" ]; then
+        echo -e "Previous toaster run directory $BUILDDIR found, cowardly refusing to start. Please remove the directory when that toaster instance is over" 2>&1
+        exit 1;
+    fi
+
+    mkdir -p "$BUILDDIR"
+
     RUNNING=1
     function trap_ctrlc() {
         echo "** Stopping system"
         webserverKillAll
         RUNNING=0
     }
+
+    function do_cleanup() {
+        find "$BUILDDIR" -type f | xargs rm
+        rmdir "$BUILDDIR"
+    }
+    function cleanup() {
+        if grep -ir error "$BUILDDIR" >/dev/null; then
+            if grep -irn "That port is already in use" "$BUILDDIR"; then
+                echo "You can use the \"webport=PORTNUMBER\" parameter to start Toaster on a different port (port $WEB_PORT is already in use)"
+                do_cleanup
+            else
+                echo -e "\nErrors found in the Toaster log files present in '$BUILDDIR'. Directory will not be cleaned.\n Please review the errors and notify toaster@yoctoproject.org or submit a bug https://bugzilla.yoctoproject.org/enter_bug.cgi?product=Toaster"
+            fi
+        else
+            echo "No errors found, removing the run directory '$BUILDDIR'"
+            do_cleanup
+        fi;
+    }
     TOASTER_MANAGED=1
     export TOASTER_MANAGED=1
     if [ $WEBSERVER -gt 0 ] && ! webserverStartAll; then
         echo "Failed to start the web server, stopping" 1>&2;
+        cleanup
         exit 1;
     fi
     if [ $WEBSERVER -gt 0 ]; then
@@ -209,9 +235,10 @@ if [ -z "$ZSH_NAME" ] && [ `basename \"$0\"` = `basename \"$BASH_SOURCE\"` ]; th
     trap trap_ctrlc SIGINT
     echo "Toaster is now running. You can stop it with Ctrl-C"
     while [ $RUNNING -gt 0 ]; do
-	python $BBBASEDIR/lib/toaster/manage.py runbuilds
-	sleep 1
+        python $BBBASEDIR/lib/toaster/manage.py runbuilds 2>&1 | tee -a "$BUILDDIR/toaster.log"
+        sleep 1
     done
+    cleanup
     echo "**** Exit"
     exit 0
 fi
@@ -275,8 +302,8 @@ case $CMD in
         fi
         unset BBSERVER
         PREREAD=""
-        if [ -e conf/toaster-pre.conf ]; then
-                PREREAD="--read conf/toaster-pre.conf"
+        if [ -e ${BUILDDIR}/conf/toaster-pre.conf ]; then
+		rm ${BUILDDIR}/conf/toaster-pre.conf
         fi
         bitbake $PREREAD --postread conf/toaster.conf --server-only -t xmlrpc -B 0.0.0.0:0
         if [ $? -ne 0 ]; then
@@ -285,7 +312,7 @@ case $CMD in
         else
             export BBSERVER=0.0.0.0:-1
             if [ $NOTOASTERUI == 0 ]; then        # we start the TOASTERUI only if not inhibited
-                bitbake --observe-only -u toasterui >${BUILDDIR}/toaster_ui.log 2>&1 & echo $! >${BUILDDIR}/.toasterui.pid
+                bitbake --observe-only -u toasterui >>${BUILDDIR}/toaster_ui.log 2>&1 & echo $! >${BUILDDIR}/.toasterui.pid
             fi
         fi
         if [ $start_success -eq 1 ]; then
diff --git a/lib/bb/ui/buildinfohelper.py b/lib/bb/ui/buildinfohelper.py
index 4e2d4a7..491fd15 100644
--- a/lib/bb/ui/buildinfohelper.py
+++ b/lib/bb/ui/buildinfohelper.py
@@ -656,18 +656,41 @@ class BuildInfoHelper(object):
         assert path.startswith("/")
         assert 'build' in self.internal_state
 
-        def _slkey(layer_version):
-            assert isinstance(layer_version, Layer_Version)
-            return len(layer_version.layer.local_path)
-
-        # Heuristics: we always match recipe to the deepest layer path that
-        # we can match to the recipe file path
-        for bl in sorted(self.orm_wrapper.layer_version_objects, reverse=True, key=_slkey):
-            if (path.startswith(bl.layer.local_path)):
-                return bl
-
-        #if we get here, we didn't read layers correctly; mockup the new layer
-        unknown_layer, created = Layer.objects.get_or_create(name="unknown", local_path="/", layer_index_url="")
+        if self.brbe is None:
+            def _slkey_interactive(layer_version):
+                assert isinstance(layer_version, Layer_Version)
+                return len(layer_version.layer.local_path)
+
+            # Heuristics: we always match recipe to the deepest layer path in the discovered layers
+            for lvo in sorted(self.orm_wrapper.layer_version_objects, reverse=True, key=_slkey_interactive):
+                # we can match to the recipe file path
+                if path.startswith(lvo.layer.local_path):
+                    return lvo
+
+        else:
+            br_id, be_id = self.brbe.split(":")
+            from bldcontrol.bbcontroller import getBuildEnvironmentController
+            from bldcontrol.models import BuildRequest
+            bc = getBuildEnvironmentController(pk = be_id)
+
+            def _slkey_managed(layer_version):
+                return len(bc.getGitCloneDirectory(layer_version.giturl, layer_version.commit) + layer_version.dirpath)
+
+            # Heuristics: we match the path to where the layers have been checked out
+            for brl in sorted(BuildRequest.objects.get(pk = br_id).brlayer_set.all(), reverse = True, key = _slkey_managed):
+                localdirname = os.path.join(os.path.join(bc.be.sourcedir, bc.getGitCloneDirectory(brl.giturl, brl.commit)), brl.dirpath)
+                if path.startswith(localdirname):
+                    #logger.warn("-- managed: matched path %s with layer %s " % (path, localdirname))
+                    # we matched the BRLayer, but we need the layer_version that generated this br
+                    for lvo in self.orm_wrapper.layer_version_objects:
+                        if brl.name == lvo.layer.name:
+                            return lvo
+
+        #if we get here, we didn't read layers correctly; dump whatever information we have on the error log
+        logger.error("Could not match layer version for recipe path %s : %s" % (path, self.orm_wrapper.layer_version_objects))
+
+        #mockup the new layer
+        unknown_layer, created = Layer.objects.get_or_create(name="__FIXME__unidentified_layer", local_path="/", layer_index_url="")
         unknown_layer_version_obj, created = Layer_Version.objects.get_or_create(layer = unknown_layer, build = self.internal_state['build'])
 
         return unknown_layer_version_obj
diff --git a/lib/toaster/bldcontrol/management/commands/runbuilds.py b/lib/toaster/bldcontrol/management/commands/runbuilds.py
index 3b539b5..c4ab87b 100644
--- a/lib/toaster/bldcontrol/management/commands/runbuilds.py
+++ b/lib/toaster/bldcontrol/management/commands/runbuilds.py
@@ -68,7 +68,7 @@ class Command(NoArgsCommand):
                 task = None
             bbctrl.build(list(map(lambda x:x.target, br.brtarget_set.all())), task)
 
-            logger.debug("runbuilds: Build launched, exiting")
+            logger.debug("runbuilds: Build launched, exiting. Follow build logs at %s/toaster_ui.log" % bec.be.builddir)
             # disconnect from the server
             bbctrl.disconnect()
 
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 7353844..b67a676 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -3248,7 +3248,7 @@ else:
     def xhr_build(request, pid):
         raise Exception("page not available in interactive mode")
 
-    def xhr_projectinfo(request, pid):
+    def xhr_projectinfo(request):
         raise Exception("page not available in interactive mode")
 
     def xhr_projectedit(request, pid):
diff --git a/lib/toaster/toastermain/settings.py b/lib/toaster/toastermain/settings.py
index 7cf9052..ea7c353 100644
--- a/lib/toaster/toastermain/settings.py
+++ b/lib/toaster/toastermain/settings.py
@@ -344,7 +344,7 @@ LOGGING = {
     },
     'formatters': {
         'datetime': {
-            'format': '%(levelname)s %(asctime)s %(message)s'
+            'format': '%(asctime)s %(levelname)s %(message)s'
         }
     },
     'handlers': {
@@ -365,8 +365,8 @@ LOGGING = {
             'level': 'DEBUG',
         },
         'django.request': {
-            'handlers': ['mail_admins'],
-            'level': 'ERROR',
+            'handlers': ['console'],
+            'level': 'WARN',
             'propagate': True,
         },
     }
diff --git a/lib/toaster/toastermain/urls.py b/lib/toaster/toastermain/urls.py
index 6112067..f66f11d 100644
--- a/lib/toaster/toastermain/urls.py
+++ b/lib/toaster/toastermain/urls.py
@@ -23,6 +23,9 @@ from django.conf.urls import patterns, include, url
 from django.views.generic import RedirectView
 from django.views.decorators.cache import never_cache
 
+import logging
+
+logger = logging.getLogger("toaster")
 
 # Uncomment the next two lines to enable the admin:
 from django.contrib import admin
@@ -47,10 +50,12 @@ import toastermain.settings
 
 if toastermain.settings.FRESH_ENABLED:
     urlpatterns.insert(1, url(r'', include('fresh.urls')))
+    logger.info("Enabled django-fresh extension")
 
 if toastermain.settings.DEBUG_PANEL_ENABLED:
     import debug_toolbar
     urlpatterns.insert(1, url(r'', include(debug_toolbar.urls)))
+    logger.info("Enabled django_toolbar extension")
 
 
 if toastermain.settings.MANAGED:
@@ -70,4 +75,15 @@ for t in os.walk(os.path.dirname(currentdir)):
 
     if "urls.py" in t[2] and t[0] != currentdir:
         modulename = os.path.basename(t[0])
-        urlpatterns.insert(0, url(r'^' + modulename + '/', include ( modulename + '.urls')))
+        # make sure we don't have this module name in
+        conflict = False
+        for p in urlpatterns:
+            if p.regex.pattern == '^' + modulename + '/':
+                conflict = True
+        if not conflict:
+            urlpatterns.insert(0, url(r'^' + modulename + '/', include ( modulename + '.urls')))
+        else:
+            logger.warn("Module \'%s\' has a regexp conflict, was not added to the urlpatterns" % modulename)
+
+from pprint import pformat
+logger.debug("urlpatterns list %s", pformat(urlpatterns))
-- 
1.9.1



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

* [PATCH 09/27] toaster: display Toaster mode and version in debug mode
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (7 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 08/27] toaster: improve logging facilities for toaster Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 10/27] toastergui: set column heading to 'Revision' Alex DAMIAN
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

This patch displays the current running mode and checked-out git branch
as Toaster version when running in debug mode.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/static/css/default.css | 19 +++++++++++++++++++
 lib/toaster/toastergui/templates/base.html    |  6 ++++++
 lib/toaster/toastergui/views.py               |  8 ++++++--
 lib/toaster/toastermain/settings.py           |  5 +++--
 4 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/lib/toaster/toastergui/static/css/default.css b/lib/toaster/toastergui/static/css/default.css
index 1095254..a866773 100644
--- a/lib/toaster/toastergui/static/css/default.css
+++ b/lib/toaster/toastergui/static/css/default.css
@@ -2,6 +2,25 @@
 .logo img { height: 30px; width: auto !important; }
 .logo { padding-top: 4px !important; padding-bottom:0px !important; }
 
+/* style the version text */
+.version-text {
+	color: #AAA;
+	font-size: 0.6em;
+	display: table-footer-group;
+	padding: 0px;
+	margin: 1px 1px 1px 1px;
+}
+
+.version-brand, .version-brand:hover, a.version-brand:focus  {
+    color: #777;
+    display: block;
+    float: left;
+    font-size: 20px;
+    font-weight: 200;
+    padding: 00px 0px;
+    text-shadow: 0 1px 0 #fff;
+}
+
 /* Style the breadcrumb */
 .breadcrumb { display: inline-block; background-color: transparent; }
 .section { margin: 20px 0; }
diff --git a/lib/toaster/toastergui/templates/base.html b/lib/toaster/toastergui/templates/base.html
index e95b5e0..6f249bc 100644
--- a/lib/toaster/toastergui/templates/base.html
+++ b/lib/toaster/toastergui/templates/base.html
@@ -59,6 +59,12 @@
     <div class="navbar-inner">
             <a class="brand logo" href="#"><img src="{% static 'img/logo.png' %}" class="" alt="Yocto logo project"/></a>
             <a class="brand" href="/">Toaster</a>
+            {% if DEBUG %}
+            <div style="display: inline;" class="version-brand">
+              <p class="version-text">version {{TOASTER_VERSION}}</p>
+              <p class="version-text">{%if MANAGED%}managed{%else%}interactive{%endif%} mode</p>
+            </div>
+            {% endif %}
             <a class="pull-right manual" target="_blank" href="http://www.yoctoproject.org/documentation/toaster-manual">
                 <i class="icon-book"></i>
                 Toaster manual
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index b67a676..4b770ff 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1709,10 +1709,12 @@ if toastermain.settings.MANAGED:
 
     # the context processor that supplies data used across all the pages
     def managedcontextprocessor(request):
+        import subprocess
         ret = {
             "projects": Project.objects.all(),
             "MANAGED" : toastermain.settings.MANAGED,
-            "DEBUG" : toastermain.settings.DEBUG
+            "DEBUG" : toastermain.settings.DEBUG,
+            "TOASTER_VERSION": toastermain.settings.TOASTER_VERSION,
         }
         if 'project_id' in request.session:
             try:
@@ -3057,7 +3059,9 @@ else:
         return {
             "projects": [],
             "MANAGED" : toastermain.settings.MANAGED,
-            "DEBUG" : toastermain.settings.DEBUG
+            "DEBUG" : toastermain.settings.DEBUG,
+            "TOASTER_VERSION": toastermain.settings.TOASTER_VERSION,
+
         }
 
 
diff --git a/lib/toaster/toastermain/settings.py b/lib/toaster/toastermain/settings.py
index ea7c353..b6a42c0 100644
--- a/lib/toaster/toastermain/settings.py
+++ b/lib/toaster/toastermain/settings.py
@@ -211,8 +211,6 @@ MIDDLEWARE_CLASSES = (
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
-    'django.middleware.cache.UpdateCacheMiddleware',
-    'django.middleware.cache.FetchFromCacheMiddleware',
     # Uncomment the next line for simple clickjacking protection:
     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 )
@@ -233,6 +231,9 @@ CACHES = {
 from os.path import dirname as DN
 SITE_ROOT=DN(DN(os.path.abspath(__file__)))
 
+import subprocess
+TOASTER_VERSION = subprocess.Popen('cd %s; git branch | grep "^* " | tr -d "* "' % SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
 ROOT_URLCONF = 'toastermain.urls'
 
 # Python dotted path to the WSGI application used by Django's runserver.
-- 
1.9.1



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

* [PATCH 10/27] toastergui: set column heading to 'Revision'
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (8 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 09/27] toaster: display Toaster mode and version in debug mode Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 11/27] toastergui: add the word 'compatible' to 'all' pages Alex DAMIAN
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Replace the column heading 'Branch, tag or commit' with
'Revision'. This also fixes 7023.

[YOCTO #7023]

Signed-off-by: Belen Barros Pena <belen.barros.pena@intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/templates/layerdetails.html |  5 ++++-
 lib/toaster/toastergui/views.py                    | 10 ++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 4ffd071..6705215 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -142,7 +142,10 @@
                   <i id="change-subdir" class="icon-pencil"></i>
                   <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
                 </dd>
-                <dt>Brach, tag or commit</dt>
+                <dt>
+                  <i class="icon-question-sign get-help" title="The Git branch, tag or commit"></i>
+                  Revision
+                </dt>
                 <dd>
                   <span class="current-value">{{layerversion.commit}}</span>
                   <form style="display:none;">
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 4b770ff..9567e62 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2574,9 +2574,9 @@ if toastermain.settings.MANAGED:
                     'hidden': 1,
                     'qhelp': "The layer directory within the Git repository",
                 },
-                {   'name': 'Branch, tag o commit',
+                {   'name': 'Revision',
                     'clclass': 'branch',
-                    'qhelp': "The Git branch of the layer. For the layers from the OpenEmbedded source, the branch matches the Yocto Project version you selected for this project",
+                    'qhelp': "The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project",
                 },
                 {   'name': 'Dependencies',
                     'clclass': 'dependencies',
@@ -2740,8 +2740,9 @@ if toastermain.settings.MANAGED:
                         'options': map(lambda x: ("Targets provided by " + x.name + " layers", 'layer_source__pk:' + str(x.id), queryset_with_search.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()),
                     }
                 },
-                {   'name': 'Branch, tag or commit',
+                {   'name': 'Revision',
                     'clclass': 'branch',
+                    'qhelp': "The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project.",
                     'hidden': 1,
                 },
             ]
@@ -2827,8 +2828,9 @@ if toastermain.settings.MANAGED:
                         'options': map(lambda x: (x.name, 'layer_source__pk:' + str(x.id), queryset_with_search.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()),
                     }
                 },
-                {   'name': 'Branch, tag or commit',
+                {   'name': 'Revision',
                     'clclass': 'branch',
+                    'qhelp' : "The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project",
                     'hidden': 1,
                 },
                 {   'name': 'Select',
-- 
1.9.1



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

* [PATCH 11/27] toastergui: add the word 'compatible' to 'all' pages
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (9 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 10/27] toastergui: set column heading to 'Revision' Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 12/27] toastergui: add download task log icon to recipe details page Alex DAMIAN
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Labels for the 'all' pages don't really convey what's provided in them.
The team has suggested we add the word 'compatible' to them,
to make clear they will show all layers / targets / machines that
can be built with the version of the build system you are
using in a certain project. A link like 'view all targets'
becomes 'view all compatible targets'.

I've also added some help text.

Signed-off-by: Belen Barros Pena <belen.barros.pena@intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/static/css/default.css      |  2 +-
 lib/toaster/toastergui/templates/layerdetails.html |  2 +-
 lib/toaster/toastergui/templates/layers.html       |  6 +++---
 lib/toaster/toastergui/templates/machines.html     |  6 +++---
 lib/toaster/toastergui/templates/project.html      | 24 ++++++++++++++--------
 lib/toaster/toastergui/templates/targets.html      |  6 +++---
 6 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/lib/toaster/toastergui/static/css/default.css b/lib/toaster/toastergui/static/css/default.css
index a866773..41b73cc 100644
--- a/lib/toaster/toastergui/static/css/default.css
+++ b/lib/toaster/toastergui/static/css/default.css
@@ -34,7 +34,7 @@
 .get-help-yellow:hover { color: #B38942; cursor: pointer; }
 .get-help-red { color: #B94A48; font-size: 16px; padding-left: 2px; }
 .get-help-red:hover { color: #943A38; cursor: pointer; }
-.build-form .get-help { margin-left: 5px; }
+.build-form>i:first-of-type { margin-left: 5px; }
 .manual { margin: 11px 15px;}
 .heading-help { font-size: 14px; }
 
diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 6705215..7a1a22d 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -3,7 +3,7 @@
 {% load humanize %}
 {% load static %}
 {% block localbreadcrumb %}
-<li><a href="{% url 'layers' %}">All layers</a></li>
+<li><a href="{% url 'layers' %}">All compatible layers</a></li>
 <li>
   {{layerversion.layer.name}} ({{layerversion.commit|truncatechars:13}})
 </li>
diff --git a/lib/toaster/toastergui/templates/layers.html b/lib/toaster/toastergui/templates/layers.html
index 33160e5..0943c39 100644
--- a/lib/toaster/toastergui/templates/layers.html
+++ b/lib/toaster/toastergui/templates/layers.html
@@ -3,7 +3,7 @@
 {% load humanize %}
 
 {% block localbreadcrumb %}
-<li>Layers</li>
+<li>All compatible layers</li>
 {% endblock %}
 
 {% block projectinfomain %}
@@ -14,9 +14,9 @@
   {% elif request.GET.filter and total_count ==  0 or request.GET.search and total_count == 0 %}
       No layers found
   {%else%}
-      All layers
+      All compatible layers
   {%endif%}
-                        <i class="icon-question-sign get-help heading-help" title="This page lists all the layers compatible with {{project.release.name}} that Toaster knows about."></i>
+                        <i class="icon-question-sign get-help heading-help" title="This page lists all the layers compatible with the release selected for this project, which is {{project.release.description}}"></i>
                      </h1>
                 </div>
 
diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index 18e7485..e0bda51 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -3,14 +3,14 @@
 {% load humanize %}
 
 {% block localbreadcrumb %}
-<li>Machines</li>
+<li>All compatible machines</li>
 {% endblock %}
 
 {% block projectinfomain %}
                 <div class="page-header">
                     <h1>
-                        All machines
-                        <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with Yocto Project 1.7 'Dxxxx' that Toaster knows about. They include community-created targets suitable for use on top of OpenEmbedded Core and any targets you have imported"></i>
+                        All compatible machines
+                        <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with the release selected for this project, which is {{project.release.description}}"></i>
                      </h1>
                 </div>
                 <!--div class="alert">
diff --git a/lib/toaster/toastergui/templates/project.html b/lib/toaster/toastergui/templates/project.html
index 3b75d19..2c9cd81 100644
--- a/lib/toaster/toastergui/templates/project.html
+++ b/lib/toaster/toastergui/templates/project.html
@@ -1,4 +1,4 @@
-{% extends "baseprojectpage.html" %}
+ {% extends "baseprojectpage.html" %}
 <!--
 vim: expandtab tabstop=2
 -->
@@ -98,9 +98,8 @@ vim: expandtab tabstop=2
       </div>
       <i class="icon-question-sign get-help get-help-blue" title="Type the name of one or more targets you want to build, separated by a space. You can also specify a task by appending a semicolon and a task name to a target name, like so: <code>core-image-minimal:do_build</code>"></i>
       <p>
-        <a href="{% url 'all-targets' %}">
-          View all targets
-        </a>
+        <a href="{% url 'all-targets' %}">View all compatible targets</a>
+        <i class="icon-question-sign get-help get-help-blue heading-help" title="View all the targets you can build with the release selected for this project, which is {[project.release.desc]}"></i>
         {% if completedbuilds.count %}
           | <a href="{% url 'projectbuilds' project.id %}">View all project builds ({{completedbuilds.count}})</a>
         {% endif %}
@@ -256,7 +255,7 @@ vim: expandtab tabstop=2
         <p>
         You can:
           <ul>
-            <li> <a href="{% url 'layers'%}">View all layers available in Toaster</a>
+            <li> <a href="{% url 'layers'%}">View all compatible layers available in Toaster</a>
             <li> <a href="{% url 'importlayer' %}">Import a layer</a>
             <li> <a href="https://www.yoctoproject.org/docs/1.6.1/dev-manual/dev-manual.html#understanding-and-creating-layers" target="_blank">Read about layers in the manual</a>
           </ul>
@@ -270,7 +269,11 @@ vim: expandtab tabstop=2
         </div>
         {% csrf_token %}
       </form>
-      <p><a href="{% url 'layers' %}">View all layers</a> | <a href="{% url 'importlayer' %}">Import layer</a></p>
+      <p>
+        <a href="{% url 'layers' %}">View all compatible layers</a>
+        <i class="icon-question-sign get-help" title="View all the layers you can build with the release selected for this project, which is {[project.release.desc]}"></i>
+        |
+        <a href="{% url 'importlayer' %}">Import layer</a></p>
       <ul class="unstyled configuration-list">
           <li ng-repeat="l in layers track by l.id" class="animate-repeat">
             <a href="{[l.layerdetailurl]}" target="_#" class="layer-info" data-toggle="tooltip" tooltip="{[l.giturl]} | {[l.branch.name]}">{[l.name]}</a>
@@ -295,7 +298,9 @@ vim: expandtab tabstop=2
           {% csrf_token %}
         </form>
         <p>
-          <a href="{% url 'all-targets' %}">View all targets</a></p>
+          <a href="{% url 'all-targets' %}">View all compatible targets</a>
+          <i class="icon-question-sign get-help" title="View all the targets you can build with the release selected for this project, which is {[project.release.desc]}"></i>
+        </p>
         <div ng-if="frequenttargets.length">
         <h4 class="air">
             Most built targets
@@ -332,7 +337,10 @@ vim: expandtab tabstop=2
               <input type="reset" id="cancel-machine" class="btn btn-link" ng-click="toggle('#select-machine')" value="Cancel"></input>
               {% csrf_token %}
         </form>
-        <p><a href="{% url 'machines' %}" class="link">View all machines</a></p>
+        <p>
+          <a href="{% url 'machines' %}" class="link">View all compatible machines</a>
+        <i class="icon-question-sign get-help" title="View all the machines you can set with the release selected for this project, which is {[project.release.desc]}"></i>
+      </p>
       </div>
       <p class="link-action">
             <a href="{% url 'projectconf' project.id %}" class="link">Edit configuration variables</a>
diff --git a/lib/toaster/toastergui/templates/targets.html b/lib/toaster/toastergui/templates/targets.html
index 3038649..32c67ea 100644
--- a/lib/toaster/toastergui/templates/targets.html
+++ b/lib/toaster/toastergui/templates/targets.html
@@ -3,7 +3,7 @@
 {% load humanize %}
 
 {% block localbreadcrumb %}
-<li>Targets</li>
+<li>All compatible targets</li>
 {% endblock %}
 
 {% block projectinfomain %}
@@ -14,9 +14,9 @@
   {% elif request.GET.filter and objects.paginator.count ==  0 or request.GET.search and objects.paginator.count == 0 %}
       No targets found
   {%else%}
-      All targets
+      All compatible targets
   {%endif%}
-                        <i class="icon-question-sign get-help heading-help" title="This page lists all the targets compatible with " + {{project.release.name}} + " that Toaster knows about."></i>
+                        <i class="icon-question-sign get-help heading-help" title="This page lists all the targets compatible with the release selected for this project, which is {{project.release.description}}"></i>
                      </h1>
                 </div>
 
-- 
1.9.1



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

* [PATCH 12/27] toastergui: add download task log icon to recipe details page
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (10 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 11/27] toastergui: add the word 'compatible' to 'all' pages Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 13/27] toaster: machines Fix undefined variables Alex DAMIAN
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

When a task fails, we keep the log and allow users to
download it. Make sure the download is provided in the
tasks table of the recipe details page.

[YOCTO #7207]

Signed-off-by: Belen Barros Pena <belen.barros.pena@intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/static/js/libtoaster.js |  4 +++-
 lib/toaster/toastergui/templates/recipe.html   | 11 +++++------
 lib/toaster/toastergui/templates/tasks.html    | 10 +++++-----
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/lib/toaster/toastergui/static/js/libtoaster.js b/lib/toaster/toastergui/static/js/libtoaster.js
index 04264cd..2dc5b0a 100644
--- a/lib/toaster/toastergui/static/js/libtoaster.js
+++ b/lib/toaster/toastergui/static/js/libtoaster.js
@@ -1,4 +1,3 @@
-
 /* All shared functionality to go in libtoaster object.
  * This object really just helps readability since we can then have
  * a traceable namespace.
@@ -315,6 +314,9 @@ $(document).ready(function() {
     // initialise the tooltips for the icon-pencil icons
     $(".icon-pencil").tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Change" });
 
+    // initialise the tooltips for the download icons
+    $(".icon-download-alt").tooltip({ container: 'body', html: true, delay: { show: 200 } });
+
     // linking directly to tabs
     $(function(){
           var hash = window.location.hash;
diff --git a/lib/toaster/toastergui/templates/recipe.html b/lib/toaster/toastergui/templates/recipe.html
index d91768d..621b852 100644
--- a/lib/toaster/toastergui/templates/recipe.html
+++ b/lib/toaster/toastergui/templates/recipe.html
@@ -124,17 +124,16 @@
 
                     <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 %}
+                            <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
+                                <i class="icon-download-alt" title="Download task log file"></i>
+                            </a>
+                        {% endif %}
                         <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i>
                     </td>
                     <td>
                         {% ifnotequal task.sstate_result task.SSTATE_NA %}
                         <a {{ task|task_color }} href="{% url "task" build.pk task.pk %}">{{task.get_sstate_result_display}}</a>
-                    {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %}
-                        <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
-                            <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
-                        </a>
-                    {% endif %}
-
                         {% endifnotequal %}
                     </td>
 
diff --git a/lib/toaster/toastergui/templates/tasks.html b/lib/toaster/toastergui/templates/tasks.html
index 4cbcc5e..5c1c476 100644
--- a/lib/toaster/toastergui/templates/tasks.html
+++ b/lib/toaster/toastergui/templates/tasks.html
@@ -93,12 +93,12 @@
             </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 %}
+                    <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
+                        <i class="icon-download-alt" title="Download task log file"></i>
+                    </a>
+                {% endif %}
                 <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i>
-                    {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %}
-                        <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
-                            <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
-                        </a>
-                    {% endif %}
             </td>
             <td class="cache_attempt">
                 <a href="{%url "task" build.pk task.pk%} ">{{task.get_sstate_result_display|format_none_and_zero}}</a>
-- 
1.9.1



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

* [PATCH 13/27] toaster: machines Fix undefined variables
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (11 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 12/27] toastergui: add download task log icon to recipe details page Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 14/27] toaster: Add add/select functionality to machines page Alex DAMIAN
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

pagesize and orderby were undefined causing an error to be thrown when
browsing to the all machines page

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/toastergui/views.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 9567e62..73a5c7e 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2774,6 +2774,7 @@ if toastermain.settings.MANAGED:
         # define here what parameters the view needs in the GET portion in order to
         # be able to display something.  'count' and 'page' are mandatory for all views
         # that use paginators.
+        (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:+')
         mandatory_parameters = { 'count': 10,  'page' : 1, 'orderby' : 'name:+' };
         retval = _verify_parameters( request.GET, mandatory_parameters )
         if retval:
-- 
1.9.1



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

* [PATCH 14/27] toaster: Add add/select functionality to machines page
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (12 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 13/27] toaster: machines Fix undefined variables Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 15/27] toaster: machines Make sure we don't overwrite the pagesize Alex DAMIAN
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

This feature for the machines page allows the user to add a layer and
it's dependencies to the current project and then if successful select
the machine(s) which become available due to being provided by the
layer.

AlexD merged the changes into the submission queue.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/static/js/machines.js   | 89 +++++++++++++++++++++++
 lib/toaster/toastergui/templates/machines.html | 99 +++++++++++++-------------
 lib/toaster/toastergui/views.py                | 12 ++--
 3 files changed, 146 insertions(+), 54 deletions(-)
 create mode 100644 lib/toaster/toastergui/static/js/machines.js

diff --git a/lib/toaster/toastergui/static/js/machines.js b/lib/toaster/toastergui/static/js/machines.js
new file mode 100644
index 0000000..a3ea43b
--- /dev/null
+++ b/lib/toaster/toastergui/static/js/machines.js
@@ -0,0 +1,89 @@
+"use strict"
+
+function machinesPageInit (ctx) {
+
+
+  function setLayerInCurrentPrj(addLayerBtn, depsList){
+    var alertMsg = $("#alert-msg");
+
+    $(".select-or-add").each(function(){
+      /* If we have added a layer it may also enable other machines so search
+       * for other machines that have that layer and enable them */
+      var selectMachineBtn = $(this).children(".select-machine-btn");
+      var otherAddLayerBtns = $(this).children(".add-layer");
+
+      if (addLayerBtn.data('layer-version-id') ==  selectMachineBtn.data('layer-version-id')) {
+        otherAddLayerBtns.fadeOut(function(){
+          selectMachineBtn.fadeIn();
+        });
+      }
+    });
+
+    /* Reset alert message */
+    alertMsg.text("");
+
+    /* If we have added layer dependencies */
+    if (depsList) {
+      alertMsg.append("You have added <strong>"+(depsList.length+1)+"</strong> layers: <span id=\"layer-affected-name\"></span> and its dependencies ");
+
+        /* Build the layer deps list */
+        depsList.map(function(layer, i){
+          var link = $("<a></a>");
+
+          link.attr("href", layer.layerdetailurl);
+          link.text(layer.name);
+          link.tooltip({title: layer.tooltip});
+
+          if (i != 0)
+            alertMsg.append(", ");
+
+          alertMsg.append(link);
+        });
+    } else {
+      alertMsg.append("You have added <strong>1</strong> layer: <span id=\"layer-affected-name\"></span>");
+    }
+
+    var layerName = addLayerBtn.data('layer-name');
+    alertMsg.children("#layer-affected-name").text(layerName);
+    $("#alert-area").show();
+  }
+
+  /* Add or remove this layer from the project */
+  $(".add-layer").click(function() {
+      var btn = $(this);
+      /* If adding get the deps for this layer */
+      var layer = {
+        id : $(this).data('layer-version-id'),
+        name : $(this).data('layer-name'),
+      };
+
+      libtoaster.getLayerDepsForProject(ctx.xhrDataTypeaheadUrl, ctx.projectId, layer.id, function (data) {
+        /* got result for dependencies */
+        if (data.list.length == 0){
+          var editData = { layerAdd : layer.id };
+          libtoaster.editProject(ctx.xhrEditProjectUrl, ctx.projectId, editData,
+            function() {
+              setLayerInCurrentPrj(btn);
+          });
+          return;
+        } else {
+          /* The add deps will include this layer so no need to add it
+           * separately.
+           */
+          show_layer_deps_modal(ctx.projectId, layer, data.list, null, null, true, function () {
+            /* Success add deps and layer */
+            setLayerInCurrentPrj(btn, data.list);
+            console.log ("TODO SUCCESS");
+          });
+        }
+      }, null);
+  });
+
+  $(".select-machine-btn").click(function(){
+    var data =  { machineName : $(this).data('machine-name') };
+    libtoaster.editProject(ctx.xhrEditProjectUrl, ctx.projectId, data,
+      function (){
+        window.location.replace(ctx.projectPageUrl);
+    }, null);
+  });
+}
diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index e0bda51..c0d4c6c 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -1,62 +1,65 @@
 {% extends "baseprojectpage.html" %}
 {% load projecttags %}
 {% load humanize %}
-
+{% load static %}
 {% block localbreadcrumb %}
 <li>All compatible machines</li>
 {% endblock %}
 
 {% block projectinfomain %}
-                <div class="page-header">
-                    <h1>
-                        All compatible machines
-                        <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with the release selected for this project, which is {{project.release.description}}"></i>
-                     </h1>
-                </div>
-                <!--div class="alert">
-                    <div class="input-append" style="margin-bottom:0px;">
-                        <input class="input-xxlarge" type="text" placeholder="Search targets" value="browser" />
-                        <a class="add-on btn">
-                            <i class="icon-remove"></i>
-                        </a>
-                        <button class="btn" type="button">Search</button>
-                        <a class="btn btn-link" href="#">Show all targets</a>
-                    </div>
-                </div-->
-                <div id="target-added" class="alert alert-info lead" style="display:none;"></div>
-                <div id="target-removed" class="alert alert-info lead" style="display:none;">
-                    <button type="button" class="close" data-dismiss="alert">&times;</button>
-                    <strong>1</strong> target deleted from <a href="project-with-targets.html">your project</a>: <a href="#">meta-aarch64</a>
-                </div>
+<script src="{% static 'js/machines.js' %}"></script>
+<script>
+
+  $(document).ready(function (){
+    var ctx = {
+      projectPageUrl : "{% url 'project' project.id %}",
+      xhrEditProjectUrl : "{% url 'xhr_projectedit' project.id %}",
+      projectId : {{project.id}},
+      xhrDataTypeaheadUrl : "{% url 'xhr_datatypeahead' %}",
+    };
+
+    try {
+      machinesPageInit(ctx);
+    } catch (e) {
+      document.write("Sorry, An error has occurred loading this page");
+      console.warn(e);
+    }
+  });
+</script>
+{% include "layers_dep_modal.html" %}
+<div class="page-header">
+  <h1>
+    All machines
+    <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with Yocto Project 1.7 'Dxxxx' that Toaster knows about. They include community-created targets suitable for use on top of OpenEmbedded Core and any targets you have imported"></i>
+  </h1>
+</div>
 
+<div class="alert alert-info lead" id="alert-area" style="display:none">
+  <button type="button" class="close" id="dismiss-alert" data-dismiss="alert">&times;</button>
+  <span id="alert-msg"></span>
+  <p style="margin-top:10px;"><a href="{% url 'project' project.id %}">Go to project configuration</a></p>
+</div>
 
 {% include "basetable_top.html" %}
-    {% for o in objects %}
-    <tr class="data">
-	<td class="machine">
-		{{o.name}}
-		<a machine="_blank" href="http://layers.openembedded.org/layerindex/branch/master/machines/?q=3g-router-image"><i class="icon-share get-info"></i></a>
-	</td>
-	<td class="description">{{o.description}}</td>
-	<td class="machine-file">
-		<code>{{o.file_path}}</code>
-		<a href="http://github.com/embeddedgeeks/meta-embeddedgeeks/blob/master/machines-core/images/3g-router-image.bb" machine="_blank"><i class="icon-share get-info"></i></a>
-	</td>
-	<td class="layer"><a href="#">{{o.layer_version.layer.name}}</a></td>
-	<td class="source">{{o.layer_source.name}}</td>
-	<td class="branch">{{o.layer_version.commit}}</td>
-	<td class="build">
-		<a id="build-machine" href="project-with-machines.html?machine=3g-router-image" class="btn btn-block" style="display:none;">
-			Build machine
-		</a>
-		<a id="add-layer" href="#" class="btn btn-block nopop" title="1 layer added">
-			<i class="icon-plus"></i>
-			Add layer
-			<i class="icon-question-sign get-help" title="To build this machine, you must first add the meta-embeddedgeeks layer to your project"></i>
-		</a>
-	</td>
-    </tr>
-    {% endfor %}
+{% for o in objects %}
+<tr class="data">
+  <td class="machine">{{o.name}}</td>
+  <td class="description">{{o.description}}</td>
+  <td class="layer"><a href="{%url "layerdetails" o.layer_version.id %}">{{o.layer_version.layer.name}}</a></td>
+  <td class="source">{{o.layer_source.name}}</td>
+  <td class="branch">{{o.layer_version.commit}}</td>
+  <td class="select-or-add">
+    <a href="#" class="btn btn-block select-machine-btn" data-machine-name="{{o.name}}" data-layer-version-id="{{o.layer_version.id}}"
+        {%if o.layer_version.id not in project_layers %}style="display:none" {%endif%}  >Select machine</a>
+    <a  href="#" class="btn btn-block nopop add-layer" data-layer-version-id="{{o.layer_version.id}}" data-layer-name="{{o.layer_version.layer.name}}" {%if o.layer_version.id in project_layers %}style="display:none" {%endif%}
+        >
+      <i class="icon-plus"></i>
+      Add layer
+      <i class="icon-question-sign get-help" title="To build this machine, you must first add the {{o.layer_version.layer.name}} layer to your project"></i>
+    </a>
+  </td>
+</tr>
+{% endfor %}
 
 {% include "basetable_bottom.html" %}
 
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 73a5c7e..641170e 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2770,6 +2770,9 @@ if toastermain.settings.MANAGED:
         return response
 
     def machines(request):
+        if not 'project_id' in request.session:
+            raise Exception("invalid page: cannot show page without a project")
+
         template = "machines.html"
         # define here what parameters the view needs in the GET portion in order to
         # be able to display something.  'count' and 'page' are mandatory for all views
@@ -2785,18 +2788,19 @@ if toastermain.settings.MANAGED:
         (filter_string, search_term, ordering_string) = _search_tuple(request, Machine)
 
         queryset_all = Machine.objects.all()
-#        if 'project_id' in request.session:
-#            queryset_all = queryset_all.filter(Q(layer_version__up_branch__name = Project.objects.get(request.session['project_id']).release.branch_name) | Q(layer_version__build__in = Project.objects.get(request.session['project_id']).build_set.all()))
 
         queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
         queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name')
 
+        project_layers = ProjectLayer.objects.filter(project_id=request.session['project_id']).values_list('layercommit',flat=True)
+
         # retrieve the objects that will be displayed in the table; machines a paginator and gets a page range to display
         machine_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1))
 
 
         context = {
             'objects' : machine_info,
+            'project_layers' : project_layers,
             'objectname' : "machines",
             'default_orderby' : 'name:+',
             'total_count': queryset_with_search.count(),
@@ -2810,10 +2814,6 @@ if toastermain.settings.MANAGED:
                     'dclass': 'span5',
                     'clclass': 'description',
                 },
-                {   'name': 'Machine file',
-                    'clclass': 'machine-file',
-                    'hidden': 1,
-                },
                 {   'name': 'Layer',
                     'clclass': 'layer',
                 },
-- 
1.9.1



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

* [PATCH 15/27] toaster: machines Make sure we don't overwrite the pagesize
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (13 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 14/27] toaster: Add add/select functionality to machines page Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 16/27] toaster: All machines add a column to link back to machine conf Alex DAMIAN
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

The pagesize was accidentally being over written and should be set to
the value returned from the cookie if there was one.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/toastergui/views.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 641170e..9d85a93 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2778,7 +2778,7 @@ if toastermain.settings.MANAGED:
         # be able to display something.  'count' and 'page' are mandatory for all views
         # that use paginators.
         (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:+')
-        mandatory_parameters = { 'count': 10,  'page' : 1, 'orderby' : 'name:+' };
+        mandatory_parameters = { 'count': pagesize,  'page' : 1, 'orderby' : orderby };
         retval = _verify_parameters( request.GET, mandatory_parameters )
         if retval:
             return _redirect_parameters( 'machines', request.GET, mandatory_parameters)
-- 
1.9.1



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

* [PATCH 16/27] toaster: All machines add a column to link back to machine conf
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (14 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 15/27] toaster: machines Make sure we don't overwrite the pagesize Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 17/27] toaster: All machines Update layer notifications Alex DAMIAN
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Add a column with the "path" to the machine file and add a link back to
the vcs web to view the machine configuration file.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/orm/models.py                      | 7 ++++++-
 lib/toaster/toastergui/templates/machines.html | 1 +
 lib/toaster/toastergui/views.py                | 5 ++++-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 454f369..ad7a856 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -538,6 +538,11 @@ class Machine(models.Model):
     name = models.CharField(max_length=255)
     description = models.CharField(max_length=255)
 
+    def get_vcs_machine_file_link_url(self):
+        path = 'conf/machine/'+self.name+'.conf'
+
+        return self.layer_version.get_vcs_file_link_url(path)
+
     def __unicode__(self):
         return "Machine " + self.name + "(" + self.description + ")"
 
@@ -901,7 +906,7 @@ class Layer_Version(models.Model):
 
     # code lifted, with adaptations, from the layerindex-web application https://git.yoctoproject.org/cgit/cgit.cgi/layerindex-web/
     def _handle_url_path(self, base_url, path):
-        import re
+        import re, posixpath
         if base_url:
             if self.dirpath:
                 if path:
diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index c0d4c6c..e3329bf 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -48,6 +48,7 @@
   <td class="layer"><a href="{%url "layerdetails" o.layer_version.id %}">{{o.layer_version.layer.name}}</a></td>
   <td class="source">{{o.layer_source.name}}</td>
   <td class="branch">{{o.layer_version.commit}}</td>
+  <td class="machinefile"><code>/machine/conf/{{o.name}}.conf</code><a href="{{o.get_vcs_machine_file_link_url}}" target="_blank"><i class="icon-share get-info"></i></a></td>
   <td class="select-or-add">
     <a href="#" class="btn btn-block select-machine-btn" data-machine-name="{{o.name}}" data-layer-version-id="{{o.layer_version.id}}"
         {%if o.layer_version.id not in project_layers %}style="display:none" {%endif%}  >Select machine</a>
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 9d85a93..c89b67b 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2797,7 +2797,6 @@ if toastermain.settings.MANAGED:
         # retrieve the objects that will be displayed in the table; machines a paginator and gets a page range to display
         machine_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1))
 
-
         context = {
             'objects' : machine_info,
             'project_layers' : project_layers,
@@ -2834,6 +2833,10 @@ if toastermain.settings.MANAGED:
                     'qhelp' : "The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project",
                     'hidden': 1,
                 },
+                {   'name' : 'Machine file',
+                    'clclass' : 'machinefile',
+                    'hidden' : 1,
+                },
                 {   'name': 'Select',
                     'dclass': 'span2',
                     'qhelp': "Add or delete machines to / from your project ",
-- 
1.9.1



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

* [PATCH 17/27] toaster: All machines Update layer notifications
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (15 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 16/27] toaster: All machines add a column to link back to machine conf Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 18/27] toaster: layerdetails Don't remove alert from dom on dismissal Alex DAMIAN
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Update layer notifications to the new wording for layer add remove
notifications.
Fix bug where the the alert area is being removed from the dom on
dismiss instead of re-hidden

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

diff --git a/lib/toaster/toastergui/static/js/machines.js b/lib/toaster/toastergui/static/js/machines.js
index a3ea43b..1b7ea36 100644
--- a/lib/toaster/toastergui/static/js/machines.js
+++ b/lib/toaster/toastergui/static/js/machines.js
@@ -24,7 +24,7 @@ function machinesPageInit (ctx) {
 
     /* If we have added layer dependencies */
     if (depsList) {
-      alertMsg.append("You have added <strong>"+(depsList.length+1)+"</strong> layers: <span id=\"layer-affected-name\"></span> and its dependencies ");
+      alertMsg.append("You have added <strong>"+(depsList.length+1)+"</strong> layers to <a id=\"project-affected-name\"></a>: <span id=\"layer-affected-name\"></span> and its dependencies ");
 
         /* Build the layer deps list */
         depsList.map(function(layer, i){
@@ -40,14 +40,18 @@ function machinesPageInit (ctx) {
           alertMsg.append(link);
         });
     } else {
-      alertMsg.append("You have added <strong>1</strong> layer: <span id=\"layer-affected-name\"></span>");
+      alertMsg.append("You have added <strong>1</strong> layer to <a id=\"project-affected-name\"></a>: <strong id=\"layer-affected-name\"></strong>");
     }
 
     var layerName = addLayerBtn.data('layer-name');
     alertMsg.children("#layer-affected-name").text(layerName);
+    alertMsg.children("#project-affected-name").text(ctx.projectName).attr('href', ctx.projectPageUrl);
+
     $("#alert-area").show();
   }
 
+  $("#dismiss-alert").click(function(){ $(this).parent().hide() });
+
   /* Add or remove this layer from the project */
   $(".add-layer").click(function() {
       var btn = $(this);
diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index e3329bf..487d6b7 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -13,6 +13,7 @@
   $(document).ready(function (){
     var ctx = {
       projectPageUrl : "{% url 'project' project.id %}",
+      projectName : "{{project.name}}",
       xhrEditProjectUrl : "{% url 'xhr_projectedit' project.id %}",
       projectId : {{project.id}},
       xhrDataTypeaheadUrl : "{% url 'xhr_datatypeahead' %}",
@@ -35,9 +36,8 @@
 </div>
 
 <div class="alert alert-info lead" id="alert-area" style="display:none">
-  <button type="button" class="close" id="dismiss-alert" data-dismiss="alert">&times;</button>
+  <button type="button" class="close" id="dismiss-alert">&times;</button>
   <span id="alert-msg"></span>
-  <p style="margin-top:10px;"><a href="{% url 'project' project.id %}">Go to project configuration</a></p>
 </div>
 
 {% include "basetable_top.html" %}
-- 
1.9.1



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

* [PATCH 18/27] toaster: layerdetails Don't remove alert from dom on dismissal
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (16 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 17/27] toaster: All machines Update layer notifications Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 19/27] toaster: All machines Add layer name order by functions Alex DAMIAN
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

When dismissing the alert we actually want to keep the alert area still
in the dom for the use of future alerts. The default behaviour is to
remove it from the dom. Hide it again instead.

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

diff --git a/lib/toaster/toastergui/static/js/layerdetails.js b/lib/toaster/toastergui/static/js/layerdetails.js
index 9339ae8..99552de 100644
--- a/lib/toaster/toastergui/static/js/layerdetails.js
+++ b/lib/toaster/toastergui/static/js/layerdetails.js
@@ -261,6 +261,8 @@ function layerDetailsPageInit (ctx) {
     $("#alert-area").show();
   }
 
+  $("#dismiss-alert").click(function(){ $(this).parent().hide() });
+
   /* Add or remove this layer from the project */
   addRmLayerBtn.click(function() {
     var directive = $(this).data('directive');
diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 7a1a22d..0321a0b 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -72,7 +72,7 @@
 
     <div class="row-fluid span7 tabbable">
         <div class="alert alert-info lead" id="alert-area" style="display:none">
-          <button type="button" class="close" id="dismiss-alert" data-dismiss="alert">&times;</button>
+          <button type="button" class="close" id="dismiss-alert">&times;</button>
           <span id="alert-msg"></span>
         </div>
         <ul class="nav nav-pills">
-- 
1.9.1



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

* [PATCH 19/27] toaster: All machines Add layer name order by functions
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (17 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 18/27] toaster: layerdetails Don't remove alert from dom on dismissal Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 20/27] toaster: All machines Add filtering based on layer in project Alex DAMIAN
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Allow the layer name to be sorted alphabetically in the machines table.
Also fix the default ordering to be machine name

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

diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index 487d6b7..650c47b 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -31,7 +31,7 @@
 <div class="page-header">
   <h1>
     All machines
-    <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with Yocto Project 1.7 'Dxxxx' that Toaster knows about. They include community-created targets suitable for use on top of OpenEmbedded Core and any targets you have imported"></i>
+    <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with the current project that Toaster knows about. They include community-created targets suitable for use on top of OpenEmbedded Core and any targets you have imported"></i>
   </h1>
 </div>
 
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index c89b67b..2e52d2b 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2777,7 +2777,7 @@ if toastermain.settings.MANAGED:
         # define here what parameters the view needs in the GET portion in order to
         # be able to display something.  'count' and 'page' are mandatory for all views
         # that use paginators.
-        (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:+')
+        (pagesize, orderby) = _get_parameters_values(request, 10, 'name:+')
         mandatory_parameters = { 'count': pagesize,  'page' : 1, 'orderby' : orderby };
         retval = _verify_parameters( request.GET, mandatory_parameters )
         if retval:
@@ -2815,6 +2815,8 @@ if toastermain.settings.MANAGED:
                 },
                 {   'name': 'Layer',
                     'clclass': 'layer',
+                    'orderfield': _get_toggle_order(request, "layer_version__layer__name"),
+                    'ordericon' : _get_toggle_order_icon(request, "layer_version__layer__name"),
                 },
                 {   'name': 'Layer source',
                     'clclass': 'source',
-- 
1.9.1



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

* [PATCH 20/27] toaster: All machines Add filtering based on layer in project
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (18 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 19/27] toaster: All machines Add layer name order by functions Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 21/27] toaster: models Allow the machine's layer name to be searched Alex DAMIAN
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Add a filter so that we can filter machines which are already being provided
by a layer in the current project.
Also make sure that we're only showing layers which are compatible with
the current project.
Also handle no results returned and page heading reflecting the number of
results returned from a search.

AlexD solved conflicts while merging the patch.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/templates/machines.html | 67 +++++++++++++++++---------
 lib/toaster/toastergui/views.py                | 48 ++++++++++++++++--
 2 files changed, 86 insertions(+), 29 deletions(-)

diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index 650c47b..9930a94 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -30,38 +30,57 @@
 {% include "layers_dep_modal.html" %}
 <div class="page-header">
   <h1>
+    {% if request.GET.search %}
+      {% if objects.paginator.count != 0 %}
+        {{objects.paginator.count}} machines found
+       {% else %}
+        No Machines found
+       {% endif %}
+    {% else %}
+
     All machines
     <i class="icon-question-sign get-help heading-help" title="This page lists all the machines compatible with the current project that Toaster knows about. They include community-created targets suitable for use on top of OpenEmbedded Core and any targets you have imported"></i>
+    {% endif %}
   </h1>
 </div>
-
 <div class="alert alert-info lead" id="alert-area" style="display:none">
   <button type="button" class="close" id="dismiss-alert">&times;</button>
   <span id="alert-msg"></span>
 </div>
+{% if request.GET.search and objects.paginator.count == 0 %}
+<div class="alert row-fluid">
+<form class="navbar-search input-append pull-left" id="searchform">
+  <input class="input-xxlarge" id="search" name="search" type="text" placeholder="Search machines" value="{{request.GET.search}}"><a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>
+    <input type="hidden" name="orderby" value="">
+      <input type="hidden" name="page" value="1">
+        <button class="btn" type="submit" value="Search">Search</button>
+        <button type="submit" class="btn btn-link"><a href="{%url 'machines' %}">Show all machines</a></button>
+      </form>
+    </div>
+{% else %}
+  {% include "basetable_top.html" %}
+  {% for o in objects %}
+  <tr class="data">
+    <td class="machine">{{o.name}}</td>
+    <td class="description">{{o.description}}</td>
+    <td class="layer"><a href="{%url "layerdetails" o.layer_version.id %}">{{o.layer_version.layer.name}}</a></td>
+    <td class="source">{{o.layer_source.name}}</td>
+    <td class="branch">{{o.layer_version.get_vcs_reference}}</td>
+    <td class="machinefile"><code>/machine/conf/{{o.name}}.conf</code><a href="{{o.get_vcs_machine_file_link_url}}" target="_blank"><i class="icon-share get-info"></i></a></td>
+    <td class="select-or-add">
+      <a href="#" class="btn btn-block select-machine-btn" data-machine-name="{{o.name}}" data-layer-version-id="{{o.layer_version.id}}"
+          {%if o.layer_version.id not in project_layers %}style="display:none" {%endif%}  >Select machine</a>
+      <a  href="#" class="btn btn-block nopop add-layer" data-layer-version-id="{{o.layer_version.id}}" data-layer-name="{{o.layer_version.layer.name}}" {%if o.layer_version.id in project_layers %}style="display:none" {%endif%}
+          >
+        <i class="icon-plus"></i>
+        Add layer
+        <i class="icon-question-sign get-help" title="To build this machine, you must first add the {{o.layer_version.layer.name}} layer to your project"></i>
+      </a>
+    </td>
+  </tr>
+  {% endfor %}
 
-{% include "basetable_top.html" %}
-{% for o in objects %}
-<tr class="data">
-  <td class="machine">{{o.name}}</td>
-  <td class="description">{{o.description}}</td>
-  <td class="layer"><a href="{%url "layerdetails" o.layer_version.id %}">{{o.layer_version.layer.name}}</a></td>
-  <td class="source">{{o.layer_source.name}}</td>
-  <td class="branch">{{o.layer_version.commit}}</td>
-  <td class="machinefile"><code>/machine/conf/{{o.name}}.conf</code><a href="{{o.get_vcs_machine_file_link_url}}" target="_blank"><i class="icon-share get-info"></i></a></td>
-  <td class="select-or-add">
-    <a href="#" class="btn btn-block select-machine-btn" data-machine-name="{{o.name}}" data-layer-version-id="{{o.layer_version.id}}"
-        {%if o.layer_version.id not in project_layers %}style="display:none" {%endif%}  >Select machine</a>
-    <a  href="#" class="btn btn-block nopop add-layer" data-layer-version-id="{{o.layer_version.id}}" data-layer-name="{{o.layer_version.layer.name}}" {%if o.layer_version.id in project_layers %}style="display:none" {%endif%}
-        >
-      <i class="icon-plus"></i>
-      Add layer
-      <i class="icon-question-sign get-help" title="To build this machine, you must first add the {{o.layer_version.layer.name}} layer to your project"></i>
-    </a>
-  </td>
-</tr>
-{% endfor %}
-
-{% include "basetable_bottom.html" %}
+  {% include "basetable_bottom.html" %}
+{% endif %}
 
 {% endblock %}
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 2e52d2b..7dc4bbd 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2789,11 +2789,38 @@ if toastermain.settings.MANAGED:
 
         queryset_all = Machine.objects.all()
 
-        queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
-        queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name')
+        prj = Project.objects.get(pk = request.session['project_id'])
+        compatible_layers = prj.compatible_layerversions()
+        # Make sure we only show machines / layers which are compatible with the current project
+        queryset_all = queryset_all.filter(layer_version__in=compatible_layers)
 
         project_layers = ProjectLayer.objects.filter(project_id=request.session['project_id']).values_list('layercommit',flat=True)
 
+        by_pass_filter_string = False
+        #  "special" filters identified by these valid filter strings we
+        # by pass the usual filter applying method because we're filtering using
+        # a subquery done by project_layers
+        if "name:inprj" in filter_string:
+          queryset_all = queryset_all.filter(layer_version__in=project_layers)
+          by_pass_filter_string = True
+
+        if "name:notinprj" in filter_string:
+          queryset_all = queryset_all.exclude(layer_version__in=project_layers)
+          by_pass_filter_string = True
+
+        queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
+
+        if by_pass_filter_string:
+          queryset = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
+        else:
+          queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name')
+
+        selected_filter_count = {
+          'inprj' : queryset.filter(layer_version__in=project_layers).count(),
+          'notinprj' : queryset.exclude(layer_version__in=project_layers).count()
+        }
+
+
         # retrieve the objects that will be displayed in the table; machines a paginator and gets a page range to display
         machine_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1))
 
@@ -2802,7 +2829,7 @@ if toastermain.settings.MANAGED:
             'project_layers' : project_layers,
             'objectname' : "machines",
             'default_orderby' : 'name:+',
-            'total_count': queryset_with_search.count(),
+            'total_count': machine_info.paginator.count,
 
             'tablecols' : [
                 {   'name': 'Machine',
@@ -2840,12 +2867,23 @@ if toastermain.settings.MANAGED:
                     'hidden' : 1,
                 },
                 {   'name': 'Select',
-                    'dclass': 'span2',
-                    'qhelp': "Add or delete machines to / from your project ",
+                    'dclass': 'select span2',
+                    'qhelp': "Sets the selected machine as the project machine. You can only have one machine per project",
+                    'filter': {
+                        'class': 'select',
+                        'label': 'Show:',
+                        'options': [
+                          (u'Machines provided by layers added to this project', 'name:inprj', selected_filter_count['inprj']),
+                          (u'Machines provided by layers not added to this project', 'name:notinprj', selected_filter_count['notinprj']),
+
+                        ],
+                    }
+
                 },
 
             ]
         }
+
         response = render(request, template, context)
         _save_parameters_cookies(response, pagesize, orderby, request)
 
-- 
1.9.1



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

* [PATCH 21/27] toaster: models Allow the machine's layer name to be searched
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (19 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 20/27] toaster: All machines Add filtering based on layer in project Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 22/27] toaster: All Machines fix reset search link Alex DAMIAN
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Make the layer name searchable. If you know the name of the layer you are
interested in, searching for it is a fast way of getting the list of
machines provided by it.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/orm/models.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index ad7a856..4bb84bd 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -529,7 +529,7 @@ class Recipe_Dependency(models.Model):
 
 
 class Machine(models.Model):
-    search_allowed_fields = ["name", "description"]
+    search_allowed_fields = ["name", "description", "layer_version__layer__name"]
     layer_source = models.ForeignKey('LayerSource', default = None, null = True)  # from where did we get this machine
     up_id = models.IntegerField(null = True, default = None)                      # id of entry in the source
     up_date = models.DateTimeField(null = True, default = None)
-- 
1.9.1



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

* [PATCH 22/27] toaster: All Machines fix reset search link
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (20 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 21/27] toaster: models Allow the machine's layer name to be searched Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 23/27] toaster: all Machines exclude de-prioritised layer source items Alex DAMIAN
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

In firefox this link wasn't valid as it was inside a button element.
Remove this and add a click handler for the button.

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

diff --git a/lib/toaster/toastergui/static/js/machines.js b/lib/toaster/toastergui/static/js/machines.js
index 1b7ea36..ee8c980 100644
--- a/lib/toaster/toastergui/static/js/machines.js
+++ b/lib/toaster/toastergui/static/js/machines.js
@@ -90,4 +90,9 @@ function machinesPageInit (ctx) {
         window.location.replace(ctx.projectPageUrl);
     }, null);
   });
+
+  $("#show-all-btn").click(function(){
+    $("#search").val("")
+    $("#searchform").submit();
+  });
 }
diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index 9930a94..f63e897 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -34,7 +34,7 @@
       {% if objects.paginator.count != 0 %}
         {{objects.paginator.count}} machines found
        {% else %}
-        No Machines found
+        No machines found
        {% endif %}
     {% else %}
 
@@ -54,7 +54,7 @@
     <input type="hidden" name="orderby" value="">
       <input type="hidden" name="page" value="1">
         <button class="btn" type="submit" value="Search">Search</button>
-        <button type="submit" class="btn btn-link"><a href="{%url 'machines' %}">Show all machines</a></button>
+        <button type="submit" class="btn btn-link" id="show-all-btn">Show all machines</button>
       </form>
     </div>
 {% else %}
-- 
1.9.1



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

* [PATCH 00/27] Toaster patchset
@ 2015-02-09 18:01 Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 01/27] toastergui: remove time link for failed build requests Alex DAMIAN
                   ` (26 more replies)
  0 siblings, 27 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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


Hello,

This is a Toaster patchset containing the All Machines page implementation, and fixes
for numerous bugs. All patches have been reviewed and tested on the toaster mailing list.

Can you please pull at your convenience ?

Thank you,
Alex



The following changes since commit 207013b6dde82f9654f9be996695c8335b95a288:

  data_smart: split expanded removal values when handling _remove (2015-02-02 16:20:42 +0000)

are available in the git repository at:

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

Alexandru DAMIAN (6):
  toastergui: fix loadconf error message
  toaster: enable server-side caches and debug-panel
  toastergui: improvements in layer selection logic
  toaster: enhancements for the startup sequence
  toaster: improve logging facilities for toaster
  toaster: display Toaster mode and version in debug mode

Belen Barros Pena (7):
  toastergui: remove time link for failed build requests
  toasterui: use text() instead of html()
  toaster: correct typo in toaster script
  toastergui: set column heading to 'Revision'
  toastergui: add the word 'compatible' to 'all' pages
  toastergui: add download task log icon to recipe details page
  toastergui: links outside Toaster should open in a new window

Michael Wood (14):
  toaster: machines Fix undefined variables
  toaster: Add add/select functionality to machines page
  toaster: machines Make sure we don't overwrite the pagesize
  toaster: All machines add a column to link back to machine conf
  toaster: All machines Update layer notifications
  toaster: layerdetails Don't remove alert from dom on dismissal
  toaster: All machines Add layer name order by functions
  toaster: All machines Add filtering based on layer in project
  toaster: models Allow the machine's layer name to be searched
  toaster: All Machines fix reset search link
  toaster: all Machines exclude de-prioritised layer source items
  toaster: All machines reset order_by if removing that column
  toaster: All machines show results count if filtering or searching
  toaster: All machines Fix filter counts

 bin/toaster                                        |  82 +++++++++---
 lib/bb/ui/buildinfohelper.py                       |  47 +++++--
 lib/toaster/bldcontrol/bbcontroller.py             |  13 --
 lib/toaster/bldcontrol/localhostbecontroller.py    |  54 +++++---
 .../management/commands/checksettings.py           |  76 ++++++++---
 .../bldcontrol/management/commands/loadconf.py     |   2 +-
 .../bldcontrol/management/commands/runbuilds.py    |   2 +-
 lib/toaster/bldcontrol/sshbecontroller.py          |   2 +-
 lib/toaster/orm/models.py                          |  32 ++++-
 lib/toaster/orm/tests.py                           | 131 ++++++++++++++++++-
 lib/toaster/toastergui/static/css/default.css      |  21 ++-
 lib/toaster/toastergui/static/js/layerdetails.js   |   6 +-
 lib/toaster/toastergui/static/js/libtoaster.js     |   4 +-
 lib/toaster/toastergui/static/js/machines.js       |  98 ++++++++++++++
 lib/toaster/toastergui/templates/base.html         |   6 +
 lib/toaster/toastergui/templates/layerdetails.html |  13 +-
 lib/toaster/toastergui/templates/layers.html       |   6 +-
 lib/toaster/toastergui/templates/machines.html     | 125 ++++++++++--------
 .../toastergui/templates/managed_mrb_section.html  |   2 +-
 lib/toaster/toastergui/templates/project.html      |  24 ++--
 lib/toaster/toastergui/templates/recipe.html       |  11 +-
 lib/toaster/toastergui/templates/targets.html      |  20 +--
 lib/toaster/toastergui/templates/tasks.html        |  10 +-
 lib/toaster/toastergui/views.py                    | 142 ++++++++++++++++-----
 lib/toaster/toastermain/settings.py                |  48 ++++++-
 lib/toaster/toastermain/urls.py                    |  23 +++-
 26 files changed, 779 insertions(+), 221 deletions(-)
 create mode 100644 lib/toaster/toastergui/static/js/machines.js

-- 
1.9.1



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

* [PATCH 23/27] toaster: all Machines exclude de-prioritised layer source items
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (21 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 22/27] toaster: All Machines fix reset search link Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 24/27] toaster: All machines reset order_by if removing that column Alex DAMIAN
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

If a duplicate layer exists from another layer source and provides a
machine we don't want to show it if that layer comes from a low priority
layer source.

Signed-off-by: Michael Wood <michael.g.wood@intel.com
---
 lib/toaster/toastergui/views.py | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 7dc4bbd..88d59f4 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -203,7 +203,6 @@ def _get_search_results(search_term, queryset, model):
 
         search_objects.append(reduce(operator.or_, q_map))
     search_object = reduce(operator.and_, search_objects)
-    print "search objects", search_object
     queryset = queryset.filter(search_object)
 
     return queryset
@@ -2788,18 +2787,25 @@ if toastermain.settings.MANAGED:
         (filter_string, search_term, ordering_string) = _search_tuple(request, Machine)
 
         queryset_all = Machine.objects.all()
+        queryset_all = queryset_all.prefetch_related('layer_version')
+        queryset_all = queryset_all.prefetch_related('layer_source')
 
         prj = Project.objects.get(pk = request.session['project_id'])
         compatible_layers = prj.compatible_layerversions()
-        # Make sure we only show machines / layers which are compatible with the current project
+
+        # FILTERS SECTION
+
+        # Make sure we only show machines / layers which are compatible
+        # with the current project
         queryset_all = queryset_all.filter(layer_version__in=compatible_layers)
 
         project_layers = ProjectLayer.objects.filter(project_id=request.session['project_id']).values_list('layercommit',flat=True)
 
         by_pass_filter_string = False
-        #  "special" filters identified by these valid filter strings we
+        # "special" filters identified by these valid filter strings we
         # by pass the usual filter applying method because we're filtering using
         # a subquery done by project_layers
+
         if "name:inprj" in filter_string:
           queryset_all = queryset_all.filter(layer_version__in=project_layers)
           by_pass_filter_string = True
@@ -2808,20 +2814,25 @@ if toastermain.settings.MANAGED:
           queryset_all = queryset_all.exclude(layer_version__in=project_layers)
           by_pass_filter_string = True
 
-        queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
+        selected_filter_count = {
+          'inprj' : queryset_all.filter(layer_version__in=project_layers).count(),
+          'notinprj' : queryset_all.exclude(layer_version__in=project_layers).count()
+        }
+
+        # END FILTERS
 
         if by_pass_filter_string:
           queryset = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
         else:
           queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name')
 
-        selected_filter_count = {
-          'inprj' : queryset.filter(layer_version__in=project_layers).count(),
-          'notinprj' : queryset.exclude(layer_version__in=project_layers).count()
-        }
-
+        # Now we need to weed out the layers which will appear as duplicated
+        # because they're from a layer source which doesn't need to be used
+        for machine in queryset:
+           to_rm = machine.layer_version.get_equivalents_wpriority(prj)[1:]
+           if len(to_rm) > 0:
+             queryset = queryset.exclude(layer_version__in=to_rm)
 
-        # retrieve the objects that will be displayed in the table; machines a paginator and gets a page range to display
         machine_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1))
 
         context = {
@@ -2854,7 +2865,7 @@ if toastermain.settings.MANAGED:
                     'filter': {
                         'class': 'machine',
                         'label': 'Show:',
-                        'options': map(lambda x: (x.name, 'layer_source__pk:' + str(x.id), queryset_with_search.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()),
+                        'options': map(lambda x: (x.name, 'layer_source__pk:' + str(x.id), queryset.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()),
                     }
                 },
                 {   'name': 'Revision',
-- 
1.9.1



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

* [PATCH 24/27] toaster: All machines reset order_by if removing that column
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (22 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 23/27] toaster: all Machines exclude de-prioritised layer source items Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 25/27] toaster: All machines show results count if filtering or searching Alex DAMIAN
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

When you remove a column from a table that is currently being sorted by
that value we also need to remove the sort.

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

diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 88d59f4..255b6a3 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2846,6 +2846,7 @@ if toastermain.settings.MANAGED:
                 {   'name': 'Machine',
                     'orderfield': _get_toggle_order(request, "name"),
                     'ordericon' : _get_toggle_order_icon(request, "name"),
+                    'orderkey' : "name",
                 },
                 {   'name': 'Description',
                     'dclass': 'span5',
@@ -2855,6 +2856,7 @@ if toastermain.settings.MANAGED:
                     'clclass': 'layer',
                     'orderfield': _get_toggle_order(request, "layer_version__layer__name"),
                     'ordericon' : _get_toggle_order_icon(request, "layer_version__layer__name"),
+                    'orderkey' : "layer_version__layer__name",
                 },
                 {   'name': 'Layer source',
                     'clclass': 'source',
-- 
1.9.1



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

* [PATCH 25/27] toaster: All machines show results count if filtering or searching
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (23 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 24/27] toaster: All machines reset order_by if removing that column Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 26/27] toaster: All machines Fix filter counts Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 27/27] toastergui: links outside Toaster should open in a new window Alex DAMIAN
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Show the number of results returned if filtering as well as when
searching.

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

diff --git a/lib/toaster/toastergui/templates/machines.html b/lib/toaster/toastergui/templates/machines.html
index f63e897..2089c26 100644
--- a/lib/toaster/toastergui/templates/machines.html
+++ b/lib/toaster/toastergui/templates/machines.html
@@ -30,7 +30,7 @@
 {% include "layers_dep_modal.html" %}
 <div class="page-header">
   <h1>
-    {% if request.GET.search %}
+    {% if request.GET.search or request.GET.filter %}
       {% if objects.paginator.count != 0 %}
         {{objects.paginator.count}} machines found
        {% else %}
-- 
1.9.1



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

* [PATCH 26/27] toaster: All machines Fix filter counts
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (24 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 25/27] toaster: All machines show results count if filtering or searching Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  2015-02-09 18:01 ` [PATCH 27/27] toastergui: links outside Toaster should open in a new window Alex DAMIAN
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Filter counts needed to take into account the filters that had
previously been applied.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/toastergui/views.py | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 255b6a3..a7f58ad 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -2814,11 +2814,6 @@ if toastermain.settings.MANAGED:
           queryset_all = queryset_all.exclude(layer_version__in=project_layers)
           by_pass_filter_string = True
 
-        selected_filter_count = {
-          'inprj' : queryset_all.filter(layer_version__in=project_layers).count(),
-          'notinprj' : queryset_all.exclude(layer_version__in=project_layers).count()
-        }
-
         # END FILTERS
 
         if by_pass_filter_string:
@@ -2834,13 +2829,16 @@ if toastermain.settings.MANAGED:
              queryset = queryset.exclude(layer_version__in=to_rm)
 
         machine_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1))
+        selected_filter_count = {}
+        selected_filter_count['inprj'] = queryset.filter(layer_version__in=project_layers).count()
+        selected_filter_count['notinprj'] = queryset.count() - selected_filter_count['inprj']
 
         context = {
             'objects' : machine_info,
             'project_layers' : project_layers,
             'objectname' : "machines",
             'default_orderby' : 'name:+',
-            'total_count': machine_info.paginator.count,
+            'total_count': queryset.count(),
 
             'tablecols' : [
                 {   'name': 'Machine',
-- 
1.9.1



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

* [PATCH 27/27] toastergui: links outside Toaster should open in a new window
  2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
                   ` (25 preceding siblings ...)
  2015-02-09 18:01 ` [PATCH 26/27] toaster: All machines Fix filter counts Alex DAMIAN
@ 2015-02-09 18:01 ` Alex DAMIAN
  26 siblings, 0 replies; 28+ messages in thread
From: Alex DAMIAN @ 2015-02-09 18:01 UTC (permalink / raw)
  To: bitbake-devel

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

Make sure all links going to pages outside Toaster in
the layer details page (to web repos and the like)
open in a new tab/window.

[YOCTO #7193]

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

diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 0321a0b..6d00da3 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -111,7 +111,7 @@
             <dd>
               <span class="current-value">{{layerversion.layer.vcs_url}}</span>
               {% if layerversion.get_vcs_link_url %}
-                <a href="{{layerversion.get_vcs_link_url}}/" class="icon-share get-info"></a>
+                <a href="{{layerversion.get_vcs_link_url}}/" class="icon-share get-info" target="_blank"></a>
               {% endif %}
               <form id="change-repo-form" class="control-group" style="display:none">
                 <div class="input-append">
@@ -130,7 +130,7 @@
                 <span class="muted" style="display:none">Not set</span>
                 <span class="current-value">{{layerversion.dirpath}}</span>
                 {% if layerversion.get_vcs_dirpath_link_url %}
-                  <a href="{{layerversion.get_vcs_dirpath_link_url}}" class="icon-share get-info"></a>
+                  <a href="{{layerversion.get_vcs_dirpath_link_url}}" class="icon-share get-info" target="_blank"></a>
                 {% endif %}
                 <form id="change-subdir-form" style="display:none;">
                   <div class="input-append">
-- 
1.9.1



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

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

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-09 18:01 [PATCH 00/27] Toaster patchset Alex DAMIAN
2015-02-09 18:01 ` [PATCH 01/27] toastergui: remove time link for failed build requests Alex DAMIAN
2015-02-09 18:01 ` [PATCH 02/27] toasterui: use text() instead of html() Alex DAMIAN
2015-02-09 18:01 ` [PATCH 03/27] toaster: correct typo in toaster script Alex DAMIAN
2015-02-09 18:01 ` [PATCH 04/27] toastergui: fix loadconf error message Alex DAMIAN
2015-02-09 18:01 ` [PATCH 05/27] toaster: enable server-side caches and debug-panel Alex DAMIAN
2015-02-09 18:01 ` [PATCH 06/27] toastergui: improvements in layer selection logic Alex DAMIAN
2015-02-09 18:01 ` [PATCH 07/27] toaster: enhancements for the startup sequence Alex DAMIAN
2015-02-09 18:01 ` [PATCH 08/27] toaster: improve logging facilities for toaster Alex DAMIAN
2015-02-09 18:01 ` [PATCH 09/27] toaster: display Toaster mode and version in debug mode Alex DAMIAN
2015-02-09 18:01 ` [PATCH 10/27] toastergui: set column heading to 'Revision' Alex DAMIAN
2015-02-09 18:01 ` [PATCH 11/27] toastergui: add the word 'compatible' to 'all' pages Alex DAMIAN
2015-02-09 18:01 ` [PATCH 12/27] toastergui: add download task log icon to recipe details page Alex DAMIAN
2015-02-09 18:01 ` [PATCH 13/27] toaster: machines Fix undefined variables Alex DAMIAN
2015-02-09 18:01 ` [PATCH 14/27] toaster: Add add/select functionality to machines page Alex DAMIAN
2015-02-09 18:01 ` [PATCH 15/27] toaster: machines Make sure we don't overwrite the pagesize Alex DAMIAN
2015-02-09 18:01 ` [PATCH 16/27] toaster: All machines add a column to link back to machine conf Alex DAMIAN
2015-02-09 18:01 ` [PATCH 17/27] toaster: All machines Update layer notifications Alex DAMIAN
2015-02-09 18:01 ` [PATCH 18/27] toaster: layerdetails Don't remove alert from dom on dismissal Alex DAMIAN
2015-02-09 18:01 ` [PATCH 19/27] toaster: All machines Add layer name order by functions Alex DAMIAN
2015-02-09 18:01 ` [PATCH 20/27] toaster: All machines Add filtering based on layer in project Alex DAMIAN
2015-02-09 18:01 ` [PATCH 21/27] toaster: models Allow the machine's layer name to be searched Alex DAMIAN
2015-02-09 18:01 ` [PATCH 22/27] toaster: All Machines fix reset search link Alex DAMIAN
2015-02-09 18:01 ` [PATCH 23/27] toaster: all Machines exclude de-prioritised layer source items Alex DAMIAN
2015-02-09 18:01 ` [PATCH 24/27] toaster: All machines reset order_by if removing that column Alex DAMIAN
2015-02-09 18:01 ` [PATCH 25/27] toaster: All machines show results count if filtering or searching Alex DAMIAN
2015-02-09 18:01 ` [PATCH 26/27] toaster: All machines Fix filter counts Alex DAMIAN
2015-02-09 18:01 ` [PATCH 27/27] toastergui: links outside Toaster should open in a new window Alex DAMIAN

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