class Package(models.Model):
+ search_allowed_fields = ['name', 'installed_name', 'section', 'summary']
build = models.ForeignKey('Build')
recipe = models.ForeignKey('Recipe', null=True)
name = models.CharField(max_length=100)
class Package_Dependency(models.Model):
TYPE_RDEPENDS = 0
- TYPE_RPROVIDES = 1
+ TYPE_TRDEPENDS = 1
TYPE_RRECOMMENDS = 2
- TYPE_RSUGGESTS = 3
- TYPE_RREPLACES = 4
- TYPE_RCONFLICTS = 5
- TYPE_TRDEPENDS = 6
- TYPE_TRECOMMENDS = 7
+ TYPE_TRECOMMENDS = 3
+ TYPE_RSUGGESTS = 4
+ TYPE_RPROVIDES = 5
+ TYPE_RREPLACES = 6
+ TYPE_RCONFLICTS = 7
+ ' TODO: bpackage should be changed to remove the DEPENDS_TYPE access '
DEPENDS_TYPE = (
- (TYPE_RDEPENDS, "rdepends"),
- (TYPE_RPROVIDES, "rprovides"),
- (TYPE_RRECOMMENDS, "rrecommends"),
- (TYPE_RSUGGESTS, "rsuggests"),
- (TYPE_RREPLACES, "rreplaces"),
- (TYPE_RCONFLICTS, "rconflicts"),
- (TYPE_TRDEPENDS, "trdepends"),
- (TYPE_TRECOMMENDS, "trecommends"),
+ (TYPE_RDEPENDS, "depends"),
+ (TYPE_TRDEPENDS, "depends"),
+ (TYPE_TRECOMMENDS, "recommends"),
+ (TYPE_RRECOMMENDS, "recommends"),
+ (TYPE_RSUGGESTS, "suggests"),
+ (TYPE_RPROVIDES, "provides"),
+ (TYPE_RREPLACES, "replaces"),
+ (TYPE_RCONFLICTS, "conflicts"),
)
+ ''' Indexed by dep_type, in view order, key for short name and help
+ description which when viewed will be printf'd with the
+ package name.
+ '''
+ DEPENDS_DICT = {
+ TYPE_RDEPENDS : ("depends", "%s is required to run %s"),
+ TYPE_TRDEPENDS : ("depends", "%s is required to run %s"),
+ TYPE_TRECOMMENDS : ("recommends", "%s extends the usability of %s"),
+ TYPE_RRECOMMENDS : ("recommends", "%s extends the usability of %s"),
+ TYPE_RSUGGESTS : ("suggests", "%s is suggested for installation with %s"),
+ TYPE_RPROVIDES : ("provides", "%s is provided by %s"),
+ TYPE_RREPLACES : ("replaces", "%s is replaced by %s"),
+ TYPE_RCONFLICTS : ("conflicts", "%s conflicts with %s, which will not be installed if this package is not first removed"),
+ }
+
package = models.ForeignKey(Package, related_name='package_dependencies_source')
depends_on = models.ForeignKey(Package, related_name='package_dependencies_target') # soft dependency
dep_type = models.IntegerField(choices=DEPENDS_TYPE)
class Target_Installed_Package(models.Model):
target = models.ForeignKey(Target)
- package = models.ForeignKey(Package)
+ package = models.ForeignKey(Package, related_name='buildtargetlist_package')
class Package_File(models.Model):
package = models.ForeignKey(Package, related_name='buildfilelist_package')
{% for package in objects %}
<tr class="data">
- <td><a name="#{{package.name}}" href="{% url "package" build.pk package.pk %}">{{package.name}} ({{package.filelist_bpackage.count}} files)</a></td>
+ <td><a name="#{{package.name}}" href="{% url "package_built_detail" build.pk package.pk %}">{{package.name}} ({{package.filelist_bpackage.count}} files)</a></td>
<td>{{package.version}}-{{package.revision}}</td>
<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>
--- /dev/null
+{% extends "package_detail_base.html" %}
+{% 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 %}">
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the files produced by this package."></i>
+ Generated files ({{package.buildfilelist_package.count}})
+ </a>
+ </li>
+ <li class="active">
+ <a href="{% url 'package_built_dependencies' build.id package.id %}">
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the runtime packages required by this package."></i>
+ Runtime dependencies ({{dependency_count}})
+ </a>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="dependencies">
+ {% ifequal runtime_deps|length 0 %}
+ <div class="alert alert-info">
+ <strong>{{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.
+ </div>
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>Package</th>
+ <th>Version</th>
+ <th>Size</th>
+ </tr>
+ </thead>
+ {% for runtime_dep in runtime_deps %}
+ <tbody>
+ {% ifequal runtime_dep.version '' %}
+ <tr class="muted">
+ <td>{{runtime_dep.name}}</td>
+ <td>{{runtime_dep.version}}</td>
+ <td></td>
+ </div>
+ </tr>
+ {% else %}
+ <tr>
+ <td>
+ <a href="{% url 'package_built_detail' build.id runtime_dep.depends_on_id %}">
+ {{runtime_dep.name}}
+ </a>
+ </td>
+ <td>{{runtime_dep.version}}</td>
+ <td>{{runtime_dep.size|filtered_filesizeformat}}</td>
+ </tr>
+ {% endifequal %}
+ </tbody>
+ {% endfor %}
+ </table>
+ {% endifequal %}
+ {% ifnotequal other_deps|length 0 %}
+ <h3>Other runtime relationships</h3>
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>Package</th>
+ <th>Version</th>
+ <th>Size</th>
+
+ <th>
+ <i class="icon-question-sign get-help" title="There are 5 relationship types: recommends, suggests, provides, replaces and conflicts"></i>
+ Relationship type
+ </th>
+ </tr>
+ </thead>
+
+ {% for other_dep in other_deps %}
+ <tbody>
+ {% ifequal other_dep.version '' %}
+ <tr class="muted">
+ <td>{{other_dep.name}}</td>
+ <td>{{other_dep.version}}</td>
+ <td></td>
+ <td>
+ {{other_dep.dep_type_display}}
+ <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
+ </td>
+ </tr>
+ {% else %}
+ <tr>
+ <td>
+ <a href="{% url 'package_built_detail' build.id other_dep.depends_on_id %}">
+ {{other_dep.name}}
+ </a>
+ </td>
+ <td>{{other_dep.version}}</td>
+ <td>{{other_dep.size|filtered_filesizeformat}}</td>
+ <td>
+ {{other_dep.dep_type_display}}
+ <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
+ </td>
+ </tr>
+ </tbody>
+ {% endifequal %}
+ {% endfor %}
+ </table>
+ {% endifnotequal %}
+ </div> <!-- tab-pane -->
+ </div> <!-- tab-content -->
+ {% endwith %}
+{% endblock tabcontent %}
--- /dev/null
+{% extends "package_detail_base.html" %}
+{% load projecttags %}
+
+{% block tabcontent %}
+ {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec packageFileCount=package.buildfilelist_package.count %}
+ <!-- Generated Files -->
+ {% if package.buildtargetlist_package.count == 0 %}
+ {# Not included case #}
+ <ul class="nav nav-pills">
+ <li class="active"> <a href="#">
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the files produced by this package."></i>
+ Generated files ({{packageFileCount}})
+ </a></li>
+ <li class=""><a href="{% url 'package_built_dependencies' build.id package.id %}">
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="Shows the runtime packages required by this package."></i>
+ Runtime dependencies ({{dependency_count}})
+ </a></li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="files">
+ <!-- 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.
+ </div>
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>File</th>
+ <th>Size</th>
+ </tr>
+ </thead>
+ {% for file in package.buildfilelist_package.all|dictsort:"path" %}
+ <tbody>
+ <tr>
+ <td>{{file.path}}</td>
+ <td>{{file.size|filtered_filesizeformat}}</td>
+ </tr>
+ </tbody>
+ {% endfor %}
+ </table>
+
+ {% else %}
+ <div class="alert alert-info">
+ <strong>{{fullPackageSpec}}</strong> does not generate any files.
+ </div>
+ {% endif %}
+
+ </div> <!-- tab-pane active -->
+ </div> <!-- tab-content -->
+ {% else %}
+ {# Included case #}
+ <div class="tab-content">
+ <div class="tab-pane active">
+ <div class="lead well">
+ Package included in:
+ {% for itarget in package.buildtargetlist_package.all|dictsort:"target.target" %}
+ <a href="{% url 'package_included_detail' build.id itarget.target.id package.id %}">
+ {% if forloop.counter0 > 0 %}
+ ,
+ {% endif %}
+ {{itarget.target.target}}
+ </a>
+ {% endfor %}
+ </div>
+ </div> <!-- tab-pane active -->
+ </div> <!-- tab-content -->
+ {% endif %}
+
+ {% endwith %}
+{% endblock tabcontent %}
--- /dev/null
+{% extends "basebuilddetailpage.html" %}
+{% load projecttags %}
+
+{% 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>
+ {% else %}
+ <li><a href="{% url "packages" build.id %}"> Packages </a></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>
+ {% endblock title %}
+ </div> <!-- page-header -->
+ </div> <!-- row span11 page-header -->
+
+ {% block twocolumns %}
+ <div class="row span7 tabbable">
+ {% block tabcontent %}
+ {% endblock tabcontent %}
+ </div> <!-- row span7 -->
+
+ <div class="row span4 well">
+ <h2>Package information</h2>
+
+ <!-- info presented as definition list -->
+ <dl>
+ <dt>
+ Size
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="The size of the package"></i>
+ </dt>
+ <dd>
+ {% comment %}
+ if recipe is absent, filesize is not 0
+ {% endcomment %}
+ {% if package.recipe_id > 0 %}
+ {{package.size|filtered_filesizeformat}}
+ {% if target.file_size %}
+ ({{package.size|multiply:100|divide:target.file_size}}% of included package size)
+ {% endif %}
+
+ {% endif %}
+ </dd>
+
+ <dt>
+ License
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="The license under which this package is distributed"></i>
+ </dt>
+ <dd>{{package.license}}</dd>
+
+ {% comment %}
+ # Removed per review on 1/18/2014 until license data population
+ # problemse are resolved.
+ <dt>
+ License files
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="Location in disk of the license files that apply to the package"></i>
+ </dt>
+ <dd></dd>
+ {% endcomment %}
+
+ <dt>
+ Recipe
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="The name of the recipe building this package"></i>
+ </dt>
+ <dd>
+ {% if package.recipe_id > 0 %}
+ <a href="{% url "recipe" build.id package.recipe_id %}"> {{package.recipe.name}} </a>
+ {% else %}
+ {{package.recipe.name}}
+ {% endif %}
+ </dd>
+
+ <dt>
+ Recipe version
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="The version of the recipe building this package"></i>
+ </dt>
+ <dd>{{package.recipe.version}}</dd>
+
+ <dt>
+ Layer
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="The name of the layer providing the recipe that builds this package"></i>
+ </dt>
+ <dd>
+ {{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
+ # decision on index search algorithm
+ <a href="http://layers.openembedded.org" target="_blank">
+ <i class="icon-share get-info"></i>
+ {% endcomment %}
+ </a>
+ {% endif %}
+ </dd>
+
+ <dt>
+ Layer branch
+ <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>
+ </dt>
+ <dd>{{package.recipe.layer_version.branch}}</dd>
+ <dt>
+ Layer commit
+ <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>
+ </dt>
+
+ <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd>
+ <dt>
+ Layer directory
+ <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>
+ </dt>
+ <dd><code>{{package.recipe.layer_version.layer.local_path}}</code></dd>
+ </dl>
+ </div> <!-- row4 well -->
+ {% endblock twocolumns %}
+{% endwith %}
+{% endblock pagedetailinfomain %}
--- /dev/null
+{% extends "package_detail_base.html" %}
+{% 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 %}
+{% endblock title %}
+
+{% block tabcontent %}
+ {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec 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">
+ {% ifnotequal runtime_deps|length 0 %}
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>Package</th>
+ <th>Version</th>
+ <th>Size</th>
+ </tr>
+ </thead>
+ {% for runtime_dep in runtime_deps %}
+ <tbody>
+ <tr>
+ <td>
+ <a href="{% url 'package_included_detail' build.id target.id runtime_dep.depends_on_id %}">
+ {{runtime_dep.name}}
+ </a>
+ </td>
+ <td>{{runtime_dep.version}}</td>
+ <td>{{runtime_dep.size|filtered_filesizeformat}}</td>
+ </tr>
+ </tbody>
+ {% endfor %}
+ </table>
+ {% else %}
+ <div class="alert alert-info">
+ <strong>{{fullPackageSpec}}</strong> has no runtime dependencies.
+ </div>
+ {% endifnotequal %}
+
+ {% ifnotequal other_deps|length 0 %}
+ <h3>Other runtime relationships</h3>
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>Package</th>
+ <th>Version</th>
+ <th>Size</th>
+ <th>
+ <i class="icon-question-sign get-help" title="There are 5 relationship types: recommends, suggests, provides, replaces and conflicts"></i>
+ Relationship type
+ </th>
+ </tr>
+ </thead>
+
+ {% for other_dep in other_deps %}
+ <tbody>
+ {% if other_dep.installed %}
+ <tr>
+ <td>
+ <a href="{% url 'package_included_detail' build.id target.id other_dep.depends_on_id %}">
+ {{other_dep.name}}
+ </a>
+ </td>
+ <td>{{other_dep.version}}</td>
+ <td>{{other_dep.size|filtered_filesizeformat}}</td>
+ <td>
+ {{other_dep.dep_type_display}}
+ <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
+ </td>
+ </tr>
+ {% else %}
+ <tr class="muted">
+ <td>{{other_dep.name}}</td>
+ <td>{{other_dep.version}}</td>
+ <td></td>
+ <td>
+ {{other_dep.dep_type_display}}
+ <i class="icon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></i>
+ </td>
+ </tr>
+ {% endif %}
+ </tbody>
+ {% endfor %}
+ </table>
+ {% endifnotequal %}
+ </div> <!-- end tab-pane -->
+ </div> <!-- end tab content -->
+ {% endwith %}
+{% endblock tabcontent %}
--- /dev/null
+{% extends "package_detail_base.html" %}
+{% 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 %}
+{% endblock title %}
+
+{% block tabcontent %}
+{% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec 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">
+ {% if packageFileCount > 0 %}
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>File</th>
+ <th>Size</th>
+ </tr>
+ </thead>
+ {% for file in package.buildfilelist_package.all|dictsort:"path" %}
+ <tbody>
+ <tr>
+ <td>
+ <a href="{% url 'image_information_dir' build.id target.id file.id %}">
+ {{file.path}}
+ </a>
+ </td>
+ <td>{{file.size|filtered_filesizeformat}}</td>
+ </tr>
+ </tbody>
+ {% endfor %}
+ </table>
+
+ {% else %}
+ <div class="alert alert-info">
+ <strong>{{fullPackageSpec}}</strong> does not generate any files.
+ </div>
+ {% endif %}
+ </div> <!-- end tab-pane -->
+ </div> <!-- end tab content -->
+
+{% endwith %}
+{% endblock tabcontent %}
--- /dev/null
+{% extends "package_detail_base.html" %}
+{% 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 %}
+{% endblock title %}
+
+{% block tabcontent %}
+ {% with fullPackageSpec=package.name|add:"-"|add:package.version|add:"-"|add:package.revision|filtered_packagespec 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.
+ </div>
+ {% else %}
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th>Package</th>
+ <th>Package Version</th>
+ <th>Size</th>
+ </tr>
+ </thead>
+ {% for reverse_dep in reverse_deps|dictsort:"name" %}
+ <tbody>
+ <tr>
+ <td>
+ <a href="{% url 'package_included_detail' build.id target.id reverse_dep.dependent_id %}">
+ {{reverse_dep.name}}
+ </a>
+ </td>
+ <td>{{reverse_dep.version}}</td>
+ <td>{{reverse_dep.size|filtered_filesizeformat}}</td>
+ </tr>
+ </tbody>
+ {% endfor %}
+ </table>
+ {% endifequal %}
+ </div> <!-- end tab-pane -->
+ </div> <!-- end tab content -->
+ {% endwith %}
+{% endblock tabcontent %}
--- /dev/null
+
+ <ul class="nav nav-pills">
+ {% if active_tab == "detail" %}
+ <li class="active">
+ {% else %}
+ <li class="">
+ {% endif %}
+ <a href="{% url 'package_included_detail' build.id target.id package.id %}">
+ <i class="icon-question-sign get-help" title="The files this package adds to the image root file system"></i>
+ Files in root file system ({{packageFileCount}})
+ </a>
+ </li>
+ {% if active_tab == "dependencies" %}
+ <li class="active">
+ {% else %}
+ <li class="">
+ {% endif %}
+ <a href="{% url 'package_included_dependencies' build.id target.id package.id %}">
+ <i class="icon-question-sign get-help" data-toggle="tooltip" title="Package runtime dependencies"></i>
+ Runtime dependencies ({{dependency_count}})
+ </a>
+ </li>
+ {% if active_tab == "reverse" %}
+ <li class="active">
+ {% else %}
+ <li class="">
+ {% endif %}
+ <a href="{% url 'package_included_reverse_dependencies' build.id target.id package.id %}">
+ <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>
+ Reverse Runtime dependencies ({{reverse_count}})
+ </a>
+ </li>
+ </ul>
{% for package in packages %}
<tr>
- <td><a href="{% url "package" build.pk package.pk %}">{{package.name}}</a></td>
- <td><a href="{% url "package" build.pk package.pk %}">{{package.version}}-{{package.revision}}</a></td>
- <td><a href="{% url "package" build.pk package.pk %}">{{package.size}}</a></td>
+ <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.name}}</a></td>
+ <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.version}}_{{package.revision}}</a></td>
+ <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.size}}</a></td>
</tr>
{% endfor %}
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from datetime import datetime, timedelta
+import re
from django import template
from django.utils import timezone
+from django.template.defaultfilters import filesizeformat
register = template.Library()
"""Return empty string if the value is None, zero or Not Applicable
"""
return "" if (not value) or (value == 0) or (value == "0") or (value == 'Not Applicable') else value
+
+@register.filter
+def filtered_filesizeformat(value):
+ """Change output from fileformatsize to suppress trailing '.0' and change 'bytes' to 'B'
+ """
+ return filesizeformat(value).replace("bytes", "B").replace(".0", "")
+
+@register.filter
+def filtered_packagespec(value):
+ """Strip off empty version and revision"""
+ return re.sub(r'(--$)', '', value)
#
-# ex:ts=4:sw=4:sts=4:et
-# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
-#
# BitBake Toaster Implementation
#
# Copyright (C) 2013 Intel Corporation
url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)$', 'recipe', name='recipe'),
url(r'^build/(?P<build_id>\d+)/packages/$', 'bpackage', name='packages'),
- url(r'^build/(?P<build_id>\d+)/package/(?P<package_id>\d+)$', 'bfile', name='package'),
+ url(r'^build/(?P<build_id>\d+)/package/(?P<package_id>\d+)$', 'package_built_detail',
+ name='package_built_detail'),
+ url(r'^build/(?P<build_id>\d+)/package_built_dependencies/(?P<package_id>\d+)$',
+ 'package_built_dependencies', name='package_built_dependencies'),
+ url(r'^build/(?P<build_id>\d+)/package_included_detail/(?P<target_id>\d+)/(?P<package_id>\d+)$',
+ 'package_included_detail', name='package_included_detail'),
+ url(r'^build/(?P<build_id>\d+)/package_included_dependencies/(?P<target_id>\d+)/(?P<package_id>\d+)$',
+ 'package_included_dependencies', name='package_included_dependencies'),
+ url(r'^build/(?P<build_id>\d+)/package_included_reverse_dependencies/(?P<target_id>\d+)/(?P<package_id>\d+)$',
+ 'package_included_reverse_dependencies', name='package_included_reverse_dependencies'),
# images are known as targets in the internal model
url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)$', 'target', name='target'),
url(r'^build/(?P<build_id>\d+)/cpuusage$', 'cpuusage', name='cpuusage'),
url(r'^build/(?P<build_id>\d+)/diskio$', 'diskio', name='diskio'),
+ # image information dir - not yet implemented
+ url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/packagefile/(?P<packagefile_id>\d+)$',
+ 'image_information_dir', name='image_information_dir'),
+
# urls not linked from the dashboard
url(r'^layers/$', 'layer', name='all-layers'),
}
return render(request, template, context)
-def package(request, build_id, package_id):
- template = "singlepackage.html"
- if Build.objects.filter(pk=build_id).count() == 0 :
- return redirect(builds)
- context = {
- 'build' : Build.objects.filter(pk=build_id)[0],
- }
- return render(request, template, context)
-
def target(request, build_id, target_id):
template = "target.html"
if Build.objects.filter(pk=build_id).count() == 0 :
return render(request, template, context)
+# A set of dependency types valid for both included and built package views
+OTHER_DEPENDS_BASE = [
+ Package_Dependency.TYPE_RSUGGESTS,
+ Package_Dependency.TYPE_RPROVIDES,
+ Package_Dependency.TYPE_RREPLACES,
+ Package_Dependency.TYPE_RCONFLICTS,
+ ]
+
+# value for invalid row id
+INVALID_KEY = -1
+
+"""
+Given a package id, target_id retrieves two sets of this image and package's
+dependencies. The return value is a dictionary consisting of two other
+lists: a list of 'runtime' dependencies, that is, having RDEPENDS
+values in source package's recipe, and a list of other dependencies, that is
+the list of possible recipe variables as found in OTHER_DEPENDS_BASE plus
+the RRECOMENDS or TRECOMENDS value.
+The lists are built in the sort order specified for the package runtime
+dependency views.
+"""
+def get_package_dependencies(package_id, target_id = INVALID_KEY):
+ runtime_deps = []
+ other_deps = []
+ other_depends_types = OTHER_DEPENDS_BASE
+
+ if target_id != INVALID_KEY :
+ rdepends_type = Package_Dependency.TYPE_TRDEPENDS
+ other_depends_types += [Package_Dependency.TYPE_TRECOMMENDS]
+ else :
+ rdepends_type = Package_Dependency.TYPE_RDEPENDS
+ other_depends_types += [Package_Dependency.TYPE_RRECOMMENDS]
+
+ package = Package.objects.get(pk=package_id)
+ if target_id != INVALID_KEY :
+ alldeps = package.package_dependencies_source.filter(target_id__exact = target_id)
+ else :
+ alldeps = package.package_dependencies_source.all()
+ for idep in alldeps:
+ dep_package = Package.objects.get(pk=idep.depends_on_id)
+ dep_entry = Package_Dependency.DEPENDS_DICT[idep.dep_type]
+ if dep_package.version == '' :
+ version = ''
+ else :
+ version = dep_package.version + "-" + dep_package.revision
+ installed = False
+ if target_id != INVALID_KEY :
+ if Target_Installed_Package.objects.filter(target_id__exact = target_id, package_id__exact = dep_package.id).count() > 0:
+ installed = True
+ dep = {
+ 'name' : dep_package.name,
+ 'version' : version,
+ 'size' : dep_package.size,
+ 'dep_type' : idep.dep_type,
+ 'dep_type_display' : dep_entry[0].capitalize(),
+ 'dep_type_help' : dep_entry[1] % (dep_package.name, package.name),
+ 'depends_on_id' : dep_package.id,
+ 'installed' : installed,
+ }
+ if idep.dep_type == rdepends_type :
+ runtime_deps.append(dep)
+ elif idep.dep_type in other_depends_types :
+ other_deps.append(dep)
+
+ rdep_sorted = sorted(runtime_deps, key=lambda k: k['name'])
+ odep_sorted = sorted(
+ sorted(other_deps, key=lambda k: k['name']),
+ key=lambda k: k['dep_type'])
+ retvalues = {'runtime_deps' : rdep_sorted, 'other_deps' : odep_sorted}
+ return retvalues
+
+# Return the count of packages dependent on package for this target_id image
+def get_package_reverse_dep_count(package, target_id):
+ return package.package_dependencies_target.filter(target_id__exact=target_id, dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count()
+
+# Return the count of the packages that this package_id is dependent on.
+# Use one of the two RDEPENDS types, either TRDEPENDS if the package was
+# installed, or else RDEPENDS if only built.
+def get_package_dependency_count(package, target_id, is_installed):
+ if is_installed :
+ return package.package_dependencies_source.filter(target_id__exact = target_id,
+ dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count()
+ else :
+ return package.package_dependencies_source.filter(dep_type__exact = Package_Dependency.TYPE_RDEPENDS).count()
+
+def package_built_detail(request, build_id, package_id):
+ template = "package_built_detail.html"
+ if Build.objects.filter(pk=build_id).count() == 0 :
+ return redirect(builds)
+ package = Package.objects.filter(pk=package_id)[0]
+ context = {
+ 'build' : Build.objects.filter(pk=build_id)[0],
+ 'package' : package,
+ 'dependency_count' : get_package_dependency_count(package, -1, False),
+ }
+ return render(request, template, context)
+
+def package_built_dependencies(request, build_id, package_id):
+ template = "package_built_dependencies.html"
+ if Build.objects.filter(pk=build_id).count() == 0 :
+ return redirect(builds)
+
+ package = Package.objects.filter(pk=package_id)[0]
+ dependencies = get_package_dependencies(package_id)
+ context = {
+ 'build' : Build.objects.filter(pk=build_id)[0],
+ 'package' : package,
+ 'runtime_deps' : dependencies['runtime_deps'],
+ 'other_deps' : dependencies['other_deps'],
+ 'dependency_count' : get_package_dependency_count(package, -1, False)
+ }
+ return render(request, template, context)
+
+
+def package_included_detail(request, build_id, target_id, package_id):
+ template = "package_included_detail.html"
+ if Build.objects.filter(pk=build_id).count() == 0 :
+ return redirect(builds)
+
+ package = Package.objects.filter(pk=package_id)[0]
+ target = Target.objects.filter(pk=target_id)[0]
+ context = {
+ 'build' : Build.objects.filter(pk=build_id)[0],
+ 'target' : target,
+ 'package' : package,
+ 'reverse_count' : get_package_reverse_dep_count(package, target_id),
+ 'dependency_count' : get_package_dependency_count(package, target_id, True)
+ }
+ return render(request, template, context)
+
+def package_included_dependencies(request, build_id, target_id, package_id):
+ template = "package_included_dependencies.html"
+ if Build.objects.filter(pk=build_id).count() == 0 :
+ return redirect(builds)
+
+ package = Package.objects.filter(pk=package_id)[0]
+ target = Target.objects.filter(pk=target_id)[0]
+
+ dependencies = get_package_dependencies(package_id, target_id)
+ context = {
+ 'build' : Build.objects.filter(pk=build_id)[0],
+ 'package' : package,
+ 'target' : target,
+ 'runtime_deps' : dependencies['runtime_deps'],
+ 'other_deps' : dependencies['other_deps'],
+ 'reverse_count' : get_package_reverse_dep_count(package, target_id),
+ 'dependency_count' : get_package_dependency_count(package, target_id, True)
+ }
+ return render(request, template, context)
+
+def package_included_reverse_dependencies(request, build_id, target_id, package_id):
+ template = "package_included_reverse_dependencies.html"
+ if Build.objects.filter(pk=build_id).count() == 0 :
+ return redirect(builds)
+
+ package = Package.objects.filter(pk=package_id)[0]
+ target = Target.objects.filter(pk=target_id)[0]
+
+ reverse_deps = []
+ alldeps = package.package_dependencies_target.filter(target_id__exact=target_id)
+ for idep in alldeps:
+ dep_package = Package.objects.get(pk=idep.package_id)
+ version = dep_package.version
+ if version != '' :
+ version += '-' + dep_package.revision
+ dep = {
+ 'name' : dep_package.name,
+ 'dependent_id' : dep_package.id,
+ 'version' : version,
+ 'size' : dep_package.size
+ }
+ if idep.dep_type == Package_Dependency.TYPE_TRDEPENDS :
+ reverse_deps.append(dep)
+
+ context = {
+ 'build' : Build.objects.filter(pk=build_id)[0],
+ 'package' : package,
+ 'target' : target,
+ 'reverse_deps' : reverse_deps,
+ 'reverse_count' : get_package_reverse_dep_count(package, target_id),
+ 'dependency_count' : get_package_dependency_count(package, target_id, True)
+ }
+ return render(request, template, context)
+
+def image_information_dir(request, build_id, target_id, packagefile_id):
+ # stubbed for now
+ return redirect(builds)