mirror of
git://git.yoctoproject.org/layerindex-web.git
synced 2025-07-19 20:59:01 +02:00
Collect machine information from layers
Look for conf/machine/*.conf and add a record for each file found. These are displayed in the layer detail page if any are present. Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
parent
3b5c7ad825
commit
e4eb8213cf
2
TODO
2
TODO
|
@ -15,6 +15,7 @@ TODO:
|
||||||
* Usage links in list page?
|
* Usage links in list page?
|
||||||
* Layer submission interface design
|
* Layer submission interface design
|
||||||
* Style/extend about page
|
* Style/extend about page
|
||||||
|
* Style machine list on detail
|
||||||
* Recipe info page
|
* Recipe info page
|
||||||
* Captcha for layer submission interface?
|
* Captcha for layer submission interface?
|
||||||
* Touch up publishing interface
|
* Touch up publishing interface
|
||||||
|
@ -27,4 +28,3 @@ Later:
|
||||||
* Tool for finding/comparing duplicate recipes?
|
* Tool for finding/comparing duplicate recipes?
|
||||||
* Tool for editing SUMMARY/DESCRIPTION?
|
* Tool for editing SUMMARY/DESCRIPTION?
|
||||||
* Dynamic loading/filtering for recipes list
|
* Dynamic loading/filtering for recipes list
|
||||||
* Collect information on machines added by BSP layers?
|
|
||||||
|
|
|
@ -48,8 +48,18 @@ class RecipeAdmin(admin.ModelAdmin):
|
||||||
def has_delete_permission(self, request, obj=None):
|
def has_delete_permission(self, request, obj=None):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
class MachineAdmin(admin.ModelAdmin):
|
||||||
|
search_fields = ['name']
|
||||||
|
list_filter = ['layer__name']
|
||||||
|
readonly_fields = Machine._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
|
||||||
|
|
||||||
admin.site.register(LayerItem, LayerItemAdmin)
|
admin.site.register(LayerItem, LayerItemAdmin)
|
||||||
admin.site.register(LayerMaintainer, LayerMaintainerAdmin)
|
admin.site.register(LayerMaintainer, LayerMaintainerAdmin)
|
||||||
admin.site.register(LayerDependency, LayerDependencyAdmin)
|
admin.site.register(LayerDependency, LayerDependencyAdmin)
|
||||||
admin.site.register(LayerNote, LayerNoteAdmin)
|
admin.site.register(LayerNote, LayerNoteAdmin)
|
||||||
admin.site.register(Recipe, RecipeAdmin)
|
admin.site.register(Recipe, RecipeAdmin)
|
||||||
|
admin.site.register(Machine, MachineAdmin)
|
||||||
|
|
|
@ -118,6 +118,29 @@
|
||||||
</div> <!-- end of row-fluid -->
|
</div> <!-- end of row-fluid -->
|
||||||
</div> <!-- end of container-fluid -->
|
</div> <!-- end of container-fluid -->
|
||||||
|
|
||||||
|
{% if layeritem.machine_set.count > 0 %}
|
||||||
|
<div class="container-fluid" style="margin-bottom:1em;">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="navbar">
|
||||||
|
<div class="navbar-inner">
|
||||||
|
<a class="brand pull-left">{{ layeritem.name }} machines</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tbody>
|
||||||
|
{% for machine in layeritem.machine_set.all %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{ machine.vcs_web_url }}">{{ machine.name }}</a></td>
|
||||||
|
<td>{{ machine.description }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="container-fluid" style="margin-bottom:1em;">
|
<div class="container-fluid" style="margin-bottom:1em;">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
|
|
|
@ -150,3 +150,16 @@ class Recipe(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return os.path.join(self.filepath, self.filename)
|
return os.path.join(self.filepath, self.filename)
|
||||||
|
|
||||||
|
|
||||||
|
class Machine(models.Model):
|
||||||
|
layer = models.ForeignKey(LayerItem)
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
description = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
def vcs_web_url(self):
|
||||||
|
url = self.layer.file_url(os.path.join('conf/machine/%s.conf' % self.name))
|
||||||
|
return url or ''
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return '%s (%s)' % (self.name, self.layer.name)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import re
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
def logger_create():
|
def logger_create():
|
||||||
|
@ -65,7 +66,7 @@ def sanitise_path(inpath):
|
||||||
return outpath
|
return outpath
|
||||||
|
|
||||||
|
|
||||||
def split_path(subdir_start, recipe_path):
|
def split_bb_file_path(recipe_path, subdir_start):
|
||||||
if recipe_path.startswith(subdir_start) and fnmatch.fnmatch(recipe_path, "*.bb"):
|
if recipe_path.startswith(subdir_start) and fnmatch.fnmatch(recipe_path, "*.bb"):
|
||||||
if subdir_start:
|
if subdir_start:
|
||||||
filepath = os.path.relpath(os.path.dirname(recipe_path), subdir_start)
|
filepath = os.path.relpath(os.path.dirname(recipe_path), subdir_start)
|
||||||
|
@ -74,6 +75,13 @@ def split_path(subdir_start, recipe_path):
|
||||||
return (filepath, os.path.basename(recipe_path))
|
return (filepath, os.path.basename(recipe_path))
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
|
conf_re = re.compile(r'conf/machine/([^/.]*).conf$')
|
||||||
|
def check_machine_conf(path, subdir_start = None):
|
||||||
|
if not subdir_start or path.startswith(subdir_start):
|
||||||
|
res = conf_re.search(path)
|
||||||
|
if res:
|
||||||
|
return res.group(1)
|
||||||
|
return None
|
||||||
|
|
||||||
def update_recipe_file(data, path, recipe):
|
def update_recipe_file(data, path, recipe):
|
||||||
fn = str(os.path.join(path, recipe.filename))
|
fn = str(os.path.join(path, recipe.filename))
|
||||||
|
@ -90,6 +98,14 @@ def update_recipe_file(data, path, recipe):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info("Unable to read %s: %s", fn, str(e))
|
logger.info("Unable to read %s: %s", fn, str(e))
|
||||||
|
|
||||||
|
def update_machine_conf_file(path, machine):
|
||||||
|
with open(path) as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('#@DESCRIPTION:'):
|
||||||
|
desc = line[14:].strip()
|
||||||
|
desc = re.sub(r'Machine configuration for (the )*', '', desc)
|
||||||
|
machine.description = desc
|
||||||
|
break
|
||||||
|
|
||||||
def setup_bitbake_path(basepath):
|
def setup_bitbake_path(basepath):
|
||||||
# Set path to bitbake lib dir
|
# Set path to bitbake lib dir
|
||||||
|
@ -149,7 +165,7 @@ def main():
|
||||||
|
|
||||||
from django.core.management import setup_environ
|
from django.core.management import setup_environ
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from layerindex.models import LayerItem, Recipe
|
from layerindex.models import LayerItem, Recipe, Machine
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
import settings
|
import settings
|
||||||
|
|
||||||
|
@ -236,6 +252,7 @@ def main():
|
||||||
|
|
||||||
layerdir = os.path.join(repodir, layer.vcs_subdir)
|
layerdir = os.path.join(repodir, layer.vcs_subdir)
|
||||||
layerrecipes = Recipe.objects.filter(layer=layer)
|
layerrecipes = Recipe.objects.filter(layer=layer)
|
||||||
|
layermachines = Machine.objects.filter(layer=layer)
|
||||||
if layer.vcs_last_rev != topcommit.hexsha or options.reload:
|
if layer.vcs_last_rev != topcommit.hexsha or options.reload:
|
||||||
logger.info("Collecting data for layer %s" % layer.name)
|
logger.info("Collecting data for layer %s" % layer.name)
|
||||||
|
|
||||||
|
@ -262,13 +279,17 @@ def main():
|
||||||
|
|
||||||
for d in diff.iter_change_type('D'):
|
for d in diff.iter_change_type('D'):
|
||||||
path = d.a_blob.path
|
path = d.a_blob.path
|
||||||
(filepath, filename) = split_path(subdir_start, path)
|
(filepath, filename) = split_bb_file_path(path, subdir_start)
|
||||||
if filename:
|
if filename:
|
||||||
layerrecipes.filter(filepath=filepath).filter(filename=filename).delete()
|
layerrecipes.filter(filepath=filepath).filter(filename=filename).delete()
|
||||||
|
else:
|
||||||
|
machinename = check_machine_conf(path, subdir_start)
|
||||||
|
if machinename:
|
||||||
|
layermachines.filter(name=machinename).delete()
|
||||||
|
|
||||||
for d in diff.iter_change_type('A'):
|
for d in diff.iter_change_type('A'):
|
||||||
path = d.b_blob.path
|
path = d.b_blob.path
|
||||||
(filepath, filename) = split_path(subdir_start, path)
|
(filepath, filename) = split_bb_file_path(path, subdir_start)
|
||||||
if filename:
|
if filename:
|
||||||
recipe = Recipe()
|
recipe = Recipe()
|
||||||
recipe.layer = layer
|
recipe.layer = layer
|
||||||
|
@ -276,19 +297,36 @@ def main():
|
||||||
recipe.filepath = filepath
|
recipe.filepath = filepath
|
||||||
update_recipe_file(config_data_copy, os.path.join(layerdir, filepath), recipe)
|
update_recipe_file(config_data_copy, os.path.join(layerdir, filepath), recipe)
|
||||||
recipe.save()
|
recipe.save()
|
||||||
|
else:
|
||||||
|
machinename = check_machine_conf(path, subdir_start)
|
||||||
|
if machinename:
|
||||||
|
machine = Machine()
|
||||||
|
machine.layer = layer
|
||||||
|
machine.name = machinename
|
||||||
|
update_machine_conf_file(os.path.join(repodir, path), machine)
|
||||||
|
machine.save()
|
||||||
|
|
||||||
for d in diff.iter_change_type('M'):
|
for d in diff.iter_change_type('M'):
|
||||||
path = d.a_blob.path
|
path = d.a_blob.path
|
||||||
(filepath, filename) = split_path(subdir_start, path)
|
(filepath, filename) = split_bb_file_path(path, subdir_start)
|
||||||
if filename:
|
if filename:
|
||||||
results = layerrecipes.filter(filepath=filepath).filter(filename=filename)[:1]
|
results = layerrecipes.filter(filepath=filepath).filter(filename=filename)[:1]
|
||||||
if results:
|
if results:
|
||||||
recipe = results[0]
|
recipe = results[0]
|
||||||
update_recipe_file(config_data_copy, os.path.join(layerdir, filepath), recipe)
|
update_recipe_file(config_data_copy, os.path.join(layerdir, filepath), recipe)
|
||||||
recipe.save()
|
recipe.save()
|
||||||
|
else:
|
||||||
|
machinename = check_machine_conf(path, subdir_start)
|
||||||
|
if machinename:
|
||||||
|
results = layermachines.filter(name=machinename)
|
||||||
|
if results:
|
||||||
|
machine = results[0]
|
||||||
|
update_machine_conf_file(os.path.join(repodir, path), machine)
|
||||||
|
machine.save()
|
||||||
else:
|
else:
|
||||||
# Collect recipe data from scratch
|
# Collect recipe data from scratch
|
||||||
layerrecipes.delete()
|
layerrecipes.delete()
|
||||||
|
layermachines.delete()
|
||||||
for root, dirs, files in os.walk(layerdir):
|
for root, dirs, files in os.walk(layerdir):
|
||||||
for f in files:
|
for f in files:
|
||||||
if fnmatch.fnmatch(f, "*.bb"):
|
if fnmatch.fnmatch(f, "*.bb"):
|
||||||
|
@ -298,6 +336,15 @@ def main():
|
||||||
recipe.filepath = os.path.relpath(root, layerdir)
|
recipe.filepath = os.path.relpath(root, layerdir)
|
||||||
update_recipe_file(config_data_copy, root, recipe)
|
update_recipe_file(config_data_copy, root, recipe)
|
||||||
recipe.save()
|
recipe.save()
|
||||||
|
else:
|
||||||
|
fullpath = os.path.join(root, f)
|
||||||
|
machinename = check_machine_conf(fullpath)
|
||||||
|
if machinename:
|
||||||
|
machine = Machine()
|
||||||
|
machine.layer = layer
|
||||||
|
machine.name = machinename
|
||||||
|
update_machine_conf_file(fullpath, machine)
|
||||||
|
machine.save()
|
||||||
|
|
||||||
# Save repo info
|
# Save repo info
|
||||||
layer.vcs_last_rev = topcommit.hexsha
|
layer.vcs_last_rev = topcommit.hexsha
|
||||||
|
|
Loading…
Reference in New Issue
Block a user