diff options
Diffstat (limited to 'bitbake/lib/toaster')
6 files changed, 163 insertions, 69 deletions
diff --git a/bitbake/lib/toaster/orm/migrations/0013_recipe_parse_progress_fields.py b/bitbake/lib/toaster/orm/migrations/0013_recipe_parse_progress_fields.py new file mode 100644 index 0000000000..cc5c96d2dd --- /dev/null +++ b/bitbake/lib/toaster/orm/migrations/0013_recipe_parse_progress_fields.py | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | from __future__ import unicode_literals | ||
| 3 | |||
| 4 | from django.db import migrations, models | ||
| 5 | |||
| 6 | |||
| 7 | class Migration(migrations.Migration): | ||
| 8 | |||
| 9 | dependencies = [ | ||
| 10 | ('orm', '0012_use_release_instead_of_up_branch'), | ||
| 11 | ] | ||
| 12 | |||
| 13 | operations = [ | ||
| 14 | migrations.AddField( | ||
| 15 | model_name='build', | ||
| 16 | name='recipes_parsed', | ||
| 17 | field=models.IntegerField(default=0), | ||
| 18 | ), | ||
| 19 | migrations.AddField( | ||
| 20 | model_name='build', | ||
| 21 | name='recipes_to_parse', | ||
| 22 | field=models.IntegerField(default=1), | ||
| 23 | ), | ||
| 24 | ] | ||
diff --git a/bitbake/lib/toaster/orm/migrations/0014_allow_empty_buildname.py b/bitbake/lib/toaster/orm/migrations/0014_allow_empty_buildname.py new file mode 100644 index 0000000000..4749a14b26 --- /dev/null +++ b/bitbake/lib/toaster/orm/migrations/0014_allow_empty_buildname.py | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | from __future__ import unicode_literals | ||
| 3 | |||
| 4 | from django.db import migrations, models | ||
| 5 | |||
| 6 | |||
| 7 | class Migration(migrations.Migration): | ||
| 8 | |||
| 9 | dependencies = [ | ||
| 10 | ('orm', '0013_recipe_parse_progress_fields'), | ||
| 11 | ] | ||
| 12 | |||
| 13 | operations = [ | ||
| 14 | migrations.AlterField( | ||
| 15 | model_name='build', | ||
| 16 | name='build_name', | ||
| 17 | field=models.CharField(default='', max_length=100), | ||
| 18 | ), | ||
| 19 | ] | ||
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index 2df6d4910a..4641736add 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
| @@ -397,9 +397,15 @@ class Build(models.Model): | |||
| 397 | completed_on = models.DateTimeField() | 397 | completed_on = models.DateTimeField() |
| 398 | outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS) | 398 | outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS) |
| 399 | cooker_log_path = models.CharField(max_length=500) | 399 | cooker_log_path = models.CharField(max_length=500) |
| 400 | build_name = models.CharField(max_length=100) | 400 | build_name = models.CharField(max_length=100, default='') |
| 401 | bitbake_version = models.CharField(max_length=50) | 401 | bitbake_version = models.CharField(max_length=50) |
| 402 | 402 | ||
| 403 | # number of recipes to parse for this build | ||
| 404 | recipes_to_parse = models.IntegerField(default=1) | ||
| 405 | |||
| 406 | # number of recipes parsed so far for this build | ||
| 407 | recipes_parsed = models.IntegerField(default=0) | ||
| 408 | |||
| 403 | @staticmethod | 409 | @staticmethod |
| 404 | def get_recent(project=None): | 410 | def get_recent(project=None): |
| 405 | """ | 411 | """ |
| @@ -615,6 +621,13 @@ class Build(models.Model): | |||
| 615 | else: | 621 | else: |
| 616 | return False | 622 | return False |
| 617 | 623 | ||
| 624 | def is_parsing(self): | ||
| 625 | """ | ||
| 626 | True if the build is still parsing recipes | ||
| 627 | """ | ||
| 628 | return self.outcome == Build.IN_PROGRESS and \ | ||
| 629 | self.recipes_parsed < self.recipes_to_parse | ||
| 630 | |||
| 618 | def get_state(self): | 631 | def get_state(self): |
| 619 | """ | 632 | """ |
| 620 | Get the state of the build; one of 'Succeeded', 'Failed', 'In Progress', | 633 | Get the state of the build; one of 'Succeeded', 'Failed', 'In Progress', |
| @@ -628,6 +641,8 @@ class Build(models.Model): | |||
| 628 | return 'Cancelling'; | 641 | return 'Cancelling'; |
| 629 | elif self.is_queued(): | 642 | elif self.is_queued(): |
| 630 | return 'Queued' | 643 | return 'Queued' |
| 644 | elif self.is_parsing(): | ||
| 645 | return 'Parsing' | ||
| 631 | else: | 646 | else: |
| 632 | return self.get_outcome_text() | 647 | return self.get_outcome_text() |
| 633 | 648 | ||
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py index aa3cbd83b2..b57f670ba3 100644 --- a/bitbake/lib/toaster/toastergui/api.py +++ b/bitbake/lib/toaster/toastergui/api.py | |||
| @@ -87,7 +87,7 @@ class XhrBuildRequest(View): | |||
| 87 | br.save() | 87 | br.save() |
| 88 | 88 | ||
| 89 | except BuildRequest.DoesNotExist: | 89 | except BuildRequest.DoesNotExist: |
| 90 | return error_response('No such build id %s' % i) | 90 | return error_response('No such build request id %s' % i) |
| 91 | 91 | ||
| 92 | return error_response('ok') | 92 | return error_response('ok') |
| 93 | 93 | ||
| @@ -256,6 +256,14 @@ class MostRecentBuildsView(View): | |||
| 256 | build['id'] = build_obj.pk | 256 | build['id'] = build_obj.pk |
| 257 | build['dashboard_url'] = dashboard_url | 257 | build['dashboard_url'] = dashboard_url |
| 258 | 258 | ||
| 259 | buildrequest_id = None | ||
| 260 | if hasattr(build_obj, 'buildrequest'): | ||
| 261 | buildrequest_id = build_obj.buildrequest.pk | ||
| 262 | build['buildrequest_id'] = buildrequest_id | ||
| 263 | |||
| 264 | build['recipes_parsed_percentage'] = \ | ||
| 265 | int((build_obj.recipes_parsed / build_obj.recipes_to_parse) * 100) | ||
| 266 | |||
| 259 | tasks_complete_percentage = 0 | 267 | tasks_complete_percentage = 0 |
| 260 | if build_obj.outcome in (Build.SUCCEEDED, Build.FAILED): | 268 | if build_obj.outcome in (Build.SUCCEEDED, Build.FAILED): |
| 261 | tasks_complete_percentage = 100 | 269 | tasks_complete_percentage = 100 |
diff --git a/bitbake/lib/toaster/toastergui/static/js/mrbsection.js b/bitbake/lib/toaster/toastergui/static/js/mrbsection.js index d8c3bf7750..e7fbf01731 100644 --- a/bitbake/lib/toaster/toastergui/static/js/mrbsection.js +++ b/bitbake/lib/toaster/toastergui/static/js/mrbsection.js | |||
| @@ -33,8 +33,8 @@ function mrbSectionInit(ctx){ | |||
| 33 | return buildData[build.id] || {}; | 33 | return buildData[build.id] || {}; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | // returns true if a build's state changed to "Succeeded" or "Failed" | 36 | // returns true if a build's state changed to "Succeeded", "Failed" |
| 37 | // from some other value | 37 | // or "Cancelled" from some other value |
| 38 | function buildFinished(build) { | 38 | function buildFinished(build) { |
| 39 | var cached = getCached(build); | 39 | var cached = getCached(build); |
| 40 | return cached.state && | 40 | return cached.state && |
| @@ -49,12 +49,18 @@ function mrbSectionInit(ctx){ | |||
| 49 | return (cached.state !== build.state); | 49 | return (cached.state !== build.state); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | // returns true if the complete_percentage changed | 52 | // returns true if the tasks_complete_percentage changed |
| 53 | function progressChanged(build) { | 53 | function tasksProgressChanged(build) { |
| 54 | var cached = getCached(build); | 54 | var cached = getCached(build); |
| 55 | return (cached.tasks_complete_percentage !== build.tasks_complete_percentage); | 55 | return (cached.tasks_complete_percentage !== build.tasks_complete_percentage); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | // returns true if the number of recipes parsed/to parse changed | ||
| 59 | function recipeProgressChanged(build) { | ||
| 60 | var cached = getCached(build); | ||
| 61 | return (cached.recipes_parsed_percentage !== build.recipes_parsed_percentage); | ||
| 62 | } | ||
| 63 | |||
| 58 | function refreshMostRecentBuilds(){ | 64 | function refreshMostRecentBuilds(){ |
| 59 | libtoaster.getMostRecentBuilds( | 65 | libtoaster.getMostRecentBuilds( |
| 60 | libtoaster.ctx.mostRecentBuildsUrl, | 66 | libtoaster.ctx.mostRecentBuildsUrl, |
| @@ -68,10 +74,6 @@ function mrbSectionInit(ctx){ | |||
| 68 | var colourClass; | 74 | var colourClass; |
| 69 | var elements; | 75 | var elements; |
| 70 | 76 | ||
| 71 | // classes on the parent which signify the build state and affect | ||
| 72 | // the colour of the container for the build | ||
| 73 | var buildStateClasses = 'alert-info alert-success alert-danger'; | ||
| 74 | |||
| 75 | for (var i = 0; i < data.length; i++) { | 77 | for (var i = 0; i < data.length; i++) { |
| 76 | build = data[i]; | 78 | build = data[i]; |
| 77 | 79 | ||
| @@ -91,31 +93,25 @@ function mrbSectionInit(ctx){ | |||
| 91 | container = $(selector); | 93 | container = $(selector); |
| 92 | 94 | ||
| 93 | container.html(html); | 95 | container.html(html); |
| 94 | |||
| 95 | // style the outermost container for this build to reflect | ||
| 96 | // the new build state (red, green, blue); | ||
| 97 | // NB class set here should be in buildStateClasses | ||
| 98 | colourClass = 'alert-info'; | ||
| 99 | if (build.state == 'Succeeded') { | ||
| 100 | colourClass = 'alert-success'; | ||
| 101 | } | ||
| 102 | else if (build.state == 'Failed') { | ||
| 103 | colourClass = 'alert-danger'; | ||
| 104 | } | ||
| 105 | |||
| 106 | elements = $('[data-latest-build-result="' + build.id + '"]'); | ||
| 107 | elements.removeClass(buildStateClasses); | ||
| 108 | elements.addClass(colourClass); | ||
| 109 | } | 96 | } |
| 110 | else if (progressChanged(build)) { | 97 | else if (tasksProgressChanged(build)) { |
| 111 | // update the progress text | 98 | // update the task progress text |
| 112 | selector = '#build-pc-done-' + build.id; | 99 | selector = '#build-pc-done-' + build.id; |
| 113 | $(selector).html(build.tasks_complete_percentage); | 100 | $(selector).html(build.tasks_complete_percentage); |
| 114 | 101 | ||
| 115 | // update the progress bar | 102 | // update the task progress bar |
| 116 | selector = '#build-pc-done-bar-' + build.id; | 103 | selector = '#build-pc-done-bar-' + build.id; |
| 117 | $(selector).width(build.tasks_complete_percentage + '%'); | 104 | $(selector).width(build.tasks_complete_percentage + '%'); |
| 118 | } | 105 | } |
| 106 | else if (recipeProgressChanged(build)) { | ||
| 107 | // update the recipe progress text | ||
| 108 | selector = '#recipes-parsed-percentage-' + build.id; | ||
| 109 | $(selector).html(build.recipes_parsed_percentage); | ||
| 110 | |||
| 111 | // update the recipe progress bar | ||
| 112 | selector = '#recipes-parsed-percentage-bar-' + build.id; | ||
| 113 | $(selector).width(build.recipes_parsed_percentage + '%'); | ||
| 114 | } | ||
| 119 | 115 | ||
| 120 | buildData[build.id] = build; | 116 | buildData[build.id] = build; |
| 121 | } | 117 | } |
| @@ -128,6 +124,6 @@ function mrbSectionInit(ctx){ | |||
| 128 | ); | 124 | ); |
| 129 | } | 125 | } |
| 130 | 126 | ||
| 131 | window.setInterval(refreshMostRecentBuilds, 1000); | 127 | window.setInterval(refreshMostRecentBuilds, 1500); |
| 132 | refreshMostRecentBuilds(); | 128 | refreshMostRecentBuilds(); |
| 133 | } | 129 | } |
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html index 302b4b0da4..880485d45f 100644 --- a/bitbake/lib/toaster/toastergui/templates/mrb_section.html +++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html | |||
| @@ -26,7 +26,9 @@ | |||
| 26 | <div class="row project-name"> | 26 | <div class="row project-name"> |
| 27 | <div class="col-md-12"> | 27 | <div class="col-md-12"> |
| 28 | <small> | 28 | <small> |
| 29 | <a class="alert-link text-uppercase" href={% project_url build.project %}>{{build.project.name}}</a> | 29 | <a class="alert-link text-uppercase" href="{% project_url build.project %}"> |
| 30 | {{build.project.name}} | ||
| 31 | </a> | ||
| 30 | </small> | 32 | </small> |
| 31 | </div> | 33 | </div> |
| 32 | </div> | 34 | </div> |
| @@ -52,14 +54,18 @@ | |||
| 52 | <%:targets_abbreviated%> | 54 | <%:targets_abbreviated%> |
| 53 | </span> | 55 | </span> |
| 54 | </a> | 56 | </a> |
| 55 | <%else%> | 57 | <%else targets_abbreviated !== ''%> |
| 56 | <span data-toggle="tooltip" data-role="targets-text" title="Recipes: <%:targets%>"> | 58 | <span data-toggle="tooltip" data-role="targets-text" title="Recipes: <%:targets%>"> |
| 57 | <%:targets_abbreviated%> | 59 | <%:targets_abbreviated%> |
| 58 | </span> | 60 | </span> |
| 61 | <%else%> | ||
| 62 | ...targets not yet available... | ||
| 59 | <%/if%> | 63 | <%/if%> |
| 60 | </div> | 64 | </div> |
| 61 | 65 | ||
| 62 | <%if state == 'Queued'%> | 66 | <%if state == 'Parsing'%> |
| 67 | <%include tmpl='#parsing-recipes-build-template'/%> | ||
| 68 | <%else state == 'Queued'%> | ||
| 63 | <%include tmpl='#queued-build-template'/%> | 69 | <%include tmpl='#queued-build-template'/%> |
| 64 | <%else state == 'Succeeded' || state == 'Failed'%> | 70 | <%else state == 'Succeeded' || state == 'Failed'%> |
| 65 | <%include tmpl='#succeeded-or-failed-build-template'/%> | 71 | <%include tmpl='#succeeded-or-failed-build-template'/%> |
| @@ -75,21 +81,38 @@ | |||
| 75 | <!-- queued build --> | 81 | <!-- queued build --> |
| 76 | <script id="queued-build-template" type="text/x-jsrender"> | 82 | <script id="queued-build-template" type="text/x-jsrender"> |
| 77 | <div class="col-md-5"> | 83 | <div class="col-md-5"> |
| 84 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue" title="This build is waiting for | ||
| 85 | the build directory to become available"></span> | ||
| 86 | |||
| 78 | Build queued | 87 | Build queued |
| 79 | </div> | 88 | </div> |
| 80 | 89 | ||
| 81 | <div class="col-md-4"> | 90 | <div class="col-md-4"> |
| 82 | <%if is_default_project_build%> | 91 | <!-- cancel button --> |
| 83 | <!-- no cancel icon --> | 92 | <%include tmpl='#cancel-template'/%> |
| 84 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> | 93 | </div> |
| 85 | <%else%> | 94 | </script> |
| 86 | <!-- cancel button --> | 95 | |
| 87 | <span class="cancel-build-btn pull-right alert-link" | 96 | <!-- parsing recipes build --> |
| 88 | data-buildrequest-id="<%:id%>" data-request-url="<%:cancel_url%>"> | 97 | <script id="parsing-recipes-build-template" type="text/x-jsrender"> |
| 89 | <span class="glyphicon glyphicon-remove-circle"></span> | 98 | <!-- progress bar and parse completion percentage --> |
| 90 | Cancel | 99 | <div data-role="build-status" class="col-md-4 col-md-offset-1 progress-info"> |
| 91 | </span> | 100 | <!-- progress bar --> |
| 92 | <%/if%> | 101 | <div class="progress"> |
| 102 | <div id="recipes-parsed-percentage-bar-<%:id%>" | ||
| 103 | style="width: <%:recipes_parsed_percentage%>%;" | ||
| 104 | class="progress-bar"> | ||
| 105 | </div> | ||
| 106 | </div> | ||
| 107 | </div> | ||
| 108 | |||
| 109 | <div class="col-md-4 progress-info"> | ||
| 110 | <!-- parse completion percentage --> | ||
| 111 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue" title="BitBake is parsing the layers required for your build"></span> | ||
| 112 | |||
| 113 | Parsing <span id="recipes-parsed-percentage-<%:id%>"><%:recipes_parsed_percentage%></span>% complete | ||
| 114 | |||
| 115 | <%include tmpl='#cancel-template'/%> | ||
| 93 | </div> | 116 | </div> |
| 94 | </script> | 117 | </script> |
| 95 | 118 | ||
| @@ -110,17 +133,9 @@ | |||
| 110 | <!-- task completion percentage --> | 133 | <!-- task completion percentage --> |
| 111 | <span id="build-pc-done-<%:id%>"><%:tasks_complete_percentage%></span>% of | 134 | <span id="build-pc-done-<%:id%>"><%:tasks_complete_percentage%></span>% of |
| 112 | tasks complete | 135 | tasks complete |
| 113 | <%if is_default_project_build%> | 136 | |
| 114 | <!-- no cancel icon --> | 137 | <!-- cancel button --> |
| 115 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> | 138 | <%include tmpl='#cancel-template'/%> |
| 116 | <%else%> | ||
| 117 | <!-- cancel button --> | ||
| 118 | <span class="cancel-build-btn pull-right alert-link" | ||
| 119 | data-buildrequest-id="<%:id%>" data-request-url="<%:cancel_url%>"> | ||
| 120 | <span class="glyphicon glyphicon-remove-circle"></span> | ||
| 121 | Cancel | ||
| 122 | </span> | ||
| 123 | <%/if%> | ||
| 124 | </div> | 139 | </div> |
| 125 | </script> | 140 | </script> |
| 126 | 141 | ||
| @@ -162,19 +177,8 @@ | |||
| 162 | <div class="col-md-3"> | 177 | <div class="col-md-3"> |
| 163 | Build time: <a class="alert-link" href="<%:buildtime_url%>"><%:buildtime%></a> | 178 | Build time: <a class="alert-link" href="<%:buildtime_url%>"><%:buildtime%></a> |
| 164 | 179 | ||
| 165 | <%if is_default_project_build%> | 180 | <!-- rebuild button --> |
| 166 | <!-- info icon --> | 181 | <%include tmpl='#rebuild-template'/%> |
| 167 | <span class="pull-right glyphicon glyphicon-question-sign get-help <%if state == 'Success'%>get-help-green<%else state == 'Failed'%>get-help-red<%else%>get-help-blue<%/if%>" | ||
| 168 | title="Builds in this project cannot be started from Toaster: they are started from the command line"> | ||
| 169 | </span> | ||
| 170 | <%else%> | ||
| 171 | <!-- rebuild button --> | ||
| 172 | <span class="rebuild-btn alert-link <%if state == 'Success'%>success<%else state == 'Failed'%>danger<%else%>info<%/if%> pull-right" | ||
| 173 | data-request-url="<%:rebuild_url%>" data-target='<%:build_targets_json%>'> | ||
| 174 | <span class="glyphicon glyphicon-repeat"></span> | ||
| 175 | Rebuild | ||
| 176 | </span> | ||
| 177 | <%/if%> | ||
| 178 | </div> | 182 | </div> |
| 179 | </script> | 183 | </script> |
| 180 | 184 | ||
| @@ -187,12 +191,40 @@ | |||
| 187 | 191 | ||
| 188 | <!-- rebuild button --> | 192 | <!-- rebuild button --> |
| 189 | <div class="col-md-3"> | 193 | <div class="col-md-3"> |
| 190 | <span class="info pull-right rebuild-btn alert-link" | 194 | <%include tmpl='#rebuild-template'/%> |
| 195 | </div> | ||
| 196 | </script> | ||
| 197 | |||
| 198 | <!-- rebuild button or no rebuild icon --> | ||
| 199 | <script id="rebuild-template" type="text/x-jsrender"> | ||
| 200 | <%if is_default_project_build%> | ||
| 201 | <!-- no rebuild info icon --> | ||
| 202 | <span class="pull-right glyphicon glyphicon-question-sign get-help <%if state == 'Success'%>get-help-green<%else state == 'Failed'%>get-help-red<%else%>get-help-blue<%/if%>" | ||
| 203 | title="Builds in this project cannot be started from Toaster: they are started from the command line"> | ||
| 204 | </span> | ||
| 205 | <%else%> | ||
| 206 | <!-- rebuild button --> | ||
| 207 | <span class="rebuild-btn alert-link <%if state == 'Success'%>success<%else state == 'Failed'%>danger<%else%>info<%/if%> pull-right" | ||
| 191 | data-request-url="<%:rebuild_url%>" data-target='<%:build_targets_json%>'> | 208 | data-request-url="<%:rebuild_url%>" data-target='<%:build_targets_json%>'> |
| 192 | <span class="glyphicon glyphicon-repeat"></span> | 209 | <span class="glyphicon glyphicon-repeat"></span> |
| 193 | Rebuild | 210 | Rebuild |
| 194 | </span> | 211 | </span> |
| 195 | </div> | 212 | <%/if%> |
| 213 | </script> | ||
| 214 | |||
| 215 | <!-- cancel button or no cancel icon --> | ||
| 216 | <script id="cancel-template" type="text/x-jsrender"> | ||
| 217 | <%if is_default_project_build%> | ||
| 218 | <!-- no cancel icon --> | ||
| 219 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> | ||
| 220 | <%else%> | ||
| 221 | <!-- cancel button --> | ||
| 222 | <span class="cancel-build-btn pull-right alert-link" | ||
| 223 | data-buildrequest-id="<%:buildrequest_id%>" data-request-url="<%:cancel_url%>"> | ||
| 224 | <span class="glyphicon glyphicon-remove-circle"></span> | ||
| 225 | Cancel | ||
| 226 | </span> | ||
| 227 | <%/if%> | ||
| 196 | </script> | 228 | </script> |
| 197 | 229 | ||
| 198 | <script> | 230 | <script> |
