summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Lerner <dave.lerner@windriver.com>2014-01-23 11:47:41 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-02-17 15:38:52 +0000
commit620553df864634e7061c9124ea70a90e5c067cde (patch)
treed196d7dbea61da09846e9a645f245ab931889516
parent47634378ac516496bcc155e001983973f241ee61 (diff)
downloadpoky-620553df864634e7061c9124ea70a90e5c067cde.tar.gz
bitbake: toaster: Implementation of package detail views
Adds new package detail views. The views are based on specifications found in attachments to: https://bugzilla.yoctoproject.org/show_bug.cgi?id=4328 specifically: design-1.5.1-package-details.pdf, and design-1.1.1-included-package-details. This patch includes a redefinition of constant numbers for task dependency tasks. This is needed in order to achieve sorting criteria from the design. This change invalidates currently dependency information for currently existing builds, as it breaks compatibility. [YOCTO #4328] (Bitbake rev: 6855925c06e7e5bb15ae9d0c08d77f3a9a2574bc) Signed-off-by: Dave Lerner <dave.lerner@windriver.com> Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/toaster/orm/models.py47
-rw-r--r--bitbake/lib/toaster/toastergui/templates/bpackage.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html112
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_built_detail.html71
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_detail_base.html125
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html93
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_included_detail.html46
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html47
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_included_tabs.html33
-rw-r--r--bitbake/lib/toaster/toastergui/templates/recipe.html6
-rw-r--r--bitbake/lib/toaster/toastergui/templatetags/projecttags.py13
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py18
-rw-r--r--bitbake/lib/toaster/toastergui/views.py196
13 files changed, 777 insertions, 32 deletions
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py
index 3abee016c4..113631def0 100644
--- a/bitbake/lib/toaster/orm/models.py
+++ b/bitbake/lib/toaster/orm/models.py
@@ -145,6 +145,7 @@ class Task_Dependency(models.Model):
145 145
146 146
147class Package(models.Model): 147class Package(models.Model):
148 search_allowed_fields = ['name', 'installed_name', 'section', 'summary']
148 build = models.ForeignKey('Build') 149 build = models.ForeignKey('Build')
149 recipe = models.ForeignKey('Recipe', null=True) 150 recipe = models.ForeignKey('Recipe', null=True)
150 name = models.CharField(max_length=100) 151 name = models.CharField(max_length=100)
@@ -160,23 +161,39 @@ class Package(models.Model):
160 161
161class Package_Dependency(models.Model): 162class Package_Dependency(models.Model):
162 TYPE_RDEPENDS = 0 163 TYPE_RDEPENDS = 0
163 TYPE_RPROVIDES = 1 164 TYPE_TRDEPENDS = 1
164 TYPE_RRECOMMENDS = 2 165 TYPE_RRECOMMENDS = 2
165 TYPE_RSUGGESTS = 3 166 TYPE_TRECOMMENDS = 3
166 TYPE_RREPLACES = 4 167 TYPE_RSUGGESTS = 4
167 TYPE_RCONFLICTS = 5 168 TYPE_RPROVIDES = 5
168 TYPE_TRDEPENDS = 6 169 TYPE_RREPLACES = 6
169 TYPE_TRECOMMENDS = 7 170 TYPE_RCONFLICTS = 7
171 ' TODO: bpackage should be changed to remove the DEPENDS_TYPE access '
170 DEPENDS_TYPE = ( 172 DEPENDS_TYPE = (
171 (TYPE_RDEPENDS, "rdepends"), 173 (TYPE_RDEPENDS, "depends"),
172 (TYPE_RPROVIDES, "rprovides"), 174 (TYPE_TRDEPENDS, "depends"),
173 (TYPE_RRECOMMENDS, "rrecommends"), 175 (TYPE_TRECOMMENDS, "recommends"),
174 (TYPE_RSUGGESTS, "rsuggests"), 176 (TYPE_RRECOMMENDS, "recommends"),
175 (TYPE_RREPLACES, "rreplaces"), 177 (TYPE_RSUGGESTS, "suggests"),
176 (TYPE_RCONFLICTS, "rconflicts"), 178 (TYPE_RPROVIDES, "provides"),
177 (TYPE_TRDEPENDS, "trdepends"), 179 (TYPE_RREPLACES, "replaces"),
178 (TYPE_TRECOMMENDS, "trecommends"), 180 (TYPE_RCONFLICTS, "conflicts"),
179 ) 181 )
182 ''' Indexed by dep_type, in view order, key for short name and help
183 description which when viewed will be printf'd with the
184 package name.
185 '''
186 DEPENDS_DICT = {
187 TYPE_RDEPENDS : ("depends", "%s is required to run %s"),
188 TYPE_TRDEPENDS : ("depends", "%s is required to run %s"),
189 TYPE_TRECOMMENDS : ("recommends", "%s extends the usability of %s"),
190 TYPE_RRECOMMENDS : ("recommends", "%s extends the usability of %s"),
191 TYPE_RSUGGESTS : ("suggests", "%s is suggested for installation with %s"),
192 TYPE_RPROVIDES : ("provides", "%s is provided by %s"),
193 TYPE_RREPLACES : ("replaces", "%s is replaced by %s"),
194 TYPE_RCONFLICTS : ("conflicts", "%s conflicts with %s, which will not be installed if this package is not first removed"),
195 }
196
180 package = models.ForeignKey(Package, related_name='package_dependencies_source') 197 package = models.ForeignKey(Package, related_name='package_dependencies_source')
181 depends_on = models.ForeignKey(Package, related_name='package_dependencies_target') # soft dependency 198 depends_on = models.ForeignKey(Package, related_name='package_dependencies_target') # soft dependency
182 dep_type = models.IntegerField(choices=DEPENDS_TYPE) 199 dep_type = models.IntegerField(choices=DEPENDS_TYPE)
@@ -184,7 +201,7 @@ class Package_Dependency(models.Model):
184 201
185class Target_Installed_Package(models.Model): 202class Target_Installed_Package(models.Model):
186 target = models.ForeignKey(Target) 203 target = models.ForeignKey(Target)
187 package = models.ForeignKey(Package) 204 package = models.ForeignKey(Package, related_name='buildtargetlist_package')
188 205
189class Package_File(models.Model): 206class Package_File(models.Model):
190 package = models.ForeignKey(Package, related_name='buildfilelist_package') 207 package = models.ForeignKey(Package, related_name='buildfilelist_package')
diff --git a/bitbake/lib/toaster/toastergui/templates/bpackage.html b/bitbake/lib/toaster/toastergui/templates/bpackage.html
index 3329ddae51..b78ae4644f 100644
--- a/bitbake/lib/toaster/toastergui/templates/bpackage.html
+++ b/bitbake/lib/toaster/toastergui/templates/bpackage.html
@@ -26,7 +26,7 @@
26 {% for package in objects %} 26 {% for package in objects %}
27 27
28 <tr class="data"> 28 <tr class="data">
29 <td><a name="#{{package.name}}" href="{% url "package" build.pk package.pk %}">{{package.name}} ({{package.filelist_bpackage.count}} files)</a></td> 29 <td><a name="#{{package.name}}" href="{% url "package_built_detail" build.pk package.pk %}">{{package.name}} ({{package.filelist_bpackage.count}} files)</a></td>
30 <td>{{package.version}}-{{package.revision}}</td> 30 <td>{{package.version}}-{{package.revision}}</td>
31 <td>{%if package.recipe%}<a href="{% url "layer_versions_recipes" package.recipe.layer_version_id %}#{{package.recipe.name}}">{{package.recipe.name}}</a>{{package.package_name}}</a>{%endif%}</td> 31 <td>{%if package.recipe%}<a href="{% url "layer_versions_recipes" package.recipe.layer_version_id %}#{{package.recipe.name}}">{{package.recipe.name}}</a>{{package.package_name}}</a>{%endif%}</td>
32 32
diff --git a/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html b/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html
new file mode 100644
index 0000000000..c67f60e20b
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html
@@ -0,0 +1,112 @@
1{% extends "package_detail_base.html" %}
2{% load projecttags %}
3
4{% block tabcontent %}
5 {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
6 <ul class="nav nav-pills">
7 <li class="">
8 <a href="{% url 'package_built_detail' build.id package.id %}">
9 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the files produced by this package."></i>
10 Generated files ({{package.buildfilelist_package.count}})
11 </a>
12 </li>
13 <li class="active">
14 <a href="{% url 'package_built_dependencies' build.id package.id %}">
15 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the runtime packages required by this package."></i>
16 Runtime dependencies ({{dependency_count}})
17 </a>
18 </li>
19 </ul>
20 <div class="tab-content">
21 <div class="tab-pane active" id="dependencies">
22 {% ifequal runtime_deps|length 0 %}
23 <div class="alert alert-info">
24 <strong>{{fullPackageSpec}}</strong> has no runtime dependencies.
25 </div>
26 {% else %}
27 <div class="alert alert-info">
28 <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.
29 </div>
30 <table class="table table-bordered table-hover">
31 <thead>
32 <tr>
33 <th>Package</th>
34 <th>Version</th>
35 <th>Size</th>
36 </tr>
37 </thead>
38 {% for runtime_dep in runtime_deps %}
39 <tbody>
40 {% ifequal runtime_dep.version '' %}
41 <tr class="muted">
42 <td>{{runtime_dep.name}}</td>
43 <td>{{runtime_dep.version}}</td>
44 <td></td>
45 </div>
46 </tr>
47 {% else %}
48 <tr>
49 <td>
50 <a href="{% url 'package_built_detail' build.id runtime_dep.depends_on_id %}">
51 {{runtime_dep.name}}
52 </a>
53 </td>
54 <td>{{runtime_dep.version}}</td>
55 <td>{{runtime_dep.size|filtered_filesizeformat}}</td>
56 </tr>
57 {% endifequal %}
58 </tbody>
59 {% endfor %}
60 </table>
61 {% endifequal %}
62 {% ifnotequal other_deps|length 0 %}
63 <h3>Other runtime relationships</h3>
64 <table class="table table-bordered table-hover">
65 <thead>
66 <tr>
67 <th>Package</th>
68 <th>Version</th>
69 <th>Size</th>
70
71 <th>
72 <i class="icon-question-sign get-help" title="There are 5 relationship types: recommends, suggests, provides, replaces and conflicts"></i>
73 Relationship type
74 </th>
75 </tr>
76 </thead>
77
78 {% for other_dep in other_deps %}
79 <tbody>
80 {% ifequal other_dep.version '' %}
81 <tr class="muted">
82 <td>{{other_dep.name}}</td>
83 <td>{{other_dep.version}}</td>
84 <td></td>
85 <td>
86 {{other_dep.dep_type_display}}
87 <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
88 </td>
89 </tr>
90 {% else %}
91 <tr>
92 <td>
93 <a href="{% url 'package_built_detail' build.id other_dep.depends_on_id %}">
94 {{other_dep.name}}
95 </a>
96 </td>
97 <td>{{other_dep.version}}</td>
98 <td>{{other_dep.size|filtered_filesizeformat}}</td>
99 <td>
100 {{other_dep.dep_type_display}}
101 <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
102 </td>
103 </tr>
104 </tbody>
105 {% endifequal %}
106 {% endfor %}
107 </table>
108 {% endifnotequal %}
109 </div> <!-- tab-pane -->
110 </div> <!-- tab-content -->
111 {% endwith %}
112{% endblock tabcontent %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_built_detail.html b/bitbake/lib/toaster/toastergui/templates/package_built_detail.html
new file mode 100644
index 0000000000..fe856a3cb6
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_built_detail.html
@@ -0,0 +1,71 @@
1{% extends "package_detail_base.html" %}
2{% load projecttags %}
3
4{% block tabcontent %}
5 {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
6 <!-- Generated Files -->
7 {% if package.buildtargetlist_package.count == 0 %}
8 {# Not included case #}
9 <ul class="nav nav-pills">
10 <li class="active"> <a href="#">
11 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the files produced by this package."></i>
12 Generated files ({{packageFileCount}})
13 </a></li>
14 <li class=""><a href="{% url 'package_built_dependencies' build.id package.id %}">
15 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the runtime packages required by this package."></i>
16 Runtime dependencies ({{dependency_count}})
17 </a></li>
18 </ul>
19 <div class="tab-content">
20 <div class="tab-pane active" id="files">
21 <!-- Package file list or if empty, alert pane -->
22 {% if packageFileCount > 0 %}
23 <div class="alert alert-info">
24 {{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.
25 </div>
26 <table class="table table-bordered table-hover">
27 <thead>
28 <tr>
29 <th>File</th>
30 <th>Size</th>
31 </tr>
32 </thead>
33 {% for file in package.buildfilelist_package.all|dictsort:"path" %}
34 <tbody>
35 <tr>
36 <td>{{file.path}}</td>
37 <td>{{file.size|filtered_filesizeformat}}</td>
38 </tr>
39 </tbody>
40 {% endfor %}
41 </table>
42
43 {% else %}
44 <div class="alert alert-info">
45 <strong>{{fullPackageSpec}}</strong> does not generate any files.
46 </div>
47 {% endif %}
48
49 </div> <!-- tab-pane active -->
50 </div> <!-- tab-content -->
51 {% else %}
52 {# Included case #}
53 <div class="tab-content">
54 <div class="tab-pane active">
55 <div class="lead well">
56 Package included in:
57 {% for itarget in package.buildtargetlist_package.all|dictsort:"target.target" %}
58 <a href="{% url 'package_included_detail' build.id itarget.target.id package.id %}">
59 {% if forloop.counter0 > 0 %}
60 ,&nbsp;
61 {% endif %}
62 {{itarget.target.target}}
63 </a>
64 {% endfor %}
65 </div>
66 </div> <!-- tab-pane active -->
67 </div> <!-- tab-content -->
68 {% endif %}
69
70 {% endwith %}
71{% endblock tabcontent %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
new file mode 100644
index 0000000000..a7aaab6de7
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
@@ -0,0 +1,125 @@
1{% extends "basebuilddetailpage.html" %}
2{% load projecttags %}
3
4{% block localbreadcrumb %}
5{% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
6 {% if target %}
7 <li><a href="{% url "target" build.id target.id %}">{{target.target}}</a></li>
8 {% else %}
9 <li><a href="{% url "packages" build.id %}"> Packages </a></li>
10 {% endif %}
11 <li>{{fullPackageSpec}}</li>
12{% endwith %}
13{% endblock localbreadcrumb %}
14
15{% block pagedetailinfomain %}
16{% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
17
18 <div class="row span11">
19 <div class="page-header">
20 {% block title %}
21 <h1>{{fullPackageSpec}}</h1>
22 {% endblock title %}
23 </div> <!-- page-header -->
24 </div> <!-- row span11 page-header -->
25
26 {% block twocolumns %}
27 <div class="row span7 tabbable">
28 {% block tabcontent %}
29 {% endblock tabcontent %}
30 </div> <!-- row span7 -->
31
32 <div class="row span4 well">
33 <h2>Package information</h2>
34
35 <!-- info presented as definition list -->
36 <dl>
37 <dt>
38 Size
39 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The size of the package"></i>
40 </dt>
41 <dd>
42 {% comment %}
43 if recipe is absent, filesize is not 0
44 {% endcomment %}
45 {% if package.recipe_id > 0 %}
46 {{package.size|filtered_filesizeformat}}
47 {% if target.file_size %}
48 ({{package.size|multiply:100|divide:target.file_size}}% of included package size)
49 {% endif %}
50
51 {% endif %}
52 </dd>
53
54 <dt>
55 License
56 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The license under which this package is distributed"></i>
57 </dt>
58 <dd>{{package.license}}</dd>
59
60 {% comment %}
61 # Removed per review on 1/18/2014 until license data population
62 # problemse are resolved.
63 <dt>
64 License files
65 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Location in disk of the license files that apply to the package"></i>
66 </dt>
67 <dd></dd>
68 {% endcomment %}
69
70 <dt>
71 Recipe
72 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The name of the recipe building this package"></i>
73 </dt>
74 <dd>
75 {% if package.recipe_id > 0 %}
76 <a href="{% url "recipe" build.id package.recipe_id %}"> {{package.recipe.name}} </a>
77 {% else %}
78 {{package.recipe.name}}
79 {% endif %}
80 </dd>
81
82 <dt>
83 Recipe version
84 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The version of the recipe building this package"></i>
85 </dt>
86 <dd>{{package.recipe.version}}</dd>
87
88 <dt>
89 Layer
90 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The name of the layer providing the recipe that builds this package"></i>
91 </dt>
92 <dd>
93 {{package.recipe.layer_version.layer.name}}
94 {% if package.recipe.layer_version.layer.name|format_none_and_zero != "" %}
95 {% comment %}
96 # Removed per team meeting of 1/29/2014 until
97 # decision on index search algorithm
98 <a href="http://layers.openembedded.org" target="_blank">
99 <i class="icon-share get-info"></i>
100 {% endcomment %}
101 </a>
102 {% endif %}
103 </dd>
104
105 <dt>
106 Layer branch
107 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The Git branch of the layer providing the recipe that builds this package"></i>
108 </dt>
109 <dd>{{package.recipe.layer_version.branch}}</dd>
110 <dt>
111 Layer commit
112 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The Git commit of the layer providing the recipe that builds this package"></i>
113 </dt>
114
115 <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd>
116 <dt>
117 Layer directory
118 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Location in disk of the layer providing the recipe that builds this package"></i>
119 </dt>
120 <dd><code>{{package.recipe.layer_version.layer.local_path}}</code></dd>
121 </dl>
122 </div> <!-- row4 well -->
123 {% endblock twocolumns %}
124{% endwith %}
125{% endblock pagedetailinfomain %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html b/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html
new file mode 100644
index 0000000000..c8c2dddf29
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html
@@ -0,0 +1,93 @@
1{% extends "package_detail_base.html" %}
2{% load projecttags %}
3
4{% block title %}
5 {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
6 <h1>{{fullPackageSpec}} <small>({{target.target}})</small></h1>
7 {% endwith %}
8{% endblock title %}
9
10{% block tabcontent %}
11 {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
12 {% include "package_included_tabs.html" with active_tab="dependencies" %}
13 <div class="tab-content">
14 <div class="tab-pane active" id="dependencies">
15 {% ifnotequal runtime_deps|length 0 %}
16 <table class="table table-bordered table-hover">
17 <thead>
18 <tr>
19 <th>Package</th>
20 <th>Version</th>
21 <th>Size</th>
22 </tr>
23 </thead>
24 {% for runtime_dep in runtime_deps %}
25 <tbody>
26 <tr>
27 <td>
28 <a href="{% url 'package_included_detail' build.id target.id runtime_dep.depends_on_id %}">
29 {{runtime_dep.name}}
30 </a>
31 </td>
32 <td>{{runtime_dep.version}}</td>
33 <td>{{runtime_dep.size|filtered_filesizeformat}}</td>
34 </tr>
35 </tbody>
36 {% endfor %}
37 </table>
38 {% else %}
39 <div class="alert alert-info">
40 <strong>{{fullPackageSpec}}</strong> has no runtime dependencies.
41 </div>
42 {% endifnotequal %}
43
44 {% ifnotequal other_deps|length 0 %}
45 <h3>Other runtime relationships</h3>
46 <table class="table table-bordered table-hover">
47 <thead>
48 <tr>
49 <th>Package</th>
50 <th>Version</th>
51 <th>Size</th>
52 <th>
53 <i class="icon-question-sign get-help" title="There are 5 relationship types: recommends, suggests, provides, replaces and conflicts"></i>
54 Relationship type
55 </th>
56 </tr>
57 </thead>
58
59 {% for other_dep in other_deps %}
60 <tbody>
61 {% if other_dep.installed %}
62 <tr>
63 <td>
64 <a href="{% url 'package_included_detail' build.id target.id other_dep.depends_on_id %}">
65 {{other_dep.name}}
66 </a>
67 </td>
68 <td>{{other_dep.version}}</td>
69 <td>{{other_dep.size|filtered_filesizeformat}}</td>
70 <td>
71 {{other_dep.dep_type_display}}
72 <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
73 </td>
74 </tr>
75 {% else %}
76 <tr class="muted">
77 <td>{{other_dep.name}}</td>
78 <td>{{other_dep.version}}</td>
79 <td></td>
80 <td>
81 {{other_dep.dep_type_display}}
82 <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
83 </td>
84 </tr>
85 {% endif %}
86 </tbody>
87 {% endfor %}
88 </table>
89 {% endifnotequal %}
90 </div> <!-- end tab-pane -->
91 </div> <!-- end tab content -->
92 {% endwith %}
93{% endblock tabcontent %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_included_detail.html b/bitbake/lib/toaster/toastergui/templates/package_included_detail.html
new file mode 100644
index 0000000000..018de3eb42
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_included_detail.html
@@ -0,0 +1,46 @@
1{% extends "package_detail_base.html" %}
2{% load projecttags %}
3
4{% block title %}
5{% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
6 <h1>{{fullPackageSpec}} <small>({{target.target}})</small></h1>
7{% endwith %}
8{% endblock title %}
9
10{% block tabcontent %}
11{% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
12 {% include "package_included_tabs.html" with active_tab="detail" %}
13 <div class="tab-content">
14 <div class="tab-pane active" id="files">
15 {% if packageFileCount > 0 %}
16 <table class="table table-bordered table-hover">
17 <thead>
18 <tr>
19 <th>File</th>
20 <th>Size</th>
21 </tr>
22 </thead>
23 {% for file in package.buildfilelist_package.all|dictsort:"path" %}
24 <tbody>
25 <tr>
26 <td>
27 <a href="{% url 'image_information_dir' build.id target.id file.id %}">
28 {{file.path}}
29 </a>
30 </td>
31 <td>{{file.size|filtered_filesizeformat}}</td>
32 </tr>
33 </tbody>
34 {% endfor %}
35 </table>
36
37 {% else %}
38 <div class="alert alert-info">
39 <strong>{{fullPackageSpec}}</strong> does not generate any files.
40 </div>
41 {% endif %}
42 </div> <!-- end tab-pane -->
43 </div> <!-- end tab content -->
44
45{% endwith %}
46{% endblock tabcontent %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html b/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html
new file mode 100644
index 0000000000..9cfc7fe7c2
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html
@@ -0,0 +1,47 @@
1{% extends "package_detail_base.html" %}
2{% load projecttags %}
3
4{% block title %}
5 {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec %}
6 <h1>{{fullPackageSpec}} <small>({{target.target}})</small></h1>
7 {% endwith %}
8{% endblock title %}
9
10{% block tabcontent %}
11 {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
12 {% include "package_included_tabs.html" with active_tab="reverse" %}
13 <div class="tab-content">
14 <div class="tab-pane active" id="brought-in-by">
15
16 {% ifequal reverse_deps|length 0 %}
17 <div class="alert alert-info">
18 <strong>{{fullPackageSpec}}</strong> has no reverse runtime dependencies.
19 </div>
20 {% else %}
21 <table class="table table-bordered table-hover">
22 <thead>
23 <tr>
24 <th>Package</th>
25 <th>Package Version</th>
26 <th>Size</th>
27 </tr>
28 </thead>
29 {% for reverse_dep in reverse_deps|dictsort:"name" %}
30 <tbody>
31 <tr>
32 <td>
33 <a href="{% url 'package_included_detail' build.id target.id reverse_dep.dependent_id %}">
34 {{reverse_dep.name}}
35 </a>
36 </td>
37 <td>{{reverse_dep.version}}</td>
38 <td>{{reverse_dep.size|filtered_filesizeformat}}</td>
39 </tr>
40 </tbody>
41 {% endfor %}
42 </table>
43 {% endifequal %}
44 </div> <!-- end tab-pane -->
45 </div> <!-- end tab content -->
46 {% endwith %}
47{% endblock tabcontent %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_included_tabs.html b/bitbake/lib/toaster/toastergui/templates/package_included_tabs.html
new file mode 100644
index 0000000000..5a97ba36b3
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/package_included_tabs.html
@@ -0,0 +1,33 @@
1
2 <ul class="nav nav-pills">
3 {% if active_tab == "detail" %}
4 <li class="active">
5 {% else %}
6 <li class="">
7 {% endif %}
8 <a href="{% url 'package_included_detail' build.id target.id package.id %}">
9 <i class="icon-question-sign get-help" title="The files this package adds to the image root file system"></i>
10 Files in root file system ({{packageFileCount}})
11 </a>
12 </li>
13 {% if active_tab == "dependencies" %}
14 <li class="active">
15 {% else %}
16 <li class="">
17 {% endif %}
18 <a href="{% url 'package_included_dependencies' build.id target.id package.id %}">
19 <i class="icon-question-sign get-help" data-toggle="tooltip" title="Package runtime dependencies"></i>
20 Runtime dependencies ({{dependency_count}})
21 </a>
22 </li>
23 {% if active_tab == "reverse" %}
24 <li class="active">
25 {% else %}
26 <li class="">
27 {% endif %}
28 <a href="{% url 'package_included_reverse_dependencies' build.id target.id package.id %}">
29 <i class="icon-question-sign get-help" data-toggle="tooltip" title="The package runtime reverse dependencies (i.e. which other packages in this image depend on this package). Reverse dependencies reflect only the 'depends' dependency type"></i>
30 Reverse Runtime dependencies ({{reverse_count}})
31 </a>
32 </li>
33 </ul>
diff --git a/bitbake/lib/toaster/toastergui/templates/recipe.html b/bitbake/lib/toaster/toastergui/templates/recipe.html
index 5dea75382f..eba15baad3 100644
--- a/bitbake/lib/toaster/toastergui/templates/recipe.html
+++ b/bitbake/lib/toaster/toastergui/templates/recipe.html
@@ -161,9 +161,9 @@
161 {% for package in packages %} 161 {% for package in packages %}
162 162
163 <tr> 163 <tr>
164 <td><a href="{% url "package" build.pk package.pk %}">{{package.name}}</a></td> 164 <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.name}}</a></td>
165 <td><a href="{% url "package" build.pk package.pk %}">{{package.version}}-{{package.revision}}</a></td> 165 <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.version}}_{{package.revision}}</a></td>
166 <td><a href="{% url "package" build.pk package.pk %}">{{package.size}}</a></td> 166 <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.size}}</a></td>
167 </tr> 167 </tr>
168 168
169 {% endfor %} 169 {% endfor %}
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py
index 5105be48d2..667bc38420 100644
--- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py
+++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py
@@ -20,8 +20,10 @@
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 datetime import datetime, timedelta 22from datetime import datetime, timedelta
23import re
23from django import template 24from django import template
24from django.utils import timezone 25from django.utils import timezone
26from django.template.defaultfilters import filesizeformat
25 27
26register = template.Library() 28register = template.Library()
27 29
@@ -101,3 +103,14 @@ def format_none_and_zero(value):
101 """Return empty string if the value is None, zero or Not Applicable 103 """Return empty string if the value is None, zero or Not Applicable
102 """ 104 """
103 return "" if (not value) or (value == 0) or (value == "0") or (value == 'Not Applicable') else value 105 return "" if (not value) or (value == 0) or (value == "0") or (value == 'Not Applicable') else value
106
107@register.filter
108def filtered_filesizeformat(value):
109 """Change output from fileformatsize to suppress trailing '.0' and change 'bytes' to 'B'
110 """
111 return filesizeformat(value).replace("bytes", "B").replace(".0", "")
112
113@register.filter
114def filtered_packagespec(value):
115 """Strip off empty version and revision"""
116 return re.sub(r'(--$)', '', value)
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index 6e7595b087..8be27b08bc 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -1,7 +1,4 @@
1# 1#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation 2# BitBake Toaster Implementation
6# 3#
7# Copyright (C) 2013 Intel Corporation 4# Copyright (C) 2013 Intel Corporation
@@ -35,7 +32,16 @@ urlpatterns = patterns('toastergui.views',
35 url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)$', 'recipe', name='recipe'), 32 url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)$', 'recipe', name='recipe'),
36 33
37 url(r'^build/(?P<build_id>\d+)/packages/$', 'bpackage', name='packages'), 34 url(r'^build/(?P<build_id>\d+)/packages/$', 'bpackage', name='packages'),
38 url(r'^build/(?P<build_id>\d+)/package/(?P<package_id>\d+)$', 'bfile', name='package'), 35 url(r'^build/(?P<build_id>\d+)/package/(?P<package_id>\d+)$', 'package_built_detail',
36 name='package_built_detail'),
37 url(r'^build/(?P<build_id>\d+)/package_built_dependencies/(?P<package_id>\d+)$',
38 'package_built_dependencies', name='package_built_dependencies'),
39 url(r'^build/(?P<build_id>\d+)/package_included_detail/(?P<target_id>\d+)/(?P<package_id>\d+)$',
40 'package_included_detail', name='package_included_detail'),
41 url(r'^build/(?P<build_id>\d+)/package_included_dependencies/(?P<target_id>\d+)/(?P<package_id>\d+)$',
42 'package_included_dependencies', name='package_included_dependencies'),
43 url(r'^build/(?P<build_id>\d+)/package_included_reverse_dependencies/(?P<target_id>\d+)/(?P<package_id>\d+)$',
44 'package_included_reverse_dependencies', name='package_included_reverse_dependencies'),
39 45
40 # images are known as targets in the internal model 46 # images are known as targets in the internal model
41 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$', 'target', name='target'), 47 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$', 'target', name='target'),
@@ -47,6 +53,10 @@ urlpatterns = patterns('toastergui.views',
47 url(r'^build/(?P<build_id>\d+)/cpuusage$', 'cpuusage', name='cpuusage'), 53 url(r'^build/(?P<build_id>\d+)/cpuusage$', 'cpuusage', name='cpuusage'),
48 url(r'^build/(?P<build_id>\d+)/diskio$', 'diskio', name='diskio'), 54 url(r'^build/(?P<build_id>\d+)/diskio$', 'diskio', name='diskio'),
49 55
56 # image information dir - not yet implemented
57 url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/packagefile/(?P<packagefile_id>\d+)$',
58 'image_information_dir', name='image_information_dir'),
59
50 60
51 # urls not linked from the dashboard 61 # urls not linked from the dashboard
52 url(r'^layers/$', 'layer', name='all-layers'), 62 url(r'^layers/$', 'layer', name='all-layers'),
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 7b84df3340..37e2af2574 100644
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -378,15 +378,6 @@ def recipe(request, build_id, recipe_id):
378 } 378 }
379 return render(request, template, context) 379 return render(request, template, context)
380 380
381def package(request, build_id, package_id):
382 template = "singlepackage.html"
383 if Build.objects.filter(pk=build_id).count() == 0 :
384 return redirect(builds)
385 context = {
386 'build' : Build.objects.filter(pk=build_id)[0],
387 }
388 return render(request, template, context)
389
390def target(request, build_id, target_id): 381def target(request, build_id, target_id):
391 template = "target.html" 382 template = "target.html"
392 if Build.objects.filter(pk=build_id).count() == 0 : 383 if Build.objects.filter(pk=build_id).count() == 0 :
@@ -705,4 +696,191 @@ def layer_versions_recipes(request, layerversion_id):
705 696
706 return render(request, template, context) 697 return render(request, template, context)
707 698
699# A set of dependency types valid for both included and built package views
700OTHER_DEPENDS_BASE = [
701 Package_Dependency.TYPE_RSUGGESTS,
702 Package_Dependency.TYPE_RPROVIDES,
703 Package_Dependency.TYPE_RREPLACES,
704 Package_Dependency.TYPE_RCONFLICTS,
705 ]
706
707# value for invalid row id
708INVALID_KEY = -1
709
710"""
711Given a package id, target_id retrieves two sets of this image and package's
712dependencies. The return value is a dictionary consisting of two other
713lists: a list of 'runtime' dependencies, that is, having RDEPENDS
714values in source package's recipe, and a list of other dependencies, that is
715the list of possible recipe variables as found in OTHER_DEPENDS_BASE plus
716the RRECOMENDS or TRECOMENDS value.
717The lists are built in the sort order specified for the package runtime
718dependency views.
719"""
720def get_package_dependencies(package_id, target_id = INVALID_KEY):
721 runtime_deps = []
722 other_deps = []
723 other_depends_types = OTHER_DEPENDS_BASE
724
725 if target_id != INVALID_KEY :
726 rdepends_type = Package_Dependency.TYPE_TRDEPENDS
727 other_depends_types += [Package_Dependency.TYPE_TRECOMMENDS]
728 else :
729 rdepends_type = Package_Dependency.TYPE_RDEPENDS
730 other_depends_types += [Package_Dependency.TYPE_RRECOMMENDS]
731
732 package = Package.objects.get(pk=package_id)
733 if target_id != INVALID_KEY :
734 alldeps = package.package_dependencies_source.filter(target_id__exact = target_id)
735 else :
736 alldeps = package.package_dependencies_source.all()
737 for idep in alldeps:
738 dep_package = Package.objects.get(pk=idep.depends_on_id)
739 dep_entry = Package_Dependency.DEPENDS_DICT[idep.dep_type]
740 if dep_package.version == '' :
741 version = ''
742 else :
743 version = dep_package.version + "-" + dep_package.revision
744 installed = False
745 if target_id != INVALID_KEY :
746 if Target_Installed_Package.objects.filter(target_id__exact = target_id, package_id__exact = dep_package.id).count() > 0:
747 installed = True
748 dep = {
749 'name' : dep_package.name,
750 'version' : version,
751 'size' : dep_package.size,
752 'dep_type' : idep.dep_type,
753 'dep_type_display' : dep_entry[0].capitalize(),
754 'dep_type_help' : dep_entry[1] % (dep_package.name, package.name),
755 'depends_on_id' : dep_package.id,
756 'installed' : installed,
757 }
758 if idep.dep_type == rdepends_type :
759 runtime_deps.append(dep)
760 elif idep.dep_type in other_depends_types :
761 other_deps.append(dep)
762
763 rdep_sorted = sorted(runtime_deps, key=lambda k: k['name'])
764 odep_sorted = sorted(
765 sorted(other_deps, key=lambda k: k['name']),
766 key=lambda k: k['dep_type'])
767 retvalues = {'runtime_deps' : rdep_sorted, 'other_deps' : odep_sorted}
768 return retvalues
769
770# Return the count of packages dependent on package for this target_id image
771def get_package_reverse_dep_count(package, target_id):
772 return package.package_dependencies_target.filter(target_id__exact=target_id, dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count()
773
774# Return the count of the packages that this package_id is dependent on.
775# Use one of the two RDEPENDS types, either TRDEPENDS if the package was
776# installed, or else RDEPENDS if only built.
777def get_package_dependency_count(package, target_id, is_installed):
778 if is_installed :
779 return package.package_dependencies_source.filter(target_id__exact = target_id,
780 dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count()
781 else :
782 return package.package_dependencies_source.filter(dep_type__exact = Package_Dependency.TYPE_RDEPENDS).count()
783
784def package_built_detail(request, build_id, package_id):
785 template = "package_built_detail.html"
786 if Build.objects.filter(pk=build_id).count() == 0 :
787 return redirect(builds)
788 package = Package.objects.filter(pk=package_id)[0]
789 context = {
790 'build' : Build.objects.filter(pk=build_id)[0],
791 'package' : package,
792 'dependency_count' : get_package_dependency_count(package, -1, False),
793 }
794 return render(request, template, context)
795
796def package_built_dependencies(request, build_id, package_id):
797 template = "package_built_dependencies.html"
798 if Build.objects.filter(pk=build_id).count() == 0 :
799 return redirect(builds)
800
801 package = Package.objects.filter(pk=package_id)[0]
802 dependencies = get_package_dependencies(package_id)
803 context = {
804 'build' : Build.objects.filter(pk=build_id)[0],
805 'package' : package,
806 'runtime_deps' : dependencies['runtime_deps'],
807 'other_deps' : dependencies['other_deps'],
808 'dependency_count' : get_package_dependency_count(package, -1, False)
809 }
810 return render(request, template, context)
811
812
813def package_included_detail(request, build_id, target_id, package_id):
814 template = "package_included_detail.html"
815 if Build.objects.filter(pk=build_id).count() == 0 :
816 return redirect(builds)
817
818 package = Package.objects.filter(pk=package_id)[0]
819 target = Target.objects.filter(pk=target_id)[0]
820 context = {
821 'build' : Build.objects.filter(pk=build_id)[0],
822 'target' : target,
823 'package' : package,
824 'reverse_count' : get_package_reverse_dep_count(package, target_id),
825 'dependency_count' : get_package_dependency_count(package, target_id, True)
826 }
827 return render(request, template, context)
828
829def package_included_dependencies(request, build_id, target_id, package_id):
830 template = "package_included_dependencies.html"
831 if Build.objects.filter(pk=build_id).count() == 0 :
832 return redirect(builds)
833
834 package = Package.objects.filter(pk=package_id)[0]
835 target = Target.objects.filter(pk=target_id)[0]
836
837 dependencies = get_package_dependencies(package_id, target_id)
838 context = {
839 'build' : Build.objects.filter(pk=build_id)[0],
840 'package' : package,
841 'target' : target,
842 'runtime_deps' : dependencies['runtime_deps'],
843 'other_deps' : dependencies['other_deps'],
844 'reverse_count' : get_package_reverse_dep_count(package, target_id),
845 'dependency_count' : get_package_dependency_count(package, target_id, True)
846 }
847 return render(request, template, context)
848
849def package_included_reverse_dependencies(request, build_id, target_id, package_id):
850 template = "package_included_reverse_dependencies.html"
851 if Build.objects.filter(pk=build_id).count() == 0 :
852 return redirect(builds)
853
854 package = Package.objects.filter(pk=package_id)[0]
855 target = Target.objects.filter(pk=target_id)[0]
856
857 reverse_deps = []
858 alldeps = package.package_dependencies_target.filter(target_id__exact=target_id)
859 for idep in alldeps:
860 dep_package = Package.objects.get(pk=idep.package_id)
861 version = dep_package.version
862 if version != '' :
863 version += '-' + dep_package.revision
864 dep = {
865 'name' : dep_package.name,
866 'dependent_id' : dep_package.id,
867 'version' : version,
868 'size' : dep_package.size
869 }
870 if idep.dep_type == Package_Dependency.TYPE_TRDEPENDS :
871 reverse_deps.append(dep)
872
873 context = {
874 'build' : Build.objects.filter(pk=build_id)[0],
875 'package' : package,
876 'target' : target,
877 'reverse_deps' : reverse_deps,
878 'reverse_count' : get_package_reverse_dep_count(package, target_id),
879 'dependency_count' : get_package_dependency_count(package, target_id, True)
880 }
881 return render(request, template, context)
882
883def image_information_dir(request, build_id, target_id, packagefile_id):
884 # stubbed for now
885 return redirect(builds)
708 886