summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Wood <michael.g.wood@intel.com>2016-05-26 16:12:23 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-06-15 08:35:04 +0100
commitcaae3b6206dc31690f0c6638daaa7bb072c69042 (patch)
tree780fc9c4e430f93e1b1ae8d522ee921e82515876
parentb2a68f55110b39aaf0b0d47bf533251a59a40a41 (diff)
downloadpoky-caae3b6206dc31690f0c6638daaa7bb072c69042.tar.gz
bitbake: toaster: port Installed packages table to ToasterTable
(Bitbake rev: 2418c092abd9a503becf5e786125f8cdddd8652c) Signed-off-by: Michael Wood <michael.g.wood@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/toaster/toastergui/buildtables.py63
-rw-r--r--bitbake/lib/toaster/toastergui/templates/builddashboard.html4
-rw-r--r--bitbake/lib/toaster/toastergui/templates/target.html118
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py9
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py169
5 files changed, 75 insertions, 288 deletions
diff --git a/bitbake/lib/toaster/toastergui/buildtables.py b/bitbake/lib/toaster/toastergui/buildtables.py
index 51c136f988..17de369305 100644
--- a/bitbake/lib/toaster/toastergui/buildtables.py
+++ b/bitbake/lib/toaster/toastergui/buildtables.py
@@ -19,8 +19,8 @@
19# with this program; if not, write to the Free Software Foundation, Inc., 19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 21
22from orm.models import Build, Task 22from orm.models import Build, Task, Target, Package
23from django.db.models import Q 23from django.db.models import Q, Sum
24 24
25import toastergui.tables as tables 25import toastergui.tables as tables
26from toastergui.widgets import ToasterTable 26from toastergui.widgets import ToasterTable
@@ -155,6 +155,65 @@ class BuiltPackagesTable(BuildTablesMixin, BuiltPackagesTableBase):
155 self.columns = list(remove_dep_cols(self.columns)) 155 self.columns = list(remove_dep_cols(self.columns))
156 156
157 157
158class InstalledPackagesTable(BuildTablesMixin, BuiltPackagesTableBase):
159 """ Show all packages installed in an image """
160 def __init__(self, *args, **kwargs):
161 super(InstalledPackagesTable, self).__init__(*args, **kwargs)
162 self.title = "Installed Packages"
163 self.default_orderby = "name"
164
165 def make_package_list(self, target):
166 # The database design means that you get the intermediate objects and
167 # not package objects like you'd really want so we get them here
168 pkgs = target.target_installed_package_set.values_list('package',
169 flat=True)
170 return Package.objects.filter(pk__in=pkgs)
171
172 def get_context_data(self, **kwargs):
173 context = super(InstalledPackagesTable,
174 self).get_context_data(**kwargs)
175
176 target = Target.objects.get(pk=kwargs['target_id'])
177 packages = self.make_package_list(target)
178
179 context['packages_sum'] = packages.aggregate(
180 Sum('installed_size'))['installed_size__sum']
181
182 context['target'] = target
183 return context
184
185 def setup_queryset(self, *args, **kwargs):
186 build = Build.objects.get(pk=kwargs['build_id'])
187 self.static_context_extra['build'] = build
188
189 target = Target.objects.get(pk=kwargs['target_id'])
190 self.queryset = self.make_package_list(target)
191
192 def setup_columns(self, *args, **kwargs):
193 super(InstalledPackagesTable, self).setup_columns(**kwargs)
194 self.add_column(title="Installed size",
195 static_data_name="installed_size",
196 static_data_template="{% load projecttags %}"
197 "{{data.size|filtered_filesizeformat}}",
198 orderable=True)
199
200 # Add the template to show installed name for installed packages
201 install_name_tmpl =\
202 ('{{data.name}} '
203 '{% if data.installed_name and data.installed_name !='
204 ' data.name %}'
205 '<span class="muted"> as {{data.installed_name}}</span>'
206 ' <i class="icon-question-sign get-help hover-help"'
207 ' title="{{data.name}} was renamed at packaging time and'
208 ' was installed in your image as {{data.installed_name}}'
209 '"></i>{% endif %} ')
210
211 for column in self.columns:
212 if column['static_data_name'] == 'name':
213 column['static_data_template'] = install_name_tmpl
214 break
215
216
158class BuiltRecipesTable(BuildTablesMixin): 217class BuiltRecipesTable(BuildTablesMixin):
159 """ Table to show the recipes that have been built in this build """ 218 """ Table to show the recipes that have been built in this build """
160 219
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
index 5425dfe610..f33757eaca 100644
--- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html
+++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
@@ -102,7 +102,7 @@
102 files from a previous build already exist in your 102 files from a previous build already exist in your
103 <code>.../poky/build/tmp/deploy</code> 103 <code>.../poky/build/tmp/deploy</code>
104 directory. You can 104 directory. You can
105 also <a href="{% url 'targetpkg' build.pk target.target.pk %}">view the 105 also <a href="{% url 'target' build.pk target.target.pk %}">view the
106 license manifest information</a> in Toaster. 106 license manifest information</a> in Toaster.
107 </p> 107 </p>
108 </div> 108 </div>
@@ -115,7 +115,7 @@
115 License manifest 115 License manifest
116 </dt> 116 </dt>
117 <dd> 117 <dd>
118 <a href="{% url 'targetpkg' build.pk target.target.pk %}">View in Toaster</a> | 118 <a href="{% url 'target' build.pk target.target.pk %}">View in Toaster</a> |
119 <a href="{% url 'build_artifact' build.pk 'licensemanifest' target.target.pk %}">Download</a></dd> 119 <a href="{% url 'build_artifact' build.pk 'licensemanifest' target.target.pk %}">Download</a></dd>
120 <dt> 120 <dt>
121 <i class="icon-question-sign get-help" title="Image files are stored in <code>/build/tmp/deploy/images/</code>"></i> 121 <i class="icon-question-sign get-help" title="Image files are stored in <code>/build/tmp/deploy/images/</code>"></i>
diff --git a/bitbake/lib/toaster/toastergui/templates/target.html b/bitbake/lib/toaster/toastergui/templates/target.html
index 9f31239d8e..0b2fe99577 100644
--- a/bitbake/lib/toaster/toastergui/templates/target.html
+++ b/bitbake/lib/toaster/toastergui/templates/target.html
@@ -17,9 +17,7 @@
17{% endblock %} 17{% endblock %}
18 18
19{% block buildinfomain %} 19{% block buildinfomain %}
20
21<div class="col-md-10"> 20<div class="col-md-10">
22
23 <div class="page-header"> 21 <div class="page-header">
24 <h1> 22 <h1>
25 {% if request.GET.search and objects.paginator.count > 0 %} 23 {% if request.GET.search and objects.paginator.count > 0 %}
@@ -31,8 +29,6 @@
31 {% endif %} 29 {% endif %}
32 </h1> 30 </h1>
33 </div> 31 </div>
34
35
36<div id="navTab"> 32<div id="navTab">
37 <ul class="nav nav-pills"> 33 <ul class="nav nav-pills">
38 <li class="active"> 34 <li class="active">
@@ -50,113 +46,11 @@
50 </ul> 46 </ul>
51 47
52 <div id="image-packages" class="tab-pane"> 48 <div id="image-packages" class="tab-pane">
53 49 {# xhr_table_url is just the current url so leave it blank #}
54 {% if objects.paginator.count == 0 %} 50 {% with xhr_table_url='' %}
55 <div class="alert"> 51 {% include "toastertable.html" %}
56 <form class="no-results input-append" id="searchform"> 52 {% endwith %}
57 <input id="search" name="search" class="input-xxlarge" type="text" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="input-append-addon btn" tabindex="-1"><i class="glyphicon glyphicon-remove"></i></a>{% endif %}
58 <button class="btn" type="submit" value="Search">Search</button>
59 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all packages</button>
60 </form>
61 </div>
62
63
64 {% else %}
65 {% include "basetable_top.html" %}
66 {% for package in objects %}
67 <tr>
68 {# order of the table data must match the columns defined in template's context tablecols #}
69 <td class="package_name">
70 <a href="{% url 'package_included_detail' build.id target.id package.id %}">
71 {{package.name}}
72 </a>
73 {% if package.installed_name and package.name != package.installed_name %}
74 <span class="muted"> as {{package.installed_name}}</span>
75 <i class="icon-question-sign get-help hover-help" title='{{package.name|add:" was renamed at packaging time and was installed in your image as "|add:package.installed_name}}'></i>
76 {% endif %}
77 </td>
78 <td class="package_version">
79 <a href="{% url 'package_included_detail' build.id target.id package.id %}">
80 {{package.version|filtered_packageversion:package.revision}}
81 </a>
82 </td>
83 <td class="license">
84 {{package.license}}
85 </td>
86 <td class="size sizecol">
87 {{package.size|filtered_installedsize:package.installed_size|filtered_filesizeformat}}
88 </td>
89
90 <td class="size_over_total sizecol">
91 {{package|filter_sizeovertotal:packages_sum}}
92 </td>
93 <td class="depends">
94 {% with deps=package.runtime_dependencies %}
95 {% with deps_count=deps|length %}
96 {% if deps_count > 0 %}
97 <a class="btn"
98 title="<a href='{% url "package_included_dependencies" build.id target.id package.id %}'>{{package.name}}</a> dependencies"
99 data-content="<ul class='list-unstyled'>
100 {% for i in deps|dictsort:'depends_on.name' %}
101 <li><a href='{% url "package_included_detail" build.pk target.id i.depends_on.pk %}'>{{i.depends_on.name}}</a></li>
102 {% endfor %}
103 </ul>">
104 {{deps_count}}
105 </a>
106 {% endif %}
107 {% endwith %}
108 {% endwith %}
109 </td>
110 <td class="brought_in_by">
111 {% with rdeps=package.reverse_runtime_dependencies %}
112 {% with rdeps_count=rdeps|length %}
113 {% if rdeps_count > 0 %}
114 <a class="btn"
115 title="<a href='{% url "package_included_reverse_dependencies" build.id target.id package.id %}'>{{package.name}}</a> reverse dependencies"
116 data-content="<ul class='list-unstyled'>
117 {% for i in rdeps|dictsort:'package.name' %}
118 <li><a href='{% url "package_included_detail" build.id target.id i.package.id %}'>{{i.package.name}}</a></li>
119 {% endfor %}
120 </ul>">
121 {{rdeps_count}}
122 </a>
123 {% endif %}
124 {% endwith %}
125 {% endwith %}
126 </td>
127 <td class="recipe_name">
128 {% if package.recipe.version %}
129 <a href="{% url 'recipe' build.id package.recipe_id %}">
130 {{ package.recipe.name }}
131 </a>
132 {% endif %}
133 </td>
134 <td class="recipe_version">
135 {% if package.recipe.version %}
136 <a href="{% url 'recipe' build.id package.recipe_id %}">
137 {{ package.recipe.version }}
138 </a>
139 {% endif %}
140 </td>
141 <td class="layer_name">
142 {{ package.recipe.layer_version.layer.name }}
143 </td>
144 <td class="layer_branch">
145 {{ package.recipe.layer_version.branch}}
146 </td>
147 <td class="layer_commit">
148 <a class="btn"
149 data-content="<ul class='list-unstyled'>
150 <li>{{package.recipe.layer_version.commit}}</li>
151 </ul>">
152 {{package.recipe.layer_version.commit|truncatechars:13}}
153 </a>
154 </td>
155 </tr>
156 {% endfor %}
157
158 {% include "basetable_bottom.html" %}
159 {% endif %}
160 </div> <!-- tabpane --> 53 </div> <!-- tabpane -->
161</div> <!--span 10--> 54 </div> <!--navTab -->>
55<!-- col-md-10 -->
162{% endblock buildinfomain %} 56{% endblock buildinfomain %}
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index c4913f124a..9510a386ea 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -68,9 +68,12 @@ urlpatterns = patterns('toastergui.views',
68 url(r'^build/(?P<build_id>\d+)/package_included_reverse_dependencies/(?P<target_id>\d+)/(?P<package_id>\d+)$', 68 url(r'^build/(?P<build_id>\d+)/package_included_reverse_dependencies/(?P<target_id>\d+)/(?P<package_id>\d+)$',
69 'package_included_reverse_dependencies', name='package_included_reverse_dependencies'), 69 'package_included_reverse_dependencies', name='package_included_reverse_dependencies'),
70 70
71 # images are known as targets in the internal model 71 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$',
72 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$', 'target', name='target'), 72 buildtables.InstalledPackagesTable.as_view(
73 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/targetpkg$', 'targetpkg', name='targetpkg'), 73 template_name="target.html"),
74 name='target'),
75
76
74 url(r'^dentries/build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$', 'xhr_dirinfo', name='dirinfo_ajax'), 77 url(r'^dentries/build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$', 'xhr_dirinfo', name='dirinfo_ajax'),
75 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/dirinfo$', 'dirinfo', name='dirinfo'), 78 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/dirinfo$', 'dirinfo', name='dirinfo'),
76 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/dirinfo_filepath/_(?P<file_path>(?:/[^/\n]+)*)$', 'dirinfo', name='dirinfo_filepath'), 79 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/dirinfo_filepath/_(?P<file_path>(?:/[^/\n]+)*)$', 'dirinfo', name='dirinfo_filepath'),
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 35ab63a22e..88bc39a166 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -681,175 +681,6 @@ def recipe_packages(request, build_id, recipe_id):
681 _set_parameters_values(pagesize, orderby, request) 681 _set_parameters_values(pagesize, orderby, request)
682 return response 682 return response
683 683
684def target_common( request, build_id, target_id, variant ):
685 template = "target.html"
686 default_orderby = 'name:+'
687
688 (pagesize, orderby) = _get_parameters_values(request, 25, default_orderby)
689 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': orderby }
690 retval = _verify_parameters( request.GET, mandatory_parameters )
691 if retval:
692 return _redirect_parameters(
693 variant, request.GET, mandatory_parameters,
694 build_id = build_id, target_id = target_id )
695 ( filter_string, search_term, ordering_string ) = _search_tuple( request, Package )
696
697 # FUTURE: get rid of nested sub-queries replacing with ManyToMany field
698 queryset = Package.objects.filter(
699 size__gte = 0,
700 id__in = Target_Installed_Package.objects.filter(
701 target_id=target_id ).values( 'package_id' ))
702 packages_sum = queryset.aggregate( Sum( 'installed_size' ))
703 queryset = _get_queryset(
704 Package, queryset, filter_string, search_term, ordering_string, 'name' )
705 queryset = queryset.select_related("recipe", "recipe__layer_version", "recipe__layer_version__layer")
706 packages = _build_page_range( Paginator(queryset, pagesize), request.GET.get( 'page', 1 ))
707
708 build = Build.objects.get( pk = build_id )
709
710 # bring in package dependencies
711 for p in packages.object_list:
712 p.runtime_dependencies = p.package_dependencies_source.filter(
713 target_id = target_id, dep_type=Package_Dependency.TYPE_TRDEPENDS ).select_related("depends_on")
714 p.reverse_runtime_dependencies = p.package_dependencies_target.filter(
715 target_id = target_id, dep_type=Package_Dependency.TYPE_TRDEPENDS ).select_related("package")
716 tc_package = {
717 'name' : 'Package',
718 'qhelp' : 'Packaged output resulting from building a recipe included in this image',
719 'orderfield' : _get_toggle_order( request, "name" ),
720 'ordericon' : _get_toggle_order_icon( request, "name" ),
721 }
722 tc_packageVersion = {
723 'name' : 'Package version',
724 'qhelp' : 'The package version and revision',
725 }
726 tc_size = {
727 'name' : 'Size',
728 'qhelp' : 'The size of the package',
729 'orderfield' : _get_toggle_order( request, "size", True ),
730 'ordericon' : _get_toggle_order_icon( request, "size" ),
731 'orderkey' : 'size',
732 'clclass' : 'size',
733 'dclass' : 'span2',
734 }
735 if ( variant == 'target' ):
736 tc_size[ "hidden" ] = 0
737 else:
738 tc_size[ "hidden" ] = 1
739 tc_sizePercentage = {
740 'name' : 'Size over total (%)',
741 'qhelp' : 'Proportion of the overall size represented by this package',
742 'clclass' : 'size_over_total',
743 'hidden' : 1,
744 }
745 tc_license = {
746 'name' : 'License',
747 'qhelp' : 'The license under which the package is distributed. Separate license names u\
748sing | (pipe) means there is a choice between licenses. Separate license names using & (ampersand) m\
749eans multiple licenses exist that cover different parts of the source',
750 'orderfield' : _get_toggle_order( request, "license" ),
751 'ordericon' : _get_toggle_order_icon( request, "license" ),
752 'orderkey' : 'license',
753 'clclass' : 'license',
754 }
755 if ( variant == 'target' ):
756 tc_license[ "hidden" ] = 1
757 else:
758 tc_license[ "hidden" ] = 0
759 tc_dependencies = {
760 'name' : 'Dependencies',
761 'qhelp' : "Package runtime dependencies (other packages)",
762 'clclass' : 'depends',
763 }
764 if ( variant == 'target' ):
765 tc_dependencies[ "hidden" ] = 0
766 else:
767 tc_dependencies[ "hidden" ] = 1
768 tc_rdependencies = {
769 'name' : 'Reverse dependencies',
770 'qhelp' : 'Package run-time reverse dependencies (i.e. which other packages depend on this package',
771 'clclass' : 'brought_in_by',
772 }
773 if ( variant == 'target' ):
774 tc_rdependencies[ "hidden" ] = 0
775 else:
776 tc_rdependencies[ "hidden" ] = 1
777 tc_recipe = {
778 'name' : 'Recipe',
779 'qhelp' : 'The name of the recipe building the package',
780 'orderfield' : _get_toggle_order( request, "recipe__name" ),
781 'ordericon' : _get_toggle_order_icon( request, "recipe__name" ),
782 'orderkey' : "recipe__name",
783 'clclass' : 'recipe_name',
784 'hidden' : 0,
785 }
786 tc_recipeVersion = {
787 'name' : 'Recipe version',
788 'qhelp' : 'Version and revision of the recipe building the package',
789 'clclass' : 'recipe_version',
790 'hidden' : 1,
791 }
792 tc_layer = {
793 'name' : 'Layer',
794 'qhelp' : 'The name of the layer providing the recipe that builds the package',
795 'orderfield' : _get_toggle_order( request, "recipe__layer_version__layer__name" ),
796 'ordericon' : _get_toggle_order_icon( request, "recipe__layer_version__layer__name" ),
797 'orderkey' : "recipe__layer_version__layer__name",
798 'clclass' : 'layer_name',
799 'hidden' : 1,
800 }
801 tc_layerBranch = {
802 'name' : 'Layer branch',
803 'qhelp' : 'The Git branch of the layer providing the recipe that builds the package',
804 'orderfield' : _get_toggle_order( request, "recipe__layer_version__branch" ),
805 'ordericon' : _get_toggle_order_icon( request, "recipe__layer_version__branch" ),
806 'orderkey' : "recipe__layer_version__branch",
807 'clclass' : 'layer_branch',
808 'hidden' : 1,
809 }
810 tc_layerCommit = {
811 'name' : 'Layer commit',
812 'qhelp' : 'The Git commit of the layer providing the recipe that builds the package',
813 'clclass' : 'layer_commit',
814 'hidden' : 1,
815 }
816
817 context = {
818 'objectname': variant,
819 'build' : build,
820 'project' : build.project,
821 'target' : Target.objects.filter( pk = target_id )[ 0 ],
822 'objects' : packages,
823 'packages_sum' : packages_sum[ 'installed_size__sum' ],
824 'object_search_display': "packages included",
825 'default_orderby' : default_orderby,
826 'tablecols' : [
827 tc_package,
828 tc_packageVersion,
829 tc_license,
830 tc_size,
831 tc_sizePercentage,
832 tc_dependencies,
833 tc_rdependencies,
834 tc_recipe,
835 tc_recipeVersion,
836 tc_layer,
837 tc_layerBranch,
838 tc_layerCommit,
839 ]
840 }
841
842
843 response = render(request, template, context)
844 _set_parameters_values(pagesize, orderby, request)
845 return response
846
847def target( request, build_id, target_id ):
848 return( target_common( request, build_id, target_id, "target" ))
849
850def targetpkg( request, build_id, target_id ):
851 return( target_common( request, build_id, target_id, "targetpkg" ))
852
853from django.core.serializers.json import DjangoJSONEncoder 684from django.core.serializers.json import DjangoJSONEncoder
854from django.http import HttpResponse 685from django.http import HttpResponse
855def xhr_dirinfo(request, build_id, target_id): 686def xhr_dirinfo(request, build_id, target_id):