From a2317295bb4b8c52a83c9a70263fcc9cc73621f4 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 8 Dec 2011 13:52:53 -0600 Subject: Remove auto-deletion of package relations on inactive users We have a page where these can all be managed now, so best leave it alone in case someone accidentally marks a user inactive and all the data is lost. Signed-off-by: Dan McGee --- packages/models.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'packages') diff --git a/packages/models.py b/packages/models.py index 0d02ab31..387db5c2 100644 --- a/packages/models.py +++ b/packages/models.py @@ -229,16 +229,7 @@ class Meta: ordering = ['name'] -def remove_inactive_maintainers(sender, instance, created, **kwargs): - # instance is an auth.models.User; we want to remove any existing - # maintainer relations if the user is no longer active - if not instance.is_active: - maint_relations = PackageRelation.objects.filter(user=instance, - type=PackageRelation.MAINTAINER) - maint_relations.delete() - -post_save.connect(remove_inactive_maintainers, sender=User, - dispatch_uid="packages.models") +# hook up some signals for sender in (PackageRelation, SignoffSpecification, Signoff): pre_save.connect(set_created_field, sender=sender, dispatch_uid="packages.models") -- cgit v1.2.3-54-g00ecf From 3e094a548f409e4a87454764f6baf814464d9619 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 8 Dec 2011 14:39:30 -0600 Subject: Add a new FlagRequest model This will be used to store all of the submitted data we get via flag out of date forms on the website. Signed-off-by: Dan McGee --- main/models.py | 2 +- packages/admin.py | 11 +- packages/migrations/0012_auto__add_flagrequest.py | 201 ++++++++++++++++++++++ packages/models.py | 34 +++- 4 files changed, 241 insertions(+), 7 deletions(-) create mode 100644 packages/migrations/0012_auto__add_flagrequest.py (limited to 'packages') diff --git a/main/models.py b/main/models.py index 9156fb51..cefebf76 100644 --- a/main/models.py +++ b/main/models.py @@ -6,7 +6,6 @@ from .fields import PositiveBigIntegerField, PGPKeyField from .utils import cache_function, make_choice, set_created_field -from packages.models import PackageRelation from datetime import datetime from itertools import groupby @@ -193,6 +192,7 @@ def is_signed(self): @property def maintainers(self): + from packages.models import PackageRelation if self._maintainers is None: self._maintainers = User.objects.filter( package_relations__pkgbase=self.pkgbase, diff --git a/packages/admin.py b/packages/admin.py index 01b6ed6c..14fa8960 100644 --- a/packages/admin.py +++ b/packages/admin.py @@ -1,12 +1,21 @@ from django.contrib import admin -from .models import PackageRelation +from .models import PackageRelation, FlagRequest class PackageRelationAdmin(admin.ModelAdmin): list_display = ('user', 'pkgbase', 'type', 'created') list_filter = ('type', 'user') search_fields = ('user__username', 'pkgbase') + date_hierarchy = 'created' + +class FlagRequestAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'created', 'who', 'is_spam', 'is_legitimate', + 'message') + list_filter = ('is_spam', 'is_legitimate') + search_fields = ('pkgbase', 'user_email', 'message') + date_hierarchy = 'created' admin.site.register(PackageRelation, PackageRelationAdmin) +admin.site.register(FlagRequest, FlagRequestAdmin) # vim: set ts=4 sw=4 et: diff --git a/packages/migrations/0012_auto__add_flagrequest.py b/packages/migrations/0012_auto__add_flagrequest.py new file mode 100644 index 00000000..a501daff --- /dev/null +++ b/packages/migrations/0012_auto__add_flagrequest.py @@ -0,0 +1,201 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'FlagRequest' + db.create_table('packages_flagrequest', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('user_email', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('created', self.gf('django.db.models.fields.DateTimeField')()), + ('ip_address', self.gf('django.db.models.fields.IPAddressField')(max_length=15)), + ('pkgbase', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), + ('repo', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['main.Repo'])), + ('num_packages', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)), + ('message', self.gf('django.db.models.fields.TextField')(blank=True)), + ('is_spam', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('is_legitimate', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('packages', ['FlagRequest']) + + if db.backend_name == 'mysql': + # stupid f#$%ing storage of IP address as a 15 character type + db.execute("ALTER TABLE packages_flagrequest " + "MODIFY ip_address char(39) NOT NULL") + + + def backwards(self, orm): + # Deleting model 'FlagRequest' + db.delete_table('packages_flagrequest') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'main.arch': { + 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, + 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + }, + 'main.package': { + 'Meta': {'ordering': "('pkgname',)", 'unique_together': "(('pkgname', 'repo', 'arch'),)", 'object_name': 'Package', 'db_table': "'packages'"}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), + 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'compressed_size': ('main.fields.PositiveBigIntegerField', [], {}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'installed_size': ('main.fields.PositiveBigIntegerField', [], {}), + 'last_update': ('django.db.models.fields.DateTimeField', [], {}), + 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pgp_signature': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkgdesc': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) + }, + 'main.repo': { + 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, + 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'packages.conflict': { + 'Meta': {'ordering': "['name']", 'object_name': 'Conflict'}, + 'comparison': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'conflicts'", 'to': "orm['main.Package']"}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + 'packages.flagrequest': { + 'Meta': {'object_name': 'FlagRequest'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'is_legitimate': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'num_packages': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Repo']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}) + }, + 'packages.license': { + 'Meta': {'ordering': "['name']", 'object_name': 'License'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'licenses'", 'to': "orm['main.Package']"}) + }, + 'packages.packagegroup': { + 'Meta': {'object_name': 'PackageGroup'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'groups'", 'to': "orm['main.Package']"}) + }, + 'packages.packagerelation': { + 'Meta': {'unique_together': "(('pkgbase', 'user', 'type'),)", 'object_name': 'PackageRelation'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_relations'", 'to': "orm['auth.User']"}) + }, + 'packages.provision': { + 'Meta': {'ordering': "['name']", 'object_name': 'Provision'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'provides'", 'to': "orm['main.Package']"}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + 'packages.replacement': { + 'Meta': {'ordering': "['name']", 'object_name': 'Replacement'}, + 'comparison': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'replaces'", 'to': "orm['main.Package']"}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + 'packages.signoff': { + 'Meta': {'object_name': 'Signoff'}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Arch']"}), + 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Repo']"}), + 'revoked': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_signoffs'", 'to': "orm['auth.User']"}) + }, + 'packages.signoffspecification': { + 'Meta': {'object_name': 'SignoffSpecification'}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Arch']"}), + 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'known_bad': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Repo']"}), + 'required': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}) + } + } + + complete_apps = ['packages'] diff --git a/packages/models.py b/packages/models.py index 387db5c2..77cade68 100644 --- a/packages/models.py +++ b/packages/models.py @@ -4,6 +4,7 @@ from django.db.models.signals import pre_save, post_save from django.contrib.auth.models import User +from main.models import Arch, Repo from main.utils import set_created_field class PackageRelation(models.Model): @@ -71,8 +72,8 @@ class SignoffSpecification(models.Model): pkgver = models.CharField(max_length=255) pkgrel = models.CharField(max_length=255) epoch = models.PositiveIntegerField(default=0) - arch = models.ForeignKey('main.Arch') - repo = models.ForeignKey('main.Repo') + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) user = models.ForeignKey(User, null=True) created = models.DateTimeField(editable=False) required = models.PositiveIntegerField(default=2, @@ -134,8 +135,8 @@ class Signoff(models.Model): pkgver = models.CharField(max_length=255) pkgrel = models.CharField(max_length=255) epoch = models.PositiveIntegerField(default=0) - arch = models.ForeignKey('main.Arch') - repo = models.ForeignKey('main.Repo') + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) user = models.ForeignKey(User, related_name="package_signoffs") created = models.DateTimeField(editable=False) revoked = models.DateTimeField(null=True) @@ -164,6 +165,29 @@ def __unicode__(self): return u'%s-%s: %s%s' % ( self.pkgbase, self.full_version, self.user, revoked) + +class FlagRequest(models.Model): + user = models.ForeignKey(User, blank=True, null=True) + user_email = models.EmailField('email address') + created = models.DateTimeField(editable=False) + ip_address = models.IPAddressField('IP address') + pkgbase = models.CharField(max_length=255, db_index=True) + repo = models.ForeignKey(Repo) + num_packages = models.PositiveIntegerField('number of packages', default=1) + message = models.TextField('message to developer', blank=True) + is_spam = models.BooleanField(default=False, + help_text="Is this comment from a real person?") + is_legitimate = models.BooleanField(default=True, + help_text="Is this actually an out-of-date flag request?") + + def who(self): + if self.user: + return self.user.get_full_name() + return self.user_email + + def __unicode__(self): + return u'%s from %s on %s' % (self.pkgbase, self.who(), self.created) + class PackageGroup(models.Model): ''' Represents a group a package is in. There is no actual group entity, @@ -230,7 +254,7 @@ class Meta: # hook up some signals -for sender in (PackageRelation, SignoffSpecification, Signoff): +for sender in (PackageRelation, SignoffSpecification, Signoff, FlagRequest): pre_save.connect(set_created_field, sender=sender, dispatch_uid="packages.models") -- cgit v1.2.3-54-g00ecf From 5006da56476ebd3614cab68c574ab893e82d5aaf Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 8 Dec 2011 15:02:28 -0600 Subject: Store flag requests in the database This makes them persistent rather than the transient beings they currently are. We attempt to capture all the metadata we need to be able to do things with this later- aka IP address (for spam checking later), fields that allow us to mark the request as spam or not an actual out-of-date report, etc. As a bonus, logged-in developers now get the email address field filled in for free. Yay. Signed-off-by: Dan McGee --- packages/views/flag.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/views/flag.py b/packages/views/flag.py index 7e9d87c7..4132f9a7 100644 --- a/packages/views/flag.py +++ b/packages/views/flag.py @@ -9,6 +9,7 @@ from django.views.generic.simple import direct_to_template from django.views.decorators.cache import never_cache +from ..models import FlagRequest from main.models import Package @@ -17,7 +18,7 @@ def flaghelp(request): class FlagForm(forms.Form): email = forms.EmailField(label='* E-mail Address') - usermessage = forms.CharField(label='Message To Dev', + message = forms.CharField(label='Message To Dev', widget=forms.Textarea, required=False) # The field below is used to filter out bots that blindly fill out all # input elements @@ -47,6 +48,16 @@ def flag(request, name, repo, arch): flagged_pkgs = list(pkgs) pkgs.update(flag_date=datetime.utcnow()) + # store our flag request + flag_request = FlagRequest(user_email=form.cleaned_data['email'], + ip_address=request.META.get('REMOTE_ADDR', '127.0.0.1'), + pkgbase=pkg.pkgbase, repo=pkg.repo, + num_packages=len(flagged_pkgs), + message=form.cleaned_data['message']) + if request.user.is_authenticated(): + flag_request.user = request.user + flag_request.save() + maints = pkg.maintainers if not maints: toemail = settings.NOTIFICATIONS @@ -65,7 +76,7 @@ def flag(request, name, repo, arch): tmpl = loader.get_template('packages/outofdate.txt') ctx = Context({ 'email': form.cleaned_data['email'], - 'message': form.cleaned_data['usermessage'], + 'message': form.cleaned_data['message'], 'pkg': pkg, 'packages': flagged_pkgs, }) @@ -78,7 +89,10 @@ def flag(request, name, repo, arch): return redirect('package-flag-confirmed', name=name, repo=repo, arch=arch) else: - form = FlagForm() + initial = {} + if request.user.is_authenticated(): + initial['email'] = request.user.email + form = FlagForm(initial=initial) context = { 'package': pkg, -- cgit v1.2.3-54-g00ecf From 4fa709ea86c8eefac05a848187fc7281edff8fa9 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 9 Dec 2011 09:28:49 -0600 Subject: populate_signoffs: add an SVN log cache for duplicate lookups Signed-off-by: Dan McGee --- packages/management/commands/populate_signoffs.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/management/commands/populate_signoffs.py b/packages/management/commands/populate_signoffs.py index ce5ec734..42496e9d 100644 --- a/packages/management/commands/populate_signoffs.py +++ b/packages/management/commands/populate_signoffs.py @@ -44,6 +44,9 @@ def handle_noargs(self, **options): return add_signoff_comments() def svn_log(pkgbase, repo): + '''Retrieve the most recent SVN log entry for the given pkgbase and + repository. The configured setting SVN_BASE_URL is used along with the + svn_root for each repository to form the correct URL.''' path = '%s%s/%s/trunk/' % (settings.SVN_BASE_URL, repo.svn_root, pkgbase) cmd = ['svn', 'log', '--limit=1', '--xml', path] log_data = subprocess.check_output(cmd) @@ -59,6 +62,17 @@ def svn_log(pkgbase, repo): 'message': xml.findtext('logentry/msg'), } +def cached_svn_log(pkgbase, repo): + '''Retrieve the cached version of the SVN log if possible, else delegate to + svn_log() to do the work and cache the result.''' + key = (pkgbase, repo) + if key in cached_svn_log.cache: + return cached_svn_log.cache[key] + log = svn_log(pkgbase, repo) + cached_svn_log.cache[key] = log + return log +cached_svn_log.cache = {} + def create_specification(package, log, finder): trimmed_message = log['message'].strip() spec = SignoffSpecification(pkgbase=package.pkgbase, @@ -80,7 +94,7 @@ def add_signoff_comments(): continue logger.debug("getting SVN log for %s (%s)", group.pkgbase, group.repo) - log = svn_log(group.pkgbase, group.repo) + log = cached_svn_log(group.pkgbase, group.repo) logger.info("creating spec with SVN message for %s", group.pkgbase) spec = create_specification(group.packages[0], log, finder) spec.save() -- cgit v1.2.3-54-g00ecf