Openembedded Bitbake Development
 help / color / mirror / Atom feed
* [PATCH 0/5] Toaster patchset pull request
@ 2015-01-08 13:15 Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 1/5] toaster: Improve client side error handling Alex DAMIAN
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Alex DAMIAN @ 2015-01-08 13:15 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

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

Hi,

This is a toaster patchset with patches that have been reviewed on the toaster mailing list.

It contains bugfixes and new features in the frontend Web interface.

Can you please pull at your convenience ?

Cheers,
Alex

The following changes since commit 86704281b79e524dccccc88cbf996b299b33bae2:

  ast: Add error when trying to use dash in sh function names (2015-01-08 10:37:06 +0000)

are available in the git repository at:

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

Alexandru DAMIAN (4):
  toaster: write pre-read conf file for build variables
  toaster: do not launch web browser on noweb option
  toaster: branch name priority resolution
  toaster: implementation of project page

Michael Wood (1):
  toaster: Improve client side error handling

 bin/toaster                                        |  13 +-
 lib/toaster/bldcontrol/bbcontroller.py             |   5 +
 .../bldcontrol/management/commands/runbuilds.py    |   5 +-
 lib/toaster/orm/models.py                          |   9 +-
 lib/toaster/toastergui/static/js/libtoaster.js     |  39 +++-
 lib/toaster/toastergui/static/js/projectapp.js     | 242 +++++++++++++++------
 lib/toaster/toastergui/templates/base.html         |   5 +
 lib/toaster/toastergui/templates/layers.html       |   8 +-
 lib/toaster/toastergui/templates/mrb_section.html  |   8 +-
 lib/toaster/toastergui/templates/project.html      |  50 +++--
 lib/toaster/toastergui/templates/targets.html      |   8 +-
 lib/toaster/toastergui/views.py                    | 103 ++++-----
 12 files changed, 329 insertions(+), 166 deletions(-)

-- 
1.9.1


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

* [PATCH 1/5] toaster: Improve client side error handling
  2015-01-08 13:15 [PATCH 0/5] Toaster patchset pull request Alex DAMIAN
@ 2015-01-08 13:15 ` Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 2/5] toaster: write pre-read conf file for build variables Alex DAMIAN
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alex DAMIAN @ 2015-01-08 13:15 UTC (permalink / raw)
  To: bitbake-devel

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

Make use of the toastermain.settings.DEBUG flag to toggle the client
side error logging. Make the error logging consistent by using
console.warn/error across the project, this adds traceability to the
warnings. Also handles the case where console is not available by
stubbing it in libtoaster.

Signed-off-by: Michael Wood <michael.g.wood@intel.com>
---
 lib/toaster/toastergui/static/js/libtoaster.js    | 39 ++++++++++++++++++++---
 lib/toaster/toastergui/static/js/projectapp.js    | 28 ++++++++--------
 lib/toaster/toastergui/templates/base.html        |  5 +++
 lib/toaster/toastergui/templates/layers.html      |  8 ++---
 lib/toaster/toastergui/templates/mrb_section.html |  8 ++---
 lib/toaster/toastergui/templates/targets.html     |  8 ++---
 lib/toaster/toastergui/views.py                   |  6 ++--
 7 files changed, 69 insertions(+), 33 deletions(-)

diff --git a/lib/toaster/toastergui/static/js/libtoaster.js b/lib/toaster/toastergui/static/js/libtoaster.js
index 15815b3..a2a0abd 100644
--- a/lib/toaster/toastergui/static/js/libtoaster.js
+++ b/lib/toaster/toastergui/static/js/libtoaster.js
@@ -81,14 +81,14 @@ var libtoaster = (function (){
         headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
         success: function (_data) {
           if (_data.error != "ok") {
-            console.log(_data.error);
+            console.warn(_data.error);
           } else {
             if (onsuccess != undefined) onsuccess(_data);
           }
         },
         error: function (_data) {
-          console.log("Call failed");
-          console.log(_data);
+          console.warn("Call failed");
+          console.warn(_data);
           if (onfail) onfail(data);
     } });
   };
@@ -102,13 +102,13 @@ var libtoaster = (function (){
         headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
         success: function (_data) {
           if (_data.error != "ok") {
-            console.log(_data.error);
+            console.warn(_data.error);
           } else {
             if (onsuccess != undefined) onsuccess(_data);
           }
         },
         error: function (_data) {
-          console.log(_data);
+          console.warn(_data);
           if (onfail) onfail(data);
         }
     });
@@ -168,6 +168,7 @@ var libtoaster = (function (){
     getProjectInfo: _getProjectInfo,
     getLayerDepsForProject : _getLayerDepsForProject,
     editProject : _editProject,
+    debug: false,
   }
 })();
 
@@ -203,6 +204,15 @@ function reload_params(params) {
 /* Things that happen for all pages */
 $(document).ready(function() {
 
+    /* If we don't have a console object which might be the case in some
+     * browsers, no-op it to avoid undefined errors.
+     */
+    if (!window.console) {
+      window.console = {};
+      window.console.warn = function() {};
+      window.console.error = function() {};
+    }
+
     /*
      * PrettyPrint plugin.
      *
@@ -320,4 +330,23 @@ $(document).ready(function() {
     if (location.href.search('#warnings') > -1) {
         $('#collapse-warnings').addClass('in');
     }
+
+    function check_for_duplicate_ids () {
+      /* warn about duplicate element ids */
+      var ids = {};
+      $("[id]").each(function() {
+        if (this.id && ids[this.id]) {
+          console.warn('Duplicate element id #'+this.id);
+        }
+        ids[this.id] = true;
+      });
+    }
+
+    if (libtoaster.debug) {
+      check_for_duplicate_ids();
+    } else {
+      /* Debug is false so supress warnings by overriding the functions */
+      window.console.warn = function () {};
+      window.console.error = function () {};
+   }
 });
diff --git a/lib/toaster/toastergui/static/js/projectapp.js b/lib/toaster/toastergui/static/js/projectapp.js
index bb97f32..767ea13 100644
--- a/lib/toaster/toastergui/static/js/projectapp.js
+++ b/lib/toaster/toastergui/static/js/projectapp.js
@@ -136,7 +136,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: type, value: currentValue}})
             .success(function (_data) {
                 if (_data.error != "ok") {
-                    alert(_data.error);
+                    console.warn(_data.error);
                     deffered.reject(_data.error);
                 }
                 deffered.resolve(_data.list);
@@ -152,12 +152,12 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         if (inXHRcall) {
             if (callparams.data === undefined) {
                 // we simply skip the data refresh calls
-                console.log("race on XHR, aborted");
+                console.warn("race on XHR, aborted");
                 return;
             } else {
                 // we return a promise that we'll solve by reissuing the command later
                 var delayed = $q.defer();
-                console.log("race on XHR, delayed");
+                console.warn("race on XHR, delayed");
                 $interval(function () {$scope._makeXHRCall(callparams).then(function (d) { delayed.resolve(d); });}, 100, 1);
 
                 return delayed.promise;
@@ -171,7 +171,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 
         $http(callparams).success(function(_data, _status, _headers, _config) {
             if (_data.error != "ok") {
-                alert("Failed XHR request (" + _status + "): " + _data.error);
+                console.warn("Failed XHR request (" + _status + "): " + _data.error);
                 console.error("Failed XHR request: ", _data, _status, _headers, _config);
                 // stop refreshing hte page
                 $interval.cancel($scope.pollHandle);
@@ -267,7 +267,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                 deffered.resolve(_data);
             }
         }).error(function(_data, _status, _headers, _config) {
-                alert("Failed HTTP XHR request (" + _status + ")" + _data);
+                console.warn("Failed HTTP XHR request (" + _status + ")" + _data);
                 console.error("Failed HTTP XHR request: ", _data, _status, _headers, _config);
                 inXHRcall = false;
                 deffered.reject(_data.error);
@@ -298,7 +298,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 
     $scope.targetNamedBuild = function(target) {
         if ($scope.targetName === undefined && $scope.targetName1 === undefined){
-            alert("No target defined, please type in a target name");
+            console.warn("No target defined, please type in a target name");
             return;
         }
 
@@ -310,7 +310,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                 targets: $scope.safeTargetName,
             }
         }).then(function (data) {
-            console.log("received ", data);
+            console.warn("received ", data);
             $scope.targetName = undefined;
             $scope.targetName1 = undefined;
             $location.hash('buildslist');
@@ -357,7 +357,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "layerdeps", value: $scope.layerAddId }})
         .success(function (_data) {
              if (_data.error != "ok") {
-                 alert(_data.error);
+                 console.warn(_data.error);
              } else {
                  if (_data.list.length > 0) {
                      // activate modal
@@ -369,7 +369,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                          $scope.selectedItems = (function () { s = {}; for (var i = 0; i < items.length; i++) { s[items[i].id] = true; };return s; })();
 
                          $scope.ok = function() {
-                            console.log("scope selected is ", $scope.selectedItems);
+                            console.warn("scope selected is ", $scope.selectedItems);
                             $modalInstance.close(Object.keys($scope.selectedItems).filter(function (e) { return $scope.selectedItems[e];}));
                          };
 
@@ -378,7 +378,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                          };
 
                          $scope.update = function() {
-                            console.log("updated ", $scope.selectedItems);
+                            console.warn("updated ", $scope.selectedItems);
                          };
                        },
                        resolve: {
@@ -393,7 +393,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 
                      modalInstance.result.then(function (selectedArray) {
                          selectedArray.push($scope.layerAddId);
-                         console.log("selected", selectedArray);
+                         console.warn("selected", selectedArray);
 
                          $scope._makeXHRCall({
                              method: "POST", url: $scope.urls.xhr_edit,
@@ -473,7 +473,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 
     $scope.edit = function(elementid) {
         var data = {};
-        console.log("edit with ", elementid);
+        console.warn("edit with ", elementid);
         var alertText = undefined;
         var alertZone = undefined;
         var oldLayers = [];
@@ -675,7 +675,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 */
 
 function test_diff_arrays() {
-    _diffArrays([1,2,3], [2,3,4], function(e,f) { return e==f; }, function(e) {console.log("added", e)}, function(e) {console.log("deleted", e);})
+    _diffArrays([1,2,3], [2,3,4], function(e,f) { return e==f; }, function(e) {console.warn("added", e)}, function(e) {console.warn("deleted", e);})
 }
 
 // test_diff_arrays();
@@ -685,6 +685,6 @@ var s = undefined;
 function test_set_alert(text) {
     s = angular.element("div#main").scope();
     s.displayAlert(s.zone3alerts, text);
-    console.log(s.zone3alerts);
+    console.warn(s.zone3alerts);
     s.$digest();
 }
diff --git a/lib/toaster/toastergui/templates/base.html b/lib/toaster/toastergui/templates/base.html
index bc7a0ee..e95b5e0 100644
--- a/lib/toaster/toastergui/templates/base.html
+++ b/lib/toaster/toastergui/templates/base.html
@@ -21,6 +21,11 @@
 </script>
 <script src="{% static 'js/libtoaster.js' %}">
 </script>
+{% if DEBUG %}
+<script>
+  libtoaster.debug = true;
+ </script>
+{% endif %}
 <script src="{% static 'js/base.js' %}"></script>
 {%if MANAGED %}
 <script>
diff --git a/lib/toaster/toastergui/templates/layers.html b/lib/toaster/toastergui/templates/layers.html
index ced54c2..33160e5 100644
--- a/lib/toaster/toastergui/templates/layers.html
+++ b/lib/toaster/toastergui/templates/layers.html
@@ -126,15 +126,15 @@ function _makeXHREditCall(data, onsuccess, onfail) {
         headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
         success: function (_data) {
             if (_data.error != "ok") {
-                alert(_data.error);
+                console.warn(_data.error);
             } else {
                 updateButtons(_data.layers.map(function (e) {return e.id}));
                 if (onsuccess != undefined) onsuccess(_data);
             }
         },
         error: function (_data) {
-            alert("Call failed");
-            console.log(_data);
+            console.warn("Call failed");
+            console.warn(_data);
         }
     });
 }
@@ -215,7 +215,7 @@ function layerAdd(layerId, layerName, layerURL) {
         data: {'type': 'layerdeps','value':layerId},
         success: function(_data) {
                 if (_data.error != "ok") {
-                    alert(_data.error);
+                    console.warn(_data.error);
                 } else {
                     updateLayerCountLabels(_data.list.length+1);
 
diff --git a/lib/toaster/toastergui/templates/mrb_section.html b/lib/toaster/toastergui/templates/mrb_section.html
index 73031e2..432955a 100644
--- a/lib/toaster/toastergui/templates/mrb_section.html
+++ b/lib/toaster/toastergui/templates/mrb_section.html
@@ -79,21 +79,21 @@ function _makeXHRBuildCall(url, data, onsuccess, onfail) {
         headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
         success: function (_data) {
             if (_data.error != "ok") {
-                alert(_data.error);
+                console.warn(_data.error);
             } else {
                 if (onsuccess != undefined) onsuccess(_data);
             }
         },
         error: function (_data) {
-            alert("Call failed");
-            console.log(_data);
+            console.warn("Call failed");
+            console.warn(_data);
             if (onfail) onfail(data);
         } });
 }
 
 
 function scheduleBuild(url, projectName, buildlist) {
-  console.log("scheduleBuild");
+  console.warn("scheduleBuild");
   _makeXHRBuildCall(url, {targets: buildlist.join(" ")}, function (_data) {
 
       $('#latest-builds').prepend('<div class="alert alert-info" style="padding-top:0px">' + '<span class="label label-info" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;">'+projectName+'</span><div class="row-fluid">' +
diff --git a/lib/toaster/toastergui/templates/targets.html b/lib/toaster/toastergui/templates/targets.html
index f4313f9..cc339fb 100644
--- a/lib/toaster/toastergui/templates/targets.html
+++ b/lib/toaster/toastergui/templates/targets.html
@@ -119,15 +119,15 @@ function _makeXHREditCall(data, onsuccess, onfail) {
         headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
         success: function (_data) {
             if (_data.error != "ok") {
-                alert(_data.error);
+                console.warn(_data.error);
             } else {
                 updateButtons(_data.layers.map(function (e) {return e.id}));
                 if (onsuccess != undefined) onsuccess(_data);
             }
         },
         error: function (_data) {
-            alert("Call failed");
-            console.log(_data);
+            console.warn("Call failed");
+            console.warn(_data);
         }
     });
 }
@@ -202,7 +202,7 @@ function layerAdd(layerId, layerName, layerURL, pressedButtonId) {
         data: {'type': 'layerdeps','value':layerId},
         success: function(_data) {
                 if (_data.error != "ok") {
-                    alert(_data.error);
+                    console.warn(_data.error);
                 } else {
                     updateLayerCountLabels(_data.list.length+1);
 
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 679c1e9..420b37c 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1898,7 +1898,8 @@ if toastermain.settings.MANAGED:
     def managedcontextprocessor(request):
         ret = {
             "projects": Project.objects.all(),
-            "MANAGED" : toastermain.settings.MANAGED
+            "MANAGED" : toastermain.settings.MANAGED,
+            "DEBUG" : toastermain.settings.DEBUG
         }
         if 'project_id' in request.session:
             try:
@@ -2923,7 +2924,8 @@ else:
     def managedcontextprocessor(request):
         return {
             "projects": [],
-            "MANAGED" : toastermain.settings.MANAGED
+            "MANAGED" : toastermain.settings.MANAGED,
+            "DEBUG" : toastermain.settings.DEBUG
         }
 
     def newproject(request):
-- 
1.9.1



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

* [PATCH 2/5] toaster: write pre-read conf file for build variables
  2015-01-08 13:15 [PATCH 0/5] Toaster patchset pull request Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 1/5] toaster: Improve client side error handling Alex DAMIAN
@ 2015-01-08 13:15 ` Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 3/5] toaster: do not launch web browser on noweb option Alex DAMIAN
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alex DAMIAN @ 2015-01-08 13:15 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

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

We change the setting of variables from directly injection
into the set-up cooker to writing a conf file that is pre-read
on bitbake server startup. This is needed because the injection
can only happen after the variable set is parsed, and the variables
already inferred, so setting up variables happens too late.

[YOCTO #7045]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 bin/toaster                                             | 6 +++++-
 lib/toaster/bldcontrol/bbcontroller.py                  | 5 +++++
 lib/toaster/bldcontrol/management/commands/runbuilds.py | 5 +----
 lib/toaster/orm/models.py                               | 1 +
 4 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/bin/toaster b/bin/toaster
index 7511012..6969bf7 100755
--- a/bin/toaster
+++ b/bin/toaster
@@ -251,7 +251,11 @@ case $CMD in
             return 4
         fi
         unset BBSERVER
-        bitbake --postread conf/toaster.conf --server-only -t xmlrpc -B 0.0.0.0:0
+        PREREAD=""
+        if [ -e conf/toaster-pre.conf ]; then
+                PREREAD="--read 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
             start_success=0
             echo "Bitbake server start failed"
diff --git a/lib/toaster/bldcontrol/bbcontroller.py b/lib/toaster/bldcontrol/bbcontroller.py
index 7c27fe1..102606e 100644
--- a/lib/toaster/bldcontrol/bbcontroller.py
+++ b/lib/toaster/bldcontrol/bbcontroller.py
@@ -135,6 +135,11 @@ class BuildEnvironmentController(object):
         bblayerconffile.write("# line added by toaster build control\nBBLAYERS = \"" + " ".join(layerlist) + "\"")
         bblayerconffile.close()
 
+    def writePreConfFile(self, variable_list):
+        prefilepath = os.path.join(self.be.builddir, "conf/toaster-pre.conf")
+        with open(prefilepath, "w") as prefile:
+            for i in variable_list:
+                prefile.write("%s=\"%s\"\n" % (i.name, i.value))
 
 
     def startBBServer(self, brbe):
diff --git a/lib/toaster/bldcontrol/management/commands/runbuilds.py b/lib/toaster/bldcontrol/management/commands/runbuilds.py
index 56c989c..bdce6ee 100644
--- a/lib/toaster/bldcontrol/management/commands/runbuilds.py
+++ b/lib/toaster/bldcontrol/management/commands/runbuilds.py
@@ -53,14 +53,11 @@ class Command(NoArgsCommand):
 
             # set up the buid environment with the needed layers
             bec.setLayers(br.brbitbake_set.all(), br.brlayer_set.all())
+            bec.writePreConfFile(br.brvariable_set.all())
 
             # get the bb server running with the build req id and build env id
             bbctrl = bec.getBBController("%d:%d" % (br.pk, bec.be.pk))
 
-            # set the build configuration
-            for variable in br.brvariable_set.all():
-                bbctrl.setVariable(variable.name, variable.value)
-
             # trigger the build command
             task = reduce(lambda x, y: x if len(y)== 0 else y, map(lambda y: y.task, br.brtarget_set.all()))
             if len(task) == 0:
diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 46b704c..6fbbeed 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -529,6 +529,7 @@ class Recipe_Dependency(models.Model):
 
 
 class Machine(models.Model):
+    search_allowed_fields = ["name", "description"]
     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] 6+ messages in thread

* [PATCH 3/5] toaster: do not launch web browser on noweb option
  2015-01-08 13:15 [PATCH 0/5] Toaster patchset pull request Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 1/5] toaster: Improve client side error handling Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 2/5] toaster: write pre-read conf file for build variables Alex DAMIAN
@ 2015-01-08 13:15 ` Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 4/5] toaster: branch name priority resolution Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 5/5] toaster: implementation of project page Alex DAMIAN
  4 siblings, 0 replies; 6+ messages in thread
From: Alex DAMIAN @ 2015-01-08 13:15 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

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

This patch makes Toaster managed mode obey the "noweb" parameter
by not starting the web server and launching the web browser
command if the "noweb" parameter is specified.

The web browser will be pointed at 127.0.0.1 instead of 0.0.0.0

[YOCTO #7039]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 bin/toaster | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/bin/toaster b/bin/toaster
index 6969bf7..a6d2e92 100755
--- a/bin/toaster
+++ b/bin/toaster
@@ -185,11 +185,14 @@ if [ -z "$ZSH_NAME" ] && [ `basename \"$0\"` = `basename \"$BASH_SOURCE\"` ]; th
     }
     TOASTER_MANAGED=1
     export TOASTER_MANAGED=1
-    if ! webserverStartAll; then
+    if [ $WEBSERVER -gt 0 ] && ! webserverStartAll; then
         echo "Failed to start the web server, stopping" 1>&2;
         exit 1;
     fi
-    xdg-open http://0.0.0.0:$WEB_PORT/ >/dev/null 2>&1 &
+    if [ $WEBSERVER -gt 0 ]; then
+        echo "Starting browser..."
+        xdg-open http://127.0.0.1:$WEB_PORT/ >/dev/null 2>&1 &
+    fi
     trap trap_ctrlc SIGINT
     echo "Running. Stop with Ctrl-C"
     while [ $RUNNING -gt 0 ]; do
-- 
1.9.1



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

* [PATCH 4/5] toaster: branch name priority resolution
  2015-01-08 13:15 [PATCH 0/5] Toaster patchset pull request Alex DAMIAN
                   ` (2 preceding siblings ...)
  2015-01-08 13:15 ` [PATCH 3/5] toaster: do not launch web browser on noweb option Alex DAMIAN
@ 2015-01-08 13:15 ` Alex DAMIAN
  2015-01-08 13:15 ` [PATCH 5/5] toaster: implementation of project page Alex DAMIAN
  4 siblings, 0 replies; 6+ messages in thread
From: Alex DAMIAN @ 2015-01-08 13:15 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

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

Adding a Layer_Version function that gets back the
branch name that should be used/displayed for finding the
targeted git branch name.

Change the commit id to use the branch name instead of the
last-updated commit hash from the layer source.

[YOCTO #7031]

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

diff --git a/lib/toaster/orm/models.py b/lib/toaster/orm/models.py
index 6fbbeed..5eff955 100644
--- a/lib/toaster/orm/models.py
+++ b/lib/toaster/orm/models.py
@@ -740,7 +740,7 @@ class LayerIndexLayerSource(LayerSource):
             lv.up_date = lbi['updated']
             lv.up_branch = Branch.objects.get(layer_source = self, up_id = lbi['branch'])
             lv.branch = lbi['actual_branch']
-            lv.commit = lbi['vcs_last_rev']
+            lv.commit = lbi['actual_branch']
             lv.dirpath = lbi['vcs_subdir']
             lv.save()
 
@@ -960,6 +960,12 @@ class Layer_Version(models.Model):
                 key = lambda x: _get_ls_priority(x.layer_source),
                 reverse = True)
 
+    def get_vcs_reference(self):
+        if self.commit is not None and len(self.commit) > 0:
+            return self.commit
+        if self.branch is not None and len(self.branch) > 0:
+            return self.branch
+        return self.up_branch.name
 
     def __unicode__(self):
         return  str(self.layer) + " (" + self.commit +")"
-- 
1.9.1



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

* [PATCH 5/5] toaster: implementation of project page
  2015-01-08 13:15 [PATCH 0/5] Toaster patchset pull request Alex DAMIAN
                   ` (3 preceding siblings ...)
  2015-01-08 13:15 ` [PATCH 4/5] toaster: branch name priority resolution Alex DAMIAN
@ 2015-01-08 13:15 ` Alex DAMIAN
  4 siblings, 0 replies; 6+ messages in thread
From: Alex DAMIAN @ 2015-01-08 13:15 UTC (permalink / raw)
  To: bitbake-devel; +Cc: Alexandru DAMIAN

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

This patch brings the project page in line with the design,
including build error handling and suggestions.

Includes some refactoring for already existing code.

[YOCTO #6587]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/toaster/toastergui/static/js/projectapp.js | 234 ++++++++++++++++++-------
 lib/toaster/toastergui/templates/project.html  |  50 ++++--
 lib/toaster/toastergui/views.py                |  97 +++++-----
 3 files changed, 246 insertions(+), 135 deletions(-)

diff --git a/lib/toaster/toastergui/static/js/projectapp.js b/lib/toaster/toastergui/static/js/projectapp.js
index 767ea13..0bdc55a 100644
--- a/lib/toaster/toastergui/static/js/projectapp.js
+++ b/lib/toaster/toastergui/static/js/projectapp.js
@@ -100,6 +100,16 @@ function _diffArrays(existingArray, newArray, compareElements, onAdded, onDelete
 
 }
 
+// add Array findIndex if not there
+
+if (Array.prototype.findIndex === undefined) {
+    Array.prototype.findIndex = function (callback) {
+        var i = 0;
+        for ( i = 0; i < this.length; i++ )
+            if (callback(this[i], i, this)) return i;
+        return -1;
+    }
+}
 
 var projectApp = angular.module('project', ['ngCookies', 'ngAnimate', 'ui.bootstrap', 'ngRoute', 'ngSanitize'],  angular_formpost);
 
@@ -126,11 +136,17 @@ projectApp.filter('timediff', function() {
     }
 });
 
+/**
+ * main controller for the project page
+ */
 
-// main controller for the project page
 projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $cookieStore, $q, $sce, $anchorScroll, $animate, $sanitize) {
 
-    $scope.getSuggestions = function(type, currentValue) {
+    /**
+     * Retrieves text suggestions for text-edit drop down autocomplete boxes
+     */
+
+    $scope.getAutocompleteSuggestions = function(type, currentValue) {
         var deffered = $q.defer();
 
         $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: type, value: currentValue}})
@@ -147,17 +163,19 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 
     var inXHRcall = false;
 
-    // default handling of XHR calls that handles errors and updates commonly-used pages
+    /**
+     * XHR call wrapper that automatically handles errors and auto-updates the page content to reflect project state on server side.
+     */
     $scope._makeXHRCall = function(callparams) {
         if (inXHRcall) {
             if (callparams.data === undefined) {
                 // we simply skip the data refresh calls
-                console.warn("race on XHR, aborted");
+                console.warn("TRC1: race on XHR, aborted");
                 return;
             } else {
                 // we return a promise that we'll solve by reissuing the command later
                 var delayed = $q.defer();
-                console.warn("race on XHR, delayed");
+                console.warn("TRC2: race on XHR, delayed");
                 $interval(function () {$scope._makeXHRCall(callparams).then(function (d) { delayed.resolve(d); });}, 100, 1);
 
                 return delayed.promise;
@@ -178,33 +196,6 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                 deffered.reject(_data.error);
             }
             else {
-
-                if (_data.builds !== undefined) {
-                    var toDelete = [];
-                    // step 1 - delete entries not found
-                    $scope.builds.forEach(function (elem) {
-                        if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id && elemX.status == elem.status; })) {
-                            toDelete.push(elem);
-                        }
-                    });
-                    toDelete.forEach(function (elem) {
-                        $scope.builds.splice($scope.builds.indexOf(elem),1);
-                    });
-                    // step 2 - merge new entries
-                    _data.builds.forEach(function (elem) {
-                        var found = false;
-                        var i = 0;
-                        for (i = 0 ; i < $scope.builds.length; i ++) {
-                            if ($scope.builds[i].id > elem.id) continue;
-                            if ($scope.builds[i].id == elem.id) { found=true; break;}
-                            if ($scope.builds[i].id < elem.id) break;
-                        }
-                        if (!found) {
-                            $scope.builds.splice(i, 0, elem);
-                        }
-                    });
-
-                }
                 if (_data.layers !== undefined) {
 
                     var addedLayers = [];
@@ -239,12 +230,59 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                     // step 3 - display alerts.
                     if (addedLayers.length > 0) {
                         $scope.displayAlert($scope.zone2alerts, "You have added <b>"+addedLayers.length+"</b> layer" + ((addedLayers.length>1)?"s: ":": ") + addedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", "), "alert-info");
+                        // invalidate error layer data based on current layers
+                        $scope.layersForTargets = {};
                     }
                     if (deletedLayers.length > 0) {
                         $scope.displayAlert($scope.zone2alerts, "You have deleted <b>"+deletedLayers.length+"</b> layer" + ((deletedLayers.length>1)?"s: ":": ") + deletedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", "), "alert-info");
+                        // invalidate error layer data based on current layers
+                        $scope.layersForTargets = {};
                     }
 
                 }
+
+
+                if (_data.builds !== undefined) {
+                    var toDelete = [];
+                    // step 1 - delete entries not found
+                    $scope.builds.forEach(function (elem) {
+                        if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id && elemX.status == elem.status; })) {
+                            toDelete.push(elem);
+                        }
+                    });
+                    toDelete.forEach(function (elem) {
+                        $scope.builds.splice($scope.builds.indexOf(elem),1);
+                    });
+                    // step 2 - merge new entries
+                    _data.builds.forEach(function (elem) {
+                        var found = false;
+                        var i = 0;
+                        for (i = 0 ; i < $scope.builds.length; i ++) {
+                            if ($scope.builds[i].id > elem.id) continue;
+                            if ($scope.builds[i].id == elem.id) { found=true; break;}
+                            if ($scope.builds[i].id < elem.id) break;
+                        }
+                        if (!found) {
+                            $scope.builds.splice(i, 0, elem);
+                        }
+                    });
+                    // step 3 - merge "Canceled" builds
+                    $scope.canceledBuilds.forEach(function (elem) {
+                        // mock the build object
+                        var found = false;
+                        var i = 0;
+                        for (i = 0; i < $scope.builds.length; i ++) {
+                           if ($scope.builds[i].id > elem.id) continue;
+                            if ($scope.builds[i].id == elem.id) { found=true; break;}
+                            if ($scope.builds[i].id < elem.id) break;
+                        }
+                        if (!found) {
+                            $scope.builds.splice(i, 0, elem);
+                        }
+                    });
+
+                    $scope.fetchLayersForTargets();
+                }
                 if (_data.targets !== undefined) {
                     $scope.targets = _data.targets;
                 }
@@ -267,17 +305,26 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                 deffered.resolve(_data);
             }
         }).error(function(_data, _status, _headers, _config) {
-                console.warn("Failed HTTP XHR request (" + _status + ")" + _data);
+            if (_status == 0) {
+                // the server has gone away
+                alert("The server is not responding. The application will terminate now")
+                $interval.cancel($scope.pollHandle);
+            }
+            else {
                 console.error("Failed HTTP XHR request: ", _data, _status, _headers, _config);
                 inXHRcall = false;
                 deffered.reject(_data.error);
+            }
         });
 
         return deffered.promise;
     }
 
     $scope.layeralert = undefined;
-    // shows user alerts on invalid project data
+    /**
+     * Verifies and shows user alerts on invalid project data
+     */
+
     $scope.validateData = function () {
         if ($scope.layers.length == 0) {
             $scope.layeralert = $scope.displayAlert($scope.zone1alerts, "You need to add some layers to this project. <a href=\""+$scope.urls.layers+"\">View all layers available in Toaster</a> or <a href=\""+$scope.urls.importlayer+"\">import a layer</a>");
@@ -289,14 +336,14 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         }
     }
 
-    $scope.targetExistingBuild = function(targets) {
+    $scope.buildExistingTarget = function(targets) {
         var oldTargetName = $scope.targetName;
         $scope.targetName = targets.map(function(v,i,a){return v.target}).join(' ');
         $scope.targetNamedBuild();
         $scope.targetName = oldTargetName;
     }
 
-    $scope.targetNamedBuild = function(target) {
+    $scope.buildNamedTarget = function(target) {
         if ($scope.targetName === undefined && $scope.targetName1 === undefined){
             console.warn("No target defined, please type in a target name");
             return;
@@ -310,7 +357,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                 targets: $scope.safeTargetName,
             }
         }).then(function (data) {
-            console.warn("received ", data);
+            console.warn("TRC3: received ", data);
             $scope.targetName = undefined;
             $scope.targetName1 = undefined;
             $location.hash('buildslist');
@@ -329,22 +376,20 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         $scope.safeTargetName = $scope.safeTargetName.replace(/\[.*\]/, '').trim();
     }
 
-    $scope.buildCancel = function(id) {
+    $scope.buildCancel = function(build) {
         $scope._makeXHRCall({
             method: "POST", url: $scope.urls.xhr_build,
             data: {
-                buildCancel: id,
+                buildCancel: build.id,
             }
+        }).then( function () {
+            build['status'] = "deleted";
+            $scope.canceledBuilds.push(build);
         });
     }
 
-    $scope.buildDelete = function(id) {
-        $scope._makeXHRCall({
-            method: "POST", url: $scope.urls.xhr_build,
-            data: {
-                buildDelete: id,
-            }
-        });
+    $scope.buildDelete = function(build) {
+        $scope.canceledBuilds.splice($scope.canceledBuilds.indexOf(build), 1);
     }
 
 
@@ -352,6 +397,12 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         $scope.layerAddId = item.id;
     }
 
+
+    $scope.layerAddById = function (id) {
+        $scope.layerAddId = id;
+        $scope.layerAdd();
+    }
+
     $scope.layerAdd = function() {
 
         $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "layerdeps", value: $scope.layerAddId }})
@@ -369,7 +420,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                          $scope.selectedItems = (function () { s = {}; for (var i = 0; i < items.length; i++) { s[items[i].id] = true; };return s; })();
 
                          $scope.ok = function() {
-                            console.warn("scope selected is ", $scope.selectedItems);
+                            console.warn("TRC4: scope selected is ", $scope.selectedItems);
                             $modalInstance.close(Object.keys($scope.selectedItems).filter(function (e) { return $scope.selectedItems[e];}));
                          };
 
@@ -378,7 +429,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                          };
 
                          $scope.update = function() {
-                            console.warn("updated ", $scope.selectedItems);
+                            console.warn("TRC5: updated ", $scope.selectedItems);
                          };
                        },
                        resolve: {
@@ -393,7 +444,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
 
                      modalInstance.result.then(function (selectedArray) {
                          selectedArray.push($scope.layerAddId);
-                         console.warn("selected", selectedArray);
+                         console.warn("TRC6: selected", selectedArray);
 
                          $scope._makeXHRCall({
                              method: "POST", url: $scope.urls.xhr_edit,
@@ -429,7 +480,16 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
     }
 
 
-    $scope.test = function(elementid) {
+    /**
+     * Verifies if a project settings change would trigger layer updates. If user confirmation is needed,
+     * a modal dialog will prompt the user to ack the changes. If not, the editProjectSettings() function is called directly.
+     *
+     * Only "versionlayers" change for is supported (and hardcoded) for now.
+     */
+
+    $scope.testProjectSettingsChange = function(elementid) {
+        if (elementid != '#change-project-version') throw "Not implemented";
+
         $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "versionlayers", value: $scope.projectVersion }}).
         success(function (_data) {
             if (_data.error != "ok") {
@@ -463,17 +523,21 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                        }
                      });
 
-                     modalInstance.result.then(function () { $scope.edit(elementid)});
+                     modalInstance.result.then(function () { $scope.editProjectSettings(elementid)});
                  } else {
-                    $scope.edit(elementid);
+                    $scope.editProjectSettings(elementid);
                  }
             }
         });
     }
 
-    $scope.edit = function(elementid) {
+    /**
+     * Performs changes to project settings, and updates the user interface accordingly.
+     */
+
+    $scope.editProjectSettings = function(elementid) {
         var data = {};
-        console.warn("edit with ", elementid);
+        console.warn("TRC7: editProjectSettings with ", elementid);
         var alertText = undefined;
         var alertZone = undefined;
         var oldLayers = [];
@@ -508,10 +572,14 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
                 alertText += "<strong>" + $scope.project.release.desc + "</strong>. ";
             }
             if (elementid == '#change-project-version') {
+                $scope.layersForTargets = {};   // invalidate error layers for the targets, since layers changed
+
                 // requirement https://bugzilla.yoctoproject.org/attachment.cgi?id=2229, notification for changed version to include layers
                 $scope.zone2alerts.forEach(function (e) { e.close() });
                 alertText += "This has caused the following changes in your project layers:<ul>"
 
+
+                // warnings - this is executed AFTER the generic XHRCall handling is done; at this point,
                 if (_data.layers !== undefined) {
                     // show added/deleted layer notifications; scope.layers is already updated by this point.
                     var addedLayers = [];
@@ -547,6 +615,10 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
     }
 
 
+    /**
+     * Extracts a command passed through the local path in location, and executes/updates UI based on the command
+     */
+
     $scope.updateDisplayWithCommands = function() {
         cmd = $location.path();
 
@@ -630,6 +702,10 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         });
     }
 
+    /**
+     * Utility function to display an alert to the user
+     */
+
     $scope.displayAlert = function(zone, text, type) {
         if (zone.maxid === undefined) { zone.maxid = 0; }
         var crtid = zone.maxid ++;
@@ -644,6 +720,10 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         return o;
     }
 
+    /**
+     * Toggles display items between label and input box (the edit pencil icon) on selected settings in project page
+     */
+
     $scope.toggle = function(id) {
         $scope.projectName = $scope.project.name;
         $scope.projectVersion = $scope.project.release.id;
@@ -657,34 +737,52 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
         keys = Object.keys($scope.mostBuiltTargets);
         keys = keys.filter(function (e) { if ($scope.mostBuiltTargets[e]) return e });
         return keys.length == 0;
+    }
+
+    /**
+     * Helper function to deal with error string recognition and manipulation
+     */
 
+    $scope.getTargetNameFromErrorMsg = function (msg) {
+        targets = msg.split(" ").splice(2).map(function (v) { return v.replace(/'/g, '')})
+        return targets;
     }
 
-    // init code
-    //
-    $scope.init = function() {
-        $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 2000, 0);
+    $scope.fetchLayersForTargets = function () {
+        $scope.builds.forEach(function (buildrequest) {
+            buildrequest.errors.forEach(function (error) {
+                if (error.msg.indexOf("Nothin") == 0) {
+                    $scope.getTargetNameFromErrorMsg(error.msg).forEach(function (target) {
+                        if ($scope.layersForTargets[target] === undefined)
+                        $scope.getAutocompleteSuggestions("layers4target", target).then( function (list) {
+                            $scope.layersForTargets[target] = list;
+                        })
+                    })
+                }
+            })
+        })
     }
 
-    $scope.init();
-});
 
+    /**
+     * Page init code - just init variables and set the automated refresh
+     */
 
-/**
-    TESTING CODE
-*/
+    $scope.init = function() {
+        $scope.canceledBuilds = [];
+        $scope.layersForTargets = {};
+        $scope.fetchLayersForTargets();
+        $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 2000, 0);
+    }
 
-function test_diff_arrays() {
-    _diffArrays([1,2,3], [2,3,4], function(e,f) { return e==f; }, function(e) {console.warn("added", e)}, function(e) {console.warn("deleted", e);})
-}
+});
 
-// test_diff_arrays();
 
 var s = undefined;
 
 function test_set_alert(text) {
     s = angular.element("div#main").scope();
     s.displayAlert(s.zone3alerts, text);
-    console.warn(s.zone3alerts);
+    console.warn("TRC8: zone3alerts", s.zone3alerts);
     s.$digest();
 }
diff --git a/lib/toaster/toastergui/templates/project.html b/lib/toaster/toastergui/templates/project.html
index 2979db7..67b2672 100644
--- a/lib/toaster/toastergui/templates/project.html
+++ b/lib/toaster/toastergui/templates/project.html
@@ -89,9 +89,9 @@ vim: expandtab tabstop=2
 
   <!-- build form -->
   <div class="well">
-    <form class="build-form" ng-submit="targetNamedBuild()">
+    <form class="build-form" ng-submit="buildNamedTarget()">
       <div class="input-append controls">
-        <input type="text" class="huge span7" placeholder="Type the target(s) you want to build" autocomplete="off" ng-model="targetName" typeahead="e.name for e in getSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length"/>
+        <input type="text" class="huge span7" placeholder="Type the target(s) you want to build" autocomplete="off" ng-model="targetName" typeahead="e.name for e in getAutocompleteSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length"/>
         <button type="submit" id="build-button" class="btn btn-large btn-primary" ng-disabled="!targetName.length">
         Build
         </button>
@@ -108,6 +108,9 @@ vim: expandtab tabstop=2
     </form>
   </div>
 
+
+  <!-- latest builds list -->
+
   <a id="buildslist"></a>
   <h2 class="air" ng-if="builds.length">Latest builds</h2>
   <div class="animate-repeat alert"  ng-repeat="b in builds track by b.id" ng-class="{'queued':'alert-info', 'deleted':'alert-info', 'in progress': 'alert-info', 'failed':'alert-error', 'completed':{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.build[0].status]}[b.status]">
@@ -116,9 +119,27 @@ vim: expandtab tabstop=2
 
           <case ng-switch-when="failed">
             <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></div>
+            <div >
+                <button class="btn pull-right btn-danger" ng-click="buildExistingTarget(b.targets)">Run again</button>
+            </div>
             <div class="row-fluid">
               <div class="air well" ng-repeat="e in b.errors">
-                Error type {[e.type]}: <pre>{[e.msg]}</pre>
+                    <pre>{[e.msg]}</pre>
+                  <ngif ng-if="e.msg.indexOf('Nothin') == 0">
+                    <div ng-repeat="t in getTargetNameFromErrorMsg(e.msg)">
+                     <p class="lead">The target <strong>{[t]}</strong> is not provided by any of your project layers.</p>
+                     <p> Your build has failed because the target <strong>{[t]}</strong> is not provided by any of your project layers.</p>
+                     <ngif ng-if="layersForTargets[t].length > 0">
+                       <p>The following layers provide this target. You could add one of them to your project.</p>
+                       <button class="btn btn-danger add-layer-with-dependencies" ng-repeat="l in layersForTargets[t]" ng-click="layerAddById(l.id)">Add {[l.name]}</button>
+                     </ngif>
+                    </div>
+                  </ngif>
+                  <ngif ng-if="e.msg.indexOf('Nothin') != 0">
+                    <p>
+                    Please contact your system administrator to help troubleshoot this error.
+                    </p>
+                  </ngif>
               </div>
             </div>
           </case>
@@ -128,7 +149,7 @@ vim: expandtab tabstop=2
             <div class="span4 lead" >Build queued
               <i title="This build will start as soon as a build server is available" class="icon-question-sign get-help get-help-blue heading-help" data-toggle="tooltip"></i>
             </div>
-            <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button>
+            <button class="btn pull-right btn-info" ng-click="buildCancel(b)">Cancel</button>
           </case>
 
           <case ng-switch-when="created">
@@ -136,7 +157,7 @@ vim: expandtab tabstop=2
             <div class="span6" >
               <span class="lead">Creating build</span>
             </div>
-            <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button>
+            <button class="btn pull-right btn-info" ng-click="buildCancel(b)">Cancel</button>
           </case>
 
           <case ng-switch-when="deleted">
@@ -144,7 +165,7 @@ vim: expandtab tabstop=2
             <div class="span6" id="{[b.id]}-deleted" >
               <span class="lead">Build deleted</span>
             </div>
-            <button class="btn pull-right btn-info" ng-click="buildDelete(b.id)">Close</button>
+            <button class="btn pull-right btn-info" ng-click="buildDelete(b)">Close</button>
           </case>
 
 
@@ -198,7 +219,7 @@ vim: expandtab tabstop=2
             </div>
             <div> <span class="lead">Build time: <a href="{[b.build[0].build_time_page_url]}">{[b.build[0].build_time|timediff]}</a></span>
                 <button class="btn pull-right" ng-class="{'Succeeded':  'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]"
-                    ng-click="targetExistingBuild(b.targets)">Run again</button>
+                    ng-click="buildExistingTarget(b.targets)">Run again</button>
 
             </div>
           </case>
@@ -244,7 +265,7 @@ vim: expandtab tabstop=2
       </div>
       <form ng-submit="layerAdd()">
         <div class="input-append">
-          <input type="text" class="input-xlarge" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" ng-model="layerAddName" typeahead="e.name for e in getSuggestions('layers', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" typeahead-on-select="onLayerSelect($item, $model, $label)" typeahead-editable="false" ng-class="{ 'has-error': layerAddName.$invalid }" />
+          <input type="text" class="input-xlarge" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" ng-model="layerAddName" typeahead="e.name for e in getAutocompleteSuggestions('layers', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" typeahead-on-select="onLayerSelect($item, $model, $label)" typeahead-editable="false" ng-class="{ 'has-error': layerAddName.$invalid }" />
           <input type="submit" id="add-layer" class="btn" value="Add" ng-disabled="!layerAddName.length"/>
         </div>
         {% csrf_token %}
@@ -265,9 +286,9 @@ vim: expandtab tabstop=2
         Targets
         <i class="icon-question-sign get-help heading-help" title="What you build, often a recipe producing a root file system file (an image). Something like <code>core-image-minimal</code> or <code>core-image-sato</code>"></i>
       </h3>
-        <form ng-submit="targetNamedBuild()">
+        <form ng-submit="buildNamedTarget()">
           <div class="input-append">
-            <input type="text" class="input-xlarge" placeholder="Type the target(s) you want to build" autocomplete="off" data-minLength="1"  ng-model="targetName1" typeahead="e.name for e in getSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length">
+            <input type="text" class="input-xlarge" placeholder="Type the target(s) you want to build" autocomplete="off" data-minLength="1"  ng-model="targetName1" typeahead="e.name for e in getAutocompleteSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length">
             <button type="submit" id="build-button" class="btn btn-primary" ng-disabled="!targetName1.length">
               Build </button>
           </div>
@@ -304,8 +325,8 @@ vim: expandtab tabstop=2
           <strong>Machine changes have a big impact on build outcome.</strong>
               You cannot really compare the builds for the new machine with the previous ones.
         </div>
-        <form ng-submit="edit('#select-machine')" class="input-append">
-              <input type="text" id="machine" autocomplete="off" ng-model="machineName" typeahead="m.name for m in getSuggestions('machines', $viewValue)"/>
+        <form ng-submit="editProjectSettings('#select-machine')" class="input-append">
+              <input type="text" id="machine" autocomplete="off" ng-model="machineName" typeahead="m.name for m in getAutocompleteSuggestions('machines', $viewValue)"/>
               <input type="submit" id="apply-change-machine" class="btn" type="button" ng-disabled="machineName == machine.name || machineName.length == 0" value="Save"></input>
               <input type="reset" id="cancel-machine" class="btn btn-link" ng-click="toggle('#select-machine')" value="Cancel"></input>
               {% csrf_token %}
@@ -337,7 +358,7 @@ vim: expandtab tabstop=2
       <i class="icon-pencil" ng-click="toggle('#change-project-name')" ></i>
     </p>
     <div id="change-project-name" style="display:none;">
-      <form ng-submit="edit('#change-project-name')" class="input-append">
+      <form ng-submit="editProjectSettings('#change-project-name')" class="input-append">
         <input type="text" class="input-xlarge" id="type-project-name" ng-model="projectName">
         <input type="submit" class="btn" value="Save" ng-disabled="project.name == projectName"/>
         <input type="reset" class="btn btn-link" value="Cancel" ng-click="toggle('#change-project-name')">
@@ -354,7 +375,7 @@ vim: expandtab tabstop=2
       <i id="change-version" class="icon-pencil" ng-click="toggle('#change-project-version')" ></i>
     </p>
     <div class="div-inline" id="change-project-version" style="display:none;">
-      <form ng-submit="test('#change-project-version')" class="input-append">
+      <form ng-submit="testProjectSettingsChange('#change-project-version')" class="input-append">
         <select id="select-version" ng-model="projectVersion">
           <option ng-repeat="r in releases" value="{[r.id]}" ng-selected="r.id == project.release.id">{[r.description]}</option>
         </select>
@@ -404,6 +425,7 @@ angular.element(document).ready(function() {
   scope.updateDisplayWithCommands();
   scope.validateData();
 
+  scope.init();
   scope.$digest();
 
   });
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 420b37c..8c21ca4 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -40,7 +40,6 @@ from django.utils import formats
 from toastergui.templatetags.projecttags import json as jsonfilter
 import json
 
-
 # all new sessions should come through the landing page;
 # determine in which mode we are running in, and redirect appropriately
 def landing(request):
@@ -52,37 +51,25 @@ def landing(request):
 
     return render(request, 'landing.html')
 
+# returns a list for most recent builds; for use in the Project page, xhr_ updates,  and other places, as needed
 def _project_recent_build_list(prj):
-        # build requests not yet started
-        return (map(lambda x: {
-                "id":  x.pk,
-                "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
-                "status": x.get_state_display(),
-            }, prj.buildrequest_set.filter(state__lt = BuildRequest.REQ_INPROGRESS).order_by("-pk")) +
-        # build requests started, but with no build yet
-            map(lambda x: {
-                "id":  x.pk,
-                "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
-                "status": x.get_state_display(),
-            }, prj.buildrequest_set.filter(state = BuildRequest.REQ_INPROGRESS, build = None).order_by("-pk")) +
-        # build requests that failed
-            map(lambda x: {
-                "id":  x.pk,
-                "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
-                "status": x.get_state_display(),
-                "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()),
-            }, prj.buildrequest_set.filter(state = BuildRequest.REQ_FAILED).order_by("-pk")) +
-        # and already made builds
-            map(lambda x: {
-                "id": x.pk,
-                "targets": map(lambda y: {"target": y.target }, x.target_set.all()),
-                "status": x.get_outcome_display(),
-                "completed_on" : x.completed_on.strftime('%s')+"000",
-                "build_time" : (x.completed_on - x.started_on).total_seconds(),
-                "build_page_url" : reverse('builddashboard', args=(x.pk,)),
-                "completeper": x.completeper(),
-                "eta": x.eta().ctime(),
-            }, prj.build_set.all()))
+    return map(lambda x: {
+            "id":  x.pk,
+            "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.brtarget_set.all()),
+            "status": x.get_state_display(),
+            "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.exclude(errmsg__contains="Command Failed")),
+            "build" : map( lambda y: {"id": y.pk,
+                        "status": y.get_outcome_display(),
+                        "completed_on" : y.completed_on.strftime('%s')+"000",
+                        "build_time" : (y.completed_on - y.started_on).total_seconds(),
+                        "build_page_url" : reverse('builddashboard', args=(y.pk,)),
+                        'build_time_page_url': reverse('buildtime', args=(y.pk,)),
+                        "errors": y.errors_no,
+                        "warnings": y.warnings_no,
+                        "completeper": y.completeper(),
+                        "eta": y.eta().strftime('%s')+"000"}, Build.objects.filter(buildrequest = x)),
+        }, list(prj.buildrequest_set.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) +
+            list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3]))
 
 
 def _build_page_range(paginator, index = 1):
@@ -1959,25 +1946,6 @@ if toastermain.settings.MANAGED:
 
         raise Exception("Invalid HTTP method for this page")
 
-    # returns a list for most recent builds; for use in the Project page, xhr_ updates,  and other places, as needed
-    def _project_recent_build_list(prj):
-        return map(lambda x: {
-                "id":  x.pk,
-                "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.brtarget_set.all()),
-                "status": x.get_state_display(),
-                "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()),
-                "build" : map( lambda y: {"id": y.pk,
-                            "status": y.get_outcome_display(),
-                            "completed_on" : y.completed_on.strftime('%s')+"000",
-                            "build_time" : (y.completed_on - y.started_on).total_seconds(),
-                            "build_page_url" : reverse('builddashboard', args=(y.pk,)),
-                            'build_time_page_url': reverse('buildtime', args=(y.pk,)),
-                            "errors": y.errors_no,
-                            "warnings": y.warnings_no,
-                            "completeper": y.completeper(),
-                            "eta": y.eta().strftime('%s')+"000"}, Build.objects.filter(buildrequest = x)),
-            }, list(prj.buildrequest_set.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) +
-                list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3]))
 
 
     # Shows the edit project page
@@ -2177,7 +2145,7 @@ if toastermain.settings.MANAGED:
                 # all layers for the current project
                 queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('value',''))
 
-                # but not layers with equivalent layers already in project               
+                # but not layers with equivalent layers already in project
                 if not request.GET.has_key('include_added'):
                     queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()])[:8]
 
@@ -2192,7 +2160,9 @@ if toastermain.settings.MANAGED:
                 queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter(
                     layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])])
 
-                return HttpResponse(jsonfilter( { "error":"ok", "list" : map( _lv_to_dict, queryset) }), content_type = "application/json")
+                final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset])
+
+                return HttpResponse(jsonfilter( { "error":"ok", "list" : map( _lv_to_dict, final_list) }), content_type = "application/json")
 
 
 
@@ -2213,16 +2183,36 @@ if toastermain.settings.MANAGED:
                     }), content_type = "application/json")
 
 
+            # 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):
+                    final_list = []
+                else:
+                    queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET.get('value', '__none__'))
+
+                    # exclude layers in the project
+                    queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()])
+
+                    # and show only the selected layers for this project
+                    final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset_all])
+
+                return HttpResponse(jsonfilter( { "error":"ok",  "list" : map( _lv_to_dict, final_list) }), content_type = "application/json")
+
             # returns targets provided by current project layers
             if request.GET['type'] == "targets":
                 queryset_all = Recipe.objects.all()
-                queryset_all = queryset_all.filter(layer_version__in =  prj.projectlayer_equivalent_set())
+                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)
                 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]),
 
                     }), content_type = "application/json")
 
+            # returns machines provided by the current project layers
             if request.GET['type'] == "machines":
                 queryset_all = Machine.objects.all()
                 if 'project_id' in request.session:
@@ -2234,6 +2224,7 @@ if toastermain.settings.MANAGED:
 
                     }), content_type = "application/json")
 
+            # returns all projects
             if request.GET['type'] == "projects":
                 queryset_all = Project.objects.all()
                 ret = { "error": "ok",
-- 
1.9.1



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

end of thread, other threads:[~2015-01-09  0:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-08 13:15 [PATCH 0/5] Toaster patchset pull request Alex DAMIAN
2015-01-08 13:15 ` [PATCH 1/5] toaster: Improve client side error handling Alex DAMIAN
2015-01-08 13:15 ` [PATCH 2/5] toaster: write pre-read conf file for build variables Alex DAMIAN
2015-01-08 13:15 ` [PATCH 3/5] toaster: do not launch web browser on noweb option Alex DAMIAN
2015-01-08 13:15 ` [PATCH 4/5] toaster: branch name priority resolution Alex DAMIAN
2015-01-08 13:15 ` [PATCH 5/5] toaster: implementation of project page Alex DAMIAN

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