mirror of
git://git.yoctoproject.org/layerindex-web.git
synced 2025-07-06 05:34:46 +02:00
update_layer.py: Save and show recipe dependencies
Added a model for the PACKAGECONFIG variable, which has a one to many relationship with the Recipe model. Added models for static build dependencies and dynamic build dependenices, both of which have a many to many relationship with the Recipe model. These objects are created in update_layer.py and are displayed on the Recipe detail page. Added a depends search option for recipes, allowing users to search for recipes based on the recipe's build dependencies. Fixes [YOCTO #12129] Fixes [YOCTO #11415] Signed-off-by: Amanda Brindle <amanda.r.brindle@intel.com>
This commit is contained in:
parent
a64bfed81b
commit
5817a0319e
|
@ -89,12 +89,27 @@ class LayerUpdateAdmin(admin.ModelAdmin):
|
||||||
class RecipeAdmin(admin.ModelAdmin):
|
class RecipeAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['filename', 'pn']
|
search_fields = ['filename', 'pn']
|
||||||
list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name']
|
list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name']
|
||||||
readonly_fields = [fieldname for fieldname in Recipe._meta.get_all_field_names() if fieldname not in ['recipefiledependency', 'classicrecipe']]
|
readonly_fields = [fieldname for fieldname in Recipe._meta.get_all_field_names() if fieldname not in ['recipefiledependency', 'classicrecipe', 'packageconfig']]
|
||||||
def has_add_permission(self, request, obj=None):
|
def has_add_permission(self, request, obj=None):
|
||||||
return False
|
return False
|
||||||
def has_delete_permission(self, request, obj=None):
|
def has_delete_permission(self, request, obj=None):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
class PackageConfigAdmin(admin.ModelAdmin):
|
||||||
|
search_fields = ['feature']
|
||||||
|
list_display = ('feature',)
|
||||||
|
ordering = ('feature',)
|
||||||
|
|
||||||
|
class StaticBuildDepAdmin(admin.ModelAdmin):
|
||||||
|
search_fields = ['name']
|
||||||
|
list_display = ('name',)
|
||||||
|
filter_horizontal = ('recipes',)
|
||||||
|
|
||||||
|
class DynamicBuildDepAdmin(admin.ModelAdmin):
|
||||||
|
search_fields = ['name']
|
||||||
|
list_display = ('name',)
|
||||||
|
filter_horizontal = ('package_configs',)
|
||||||
|
|
||||||
class ClassicRecipeAdmin(admin.ModelAdmin):
|
class ClassicRecipeAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['filename', 'pn']
|
search_fields = ['filename', 'pn']
|
||||||
list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name']
|
list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name']
|
||||||
|
@ -159,6 +174,9 @@ admin.site.register(LayerDependency, LayerDependencyAdmin)
|
||||||
admin.site.register(LayerNote, LayerNoteAdmin)
|
admin.site.register(LayerNote, LayerNoteAdmin)
|
||||||
admin.site.register(Update, UpdateAdmin)
|
admin.site.register(Update, UpdateAdmin)
|
||||||
admin.site.register(LayerUpdate, LayerUpdateAdmin)
|
admin.site.register(LayerUpdate, LayerUpdateAdmin)
|
||||||
|
admin.site.register(PackageConfig, PackageConfigAdmin)
|
||||||
|
admin.site.register(StaticBuildDep, StaticBuildDepAdmin)
|
||||||
|
admin.site.register(DynamicBuildDep, DynamicBuildDepAdmin)
|
||||||
admin.site.register(Recipe, RecipeAdmin)
|
admin.site.register(Recipe, RecipeAdmin)
|
||||||
admin.site.register(RecipeFileDependency)
|
admin.site.register(RecipeFileDependency)
|
||||||
admin.site.register(Machine, MachineAdmin)
|
admin.site.register(Machine, MachineAdmin)
|
||||||
|
|
50
layerindex/migrations/0010_add_dependencies.py
Normal file
50
layerindex/migrations/0010_add_dependencies.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('layerindex', '0009_layerbranch_collection'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DynamicBuildDep',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PackageConfig',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('feature', models.CharField(max_length=255)),
|
||||||
|
('with_option', models.CharField(max_length=255, blank=True)),
|
||||||
|
('without_option', models.CharField(max_length=255, blank=True)),
|
||||||
|
('build_deps', models.CharField(max_length=255, blank=True)),
|
||||||
|
('recipe', models.ForeignKey(to='layerindex.Recipe')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='StaticBuildDep',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('recipes', models.ManyToManyField(to='layerindex.Recipe')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='dynamicbuilddep',
|
||||||
|
name='package_configs',
|
||||||
|
field=models.ManyToManyField(to='layerindex.PackageConfig'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='dynamicbuilddep',
|
||||||
|
name='recipes',
|
||||||
|
field=models.ManyToManyField(to='layerindex.Recipe'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -357,6 +357,30 @@ class Recipe(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return os.path.join(self.filepath, self.filename)
|
return os.path.join(self.filepath, self.filename)
|
||||||
|
|
||||||
|
class PackageConfig(models.Model):
|
||||||
|
recipe = models.ForeignKey(Recipe)
|
||||||
|
feature = models.CharField(max_length=255)
|
||||||
|
with_option = models.CharField(max_length=255, blank=True)
|
||||||
|
without_option = models.CharField(max_length=255, blank=True)
|
||||||
|
build_deps = models.CharField(max_length=255, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s - %s" % (self.recipe, self.feature)
|
||||||
|
|
||||||
|
class StaticBuildDep(models.Model):
|
||||||
|
recipes = models.ManyToManyField(Recipe)
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class DynamicBuildDep(models.Model):
|
||||||
|
package_configs = models.ManyToManyField(PackageConfig)
|
||||||
|
recipes = models.ManyToManyField(Recipe)
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
class RecipeFileDependency(models.Model):
|
class RecipeFileDependency(models.Model):
|
||||||
recipe = models.ForeignKey(Recipe)
|
recipe = models.ForeignKey(Recipe)
|
||||||
|
|
|
@ -57,6 +57,7 @@ def split_recipe_fn(path):
|
||||||
|
|
||||||
def update_recipe_file(tinfoil, data, path, recipe, layerdir_start, repodir):
|
def update_recipe_file(tinfoil, data, path, recipe, layerdir_start, repodir):
|
||||||
fn = str(os.path.join(path, recipe.filename))
|
fn = str(os.path.join(path, recipe.filename))
|
||||||
|
from layerindex.models import PackageConfig, StaticBuildDep, DynamicBuildDep
|
||||||
try:
|
try:
|
||||||
logger.debug('Updating recipe %s' % fn)
|
logger.debug('Updating recipe %s' % fn)
|
||||||
if hasattr(tinfoil, 'parse_recipe_file'):
|
if hasattr(tinfoil, 'parse_recipe_file'):
|
||||||
|
@ -81,6 +82,43 @@ def update_recipe_file(tinfoil, data, path, recipe, layerdir_start, repodir):
|
||||||
recipe.blacklisted = envdata.getVarFlag('PNBLACKLIST', recipe.pn, True) or ""
|
recipe.blacklisted = envdata.getVarFlag('PNBLACKLIST', recipe.pn, True) or ""
|
||||||
recipe.save()
|
recipe.save()
|
||||||
|
|
||||||
|
# Handle static build dependencies for this recipe
|
||||||
|
static_dependencies = envdata.getVar("DEPENDS", True) or ""
|
||||||
|
for dep in static_dependencies.split():
|
||||||
|
static_build_dependency = StaticBuildDep.objects.get_or_create(name=dep)
|
||||||
|
static_build_dependency[0].save()
|
||||||
|
static_build_dependency[0].recipes.add(recipe)
|
||||||
|
|
||||||
|
# Handle the PACKAGECONFIG variables for this recipe
|
||||||
|
package_config_VarFlags = envdata.getVarFlags("PACKAGECONFIG")
|
||||||
|
for key, value in package_config_VarFlags.items():
|
||||||
|
if key == "doc":
|
||||||
|
continue
|
||||||
|
package_config = PackageConfig()
|
||||||
|
package_config.feature = key
|
||||||
|
package_config.recipe = recipe
|
||||||
|
package_config_vals = value.split(",")
|
||||||
|
try:
|
||||||
|
package_config.build_deps = package_config_vals[2]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
package_config.with_option = package_config_vals[0]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
package_config.without_option = package_config_vals[1]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
package_config.save()
|
||||||
|
# Handle the dynamic dependencies for the PACKAGECONFIG variable
|
||||||
|
if package_config.build_deps:
|
||||||
|
for dep in package_config.build_deps.split():
|
||||||
|
dynamic_build_dependency = DynamicBuildDep.objects.get_or_create(name=dep)
|
||||||
|
dynamic_build_dependency[0].save()
|
||||||
|
dynamic_build_dependency[0].package_configs.add(package_config)
|
||||||
|
dynamic_build_dependency[0].recipes.add(recipe)
|
||||||
|
|
||||||
# Get file dependencies within this layer
|
# Get file dependencies within this layer
|
||||||
deps = envdata.getVar('__depends', True)
|
deps = envdata.getVar('__depends', True)
|
||||||
filedeps = []
|
filedeps = []
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidde
|
||||||
from django.core.urlresolvers import reverse, reverse_lazy, resolve
|
from django.core.urlresolvers import reverse, reverse_lazy, resolve
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from layerindex.models import Branch, LayerItem, LayerMaintainer, LayerBranch, LayerDependency, LayerNote, Update, LayerUpdate, Recipe, Machine, Distro, BBClass, BBAppend, RecipeChange, RecipeChangeset, ClassicRecipe
|
from layerindex.models import Branch, LayerItem, LayerMaintainer, LayerBranch, LayerDependency, LayerNote, Update, LayerUpdate, Recipe, Machine, Distro, BBClass, BBAppend, RecipeChange, RecipeChangeset, ClassicRecipe, StaticBuildDep, DynamicBuildDep
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from django.views.generic import TemplateView, DetailView, ListView
|
from django.views.generic import TemplateView, DetailView, ListView
|
||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
|
@ -428,6 +428,19 @@ class RecipeSearchView(ListView):
|
||||||
for item in query_items:
|
for item in query_items:
|
||||||
if item.startswith('inherits:'):
|
if item.startswith('inherits:'):
|
||||||
inherits.append(item.split(':')[1])
|
inherits.append(item.split(':')[1])
|
||||||
|
|
||||||
|
# support searches by build dependencies
|
||||||
|
elif item.startswith('depends:'):
|
||||||
|
depsearch = item.split(':')[1]
|
||||||
|
qobj = Q(pk__in=[])
|
||||||
|
static_build_dependencies = StaticBuildDep.objects.filter(name=depsearch).first()
|
||||||
|
dynamic_build_dependencies = DynamicBuildDep.objects.filter(name=depsearch).first()
|
||||||
|
if static_build_dependencies:
|
||||||
|
qobj |= Q(staticbuilddep=static_build_dependencies)
|
||||||
|
if dynamic_build_dependencies:
|
||||||
|
qobj |= Q(dynamicbuilddep=dynamic_build_dependencies)
|
||||||
|
init_qs = init_qs.filter(qobj).distinct()
|
||||||
|
|
||||||
# support searches by layer name
|
# support searches by layer name
|
||||||
elif item.startswith('layer:'):
|
elif item.startswith('layer:'):
|
||||||
query_layername = item.split(':')[1].strip().lower()
|
query_layername = item.split(':')[1].strip().lower()
|
||||||
|
@ -845,6 +858,8 @@ class RecipeDetailView(DetailView):
|
||||||
if append.matches_recipe(recipe):
|
if append.matches_recipe(recipe):
|
||||||
verappends.append(append)
|
verappends.append(append)
|
||||||
context['verappends'] = verappends
|
context['verappends'] = verappends
|
||||||
|
context['packageconfigs'] = recipe.packageconfig_set.order_by('feature')
|
||||||
|
context['staticdependencies'] = recipe.staticbuilddep_set.order_by('name')
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,39 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Dependencies <i class="icon-exclamation-sign" data-toggle="tooltip" title="NOTE: Dependencies may vary based on configuration"></i></th>
|
||||||
|
<td>
|
||||||
|
{% if staticdependencies %}
|
||||||
|
<ul class="unstyled">
|
||||||
|
{% for dep in staticdependencies %}
|
||||||
|
<li> {{dep.name}} </li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% if packageconfigs %}
|
||||||
|
<ul class="unstyled">
|
||||||
|
{% for pc in packageconfigs %}
|
||||||
|
{% for dep in pc.dynamicbuilddep_set.all %}
|
||||||
|
<li> {{dep.name}}<i class="icon-cog" data-toggle="tooltip" title="If "{{pc.feature}}" is set in PACKAGECONFIG"></i></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>PACKAGECONFIG options</th>
|
||||||
|
<td>
|
||||||
|
{% if packageconfigs %}
|
||||||
|
<ul class="unstyled">
|
||||||
|
{% for pc in packageconfigs %}
|
||||||
|
<li> {{ pc.feature }} </li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -149,3 +182,11 @@
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user