Skip to contentSkip to conversation

toaster patchset upstream submission

PATCH New Alex DAMIAN 1 participant 10 messages Mar 27, 2014

lore
Share & tools
lore
#0 lore raw

cover toaster patchset upstream submission

From: Alexandru DAMIAN <[email protected]>

Hello,

This is a pull request for Toaster UI patches. The patches have been reviewed on the toaster mail list.

Can you please merge ?

Thank you,
Alex

The following changes since commit 0664fa15597785dd90cf205531a9801e6da6ba47:

knotty: Show a link to the logfile for failed setscene tasks (2014-03-27 10:41:36 +0000)

are available in the git repository at:

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

Belen Barros Pena (1):
toaster: Fix typo in heading code

Dave Lerner (2):
toaster: show installed package name
toaster: fix dirinfo empty dir expansion

David Reyna (6):
toaster: add Image detail and multiple targets to dashboard
toaster: blocks for custom/highlighted navigation and breadcrumb links
toaster: insure _get_query returns distinct records
toaster: add support for empty states in pages
toaster: added file types to the Outputs column in the build
toaster: filter tasks with cache attempts for all attempts

 lib/toaster/orm/models.py                          |   5 +
 lib/toaster/toastergui/static/css/default.css      |   4 +-
 lib/toaster/toastergui/static/img/toaster.png      | Bin 0 -> 51986 bytes
 .../toastergui/templates/basebuildpage.html        |  51 ++++++--
 lib/toaster/toastergui/templates/bpackage.html     |  40 ++++--
 lib/toaster/toastergui/templates/build.html        |  56 ++++++--
 .../toastergui/templates/builddashboard.html       |  89 ++++++++++---
 .../toastergui/templates/configuration.html        |   6 +-
 lib/toaster/toastergui/templates/configvars.html   |  12 +-
 .../templates/package_built_dependencies.html      |  10 +-
 .../toastergui/templates/package_built_detail.html |   8 +-
 .../toastergui/templates/package_detail_base.html  |  36 ++++--
 .../templates/package_included_dependencies.html   |  31 +++--
 .../templates/package_included_detail.html         |  14 +-
 .../package_included_reverse_dependencies.html     |  17 ++-
 lib/toaster/toastergui/templates/recipes.html      |   4 +
 lib/toaster/toastergui/templates/target.html       |  10 ++
 lib/toaster/toastergui/templates/tasks.html        |  64 ++++++++--
 lib/toaster/toastergui/templatetags/projecttags.py |  19 +--
 lib/toaster/toastergui/views.py                    | 142 +++++++++++++++++----
 20 files changed, 474 insertions(+), 144 deletions(-)
 create mode 100755 lib/toaster/toastergui/static/img/toaster.png
Signature · 1 line
1.8.3.2
#1 lore raw

PATCH 1/9 toaster: add Image detail and multiple targets to dashboard

From: David Reyna <[email protected]>

Filled in the Image section detail information and allow for multiple targets. Each target has a separate section. Added license manifest display. Changed the target of the license manifest link. Added Tasks failed in the build summary. The target lists required filters to create sorted lists.

[YOCTO #4258]
[YOCTO #5936]

---
 lib/toaster/orm/models.py                          |  5 ++
 .../toastergui/templates/basebuildpage.html        |  7 +-
 .../toastergui/templates/builddashboard.html       | 87 +++++++++++++++++-----
 lib/toaster/toastergui/views.py                    | 49 +++++++++++-
 4 files changed, 122 insertions(+), 26 deletions(-)
lib/toaster/orm/models.py +5 -0
index 3059908..4975433 100644
@@ -50,6 +50,11 @@ class Build(models.Model):
     build_name = models.CharField(max_length=100)
     bitbake_version = models.CharField(max_length=50)
 
+    def get_sorted_target_list(self):
+        tgts = Target.objects.filter(build_id = self.id).order_by( 'target' );
+        return( tgts );
+
+
 @python_2_unicode_compatible
 class Target(models.Model):
     search_allowed_fields = ['target', 'file_name']
lib/toaster/toastergui/templates/basebuildpage.html +5 -2
index 636fca2..0ce5dbd 100644
@@ -1,4 +1,5 @@
 {% extends "base.html" %}
+{% load projecttags %}
 {% load humanize %}
 {% block pagecontent %}
 
@@ -8,7 +9,7 @@
     <div class="section">
         <ul class="breadcrumb" id="breadcrumb">
 <li><a href="{% url 'all-builds' %}">All builds</a></li>
-<li><a href="{%url 'builddashboard' build.pk%}">{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+{{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
+<li><a href="{%url 'builddashboard' build.pk%}">{{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
             {% block localbreadcrumb %}{% endblock %}
         </ul>
         <script>
@@ -25,10 +26,12 @@
         <!-- begin left sidebar container -->
         <div id="nav" class="span2">
             <ul class="nav nav-list well">
+              {% if build.target_set.all.0.is_image %}
                 <li class="nav-header">Images</li>
-            {% for t in build.target_set.all|dictsort:"target" %}
+            {% for t in build.get_sorted_target_list %}
                 <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
             {% endfor %}
+                  {% endif %}
                 <li class="nav-header">Build</li>
                 <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
                 <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
lib/toaster/toastergui/templates/builddashboard.html +67 -20

129 lines not on this page · raw message

lib/toaster/toastergui/views.py +45 -4

70 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#2 lore raw

PATCH 2/9 toaster: blocks for custom/highlighted navigation and breadcrumb links

From: David Reyna <[email protected]>

Implement the navigation links as blocks so that each page can override and have its respective link appear highlighted. Make the build breadcrumb a block so that it is customizable to not be a link for the dashboard page. Reorder the page headers to be consistent order for extends, projecttags, localbreadcrumb, nav-links.

[YOCTO #5916]
[YOCTO #4258]

---
 .../toastergui/templates/basebuildpage.html        | 50 ++++++++++++++++------
 lib/toaster/toastergui/templates/bpackage.html     |  6 ++-
 .../toastergui/templates/builddashboard.html       |  4 ++
 .../toastergui/templates/configuration.html        |  6 ++-
 lib/toaster/toastergui/templates/configvars.html   | 10 +++--
 lib/toaster/toastergui/templates/recipes.html      |  4 ++
 lib/toaster/toastergui/templates/target.html       | 10 +++++
 lib/toaster/toastergui/templates/tasks.html        | 30 +++++++++++++
 8 files changed, 101 insertions(+), 19 deletions(-)
lib/toaster/toastergui/templates/basebuildpage.html +36 -14
index 0ce5dbd..778c4d4 100644
@@ -9,7 +9,13 @@
     <div class="section">
         <ul class="breadcrumb" id="breadcrumb">
 <li><a href="{% url 'all-builds' %}">All builds</a></li>
-<li><a href="{%url 'builddashboard' build.pk%}">{{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
+            <li>
+            {% block parentbreadcrumb %}
+            <a href="{%url 'builddashboard' build.pk%}">
+                {{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})
+            </a>
+            {% endblock %}
+            </li>
             {% block localbreadcrumb %}{% endblock %}
         </ul>
         <script>
@@ -28,19 +34,35 @@
             <ul class="nav nav-list well">
               {% if build.target_set.all.0.is_image %}
                 <li class="nav-header">Images</li>
-            {% for t in build.get_sorted_target_list %}
-                <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
-            {% endfor %}
-                  {% endif %}
-                <li class="nav-header">Build</li>
-                <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
-                <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
-                <li><a href="{% url 'recipes' build.pk %}">Recipes</a></li>
-                <li><a href="{% url 'packages' build.pk %}">Packages</a></li>
-                <li class="nav-header">Performance</li>
-                <li><a href="{% url 'buildtime' build.pk %}">Time</a></li>
-                <li><a href="{% url 'cpuusage' build.pk %}">CPU usage</a></li>
-                <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
+                {% block nav-target %}
+                  {% for t in build.get_sorted_target_list %}
+                    <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
+                  {% endfor %}
+                {% endblock %}
+              {% endif %}
+              <li class="nav-header">Build</li>
+              {% block nav-configuration %}
+                  <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
+              {% endblock %}
+              {% block nav-tasks %}
+                  <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
+              {% endblock %}
+              {% block nav-recipes %}
+                  <li><a href="{% url 'recipes' build.pk %}">Recipes</a></li>
+              {% endblock %}
+              {% block nav-packages %}
+                  <li><a href="{% url 'packages' build.pk %}">Packages</a></li>
+              {% endblock %}
+                  <li class="nav-header">Performance</li>
+              {% block nav-buildtime %}
+                  <li><a href="{% url 'buildtime' build.pk %}">Time</a></li>
+              {% endblock %}
+              {% block nav-cpuusage %}
+                  <li><a href="{% url 'cpuusage' build.pk %}">CPU usage</a></li>
+              {% endblock %}
+              {% block nav-diskio %}
+                  <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
+              {% endblock %}
             </ul>
         </div>
         <!-- end left sidebar container -->
lib/toaster/toastergui/templates/bpackage.html +5 -1
index dad0d7f..77f7894 100644
@@ -6,6 +6,10 @@
 <li>Packages</li>
 {% endblock %}
 
+{% block nav-packages %}
+  <li class="active"><a href="{% url 'packages' build.pk %}">Packages</a></li>
+{% endblock %}
+
 {% block buildinfomain %}
 <div class="span10">
 <div class="page-header">
@@ -30,7 +34,7 @@
         </form>
       </div>
   </div>
-  
+
 {% else %}
 {% include "basetable_top.html" %}
 
lib/toaster/toastergui/templates/builddashboard.html +4 -0
index 9d91f40..6563128 100644
@@ -2,6 +2,10 @@
 {% load humanize %}
 {% load projecttags %}
 
+{% block parentbreadcrumb %}
+{{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})
+{% endblock %}
+
 {% block buildinfomain %}
 <!-- page title -->
 <div class="row-fluid span10">
lib/toaster/toastergui/templates/configuration.html +5 -1
index 674f896..49a6a89 100644
@@ -1,9 +1,13 @@
 {% extends "basebuildpage.html" %}
+{% load projecttags %}
+
 {% block localbreadcrumb %}
 <li>Configuration</li>
 {% endblock %}
 
-{% load projecttags %}
+{% block nav-configuration %}
+  <li class="active"><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
+{% endblock %}
 
 {% block buildinfomain %}
 <!-- page title -->
lib/toaster/toastergui/templates/configvars.html +7 -3
index 24cb2a5..de4940e 100644
@@ -1,9 +1,13 @@
 {% extends "basebuildpage.html" %}
+{% load projecttags %}
+
 {% block localbreadcrumb %}
 <li>Configuration</li>
 {% endblock %}
 
-{% load projecttags %}
+{% block nav-configuration %}
+  <li class="active"><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
+{% endblock %}
 
 {% block buildinfomain %}
 <!-- page title -->
@@ -30,7 +34,7 @@
 
   <!-- variables -->
   <div id="variables" class="tab-pane">
-  
+
   {% if objects.paginator.count == 0 %}
   <div class="row-fluid">
       <div class="alert">
@@ -41,7 +45,7 @@
         </form>
       </div>
   </div>
-  
+
   {% else %}
   {% include "basetable_top.html" %}
 
lib/toaster/toastergui/templates/recipes.html +4 -0
index 22c3d1a..907b83d 100755
@@ -6,6 +6,10 @@
 <li>Recipes</li>
 {% endblock %}
 
+{% block nav-recipes %}
+  <li class="active"><a href="{% url 'recipes' build.pk %}">Recipes</a></li>
+{% endblock %}
+
 {% block buildinfomain %}
 <div class="span10">
 <div class="page-header">
lib/toaster/toastergui/templates/target.html +10 -0
index 5396b17..ceffada 100644
@@ -5,6 +5,16 @@
 
 {% load projecttags %}
 
+{% block nav-target %}
+  {% for t in build.get_sorted_target_list %}
+    {% ifequal target.pk t.pk %}
+      <li class="active"><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
+    {% else %}
+      <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
+    {% endifequal %}
+  {% endfor %}
+{% endblock %}
+
 {% block buildinfomain %}
 
 <div class="row-fluid span10">
lib/toaster/toastergui/templates/tasks.html +30 -0
index ace30de..8c73dc2 100644
@@ -1,9 +1,39 @@
 {% extends "basebuildpage.html" %}
 {% load projecttags %}
+
 {% block localbreadcrumb %}
 <li>{{title}}</li>
 {% endblock %}
 
+{% block nav-tasks %}
+  {% if 'Tasks' == title %}
+    <li class="active"><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
+  {% else %}
+    <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
+  {% endif %}
+{% endblock %}
+{% block nav-buildtime %}
+  {% if 'Time' == title %}
+    <li class="active"><a href="{% url 'buildtime' build.pk %}">Time</a></li>
+  {% else %}
+    <li><a href="{% url 'buildtime' build.pk %}">Time</a></li>
+  {% endif %}
+{% endblock %}
+{% block nav-cpuusage %}
+  {% if 'CPU usage' == title %}
+    <li class="active"><a href="{% url 'cpuusage' build.pk %}">CPU usage</a></li>
+  {% else %}
+    <li><a href="{% url 'cpuusage' build.pk %}">CPU usage</a></li>
+  {% endif %}
+{% endblock %}
+{% block nav-diskio %}
+  {% if 'Disk I/O' == title %}
+    <li class="active"><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
+  {% else %}
+    <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
+  {% endif %}
+{% endblock %}
+
 {% block buildinfomain %}
 <div class="span10">
 <div class="page-header">
Signature · 1 line
1.8.3.2
#3 lore raw

PATCH 3/9 toaster: insure _get_query returns distinct records

In reply to Alex DAMIAN

From: David Reyna <[email protected]>

The '_get_query' can return duplicate records if a search term appears multiple times in the same row, so the queryset must be made distinct before returning.
This commit also removes the initial special case for configvars in favor of this general solution.

[YOCTO #6012]

---
 lib/toaster/toastergui/views.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
lib/toaster/toastergui/views.py +3 -4
index 4f31ddb..8f6e201 100644
@@ -192,7 +192,8 @@ def _get_queryset(model, queryset, filter_string, search_term, ordering_string):
         else:
             queryset = queryset.order_by(column)
 
-    return queryset
+    # insure only distinct records (e.g. from multiple search hits) are returned 
+    return queryset.distinct()
 
 # shows the "all builds" page
 def builds(request):
@@ -1060,10 +1061,8 @@ def configvars(request, build_id):
         return _redirect_parameters( 'configvars', request.GET, mandatory_parameters, build_id = build_id)
 
     queryset = Variable.objects.filter(build=build_id).exclude(variable_name__istartswith='B_').exclude(variable_name__istartswith='do_')
-    queryset_with_search =  _get_queryset(Variable, queryset, None, search_term, ordering_string).distinct().exclude(variable_value='',vhistory__file_name__isnull=True)
+    queryset_with_search =  _get_queryset(Variable, queryset, None, search_term, ordering_string).exclude(variable_value='',vhistory__file_name__isnull=True)
     queryset = _get_queryset(Variable, queryset, filter_string, search_term, ordering_string)
-    # remove duplicate records from multiple search hits in the VariableHistory table
-    queryset = queryset.distinct()
     # remove records where the value is empty AND there are no history files
     queryset = queryset.exclude(variable_value='',vhistory__file_name__isnull=True)
 
Signature · 1 line
1.8.3.2
#4 lore raw

PATCH 4/9 toaster: Fix typo in heading code

In reply to Alex DAMIAN

From: Belen Barros Pena <[email protected]>

Fix typo in the code that handles the changes in the h1 text in order to display the number of results returned by a search.

[YOCTO #6001]

---
 lib/toaster/toastergui/templates/configvars.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/toaster/toastergui/templates/configvars.html +1 -1
index de4940e..1bd29aa 100644
@@ -16,7 +16,7 @@
  <h1>
   {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %}
       {{objects.paginator.count}} variable{{objects.paginator.count|pluralize}} found
-  {%elif request.GET.filter and objects.paginator.count == 0 or request.GETs.search and objects.paginator.count == 0 %}
+  {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %}
       No variables found
   {%else%}
       Configuration
Signature · 1 line
1.8.3.2
#5 lore raw

PATCH 5/9 toaster: show installed package name

In reply to Alex DAMIAN

From: Dave Lerner <[email protected]>

[YOCTO #5922]

Implement changes that show the installed package name after the official 'recipe-named' package name. If the alias exists and is different than the package name, then the alias is shown as a 'muted' string after the package name in the form 'as some-alias-name'. This formatting appears in the included package pages in the elements:
* local breadcrumbs at the top of package included pages,
* <h1> title headings along with a help bubble that is not hovering, and
* package lists where the help bubble appears when the mouse hovers over the row.

The changes in detail in this patch per file are:
views.py
- added function that tests whether the package object's installed_name should be shown,
- added function that appends package name with version and revision to encapsulate package name formatting in one place and referred to as package.fullpackagespec,
- changed package_built* and package_included* functions to use both of the above new formatting functions, passing the formatted values to templates, and
- adhered to django coding styles by renaming module local 'get_package*' functions with "_" prefix.

package_detail_base.html
- added display of package aliases for included package page,
- refactored to use package.fullpackagespec, formatted by view function,
- added javascript function to format package alias with help, and
- removed trailing whitespace.

package_included_detail.html
- used javascript function above to format package alias, and
- refactored to use package.fullpackagespec.

package_included_dependencies.html
- used javascript function above to format package alias,
- refactored to use package.fullpackagespec,
- forced empty data cells following hover-help to draw borders by appending space, and
- removed trailing whitespace.

package_included_reverse_dependencies.html
- use javascript function above to format package alias,
- refactor to use views fullpackagespe, and
- force empty data cells following hover-help to draw borders by appending space.

package_built_detail.html
- refactored to use package.fullpackagespec, and
- removed trailing whitespace.

package_built_dependencies.html
- refactored to use package.fullpackagespec, and
- removed trailing whitespace.

projecttags.py
- removed unused filter to handle installed name
- removed extra spaces around "title = " in format_vpackage_namehelp

---
 .../templates/package_built_dependencies.html      | 10 ++--
 .../toastergui/templates/package_built_detail.html |  8 +--
 .../toastergui/templates/package_detail_base.html  | 36 ++++++++++---
 .../templates/package_included_dependencies.html   | 31 ++++++-----
 .../templates/package_included_detail.html         | 14 +++--
 .../package_included_reverse_dependencies.html     | 17 +++---
 lib/toaster/toastergui/templatetags/projecttags.py | 10 +---
 lib/toaster/toastergui/views.py                    | 60 +++++++++++++++++-----
 8 files changed, 121 insertions(+), 65 deletions(-)
lib/toaster/toastergui/templates/package_built_dependencies.html +4 -6
index 4932f74..a2011d6 100644
@@ -2,7 +2,6 @@
 {% load projecttags %}
 
 {% block tabcontent %}
-    {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
         <ul class="nav nav-pills">
             <li class="">
                 <a href="{% url 'package_built_detail' build.id package.id %}">
@@ -21,11 +20,11 @@
             <div class="tab-pane active" id="dependencies">
             {% ifequal runtime_deps|length 0 %}
                 <div class="alert alert-info">
-                    <strong>{{fullPackageSpec}}</strong> has no runtime dependencies.
+                    <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies.
                 </div>
             {% else %}
                 <div class="alert alert-info">
-                    <strong>{{fullPackageSpec}}</strong> is <strong>not included</strong> in any image.  These are its projected runtime dependencies if you were to include it in future builds.
+                    <strong>{{package.fullpackagespec}}</strong> is <strong>not included</strong> in any image.  These are its projected runtime dependencies if you were to include it in future builds.
                 </div>
                 <table class="table table-bordered table-hover">
                     <thead>
@@ -56,7 +55,7 @@
                                 </tr>
                             {% endifequal %}
 						{% endfor %}
-                    </tbody>    
+                    </tbody>
                 </table>
             {% endifequal %}
             {% ifnotequal other_deps|length 0 %}
@@ -72,7 +71,7 @@
                                 Relationship type
                             </th>
                         </tr>
-                    </thead>       
+                    </thead>
                     <tbody>
 						{% for other_dep in other_deps %}
                         	{% ifequal other_dep.version '' %}
@@ -106,5 +105,4 @@
                 {% endifnotequal %}
             </div> <!-- tab-pane -->
         </div> <!-- tab-content -->
-    {% endwith %}
 {% endblock tabcontent %}
lib/toaster/toastergui/templates/package_built_detail.html +4 -4
index d8f0b75..6ccd405 100644
@@ -2,7 +2,7 @@
 {% load projecttags %}
 
 {% block tabcontent %}
-    {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
+    {% with packageFileCount=package.buildfilelist_package.count %}
         <!-- Generated Files -->
         {% if package.buildtargetlist_package.count == 0 %}
             {# Not included case #}
@@ -21,7 +21,7 @@
             <!-- Package file list or if empty, alert pane -->
             {% if packageFileCount > 0 %}
                 <div class="alert alert-info">
-                    {{fullPackageSpec}} is <strong>not included</strong> in any image.  These are the files that would be added to an image root file system if you were to include it in future builds.
+                    {{package.fullpackagespec}} is <strong>not included</strong> in any image.  These are the files that would be added to an image root file system if you were to include it in future builds.
                 </div>
                 <table class="table table-bordered table-hover">
                     <thead>
@@ -29,7 +29,7 @@
                             <th>File</th>
                             <th>Size</th>
                         </tr>
-                    </thead>                   
+                    </thead>
                     <tbody>
 						{% for file in package.buildfilelist_package.all|dictsort:"path" %}
                             <tr>
@@ -42,7 +42,7 @@
 
             {% else %}
                 <div class="alert alert-info">
-                    <strong>{{fullPackageSpec}}</strong> does not generate any files.
+                    <strong>{{package.fullpackagespec}}</strong> does not generate any files.
                 </div>
             {% endif %}
 
lib/toaster/toastergui/templates/package_detail_base.html +28 -8
index 6925aec..5ec9dd7 100644
@@ -1,24 +1,45 @@
 {% extends "basebuilddetailpage.html" %}
 {% load projecttags %}
 
+{% block extraheadcontent %}
+    <!-- functions to format package 'installed_package' alias -->
+    <script>
+    function fmtAliasHelp(package_name, alias, hover) {
+        var r = null;
+        if (alias != null && alias != '') {
+            r = '<span class="muted"> as ' + alias + '&nbsp';
+            r += '<i class="icon-question-sign get-help';
+            if (hover) {
+                r+= ' hover-help';
+            }
+            else {
+                r+= ' heading-help';
+            }
+            r += '"';
+            title = package_name + ' was renamed at packaging time and was installed on your system as ' + alias;
+            r += ' title="' + title + '">';
+            r += '</i>';
+            r += '</span>';
+            document.write(r);
+        }
+    }
+    </script>
+{% endblock extraheadcontent %}
 {% block localbreadcrumb %}
-{% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
     {% if target %}
         <li><a href="{% url "target" build.id target.id %}">{{target.target}}</a></li>
+        <li>{{package.fullpackagespec}} {% if package.alias %} as {{package.alias}}{% endif %}</li>
     {% else %}
         <li><a href="{% url "packages" build.id %}"> Packages </a></li>
+        <li>{{package.fullpackagespec}}</li>
     {% endif %}
-        <li>{{fullPackageSpec}}</li>
-{% endwith %}
 {% endblock localbreadcrumb %}
 
 {% block pagedetailinfomain %}
-{% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
-
     <div class="row span11">
         <div class="page-header">
             {% block title %}
-            <h1>{{fullPackageSpec}}</h1>
+            <h1>{{package.fullpackagespec}}</h1>
             {% endblock title %}
         </div> <!-- page-header -->
     </div> <!-- row span11 page-header -->
@@ -93,7 +114,7 @@
                 {{package.recipe.layer_version.layer.name}}
                 {% if package.recipe.layer_version.layer.name|format_none_and_zero != "" %}
                     {% comment %}
-                    # Removed per team meeting of 1/29/2014 until 
+                    # Removed per team meeting of 1/29/2014 until
                     # decision on index search algorithm
                     <a href="http://layers.openembedded.org"  target="_blank">
                     <i class="icon-share get-info"></i>
@@ -121,5 +142,4 @@
         </dl>
     </div> <!-- row4 well -->
     {% endblock twocolumns %}
-{% endwith %}
 {% endblock pagedetailinfomain %}
lib/toaster/toastergui/templates/package_included_dependencies.html +18 -13
index c76774a..e06e073 100644
@@ -2,13 +2,15 @@
 {% load projecttags %}
 
 {% block title %}
-    {% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
-        <h1>{{fullPackageSpec}} <small>({{target.target}})</small></h1>
-    {% endwith %}
+    <h1>
+        {{package.fullpackagespec}}
+        <script> fmtAliasHelp("{{package.name}}", "{{package.alias}}", false) </script>
+        <small>({{target.target}})</small>
+    </h1>
 {% endblock title %}
 
 {% block tabcontent %}
-    {% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
+    {% with packageFileCount=package.buildfilelist_package.count %}
     {% include "package_included_tabs.html" with active_tab="dependencies" %}
     <div class="tab-content">
        <div class="tab-pane active" id="dependencies">
@@ -29,22 +31,22 @@
                                <a href="{% url 'package_included_detail' build.id target.id runtime_dep.depends_on_id %}">
                                     {{runtime_dep.name}}
                                 </a>
+                                <script>fmtAliasHelp("{{runtime_dep.name}}", "{{runtime_dep.alias}}", true)</script>
                             </td>
                             {% else %}
                             <td>
                                 {{runtime_dep.name|format_vpackage_namehelp}}
                             </td>
                             {% endif %}
-
-                            <td>{{runtime_dep.version}}</td>
-                            <td>{{runtime_dep.size|filtered_filesizeformat}}</td>
+                            <td>{{runtime_dep.version}}&nbsp;</td>
+                            <td>{{runtime_dep.size|filtered_filesizeformat}}&nbsp;</td>
                         </tr>
 					{% endfor %}
-                 </tbody>                
+                 </tbody>
             </table>
         {% else %}
             <div class="alert alert-info">
-                <strong>{{fullPackageSpec}}</strong> has no runtime dependencies.
+                <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies.
             </div>
         {% endifnotequal %}
 
@@ -61,7 +63,7 @@
                             Relationship type
                         </th>
                     </tr>
-                </thead>               
+                </thead>
                 <tbody>
 					{% for other_dep in other_deps %}
                         {% if other_dep.installed %}
@@ -70,6 +72,9 @@
                                 <td>
                                     <a href="{% url 'package_included_detail' build.id target.id other_dep.depends_on_id %}">
                                         {{other_dep.name}}
+                                        <script>
+                                        fmtAliasHelp("{{other_dep.name}}","{{other_dep.alias}}", true)
+                                        </script>
                                     </a>
                                 </td>
                                 {% else %}
@@ -77,8 +82,8 @@
                                         {{other_dep.name|format_vpackage_namehelp}}
                                     </td>
                                 {% endif %}
-                                <td>{{other_dep.version}}</td>
-                                <td>{{other_dep.size|filtered_filesizeformat}}</td>
+                                <td>{{other_dep.version}}&nbsp;</td>
+                                <td>{{other_dep.size|filtered_filesizeformat}}&nbsp;</td>
                                 <td>
                                     {{other_dep.dep_type_display}}
                                     <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
@@ -96,7 +101,7 @@
                             </tr>
                         {% endif %}
 					{% endfor %}
-                </tbody>               
+                </tbody>
             </table>
         {% endifnotequal %}
         </div> <!-- end tab-pane -->
lib/toaster/toastergui/templates/package_included_detail.html +9 -5
index ce4f1cb..e89ebdf 100644
@@ -2,13 +2,17 @@
 {% load projecttags %}
 
 {% block title %}
-{% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
-        <h1>{{fullPackageSpec}} <small>({{target.target}})</small></h1>
-{% endwith %}
+        <h1>
+            {{package.fullpackagespec}}
+            <script>
+                fmtAliasHelp("{{package.name}}", "{{package.alias}}", false)
+            </script>
+            <small>({{target.target}})</small>
+        </h1>
 {% endblock title %}
 
 {% block tabcontent %}
-{% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
+{% with packageFileCount=package.buildfilelist_package.count %}
     {% include "package_included_tabs.html" with active_tab="detail" %}
     <div class="tab-content">
         <div class="tab-pane active" id="files">
@@ -36,7 +40,7 @@
 
             {% else %}
             <div class="alert alert-info">
-                <strong>{{fullPackageSpec}}</strong> does not generate any files.
+                <strong>{{package.fullpackagespec}}</strong> does not generate any files.
             </div>
             {% endif %}
         </div> <!-- end tab-pane -->
lib/toaster/toastergui/templates/package_included_reverse_dependencies.html +10 -7
index 8653ae0..1efcb1a 100644
@@ -2,20 +2,22 @@
 {% load projecttags %}
 
 {% block title %}
-    {% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec  %}
-        <h1>{{fullPackageSpec}} <small>({{target.target}})</small></h1>
-    {% endwith %}
+        <h1>
+            {{package.fullpackagespec}}
+            <script> fmtAliasHelp("{{package.name}}", "{{package.alias}}", false) </script>
+            <small>({{target.target}})</small>
+        </h1>
 {% endblock title %}
 
 {% block tabcontent %}
-    {% with fullPackageSpec=package.name|add:"_"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
+    {% with packageFileCount=package.buildfilelist_package.count %}
     {% include "package_included_tabs.html" with active_tab="reverse" %}
     <div class="tab-content">
         <div class="tab-pane active" id="brought-in-by">
 
         {% ifequal reverse_deps|length  0 %}
            <div class="alert alert-info">
-                <strong>{{fullPackageSpec}}</strong> has no reverse runtime dependencies.
+                <strong>{{package.fullpackagespec}}</strong> has no reverse runtime dependencies.
             </div>
         {% else %}
             <table class="table table-bordered table-hover">
@@ -34,6 +36,7 @@
                                 <a href="{% url 'package_included_detail' build.id target.id reverse_dep.dependent_id %}">
                                     {{reverse_dep.name}}
                                 </a>
+                                <script>fmtAliasHelp("{{reverse_dep.name}}", "{{reverse_dep.alias}}", true)</script>
                             </td>
                             {% else %}
                             <td>
@@ -41,8 +44,8 @@
                             </td>
                             {% endif %}
 
-                            <td>{{reverse_dep.version}}</td>
-                            <td>{{reverse_dep.size|filtered_filesizeformat}}</td>
+                            <td>{{reverse_dep.version}}&nbsp;</td>
+                            <td>{{reverse_dep.size|filtered_filesizeformat}}&nbsp;</td>
                         </tr>
 					{% endfor %}
                 </tbody>
lib/toaster/toastergui/templatetags/projecttags.py +1 -9
index 34c3c21..76166ca 100644
@@ -208,14 +208,6 @@ def filtered_installedsize(size, installed_size):
     return size if (installed_size == 0) or (installed_size == "") or (installed_size == None) else installed_size
 
 @register.filter
-def filtered_installedname(name, installed_name):
-    """If package.installed_name not null and not empty
-        return <div class=muted> as {{package.installed_name}}
-        otherwise ""
-    """
-    return name if (name == installed_name) or (not installed_name) or (installed_name == "") else name + " as " + installed_name
-
[email protected]
 def filtered_packageversion(version, revision):
     """ Emit "version-revision" if version and revision are not null
         else "version" if version is not null
@@ -245,6 +237,6 @@ def format_vpackage_rowclass(size):
 def format_vpackage_namehelp(name):
     r =  name + '&nbsp;'
     r += '<i class="icon-question-sign get-help hover-help"'
-    r += ' title = "' + name + ' only has dependency information available.">'
+    r += ' title="' + name + ' only has dependency information available.">'
     r += '</i>'
     return mark_safe(r)
lib/toaster/toastergui/views.py +47 -13

151 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#6 lore raw

PATCH 6/9 toaster: add support for empty states in pages

In reply to Alex DAMIAN

From: David Reyna <[email protected]>

Add support for empty states in the top build page, the all packages page, and the all tasks page.

[YOCTO #4865]

---
 lib/toaster/toastergui/static/css/default.css  |   4 +-
 lib/toaster/toastergui/static/img/toaster.png  | Bin 0 -> 51986 bytes
 lib/toaster/toastergui/templates/bpackage.html |  34 +++++++++++++----
 lib/toaster/toastergui/templates/build.html    |  50 ++++++++++++++++++++-----
 lib/toaster/toastergui/templates/tasks.html    |  34 +++++++++++------
 5 files changed, 93 insertions(+), 29 deletions(-)
 create mode 100755 lib/toaster/toastergui/static/img/toaster.png
lib/toaster/toastergui/static/css/default.css +3 -1
index d960f4b..260f5d4 100644
@@ -106,7 +106,9 @@ select { width: auto; }
 .task-name { margin-left: 7px; }
 .icon-hand-right {color: #ccccc; }
 .help-inline { margin: 5px; }
-
+.hero-unit { margin: 20px 0 30px; }
+.hero-unit > .close { font-size:40px; }
+.hero-actions { margin-top: 30px; }
 
 
 
lib/toaster/toastergui/static/img/toaster.png new file binary +0 -0
new file mode 100755
index 0000000000000000000000000000000000000000..11bb5d51b1efc54084aa94d1bc84f4d00ee3d59e
GIT binary patch
lib/toaster/toastergui/templates/bpackage.html +27 -7
index 77f7894..22609e2 100644
@@ -12,8 +12,27 @@
 
 {% block buildinfomain %}
 <div class="span10">
+
+{% if not request.GET.filter and not request.GET.search and not objects.paginator.count %}
+
+<!-- Empty - no data in database -->
 <div class="page-header">
-<h1>
+  <div class="page-header">
+    <h1>
+    Packages
+    </h1>
+    </div>
+  <div class="alert alert-info lead">
+    <STRONG>No packages were built.</STRONG> How did this happen? Well, BitBake reuses as much stuff as possible.
+    If all of the packages needed were already built and available in your build infrastructure, Bitbake
+    will not rebuild any of them. This might be slightly confusing, but it does make everything faster.
+  </div>
+</div>
+
+{% else %}
+
+<div class="page-header">
+  <h1>
   {% if request.GET.search and objects.paginator.count > 0  %}
       {{objects.paginator.count}} package{{objects.paginator.count|pluralize}} found
   {%elif request.GET.search and objects.paginator.count == 0%}
@@ -21,10 +40,10 @@
   {%else%}
       Packages
   {%endif%}
- </h1>
+  </h1>
 </div>
 
-{% if objects.paginator.count == 0 %}
+  {% if objects.paginator.count == 0 %}
   <div class="row-fluid">
       <div class="alert">
         <form class="no-results input-append" id="searchform">
@@ -35,8 +54,8 @@
       </div>
   </div>
 
-{% else %}
-{% include "basetable_top.html" %}
+  {% else %}
+  {% include "basetable_top.html" %}
 
     {% for package in objects %}
 
@@ -84,7 +103,8 @@
     </tr>
     {% endfor %}
 
-{% include "basetable_bottom.html" %}
-{% endif %}
+  {% include "basetable_bottom.html" %}
+  {% endif %} {# objects.paginator.count #}
+{% endif %} {# Empty #}
 </div>
 {% endblock %}
lib/toaster/toastergui/templates/build.html +40 -10

88 lines not on this page · raw message

lib/toaster/toastergui/templates/tasks.html +23 -11
index 8c73dc2..ca7e187 100644
@@ -36,19 +36,30 @@
 
 {% block buildinfomain %}
 <div class="span10">
-<div class="page-header">
-<h1>
-  {% if request.GET.filter or request.GET.search and objects.paginator.count > 0  %}
+{% if not request.GET.filter and not request.GET.search and not objects.paginator.count %}
+  <!-- Empty - no data in database -->
+  <div class="page-header">
+  <h1>{{title}}</h1>
+  </div>
+  <div class="alert alert-info lead">
+  No data was recorded for this build.
+  </div>
+
+{% else %}
+
+  <div class="page-header">
+  <h1>
+  {% if  request.GET.filter and objects.paginator.count >  0 or request.GET.search and objects.paginator.count >  0 %}
       {{objects.paginator.count}} task{{objects.paginator.count|pluralize}} found
-  {%elif request.GET.filter or request.GET.search and objects.paginator.count == 0%}
+  {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %}
       No tasks found
   {%else%}
       {{title}}
   {%endif%}
- </h1>
-</div>
+  </h1>
+  </div>
 
-{% if objects.paginator.count == 0 %}
+  {% if objects.paginator.count == 0 %}
   <div class="row-fluid">
       <div class="alert">
         <form class="no-results input-append" id="searchform">
@@ -60,8 +71,8 @@
   </div>
 
 
-{% else %}
-{% include "basetable_top.html" %}
+  {% else %}
+  {% include "basetable_top.html" %}
 
     {% for task in objects %}
         <tr {{ task|task_color }} class="flash" id="{{task.order}}" name="{{task.order}}">
@@ -102,7 +113,8 @@
         </tr>
     {% endfor %}
 
-{% include "basetable_bottom.html" %}
-{% endif %}
+  {% include "basetable_bottom.html" %}
+  {% endif %} {# objects.paginator.count #}
+{% endif %} {# empty #}
 </div>
 {% endblock %}
Signature · 1 line
1.8.3.2
#7 lore raw

PATCH 7/9 toaster: added file types to the Outputs column in the build

In reply to Alex DAMIAN

From: David Reyna <[email protected]>

The file types are displayed in the Outputs column in the build page. The file types are derived from the target image filenames.

[YOCTO #5947]

---
 lib/toaster/toastergui/templates/build.html        |  6 +++++-
 lib/toaster/toastergui/templatetags/projecttags.py |  9 ++++++++
 lib/toaster/toastergui/views.py                    | 24 ++++++++++++++++++++--
 3 files changed, 36 insertions(+), 3 deletions(-)
lib/toaster/toastergui/templates/build.html +5 -1
index 38ab2bf..7d13cc8 100644
@@ -122,7 +122,11 @@
             <td class="warnings_no">{% if  build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td>
             <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td>
             <td class="log">{{build.cooker_log_path}}</td>
-            <td class="output">{% if build.outcome == 0 %}{% for t in build.target_set.all %}{% if t.is_image %}<a href="{%url "builddashboard" build.id%}#images">TODO: compute image output fstypes</a>{% endif %}{% endfor %}{% endif %}</td>
+            <td class="output">
+              {% if build.outcome == build.SUCCEEDED %}
+              <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
+              {% endif %}
+            </td>
         </tr>
 
         {% endfor %}
lib/toaster/toastergui/templatetags/projecttags.py +9 -0
index 76166ca..aa0ba39 100644
@@ -240,3 +240,12 @@ def format_vpackage_namehelp(name):
     r += ' title="' + name + ' only has dependency information available.">'
     r += '</i>'
     return mark_safe(r)
+
[email protected]
+def get_dict_value(dictionary, key):
+    """ return the value of a dictionary key
+    """
+    try:
+        return dictionary[key]
+    except KeyError:
+        return ''
lib/toaster/toastergui/views.py +22 -2
index 0f92caf..d323b37 100644
@@ -19,13 +19,13 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-import operator
+import operator,re
 
 from django.db.models import Q, Sum
 from django.shortcuts import render, redirect
 from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
 from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency
-from orm.models import Target_Installed_Package, Target_Image_File
+from orm.models import Target_Installed_Package, Target_File, Target_Image_File
 from django.views.decorators.cache import cache_control
 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 from django.http import HttpResponseBadRequest
@@ -231,6 +231,25 @@ def builds(request):
         else:
             b.eta = 0
 
+    # set up list of fstypes for each build
+    fstypes_map = {};
+    for build in build_info:
+        targets = Target.objects.filter( build_id = build.id )
+        comma = "";
+        extensions = "";
+        for t in targets:
+            if ( not t.is_image ):
+                continue
+            tif = Target_Image_File.objects.filter( target_id = t.id )
+            for i in tif:
+                s=re.sub('.*tar.bz2', 'tar.bz2', i.file_name)
+                if s == i.file_name:
+                    s=re.sub('.*\.', '', i.file_name)
+                if None == re.search(s,extensions):
+                    extensions += comma + s
+                    comma = ", "
+        fstypes_map[build.id]=extensions
+
     # send the data to the template
     context = {
             # specific info for
@@ -238,6 +257,7 @@ def builds(request):
             # TODO: common objects for all table views, adapt as needed
                 'objects' : build_info,
                 'objectname' : "builds",
+                'fstypes' : fstypes_map,
                 'search_term' : search_term,
                 'total_count' : queryset_with_search.count(),
             # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns
Signature · 1 line
1.8.3.2
#8 lore raw

PATCH 8/9 toaster: fix dirinfo empty dir expansion

In reply to Alex DAMIAN

From: Dave Lerner <[email protected]>

[YOCTO 6036]

In the page that shows the directory layout for an image, if the directory is empty, then the directory folder icon should be black and the table row should not be 'expandable' on a mouse click. That behavior depends on the directory's child entry count calculated in the view function controlling that page.

Two images in the database with the same directory path in the target image, but one with path having entries and the other not having any entries caused the path without entries to be clickable; the query for a directory's count of entries, didn't filter on the image id, only on the path.

---
 lib/toaster/toastergui/views.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/toaster/toastergui/views.py +1 -1
index d323b37..4f7170b 100644
@@ -646,7 +646,7 @@ def _get_dir_entries(build_id, target_id, start):
             if o.inodetype == Target_File.ITYPE_DIRECTORY:
                 entry['isdir'] = 1
                 # is there content in directory
-                entry['childcount'] = Target_File.objects.filter(directory__path=o.path).all().count()
+                entry['childcount'] = Target_File.objects.filter(target__exact=target_id, directory__path=o.path).all().count()
             else:
                 entry['isdir'] = 0
 
Signature · 1 line
1.8.3.2
#9 lore raw

PATCH 9/9 toaster: filter tasks with cache attempts for all attempts

In reply to Alex DAMIAN

From: David Reyna <[email protected]>

Adjust the filter for task cache attempts to include all attempts except SSTATE_NA.

[YOCTO #5923]

---
 lib/toaster/toastergui/views.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/toaster/toastergui/views.py +1 -1
index 4f7170b..4e412ca 100644
@@ -872,7 +872,7 @@ def tasks_common(request, build_id, variant):
                    'class' : 'cache_attempt',
                    'label': 'Show:',
                    'options' : [
-                               ('Tasks with cache attempts', 'sstate_result:%d'%Task.SSTATE_NA, queryset_with_search.filter(sstate_result=Task.SSTATE_NA).count(), 'Show all tasks that tried to restore ouput from the <code>sstate-cache</code> directory or mirrors'),
+                               ('Tasks with cache attempts', 'sstate_result__gt:%d'%Task.SSTATE_NA, queryset_with_search.filter(sstate_result__gt=Task.SSTATE_NA).count(), 'Show all tasks that tried to restore ouput from the <code>sstate-cache</code> directory or mirrors'),
                                ("Tasks with 'File not in cache' attempts", 'sstate_result:%d'%Task.SSTATE_MISS,  queryset_with_search.filter(sstate_result=Task.SSTATE_MISS).count(), 'Show tasks that tried to restore output, but did not find it in the <code>sstate-cache</code> directory or mirrors'),
                                ("Tasks with 'Failed' cache attempts", 'sstate_result:%d'%Task.SSTATE_FAILED,  queryset_with_search.filter(sstate_result=Task.SSTATE_FAILED).count(), 'Show tasks that found the required output in the <code>sstate-cache</code> directory or mirrors, but could not restore it'),
                                ("Tasks with 'Succeeded' cache attempts", 'sstate_result:%d'%Task.SSTATE_RESTORED,  queryset_with_search.filter(sstate_result=Task.SSTATE_RESTORED).count(), 'Show tasks that successfully restored the required output from the <code>sstate-cache</code> directory or mirrors'),
Signature · 1 line
1.8.3.2