diff options
author | Elliot Smith <elliot.smith@intel.com> | 2016-07-11 14:47:06 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-08-11 00:09:26 +0100 |
commit | dd99cf957da5836dc9b48d200f15a66f0bbce245 (patch) | |
tree | e7b8b8fa6b88520aabd6f17bc41cc8410af66761 /bitbake/lib/toaster | |
parent | 952ffb3e1f4a00793e0c9c49bc0c8fb8729424c4 (diff) | |
download | poky-dd99cf957da5836dc9b48d200f15a66f0bbce245.tar.gz |
bitbake: toaster: show progress of recipe parsing in recent builds area
Modify buildinfohelper and toasterui so that they record the
recipe parse progress (from ParseProgress events in bitbake)
on the Build object.
Note that because the Build object is now created at the
point when ParseStarted occurs, it is necessary to set the
build name to the empty string initially (hence the migration).
The build name can be set when the build properly starts,
i.e. at the BuildStarted event.
Then use this additional data to determine whether a Build
is in a "Parsing" state, and report this in the JSON API.
This enables the most recent builds area to show the recipe
parse progress.
Add additional logic to update the progress bar if the progress
for a build object changes.
[YOCTO #9631]
(Bitbake rev: f33d51d46d70e73e04e325807c1bc4eb68462f7b)
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
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> |