From 9af114492887b874e44e5fd2e4b0067b447af3e4 Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Sun, 12 May 2013 21:38:19 +0100 Subject: [PATCH] Collect bbappends and bbclasses for each layer Collect bbappend/bbclass info during the update process and display it on the layer detail page. Signed-off-by: Paul Eggleton --- TODO | 1 - layerindex/admin.py | 20 +++ .../0004_auto__add_bbclass__add_bbappend.py | 139 ++++++++++++++++++ layerindex/models.py | 32 ++++ layerindex/update.py | 135 +++++++++++------ layerindex/views.py | 2 + templates/layerindex/detail.html | 45 ++++++ 7 files changed, 328 insertions(+), 46 deletions(-) create mode 100644 layerindex/migrations/0004_auto__add_bbclass__add_bbappend.py diff --git a/TODO b/TODO index d71537e..fa01663 100644 --- a/TODO +++ b/TODO @@ -27,6 +27,5 @@ Later: * Create simple script to check for unlisted layer subdirectories in all repos * Move import script to utils/ subdir * Are we going to need some way of indicating forks of another layer? (would rather avoid having forks altogether...) -* Track bbappends in each layer * Auto-detect more values from github pages? * Ability for submitters to get email notification about publication? diff --git a/layerindex/admin.py b/layerindex/admin.py index 00ea64f..85a200b 100644 --- a/layerindex/admin.py +++ b/layerindex/admin.py @@ -62,6 +62,24 @@ class MachineAdmin(admin.ModelAdmin): def has_delete_permission(self, request, obj=None): return False +class BBAppendAdmin(admin.ModelAdmin): + search_fields = ['filename'] + list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name'] + readonly_fields = BBAppend._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 BBClassAdmin(admin.ModelAdmin): + search_fields = ['name'] + list_filter = ['layerbranch__layer__name', 'layerbranch__branch__name'] + readonly_fields = BBClass._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(Branch, BranchAdmin) admin.site.register(LayerItem, LayerItemAdmin) admin.site.register(LayerBranch, LayerBranchAdmin) @@ -71,3 +89,5 @@ admin.site.register(LayerNote, LayerNoteAdmin) admin.site.register(Recipe, RecipeAdmin) admin.site.register(RecipeFileDependency) admin.site.register(Machine, MachineAdmin) +admin.site.register(BBAppend, BBAppendAdmin) +admin.site.register(BBClass, BBClassAdmin) diff --git a/layerindex/migrations/0004_auto__add_bbclass__add_bbappend.py b/layerindex/migrations/0004_auto__add_bbclass__add_bbappend.py new file mode 100644 index 0000000..0216914 --- /dev/null +++ b/layerindex/migrations/0004_auto__add_bbclass__add_bbappend.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'BBClass' + db.create_table('layerindex_bbclass', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('layerbranch', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['layerindex.LayerBranch'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + )) + db.send_create_signal('layerindex', ['BBClass']) + + # Adding model 'BBAppend' + db.create_table('layerindex_bbappend', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('layerbranch', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['layerindex.LayerBranch'])), + ('filename', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('filepath', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + )) + db.send_create_signal('layerindex', ['BBAppend']) + + + def backwards(self, orm): + # Deleting model 'BBClass' + db.delete_table('layerindex_bbclass') + + # Deleting model 'BBAppend' + db.delete_table('layerindex_bbappend') + + + models = { + 'layerindex.bbappend': { + 'Meta': {'object_name': 'BBAppend'}, + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'filepath': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerBranch']"}) + }, + 'layerindex.bbclass': { + 'Meta': {'object_name': 'BBClass'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerBranch']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'layerindex.branch': { + 'Meta': {'object_name': 'Branch'}, + 'bitbake_branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'sort_priority': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'layerindex.layerbranch': { + 'Meta': {'object_name': 'LayerBranch'}, + 'branch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.Branch']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerItem']"}), + 'vcs_last_commit': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'vcs_last_fetch': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'vcs_last_rev': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), + 'vcs_subdir': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}) + }, + 'layerindex.layerdependency': { + 'Meta': {'object_name': 'LayerDependency'}, + 'dependency': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependents_set'", 'to': "orm['layerindex.LayerItem']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependencies_set'", 'to': "orm['layerindex.LayerBranch']"}) + }, + 'layerindex.layeritem': { + 'Meta': {'object_name': 'LayerItem'}, + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_preference': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'layer_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'mailing_list_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'N'", 'max_length': '1'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'usage_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'vcs_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'vcs_web_file_base_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'vcs_web_tree_base_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'vcs_web_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'layerindex.layermaintainer': { + 'Meta': {'object_name': 'LayerMaintainer'}, + 'email': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerBranch']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'responsibility': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'A'", 'max_length': '1'}) + }, + 'layerindex.layernote': { + 'Meta': {'object_name': 'LayerNote'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerItem']"}), + 'text': ('django.db.models.fields.TextField', [], {}) + }, + 'layerindex.machine': { + 'Meta': {'object_name': 'Machine'}, + 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerBranch']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'layerindex.recipe': { + 'Meta': {'object_name': 'Recipe'}, + 'bbclassextend': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'bugtracker': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'filepath': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.LayerBranch']"}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'pn': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'provides': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'pv': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'section': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'layerindex.recipefiledependency': { + 'Meta': {'object_name': 'RecipeFileDependency'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layerbranch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['layerindex.LayerBranch']"}), + 'path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['layerindex.Recipe']"}) + } + } + + complete_apps = ['layerindex'] \ No newline at end of file diff --git a/layerindex/models.py b/layerindex/models.py index f4d8cc1..4503684 100644 --- a/layerindex/models.py +++ b/layerindex/models.py @@ -270,3 +270,35 @@ class Machine(models.Model): def __unicode__(self): return '%s (%s)' % (self.name, self.layerbranch.layer.name) + + +class BBAppend(models.Model): + layerbranch = models.ForeignKey(LayerBranch) + filename = models.CharField(max_length=255) + filepath = models.CharField(max_length=255, blank=True) + + class Meta: + verbose_name = "Append" + + def vcs_web_url(self): + url = self.layerbranch.file_url(os.path.join(self.filepath, self.filename)) + return url or '' + + def __unicode__(self): + return os.path.join(self.filepath, self.filename) + + +class BBClass(models.Model): + layerbranch = models.ForeignKey(LayerBranch) + name = models.CharField(max_length=100) + + class Meta: + verbose_name = "Class" + verbose_name_plural = "Classes" + + def vcs_web_url(self): + url = self.layerbranch.file_url(os.path.join('classes', "%s.bbclass" % self.name)) + return url or '' + + def __unicode__(self): + return '%s (%s)' % (self.name, self.layerbranch.layer.name) diff --git a/layerindex/update.py b/layerindex/update.py index f946eb9..45291e4 100755 --- a/layerindex/update.py +++ b/layerindex/update.py @@ -59,16 +59,37 @@ def runcmd(cmd,destdir=None,printerr=True): return output -def split_bb_file_path(recipe_path, subdir_start): - if fnmatch.fnmatch(recipe_path, "*.bb"): - if subdir_start: - filepath = os.path.relpath(os.path.dirname(recipe_path), subdir_start) +machine_conf_re = re.compile(r'conf/machine/([^/.]*).conf$') +bbclass_re = re.compile(r'classes/([^/.]*).bbclass$') +def detect_file_type(path, subdir_start): + typename = None + if fnmatch.fnmatch(path, "*.bb"): + typename = 'recipe' + elif fnmatch.fnmatch(path, "*.bbappend"): + typename = 'bbappend' + else: + # Check if it's a machine conf file + subpath = path[len(subdir_start):] + res = machine_conf_re.match(subpath) + if res: + typename = 'machine' + return (typename, None, res.group(1)) else: - filepath = os.path.dirname(recipe_path) - return (filepath, os.path.basename(recipe_path)) - return (None, None) + res = bbclass_re.match(subpath) + if res: + typename = 'bbclass' + return (typename, None, res.group(1)) + + if typename == 'recipe' or typename == 'bbappend': + if subdir_start: + filepath = os.path.relpath(os.path.dirname(path), subdir_start) + else: + filepath = os.path.dirname(path) + return (typename, filepath, os.path.basename(path)) + + return (None, None, None) + -conf_re = re.compile(r'conf/machine/([^/.]*).conf$') def check_machine_conf(path, subdir_start): subpath = path[len(subdir_start):] res = conf_re.match(subpath) @@ -202,7 +223,7 @@ def main(): from django.core.management import setup_environ from django.conf import settings - from layerindex.models import LayerItem, LayerBranch, Recipe, RecipeFileDependency, Machine + from layerindex.models import LayerItem, LayerBranch, Recipe, RecipeFileDependency, Machine, BBAppend, BBClass from django.db import transaction import settings @@ -379,6 +400,8 @@ def main(): layerdir_start = os.path.normpath(layerdir) + os.sep layerrecipes = Recipe.objects.filter(layerbranch=layerbranch) layermachines = Machine.objects.filter(layerbranch=layerbranch) + layerappends = BBAppend.objects.filter(layerbranch=layerbranch) + layerclasses = BBClass.objects.filter(layerbranch=layerbranch) if layerbranch.vcs_last_rev != topcommit.hexsha or options.reload: # Check out appropriate branch if not options.nocheckout: @@ -443,19 +466,21 @@ def main(): for d in diff.iter_change_type('D'): path = d.a_blob.path if path.startswith(subdir_start): - (filepath, filename) = split_bb_file_path(path, subdir_start) - if filename: + (typename, filepath, filename) = detect_file_type(path, subdir_start) + if typename == 'recipe': layerrecipes.filter(filepath=filepath).filter(filename=filename).delete() - else: - machinename = check_machine_conf(path, subdir_start) - if machinename: - layermachines.filter(name=machinename).delete() + elif typename == 'bbappend': + layerappends.filter(filepath=filepath).filter(filename=filename).delete() + elif typename == 'machine': + layermachines.filter(name=filename).delete() + elif typename == 'bbclass': + layerclasses.filter(name=filename).delete() for d in diff.iter_change_type('A'): path = d.b_blob.path if path.startswith(subdir_start): - (filepath, filename) = split_bb_file_path(path, subdir_start) - if filename: + (typename, filepath, filename) = detect_file_type(path, subdir_start) + if typename == 'recipe': recipe = Recipe() recipe.layerbranch = layerbranch recipe.filename = filename @@ -463,35 +488,43 @@ def main(): update_recipe_file(config_data_copy, os.path.join(layerdir, filepath), recipe, layerdir_start, repodir) recipe.save() updatedrecipes.add(recipe) - else: - machinename = check_machine_conf(path, subdir_start) - if machinename: - machine = Machine() - machine.layerbranch = layerbranch - machine.name = machinename - update_machine_conf_file(os.path.join(repodir, path), machine) - machine.save() + elif typename == 'bbappend': + append = BBAppend() + append.layerbranch = layerbranch + append.filename = filename + append.filepath = filepath + append.save() + elif typename == 'machine': + machine = Machine() + machine.layerbranch = layerbranch + machine.name = filename + update_machine_conf_file(os.path.join(repodir, path), machine) + machine.save() + elif typename == 'bbclass': + bbclass = BBClass() + bbclass.layerbranch = layerbranch + bbclass.name = filename + bbclass.save() dirtyrecipes = set() for d in diff.iter_change_type('M'): path = d.a_blob.path if path.startswith(subdir_start): - (filepath, filename) = split_bb_file_path(path, subdir_start) - if filename: + (typename, filepath, filename) = detect_file_type(path, subdir_start) + if typename == 'recipe': results = layerrecipes.filter(filepath=filepath).filter(filename=filename)[:1] if results: recipe = results[0] update_recipe_file(config_data_copy, os.path.join(layerdir, filepath), recipe, layerdir_start, repodir) recipe.save() updatedrecipes.add(recipe) - 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() + elif typename == 'machine': + results = layermachines.filter(name=filename) + if results: + machine = results[0] + update_machine_conf_file(os.path.join(repodir, path), machine) + machine.save() + deps = RecipeFileDependency.objects.filter(layerbranch=layerbranch).filter(path=path) for dep in deps: dirtyrecipes.add(dep.recipe) @@ -503,26 +536,38 @@ def main(): # Collect recipe data from scratch layerrecipes.delete() layermachines.delete() + layerappends.delete() + layerclasses.delete() for root, dirs, files in os.walk(layerdir): if '.git' in dirs: dirs.remove('.git') for f in files: - if fnmatch.fnmatch(f, "*.bb"): + fullpath = os.path.join(root, f) + (typename, _, filename) = detect_file_type(fullpath, layerdir_start) + if typename == 'recipe': recipe = Recipe() recipe.layerbranch = layerbranch recipe.filename = f recipe.filepath = os.path.relpath(root, layerdir) update_recipe_file(config_data_copy, root, recipe, layerdir_start, repodir) recipe.save() - else: - fullpath = os.path.join(root, f) - machinename = check_machine_conf(fullpath, layerdir_start) - if machinename: - machine = Machine() - machine.layerbranch = layerbranch - machine.name = machinename - update_machine_conf_file(fullpath, machine) - machine.save() + elif typename == 'bbappend': + append = BBAppend() + append.layerbranch = layerbranch + append.filename = f + append.filepath = os.path.relpath(root, layerdir) + append.save() + elif typename == 'machine': + machine = Machine() + machine.layerbranch = layerbranch + machine.name = filename + update_machine_conf_file(fullpath, machine) + machine.save() + elif typename == 'bbclass': + bbclass = BBClass() + bbclass.layerbranch = layerbranch + bbclass.name = filename + bbclass.save() # Save repo info layerbranch.vcs_last_rev = topcommit.hexsha diff --git a/layerindex/views.py b/layerindex/views.py index ac8f964..fe22b58 100644 --- a/layerindex/views.py +++ b/layerindex/views.py @@ -245,6 +245,8 @@ class LayerDetailView(DetailView): layerbranch = layer.get_layerbranch(self.request.session.get('branch', 'master')) context['layerbranch'] = layerbranch context['machines'] = layerbranch.machine_set.order_by('name') + context['appends'] = layerbranch.bbappend_set.order_by('filename') + context['classes'] = layerbranch.bbclass_set.order_by('name') return context class LayerReviewDetailView(LayerDetailView): diff --git a/templates/layerindex/detail.html b/templates/layerindex/detail.html index a1ebae4..eae3cee 100644 --- a/templates/layerindex/detail.html +++ b/templates/layerindex/detail.html @@ -214,6 +214,51 @@ {% endif %} + {% if appends.count > 0 %} +
+
+ + + + + {% for append in appends %} + + + + {% endfor %} + +
{{ append.filename }}
+
+
+ {% endif %} + + {% if classes.count > 0 %} +
+
+ + + + + {% for class in classes %} + + + + {% endfor %} + +
{{ class.name }}
+
+
+ {% endif %} + + {% endautoescape %} {% endblock %}