layerindex: Add distro to web interface and model

Add the distros to the index.  This looks a lot like the machines
and allows users to search for a particular distro.

Signed-off-by: Liam R. Howlett <Liam.Howlett@WindRiver.com>

Added associated migration.

Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
This commit is contained in:
Liam R. Howlett 2016-10-04 14:00:20 -04:00 committed by Paul Eggleton
parent 4f0be8a7d0
commit 31c85196d0
15 changed files with 248 additions and 4 deletions

View File

@ -75,6 +75,16 @@ class MachineAdmin(admin.ModelAdmin):
def has_delete_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None):
return False return False
class DistroAdmin(admin.ModelAdmin):
search_fields = ['name']
list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name']
readonly_fields = Distro._meta.get_all_field_names()
def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
class BBAppendAdmin(admin.ModelAdmin): class BBAppendAdmin(admin.ModelAdmin):
search_fields = ['filename'] search_fields = ['filename']
list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name'] list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name']
@ -111,6 +121,7 @@ admin.site.register(LayerNote, LayerNoteAdmin)
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)
admin.site.register(Distro, DistroAdmin)
admin.site.register(BBAppend, BBAppendAdmin) admin.site.register(BBAppend, BBAppendAdmin)
admin.site.register(BBClass, BBClassAdmin) admin.site.register(BBClass, BBClassAdmin)
admin.site.register(RecipeChangeset, RecipeChangesetAdmin) admin.site.register(RecipeChangeset, RecipeChangesetAdmin)

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('layerindex', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Distro',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)),
('name', models.CharField(max_length=255)),
('description', models.CharField(max_length=255)),
('updated', models.DateTimeField(auto_now=True)),
('layerbranch', models.ForeignKey(to='layerindex.LayerBranch')),
],
),
]

View File

@ -361,6 +361,20 @@ class Machine(models.Model):
def __str__(self): def __str__(self):
return '%s (%s)' % (self.name, self.layerbranch.layer.name) return '%s (%s)' % (self.name, self.layerbranch.layer.name)
class Distro(models.Model):
layerbranch = models.ForeignKey(LayerBranch)
name = models.CharField(max_length=255)
description = models.CharField(max_length=255)
updated = models.DateTimeField(auto_now=True)
def vcs_web_url(self):
url = self.layerbranch.file_url(os.path.join('conf/distro/%s.conf' % self.name))
return url or ''
def __str__(self):
return '%s (%s)' % (self.name, self.layerbranch.layer.name)
class BBAppend(models.Model): class BBAppend(models.Model):
layerbranch = models.ForeignKey(LayerBranch) layerbranch = models.ForeignKey(LayerBranch)

View File

@ -152,6 +152,7 @@ def get_var_files(fn, varlist, d):
return varfiles return varfiles
machine_conf_re = re.compile(r'conf/machine/([^/.]*).conf$') machine_conf_re = re.compile(r'conf/machine/([^/.]*).conf$')
distro_conf_re = re.compile(r'conf/distro/([^/.]*).conf$')
bbclass_re = re.compile(r'classes/([^/.]*).bbclass$') bbclass_re = re.compile(r'classes/([^/.]*).bbclass$')
def detect_file_type(path, subdir_start): def detect_file_type(path, subdir_start):
typename = None typename = None
@ -171,6 +172,10 @@ def detect_file_type(path, subdir_start):
if res: if res:
typename = 'bbclass' typename = 'bbclass'
return (typename, None, res.group(1)) return (typename, None, res.group(1))
res = distro_conf_re.match(subpath)
if res:
typename = 'distro'
return (typename, None, res.group(1))
if typename == 'recipe' or typename == 'bbappend': if typename == 'recipe' or typename == 'bbappend':
if subdir_start: if subdir_start:

View File

@ -1,4 +1,4 @@
from layerindex.models import Branch, LayerItem, LayerNote, LayerBranch, LayerDependency, Recipe, Machine from layerindex.models import Branch, LayerItem, LayerNote, LayerBranch, LayerDependency, Recipe, Machine, Distro
from rest_framework import viewsets, serializers from rest_framework import viewsets, serializers
from layerindex.querysethelper import params_to_queryset, get_search_tuple from layerindex.querysethelper import params_to_queryset, get_search_tuple
@ -56,3 +56,11 @@ class MachineSerializer(serializers.ModelSerializer):
class MachineViewSet(ParametricSearchableModelViewSet): class MachineViewSet(ParametricSearchableModelViewSet):
queryset = Machine.objects.all() queryset = Machine.objects.all()
serializer_class = MachineSerializer serializer_class = MachineSerializer
class DistroSerializer(serializers.ModelSerializer):
class Meta:
model = Distro
class DistroViewSet(ParametricSearchableModelViewSet):
queryset = Distro.objects.all()
serializer_class = DistroSerializer

View File

@ -160,6 +160,7 @@ def main():
layerdir_start = os.path.normpath(oeclassicpath) + os.sep layerdir_start = os.path.normpath(oeclassicpath) + os.sep
layerrecipes = Recipe.objects.filter(layerbranch=layerbranch) layerrecipes = Recipe.objects.filter(layerbranch=layerbranch)
layermachines = Machine.objects.filter(layerbranch=layerbranch) layermachines = Machine.objects.filter(layerbranch=layerbranch)
layerdistros = Distro.objects.filter(layerbranch=layerbranch)
layerappends = BBAppend.objects.filter(layerbranch=layerbranch) layerappends = BBAppend.objects.filter(layerbranch=layerbranch)
layerclasses = BBClass.objects.filter(layerbranch=layerbranch) layerclasses = BBClass.objects.filter(layerbranch=layerbranch)
@ -172,6 +173,7 @@ def main():
layerrecipes.delete() layerrecipes.delete()
layermachines.delete() layermachines.delete()
layerdistros.delete()
layerappends.delete() layerappends.delete()
layerclasses.delete() layerclasses.delete()
for root, dirs, files in os.walk(oeclassicpath): for root, dirs, files in os.walk(oeclassicpath):

View File

@ -115,6 +115,19 @@ def update_machine_conf_file(path, machine):
break break
machine.description = desc machine.description = desc
def update_distro_conf_file(path, distro):
logger.debug('Updating distro %s' % path)
desc = ""
with open(path, 'r') as f:
for line in f:
if line.startswith('#@NAME:'):
desc = line[7:].strip()
if line.startswith('#@DESCRIPTION:'):
desc = line[14:].strip()
desc = re.sub(r'Distribution configuration for( running)*( an)*( the)*', '', desc)
break
distro.description = desc
def main(): def main():
if LooseVersion(git.__version__) < '0.3.1': if LooseVersion(git.__version__) < '0.3.1':
logger.error("Version of GitPython is too old, please install GitPython (python-git) 0.3.1 or later in order to use this script") logger.error("Version of GitPython is too old, please install GitPython (python-git) 0.3.1 or later in order to use this script")
@ -161,7 +174,7 @@ def main():
utils.setup_django() utils.setup_django()
import settings import settings
from layerindex.models import LayerItem, LayerBranch, Recipe, RecipeFileDependency, Machine, BBAppend, BBClass from layerindex.models import LayerItem, LayerBranch, Recipe, RecipeFileDependency, Machine, Distro, BBAppend, BBClass
from django.db import transaction from django.db import transaction
logger.setLevel(options.loglevel) logger.setLevel(options.loglevel)
@ -269,6 +282,7 @@ def main():
layerdir_start = os.path.normpath(layerdir) + os.sep layerdir_start = os.path.normpath(layerdir) + os.sep
layerrecipes = Recipe.objects.filter(layerbranch=layerbranch) layerrecipes = Recipe.objects.filter(layerbranch=layerbranch)
layermachines = Machine.objects.filter(layerbranch=layerbranch) layermachines = Machine.objects.filter(layerbranch=layerbranch)
layerdistros = Distro.objects.filter(layerbranch=layerbranch)
layerappends = BBAppend.objects.filter(layerbranch=layerbranch) layerappends = BBAppend.objects.filter(layerbranch=layerbranch)
layerclasses = BBClass.objects.filter(layerbranch=layerbranch) layerclasses = BBClass.objects.filter(layerbranch=layerbranch)
if layerbranch.vcs_last_rev != topcommit.hexsha or options.reload: if layerbranch.vcs_last_rev != topcommit.hexsha or options.reload:
@ -384,6 +398,15 @@ def main():
else: else:
logger.warn("Renamed machine %s could not be found" % oldpath) logger.warn("Renamed machine %s could not be found" % oldpath)
other_adds.append(diffitem) other_adds.append(diffitem)
elif oldtypename == 'distro':
results = layerdistros.filter(name=oldfilename)
if len(results):
logger.debug("Rename distro %s to %s" % (results[0], newfilename))
results[0].name = newfilename
results[0].save()
else:
logger.warn("Renamed distro %s could not be found" % oldpath)
other_adds.append(diffitem)
elif oldtypename == 'bbclass': elif oldtypename == 'bbclass':
results = layerclasses.filter(name=oldfilename) results = layerclasses.filter(name=oldfilename)
if len(results): if len(results):
@ -422,6 +445,8 @@ def main():
layerappends.filter(filepath=filepath).filter(filename=filename).delete() layerappends.filter(filepath=filepath).filter(filename=filename).delete()
elif typename == 'machine': elif typename == 'machine':
layermachines.filter(name=filename).delete() layermachines.filter(name=filename).delete()
elif typename == 'distro':
layerdistros.filter(name=filename).delete()
elif typename == 'bbclass': elif typename == 'bbclass':
layerclasses.filter(name=filename).delete() layerclasses.filter(name=filename).delete()
@ -452,6 +477,12 @@ def main():
machine.name = filename machine.name = filename
update_machine_conf_file(os.path.join(repodir, path), machine) update_machine_conf_file(os.path.join(repodir, path), machine)
machine.save() machine.save()
elif typename == 'distro':
distro = Distro()
distro.layerbranch = layerbranch
distro.name = filename
update_distro_conf_file(os.path.join(repodir, path), distro)
distro.save()
elif typename == 'bbclass': elif typename == 'bbclass':
bbclass = BBClass() bbclass = BBClass()
bbclass.layerbranch = layerbranch bbclass.layerbranch = layerbranch
@ -483,6 +514,12 @@ def main():
machine = results[0] machine = results[0]
update_machine_conf_file(os.path.join(repodir, path), machine) update_machine_conf_file(os.path.join(repodir, path), machine)
machine.save() machine.save()
elif typename == 'distro':
results = layerdistros.filter(name=filename)
if results:
distro = results[0]
update_distro_conf_file(os.path.join(repodir, path), distro)
distro.save()
deps = RecipeFileDependency.objects.filter(layerbranch=layerbranch).filter(path=path) deps = RecipeFileDependency.objects.filter(layerbranch=layerbranch).filter(path=path)
for dep in deps: for dep in deps:
@ -523,6 +560,7 @@ def main():
layerrecipe_fns.append(fullpath) layerrecipe_fns.append(fullpath)
layermachines.delete() layermachines.delete()
layerdistros.delete()
layerappends.delete() layerappends.delete()
layerclasses.delete() layerclasses.delete()
for root, dirs, files in os.walk(layerdir): for root, dirs, files in os.walk(layerdir):
@ -550,6 +588,12 @@ def main():
machine.name = filename machine.name = filename
update_machine_conf_file(fullpath, machine) update_machine_conf_file(fullpath, machine)
machine.save() machine.save()
elif typename == 'distro':
distro = Distro()
distro.layerbranch = layerbranch
distro.name = filename
update_distro_conf_file(fullpath, distro)
distro.save()
elif typename == 'bbclass': elif typename == 'bbclass':
bbclass = BBClass() bbclass = BBClass()
bbclass.layerbranch = layerbranch bbclass.layerbranch = layerbranch

View File

@ -21,6 +21,7 @@ router.register(r'layerBranches', restviews.LayerBranchViewSet)
router.register(r'layerDependencies', restviews.LayerDependencyViewSet) router.register(r'layerDependencies', restviews.LayerDependencyViewSet)
router.register(r'recipes', restviews.RecipeViewSet) router.register(r'recipes', restviews.RecipeViewSet)
router.register(r'machines', restviews.MachineViewSet) router.register(r'machines', restviews.MachineViewSet)
router.register(r'distros', restviews.DistroViewSet)
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', url(r'^$',
@ -37,6 +38,8 @@ urlpatterns = patterns('',
RedirectView.as_view(url=reverse_lazy('recipe_search', args=('master',)), permanent=False)), RedirectView.as_view(url=reverse_lazy('recipe_search', args=('master',)), permanent=False)),
url(r'^machines/$', url(r'^machines/$',
RedirectView.as_view(url=reverse_lazy('machine_search', args=('master',)), permanent=False)), RedirectView.as_view(url=reverse_lazy('machine_search', args=('master',)), permanent=False)),
url(r'^distros/$',
RedirectView.as_view(url=reverse_lazy('distro_search', args=('master',)), permanent=False)),
url(r'^submit/$', edit_layer_view, {'template_name': 'layerindex/submitlayer.html'}, name="submit_layer"), url(r'^submit/$', edit_layer_view, {'template_name': 'layerindex/submitlayer.html'}, name="submit_layer"),
url(r'^submit/thanks$', url(r'^submit/thanks$',

View File

@ -7,7 +7,7 @@
from django.conf.urls import * from django.conf.urls import *
from django.views.defaults import page_not_found from django.views.defaults import page_not_found
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, RedirectParamsView, DuplicatesView from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, DistroSearchView, PlainTextListView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, RedirectParamsView, DuplicatesView
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', url(r'^$',
@ -28,6 +28,10 @@ urlpatterns = patterns('',
MachineSearchView.as_view( MachineSearchView.as_view(
template_name='layerindex/machines.html'), template_name='layerindex/machines.html'),
name='machine_search'), name='machine_search'),
url(r'^distros/$',
DistroSearchView.as_view(
template_name='layerindex/distros.html'),
name='distro_search'),
url(r'^edit/(?P<slug>[-\w]+)/$', edit_layer_view, {'template_name': 'layerindex/editlayer.html'}, name="edit_layer"), url(r'^edit/(?P<slug>[-\w]+)/$', edit_layer_view, {'template_name': 'layerindex/editlayer.html'}, name="edit_layer"),
url(r'^duplicates/$', url(r'^duplicates/$',
DuplicatesView.as_view( DuplicatesView.as_view(

View File

@ -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, Recipe, Machine, BBClass, BBAppend, RecipeChange, RecipeChangeset, ClassicRecipe from layerindex.models import Branch, LayerItem, LayerMaintainer, LayerBranch, LayerDependency, LayerNote, Recipe, Machine, Distro, BBClass, BBAppend, RecipeChange, RecipeChangeset, ClassicRecipe
from datetime import datetime from datetime import datetime
from itertools import chain from itertools import chain
from django.views.generic import TemplateView, DetailView, ListView from django.views.generic import TemplateView, DetailView, ListView
@ -326,6 +326,7 @@ class LayerDetailView(DetailView):
if layerbranch: if layerbranch:
context['layerbranch'] = layerbranch context['layerbranch'] = layerbranch
context['machines'] = layerbranch.machine_set.order_by('name') context['machines'] = layerbranch.machine_set.order_by('name')
context['distros'] = layerbranch.distro_set.order_by('name')
context['appends'] = layerbranch.bbappend_set.order_by('filename') context['appends'] = layerbranch.bbappend_set.order_by('filename')
context['classes'] = layerbranch.bbclass_set.order_by('name') context['classes'] = layerbranch.bbclass_set.order_by('name')
context['url_branch'] = self.kwargs['branch'] context['url_branch'] = self.kwargs['branch']
@ -596,6 +597,32 @@ class MachineSearchView(ListView):
return context return context
class DistroSearchView(ListView):
context_object_name = 'distro_list'
paginate_by = 50
def get_queryset(self):
_check_url_branch(self.kwargs)
query_string = self.request.GET.get('q', '')
init_qs = Distro.objects.filter(layerbranch__branch__name=self.kwargs['branch'])
if query_string.strip():
entry_query = simplesearch.get_query(query_string, ['name', 'description'])
return init_qs.filter(entry_query).order_by('name', 'layerbranch__layer')
if 'q' in self.request.GET:
return init_qs.order_by('name', 'layerbranch__layer')
# Be consistent with RecipeSearchView
return Distro.objects.none()
def get_context_data(self, **kwargs):
context = super(DistroSearchView, self).get_context_data(**kwargs)
context['search_keyword'] = self.request.GET.get('q', '')
context['url_branch'] = self.kwargs['branch']
context['this_url_name'] = resolve(self.request.path_info).url_name
return context
class PlainTextListView(ListView): class PlainTextListView(ListView):
def render_to_response(self, context): def render_to_response(self, context):
"Returns a plain text response rendering of the template" "Returns a plain text response rendering of the template"

View File

@ -168,6 +168,9 @@
{% if classes.count > 0 %} {% if classes.count > 0 %}
<li><a href="#classes" data-toggle="tab">Classes</a></li> <li><a href="#classes" data-toggle="tab">Classes</a></li>
{% endif %} {% endif %}
{% if distros.count > 0 %}
<li><a href="#distros" data-toggle="tab">Distros</a></li>
{% endif %}
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
@ -265,6 +268,26 @@
</table> </table>
</div> </div>
{% endif %} {% endif %}
{% if distros.count > 0 %}
<div class="tab-pane" id="distros">
<div class="navbar">
<div class="navbar-inner">
<a class="brand pull-left">{{ layeritem.name }} distros</a>
</div>
</div>
<table class="table table-bordered">
<tbody>
{% for distro in distros %}
<tr>
<td><a href="{{ distro.vcs_web_url }}">{{ distro.name }}</a></td>
<td>{{ distro.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div> </div>

View File

@ -0,0 +1,76 @@
{% extends "base_toplevel.html" %}
{% load i18n %}
{% comment %}
layerindex-web - distro index page template
Copyright (C) 2013 Intel Corporation
Copyright (C) 2016 Wind River Systems
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
<!--
{% block title_append %} - distros{% endblock %}
-->
{% block navs %}
{% autoescape on %}
<li><a href="{% url 'layer_list' url_branch %}">Layers</a></li>
<li><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li>
<li><a href="{% url 'machine_search' url_branch %}">Machines</a></li>
<li class="active"><a href="{% url 'distro_search' url_branch %}">Distros</a></li>
{% endautoescape %}
{% endblock %}
{% block content_inner %}
{% autoescape on %}
<div class="row-fluid">
<div class="input-append">
<form id="filter-form" action="{% url 'distro_search' url_branch %}" method="get">
<input type="text" class="input-xxlarge" id="appendedInputButtons" placeholder="Search distros" name="q" value="{{ search_keyword }}" />
<button class="btn" type="submit">search</button>
</form>
</div>
</div>
{% if distro_list %}
<table class="table table-striped table-bordered distrostable">
<thead>
<tr>
<th>Distro name</th>
<th class="span9">Description</th>
<th>Layer</th>
</tr>
</thead>
<tbody>
{% for distro in distro_list %}
<tr>
<td><a href="{{ distro.vcs_web_url }}">{{ distro.name }}</a></td>
<td>{{ distro.description }}</td>
<td><a href="{% url 'layer_item' url_branch distro.layerbranch.layer.name %}">{{ distro.layerbranch.layer.name }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if is_paginated %}
{% load pagination %}
{% pagination page_obj %}
{% endif %}
{% else %}
{% if search_keyword %}
<p>No matching distros in database.</p>
{% endif %}
{% endif %}
{% endautoescape %}
{% endblock %}

View File

@ -21,6 +21,7 @@
<li class="active"><a href="{% url 'layer_list' url_branch %}">Layers</a></li> <li class="active"><a href="{% url 'layer_list' url_branch %}">Layers</a></li>
<li><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li> <li><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li>
<li><a href="{% url 'machine_search' url_branch %}">Machines</a></li> <li><a href="{% url 'machine_search' url_branch %}">Machines</a></li>
<li><a href="{% url 'distro_search' url_branch %}">Distros</a></li>
{% endautoescape %} {% endautoescape %}
{% endblock %} {% endblock %}

View File

@ -20,6 +20,7 @@
<li><a href="{% url 'layer_list' url_branch %}">Layers</a></li> <li><a href="{% url 'layer_list' url_branch %}">Layers</a></li>
<li><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li> <li><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li>
<li class="active"><a href="{% url 'machine_search' url_branch %}">Machines</a></li> <li class="active"><a href="{% url 'machine_search' url_branch %}">Machines</a></li>
<li><a href="{% url 'distro_search' url_branch %}">Distros</a></li>
{% endautoescape %} {% endautoescape %}
{% endblock %} {% endblock %}

View File

@ -20,6 +20,7 @@
<li><a href="{% url 'layer_list' url_branch %}">Layers</a></li> <li><a href="{% url 'layer_list' url_branch %}">Layers</a></li>
<li class="active"><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li> <li class="active"><a href="{% url 'recipe_search' url_branch %}">Recipes</a></li>
<li><a href="{% url 'machine_search' url_branch %}">Machines</a></li> <li><a href="{% url 'machine_search' url_branch %}">Machines</a></li>
<li><a href="{% url 'distro_search' url_branch %}">Distros</a></li>
{% endautoescape %} {% endautoescape %}
{% endblock %} {% endblock %}